提交 9ee0bb8c authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 5aa3bc6d
import React, { useState, useEffect, useCallback } from 'react'; import React, { useState, useEffect, useCallback } from 'react'
import { SendOutlined } from '@ant-design/icons'; import { SendOutlined } from '@ant-design/icons'
import { Input, Space, Button, message } from 'antd'; import { Input, Space, Button, message } from 'antd'
import md5 from 'js-md5'; import md5 from 'js-md5'
import dayjs from 'dayjs'; import dayjs from 'dayjs'
import { sleep } from '@/utils/common'; import { sleep } from '@/utils/common'
import './index.less'; import './index.less'
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux'
import { setEditorAi } from '@/store/modules/editor'; import { setEditorAi } from '@/store/modules/editor'
import normalAvatar from '@/assets/images/icon-normal-avatar.png'; import normalAvatar from '@/assets/images/icon-normal-avatar.png'
const UUID = 'f3846153ba784b6d86bdcd5533259c88'; const UUID = 'f3846153ba784b6d86bdcd5533259c88'
const auth_key = 'f3846153ba784b6d86bdcd5533259c88'; const auth_key = 'f3846153ba784b6d86bdcd5533259c88'
const auth_secret = 'HO4IyLEwEOHpeOXBxaLQUOqWslJRGs1M'; const auth_secret = 'HO4IyLEwEOHpeOXBxaLQUOqWslJRGs1M'
const AIDrawerComponent = (props) => { const AIDrawerComponent = props => {
const { selectText } = props; const { selectText } = props
const dispatch = useDispatch(); const dispatch = useDispatch()
const { userInfo } = useSelector((state) => state.user); // 用户状态信息 const { userInfo } = useSelector(state => state.user) // 用户状态信息
const { editorAi } = useSelector((state) => state.editor); // ai信息设置 const { editorAi } = useSelector(state => state.editor) // ai信息设置
const [value, setValue] = useState(selectText); // 输入值 const [value, setValue] = useState(selectText) // 输入值
const [loading, setLoading] = useState(false); // loading const [loading, setLoading] = useState(false) // loading
const [chatId, setChatId] = useState(null); // 对话的id const [chatId, setChatId] = useState(null) // 对话的id
const [chatContentList, setChatContentList] = useState([]); // 对话数据 const [chatContentList, setChatContentList] = useState([]) // 对话数据
const element = document.querySelector('#chat-content'); const element = document.querySelector('#chat-content')
let str = ''; let str = ''
useEffect(() => { useEffect(() => {
if (editorAi && Object.entries(editorAi).length > 0) { if (editorAi && Object.entries(editorAi).length > 0) {
let tempJSON = JSON.parse(JSON.stringify(chatContentList)); let tempJSON = JSON.parse(JSON.stringify(chatContentList))
let conversationId = editorAi.conversationId; let conversationId = editorAi.conversationId
const item = tempJSON.filter((item) => item.conversationId === conversationId); const item = tempJSON.filter(item => item.conversationId === conversationId)
if (item && item.length > 0) { if (item && item.length > 0) {
tempJSON[tempJSON.length - 1] = editorAi; tempJSON[tempJSON.length - 1] = editorAi
} else { } else {
tempJSON.push(editorAi); tempJSON.push(editorAi)
} }
setChatId(editorAi.chatId); setChatId(editorAi.chatId)
setChatContentList(tempJSON); setChatContentList(tempJSON)
element.scrollTo(0, 999999); element.scrollTo(0, 999999)
} else { } else {
setLoading(false); setLoading(false)
} }
}, [editorAi]); }, [editorAi])
useEffect(() => { useEffect(() => {
if (selectText) { if (selectText) {
targetChat(); targetChat()
} }
return () => { return () => {
setValue(''); setValue('')
setChatContentList([]); setChatContentList([])
setChatId(null); setChatId(null)
}; }
}, []); }, [])
let cData = []; let cData = []
let buffer = ''; let buffer = ''
const readBuffer = (reader, decoder) => { const readBuffer = (reader, decoder) => {
return reader.read().then(async ({ done, value }) => { return reader.read().then(async ({ done, value }) => {
if (done) { if (done) {
// 处理最后的缓冲数据 // 处理最后的缓冲数据
setLoading(false); setLoading(false)
setValue(''); setValue('')
dispatch(setEditorAi({})); dispatch(setEditorAi({}))
str = ''; str = ''
processBuffer(buffer); processBuffer(buffer)
return; return
} }
await sleep(80); await sleep(80)
buffer += decoder.decode(value, { stream: true }); buffer += decoder.decode(value, { stream: true })
// 检查缓冲区中是否有完整的消息 // 检查缓冲区中是否有完整的消息
const messages = buffer.split('\n\n'); // 假设每个消息以换行符结束 const messages = buffer.split('\n\n') // 假设每个消息以换行符结束
messages.forEach((message, index) => { messages.forEach((message, index) => {
if (index < messages.length - 1) { if (index < messages.length - 1) {
processBuffer(message); processBuffer(message)
} }
}); })
buffer = messages[messages.length - 1]; // 更新缓冲区 buffer = messages[messages.length - 1] // 更新缓冲区
readBuffer(reader, decoder); readBuffer(reader, decoder)
}); })
}; }
const processBuffer = (text) => { const processBuffer = text => {
let aiContent = {}; let aiContent = {}
try { try {
const content = text.replace(/\n+/g, '').split('data:'); const content = text.replace(/\n+/g, '').split('data:')
if (content instanceof Array) { if (content instanceof Array) {
const itemContent = JSON.parse(content[1]); const itemContent = JSON.parse(content[1])
if (!(itemContent.finish && itemContent.finish === true)) { if (!(itemContent.finish && itemContent.finish === true)) {
str += itemContent.content; str += itemContent.content
aiContent = { aiContent = {
type: 'ai', type: 'ai',
content: str, content: str,
chatId: itemContent.chatId, chatId: itemContent.chatId,
avatar: itemContent.role.avatar, avatar: itemContent.role.avatar,
conversationId: itemContent.conversationId, conversationId: itemContent.conversationId
}; }
dispatch(setEditorAi(aiContent)); dispatch(setEditorAi(aiContent))
} }
} }
} catch {} } catch {}
}; }
// 提交对话 // 提交对话
const targetChat = async () => { const targetChat = async () => {
if (value) { if (value) {
setLoading(true); setLoading(true)
const timestamp = Date.now(); const timestamp = Date.now()
fetch('/openapi/agent/chat/stream/v1', { fetch('/api/tiangong/openapi/agent/chat/stream/v1', {
method: 'POST', method: 'POST',
responseType: 'stream', // 设置响应类型为 'stream' responseType: 'stream', // 设置响应类型为 'stream'
headers: { headers: {
...@@ -120,105 +120,96 @@ const AIDrawerComponent = (props) => { ...@@ -120,105 +120,96 @@ const AIDrawerComponent = (props) => {
authKey: auth_key, authKey: auth_key,
timestamp: timestamp, timestamp: timestamp,
sign: md5(`${auth_key}${auth_secret}${timestamp}`), sign: md5(`${auth_key}${auth_secret}${timestamp}`),
stream: true, // or change to "false" 不处理流式返回内容 stream: true // or change to "false" 不处理流式返回内容
}, },
body: JSON.stringify({ body: JSON.stringify({
agentId: UUID, agentId: UUID,
chatId: chatId, chatId: chatId,
userChatInput: value, userChatInput: value
}), }),
mode: 'cors', mode: 'cors'
}) })
.then((response) => { .then(response => {
// response.body 是一个 ReadableStream 对象 // response.body 是一个 ReadableStream 对象
const stream = response.body; const stream = response.body
// 使用流式数据 // 使用流式数据
const reader = stream.getReader(); const reader = stream.getReader()
const decoder = new TextDecoder(); // 用于解码二进制数据流 const decoder = new TextDecoder() // 用于解码二进制数据流
let userContent = { let userContent = {
type: 'user', type: 'user',
content: value, content: value,
time: Date.now(), time: Date.now()
}; }
let tempJSON = JSON.parse(JSON.stringify(chatContentList)); let tempJSON = JSON.parse(JSON.stringify(chatContentList))
tempJSON.push(userContent); tempJSON.push(userContent)
setChatContentList(tempJSON); setChatContentList(tempJSON)
// 开始读取流数据 // 开始读取流数据
readBuffer(reader, decoder); readBuffer(reader, decoder)
}) })
.catch((error) => { .catch(error => {
// 处理请求错误 // 处理请求错误
console.error('Request failed:', error); console.error('Request failed:', error)
}); })
} else { } else {
message.error('请输入对话内容!'); message.error('请输入对话内容!')
} }
}; }
return ( return (
<div className='ai-drawer-content'> <div className="ai-drawer-content">
<div className='ai-chat-container'> <div className="ai-chat-container">
<div className='chat-content' id='chat-content'> <div className="chat-content" id="chat-content">
<div className='chat-content-padd'> <div className="chat-content-padd">
{chatContentList && {chatContentList &&
chatContentList.length > 0 && chatContentList.length > 0 &&
chatContentList.map((item, index) => { chatContentList.map((item, index) => {
return ( return (
<div className={`chat-content-item`} key={index}> <div className={`chat-content-item`} key={index}>
{item.type === 'user' && ( {item.type === 'user' && <div className="time">{dayjs(item.time).format('YYYY-MM-DD HH:mm')}</div>}
<div className='time'>{dayjs(item.time).format('YYYY-MM-DD HH:mm')}</div>
)}
{item.type === 'ai' && ( {item.type === 'ai' && (
<div className='inside'> <div className="inside">
<div className='ai-in-content'> <div className="ai-in-content">
<div className='img'> <div className="img">
<img src={item.avatar} alt='' /> <img src={item.avatar} alt="" />
</div> </div>
<div className='ask-content'>{item.content}</div> <div className="ask-content">{item.content}</div>
</div> </div>
</div> </div>
)} )}
{item.type === 'user' && ( {item.type === 'user' && (
<div className='inside inside-user'> <div className="inside inside-user">
<div className='user-in-content'> <div className="user-in-content">
<div className='ask-content'>{item.content}</div> <div className="ask-content">{item.content}</div>
<div className='img'> <div className="img">
<img src={userInfo.pic ? userInfo.pic : normalAvatar} alt='用户头像' /> <img src={userInfo.pic ? userInfo.pic : normalAvatar} alt="用户头像" />
</div> </div>
</div> </div>
</div> </div>
)} )}
</div> </div>
); )
})} })}
</div> </div>
</div> </div>
</div> </div>
<div className='ai-chat-ask'> <div className="ai-chat-ask">
<div className='text'> <div className="text">
<Input.TextArea <Input.TextArea
value={value} value={value}
defaultValue={value} defaultValue={value}
allowClear allowClear
disabled={loading} disabled={loading}
onChange={(e) => setValue(e.target.value)} onChange={e => setValue(e.target.value)}
palceholder='请输入内容' palceholder="请输入内容"
style={{ height: '80px', resize: 'none' }} style={{ height: '80px', resize: 'none' }}></Input.TextArea>
></Input.TextArea>
</div> </div>
<div className='button'> <div className="button">
<Button <Button type="primary" icon={<SendOutlined />} loading={loading} size="large" onClick={targetChat}></Button>
type='primary'
icon={<SendOutlined />}
loading={loading}
size='large'
onClick={targetChat}
></Button>
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default AIDrawerComponent; export default AIDrawerComponent
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论