ソースを参照

feat: 优化对话模块

zhupei@smartai.com 1 年間 前
コミット
5faf1a4b11

+ 5 - 1
public/config.js

@@ -9,7 +9,10 @@ window.DMX_VERSION = '1.0.1';
  */
 window.API_BASE_URL = 'http://192.168.20.119:9301';
 
-window.WEBSOCKET_BASE_URL = '192.168.20.119:9301';
+/**
+ * 对话websocket连接地址
+ */
+window.WEBSOCKET_BASE_URL = 'ws://192.168.20.119:9301';
 
 /**
  * 静态资源地址
@@ -46,6 +49,7 @@ window.IFRAME_URL_CHUJUAN = 'http://192.168.20.119:8501';
 
 /**
  * 小数系统访问地址
+ * 导航栏 小数 通过 无界 微前端 方式嵌入到大模型2.0
  */
 window.XIAOSHU_URL = 'http://192.168.20.119:9301';
 

+ 9 - 1
public/i18n/lang-en.json

@@ -16,6 +16,7 @@
     "Agent": "Agent",
     "智能体": "Intelligent",
     "权限管理": "Permission",
+    "小数": "Xiaoshu",
 
     "search": "Search",
     "language": "Language",
@@ -123,6 +124,13 @@
     "history_empty": "Empty",
 
     "hello": "Welcome",
-    "nice_day": "Let's spend a wonderful day together"
+    "nice_day": "Let's spend a wonderful day together",
+
+    "attention": "The content is generated by an AI big model, please carefully identify it",
+
+    "file_upload_message": "Upload",
+    "input_message": "Enter your question",
+    "input_placholder": "Enter text content",
+    "input_confirm": "Confirm"
   }
 }

+ 8 - 1
public/i18n/lang-zh.json

@@ -125,6 +125,13 @@
     "history_nomore": "没有更多了",
     "history_empty": "暂无数据",
     "hello": "你好",
-    "nice_day": "让我们一起度过美好的一天"
+    "nice_day": "让我们一起度过美好的一天",
+
+    "attention": "内容由 AI 大模型生成,请仔细甄别",
+
+    "file_upload_message": "文件上传",
+    "input_message": "输入您的问题",
+    "input_placholder": "输入文本内容",
+    "input_confirm": "发送"
   }
 }

+ 0 - 1
src/modules/chat-index/README.md

@@ -1 +0,0 @@
-# 会话

+ 4 - 2
src/modules/conversation-chat/DialogFooter.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="dialog-footer">
-    <div>内容由 AI 大模型生成,请仔细甄别</div>
+    <div>{{ $t('conversation.attention') }}</div>
   </div>
 </template>
 
@@ -12,6 +12,8 @@
   justify-content: center;
   align-items: center;
 
-  color: var(--color-text-1);
+  color: var(--color-text-3);
+
+  font-size: 12px;
 }
 </style>

+ 1 - 1
src/modules/conversation-chat/DialogInput.vue

@@ -6,7 +6,7 @@
       <div class="textarea-container">
         <a-textarea
           class="textarea-input"
-          placeholder="输入文本内容"
+          :placeholder="$t('conversation.input_placholder')"
           :model-value="input_text_value"
           allow-clear
           :auto-size="{

+ 1 - 0
src/modules/conversation-chat/DialogInputTop.vue

@@ -6,6 +6,7 @@
     </template>
 
     <template v-if="menu_id === 9">
+      <!-- 文档报告 -->
       <a-space size="large">
         <a-tooltip :content="radio_qingxi_text">
           <a-radio :value="1" :model-value="act_type" @click="handleRadioClick(1)">文档清洗</a-radio>

+ 4 - 0
src/modules/conversation-chat/DialogItem.vue

@@ -21,6 +21,10 @@ import DialogAnswer from '../conversation-item/DialogAnswer.vue';
 
 const props = defineProps({
   dialog: Object,
+
+  /**
+   * 对话区域的宽度
+   */
   width: Number
 });
 

+ 6 - 0
src/modules/conversation-chat/DialogList.vue

