| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- 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: ''
- // 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;
- }
- }
- // console.log(message_obj.message_id, 3333);
- // console.log(currentMsg.client_custom_chat_message_id, 444);
- /**
- * 将前面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 == '</think>') {
- 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.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)) {
- 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.answer += `<img src="${res_content.url}" />`;
- 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;
- }
- }
- 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 + `<img src="${currentMsg.client_custom_linked_image}" />`;
- // }
- // // 拼接文件的下载链接
- // 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
- };
- }
|