159 lines
4.6 KiB
TypeScript
159 lines
4.6 KiB
TypeScript
import { cacheGet, getUserInfo } from '@/utils/cacheUtil'
|
||
import { LoadingOutlined } from '@ant-design/icons'
|
||
import { CopilotKit, useCopilotChatInternal as useCopilotChat } from '@copilotkit/react-core'
|
||
import { Flex, Mentions, Spin } from 'antd'
|
||
import { useCallback, useState } from 'react'
|
||
|
||
const Chat: React.FC = () => {
|
||
const [currentAppKey, setCurrentAppKey] = useState<string>('')
|
||
const [newMessage, setNewMessage] = useState('')
|
||
const { messages, sendMessage, setMessages, isLoading, reloadMessages, stopGeneration } = useCopilotChat()
|
||
const callSendMessage = useCallback(
|
||
async (message: string) => {
|
||
await sendMessage({
|
||
id: new Date().getTime() + '',
|
||
role: 'user',
|
||
content: message
|
||
})
|
||
},
|
||
[sendMessage]
|
||
)
|
||
|
||
const handleSendMessage = useCallback(() => {
|
||
// 提前存好本次的提问内容,重新生成的话直接从缓存中获取之前的提问内容
|
||
let question: string = newMessage || ''
|
||
const token = cacheGet('token')
|
||
const tenantId = cacheGet('tenantId')
|
||
let conversation_id = ''
|
||
if (messages[1]?.id) {
|
||
conversation_id = messages[1]?.id.split('_')[0]
|
||
}
|
||
const userInfo = getUserInfo()
|
||
const difyJson = {
|
||
inputs: {
|
||
Token: token || '',
|
||
tenantid: tenantId || '',
|
||
query: question
|
||
},
|
||
appKey: currentAppKey,
|
||
files: [],
|
||
user: userInfo?.id || 'anonymous',
|
||
query: question,
|
||
conversation_id
|
||
}
|
||
// 设置好目前状态下的聊天列表数据,包含之前已经结束的沟通内容,以及本次用户的提问,本次AI的回答占位
|
||
callSendMessage(JSON.stringify(difyJson))
|
||
setNewMessage('')
|
||
}, [callSendMessage, newMessage, currentAppKey])
|
||
|
||
const handleParse = (jsonStr: string) => {
|
||
let res = ''
|
||
try {
|
||
const parsed = JSON.parse(jsonStr)
|
||
res = parsed?.query
|
||
} catch (e) {}
|
||
return res
|
||
}
|
||
|
||
// 换行
|
||
const handleNewline = () => {
|
||
setNewMessage(prevValue => `${prevValue}\n`)
|
||
}
|
||
const handleKeyDown = async (e: any) => {
|
||
e.stopPropagation()
|
||
const res = await cacheGet('sendMessage')
|
||
if (e.key === 'Enter') {
|
||
if (e.ctrlKey) {
|
||
if (newMessage) {
|
||
if (res === 'ctrlEnter') {
|
||
handleSendMessage()
|
||
} else {
|
||
handleNewline()
|
||
}
|
||
}
|
||
} else {
|
||
if (res === 'Enter' || !res) {
|
||
if (newMessage) {
|
||
handleSendMessage()
|
||
} else {
|
||
setNewMessage('')
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return (
|
||
<>
|
||
{messages.map((message, index) => {
|
||
const userMessageId = message.id
|
||
// 实际的会话消息
|
||
return (
|
||
<Flex key={index} vertical data-message-id={userMessageId}>
|
||
{/* 用户提问 */}
|
||
{message.role === 'user' && <Flex key={message.id}>{handleParse(message.content as string) ?? ''}</Flex>}
|
||
|
||
{message.role === 'assistant' && (
|
||
<div>
|
||
<div
|
||
style={{
|
||
width: 'calc(100% - 20px)',
|
||
marginLeft: '20px'
|
||
}}
|
||
>
|
||
<Flex>
|
||
{isLoading && !message.content && index === messages.length - 1 && (
|
||
<Flex>
|
||
<Spin indicator={<LoadingOutlined />} />
|
||
<span>检索中</span>
|
||
</Flex>
|
||
)}
|
||
{message.content ?? ''}
|
||
</Flex>
|
||
{message?.generativeUI?.()}
|
||
</div>
|
||
</div>
|
||
)}
|
||
</Flex>
|
||
)
|
||
})}
|
||
<div className='p-4'>
|
||
<Mentions
|
||
autoFocus
|
||
open={false}
|
||
placeholder='请输入内容'
|
||
rows={4}
|
||
value={newMessage}
|
||
maxLength={10000}
|
||
onKeyDown={handleKeyDown}
|
||
options={[]}
|
||
onInput={e => {
|
||
const value = (e.target as HTMLInputElement).value
|
||
// 检查内容是否只包含空格或回车符
|
||
if (/^\s*$/.test(value)) {
|
||
setNewMessage('') // 如果只包含空格或回车符,清空输入框
|
||
} else {
|
||
setNewMessage(value) // 否则更新输入内容
|
||
}
|
||
}}
|
||
/>
|
||
</div>
|
||
</>
|
||
)
|
||
}
|
||
|
||
const Test2: React.FC = () => {
|
||
return (
|
||
<CopilotKit
|
||
runtimeUrl='/agui-api/copilotkit/dify'
|
||
showDevConsole={false}
|
||
// publicApiKey={'ck_pub_cc922145a5da9b8513bc10df473cd6f7'}
|
||
agent='agentic_chat_metadata'
|
||
>
|
||
<Chat />
|
||
</CopilotKit>
|
||
)
|
||
}
|
||
|
||
export default Test2
|