diff --git a/src/components/Dashboard.vue b/src/components/Dashboard.vue index 69cebdb..b7635a8 100644 --- a/src/components/Dashboard.vue +++ b/src/components/Dashboard.vue @@ -250,38 +250,29 @@ const chatMessages = ref([ // DeepSeek API 调用函数 const sendMessage = async () => { - if (!userInput.value.trim() || isLoading.value) return - + if (!userInput.value.trim() || isLoading.value) return; + // 添加用户消息到对话 - const userMessage = userInput.value.trim() - chatMessages.value.push({ role: 'user', content: userMessage }) - userInput.value = '' - - // 滚动到底部 - await nextTick() - if (chatMessagesRef.value) { - chatMessagesRef.value.scrollTop = chatMessagesRef.value.scrollHeight - } - - // 设置加载状态 - isLoading.value = true - + const userMessage = userInput.value.trim(); + chatMessages.value.push({ role: 'user', content: userMessage }); + userInput.value = ''; + + // 立即滚动到底部(用户消息) + await nextTick(); + scrollToBottom(); + + // 设置加载状态并添加占位消息 + isLoading.value = true; + chatMessages.value.push({ role: 'assistant', content: '思考中...' }); + const aiMessageIndex = chatMessages.value.length - 1; + try { - // 准备发送到 DeepSeek API 的消息历史 - const apiMessages = [ - { role: 'system', content: '' } - ] - - // 添加最近的10条消息历史(如果有的话) - const recentMessages = chatMessages.value.slice(-10) - recentMessages.forEach(msg => { - apiMessages.push({ - role: msg.role === 'assistant' ? 'assistant' : 'user', - content: msg.content - }) - }) - - // 调用 DeepSeek API + // 只保留最近5条消息以优化性能 + const apiMessages = chatMessages.value + .slice(-5) + .map(msg => ({ role: msg.role, content: msg.content })); + + // 调用API(启用流式传输) const response = await fetch('https://api.deepseek.com/chat/completions', { method: 'POST', headers: { @@ -291,36 +282,59 @@ const sendMessage = async () => { body: JSON.stringify({ model: 'deepseek-chat', messages: apiMessages, - stream: false + stream: true // 关键优化:启用流式响应 }) - }) - + }); + if (!response.ok) { - throw new Error('API请求失败') + throw new Error(`API错误: ${response.status}`); + } + + // 流式处理数据 + const reader = response.body.getReader(); + let fullResponse = ''; + const decoder = new TextDecoder(); + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + // 解析流式数据(假设API返回ndjson格式) + const chunk = decoder.decode(value); + const lines = chunk.split('\n').filter(line => line.trim()); + + for (const line of lines) { + try { + const data = JSON.parse(line.replace('data: ', '')); + if (data.choices?.[0]?.delta?.content) { + fullResponse += data.choices[0].delta.content; + // 实时更新UI(逐字显示) + chatMessages.value[aiMessageIndex].content = md.render(fullResponse); + scrollToBottom(); + } + } catch (e) { + console.warn('解析流数据失败:', e); + } + } } - - const data = await response.json() - const aiResponse = data.choices && data.choices[0]?.message?.content || '抱歉,我无法回答这个问题。' - - const aiResponseHtml = md.render(aiResponse) - // 添加AI回复到对话 - chatMessages.value.push({ role: 'assistant', content: aiResponseHtml }) - } catch (error) { - console.error('DeepSeek API调用失败:', error) - chatMessages.value.push({ role: 'assistant', content: '抱歉,我遇到了技术问题,请稍后再试。' }) + console.error('请求失败:', error); + chatMessages.value[aiMessageIndex].content = '抱歉,回答时遇到问题,请重试。'; } finally { - isLoading.value = false - - // 滚动到底部 - await nextTick() - if (chatMessagesRef.value) { - chatMessagesRef.value.scrollTop = chatMessagesRef.value.scrollHeight - } + isLoading.value = false; + scrollToBottom(); } -} +}; +// 滚动辅助函数 +const scrollToBottom = () => { + nextTick().then(() => { + if (chatMessagesRef.value) { + chatMessagesRef.value.scrollTop = chatMessagesRef.value.scrollHeight; + } + }); +}; // 研究经费图例状态 const fundingLegendStatus = ref([true, true, true])