|  |  | @ -47,6 +47,13 @@ function ChatConversation() { | 
			
		
	
		
		
			
				
					
					|  |  |  |   const [typingMessage, setTypingMessage] = useState('') |  |  |  |   const [typingMessage, setTypingMessage] = useState('') | 
			
		
	
		
		
			
				
					
					|  |  |  |   const [isTyping, setIsTyping] = useState(false) |  |  |  |   const [isTyping, setIsTyping] = useState(false) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   const [streamingContent, setStreamingContent] = useState('') | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const [isStreaming, setIsStreaming] = useState(false) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const [currentStreamingMessageId, setCurrentStreamingMessageId] = useState(null) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   // 流式输出状态 - 已移除
 |  |  |  |   // 流式输出状态 - 已移除
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   const messagesEndRef = useRef(null) |  |  |  |   const messagesEndRef = useRef(null) | 
			
		
	
	
		
		
			
				
					|  |  | @ -127,6 +134,36 @@ function ChatConversation() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     typeNextWords() |  |  |  |     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 = () => { |  |  |  |   const createNewConversation = () => { | 
			
		
	
	
		
		
			
				
					|  |  | @ -183,7 +220,7 @@ function ChatConversation() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     setLoading(true) |  |  |  |     setLoading(true) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     try { |  |  |  |     try { | 
			
		
	
		
		
			
				
					
					|  |  |  |       // 调用本地后端接口(非流式版本)
 |  |  |  |       // 调用本地后端接口
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       const result = await callLocalChatAPI(messageText) |  |  |  |       const result = await callLocalChatAPI(messageText) | 
			
		
	
		
		
			
				
					
					|  |  |  |       console.log('API result:', result) |  |  |  |       console.log('API result:', result) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -200,9 +237,12 @@ function ChatConversation() { | 
			
		
	
		
		
			
				
					
					|  |  |  |       console.log('Final content:', finalContent) |  |  |  |       console.log('Final content:', finalContent) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (finalContent.trim()) { |  |  |  |       if (finalContent.trim()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         // 暂时直接添加消息,不使用打字机效果
 |  |  |  |         // 先添加一个空的助手消息
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         console.log('Adding message directly:', finalContent) |  |  |  |         const assistantMessageId = conversationStore.addMessage('assistant', '') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         conversationStore.addMessage('assistant', finalContent) |  |  |  |         setCurrentStreamingMessageId(assistantMessageId) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // 开始模拟流式效果
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         simulateStreamingEffect(finalContent, assistantMessageId) | 
			
		
	
		
		
			
				
					
					|  |  |  |       } else { |  |  |  |       } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |         console.log('No content, adding fallback message') |  |  |  |         console.log('No content, adding fallback message') | 
			
		
	
		
		
			
				
					
					|  |  |  |         conversationStore.addMessage('assistant', '抱歉,我无法生成回复内容。') |  |  |  |         conversationStore.addMessage('assistant', '抱歉,我无法生成回复内容。') | 
			
		
	
	
		
		
			
				
					|  |  | @ -270,14 +310,22 @@ function ChatConversation() { | 
			
		
	
		
		
			
				
					
					|  |  |  |   // 渲染单条消息 ==================================
 |  |  |  |   // 渲染单条消息 ==================================
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   const renderMessage = (msg, index) => { |  |  |  |   const renderMessage = (msg, index) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |     const isUser = msg.role === 'user' |  |  |  |     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') { |  |  |  |     if (msg.role === 'assistant') { | 
			
		
	
		
		
			
				
					
					|  |  |  |       console.log('Rendering assistant message:', {  |  |  |  |       console.log('Rendering assistant message:', {  | 
			
		
	
		
		
			
				
					
					|  |  |  |         index,  |  |  |  |         index,  | 
			
		
	
		
		
			
				
					
					|  |  |  |         content: msg.content,  |  |  |  |         content: msg.content,  | 
			
		
	
		
		
			
				
					
					|  |  |  |         displayContent |  |  |  |         displayContent, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         isCurrentStreaming, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         streamingContent | 
			
		
	
		
		
			
				
					
					|  |  |  |       }) |  |  |  |       }) | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |      |  |  |  |      | 
			
		
	
	
		
		
			
				
					|  |  | 
 |