提交 54c8475e authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 e0539045
差异被折叠。
...@@ -31,7 +31,9 @@ ...@@ -31,7 +31,9 @@
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"js-md5": "^0.8.3", "js-md5": "^0.8.3",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"lucide-react": "^0.474.0",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"nanoid": "^3.3.8",
"qs": "^6.11.2", "qs": "^6.11.2",
"rc-slider-captcha": "^1.3.0", "rc-slider-captcha": "^1.3.0",
"react": "^18.3.1", "react": "^18.3.1",
......
...@@ -122,22 +122,35 @@ ...@@ -122,22 +122,35 @@
} }
.chapter-right { .chapter-right {
flex: 1; flex: 1;
display: flex;
align-items: center;
.chapter-right-content { .chapter-right-content {
flex: 1;
padding: 10px; padding: 10px;
border-radius: 5px; border-radius: 5px;
&:hover { &:hover {
background-color: #e5e7eb; background-color: #e5e7eb;
} }
h3 { h3,
.chapter-title {
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
} }
p { p,
.chapter-desc {
font-size: 13px; font-size: 13px;
color: #999; color: #999;
} }
} }
&:hover {
.chapter-right-tools {
opacity: 1;
}
}
.chapter-right-tools {
opacity: 0;
}
} }
.message-file { .message-file {
......
...@@ -7,33 +7,47 @@ import { ...@@ -7,33 +7,47 @@ import {
FileTextOutlined, FileTextOutlined,
FileWordOutlined, FileWordOutlined,
DownloadOutlined, DownloadOutlined,
PlusCircleOutlined,
DeleteOutlined,
} from '@ant-design/icons' } from '@ant-design/icons'
import { ConfigProvider, Modal, Input, Button } from 'antd' import { ConfigProvider, Modal, Input, Button, Dropdown } from 'antd'
const { TextArea } = Input const { TextArea } = Input
import './AISearchModal.less' import './AISearchModal.less'
import { usePaper } from '@/hooks/useWenku' import { usePaper } from '@/hooks/useWenku'
import { useCopyToClipboard } from 'react-use' import { useCopyToClipboard } from 'react-use'
import { CircleEllipsis } from 'lucide-react'
export default function AIModal() { export default function AIModal() {
const [isModalOpen, setIsModalOpen] = useState(true) const [isModalOpen, setIsModalOpen] = useState(true)
const [content, setContent] = useState('商业数据分析') const [content, setContent] = useState('')
const [textIndent, setTextIndent] = useState(0) const [textIndent, setTextIndent] = useState(0)
const prePromptRef = useRef(null) const prePromptRef = useRef(null)
const messageScrollRef = useRef(null) const messageScrollRef = useRef(null)
const { messages, setMessages, isLoading, generateOutline, generatePaper } = usePaper() const {
messages,
setMessages,
isLoading,
generateOutline,
generatePaper,
chapterTagRender,
getChaptersMarkdown,
addChapter,
updateChapter,
removeChapter,
} = usePaper()
useEffect(() => { useEffect(() => {
if (prePromptRef.current) { if (prePromptRef.current) {
const width = prePromptRef.current.offsetWidth + 10 const width = prePromptRef.current.offsetWidth + 10
setTextIndent(width) setTextIndent(width)
} }
}, [isModalOpen]) }, [isModalOpen])
const [isEditMessage, setIsEditMessage] = useState(false)
useEffect(() => { useEffect(() => {
if (messageScrollRef.current) { if (messageScrollRef.current && !isEditMessage) {
const scrollContainer = messageScrollRef.current const scrollContainer = messageScrollRef.current
scrollContainer.scrollTop = scrollContainer.scrollHeight scrollContainer.scrollTop = scrollContainer.scrollHeight
} }
}, [messages]) }, [messages, isEditMessage])
const prePrompt = '帮我生成一篇课题报告,主题是:' const prePrompt = '帮我生成一篇课题报告,主题是:'
const handleEnterSearch = (e) => { const handleEnterSearch = (e) => {
...@@ -45,13 +59,14 @@ export default function AIModal() { ...@@ -45,13 +59,14 @@ export default function AIModal() {
const handleSearch = () => { const handleSearch = () => {
generateOutline(prePrompt + content) generateOutline(prePrompt + content)
setContent('') setContent('')
setIsEditMessage(false)
} }
const [, copyToClipboard] = useCopyToClipboard() const [, copyToClipboard] = useCopyToClipboard()
// 复制内容 // 复制内容
const handleCopy = (content) => { const handleCopy = (msg) => {
copyToClipboard(content) copyToClipboard(getChaptersMarkdown(msg.chapters))
} }
// 生成论文 // 生成论文
...@@ -59,13 +74,26 @@ export default function AIModal() { ...@@ -59,13 +74,26 @@ export default function AIModal() {
setMessages((prevMessages) => { setMessages((prevMessages) => {
return [...prevMessages, { content: '正在生成长文...', role: 'ai', tips: '预计10分钟', queryID: msg.queryID }] return [...prevMessages, { content: '正在生成长文...', role: 'ai', tips: '预计10分钟', queryID: msg.queryID }]
}) })
const paper = await generatePaper({ userQuery: msg.userQuery, queryID: msg.queryID, outline: msg.content }) const paper = await generatePaper({
userQuery: msg.userQuery,
queryID: msg.queryID,
outline: getChaptersMarkdown(msg.chapters),
})
setMessages((prevMessages) => { setMessages((prevMessages) => {
prevMessages.pop() prevMessages.pop()
return [...prevMessages, { content: '已为您生成初稿,请点击下载', role: 'ai', queryID: msg.queryID, paper }] return [...prevMessages, { content: '已为您生成初稿,请点击下载', role: 'ai', queryID: msg.queryID, paper }]
}) })
} }
let chapterMenuItems = [
{ key: 'add', label: '新增', icon: <PlusCircleOutlined style={{ fontSize: 14 }} /> },
{ key: 'remove', label: '删除', icon: <DeleteOutlined style={{ fontSize: 14 }} /> },
]
const handleMenuClick = async (e, chapter, message) => {
setIsEditMessage(true)
if (e.key === 'add') addChapter(chapter, message)
if (e.key === 'remove') removeChapter(chapter, message)
}
const MessageRender = ({ msg }) => { const MessageRender = ({ msg }) => {
if (msg.role === 'ai') { if (msg.role === 'ai') {
if (msg.chapters && msg.chapters.length) { if (msg.chapters && msg.chapters.length) {
...@@ -73,11 +101,11 @@ export default function AIModal() { ...@@ -73,11 +101,11 @@ export default function AIModal() {
<div className={`message-item ${msg.role}`}> <div className={`message-item ${msg.role}`}>
<div className="message-box"> <div className="message-box">
<div className="message-content"> <div className="message-content">
{msg.chapters.map((item, index) => { {msg.chapters.map((item) => {
return ( return (
<div className="chapter-item" key={index}> <div className="chapter-item" key={item.id}>
<div className="chapter-left"> <div className="chapter-left">
<div className="chapter-left-title">{item.tag}</div> <div className="chapter-left-title">{chapterTagRender(item, msg.chapters)}</div>
<div className="line-dot"> <div className="line-dot">
<div className="dot"></div> <div className="dot"></div>
<div className="line"></div> <div className="line"></div>
...@@ -85,8 +113,33 @@ export default function AIModal() { ...@@ -85,8 +113,33 @@ export default function AIModal() {
</div> </div>
<div className="chapter-right"> <div className="chapter-right">
<div className="chapter-right-content"> <div className="chapter-right-content">
<h3>{item.title}</h3> <Input
<p>{item.desc}</p> className="chapter-title"
placeholder="请输入标题"
defaultValue={item.title}
variant="borderless"
onBlur={(e) => updateChapter(item, msg, { ...item, title: e.target.value })}
/>
{item.level !== 1 && (
<Input
className="chapter-desc"
placeholder="请输入你的备注,如这个章节必须包含正反观点等。"
defaultValue={item.desc}
variant="borderless"
onBlur={(e) => updateChapter(item, msg, { ...item, desc: e.target.value })}
/>
)}
{/* <h3>{item.title}</h3> */}
{/* <p>{item.desc}</p> */}
</div>
<div className="chapter-right-tools">
{item.level !== 1 && (
<Dropdown
menu={{ items: chapterMenuItems, onClick: (e) => handleMenuClick(e, item, msg) }}
getPopupContainer={(triggerNode) => triggerNode.parentNode}>
<Button type="text" icon={<CircleEllipsis color="#222" size={20} />}></Button>
</Dropdown>
)}
</div> </div>
</div> </div>
</div> </div>
...@@ -110,7 +163,7 @@ export default function AIModal() { ...@@ -110,7 +163,7 @@ export default function AIModal() {
onClick={() => handleGeneratePaper(msg)}> onClick={() => handleGeneratePaper(msg)}>
生成长文 生成长文
</Button> </Button>
<Button type="text" size="small" icon={<CopyOutlined />} onClick={() => handleCopy(msg.content)}> <Button type="text" size="small" icon={<CopyOutlined />} onClick={() => handleCopy(msg)}>
复制内容 复制内容
</Button> </Button>
</div> </div>
...@@ -163,8 +216,8 @@ export default function AIModal() { ...@@ -163,8 +216,8 @@ export default function AIModal() {
onCancel={() => setIsModalOpen(false)} onCancel={() => setIsModalOpen(false)}
width={1000}> width={1000}>
<div className="message-scroll" ref={messageScrollRef}> <div className="message-scroll" ref={messageScrollRef}>
{messages.map((msg, index) => { {messages.map((msg) => {
return <MessageRender msg={msg} key={index}></MessageRender> return <MessageRender msg={msg} key={msg.id}></MessageRender>
})} })}
</div> </div>
<div className="input-container"> <div className="input-container">
......
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论