|
|
|
|
@ -47,6 +47,13 @@ function ChatConversation() {
|
|
|
|
|
const [typingMessage, setTypingMessage] = useState('')
|
|
|
|
|
const [isTyping, setIsTyping] = useState(false)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [streamingContent, setStreamingContent] = useState('')
|
|
|
|
|
const [isStreaming, setIsStreaming] = useState(false)
|
|
|
|
|
const [currentStreamingMessageId, setCurrentStreamingMessageId] = useState(null)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 流式输出状态 - 已移除
|
|
|
|
|
|
|
|
|
|
const messagesEndRef = useRef(null)
|
|
|
|
|
@ -127,6 +134,36 @@ function ChatConversation() {
|
|
|
|
|
typeNextWords()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 模拟流式效果
|
|
|
|
|
const simulateStreamingEffect = (fullContent, messageId) => {
|
|
|
|
|
setIsStreaming(true)
|
|
|
|
|
setStreamingContent('')
|
|
|
|
|
|
|
|
|
|
let currentIndex = 0
|
|
|
|
|
const chunkSize = 3 // 每次显示3个字符
|
|
|
|
|
const delay = 50 // 50ms间隔,可以调整速度
|
|
|
|
|
|
|
|
|
|
const streamNext = () => {
|
|
|
|
|
if (currentIndex < fullContent.length) {
|
|
|
|
|
const nextIndex = Math.min(currentIndex + chunkSize, fullContent.length)
|
|
|
|
|
const currentContent = fullContent.substring(0, nextIndex)
|
|
|
|
|
|
|
|
|
|
setStreamingContent(currentContent)
|
|
|
|
|
conversationStore.updateMessage(messageId, currentContent)
|
|
|
|
|
|
|
|
|
|
currentIndex = nextIndex
|
|
|
|
|
setTimeout(streamNext, delay)
|
|
|
|
|
} else {
|
|
|
|
|
// 流式效果完成
|
|
|
|
|
setIsStreaming(false)
|
|
|
|
|
setStreamingContent('')
|
|
|
|
|
setCurrentStreamingMessageId(null)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
streamNext()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建新对话
|
|
|
|
|
const createNewConversation = () => {
|
|
|
|
|
@ -183,7 +220,7 @@ function ChatConversation() {
|
|
|
|
|
setLoading(true)
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 调用本地后端接口(非流式版本)
|
|
|
|
|
// 调用本地后端接口
|
|
|
|
|
const result = await callLocalChatAPI(messageText)
|
|
|
|
|
console.log('API result:', result)
|
|
|
|
|
|
|
|
|
|
@ -200,9 +237,12 @@ function ChatConversation() {
|
|
|
|
|
console.log('Final content:', finalContent)
|
|
|
|
|
|
|
|
|
|
if (finalContent.trim()) {
|
|
|
|
|
// 暂时直接添加消息,不使用打字机效果
|
|
|
|
|
console.log('Adding message directly:', finalContent)
|
|
|
|
|
conversationStore.addMessage('assistant', finalContent)
|
|
|
|
|
// 先添加一个空的助手消息
|
|
|
|
|
const assistantMessageId = conversationStore.addMessage('assistant', '')
|
|
|
|
|
setCurrentStreamingMessageId(assistantMessageId)
|
|
|
|
|
|
|
|
|
|
// 开始模拟流式效果
|
|
|
|
|
simulateStreamingEffect(finalContent, assistantMessageId)
|
|
|
|
|
} else {
|
|
|
|
|
console.log('No content, adding fallback message')
|
|
|
|
|
conversationStore.addMessage('assistant', '抱歉,我无法生成回复内容。')
|
|
|
|
|
@ -270,14 +310,22 @@ function ChatConversation() {
|
|
|
|
|
// 渲染单条消息 ==================================
|
|
|
|
|
const renderMessage = (msg, index) => {
|
|
|
|
|
const isUser = msg.role === 'user'
|
|
|
|
|
const displayContent = msg.content || ''
|
|
|
|
|
|
|
|
|
|
// 如果是当前正在流式输出的消息,显示流式内容
|
|
|
|
|
const isCurrentStreaming = isStreaming &&
|
|
|
|
|
currentStreamingMessageId === msg.id &&
|
|
|
|
|
msg.role === 'assistant'
|
|
|
|
|
|
|
|
|
|
const displayContent = isCurrentStreaming ? streamingContent : (msg.content || '')
|
|
|
|
|
|
|
|
|
|
// 调试信息
|
|
|
|
|
if (msg.role === 'assistant') {
|
|
|
|
|
console.log('Rendering assistant message:', {
|
|
|
|
|
index,
|
|
|
|
|
content: msg.content,
|
|
|
|
|
displayContent
|
|
|
|
|
displayContent,
|
|
|
|
|
isCurrentStreaming,
|
|
|
|
|
streamingContent
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|