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 { formatMarkdownString } from './format-anwser-string'; import { formatStaticAssetsUrl } from '../../utils/utils'; import { formatRefferenceString, formatRefferenceFlag, formatFileDownloadStr } from './format-dialog-answer-custom-markdown-str'; import formatDialogAnswerAttachedHtmlBeforeRender from './format-dialog-answer-attached-html-before-render'; import { isDate } from 'lodash-es'; /** * 格式化sse发送消息的参数 * 此方法返回的数据项,为智能体返回的回答的数据 * * 请注意,通常情况下,此文件改动,可能意味着 ./format-dialog-answer-from-history.js 文件也需要改动 * 此文件是针对 实时对话 进行的回答字符串的处理 * ./format-dialog-answer-from-history.js 文件是针对历史会话回答的字符串进行处理 * @param {string} message_str * @param {object} preMsg - 前一次的消息,如果是流式消息,则需要上一次的Content进行拼接,从而形成新的消息 * @returns */ let fountThink = false; let message_id = ''; export default function formatDialogAnswerFromSseReceiveMessage(message_obj, preMsg, agentInfo, mixAnswer) { const res_content = message_obj.data; if (message_id !== message_obj?.message_id) { fountThink = false; message_id = message_obj?.message_id; } // 复制一份原消息内容 const copyPreMsg = jsonParse(jsonStringify(preMsg)); const icon_src = getIcon4Answer(agentInfo); /** * 类别: * message_end * error * message * stream * system */ const resType = message_obj.event; const resMessage = res_content?.answer; // 消息内容 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: '' // 会话的message_id client_custom_chat_message_id: '', deep_answer: '', parent_id: '' // client_custom_item_think: false, // 是否有思考 // client_custom_item_think_content: '', //思考内容 // client_custom_item_internet: false, //是否联网 // client_custom_item_internet_list: [], //联网内容 // client_custom_chat_message_id: '' //会话的message_id }; // if (Object.keys(message_obj).includes('message_id')) { // } if (Object.keys(message_obj).includes('isDeep')) { currentMsg.client_custom_item_think = message_obj.isDeep; } if (Object.keys(message_obj).includes('isInternet')) { currentMsg.client_custom_item_internet = message_obj.isInternet; if (res_content.title === 'SearXNG 搜索') { currentMsg.client_custom_item_internet_list = res_content.outputs.json; } } /** * 将前面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; // currentMsg.client_custom_running_msg = ''; // 已有正常消息,系统消息置空,不再显示 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 (message_obj.isDeep) { if (!fountThink) { currentMsg.client_custom_chat_deep_loading = true; currentMsg.deep_answer = currentMsg.deep_answer += res_content.answer; if (res_content.answer == '') { currentMsg.client_custom_chat_deep_loading = false; fountThink = true; } } else { currentMsg.answer = currentMsg.answer += res_content.answer; } } else { currentMsg.answer = currentMsg.answer += res_content.answer; } if (message_obj.parent_id) { currentMsg.parent_id = message_obj.parent_id; } // 测试代码 // if (!message_obj.isDeep) { // currentMsg.client_custom_chat_deep_loading = true; // currentMsg.deep_answer = currentMsg.deep_answer += res_content.answer; // } // // // 拼接数据 // if (preMsg && preMsg.answer) { // currentMsg.answer = preMsg.answer + image + 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.client_custom_running_msg = resMessage; } else { // 非系统消息类型:系统消息不再展示 currentMsg.client_custom_running_msg = ''; } /** * 处理workflow类型的消息 * workflow_started:工作流开始 * node_started:工作流节点开始 * node_finished:工作流节点结束 * workflow_finished:工作流完成 * */ if (['workflow_started', 'node_started', 'node_finished'].includes(resType)) { chat_status = 1; currentMsg.client_custom_running_msg = res_content.title; } if (['workflow_finished'].includes(resType)) { chat_status = 1; if (res_content.outputs.output) { currentMsg.answer = res_content.outputs.output || ''; } if (res_content.outputs.file) { currentMsg.client_custom_linked_download_files = { file_name: res_content.outputs.file.filename, file_url: res_content.outputs.file.url }; } if (res_content.outputs.fileList) { const file_list = res_content.outputs.fileList; currentMsg.client_custom_linked_download_files_List = []; for (const file of file_list) { currentMsg.client_custom_linked_download_files_List.push({ file_name: file.filename, file_url: file.url }); } } chat_status = 2; } if (resType === 'message_file') { chat_status = 1; if (res_content.type == 'image') { currentMsg.client_custom_linked_image = res_content.url; } if (res_content.type == 'document') { if (res_content.url) { const parts = path.split('/'); const fileName = parts.pop(); currentMsg.client_custom_linked_download_files = { file_name: fileName, file_url: res_content.url }; } } } if (resType === 'message_end') { // 会话结束 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; } currentMsg.client_custom_chat_deep_loading = false; } 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); if (message_obj.message_id) { currentMsg.client_custom_chat_message_id = message_obj.message_id; } currentMsg.client_custom_chat_message_id = message_obj.message_id || ''; return { status: chat_status, // 本轮会话的状态:0 未开始 1 进行中 2 已结束 3 错误 message: chat_msg, data: currentMsg }; }