Procházet zdrojové kódy

Merge branch 'dev' of http://192.168.0.3:3000/SD-SafeAI/shudao-main into dev

FanHong před 1 týdnem
rodič
revize
2310a0ec10

+ 4 - 0
.gitignore

@@ -31,6 +31,10 @@ shudao-go-backend/shudao-go-backend
 shudao-go-backend/shudao-go-backend.tar.gz
 shudao-go-backend/shudao-chat-go
 shudao-go-backend/shudao-chat-go.tar.gz
+shudao-go-backend/run.bat
+shudao-vue-frontend/run.bat
+
+
 
 # Backend Copied Assets (from frontend build)
 shudao-go-backend/assets/

+ 38 - 76
shudao-vue-frontend/src/views/Chat.vue

@@ -1824,80 +1824,10 @@ const handleSSEMessage = (data, aiMessageIndex) => {
         // 非专业问题,只输出summary字段内容并终止流程
         const summaryContent = data.summary || '抱歉,我暂时无法回答您的问题。'
 
-        // 只设置summary,不设置content和displayContent,避免重复显示
+        // 先缓存summary作为兜底内容,但继续等待online_answer/completed事件
         aiMessage.summary = summaryContent
-        aiMessage.isTyping = false // 停止加载动画
-
-        // 保存到数据库
-        if (aiMessage.ai_message_id) {
-          updateAIMessageContent(aiMessage.ai_message_id, summaryContent, summaryContent)
-            .catch(err => console.error('回写AI消息失败:', err))
-        }
-
-        // 关闭SSE连接
-        if (sseConnection) {
-          closeSSEConnection(sseConnection)
-          sseConnection = null
-        }
-
-        // 重置发送状态
-        isSending.value = false
-        streamingReports.value.clear()
-
-        // 重置AI回复流程状态
-        isAIReplyProcessComplete.value = true
-        
-        // ===== 🎯 非专业问题也要更新历史记录和获取推荐问题 =====
-        // 更新历史记录
-        if (ai_conversation_id.value && ai_conversation_id.value !== 0) {
-          // 先清除所有高亮
-          historyData.value.forEach((item) => {
-            item.isActive = false
-          })
-          
-          // 获取第一条用户消息作为标题
-          const firstUserMessage = chatMessages.value.find(msg => msg.type === 'user')
-          const title = firstUserMessage ? firstUserMessage.content.substring(0, 20) + '...' : '新对话'
-          
-          // 检查是否已存在
-          const existingIndex = historyData.value.findIndex(item => item.id === ai_conversation_id.value)
-          
-          if (existingIndex === -1) {
-            // 不存在,在最前面插入新项
-            const newItem = {
-              id: ai_conversation_id.value,
-              title: title,
-              time: formatTime(new Date().toISOString()),
-              businessType: 0,
-              isActive: true,
-              rawData: {
-                id: ai_conversation_id.value,
-                content: firstUserMessage?.content || '',
-                updated_at: new Date().toISOString()
-              }
-            }
-            historyData.value.unshift(newItem)
-            console.log('✅ 非专业问题:已在列表最前面插入新历史记录')
-          } else {
-            // 已存在,设为高亮并移到最前面
-            const existingItem = historyData.value.splice(existingIndex, 1)[0]
-            existingItem.isActive = true
-            existingItem.time = formatTime(new Date().toISOString())
-            historyData.value.unshift(existingItem)
-            console.log('✅ 非专业问题:已将历史记录移到最前面')
-          }
-          
-          // 更新历史记录总数
-          historyTotal.value = historyData.value.length
-        }
-        
-        // 获取推荐问题
-        const lastUserMessage = chatMessages.value.filter(msg => msg.type === 'user').pop()
-        if (lastUserMessage && aiMessage.ai_message_id && summaryContent) {
-          getAIRelatedQuestions(lastUserMessage.content, summaryContent, aiMessage.ai_message_id)
-        }
-        
-        return // 终止处理
+        aiMessage._fullSummary = summaryContent
+        break
       }
 
       // 专业问题:意图识别完成,更新为查询知识库状态
