yangg vor 6 Tagen
Ursprung
Commit
1525c9b7ce

+ 1 - 1
.env.development

@@ -1,4 +1,4 @@
 NODE_ENV=development
 #http://192.168.100.187:8062 
-VITE_BASE_AI_API=https://aiapi.raycos.com.cn
+VITE_BASE_AI_API=http://192.168.100.187:8062
 VITE_BASE_AI_F_API=http://58.246.234.210:8082

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
dist/assets/demo-qRY2l7XB.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
dist/assets/forget-password-CO8qQtid.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 1
dist/assets/index-CdtYsOh6.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
dist/assets/login-C1G5yNPb.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
dist/assets/register-CyO4CM8G.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
dist/assets/report-Bl-GN4UW.css


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
dist/assets/report-Ci4CgcF5.js


Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
dist/assets/report-DvfkzKQU.js


+ 1 - 1
dist/index.html

@@ -5,7 +5,7 @@
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title></title>
-    <script type="module" crossorigin src="/assets/index-1NK5551A.js"></script>
+    <script type="module" crossorigin src="/assets/index-CdtYsOh6.js"></script>
     <link rel="modulepreload" crossorigin href="/assets/vendor-BfKWghV4.js">
     <link rel="stylesheet" crossorigin href="/assets/index-CVrWfcbZ.css">
   </head>

+ 290 - 34
src/views/report.vue

@@ -563,8 +563,14 @@
       :style="{ width: rightMenuWidth + 'px' }"
     >
     <div v-if="inferenceModel">
-        <div style="height: 91vh;overflow: auto;" class="file-list" v-html="formatted_data">
-         
+        <div style="height: 91vh;overflow: auto;" class="file-list">
+          <!-- 步骤显示区域 -->
+          <div id="stepsContainer" v-show="showSteps" class="steps-container">
+            <h3 class="steps-title">📋 处理步骤</h3>
+            <div id="stepsList"></div>
+          </div>
+          <!-- 结果显示区域 -->
+          <div id="resultContent" v-html="formatted_data"></div>
         </div>
       </div>
     <!-- 修改收缩按钮的位置和样式 -->
@@ -871,8 +877,122 @@ const enableKnowledgeSearch = ref(false);
 const knowledgeResults = ref([]);
 const knowledgeTotal = ref(0);
 const isKnowledgeLoading = ref(false);
-const formatted_data = ref('')
+const formatted_data = ref('');
+const showSteps = ref(false);
+const steps = ref([]);
+
+// SSE消息处理函数
+const handleSSEMessage = (event, data) => {
+  // 立即处理每个事件
+  switch (event) {
+    case 'html_start':
+      formatted_data.value = '';
+      break;
+      
+    case 'html_chunk':
+      if (data && typeof data.html === 'string') {
+        // 直接追加新内容到现有内容
+        formatted_data.value += data.html;
+        // 确保滚动到最新内容
+        nextTick(() => {
+          const resultContent = document.getElementById('resultContent');
+          if (resultContent) {
+            resultContent.scrollTop = resultContent.scrollHeight;
+          }
+        });
+      }
+      break;
+      
+    case 'html_end':
+      // 完成渲染,可以在这里添加完成的标记
+      break;
+
+    case 'init_steps':
+      showSteps.value = true;
+      // 立即初始化步骤
+      initializeSteps(data.steps);
+      break;
+      
+    case 'step_update':
+      // 立即更新步骤状态
+      updateStepElement(data.step_id, data.status, data.details, data.progress);
+      break;
+    case 'final_summary':
+      
+      break;
+    case 'stream_end':
+      showSteps.value = false;
+      /* // 立即初始化步骤
+      initializeSteps(data.steps); */
+      break;
+      
+    case 'error':
+      console.error('SSE错误:', data.message);
+    /*   ElMessage.error(data.message || '处理过程中出现错误'); */
+      break;
+  }
+};
+
+// 初始化步骤
+const initializeSteps = (stepsData) => {
+  const stepsList = document.getElementById('stepsList');
+  if (!stepsList) return;
+  
+  stepsList.innerHTML = '';
+  steps.value = stepsData;
+  
+  stepsData.forEach(step => {
+    stepsList.appendChild(createStepElement(step));
+  });
+};
+
+// 创建步骤元素
+const createStepElement = (step) => {
+  const stepEl = document.createElement('div');
+  stepEl.className = `step ${step.status}`;
+  stepEl.id = `step-${step.step_id}`;
+  
+  stepEl.innerHTML = `
+    <div class="step-header">
+      <div class="step-icon">${getStepIcon(step.status)}</div>
+      <div class="step-name">${step.name || step.step_id}</div>
+    </div>
+    <div class="step-details">${step.details || ''}</div>
+    <div class="progress-bar">
+      <div class="progress-fill" style="width: ${step.progress || 0}%"></div>
+    </div>
+  `;
+  
+  return stepEl;
+};
+
+// 更新步骤元素
+const updateStepElement = (stepId, status, details, progress) => {
+  const stepEl = document.getElementById(`step-${stepId}`);
+  if (!stepEl) return;
+  
+  stepEl.className = `step ${status}`;
+  stepEl.querySelector('.step-icon').textContent = getStepIcon(status);
+  
+  if (details) {
+    stepEl.querySelector('.step-details').textContent = details;
+  }
+  
+  if (progress !== undefined) {
+    stepEl.querySelector('.progress-fill').style.width = `${progress}%`;
+  }
+};
 
+// 获取步骤图标
+const getStepIcon = (status) => {
+  switch (status) {
+    case 'pending': return '⏳';
+    case 'running': return '🔄';
+    case 'completed': return '✅';
+    case 'error': return '❌';
+    default: return '⏳';
+  }
+};
 
 // 智能体
 const inferenceModel = ref(false);
