import { jsonParse, jsonStringify } from '../../utils/utils'; import generateClientUniqueId from '../../utils/generate-client-unique-id'; import { formatCodePython, formatCodeSql } from './format-code-string'; import { getIcon4Answer } from './get-icon-4-dialog'; import { formatRefferenceString, formatRefferenceFlag, formatFileDownloadStr } from './format-dialog-answer-custom-markdown-str'; import formatDialogAnswerAttachedHtmlBeforeRender from './format-dialog-answer-attached-html-before-render'; /** * 格式化websocket发送消息的参数 * 此方法返回的数据项,为智能体返回的回答的数据 * * 请注意,通常情况下,此文件改动,可能意味着 ./format-dialog-answer-from-history.js 文件也需要改动 * 此文件是针对 实时对话 进行的回答字符串的处理 * ./format-dialog-answer-from-history.js 文件是针对历史会话回答的字符串进行处理 * @param {string} message_str * @param {object} preMsg - 前一次的消息,如果是流式消息,则需要上一次的Content进行拼接,从而形成新的消息 * @returns */ export default function formatDialogAnswerFromWebsocketReceiveMessage(message_str, preMsg, agentInfo) { const res_content = jsonParse(message_str); // 复制一份原消息内容 const copyPreMsg = jsonParse(jsonStringify(preMsg)); const icon_src = getIcon4Answer(agentInfo); /** * 类别: * close * error * message * stream * system */ const resType = res_content.type; const resMessage = res_content.message; // 消息内容 const resRefference = res_content.reference; // 引用消息 const resStepMessage = res_content.step_message; // 消息内容 const resFiles = res_content.files; // 文件 const resMessageFiles = res_content.message_files; // 关联的文件 const resDownloadUrl = res_content.download_url; // 下载链接 const resFileUrl = res_content.file_url; // 文件链接 const resFileName = res_content.file_name; // 文件名称 const resImageUrl = res_content.image_url; // 图片链接 const resExcelUrl = res_content.excel_url; // excel链接 const resExcelName = res_content.excel_name; // excel文件 const resCode = res_content.code; // 代码内容 const resSQL = res_content.sql; // SQL内容 // 文档出卷返回的数据 // 需要进行文件下载 // file_name: "76157b5884554a56bf3ed27990d44f97_1734603024" // file_url: "/api/files/download/?agent_id=basic_question_talk&file_id=76157b5884554a56bf3ed27990d44f97_1734603024&file_type=word" // message: "已经为您生成了10道中等难度的选择题,并已将这些题目保存到名为76157b5884554a56bf3ed27990d44f97_1734603024的docx文件中。希望这些题目符合您的需求!如果有其他要求,请随时告知。" // type: "message" // ------------------------------------ // 报表合并返回的数据:需要进行文件下载 // 本次对话的消息内容 const currentMsg = { /** * 对话消息类别 * 0 历史消息 * 1 新消息(本次进入页面新建的消息,但是已经结束轮次) * 2 当前的消息(此刻正在进行中的消息) */ client_custom_chat_type: 2, /** * 此项的类别 * a 智能体的回答 * q 客户端的提问 */ client_custom_item_type: 'a', // 回答的答案 /** * 会话展示时,可以通过此值,判断该如何进行内容显示 * 当值为0时,可能显示加载中动画 * 当值为1时,展示消息内容,展示 停止生成按钮 * 当值为2时,可能展示反馈操作按钮 */ client_custom_chat_status: 1, // 此轮会话的状态值 0 加载中 1 进行中 2 已结束 // 图标 client_custom_icon: icon_src, question: res_content.question, // 用户的提问内容 // answer: '', // 消息正文,markdown格式,需要进行解析 // system: '', // 系统消息 // 进行中的消息: 系统消息 client_custom_running_msg: '' // file: '', // image_url: '', // code: '', // sql: '', // reference: '' }; /** * 将前面websocket发来的数据,合并到当前的消息中 */ for (let key in copyPreMsg) { if (key === 'client_custom_chat_type' || key === 'client_custom_chat_status') { continue; } else { currentMsg[key] = copyPreMsg[key]; } } // 0 未开始 1 进行中 2 已结束 3 错误 let chat_status = 0; let chat_msg = ''; if (resType === 'message') { // 消息 chat_status = 1; currentMsg.answer = resMessage; if (resExcelUrl && resExcelName) { // 智能数据可能存在此数据 // 并且可以确保,返回的是Excel类型,后缀名为 .xlsx,且仅有文件名,没有后缀 currentMsg.client_custom_linked_download_files = { file_name: resExcelName + '.xlsx', file_url: resExcelUrl }; } if (resFileUrl && resFileName) { // 出题组卷可能存在此数据 // 并且可以确保返回的文件名没有后缀,且是 .docx 格式 currentMsg.client_custom_linked_download_files = { file_name: resFileName + '.docx', file_url: resFileUrl }; } if (resDownloadUrl) { // 文档报告可能存在此数据(type document_report) const real_url = decodeURIComponent(resDownloadUrl); const file_url_arr = decodeURIComponent(resDownloadUrl).split('/'); const file_name = file_url_arr[file_url_arr.length - 1]; // const file = { // file_type: 'word', // file_url: resDownloadUrl, // file_name: `${file_name}.docx` || '点击下载' // }; // currentMsg.file = file; // const download_file_str = formatFileDownloadStr(file_name, real_url); // currentMsg.answer = currentMsg.agentInfo + download_file_str; currentMsg.client_custom_linked_download_files = { file_name: file_name, file_url: real_url }; } // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // ------------------------------------------------------------- // 智能数据:代码和图片处理 // 上传一个excel,提问:生成一个饼状图 if (resCode) { // 智能数据可能存在此字段 const code_formated = formatCodePython(resCode); currentMsg.client_custom_linked_code = code_formated; } if (resSQL) { // 智能数据可能存在此字段 // 代码数据不能使用markdown解析器进行解析,否则会乱码 const sql_formated = formatCodeSql(resSQL); // const sql_formated = formatMarkdownString(resSQL); currentMsg.client_custom_linked_sql = sql_formated; } if (resImageUrl) { // 智能数据可能会存在此值 currentMsg.client_custom_linked_image = resImageUrl; } // ------------------------------------------------------ // ------------------------------------------------------ // ------------------------------------------------------ // ------------------------------------------------------ // ------------------------------------------------------ // 知识问答:文档引用 // 处理可能存在的文档引用效果 // 在知识问答板块中,正文存在文档引用效果 currentMsg.answer = formatRefferenceFlag(currentMsg.answer); // 文档引用效果 if (resRefference) { // 文档引用,在知识问答板块中,存在一些文档引用内容 // 需要在对话的答案底部显示文档引用的节点 // 将文档引用相关的数据拼接到答案的底部 const ref_str = formatRefferenceString(resRefference, 'client_custom_linked_refference_full_content'); if (ref_str) { currentMsg.answer = currentMsg.answer + `${ref_str}`; } // 添加字段:客户端自定义的相关字段,link完整数据 // 在答案展示部分,需要根据此数据展示文档引用效果 currentMsg.client_custom_linked_refference_full_content = resRefference; } } if (resType === 'stream') { // 流消息 chat_status = 1; // 拼接数据 if (preMsg && preMsg.answer) { currentMsg.answer = preMsg.answer + resMessage; } else { currentMsg.answer = resMessage; } if (resFiles) { // 历史记录也有此同样处理 // 文档合并有此数据 if (resFiles[0]) { const fileInfo = resFiles[0]; const f_url = fileInfo.file_url; const mock_url = `http://127.0.0.1${f_url}`; const urlObj = new URL(mock_url); const file_type = urlObj.searchParams.get('file_type'); let f_name = fileInfo.file_name; if (file_type === 'word') { f_name = f_name + '.docx'; } else { // 对于非 word类型,未知文件名 } currentMsg.client_custom_linked_download_files = { file_name: f_name, file_url: fileInfo.file_url }; } } if (resDownloadUrl) { // 报表合并 const real_url = decodeURIComponent(resDownloadUrl); const file_url_arr = decodeURIComponent(resDownloadUrl).split('/'); const file_name = file_url_arr[file_url_arr.length - 1]; currentMsg.client_custom_linked_download_files = { file_name: file_name, file_url: real_url }; } } if (resType === 'system') { // 系统消息 chat_status = 1; // currentMsg.answer = resMessage; currentMsg.client_custom_running_msg = resMessage; } if (resType === 'close') { // 会话结束 chat_status = 2; currentMsg.client_custom_chat_status = 2; // 次轮会话已结束 currentMsg.client_custom_chat_type = 1; // 修改消息类型 currentMsg.client_custom_running_msg = ''; // 已结束:系统消息不再展示 // TODO: 合并原先的内容,形成最终结果 // 如果有新消息,生成一个新消息返回,如果没有新消息,则返回原消息 if (resMessageFiles) { // 小数绘图存在此数据 const arr = []; if (Array.isArray(resMessageFiles)) { resMessageFiles.forEach((item, index) => { arr.push(item); }); // fullImageUrls.url = arr; } else { // fullImageUrls.url = arr; } // arr的值类似于: ['https://xxx.com/ancd.jpg']; } if (resMessage) { // close里依然有message,合并message(小数绘图的文生图里有这种可能性) currentMsg.answer = resMessage; } } if (resType === 'error') { // 错误消息 chat_status = 3; currentMsg.client_custom_chat_status = 2; // 本轮会话已结束 currentMsg.client_custom_chat_type = 1; // 修改消息类型: 改为 结束 currentMsg.answer = resMessage; } /** * 依据智能体回答的内容 * 生成一个唯一的ID */ currentMsg.client_custom_unique_id = generateClientUniqueId(currentMsg.answer); // --------------------------------------------------------------- // --------------------------------------------------------------- // --------------------------------------------------------------- // --------------------------------------------------------------- // /** // * 在answer字符串渲染到界面之前,在answer后拼接的html字符串 // */ // let temp_html_str = ''; // // 处理python代码 // if (currentMsg.client_custom_linked_code) { // temp_html_str = temp_html_str + currentMsg.client_custom_linked_code; // } // // 由于SQL和代码不能通过markdown解析,所以此处进行字符串的拼接 // if (currentMsg.client_custom_linked_sql) { // temp_html_str = temp_html_str + currentMsg.client_custom_linked_sql; // } // // 处理图片展示 // if (currentMsg.client_custom_linked_image) { // temp_html_str = temp_html_str + ``; // } // // 拼接文件的下载链接 // if (currentMsg.client_custom_linked_download_files) { // const file_name = currentMsg.client_custom_linked_download_files.file_name; // const file_url = currentMsg.client_custom_linked_download_files.file_url; // const download_file_str = formatFileDownloadStr(file_name, file_url); // temp_html_str = temp_html_str + download_file_str; // } // /** // * 在answer字符串渲染到界面之前,在answer后拼接的html字符串 // */ // currentMsg.client_custom_attached_html_before_render = temp_html_str; formatDialogAnswerAttachedHtmlBeforeRender(currentMsg); return { status: chat_status, // 本轮会话的状态:0 未开始 1 进行中 2 已结束 3 错误 message: chat_msg, data: currentMsg }; }