@@ -1924,6 +1854,38 @@ const handleSSEMessage = (data, aiMessageIndex) => {
         })
       }
       break
+
+    case 'online_answer': {
+      aiMessage.showStats = false
+      aiMessage.summary = ''
+
+      const finalContent = data.content || ''
+      aiMessage.content = finalContent
+
+      if (!finalContent.trim()) {
+        aiMessage.displayContent = ''
+        aiMessage.isTyping = false
+        break
+      }
+
+      const processedReply = processAIResponse(finalContent)
+      const renderedReply = renderMarkdownContent(processedReply)
+
+      startTypewriterEffect(aiMessage, renderedReply, 200)
+        .catch(err => {
+          console.error('在线回答打字机效果失败:', err)
+          aiMessage.displayContent = renderedReply
+          aiMessage.isTyping = false
+        })
+      break
+    }
+
+    case 'online_error':
+      aiMessage.showStats = false
+      aiMessage.content = data.message || '在线模型服务暂不可用'
+      aiMessage.displayContent = renderMarkdownContent(processAIResponse(aiMessage.content))
+      aiMessage.isTyping = false
+      break
       
     case 'documents':
       aiMessage.totalFiles = data.total
@@ -2328,7 +2290,7 @@ const handleSSEComplete = () => {
         
         const collectedContent = message.reports && message.reports.length > 0 
           ? JSON.stringify(contentData)
-          : message.content
+          : (message.content || message._fullSummary || message.summary || '')
         
         if (collectedContent) {
           // 同时保存summary字段(作为单独字段)
@@ -2482,7 +2444,7 @@ const handleSSEInterrupted = (data) => {
         
         const collectedContent = message.reports && message.reports.length > 0 
           ? JSON.stringify(contentData)
-          : message.content
+          : (message.content || message._fullSummary || message.summary || '')
         
         if (collectedContent) {
           // 同时保存summary字段(作为单独字段)
@@ -2549,7 +2511,7 @@ const handleStopGeneration = async () => {
         
         const collectedContent = message.reports && message.reports.length > 0 
           ? JSON.stringify(contentData)
-          : message.content
+          : (message.content || message._fullSummary || message.summary || '')
         
         if (collectedContent) {
           // 同时保存summary字段(作为单独字段)

+ 34 - 77
shudao-vue-frontend/src/views/mobile/m-Chat.vue

@@ -2475,80 +2475,10 @@ const handleSSEMessage = (data, aiMessageIndex) => {
         // 非专业问题,只输出summary字段内容并终止流程
         const summaryContent = data.summary || '抱歉,我暂时无法回答您的问题。'
 
-        // 只设置summary,不设置content和displayContent,避免重复显示
+        // 先缓存summary作为兜底内容,但继续等待online_answer/completed事件
         aiMessage.summary = summaryContent
-        aiMessage.isTyping = false // 停止加载动画
-
-        // 保存到数据库
-        if (aiMessage.ai_message_id) {
-          updateAIMessageContent(aiMessage.ai_message_id, summaryContent, summaryContent)
-            .catch(err => console.error('回写AI消息失败:', err))
-        }
-
-        // 关闭SSE连接
-        if (sseConnection) {
-          closeSSEConnection(sseConnection)
-          sseConnection = null
-        }
-
-        // 重置发送状态
-        isSending.value = false
-        streamingReports.value.clear()
-
-        // 重置AI回复流程状态
-        isAIReplyProcessComplete.value = true
-        
-        // ===== 🎯 非专业问题也要更新历史记录和获取推荐问题 =====
-        // 更新历史记录
-        if (ai_conversation_id.value && ai_conversation_id.value !== 0) {
-          // 先清除所有高亮
-          historyData.value.forEach((item) => {
-            item.isActive = false
-          })
-          
-          // 获取第一条用户消息作为标题
-          const firstUserMessage = chatMessages.value.find(msg => msg.type === 'user')
-          const title = firstUserMessage ? firstUserMessage.content.substring(0, 20) + '...' : '新对话'
-          
-          // 检查是否已存在
-          const existingIndex = historyData.value.findIndex(item => item.id === ai_conversation_id.value)
-          
-          if (existingIndex === -1) {
-            // 不存在,在最前面插入新项
-            const newItem = {
-              id: ai_conversation_id.value,
-              title: title,
-              time: formatTime(new Date().toISOString()),
-              businessType: 0,
-              isActive: true,
-              rawData: {
-                id: ai_conversation_id.value,
-                content: firstUserMessage?.content || '',
-                updated_at: new Date().toISOString()
-              }
-            }
-            historyData.value.unshift(newItem)
-            console.log('✅ 非专业问题:已在列表最前面插入新历史记录')
-          } else {
-            // 已存在,设为高亮并移到最前面
-            const existingItem = historyData.value.splice(existingIndex, 1)[0]
-            existingItem.isActive = true
-            existingItem.time = formatTime(new Date().toISOString())
-            historyData.value.unshift(existingItem)
-            console.log('✅ 非专业问题:已将历史记录移到最前面')
-          }
-          
-          // 更新历史记录总数
-          historyTotal.value = historyData.value.length
-        }
-        
-        // 获取推荐问题
-        const lastUserMessage = chatMessages.value.filter(msg => msg.type === 'user').pop()
-        if (lastUserMessage && aiMessage.ai_message_id && summaryContent) {
-          getAIRelatedQuestions(lastUserMessage.content, summaryContent, aiMessage.ai_message_id)
-        }
-        
-        return // 终止处理
+        aiMessage._fullSummary = summaryContent
+        break
       }
 
       // 专业问题:意图识别完成,更新为查询知识库状态
@@ -2575,6 +2505,32 @@ const handleSSEMessage = (data, aiMessageIndex) => {
         })
       }
       break
+
+    case 'online_answer': {
+      aiMessage.showStats = false
+      aiMessage.summary = ''
+
+      const finalContent = data.content || ''
+      aiMessage.content = finalContent
+
+      if (!finalContent.trim()) {
+        aiMessage.displayContent = ''
+        aiMessage.isTyping = false
+        break
+      }
+
+      const processedReply = processAIResponse(finalContent)
+      aiMessage.displayContent = renderMarkdownContent(processedReply)
+      aiMessage.isTyping = false
+      break
+    }
+
+    case 'online_error':
+      aiMessage.showStats = false
+      aiMessage.content = data.message || '在线模型服务暂不可用'
+      aiMessage.displayContent = renderMarkdownContent(processAIResponse(aiMessage.content))
+      aiMessage.isTyping = false
+      break
       
     case 'documents':
       aiMessage.totalFiles = data.total
@@ -2986,7 +2942,7 @@ const handleSSEComplete = () => {
         
         const collectedContent = message.reports && message.reports.length > 0 
           ? JSON.stringify(contentData)
-          : message.content
+          : (message.content || message._fullSummary || message.summary || '')
         
         if (collectedContent) {
           // 同时保存summary字段(作为单独字段)
@@ -3142,7 +3098,7 @@ const handleSSEInterrupted = (data) => {
         
         const collectedContent = message.reports && message.reports.length > 0 
           ? JSON.stringify(contentData)
-          : message.content
+          : (message.content || message._fullSummary || message.summary || '')
         
         if (collectedContent) {
           // 同时保存summary字段(作为单独字段)
@@ -3201,7 +3157,7 @@ const handleStopGeneration = async () => {
         
         const collectedContent = message.reports && message.reports.length > 0 
           ? JSON.stringify(contentData)
-          : message.content
+          : (message.content || message._fullSummary || message.summary || '')
         
         if (collectedContent) {
           // 同时保存summary字段(作为单独字段)
@@ -3271,7 +3227,8 @@ const handleReportGeneratorSubmit = async (data) => {
       window_size: data.windowSize,
       n_results: 2,
       ai_conversation_id: ai_conversation_id.value,
-      is_network_search_enabled: isNetworkSearchEnabled.value
+      is_network_search_enabled: isNetworkSearchEnabled.value,
+      user_id: userId || 1 // 测试时可直接写死 1
     }
 
     console.log('📤 发起 SSE POST 请求:', {