@@ -1423,39 +1543,110 @@ const sendMessage = async () => {
       };
 
       // 发送初始请求获取SSE URL
-      const response = await fetch(`${import.meta.env.VITE_BASE_AI_API}/api/agents/database/`, {
-        method: 'POST',
-        headers: {
-          'Authorization': `JWT ${token}`,
-          'Content-Type': 'application/json'
-        },
-        body: JSON.stringify(requestData)
-      });
+      let reader = null;
+      try {
+        // 只发送SSE请求
+        const sseResponse = await fetch(`${import.meta.env.VITE_BASE_AI_API}/api/agents/database/streaming/`, {
+          method: 'POST',
+          headers: {
+            'Authorization': `JWT ${token}`,
+            'Content-Type': 'application/json'
+          },
+          body: JSON.stringify(requestData)
+        });
 
-      if (!response.ok) {
-        throw new Error('请求失败');
-      }
+        if (!sseResponse.ok) {
+          throw new Error('SSE请求失败');
+        }
 
-      // 获取SSE URL
-      const responseData = await response.json();
-      console.log(responseData)//.result.summary
-       // 移除临时消息
-      messages.value = messages.value.filter(
-        (msg) => msg.id !== tempAiMessage.id
-      );
-      formatted_data.value = responseData.result.html
-      const messageContent = responseData.result.summary
-       // 创建新的AI消息
-      const aiMessage = reactive({
-        id: Date.now() + 2,
-        role: "assistant",
-        content: messageContent || '',
-        displayContent: "",
-        audioData:  null,
-      });
-      messages.value.push(aiMessage);
-         // 显示打字效果
-    await typeMessage(aiMessage);
+        // 处理SSE响应
+        
+        reader = sseResponse.body.getReader();
+        const decoder = new TextDecoder();
+        let buffer = '';
+        let currentEvent = '';
+        let streamContent = '';
+
+        // 读取流数据
+        while (true) {
+          const { done, value } = await reader.read();
+          if (done) break;
+          
+          buffer += decoder.decode(value, { stream: true });
+          const lines = buffer.split('\n');
+          
+          // 保留最后一行(可能不完整)
+          buffer = lines.pop() || '';
+          
+            for (const line of lines) {
+             if (line.startsWith('event:')) {
+               currentEvent = line.substring(6).trim();
+             } else if (line.startsWith('data:')) {
+               try {
+                 const dataStr = line.substring(5).trim();
+                 if (dataStr) {
+                   const data = JSON.parse(dataStr);
+                   // 立即处理每条消息
+                    
+                     handleSSEMessage(currentEvent || 'message', data);
+                     if(currentEvent === 'final_summary'){
+                        // 移除临时消息
+                        messages.value = messages.value.filter(
+                          (msg) => msg.id !== tempAiMessage.id
+                        );
+
+                         // 创建新的AI消息
+                            const aiMessage = reactive({
+                              id: Date.now() + 2,
+                              role: "assistant",
+                              content: data.summary,
+                              displayContent: "",
+                              audioData: null,
+                            });
+                            isTyping.value = true;
+                            messages.value.push(aiMessage);
+                            // 显示打字效果
+                            try {
+                              await typeMessage(aiMessage);
+                            } catch (error) {
+                              console.error('打字效果出错:', error);
+                              // 如果打字效果失败,直接显示完整内容
+                              aiMessage.displayContent = aiMessage.content;
+                            } finally {
+                              isTyping.value = false;
+                            }
+                     }      
+                 }
+               } catch (e) {
+                 console.error('Failed to parse SSE data:', line, e);
+               }
+             } else if (line === '') {
+               // 空行表示事件结束,重置当前事件
+               currentEvent = '';
+             }
+           }
+                 }
+
+        
+        
+        // 设置初始的formatted_data(如果流式数据还没开始更新)
+       /*  if (!streamContent) {
+          formatted_data.value = responseData.result.html;
+        } */
+      } catch (error) {
+        console.error('请求或处理过程出错:', error);
+        ElMessage.error('请求失败,请稍后重试');
+        throw error;
+      } finally {
+        // 确保在结束时关闭reader
+        if (reader) {
+          try {
+            await reader.cancel();
+          } catch (error) {
+            console.error('关闭reader时出错:', error);
+          }
+        }
+      }
     }
     
     
@@ -5671,6 +5862,71 @@ button,
     background: #e0f7fa;
     font-weight: 500;
   }
+  .step-header {
+            display: flex;
+            align-items: center;
+            gap: 12px;
+            margin-bottom: 8px;
+        }
+        
+        .step-icon {
+            width: 24px;
+            height: 24px;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 12px;
+            font-weight: 600;
+        }
+        
+       /*  .step.pending .step-icon {
+            background: #e5e7eb;
+            color: #6b7280;
+        }
+        
+        .step.running .step-icon {
+            background: #3b82f6;
+            color: white;
+        } */
+        
+     /*    .step.completed .step-icon {
+        
+            color: white;
+        }
+        
+        .step.error .step-icon {
+            
+            color: white;
+        } */
+        
+        .step-name {
+            font-weight: 600;
+            font-size: 16px;
+        }
+        
+        .step-details {
+            color: #6b7280;
+            font-size: 14px;
+            margin-left: 36px;
+        }
+        
+       /*  .progress-bar {
+            width: 100%;
+            height: 4px;
+            background: #e5e7eb;
+            border-radius: 2px;
+            margin-top: 8px;
+            overflow: hidden;
+            margin-left: 36px;
+        }
+        
+        .progress-fill {
+            height: 100%;
+            background: #10b981;
+            transition: width 0.3s ease;
+            width: 0%;
+        } */
 
 </style>
 

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.