@@ -23,7 +23,13 @@ import DialogSuggestion from './DialogSuggestion.vue';
 import useScrollBottom from './use-scroll-bottom';
 
 const props = defineProps({
+  /**
+   * 对话区域的告诉
+   */
   height: Number,
+  /**
+   * 对话区域的宽度
+   */
   width: Number,
 
   /**

+ 5 - 3
src/modules/conversation-chat/dialog-input/InputActions.vue

@@ -2,7 +2,7 @@
   <div class="dialog-input-actions">
     <div class="dialog-input-action-left">
       <!-- <div>联网查询</div> -->
-      <a-tooltip content="文件上传" position="top">
+      <a-tooltip :content="$t('conversation.file_upload_message')" position="top">
         <div v-if="enable_file_upload" class="action-left-item-btn" @click="handleFileUpload">
           <img src="../../../assets/file-upload.png" />
         </div>
@@ -26,8 +26,10 @@
         <div v-if="enable_voice_recognition" class="action-right-item-btn" @click="handleVoiceRecognize">语音识别</div>
       </a-tooltip> -->
 
-      <a-tooltip content="请输入您的问题" position="top">
-        <div class="action-right-item-btn submit-input-btn" @click="handleSubmit">发送</div>
+      <a-tooltip :content="$t('conversation.input_message')" position="top">
+        <div class="action-right-item-btn submit-input-btn" @click="handleSubmit">
+          {{ $t('conversation.input_confirm') }}
+        </div>
       </a-tooltip>
     </div>
   </div>

+ 5 - 1
src/modules/conversation-content/DialogContent.vue

@@ -35,11 +35,15 @@ const props = defineProps({
   max_width: Number
 });
 
+/**
+ * 内容DOM节点的样式
+ * 主要用于控制节点的宽度,避免对话内容中某些内容将对话区域撑开,造成样式异常
+ */
 const custom_style = computed(() => {
   if (props.max_width) {
     return `max-width: ${props.max_width}px;`;
   } else {
-    ('');
+    return '';
   }
 });
 </script>

+ 2 - 5
src/modules/conversation-dialog/api-dialog.js

@@ -110,12 +110,9 @@ export const files2Formdata = (f_list, key_name) => {
  * @param {*} agent_id
  * @param {*} chat_id
  * @param {*} client_file
- * @param {*} agentInfo
+ * @param {*} menu_id
  */
-export const uploadFileByAgentInfo = async (agent_id, chat_id, client_file, agentInfo) => {
-  const agent = agentInfo.agent;
-  const menu_id = agent.menuId / 1;
-
+export const uploadFileByAgentInfo = async (agent_id, chat_id, client_file, menu_id) => {
   let files_response = null;
 
   if (menu_id === 1) {

+ 26 - 26
src/modules/conversation-dialog/format-dialog-answer-custom-markdown-str.js

@@ -20,32 +20,32 @@ export function formatRefferenceString(refference, field_key) {
   // 仅返回一个容器,模板内容通过组件生成
   return `<div class="client-formated-markdown-element-item client-formated-markdown-doc-refference-container"></div>`;
 
-  const refs_markdown = [];
-  if (Array.isArray(doc_aggs)) {
-    doc_aggs.forEach((item, index) => {
-      refs_markdown.push(
-        `<li
-          class="client-formated-markdown-element-item client-formated-markdown-doc-refference-item"
-          data-doc-id="${item.doc_id}"
-          data-real-index="${index}"
-          data-ref-key="${field_key}"
-        >
-          <span class="refference-index">${index + 1}</span>
-          <span class="refference-label">${item.doc_name}</span>
-        </li>`
-      );
-    });
-  }
-
-  const li_str = refs_markdown.join('');
-
-  const ref_header = `<header class="client-formated-markdown-element-item client-formated-markdown-refference-header">
-    <div>来源</div>
-    <div>查看全部关联</div>
-  </header>`;
-  const ref_list = `<ul class="client-formated-markdown-element-item client-formated-markdown-doc-refference-container" data-ref-key="${field_key}">${li_str}</ul>`;
-
-  return `${ref_header} ${ref_list}`;
+  // const refs_markdown = [];
+  // if (Array.isArray(doc_aggs)) {
+  //   doc_aggs.forEach((item, index) => {
+  //     refs_markdown.push(
+  //       `<li
+  //         class="client-formated-markdown-element-item client-formated-markdown-doc-refference-item"
+  //         data-doc-id="${item.doc_id}"
+  //         data-real-index="${index}"
+  //         data-ref-key="${field_key}"
+  //       >
+  //         <span class="refference-index">${index + 1}</span>
+  //         <span class="refference-label">${item.doc_name}</span>
+  //       </li>`
+  //     );
+  //   });
+  // }
+
+  // const li_str = refs_markdown.join('');
+
+  // const ref_header = `<header class="client-formated-markdown-element-item client-formated-markdown-refference-header">
+  //   <div>来源</div>
+  //   <div>查看全部关联</div>
+  // </header>`;
+  // const ref_list = `<ul class="client-formated-markdown-element-item client-formated-markdown-doc-refference-container" data-ref-key="${field_key}">${li_str}</ul>`;
+
+  // return `${ref_header} ${ref_list}`;
 }
 
 export function formatRefferenceFlag(answer) {

+ 31 - 86
src/modules/conversation-dialog/format-dialog-answer-from-websocket_receive_message.js

@@ -1,11 +1,11 @@
 import { jsonParse, jsonStringify } from '../../utils/utils';
-
-import { formatCodePython, formatCodeSql } from './format-code-string';
+import { formatStaticAssetsUrl } from '../../utils/utils';
 import generateClientUniqueId from '../../utils/generate-client-unique-id';
-import { getIcon4Answer } from './get-icon-4-dialog';
 
+import { formatCodePython, formatCodeSql } from './format-code-string';
 import formatAnwserString from './format-anwser-string';
-import { formatStaticAssetsUrl } from '../../utils/utils';
+import { formatFileDownloadStr } from './format-dialog-answer-custom-markdown-str';
+import { getIcon4Answer } from './get-icon-4-dialog';
 
 import {
   formatRefferenceString,
@@ -121,47 +121,21 @@ export default function formatDialogAnswerFromWebsocketReceiveMessage(message_st
     currentMsg.answer = resMessage;
 
     if (resExcelUrl && resExcelName) {
-      // 智能数据需要用到的值
-      // const port = window.location.port ? `:${window.location.port}` : '';
-
-      // const file = {
-      //   file_type: 'excel',
-      //   file_url: `http://${window.location.hostname}${port}${resExcelUrl}`,
-      //   file_name: `${resExcelName}.xlsx` || '点击下载'
-      // };
-
-      // currentMsg.file = file;
-
+      // 智能数据可能存在此数据
+      // 并且可以确保,返回的是Excel类型,后缀名为 .xlsx,且仅有文件名,没有后缀
       currentMsg.client_custom_linked_download_files = {
-        file_name: resExcelName,
+        file_name: resExcelName + '.xlsx',
         file_url: resExcelUrl
       };
-
-      // const download_file_str = formatFileDownloadStr(resExcelName, resExcelUrl);
-
-      // currentMsg.answer = currentMsg.agentInfo + download_file_str;
     }
 
     if (resFileUrl && resFileName) {
       // 出题组卷可能存在此数据
-      // const port = window.location.port ? `:${window.location.port}` : '';
-
-      // const file = {
-      //   file_type: 'word',
-      //   file_url: `http://${window.location.hostname}${port}${resFileUrl}`,
-      //   file_name: `${resFileName}.docx` || '点击下载'
-      // };
-
-      // currentMsg.file = file;
-
+      // 并且可以确保返回的文件名没有后缀,且是 .docx 格式
       currentMsg.client_custom_linked_download_files = {
-        file_name: resFileName,
+        file_name: resFileName + '.docx',
         file_url: resFileUrl
       };
-
-      // const download_file_str = formatFileDownloadStr(resFileName, resFileUrl);
-
-      // currentMsg.answer = currentMsg.agentInfo + download_file_str;
     }
 
     if (resDownloadUrl) {
@@ -214,12 +188,6 @@ export default function formatDialogAnswerFromWebsocketReceiveMessage(message_st
 
     if (resImageUrl) {
       // 智能数据可能会存在此值
-      // const port = window.location.port ? `:${window.location.port}` : '';
-
-      // const image_url = `http://${window.location.hostname}${port}${resImageUrl}`;
-
-      // currentMsg.image_url = image_url;
-
       currentMsg.client_custom_linked_image = resImageUrl;
     }
     // ------------------------------------------------------
@@ -241,11 +209,7 @@ export default function formatDialogAnswerFromWebsocketReceiveMessage(message_st
       const ref_str = formatRefferenceString(resRefference, 'client_custom_linked_refference_full_content');
 
       if (ref_str) {
-        currentMsg.answer =
-          currentMsg.answer +
-          `
-        ${ref_str}
-      `;
+        currentMsg.answer = currentMsg.answer + `${ref_str}`;
       }
 
       // 添加字段:客户端自定义的相关字段,link完整数据
@@ -267,33 +231,7 @@ export default function formatDialogAnswerFromWebsocketReceiveMessage(message_st
 
     if (resFiles) {
       // 文档合并有此数据
-      const file_name = resFiles[0].file_name;
-      // const file_info_arr = file_name.split('.');
-      // const end_fix = file_info_arr[file_info_arr.length - 1];
-
-      // const file = {
-      //   file_name: resFiles[0].file_name,
-      //   file_url: resFiles[0].file_url
-      // };
-
-      // // 理论上报表合并,只能是 excel
-      // // if(chat_type === 'excel'){
-      // //   file.file_type = 'excel'
-      // // }
-      // if (end_fix === 'xlsx') {
-      //   file.file_type = 'excel';
-      // }
-      // if (end_fix === 'docx') {
-      //   file.file_type = 'word';
-      // }
-
-      // currentMsg.file = file;
-
       if (resFiles[0]) {
-        // console.log('报表合并,所有文件', resFiles);
-        // const download_file_str = formatFileDownloadStr(resFiles[0].file_name, resFiles[0].file_url);
-        // console.log('报表合并,所有文件', download_file_str);
-
         currentMsg.client_custom_linked_download_files = {
           file_name: resFiles[0].file_name,
           file_url: resFiles[0].file_url
@@ -356,23 +294,30 @@ export default function formatDialogAnswerFromWebsocketReceiveMessage(message_st
    */
   currentMsg.client_custom_unique_id = generateClientUniqueId(currentMsg.answer);
 
-  // if (currentMsg.answer) {
-  //   // 将markdown转换为html文件
-  //   currentMsg.answer = formatAnwserString(currentMsg.answer);
+  if (currentMsg.answer) {
+    // 将markdown转换为html文件
+    currentMsg.answer = formatAnwserString(currentMsg.answer);
 
-  //   if (currentMsg.client_custom_linked_code) {
-  //     currentMsg.answer = currentMsg.answer + currentMsg.client_custom_linked_code;
-  //   }
+    if (currentMsg.client_custom_linked_code) {
+      currentMsg.answer = currentMsg.answer + currentMsg.client_custom_linked_code;
+    }
 
-  //   // 由于SQL和代码不能通过markdown解析,所以此处进行字符串的拼接
-  //   if (currentMsg.client_custom_linked_sql) {
-  //     currentMsg.answer = currentMsg.answer + currentMsg.client_custom_linked_sql;
-  //   }
+    // 由于SQL和代码不能通过markdown解析,所以此处进行字符串的拼接
+    if (currentMsg.client_custom_linked_sql) {
+      currentMsg.answer = currentMsg.answer + currentMsg.client_custom_linked_sql;
+    }
 
-  //   if (currentMsg.client_custom_linked_image) {
-  //     currentMsg.answer = currentMsg.answer + `<img src="${currentMsg.client_custom_linked_image}" />`;
-  //   }
-  // }
+    if (currentMsg.client_custom_linked_image) {
+      currentMsg.answer = currentMsg.answer + `<img src="${currentMsg.client_custom_linked_image}" />`;
+    }
+    // 拼接文件的下载链接
+    if (answer.client_custom_linked_download_files) {
+      const file_name = answer.client_custom_linked_download_files.file_name;
+      const file_url = answer.client_custom_linked_download_files.file_url;
+      const download_file_str = formatFileDownloadStr(file_name, file_url);
+      answer_string = answer_string + download_file_str;
+    }
+  }
 
   return {
     status: chat_status, // 本轮会话的状态:0 未开始 1 进行中 2 已结束 3 错误

+ 2 - 2
src/modules/conversation-dialog/format-dialog-question-by-client.js

@@ -5,10 +5,10 @@ import { getIcon4Question } from './get-icon-4-dialog';
 /**
  * 组装客户端用户提问的数据
  */
-export default function formatDialogQuestionByClient(text, client_file_list, agentInfo) {
+export default function formatDialogQuestionByClient(text, client_file_list) {
   const cur_stamp = Date.now();
 
-  const icon_src = getIcon4Question(agentInfo);
+  const icon_src = getIcon4Question();
 
   return {
     /**

+ 0 - 6
src/modules/conversation-dialog/format-dialog-send-options.js

@@ -1,5 +1,3 @@
-// import { jsonParse, jsonStringify } from '../../utils/utils';
-
 /**
  * 组装发送websocket消息时的参数
  * @param {string} text - 纯文本数据
@@ -8,10 +6,6 @@
  * @returns
  */
 export default function formatDialogSendOptions(text, file_list, menu_id) {
-  // const agent = agentInfo.agent || {};
-  // const agent_id = agentInfo.id; // agent的ID值
-  // const menu_id = agent.menuId / 1;
-
   let send_data = {
     message: text
   };

+ 37 - 31
src/modules/conversation-dialog/use-websocket-chat.js

@@ -5,25 +5,31 @@ import { getConfigField } from '../../config/index';
 
 /**
  * 获取websocket连接的地址
- * @param {string} type - 对话类型,可选值:report/excel/chat
+ * @param {string} menu_id - 对话类型,可选值:1/2/3/4/5/6/7/8/9
  * @param {string} agent_id - 对话使用的agent ID
  * @param {string} chat_id - 对话记录的ID
  * @returns
  */
-function getWSUrl(type, agent_id, chat_id) {
-  // const host = location.host;
+function getWSUrl(menu_id, agent_id, chat_id) {
   const token = kuky_Authorization.get();
-  const host = getConfigField('WEBSOCKET_BASE_URL');
-
-  if (type === 'report') {
-    return `ws://${host}/api/${type}/ws/${agent_id}/${chat_id}?token=${token}`;
-  } else if (type === 'chat') {
-    return `ws://${host}/api/${type}/ws/${agent_id}/${chat_id}?token=${token}`;
-  } else if (type === 'excel') {
-    return `ws://${host}/api/document/ws/excel`;
+  const ws_server = getConfigField('WEBSOCKET_BASE_URL'); // websocket连接地址
+
+  if (menu_id === 1) {
+    return `${ws_server}/api/document/ws/excel`;
   } else {
-    return `ws://${host}/api/chat/ws/${agent_id}/${chat_id}?token=${token}`;
+    // return `${host}/api/${type}/ws/${agent_id}/${chat_id}?token=${token}`;
+    return `${ws_server}/api/chat/ws/${agent_id}/${chat_id}?token=${token}`;
   }
+
+  // if (type === 'report') {
+  //   return `ws://${host}/api/${type}/ws/${agent_id}/${chat_id}?token=${token}`;
+  // } else if (type === 'chat') {
+  //   return `ws://${host}/api/${type}/ws/${agent_id}/${chat_id}?token=${token}`;
+  // } else if (type === 'excel') {
+  //   return `ws://${host}/api/document/ws/excel`;
+  // } else {
+  //   return `ws://${host}/api/chat/ws/${agent_id}/${chat_id}?token=${token}`;
+  // }
 }
 
 /**
@@ -60,23 +66,23 @@ export default function useWebSocketChat(trigger) {
   const onClose = protectedFunction(trigger.onClose);
   const onError = protectedFunction(trigger.onError);
 
-  /**
-   * websocket当前状态
-   * @see https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket/readyState
-   * 0 CONNECTING 套接字已经创建,但是连接尚未打开
-   * 1 OPEN 连接已经打开,准备进行通信
-   * 2 CLOSING 连接正在关闭中
-   * 3 CLOSED 连接已关闭或者无法打开
-   * -1 此处自定义值,未启动
-   */
-  const websocket_status = ref(-1);
+  // /**
+  //  * websocket当前状态
+  //  * @see https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket/readyState
+  //  * 0 CONNECTING 套接字已经创建,但是连接尚未打开
+  //  * 1 OPEN 连接已经打开,准备进行通信
+  //  * 2 CLOSING 连接正在关闭中
+  //  * 3 CLOSED 连接已关闭或者无法打开
+  //  * -1 此处自定义值,未启动
+  //  */
+  // const websocket_status = ref(-1);
 
   /**
    * 创建一个websocket连接
    * @returns
    */
-  function createWSConnection(agent_id, chat_id, type) {
-    const wsUrl = getWSUrl(type, agent_id, chat_id);
+  function createWSConnection(agent_id, chat_id, menu_id) {
+    const wsUrl = getWSUrl(menu_id, agent_id, chat_id);
 
     const wskt = new WebSocket(wsUrl);
 
@@ -113,7 +119,7 @@ export default function useWebSocketChat(trigger) {
 
   let temp_agent_id = null;
   let temp_chat_id = null;
-  let temp_type = null;
+  let temp_menu_id = null;
   let websocket = null;
 
   return {
@@ -121,16 +127,16 @@ export default function useWebSocketChat(trigger) {
      * 初始化websocket连接
      * @param {string} agent_id
      * @param {string} chat_id
-     * @param {string} type
+     * @param {string} menu_id
      */
-    initWSConnection(agent_id, chat_id, type) {
+    initWSConnection(agent_id, chat_id, menu_id) {
       temp_agent_id = agent_id;
       temp_chat_id = chat_id;
-      temp_type = type;
+      temp_menu_id = menu_id;
 
       if (websocket === null) {
         // websocket未创建:立即创建
-        websocket = createWSConnection(temp_agent_id, temp_chat_id, temp_type);
+        websocket = createWSConnection(temp_agent_id, temp_chat_id, temp_menu_id);
       }
 
       return websocket;
@@ -144,7 +150,7 @@ export default function useWebSocketChat(trigger) {
         // console.log('websocket为空,还未创建,开始创建');
 
         // websocket未创建:立即创建
-        websocket = createWSConnection(temp_agent_id, temp_chat_id, temp_type);
+        websocket = createWSConnection(temp_agent_id, temp_chat_id, temp_menu_id);
       } else {
         // console.log('websocket已创建,不用再次创建');
       }
@@ -168,7 +174,7 @@ export default function useWebSocketChat(trigger) {
         delay_message_list.push(msg);
 
         // 已关闭: 重新创建socket
-        websocket = createWSConnection(temp_agent_id, temp_chat_id, temp_type);
+        websocket = createWSConnection(temp_agent_id, temp_chat_id, temp_menu_id);
       }
     },
     /**

+ 55 - 31
src/modules/conversation-item/DialogAnswer.vue

@@ -63,6 +63,9 @@ const props = defineProps({
    */
   answer: Object,
 
+  /**
+   * 对话区域的宽度
+   */
   width: Number
 });
 
@@ -93,6 +96,8 @@ const is_content_loading = computed(() => {
 
 /**
  * 内容区域的最大宽度
+ * 内容区域的宽度,根据父容器的宽度,减去此组件内非内容区域元素(icon等)的宽度,以及横向的的margin/padding
+ * 最终得出内容区域的最大宽度
  */
 const content_max_width = computed(() => {
   return props.width - 40 - 40 - 20;
@@ -107,39 +112,56 @@ const answer_html = computed(() => {
   const answer = props.answer;
   const str = answer.content;
 
-  let answer_string = formatAnwserString(str);
-
-  // 由于SQL和代码不能通过markdown解析,所以此处进行字符串的拼接
-  // 在markdown转换结束后,添加拼接字符串
-  if (answer.client_custom_linked_code) {
-    answer_string = answer_string + answer.client_custom_linked_code;
-  }
-
-  if (answer.client_custom_linked_sql) {
-    answer_string = answer_string + answer.client_custom_linked_sql;
-  }
-
-  if (answer.client_custom_linked_image) {
-    const img_url = formatStaticAssetsUrl(answer.client_custom_linked_image);
-    answer_string = answer_string + `<img src="${img_url}" />`;
-  }
-
-  // 处理下载链接
-  if (answer.client_custom_linked_download_files) {
-    const file_name = answer.client_custom_linked_download_files.file_name;
-    const file_url = answer.client_custom_linked_download_files.file_url;
-    const download_file_str = formatFileDownloadStr(file_name, file_url);
-    answer_string = answer_string + download_file_str;
-  }
-
-  return answer_string;
+  return str;
+
+  // /**
+  //  * 第一步处理位于:../conversation-dialogformat-dialog-answer-from-websocket_receive_message.js
+  //  * 此处将websocket的答案数据进行第二步处理
+  //  * 使用markdown解析器进行解析,并处理一部分字符串
+  //  * 最终生成html字符串
+  //  */
+  // let answer_string = formatAnwserString(str);
+
+  // // 第二步处理已经结束,html字符串已经生成
+  // // 接下来进行最后一步:附加内容的字符串拼接
+  // // 由于SQL和代码不能通过markdown解析,所以此处进行字符串的拼接
+  // // 在markdown转换结束后,添加拼接字符串
+  // // 拼接python代码
+  // if (answer.client_custom_linked_code) {
+  //   answer_string = answer_string + answer.client_custom_linked_code;
+  // }
+  // // 拼接SQL代码
+  // if (answer.client_custom_linked_sql) {
+  //   answer_string = answer_string + answer.client_custom_linked_sql;
+  // }
+  // // 拼接生成的图片
+  // if (answer.client_custom_linked_image) {
+  //   const img_url = formatStaticAssetsUrl(answer.client_custom_linked_image);
+  //   answer_string = answer_string + `<img src="${img_url}" />`;
+  // }
+  // // 拼接文件的下载链接
+  // if (answer.client_custom_linked_download_files) {
+  //   const file_name = answer.client_custom_linked_download_files.file_name;
+  //   const file_url = answer.client_custom_linked_download_files.file_url;
+  //   const download_file_str = formatFileDownloadStr(file_name, file_url);
+  //   answer_string = answer_string + download_file_str;
+  // }
+
+  // /**
+  //  * 所有步骤已经走完
+  //  * 返回最终的html字符串
+  //  */
+  // return answer_string;
 });
 
+/**
+ * 智能体回答区域容器的class值
+ * 通过唯一ID生成,可以保证界面中每一个答案都有一个唯一的容器类名
+ * 为后续其他处理(引用效果、代码美化)做准备:后续处理可以通过此class定位相关子元素
+ */
 const anwser_klass = computed(() => {
   const answer = props.answer;
 
-  // console.log(answer, '答案数据');
-
   return `klass-${answer.client_custom_unique_id}-answer-content`;
 });
 
@@ -178,13 +200,15 @@ onMounted(() => {
   const container_klass = anwser_klass.value;
   const answer = props.answer;
 
+  const full_refference = answer.client_custom_linked_refference_full_content;
+
   /**
    * 文档引用效果
    */
-  applyRefferencePopover4RefFlag(container_klass, answer.client_custom_linked_refference_full_content);
-  applyRefferencePopover4FileName(container_klass, answer.client_custom_linked_refference_full_content);
+  applyRefferencePopover4RefFlag(container_klass, full_refference);
+  applyRefferencePopover4FileName(container_klass, full_refference);
   /**
-   * 处理代码样式
+   * 处理代码样式: 美化代码的展示
    */
   applyCodeHighLight(container_klass);
 });

+ 59 - 69
src/views/conversation/ConversationChatContainer.vue

@@ -127,16 +127,16 @@ const CHAT_AGENT_INFOMATION = ref({
   config: {}
 });
 
-const header_height = 30;
-const footer_height = 30;
-const input_height = ref(100);
-
-const { width: chat_width, height: chat_height } = useEleSizeV1('chat_main');
-// const { width: input_area_width, height: input_area_height } = useEleSizeV2('dialog_input');
-
-const inputClearFn1 = useInputClear('dialog_input');
+/**
+ * input的一些操作方法
+ */
+const inputClearFn1 = useInputClear('dialog_input'); // 主表单清空
 const inputClearFn2 = useInputClear('dialog_input_top'); // 顶部附加表单的数据
-const getInputTopOptions = useInputGetOptions('dialog_input_top'); // 获取表单的参数
+const getInputTopOptions = useInputGetOptions('dialog_input_top'); // 获取附加表单参数的方法
+
+/**
+ * 对话区域滚动到底部
+ */
 const scroll2Bottom = useScroll2Bottom('list_scroller');
 const scroll2ListBottom = () => {
   nextTick(() => {
@@ -144,11 +144,17 @@ const scroll2ListBottom = () => {
   });
 };
 
-const input_style = computed(() => {
-  return {
-    // height: input_height + 'px'
-  };
-});
+/**
+ * 整个对话区域的一些尺寸定义
+ */
+const header_height = 30;
+const footer_height = 30;
+const input_height = ref(100);
+
+/**
+ * 获取到对话区域的宽度和高度
+ */
+const { width: chat_width, height: chat_height } = useEleSizeV1('chat_main');
 
 /**
  * 对话列表区域的高度
@@ -157,6 +163,12 @@ const list_height = computed(() => {
   return chat_height.value - header_height - footer_height - input_height.value - 20;
 });
 
+const input_style = computed(() => {
+  return {
+    // height: input_height + 'px'
+  };
+});
+
 // ------------------------------------------------------------------
 // ------------------------------------------------------------------
 // ------------------------------------------------------------------
@@ -167,22 +179,19 @@ const list_height = computed(() => {
 const chat_log_list = ref([]); // 历史对话的数据列表
 const chat_new_list = ref([]); // 新对话的数据列表
 const chat_suggestion = ref([]); // 对话推荐项目
-/**
- * 此轮对话的状态
- * 0 未开始
- * 1 进行中
- * 2 已结束
- * 3 错误
- */
-const chat_new_status = ref(0);
+
 /**
  * 当前新对话的ID
  * 当用户有输入后,点击提交,此时创建新对话,新对话的ID为此ID
  * 之后用户可以一直使用此ID进行对话。
  */
 const chat_new_id = ref(null);
+
 /**
  * 新对话,客户端的提问数据
+ * 用以临时保存客户端的提问数据
+ * 每当用户确认进行提问时,将新提问赋给此值
+ * 一旦对话消息通过websocket发送到服务器,此值可清空
  */
 const chat_new_question = ref({});
 
@@ -197,6 +206,11 @@ const chat_display_list = computed(() => {
   return [].concat(chat_log_list.value, chat_new_list.value);
 });
 
+/**
+ * 是否禁用输入组件
+ */
+const input_disabled = ref(false);
+
 /**
  * 菜单ID编号
  * 1 报表合并
@@ -214,17 +228,17 @@ const current_menu_id = computed(() => {
   const menu_id = agent.menuId / 1;
   return menu_id;
 });
-/**
- * 当前对话的类型
- */
-const current_chat_type = computed(() => {
-  // const agent = CHAT_AGENT_INFOMATION.value.agent;
-  // const menu_id = agent.menuId / 1;
-  const menu_id = current_menu_id.value;
-  const chat_type = menu_id === 1 ? 'excel' : '';
-
-  return chat_type;
-});
+// /**
+//  * 当前对话的类型
+//  * 目前已知类型有量类: excel 和 其他类
+//  * 当类别为excel时,文件上传接口和对话websocket链接都不一样
+//  */
+// const current_chat_type = computed(() => {
+//   const menu_id = current_menu_id.value;
+//   const chat_type = menu_id === 1 ? 'excel' : '';
+
+//   return chat_type;
+// });
 
 /**
  * 是否显示欢迎页
@@ -253,7 +267,7 @@ const show_input_others_opts = computed(() => {
 });
 
 /**
- * 分享
+ * 内容分享操作
  * @param chat_id
  */
 const handleChatShare = (chat_id) => {};
@@ -272,17 +286,12 @@ const handleErrorMessage = (msg) => {
 };
 // ---------------------------------------------
 
-/**
- * 是否禁用输入组件
- */
-const input_disabled = ref(false);
-
 /**
  * 异常处理
  * 异常处理过程是一个会话模拟的过程
  * 先在界面上显示加载动画,然后紧接着显示错误提示
  * 让用户感知到智能体有处理数据的过程
- * 所以在异常处理阶段,有一些需要处理的关键点,比如欢迎界面的显示
+ * 所以在异常处理阶段,有一些需要处理的关键点,比如欢迎界面的显示(如果在现实,则需要隐藏,否则对话显示不了)
  * @param exceptionInfo
  */
 const handleChatRequestionException = (exceptionInfo) => {
@@ -302,6 +311,7 @@ const handleChatRequestionException = (exceptionInfo) => {
 
 /**
  * 输入区域的尺寸发生了变化
+ * 整个对话区域的尺寸也需要依据此变化而变化
  * @param size
  */
 const handleInputSizeChange = (size) => {
@@ -346,7 +356,7 @@ const handleInputSubmit = async (options) => {
    * 整理客户端提问的数据
    * 组装Question数据
    */
-  const client_question = formatDialogQuestionByClient(ask_text, ask_files, CHAT_AGENT_INFOMATION.value);
+  const client_question = formatDialogQuestionByClient(ask_text, ask_files);
   // 保存用户的提问信息
   // 当消息正式发出后,将提问数据放入列表中
   chat_new_question.value = client_question;
@@ -421,8 +431,7 @@ const handleInputSubmit = async (options) => {
       return;
     }
   } else {
-    // 已创建chat
-    // console.log(chat_new_id.value, '已创建');
+    // 已创建chat,使用已创建的会话ID,进入下一步流程
   }
 
   // 文件上传后的信息
@@ -432,28 +441,15 @@ const handleInputSubmit = async (options) => {
    */
   if (ask_files.length !== 0) {
     // 进行文件上传,获取文件信息
-
     const chat_id = chat_new_id.value;
 
     try {
-      // const file_params = files2Formdata(ask_files);
-      const uploadResult = await uploadFileByAgentInfo(agent_id, chat_id, ask_files, CHAT_AGENT_INFOMATION.value);
+      const menu_id = current_menu_id.value;
+      const uploadResult = await uploadFileByAgentInfo(agent_id, chat_id, ask_files, menu_id);
 
       if (uploadResult.code / 1 === 200) {
         // 文件上传成功
         files_response = uploadResult.data;
-
-        // // TODO: 统一文件上传数据
-        // // 文档智能的文件上传文件信息在 files 里
-        // if (file_uploaded.files) {
-        //   files_response = file_uploaded.files;
-        // } else {
-        //   if (Array.isArray(file_uploaded)) {
-        //     files_response = file_uploaded;
-        //   } else {
-        //     files_response = [file_uploaded];
-        //   }
-        // }
       } else {
         // 文件上传异常
         handleChatRequestionException({
@@ -476,9 +472,10 @@ const handleInputSubmit = async (options) => {
   /**
    * 组装参数
    * 组装socket参数: 文本和文件
-   * 此方法会依据当前使用的agent,组装好传递给websocket的基础的文本和文件的参数
+   * 此方法会依据当前使用的agent,组装好传递给websocket的 基础的文本和文件的参数
    */
-  const msg_obj = formatDialogSendOptions(ask_text, files_response, current_menu_id.value);
+  const menu_id = current_menu_id.value;
+  const msg_obj = formatDialogSendOptions(ask_text, files_response, menu_id);
 
   /**
    * 文本和文件的数据已经组装完成
@@ -488,7 +485,6 @@ const handleInputSubmit = async (options) => {
    * 附加参数应该是一个键值对对象,最终和和已有的文本参数和文件参数合并成一个新的键值对对象发送给websocket
    */
   // 获取附加表单的数据项目
-  // 如果
   if (other_options && typeof other_options === 'object') {
     for (let key in other_options) {
       msg_obj[key] = other_options[key];
@@ -545,15 +541,9 @@ function handleWSSend(chat_id, value) {
    * 2. 发送消息
    */
 
-  /**
-   * 当对话类型为文档报告时,websocket连接地址不同
-   */
-  // const agent = CHAT_AGENT_INFOMATION.value.agent;
-  // const menu_id = agent.menuId / 1;
-  // const chat_type = menu_id === 1 ? 'excel' : '';
-
   //  初始化websocket连接
-  initWSConnection(props.agent_id, chat_id, current_chat_type.value);
+  const menu_id = current_menu_id.value;
+  initWSConnection(props.agent_id, chat_id, menu_id);
   // 发送socket连接
   sendWSMessage(value);
   /**