diff --git a/src/config/api.js b/src/config/api.js index e231794..c8ec997 100644 --- a/src/config/api.js +++ b/src/config/api.js @@ -80,108 +80,53 @@ export const callDeepSeekAPI = async (messages, options = {}) => { return content } -// 本地服务调用 - 流式版本 + + +// 本地服务调用 - 非流式 export const callLocalChatAPI = async (prompt, onStreamData) => { const base = '/api/chat/stream' const url = `${base}?prompt=${encodeURIComponent(prompt)}` - // 逐步调试日志 - // eslint-disable-next-line no-console - console.debug('[callLocalChatAPI] url:', url) try { - // eslint-disable-next-line no-console - console.debug('[callLocalChatAPI] fetch start') const resp = await fetch(url, { method: 'GET' }) - // eslint-disable-next-line no-console - console.debug('[callLocalChatAPI] fetch done', { - ok: resp.ok, - status: resp.status, - statusText: resp.statusText, - headers: Object.fromEntries(resp.headers.entries()) - }) if (!resp.ok) { const txt = await resp.text().catch(() => null) - // eslint-disable-next-line no-console - console.error('[callLocalChatAPI] non-OK response body:', txt) const msg = txt || resp.statusText || `HTTP_${resp.status}` const err = new Error(msg) err.status = resp.status throw err } - // 流式读取响应 - const reader = resp.body.getReader() - const decoder = new TextDecoder() - let buffer = '' + //等待完整响应 + const responseText = await resp.text() + // console.log('API response text:', responseText) + + + // 解析响应内容 let thoughtContent = '' let messageContent = '' let currentEvent = '' - try { - while (true) { - const { done, value } = await reader.read() - if (done) break - - buffer += decoder.decode(value, { stream: true }) + // 按行处理响应 + const lines = responseText.split(/\r?\n/) + + for (const line of lines) { + if (line.startsWith('event:')) { + currentEvent = line.substring(6).trim() + } else if (line.startsWith('data:')) { + const data = line.substring(5) - // 按行处理缓冲区 - const lines = buffer.split(/\r?\n/) - buffer = lines.pop() || '' // 保留最后一行(可能不完整) - - for (const line of lines) { - if (line.startsWith('event:')) { - currentEvent = line.substring(6).trim() - } else if (line.startsWith('data:')) { - const data = line.substring(5) - - if (currentEvent === 'thought') { - thoughtContent += data - console.log('Thought data received:', data, 'Total thought:', thoughtContent) // 调试信息 - // 流式输出思考内容 - 立即传递新接收到的数据 - if (onStreamData) { - onStreamData({ - type: 'thought', - content: data, // 新接收到的数据 - totalContent: thoughtContent, // 累积的完整内容 - isComplete: false - }) - } - } else if (currentEvent === 'message') { - messageContent += data - console.log('Message data received:', data, 'Total message:', messageContent) // 调试信息 - // 流式输出消息内容 - 立即传递新接收到的数据 - if (onStreamData) { - onStreamData({ - type: 'message', - content: data, // 新接收到的数据 - totalContent: messageContent, // 累积的完整内容 - isComplete: false - }) - } - } else if (currentEvent === 'complete') { - // 完成信号 - if (onStreamData) { - onStreamData({ - type: 'complete', - content: '', - isComplete: true, - thoughtContent: thoughtContent, - messageContent: messageContent - }) - } - // 流式处理完成,直接返回null,避免重复处理 - return null - } - } + if (currentEvent === 'thought') { + thoughtContent += data + } else if (currentEvent === 'message') { + messageContent += data } } - } finally { - reader.releaseLock() } // 返回最终结果 - console.log('API returning:', { thought: thoughtContent, message: messageContent }) // 调试信息 + console.log('API returning:3333', { thought: thoughtContent, message: messageContent }) // 调试信息 // 确保返回的内容不为undefined return { diff --git a/src/pages/chatConversation/ChatConversation.js b/src/pages/chatConversation/ChatConversation.js index ee29865..02e67ee 100644 --- a/src/pages/chatConversation/ChatConversation.js +++ b/src/pages/chatConversation/ChatConversation.js @@ -43,75 +43,36 @@ function ChatConversation() { const [editModalVisible, setEditModalVisible] = useState(false) const [editingConversation, setEditingConversation] = useState(null) const [newTitle, setNewTitle] = useState('') - - // 流式输出状态 - const [streamingThought, setStreamingThought] = useState('') - const [streamingMessage, setStreamingMessage] = useState('') - const [isStreaming, setIsStreaming] = useState(false) - const [displayedThought, setDisplayedThought] = useState('') - const [displayedMessage, setDisplayedMessage] = useState('') - - // 流式显示控制 + const [deepThinkingEnabled, setDeepThinkingEnabled] = useState(false) + const [typingMessage, setTypingMessage] = useState('') const [isTyping, setIsTyping] = useState(false) + // 流式输出状态 - 已移除 + const messagesEndRef = useRef(null) const inputRef = useRef(null) const typewriterTimeoutRef = useRef(null) // 获取当前会话 const currentConversation = conversations.find(conv => conv.id === currentConversationId) - const currentMessages = currentConversation?.messages || [] - // 自动滚动到底部 - 禁用 + const currentMessages = currentConversation?.messages || [] // 当前会话消息 + + // 调试信息 + console.log('Current conversation state:', { + conversations: conversations.length, + currentConversationId, + currentConversation: !!currentConversation, + currentMessages: currentMessages.length + }) + + // console.log(currentMessages,"=========================333333") const chatScrollRef = useRef(null); - // useEffect(() => { - // if (chatScrollRef.current) { - // chatScrollRef.current.scrollTop = chatScrollRef.current.scrollHeight; - // } - // }, [currentMessages, loading]); // currentMessages 是你的消息数组 const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }) } - // 打字机效果函数 - const typewriterEffect = (targetText, setDisplayedText, delay = 20) => { - let currentIndex = 0 - const currentDisplayed = displayedThought + displayedMessage - - const typeNextChar = () => { - if (currentIndex < targetText.length) { - setDisplayedText(targetText.substring(0, currentIndex + 1)) - currentIndex++ - typewriterTimeoutRef.current = setTimeout(typeNextChar, delay) - } - } - - typeNextChar() - } - - // 监听流式内容变化,实现真正的流式显示 - useEffect(() => { - if (streamingThought && streamingThought !== displayedThought) { - // 直接显示新内容,实现真正的流式显示 - setDisplayedThought(streamingThought) - setIsTyping(true) - } - }, [streamingThought]) - - useEffect(() => { - if (streamingMessage && streamingMessage !== displayedMessage) { - // 直接显示新内容,实现真正的流式显示 - setDisplayedMessage(streamingMessage) - setIsTyping(true) - } - }, [streamingMessage]) - - // 当流式输出停止时,停止打字状态 - useEffect(() => { - if (!isStreaming) { - setIsTyping(false) - } - }, [isStreaming]) + // 流式输出相关函数 - 已移除 const handleChange = value => { @@ -138,9 +99,34 @@ function ChatConversation() { } }, []) - // useEffect(() => { - // scrollToBottom() - // }, [currentMessages]) + // 打字机效果函数 - 简化版本用于测试 + const typewriterEffect = (text, onComplete) => { + console.log('Typewriter effect started with text:', text) + let index = 0 + setTypingMessage('') + setIsTyping(true) + + const typeNextWords = () => { + if (index < text.length) { + // 简化:每次显示3个字符 + const nextIndex = Math.min(index + 3, text.length) + const currentText = text.substring(0, nextIndex) + console.log('Typing progress:', currentText) + setTypingMessage(currentText) + index = nextIndex + + // 500ms间隔 + typewriterTimeoutRef.current = setTimeout(typeNextWords, 500) + } else { + console.log('Typewriter effect completed') + setIsTyping(false) + onComplete(text) + } + } + + typeNextWords() + } + // 创建新对话 const createNewConversation = () => { @@ -195,60 +181,31 @@ function ChatConversation() { setInputValue('') setLoading(true) - setIsStreaming(true) - setStreamingThought('') - setStreamingMessage('') - setDisplayedThought('') - setDisplayedMessage('') try { - // 调用本地后端接口(流式版本) - const result = await callLocalChatAPI(messageText, (streamData) => { - console.log('Stream data received:', streamData) - if (streamData.type === 'thought') { - console.log('Setting streamingThought:', streamData.content) - // 使用totalContent作为完整内容,content作为新增内容 - setStreamingThought(streamData.totalContent || streamData.content) - } else if (streamData.type === 'message') { - console.log('Setting streamingMessage:', streamData.content) - // 使用totalContent作为完整内容,content作为新增内容 - setStreamingMessage(streamData.totalContent || streamData.content) - } else if (streamData.type === 'complete') { - // 流式输出完成,将最终内容添加到对话存储 - // 使用complete事件中传递的最终内容 - const finalThought = streamData.thoughtContent || streamingThought - const finalMessage = streamData.messageContent || streamingMessage - const finalContent = finalThought + (finalMessage ? '\n\n' + finalMessage : '') - - console.log('Complete event - finalThought:', finalThought) - console.log('Complete event - finalMessage:', finalMessage) - console.log('Complete event - finalContent:', finalContent) - - if (finalContent.trim()) { - conversationStore.addMessage('assistant', finalContent) - } else { - conversationStore.addMessage('assistant', '抱歉,我无法生成回复内容。') - } - - setIsStreaming(false) - setStreamingThought('') - setStreamingMessage('') - setDisplayedThought('') - setDisplayedMessage('') - } - }) - - // 如果API没有返回流式数据,直接处理结果 - if (result && !isStreaming) { - const thought = result?.thought || '' - const message = result?.message || '' - const finalContent = thought + (message ? '\n\n' + message : '') - - if (finalContent.trim()) { - conversationStore.addMessage('assistant', finalContent) - } else { - conversationStore.addMessage('assistant', '抱歉,我无法生成回复内容。') - } + // 调用本地后端接口(非流式版本) + const result = await callLocalChatAPI(messageText) + console.log('API result:', result) + + // 直接处理结果 + const thought = result?.thought || '' + const message = result?.message || '' + console.log('Processed content:', { thought, message, deepThinkingEnabled }) + + // 根据深度思考按钮状态决定是否包含思考内容 + const finalContent = deepThinkingEnabled + ? thought + (message ? '\n\n' + message : '') + : message + + console.log('Final content:', finalContent) + + if (finalContent.trim()) { + // 暂时直接添加消息,不使用打字机效果 + console.log('Adding message directly:', finalContent) + conversationStore.addMessage('assistant', finalContent) + } else { + console.log('No content, adding fallback message') + conversationStore.addMessage('assistant', '抱歉,我无法生成回复内容。') } } catch (error) { const errorMessage = handleAPIError(error) @@ -256,11 +213,6 @@ function ChatConversation() { // 添加错误消息到独立存储 conversationStore.addMessage('assistant', `抱歉,我遇到了一个问题:${errorMessage}`) - setIsStreaming(false) - setStreamingThought('') - setStreamingMessage('') - setDisplayedThought('') - setDisplayedMessage('') } finally { setLoading(false) } @@ -318,6 +270,17 @@ function ChatConversation() { // 渲染单条消息 ================================== const renderMessage = (msg, index) => { const isUser = msg.role === 'user' + const displayContent = msg.content || '' + + // 调试信息 + if (msg.role === 'assistant') { + console.log('Rendering assistant message:', { + index, + content: msg.content, + displayContent + }) + } + return (
{!isUser && (
- +
)} {isUser &&
} @@ -337,12 +300,13 @@ function ChatConversation() { {msg.timestamp ? (typeof msg.timestamp === 'string' ? msg.timestamp - : msg.timestamp.toLocaleString()) + : msg.timestamp.toLocaleString()) // 时间 : ''} {!isUser && ( - - + + {/* 复制按钮 */} +
- - - ) - } - - // 渲染流式输出消息 - const renderStreamingMessage = () => { - if (!isStreaming && !displayedThought && !displayedMessage) return null - - return ( -
-
- -
-
-
- AI对话 - 正在思考… -
- -
- {/* 思考内容 - 浅灰色 */} - {displayedThought && ( -
- - {displayedThought} - -
- )} - - {/* 回复内容 - 正常颜色 */} - {displayedMessage && ( -
- - {displayedMessage} - - {/* 流式输入光标 */} - {isTyping && isStreaming && ( - | - )} -
- )} - - {/* 流式输出指示器 */} - {isStreaming && ( -
- } - size='small' - /> - - {isTyping ? '正在输入...' : '正在思考...'} - + {displayContent ? ( + + {displayContent} + + ) : ( +
+ 暂无内容
)}
@@ -450,6 +361,7 @@ function ChatConversation() {
) } + // ================================================= return ( @@ -467,11 +379,8 @@ function ChatConversation() { {/* 历史消息 */} {currentMessages.map(renderMessage)} - {/* 流式输出消息 */} - {renderStreamingMessage()} - - {/* 加载状态(当没有流式输出时显示) */} - {loading && !isStreaming && ( + {/* 加载状态 */} + {loading && (
@@ -519,20 +428,16 @@ function ChatConversation() { />
- {/* 模型切换 */} - {/* */} + onClick={() => setDeepThinkingEnabled(!deepThinkingEnabled)} + > + 深度思考 + {/* 上传文件 */} @@ -561,9 +466,9 @@ function ChatConversation() {