format-dialog-answer-from-websocket_receive_message.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. import { jsonParse, jsonStringify } from '../../utils/utils';
  2. import { formatStaticAssetsUrl } from '../../utils/utils';
  3. import generateClientUniqueId from '../../utils/generate-client-unique-id';
  4. import { formatCodePython, formatCodeSql } from './format-code-string';
  5. import formatAnwserString from './format-anwser-string';
  6. // import { formatFileDownloadStr } from './format-dialog-answer-custom-markdown-str';
  7. import { getIcon4Answer } from './get-icon-4-dialog';
  8. import {
  9. formatRefferenceString,
  10. formatRefferenceFlag,
  11. formatFileDownloadStr
  12. } from './format-dialog-answer-custom-markdown-str';
  13. /**
  14. * 格式化websocket发送消息的参数
  15. * 此方法返回的数据项,为智能体返回的回答的数据
  16. * @param {string} message_str
  17. * @param {object} preMsg - 前一次的消息,如果是流式消息,则需要上一次的Content进行拼接,从而形成新的消息
  18. * @returns
  19. */
  20. export default function formatDialogAnswerFromWebsocketReceiveMessage(message_str, preMsg, agentInfo) {
  21. const res_content = jsonParse(message_str);
  22. // 复制一份原消息内容
  23. const copyPreMsg = jsonParse(jsonStringify(preMsg));
  24. const icon_src = getIcon4Answer(agentInfo);
  25. /**
  26. * 类别:
  27. * close
  28. * error
  29. * message
  30. * stream
  31. * system
  32. */
  33. const resType = res_content.type;
  34. const resMessage = res_content.message; // 消息内容
  35. const resRefference = res_content.reference; // 引用消息
  36. const resStepMessage = res_content.step_message; // 消息内容
  37. const resFiles = res_content.files; // 文件
  38. const resMessageFiles = res_content.message_files; // 关联的文件
  39. const resDownloadUrl = res_content.download_url; // 下载链接
  40. const resFileUrl = res_content.file_url; // 文件链接
  41. const resFileName = res_content.file_name; // 文件名称
  42. const resImageUrl = res_content.image_url; // 图片链接
  43. const resExcelUrl = res_content.excel_url; // excel链接
  44. const resExcelName = res_content.excel_name; // excel文件
  45. const resCode = res_content.code; // 代码内容
  46. const resSQL = res_content.sql; // SQL内容
  47. // 文档出卷返回的数据
  48. // 需要进行文件下载
  49. // file_name: "76157b5884554a56bf3ed27990d44f97_1734603024"
  50. // file_url: "/api/files/download/?agent_id=basic_question_talk&file_id=76157b5884554a56bf3ed27990d44f97_1734603024&file_type=word"
  51. // message: "已经为您生成了10道中等难度的选择题,并已将这些题目保存到名为76157b5884554a56bf3ed27990d44f97_1734603024的docx文件中。希望这些题目符合您的需求!如果有其他要求,请随时告知。"
  52. // type: "message"
  53. // ------------------------------------
  54. // 报表合并返回的数据:需要进行文件下载
  55. // 本次对话的消息内容
  56. const currentMsg = {
  57. /**
  58. * 对话消息类别
  59. * 0 历史消息
  60. * 1 新消息(本次进入页面新建的消息,但是已经结束轮次)
  61. * 2 当前的消息(此刻正在进行中的消息)
  62. */
  63. client_custom_chat_type: 2,
  64. /**
  65. * 此项的类别
  66. * a 智能体的回答
  67. * q 客户端的提问
  68. */
  69. client_custom_item_type: 'a', // 回答的答案
  70. /**
  71. * 会话展示时,可以通过此值,判断该如何进行内容显示
  72. * 当值为0时,可能显示加载中动画
  73. * 当值为1时,展示消息内容,展示 停止生成按钮
  74. * 当值为2时,可能展示反馈操作按钮
  75. */
  76. client_custom_chat_status: 1, // 此轮会话的状态值 0 加载中 1 进行中 2 已结束
  77. // 图标
  78. client_custom_icon: icon_src,
  79. question: res_content.question // 用户的提问内容
  80. // answer: '', // 消息正文,markdown格式,需要进行解析
  81. // system: '', // 系统消息
  82. // file: '',
  83. // image_url: '',
  84. // code: '',
  85. // sql: '',
  86. // reference: ''
  87. };
  88. /**
  89. * 将前面websocket发来的数据,合并到当前的消息中
  90. */
  91. for (let key in copyPreMsg) {
  92. if (key === 'client_custom_chat_type' || key === 'client_custom_chat_status') {
  93. continue;
  94. } else {
  95. currentMsg[key] = copyPreMsg[key];
  96. }
  97. }
  98. // 0 未开始 1 进行中 2 已结束 3 错误
  99. let chat_status = 0;
  100. let chat_msg = '';
  101. if (resType === 'message') {
  102. // 消息
  103. chat_status = 1;
  104. currentMsg.answer = resMessage;
  105. if (resExcelUrl && resExcelName) {
  106. // 智能数据可能存在此数据
  107. // 并且可以确保,返回的是Excel类型,后缀名为 .xlsx,且仅有文件名,没有后缀
  108. currentMsg.client_custom_linked_download_files = {
  109. file_name: resExcelName + '.xlsx',
  110. file_url: resExcelUrl
  111. };
  112. }
  113. if (resFileUrl && resFileName) {
  114. // 出题组卷可能存在此数据
  115. // 并且可以确保返回的文件名没有后缀,且是 .docx 格式
  116. currentMsg.client_custom_linked_download_files = {
  117. file_name: resFileName + '.docx',
  118. file_url: resFileUrl
  119. };
  120. }
  121. if (resDownloadUrl) {
  122. // 文档报告可能存在此数据(type document_report)
  123. const real_url = decodeURIComponent(resDownloadUrl);
  124. const file_url_arr = decodeURIComponent(resDownloadUrl).split('/');
  125. const file_name = file_url_arr[file_url_arr.length - 1];
  126. // const file = {
  127. // file_type: 'word',
  128. // file_url: resDownloadUrl,
  129. // file_name: `${file_name}.docx` || '点击下载'
  130. // };
  131. // currentMsg.file = file;
  132. // const download_file_str = formatFileDownloadStr(file_name, real_url);
  133. // currentMsg.answer = currentMsg.agentInfo + download_file_str;
  134. currentMsg.client_custom_linked_download_files = {
  135. file_name: file_name,
  136. file_url: real_url
  137. };
  138. }
  139. // -------------------------------------------------------------
  140. // -------------------------------------------------------------
  141. // -------------------------------------------------------------
  142. // -------------------------------------------------------------
  143. // -------------------------------------------------------------
  144. // -------------------------------------------------------------
  145. // -------------------------------------------------------------
  146. // 智能数据:代码和图片处理
  147. // 上传一个excel,提问:生成一个饼状图
  148. if (resCode) {
  149. // 智能数据可能存在此字段
  150. const code_formated = formatCodePython(resCode);
  151. currentMsg.client_custom_linked_code = code_formated;
  152. }
  153. if (resSQL) {
  154. // 智能数据可能存在此字段
  155. // 代码数据不能使用markdown解析器进行解析,否则会乱码
  156. const sql_formated = formatCodeSql(resSQL);
  157. // const sql_formated = resSQL;
  158. currentMsg.client_custom_linked_sql = sql_formated;
  159. }
  160. if (resImageUrl) {
  161. // 智能数据可能会存在此值
  162. currentMsg.client_custom_linked_image = resImageUrl;
  163. }
  164. // ------------------------------------------------------
  165. // ------------------------------------------------------
  166. // ------------------------------------------------------
  167. // ------------------------------------------------------
  168. // ------------------------------------------------------
  169. // 知识问答:文档引用
  170. // 处理可能存在的文档引用效果
  171. // 在知识问答板块中,正文存在文档引用效果
  172. currentMsg.answer = formatRefferenceFlag(currentMsg.answer);
  173. // 文档引用效果
  174. if (resRefference) {
  175. // 文档引用,在知识问答板块中,存在一些文档引用内容
  176. // 需要在对话的答案底部显示文档引用的节点
  177. // 将文档引用相关的数据拼接到答案的底部
  178. const ref_str = formatRefferenceString(resRefference, 'client_custom_linked_refference_full_content');
  179. if (ref_str) {
  180. currentMsg.answer = currentMsg.answer + `${ref_str}`;
  181. }
  182. // 添加字段:客户端自定义的相关字段,link完整数据
  183. // 在答案展示部分,需要根据此数据展示文档引用效果
  184. currentMsg.client_custom_linked_refference_full_content = resRefference;
  185. }
  186. }
  187. if (resType === 'stream') {
  188. // 流消息
  189. chat_status = 1;
  190. // 拼接数据
  191. if (preMsg && preMsg.answer) {
  192. currentMsg.answer = preMsg.answer + resMessage;
  193. } else {
  194. currentMsg.answer = resMessage;
  195. }
  196. if (resFiles) {
  197. // 文档合并有此数据
  198. if (resFiles[0]) {
  199. currentMsg.client_custom_linked_download_files = {
  200. file_name: resFiles[0].file_name,
  201. file_url: resFiles[0].file_url
  202. };
  203. }
  204. }
  205. }
  206. if (resType === 'system') {
  207. // 系统消息
  208. chat_status = 1;
  209. currentMsg.answer = resMessage;
  210. }
  211. if (resType === 'close') {
  212. // 会话结束
  213. chat_status = 2;
  214. currentMsg.client_custom_chat_status = 2; // 次轮会话已结束
  215. currentMsg.client_custom_chat_type = 1; // 修改消息类型
  216. // TODO: 合并原先的内容,形成最终结果
  217. // 如果有新消息,生成一个新消息返回,如果没有新消息,则返回原消息
  218. if (resMessageFiles) {
  219. // 小数绘图存在此数据
  220. const arr = [];
  221. if (Array.isArray(resMessageFiles)) {
  222. resMessageFiles.forEach((item, index) => {
  223. arr.push(item);
  224. });
  225. // fullImageUrls.url = arr;
  226. } else {
  227. // fullImageUrls.url = arr;
  228. }
  229. // arr的值类似于: ['https://xxx.com/ancd.jpg'];
  230. }
  231. if (resMessage) {
  232. // close里依然有message,合并message(小数绘图的文生图里有这种可能性)
  233. currentMsg.answer = resMessage;
  234. }
  235. }
  236. if (resType === 'error') {
  237. // 错误消息
  238. chat_status = 3;
  239. currentMsg.client_custom_chat_status = 2; // 本轮会话已结束
  240. currentMsg.client_custom_chat_type = 1; // 修改消息类型: 改为 结束
  241. currentMsg.answer = resMessage;
  242. }
  243. /**
  244. * 依据智能体回答的内容
  245. * 生成一个唯一的ID
  246. */
  247. currentMsg.client_custom_unique_id = generateClientUniqueId(currentMsg.answer);
  248. // if (currentMsg.answer) {
  249. // // 将markdown转换为html文件
  250. // currentMsg.answer = formatAnwserString(currentMsg.answer);
  251. // if (currentMsg.client_custom_linked_code) {
  252. // currentMsg.answer = currentMsg.answer + currentMsg.client_custom_linked_code;
  253. // }
  254. // // 由于SQL和代码不能通过markdown解析,所以此处进行字符串的拼接
  255. // if (currentMsg.client_custom_linked_sql) {
  256. // currentMsg.answer = currentMsg.answer + currentMsg.client_custom_linked_sql;
  257. // }
  258. // if (currentMsg.client_custom_linked_image) {
  259. // currentMsg.answer = currentMsg.answer + `<img src="${currentMsg.client_custom_linked_image}" />`;
  260. // }
  261. // // 拼接文件的下载链接
  262. // if (currentMsg.client_custom_linked_download_files) {
  263. // const file_name = currentMsg.client_custom_linked_download_files.file_name;
  264. // const file_url = currentMsg.client_custom_linked_download_files.file_url;
  265. // const download_file_str = formatFileDownloadStr(file_name, file_url);
  266. // currentMsg.answer = currentMsg.answer + download_file_str;
  267. // }
  268. // }
  269. return {
  270. status: chat_status, // 本轮会话的状态:0 未开始 1 进行中 2 已结束 3 错误
  271. message: chat_msg,
  272. data: currentMsg
  273. };
  274. }