@gientech/modual 2.2.3-fix.6 → 2.2.3-fix.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (523) hide show
  1. package/README.md +761 -761
  2. package/{dist/assets/GientechStreamReader-Bae2-4f7.js → assets/GientechStreamReader-r5ZTSZk2.js} +1 -1
  3. package/{dist/assets/LeftOutlined-COk0w5nY.js → assets/LeftOutlined-DZMeGbKk.js} +1 -1
  4. package/{dist/assets/circle-plus-DOKqXUMk.js → assets/circle-plus-B73z_SUN.js} +1 -1
  5. package/{src/modules/database/assets → assets}/database.svg +11 -11
  6. package/{src/modules/database/assets → assets}/database_add.svg +53 -53
  7. package/{dist/assets → assets}/database_connect.svg +66 -66
  8. package/{dist/assets → assets}/database_upload.svg +29 -29
  9. package/{dist/assets → assets}/databse.svg +6 -6
  10. package/{dist/assets → assets}/defaultWeLogo.svg +14 -14
  11. package/{dist/assets → assets}/graph.svg +4 -4
  12. package/{src/assets/img → assets}/iconAi.svg +9 -9
  13. package/{dist/assets/index-BKbpfN9S.js → assets/index-97Oe7YBe.js} +1 -1
  14. package/{dist/assets/index-BXdyn2W3.js → assets/index-B4k3tK0f.js} +1 -1
  15. package/{dist/assets/index-Bin0NZwF.js → assets/index-BDc2zBbG.js} +7 -3
  16. package/assets/index-BIEKgWu0.js +27 -0
  17. package/assets/index-CzZQWA2P.js +1 -0
  18. package/{dist/assets/index-CpSzj-Sx.js → assets/index-DHK_n74G.js} +58 -73
  19. package/assets/index-DPA1HCWQ.js +1372 -0
  20. package/assets/index-DPyRygOA.js +745 -0
  21. package/assets/index-YHUI3QVz.js +943 -0
  22. package/{dist/assets/index-vfI1_Qg0.js → assets/index-iOuQJ8vu.js} +1 -1
  23. package/{dist/assets/index-Ct_k24Ar.js → assets/index-usBlUHOb.js} +1 -1
  24. package/{src/modules/assistantConfig/assets → assets}/knowledge.svg +4 -4
  25. package/{src/modules/database/assets → assets}/mysql.svg +14 -14
  26. package/assets/plus-BICgMvz9.js +6 -0
  27. package/assets/search-CD5YKija.js +6 -0
  28. package/{dist/assets → assets}/sensitive.svg +5 -5
  29. package/assets/style-Blt3Kyyt.js +196 -0
  30. package/assets/style2.css +1 -0
  31. package/{dist/assets/triangle-alert-CaJaaCaZ.js → assets/triangle-alert-C4Z1AkGW.js} +1 -1
  32. package/{dist/assets/x-B65AntWN.js → assets/x-DWGzNb9c.js} +1 -1
  33. package/{dist/assistantConfig.js → assistantConfig.js} +14 -9
  34. package/chat.js +1 -0
  35. package/chatCompare.js +1 -0
  36. package/database.js +20 -0
  37. package/{dist/databaseId.js → databaseId.js} +1 -1
  38. package/{dist/databaseTable.js → databaseTable.js} +1 -1
  39. package/index.js +1 -0
  40. package/modelManage.js +1 -0
  41. package/package.json +44 -125
  42. package/{dist/sensitive.js → sensitive.js} +6 -6
  43. package/streamFilesReader.js +1 -0
  44. package/{public/worker → worker}/pdf.worker.min.js +21 -21
  45. package/.editorconfig +0 -38
  46. package/.prettierignore +0 -16
  47. package/.prettierrc +0 -17
  48. package/CHANGELOG.md +0 -162
  49. package/Dockerfile +0 -15
  50. package/USAGE.md +0 -247
  51. package/bash.exe.stackdump +0 -40
  52. package/components.json +0 -21
  53. package/default.conf +0 -19
  54. package/dist/README.md +0 -761
  55. package/dist/assets/database.svg +0 -11
  56. package/dist/assets/database_add.svg +0 -53
  57. package/dist/assets/iconAi.svg +0 -9
  58. package/dist/assets/index-1PwCuRjv.js +0 -1061
  59. package/dist/assets/index-7QvYA6eT.js +0 -1
  60. package/dist/assets/index-BhUNGJOe.js +0 -27
  61. package/dist/assets/index-DT3qkjJ3.js +0 -750
  62. package/dist/assets/index-lFBFf_0k.js +0 -1890
  63. package/dist/assets/knowledge.svg +0 -4
  64. package/dist/assets/mysql.svg +0 -14
  65. package/dist/assets/style-CfNUqKAA.js +0 -196
  66. package/dist/assets/style2.css +0 -1
  67. package/dist/chat.js +0 -1
  68. package/dist/chatCompare.js +0 -1
  69. package/dist/database.js +0 -20
  70. package/dist/index.js +0 -1
  71. package/dist/modelManage.js +0 -1
  72. package/dist/package.json +0 -73
  73. package/dist/streamFilesReader.js +0 -1
  74. package/dist/worker/pdf.worker.min.js +0 -22
  75. package/doc_assets/images/1.png +0 -0
  76. package/doc_assets/images/3.png +0 -0
  77. package/doc_assets/images/component-screenshot.png +0 -1
  78. package/doc_assets//346/226/271/346/241/210/v2.0.7/345/217/230/346/233/264/346/200/273/347/273/223.md +0 -115
  79. package/doc_assets//346/226/271/346/241/210//344/274/230/345/214/226/346/226/271/346/241/210-/345/244/232/344/274/232/350/257/235SSE/350/277/236/346/216/245/347/256/241/347/220/206.md +0 -504
  80. package/doc_assets//346/226/271/346/241/210//346/215/242/350/241/214/346/240/274/345/274/217/344/277/235/346/214/201/344/274/230/345/214/226/346/226/271/346/241/210.md +0 -359
  81. package/eslint.config.js +0 -92
  82. package/index.html +0 -13
  83. package/package.json.demo-backup +0 -109
  84. package/postcss.config.cjs +0 -19
  85. package/public/icons/answerAwartar.png +0 -0
  86. package/public/icons/docx-file.png +0 -0
  87. package/public/icons/folder.png +0 -0
  88. package/public/icons/html.png +0 -0
  89. package/public/icons/image.png +0 -0
  90. package/public/icons/jpg-file.png +0 -0
  91. package/public/icons/json.png +0 -0
  92. package/public/icons/md.png +0 -0
  93. package/public/icons/pdf.png +0 -0
  94. package/public/icons/pptx.png +0 -0
  95. package/public/icons/questionAwartar.png +0 -0
  96. package/public/icons/sheets.png +0 -0
  97. package/public/icons/txt.png +0 -0
  98. package/public/icons/xlsx.png +0 -0
  99. package/public/vite.svg +0 -1
  100. package/rag/assets/index.Bd0tNzw0.js +0 -2797
  101. package/rag/assets/index.D6t67hlu.css +0 -1
  102. package/rag/assets/left.KBHV5h7q.jpg +0 -0
  103. package/rag/assets/worker-BbpylX7l.DptbXke_.js +0 -13
  104. package/release-it.json +0 -21
  105. package/scripts/README.md +0 -133
  106. package/scripts/build-demo.js +0 -88
  107. package/scripts/check-changelog.cjs +0 -124
  108. package/scripts/check-version.cjs +0 -49
  109. package/scripts/decrypt-api-key.js +0 -95
  110. package/scripts/demo-selector.js +0 -216
  111. package/scripts/dev-demo.js +0 -85
  112. package/scripts/open-file.cjs +0 -61
  113. package/scripts/preview-demo.js +0 -130
  114. package/scripts/run-demo.bat +0 -34
  115. package/src/assets/img/close.png +0 -0
  116. package/src/assets/img/database.png +0 -0
  117. package/src/assets/img/downArrow.png +0 -0
  118. package/src/assets/img/downLoad.png +0 -0
  119. package/src/assets/img/excel.png +0 -0
  120. package/src/assets/img/graphIcon.png +0 -0
  121. package/src/assets/img/img.png +0 -0
  122. package/src/assets/img/pdf.png +0 -0
  123. package/src/assets/img/ppt.png +0 -0
  124. package/src/assets/img/search.svg +0 -3
  125. package/src/assets/img/selected.svg +0 -4
  126. package/src/assets/img/singleQa.png +0 -0
  127. package/src/assets/img/txt.png +0 -0
  128. package/src/assets/img/webSearch.png +0 -0
  129. package/src/assets/img/word.png +0 -0
  130. package/src/assets/login/homeBg.png +0 -0
  131. package/src/assets/login/left.jpg +0 -0
  132. package/src/assets/login/logoImg.png +0 -0
  133. package/src/examples/ConversationAssistantPage/index.tsx +0 -42
  134. package/src/examples/LoginPage/index.tsx +0 -20
  135. package/src/examples/chat/components/DrawerGraphPreview.tsx +0 -78
  136. package/src/examples/chat/index.tsx +0 -171
  137. package/src/examples/chat/logo03.png +0 -0
  138. package/src/examples/chatCompare/icons/rag_think.svg +0 -8
  139. package/src/examples/chatCompare/icons/wenda_lianwangsousuo.svg +0 -9
  140. package/src/examples/chatCompare/index.tsx +0 -154
  141. package/src/examples/gientechStreamFilesReader/index.tsx +0 -979
  142. package/src/examples/headlessChat/assets/mind.svg +0 -6
  143. package/src/examples/headlessChat/assets/net.svg +0 -7
  144. package/src/examples/headlessChat/index.tsx +0 -298
  145. package/src/examples/knowledgebaseDetails/index.tsx +0 -119
  146. package/src/examples/ragDatabaseDataPage/index.tsx +0 -40
  147. package/src/examples/ragDatabaseIdPage/index.tsx +0 -126
  148. package/src/examples/ragDatabasePage/index.tsx +0 -36
  149. package/src/examples/ragModelManagePage/index.tsx +0 -107
  150. package/src/examples/ragModelManagePage/style.css +0 -7
  151. package/src/examples/ragSearchPage/index.tsx +0 -0
  152. package/src/examples/ragSensitiveWordsPage/index.tsx +0 -117
  153. package/src/examples/ragSensitiveWordsPage/style.css +0 -16
  154. package/src/examples/sensitiveId/index.tsx +0 -41
  155. package/src/examples/streamFiles/index.tsx +0 -417
  156. package/src/examples/utils/demo_setting_pannel.ts +0 -0
  157. package/src/lib_enter.ts +0 -44
  158. package/src/main.tsx +0 -5
  159. package/src/main.tsx.backup +0 -5
  160. package/src/modules/CHAT_UNIFICATION_PLAN.md +0 -324
  161. package/src/modules/assistantConfig/assets/databse.svg +0 -6
  162. package/src/modules/assistantConfig/assets/empty.png +0 -0
  163. package/src/modules/assistantConfig/assets/graph.svg +0 -4
  164. package/src/modules/assistantConfig/assets/sensitive.svg +0 -5
  165. package/src/modules/assistantConfig/components/Database.tsx +0 -171
  166. package/src/modules/assistantConfig/components/Graph.tsx +0 -177
  167. package/src/modules/assistantConfig/components/Knowledge.tsx +0 -276
  168. package/src/modules/assistantConfig/components/NotFoundContent.tsx +0 -21
  169. package/src/modules/assistantConfig/components/Paragraph.tsx +0 -51
  170. package/src/modules/assistantConfig/components/ParamsItem.tsx +0 -40
  171. package/src/modules/assistantConfig/components/ResourceBinderItem.tsx +0 -133
  172. package/src/modules/assistantConfig/components/SearchableSelector.tsx +0 -500
  173. package/src/modules/assistantConfig/components/Sensitive.tsx +0 -221
  174. package/src/modules/assistantConfig/components/SliderInput.tsx +0 -66
  175. package/src/modules/assistantConfig/constants.tsx +0 -75
  176. package/src/modules/assistantConfig/index.tsx +0 -785
  177. package/src/modules/assistantConfig/server.ts +0 -262
  178. package/src/modules/chat/AllFiles.tsx +0 -158
  179. package/src/modules/chat/Conversations/Item.tsx +0 -169
  180. package/src/modules/chat/Conversations/List.tsx +0 -210
  181. package/src/modules/chat/Conversations/groupByTime.ts +0 -39
  182. package/src/modules/chat/Conversations/index.tsx +0 -255
  183. package/src/modules/chat/ReferenceBar.tsx +0 -659
  184. package/src/modules/chat/constants.tsx +0 -66
  185. package/src/modules/chat/i18n.ts +0 -151
  186. package/src/modules/chat/i18n.tsx +0 -151
  187. package/src/modules/chat/icons/rag_think.svg +0 -8
  188. package/src/modules/chat/icons/wenda_lianwangsousuo.svg +0 -9
  189. package/src/modules/chat/index.tsx +0 -2400
  190. package/src/modules/chat/referenceCom/DeleteModal.tsx +0 -75
  191. package/src/modules/chat/referenceCom/DrawerContent.tsx +0 -136
  192. package/src/modules/chat/referenceCom/DrawerDatabase.tsx +0 -102
  193. package/src/modules/chat/referenceCom/DrawerGraphPreview.tsx +0 -86
  194. package/src/modules/chat/referenceCom/DrawerPreview.tsx +0 -73
  195. package/src/modules/chat/referenceCom/DrawerTitle.tsx +0 -26
  196. package/src/modules/chat/referenceCom/RenameModal.tsx +0 -86
  197. package/src/modules/chat/referenceCom/TagCom.tsx +0 -30
  198. package/src/modules/chat/style.css +0 -6
  199. package/src/modules/chat/style.less +0 -7
  200. package/src/modules/chat/types.ts +0 -17
  201. package/src/modules/chat/utils/index.ts +0 -348
  202. package/src/modules/chatCompare/UseChatCompareHooks.ts +0 -103
  203. package/src/modules/chatCompare/components/AichatCompareUseController.tsx +0 -754
  204. package/src/modules/chatCompare/components/AssistantSelector.tsx +0 -127
  205. package/src/modules/chatCompare/components/ChatInputer.tsx +0 -67
  206. package/src/modules/chatCompare/components/ChatInstance.tsx +0 -426
  207. package/src/modules/chatCompare/components/ChatItem.tsx +0 -556
  208. package/src/modules/chatCompare/components/Sender/FileCardCommon.tsx +0 -97
  209. package/src/modules/chatCompare/components/Sender/FileUpload.tsx +0 -89
  210. package/src/modules/chatCompare/components/Sender/FilesDisplay.tsx +0 -309
  211. package/src/modules/chatCompare/components/Sender/VoiceInput.tsx +0 -80
  212. package/src/modules/chatCompare/components/Sender/contexts/BadgeContext.tsx +0 -36
  213. package/src/modules/chatCompare/components/Sender/fileIcon.tsx +0 -100
  214. package/src/modules/chatCompare/components/Sender/index.tsx +0 -850
  215. package/src/modules/chatCompare/components/UseChatInstanceHooks.ts +0 -406
  216. package/src/modules/chatCompare/components/UseScrollHooks.ts +0 -36
  217. package/src/modules/chatCompare/components/components/AllFiles.tsx +0 -156
  218. package/src/modules/chatCompare/components/components/DeleteModal.tsx +0 -75
  219. package/src/modules/chatCompare/components/components/DrawerContent.tsx +0 -138
  220. package/src/modules/chatCompare/components/components/DrawerDatabase.tsx +0 -110
  221. package/src/modules/chatCompare/components/components/DrawerGraphPreview.tsx +0 -95
  222. package/src/modules/chatCompare/components/components/DrawerPreview.tsx +0 -75
  223. package/src/modules/chatCompare/components/components/DrawerTitle.tsx +0 -26
  224. package/src/modules/chatCompare/components/components/DrawerVideo.tsx +0 -85
  225. package/src/modules/chatCompare/components/components/ReferenceBar.tsx +0 -659
  226. package/src/modules/chatCompare/components/components/RenameModal.tsx +0 -86
  227. package/src/modules/chatCompare/components/components/TagCom.tsx +0 -30
  228. package/src/modules/chatCompare/components/defaultStyleSet.tsx +0 -148
  229. package/src/modules/chatCompare/components/server.ts +0 -208
  230. package/src/modules/chatCompare/components/serverFn.ts +0 -172
  231. package/src/modules/chatCompare/components/style.less +0 -97
  232. package/src/modules/chatCompare/components/useFileManager.ts +0 -173
  233. package/src/modules/chatCompare/components/utils.ts +0 -31
  234. package/src/modules/chatCompare/data.ts +0 -842
  235. package/src/modules/chatCompare/index.tsx +0 -537
  236. package/src/modules/chatCompare/utils/AiChat.types.tsx +0 -110
  237. package/src/modules/chatCompare/utils/constants.tsx +0 -70
  238. package/src/modules/chatCompare/utils/fileUploadValidator.ts +0 -183
  239. package/src/modules/chatCompare/utils/icons/rag_think.svg +0 -8
  240. package/src/modules/chatCompare/utils/icons/wenda_lianwangsousuo.svg +0 -9
  241. package/src/modules/chatCompare/utils/index.ts +0 -46
  242. package/src/modules/database/CreateModal.tsx +0 -402
  243. package/src/modules/database/assets/Doris.png +0 -0
  244. package/src/modules/database/assets/PostgreSQL.png +0 -0
  245. package/src/modules/database/assets/SQLServer.png +0 -0
  246. package/src/modules/database/assets/database_connect.svg +0 -66
  247. package/src/modules/database/assets/database_upload.svg +0 -29
  248. package/src/modules/database/assets/empty.png +0 -0
  249. package/src/modules/database/index.tsx +0 -477
  250. package/src/modules/database/server.ts +0 -196
  251. package/src/modules/databaseId/CustomCom.tsx +0 -156
  252. package/src/modules/databaseId/EditConfig.tsx +0 -280
  253. package/src/modules/databaseId/UploadDrawer.tsx +0 -535
  254. package/src/modules/databaseId/assets/aiOptimize.svg +0 -10
  255. package/src/modules/databaseId/assets/empty.png +0 -0
  256. package/src/modules/databaseId/assets/template.svg +0 -6
  257. package/src/modules/databaseId/assets/upload.svg +0 -9
  258. package/src/modules/databaseId/assets/useTemp.svg +0 -6
  259. package/src/modules/databaseId/i18n.ts +0 -360
  260. package/src/modules/databaseId/index.tsx +0 -855
  261. package/src/modules/databaseId/server.ts +0 -286
  262. package/src/modules/databaseId/style.css +0 -5
  263. package/src/modules/databaseTable/EditRowDrawer.tsx +0 -124
  264. package/src/modules/databaseTable/index.tsx +0 -359
  265. package/src/modules/databaseTable/server.ts +0 -180
  266. package/src/modules/headlessChat/ReferenceBar.tsx +0 -783
  267. package/src/modules/headlessChat/constants.tsx +0 -54
  268. package/src/modules/headlessChat/index.tsx +0 -1903
  269. package/src/modules/headlessChat/referenceCom/DeleteModal.tsx +0 -75
  270. package/src/modules/headlessChat/referenceCom/DrawerContent.tsx +0 -136
  271. package/src/modules/headlessChat/referenceCom/DrawerDatabase.tsx +0 -102
  272. package/src/modules/headlessChat/referenceCom/DrawerGraphPreview.tsx +0 -86
  273. package/src/modules/headlessChat/referenceCom/DrawerPreview.tsx +0 -73
  274. package/src/modules/headlessChat/referenceCom/DrawerTitle.tsx +0 -26
  275. package/src/modules/headlessChat/referenceCom/RenameModal.tsx +0 -86
  276. package/src/modules/headlessChat/referenceCom/TagCom.tsx +0 -30
  277. package/src/modules/headlessChat/style.less +0 -3
  278. package/src/modules/headlessChat/types.ts +0 -23
  279. package/src/modules/headlessChat/utils/index.ts +0 -348
  280. package/src/modules/knowledgeBase/index.tsx +0 -58
  281. package/src/modules/knowledgeBase/server.ts +0 -196
  282. package/src/modules/knowledgebaseDetails/KnowledgeBaseDetails.tsx +0 -169
  283. package/src/modules/knowledgebaseDetails/components/KnowledgeBaseSummaryCard.tsx +0 -193
  284. package/src/modules/knowledgebaseDetails/components/fileManagementParts.tsx +0 -534
  285. package/src/modules/knowledgebaseDetails/components/index.ts +0 -3
  286. package/src/modules/knowledgebaseDetails/index.ts +0 -3
  287. package/src/modules/knowledgebaseDetails/modules/ConfigModule.tsx +0 -49
  288. package/src/modules/knowledgebaseDetails/modules/FaqModule.tsx +0 -47
  289. package/src/modules/knowledgebaseDetails/modules/KnowledgeParseModule.tsx +0 -771
  290. package/src/modules/knowledgebaseDetails/modules/RetrievalTestModule.tsx +0 -49
  291. package/src/modules/knowledgebaseDetails/modules/UploadManagementModule.tsx +0 -49
  292. package/src/modules/knowledgebaseDetails/modules/types.ts +0 -44
  293. package/src/modules/knowledgebaseDetails/modules-shim.d.ts +0 -14
  294. package/src/modules/knowledgebaseDetails/servers/analysis.ts +0 -5
  295. package/src/modules/knowledgebaseDetails/servers/index.ts +0 -318
  296. package/src/modules/login/components/Login/LoginBox/index.tsx +0 -105
  297. package/src/modules/login/components/Login/RegisterBox/index.tsx +0 -181
  298. package/src/modules/login/components/Login/index.tsx +0 -100
  299. package/src/modules/login/i18n.ts +0 -217
  300. package/src/modules/login/index.tsx +0 -113
  301. package/src/modules/login/style.css +0 -3
  302. package/src/modules/login/useServices.ts +0 -53
  303. package/src/modules/login/utils.ts +0 -42
  304. package/src/modules/modelManage/ConfigDrawer.tsx +0 -267
  305. package/src/modules/modelManage/ReplaceModal.tsx +0 -113
  306. package/src/modules/modelManage/assets/empty.png +0 -0
  307. package/src/modules/modelManage/const.ts +0 -51
  308. package/src/modules/modelManage/i18n.ts +0 -407
  309. package/src/modules/modelManage/index.tsx +0 -668
  310. package/src/modules/modelManage/server.ts +0 -231
  311. package/src/modules/nodegraph/index.tsx +0 -1
  312. package/src/modules/search/assets/Icon-history.svg +0 -8
  313. package/src/modules/search/assets/answerAwartar.png +0 -0
  314. package/src/modules/search/assets/doc.png +0 -0
  315. package/src/modules/search/assets/genera.gif +0 -0
  316. package/src/modules/search/assets/icon-robot.svg +0 -9
  317. package/src/modules/search/assets/icon-search-bar.svg +0 -14
  318. package/src/modules/search/assets/icon-sub-title.svg +0 -3
  319. package/src/modules/search/assets/icon-title.svg +0 -9
  320. package/src/modules/search/assets/icon-zoomOut.svg +0 -9
  321. package/src/modules/search/assets/iconAi.svg +0 -9
  322. package/src/modules/search/assets/pdf.png +0 -0
  323. package/src/modules/search/assets/ppt.png +0 -0
  324. package/src/modules/search/assets/search.svg +0 -3
  325. package/src/modules/search/assets/selected.svg +0 -4
  326. package/src/modules/search/assets/txt.png +0 -0
  327. package/src/modules/search/assets/xls.png +0 -0
  328. package/src/modules/search/components/AssisSelect.tsx +0 -137
  329. package/src/modules/search/components/Editor/ChatViewEditor.tsx +0 -261
  330. package/src/modules/search/components/Editor/aichat.css +0 -1
  331. package/src/modules/search/components/Editor/constant.ts +0 -13
  332. package/src/modules/search/components/Editor/index.tsx +0 -113
  333. package/src/modules/search/components/Editor/plugins/autofomatRules.ts +0 -332
  334. package/src/modules/search/components/Editor/plugins/convertImgPlugins.tsx +0 -20
  335. package/src/modules/search/components/Editor/plugins/createIndexes.tsx +0 -38
  336. package/src/modules/search/components/Editor/plugins/displayer.ts +0 -298
  337. package/src/modules/search/components/Editor/plugins/imageClick.tsx +0 -32
  338. package/src/modules/search/components/Editor/plugins/myplugin.tsx +0 -98
  339. package/src/modules/search/components/Editor/ui/avatar.tsx +0 -19
  340. package/src/modules/search/components/Editor/ui/blockquote-element.tsx +0 -21
  341. package/src/modules/search/components/Editor/ui/button.tsx +0 -58
  342. package/src/modules/search/components/Editor/ui/calendar.tsx +0 -68
  343. package/src/modules/search/components/Editor/ui/caption.tsx +0 -46
  344. package/src/modules/search/components/Editor/ui/checkbox.tsx +0 -27
  345. package/src/modules/search/components/Editor/ui/code-block-combobox.tsx +0 -188
  346. package/src/modules/search/components/Editor/ui/code-block-element.css +0 -434
  347. package/src/modules/search/components/Editor/ui/code-block-element.tsx +0 -39
  348. package/src/modules/search/components/Editor/ui/code-leaf.tsx +0 -24
  349. package/src/modules/search/components/Editor/ui/code-line-element.tsx +0 -10
  350. package/src/modules/search/components/Editor/ui/code-syntax-leaf.tsx +0 -21
  351. package/src/modules/search/components/Editor/ui/column-element.tsx +0 -30
  352. package/src/modules/search/components/Editor/ui/column-group-element.tsx +0 -94
  353. package/src/modules/search/components/Editor/ui/command.tsx +0 -75
  354. package/src/modules/search/components/Editor/ui/comment-avatar.tsx +0 -22
  355. package/src/modules/search/components/Editor/ui/comment-create-form.tsx +0 -37
  356. package/src/modules/search/components/Editor/ui/comment-item.tsx +0 -74
  357. package/src/modules/search/components/Editor/ui/comment-leaf.tsx +0 -49
  358. package/src/modules/search/components/Editor/ui/comment-more-dropdown.tsx +0 -42
  359. package/src/modules/search/components/Editor/ui/comment-reply-items.tsx +0 -22
  360. package/src/modules/search/components/Editor/ui/comment-resolve-button.tsx +0 -32
  361. package/src/modules/search/components/Editor/ui/comment-value.tsx +0 -34
  362. package/src/modules/search/components/Editor/ui/comments-popover.tsx +0 -63
  363. package/src/modules/search/components/Editor/ui/date-element.tsx +0 -83
  364. package/src/modules/search/components/Editor/ui/dialog.tsx +0 -63
  365. package/src/modules/search/components/Editor/ui/draggable.tsx +0 -177
  366. package/src/modules/search/components/Editor/ui/dropdown-menu.tsx +0 -180
  367. package/src/modules/search/components/Editor/ui/emoji-input-element.tsx +0 -85
  368. package/src/modules/search/components/Editor/ui/excalidraw-element.tsx +0 -28
  369. package/src/modules/search/components/Editor/ui/fixed-toolbar-buttons.tsx +0 -76
  370. package/src/modules/search/components/Editor/ui/fixed-toolbar.tsx +0 -8
  371. package/src/modules/search/components/Editor/ui/floating-toolbar-buttons.tsx +0 -51
  372. package/src/modules/search/components/Editor/ui/floating-toolbar.tsx +0 -77
  373. package/src/modules/search/components/Editor/ui/heading-element.tsx +0 -48
  374. package/src/modules/search/components/Editor/ui/highlight-leaf.tsx +0 -17
  375. package/src/modules/search/components/Editor/ui/hr-element.tsx +0 -30
  376. package/src/modules/search/components/Editor/ui/icons.tsx +0 -267
  377. package/src/modules/search/components/Editor/ui/image-element.tsx +0 -74
  378. package/src/modules/search/components/Editor/ui/inline-combobox.tsx +0 -368
  379. package/src/modules/search/components/Editor/ui/input.tsx +0 -25
  380. package/src/modules/search/components/Editor/ui/insert-dropdown-menu.tsx +0 -218
  381. package/src/modules/search/components/Editor/ui/kbd-leaf.tsx +0 -20
  382. package/src/modules/search/components/Editor/ui/link-element.tsx +0 -29
  383. package/src/modules/search/components/Editor/ui/link-floating-toolbar.tsx +0 -161
  384. package/src/modules/search/components/Editor/ui/list-element.tsx +0 -30
  385. package/src/modules/search/components/Editor/ui/mark-toolbar-button.tsx +0 -24
  386. package/src/modules/search/components/Editor/ui/media-embed-element.tsx +0 -133
  387. package/src/modules/search/components/Editor/ui/media-popover.tsx +0 -97
  388. package/src/modules/search/components/Editor/ui/mention-element.tsx +0 -43
  389. package/src/modules/search/components/Editor/ui/mention-input-element.tsx +0 -141
  390. package/src/modules/search/components/Editor/ui/mode-dropdown-menu.tsx +0 -93
  391. package/src/modules/search/components/Editor/ui/more-dropdown-menu.tsx +0 -67
  392. package/src/modules/search/components/Editor/ui/paragraph-element.tsx +0 -4
  393. package/src/modules/search/components/Editor/ui/placeholder.tsx +0 -52
  394. package/src/modules/search/components/Editor/ui/popover.tsx +0 -32
  395. package/src/modules/search/components/Editor/ui/resizable.tsx +0 -66
  396. package/src/modules/search/components/Editor/ui/separator.tsx +0 -25
  397. package/src/modules/search/components/Editor/ui/style.less +0 -12
  398. package/src/modules/search/components/Editor/ui/table-cell-element.tsx +0 -143
  399. package/src/modules/search/components/Editor/ui/table-element.tsx +0 -243
  400. package/src/modules/search/components/Editor/ui/table-row-element.tsx +0 -22
  401. package/src/modules/search/components/Editor/ui/tableValue.tsx +0 -135
  402. package/src/modules/search/components/Editor/ui/todo-list-element.tsx +0 -43
  403. package/src/modules/search/components/Editor/ui/toggle-element.tsx +0 -31
  404. package/src/modules/search/components/Editor/ui/toolbar.tsx +0 -157
  405. package/src/modules/search/components/Editor/ui/tooltip.tsx +0 -65
  406. package/src/modules/search/components/Editor/ui/turn-into-dropdown-menu.tsx +0 -160
  407. package/src/modules/search/components/Editor/ui/with-draggables.tsx +0 -175
  408. package/src/modules/search/components/FileList.tsx +0 -287
  409. package/src/modules/search/components/ImageGroupView/index.tsx +0 -85
  410. package/src/modules/search/components/ResultContent.tsx +0 -232
  411. package/src/modules/search/components/SearchInput.tsx +0 -232
  412. package/src/modules/search/components/SearchLanding.tsx +0 -74
  413. package/src/modules/search/components/SearchView.tsx +0 -563
  414. package/src/modules/search/components/SimpleEditor.tsx +0 -158
  415. package/src/modules/search/components/SimpleFileList.tsx +0 -215
  416. package/src/modules/search/index.tsx +0 -10
  417. package/src/modules/search/reademe.md +0 -1
  418. package/src/modules/search/servers/apis.tsx +0 -19
  419. package/src/modules/search/servers/index.ts +0 -184
  420. package/src/modules/search/style.less +0 -503
  421. package/src/modules/search/type.ts +0 -22
  422. package/src/modules/search/utils.ts +0 -34
  423. package/src/modules/sensitive/i18n.ts +0 -391
  424. package/src/modules/sensitive/index.tsx +0 -604
  425. package/src/modules/sensitive/sensitiveEditor.tsx +0 -543
  426. package/src/modules/sensitive/server.ts +0 -197
  427. package/src/modules/sensitiveId/AutoTag.tsx +0 -311
  428. package/src/modules/sensitiveId/UploadModal.tsx +0 -181
  429. package/src/modules/sensitiveId/VirtualWrap.tsx +0 -125
  430. package/src/modules/sensitiveId/index.tsx +0 -253
  431. package/src/modules/sensitiveId/server.ts +0 -142
  432. package/src/modules/streamFilesReader/GientechStreamReader.tsx +0 -1658
  433. package/src/modules/streamFilesReader/components/Header/Toolbar.tsx +0 -0
  434. package/src/modules/streamFilesReader/components/Header/index.tsx +0 -297
  435. package/src/modules/streamFilesReader/index.tsx +0 -3
  436. package/src/style.css +0 -6
  437. package/src/type.d.ts +0 -0
  438. package/src/utils/commonFn.tsx +0 -153
  439. package/src/utils/decryptApiKey.ts +0 -40
  440. package/src/utils/gientechCommon/components/AppError.tsx +0 -32
  441. package/src/utils/gientechCommon/components/AppLoading.tsx +0 -75
  442. package/src/utils/gientechCommon/components/DeleteModal.tsx +0 -75
  443. package/src/utils/gientechCommon/components/DisplayError.tsx +0 -33
  444. package/src/utils/gientechCommon/components/DisplayLoading.tsx +0 -38
  445. package/src/utils/gientechCommon/components/FeedBackModal.tsx +0 -319
  446. package/src/utils/gientechCommon/components/FileCardCommon.tsx +0 -82
  447. package/src/utils/gientechCommon/components/FileManager/index.tsx +0 -418
  448. package/src/utils/gientechCommon/components/FileManager/style.css +0 -5
  449. package/src/utils/gientechCommon/components/Messages/GientechNewChatWelcome.tsx +0 -583
  450. package/src/utils/gientechCommon/components/Messages/ReferenceCard.tsx +0 -359
  451. package/src/utils/gientechCommon/components/Messages/RetriveItem.tsx +0 -245
  452. package/src/utils/gientechCommon/components/Messages/WebRetriveItem.tsx +0 -209
  453. package/src/utils/gientechCommon/components/Messages/defaultBot.png +0 -0
  454. package/src/utils/gientechCommon/components/Messages/defaultStyleSet.tsx +0 -148
  455. package/src/utils/gientechCommon/components/Messages/defaultWeLogo.svg +0 -14
  456. package/src/utils/gientechCommon/components/RenameModal.tsx +0 -86
  457. package/src/utils/gientechCommon/components/style.less +0 -11
  458. package/src/utils/gientechCommon/configs/commonConfig.ts +0 -2
  459. package/src/utils/gientechCommon/configs/senderConfig.ts +0 -0
  460. package/src/utils/gientechCommon/configs/stylesConfig.ts +0 -142
  461. package/src/utils/gientechCommon/hooks/AichatUseController.tsx +0 -761
  462. package/src/utils/gientechCommon/hooks/style.less +0 -8
  463. package/src/utils/gientechCommon/hooks/useFileDisplayTools.tsx +0 -352
  464. package/src/utils/gientechCommon/hooks/useFileManager.ts +0 -169
  465. package/src/utils/gientechCommon/slate/converters/deserializers.ts +0 -763
  466. package/src/utils/gientechCommon/slate/converters/mockData.ts +0 -232
  467. package/src/utils/gientechCommon/slate/converters/slateConverters.ts +0 -258
  468. package/src/utils/gientechCommon/slate/richElements/index.tsx +0 -499
  469. package/src/utils/gientechCommon/utils/fileUtils.ts +0 -86
  470. package/src/utils/gientechCommon/utils/index.ts +0 -386
  471. package/src/utils/gientechCommon/utils/request.ts +0 -37
  472. package/src/utils/gientechCommon/utils/serverFn.ts +0 -172
  473. package/src/utils/index.tsx +0 -186
  474. package/src/utils/testconfigs/demologin/index.tsx +0 -32
  475. package/src/utils/testconfigs/index.ts +0 -66
  476. package/src/vite-env.d.ts +0 -49
  477. package/stats.html +0 -4949
  478. package/tailwind.config.js +0 -170
  479. package/tsconfig.app.json +0 -31
  480. package/tsconfig.app.tsbuildinfo +0 -11
  481. package/tsconfig.json +0 -17
  482. package/tsconfig.node.json +0 -23
  483. package/tsconfig.node.tsbuildinfo +0 -1
  484. package/vite.config.app.ts +0 -91
  485. package/vite.config.ts +0 -238
  486. /package/{dist/assets → assets}/Doris.png +0 -0
  487. /package/{dist/assets → assets}/PostgreSQL.png +0 -0
  488. /package/{dist/assets → assets}/SQLServer.png +0 -0
  489. /package/{dist/assets → assets}/empty.png +0 -0
  490. /package/{dist/assets → assets}/homeBg.png +0 -0
  491. /package/{dist/assets → assets}/index-CpW6Dhpp.js +0 -0
  492. /package/{dist/assets → assets}/left.jpg +0 -0
  493. /package/{dist/assets → assets}/logoImg.png +0 -0
  494. /package/{dist/assets → assets}/style.css +0 -0
  495. /package/{dist/assets → assets}/style3.css +0 -0
  496. /package/{dist/assets → assets}/style4.css +0 -0
  497. /package/{dist/assets → assets}/style5.css +0 -0
  498. /package/{dist/assets → assets}/worker-BbpylX7l.js +0 -0
  499. /package/{dist/assistantConfig.d.ts → assistantConfig.d.ts} +0 -0
  500. /package/{dist/chat.d.ts → chat.d.ts} +0 -0
  501. /package/{dist/chatCompare.d.ts → chatCompare.d.ts} +0 -0
  502. /package/{dist/database.d.ts → database.d.ts} +0 -0
  503. /package/{dist/databaseId.d.ts → databaseId.d.ts} +0 -0
  504. /package/{dist/databaseTable.d.ts → databaseTable.d.ts} +0 -0
  505. /package/{dist/icons → icons}/answerAwartar.png +0 -0
  506. /package/{dist/icons → icons}/docx-file.png +0 -0
  507. /package/{dist/icons → icons}/folder.png +0 -0
  508. /package/{dist/icons → icons}/html.png +0 -0
  509. /package/{dist/icons → icons}/image.png +0 -0
  510. /package/{dist/icons → icons}/jpg-file.png +0 -0
  511. /package/{dist/icons → icons}/json.png +0 -0
  512. /package/{dist/icons → icons}/md.png +0 -0
  513. /package/{dist/icons → icons}/pdf.png +0 -0
  514. /package/{dist/icons → icons}/pptx.png +0 -0
  515. /package/{dist/icons → icons}/questionAwartar.png +0 -0
  516. /package/{dist/icons → icons}/sheets.png +0 -0
  517. /package/{dist/icons → icons}/txt.png +0 -0
  518. /package/{dist/icons → icons}/xlsx.png +0 -0
  519. /package/{dist/index.d.ts → index.d.ts} +0 -0
  520. /package/{dist/modelManage.d.ts → modelManage.d.ts} +0 -0
  521. /package/{dist/sensitive.d.ts → sensitive.d.ts} +0 -0
  522. /package/{dist/streamFilesReader.d.ts → streamFilesReader.d.ts} +0 -0
  523. /package/{dist/vite.svg → vite.svg} +0 -0
@@ -1,1903 +0,0 @@
1
- import React, { useEffect, useState, useMemo, useRef } from 'react';
2
- import { AiChat, AppStatusManager, validateFileUpload, showValidationErrors } from '@mxmweb/aichat';
3
- import { ChatMessageAdapter } from '@mxmweb/rtext';
4
- import request from '../../utils/gientechCommon/utils/request';
5
- import { registerPDFWorker } from '../streamFilesReader';
6
- registerPDFWorker('/worker/pdf.worker.min.js');
7
- import {
8
- getFeedbackList,
9
- handleCancelFeedBack,
10
- handleFeedBack,
11
- } from '../../utils/gientechCommon/utils/serverFn';
12
- import { toCopy } from '../../utils/commonFn';
13
- import { uid } from 'uid';
14
- import GientechNewChatWelcome from '../../utils/gientechCommon/components/Messages/GientechNewChatWelcome';
15
- import AichatUseController from '../../utils/gientechCommon/hooks/AichatUseController';
16
- import { useFileManager } from '../../utils/gientechCommon/hooks/useFileManager';
17
- import { useFileDisplayTools } from '../../utils/gientechCommon/hooks/useFileDisplayTools';
18
- import FeedBackModal from '../../utils/gientechCommon/components/FeedBackModal';
19
- import { ConfigProvider, Drawer, message } from 'antd';
20
- import AppLoading from '../../utils/gientechCommon/components/AppLoading';
21
- import DisplayLoading from '../../utils/gientechCommon/components/DisplayLoading';
22
- import AppError from '../../utils/gientechCommon/components/AppError';
23
- import DisplayError from '../../utils/gientechCommon/components/DisplayError';
24
- import { DefaultSenderConfig } from './constants';
25
- import { mergeFiles } from '../../utils/gientechCommon/utils/fileUtils';
26
- import '@mxmweb/rtext/style.css';
27
- import '@mxmweb/aichat/style.css';
28
- import '@mxmweb/zui/style.css';
29
- import { ReferenceBar } from './ReferenceBar';
30
- import { DrawerType } from '../chat';
31
- import { fileViewTypes, getMarkExcludeType, getUrlPrefix, TempBaseUrl } from './utils';
32
- import { DrawerContent } from './referenceCom/DrawerContent';
33
- import axios from 'axios';
34
- import DrawerPreview from './referenceCom/DrawerPreview';
35
-
36
- interface SenderConfig {
37
- upload_size_limit?: number;
38
- upload_number_limit?: number;
39
- upload_file_type_limit?: string[];
40
- upload_limit_message?: string;
41
- actions?: Array<{
42
- name: string;
43
- icon?: React.ReactNode;
44
- badgeCount?: number;
45
- tip?: string;
46
- }>;
47
- switchs?: Array<{
48
- label: string;
49
- name: string;
50
- type: 'switch' | 'checkbox';
51
- defaultValue: boolean;
52
- enabled: boolean;
53
- icon?: React.ReactNode;
54
- }>;
55
- }
56
-
57
- interface HeadlessChatAdopterProps {
58
- token: string;
59
- url?: string;
60
- initialMessage?: string;
61
- title?: string;
62
- configId?: string;
63
- useLogin?: boolean;
64
- styles?: any;
65
- welcomeContent?: string;
66
- senderConfig?: SenderConfig;
67
- onError?: (ems: any) => void;
68
- eventsEmit?: (eventName: string, data: any) => void;
69
- [key: string]: any;
70
- }
71
-
72
- export default function withHeadLessChatAdopter(
73
- WrappedComponent: React.ComponentType<any> = AiChat as any
74
- ) {
75
- /**
76
- * GientechChatAdopter 高阶组件
77
- * 封装了与Gientech后端服务的接口对接、状态管理、事件处理等核心业务逻辑
78
- * @param {React.ComponentType} WrappedComponent - 需要包裹的基础聊天组件,默认为 AiChat
79
- */
80
- return function GientechChatAdopter({
81
- disclaimers,
82
- token,
83
- url = 'http://localhost:8888',
84
- welcomeContent = '欢迎来到小鲸智能助手,有什么能帮你的么?',
85
- styles,
86
- eventsEmit,
87
- onError,
88
- configId,
89
- senderConfig,
90
- initialMessage,
91
- ...rest
92
- }: HeadlessChatAdopterProps) {
93
- console.log('[HeadlessChat] 组件初始化 - 接收到的 props:', {
94
- configId,
95
- url,
96
- hasToken: !!token,
97
- });
98
- const [open, setOpen] = useState(false);
99
- const [content, setContent] = useState<
100
- | {
101
- title: '';
102
- file_type: '';
103
- metadata: { offset: [] };
104
- }
105
- | any
106
- >(null);
107
- const [drawerType, setDrawerType] = useState<string>('mark');
108
- const [curFileInfo, setCurFileInfo] = useState({
109
- url: '',
110
- parse_url: '',
111
- file_type: '',
112
- file_name: '',
113
- });
114
- // =================================================================
115
- // State Management - 状态管理
116
- // =================================================================
117
- const [conversationList, setConversationList] = useState<any[]>([]); // 对话列表
118
- const [chatData, setChatData] = useState<any[]>([]); // 所有对话的聊天记录
119
- const [activeSessionId, setActiveSessionId] = useState<string | undefined>(undefined); // 当前激活的对话ID
120
- const [recommandQuestions, setRecommandQuestions] = useState<any[]>([]); // 推荐问题列表
121
- const [assistantList] = useState<any[]>([]); // 智能体(助手)列表
122
- const [appStatus, setAppStatus] = useState<AppStatusManager>({
123
- display: 'ready', // 主聊天区域状态: ready, loading, processing, error, uploading
124
- sender: 'ready', // 发送器状态: ready, processing, error, uploading
125
- app: 'initializing', // 应用整体状态: initializing, ready, error
126
- });
127
- // 深合并函数,用于合并默认配置和外部配置
128
- function deepMerge(defaultConfig: any, customConfig: any): any {
129
- if (!customConfig) return defaultConfig;
130
- const result = { ...defaultConfig };
131
- for (const key in customConfig) {
132
- if (Object.prototype.hasOwnProperty.call(customConfig, key)) {
133
- // 特殊处理 actions 数组:合并而不是替换
134
- if (
135
- key === 'actions' &&
136
- Array.isArray(defaultConfig[key]) &&
137
- Array.isArray(customConfig[key])
138
- ) {
139
- // 创建一个以 name 为 key 的 Map,优先使用 customConfig 中的 action
140
- const actionsMap = new Map();
141
- // 先添加 defaultConfig 中的 actions
142
- (defaultConfig[key] as any[]).forEach((action: any) => {
143
- if (action.name) {
144
- actionsMap.set(action.name, action);
145
- }
146
- });
147
- // 然后用 customConfig 中的 actions 覆盖或添加
148
- (customConfig[key] as any[]).forEach((action: any) => {
149
- if (action.name) {
150
- actionsMap.set(action.name, action);
151
- }
152
- });
153
- result[key] = Array.from(actionsMap.values());
154
- } else if (
155
- typeof defaultConfig[key] === 'object' &&
156
- defaultConfig[key] !== null &&
157
- !Array.isArray(defaultConfig[key]) &&
158
- typeof customConfig[key] === 'object' &&
159
- customConfig[key] !== null &&
160
- !Array.isArray(customConfig[key])
161
- ) {
162
- result[key] = deepMerge(defaultConfig[key], customConfig[key]);
163
- } else {
164
- result[key] = customConfig[key];
165
- }
166
- }
167
- }
168
- return result;
169
- }
170
-
171
- // 发送器配置支持外部传入,merge 默认和外部
172
- const [dynamicSenderConfig, setDynamicSenderConfig] = useState(() => {
173
- const merged = deepMerge(DefaultSenderConfig, senderConfig);
174
- return merged;
175
- });
176
-
177
- // 监听外部 senderConfig 变化自动 merge
178
- useEffect(() => {
179
- if (senderConfig) {
180
- const merged = deepMerge(DefaultSenderConfig, senderConfig);
181
- setDynamicSenderConfig(merged);
182
- }
183
- }, [senderConfig]);
184
-
185
- // 使用统一的文件管理 Hook
186
- const {
187
- fileManagerData,
188
- fileStatuses,
189
- setFileManagerData,
190
- setFileStatuses,
191
- pollFileStatus: pollFileStatusHook,
192
- handleRemoveFromTemp,
193
- resetStopFlag,
194
- setStopFlag,
195
- stoppedRef,
196
- } = useFileManager({
197
- url,
198
- token,
199
- activeSessionId,
200
- chatData,
201
- onError,
202
- });
203
-
204
- // 新增:记录 sender switchs 的选中状态
205
- const [senderSwitchValues, setSenderSwitchValues] = useState<{ [key: string]: boolean }>({});
206
-
207
- // =================================================================
208
- // Refs - 引用
209
- // =================================================================
210
- const prevActiveSessionId = useRef<string | undefined>(undefined); // 记录上一个激活的对话ID,用于对比变化
211
- const setUploadedFilesRef = useRef<(files: any[]) => void>(undefined); // 引用核心组件的文件上传方法
212
- const removeFileRef = useRef<(fileObj: any, idx: number, _type: string) => void>(undefined); // 引用核心组件的文件移除方法
213
- const fileInputRef = useRef<HTMLInputElement>(null); // 文件上传input引用
214
- const setFileListPopoverOpenRef = useRef<((open: boolean) => void) | null>(null); // 文件列表 Popover 控制函数引用
215
- const senderConfigRef = useRef<SenderConfig | undefined>(undefined); // 引用核心组件的上传限制配置
216
- const uploadedFilesRef = useRef<any[]>([]); // 引用核心组件的已上传文件列表
217
-
218
- const [feedParam, setFeedParam] = useState<{
219
- queryId?: number | string | undefined;
220
- restult?: number;
221
- }>({});
222
- const [openFeed, setOpenFeed] = useState(false);
223
- const [feedBackList, setFeedBackList] = useState<any>([]);
224
- // stoppedRef 已由 useFileManager hook 管理
225
-
226
- // =================================================================
227
- // Custom Hooks - 自定义钩子
228
- // =================================================================
229
- // 引入SSE控制器,封装了流式请求、消息管理等复杂逻辑
230
- const { api_startChat_re, addEmptyMessage, setLastEmptyMessage, stopStream } =
231
- AichatUseController({
232
- baseUrl: url,
233
- token,
234
- setChatData,
235
- activeSessionId,
236
- setAppStatus,
237
- setConversationList,
238
- });
239
-
240
- // =================================================================
241
- // Memoized Values - 缓存计算值
242
- // =================================================================
243
-
244
- // welcomeContent 伪消息唯一 id/time/queryId
245
- const welcomeMsgId = useRef(uid(32));
246
- const welcomeMsgQueryId = useRef(uid(32));
247
- const welcomeMsgTime = useRef(Date.now());
248
-
249
- /**
250
- * 将智能体列表转换为以ID为键的Map,便于快速查找
251
- */
252
- const assistantMap = useMemo(() => {
253
- const map: Record<string, any> = {};
254
- (assistantList || []).forEach(item => {
255
- map[item.id] = item;
256
- });
257
- return map;
258
- }, [assistantList]);
259
-
260
- /**
261
- * 根据 activeSessionId 从 chatData 中筛选出当前对话的数据, 并合并智能体信息
262
- */
263
- const currentChatData = useMemo(() => {
264
- let data = chatData.find((c: any) => c.id === activeSessionId) || {
265
- id: activeSessionId,
266
- messages: [],
267
- };
268
- let messages = data.messages || [];
269
- // 检查第一条是否已经是 welcome 消息,如果不是则插入
270
- if (welcomeContent && (messages.length === 0 || !messages[0]?.isDefault)) {
271
- messages = [
272
- {
273
- istype: 'ai',
274
- content: welcomeContent,
275
- time: welcomeMsgTime.current,
276
- clientSideId: welcomeMsgId.current,
277
- isWelcome: true,
278
- isDefault: true,
279
- queryId: welcomeMsgQueryId.current,
280
- },
281
- ...messages,
282
- ];
283
- }
284
- // 如果第一条已经是 isDefault: true 的欢迎消息,确保它的 isWelcome 字段存在
285
- if (messages[0]?.isDefault && !messages[0]?.isWelcome) {
286
- messages[0].isWelcome = true;
287
- }
288
- const assistantInfo = data.configId ? assistantMap[data.configId] : null;
289
- return {
290
- ...data,
291
- messages,
292
- assistantInfo,
293
- };
294
- }, [chatData, activeSessionId, assistantMap, welcomeContent]);
295
-
296
- /**
297
- * 从当前会话的所有用户消息的 filePaths 中收集所有文件
298
- * filePaths 应该包含所有历史文件,而 currentFiles 只是当前对话的上传文件
299
- */
300
- const allFilesFromQuery = useMemo(() => {
301
- const filesMap = new Map<string, any>(); // 使用 Map 去重,以 uid 为 key
302
-
303
- // 遍历当前会话的所有用户消息
304
- const userMessages = (currentChatData?.messages || []).filter(
305
- (msg: any) => msg.istype === 'user'
306
- );
307
-
308
- for (const msg of userMessages) {
309
- // 获取 filePaths(可能是 JSON 字符串或数组)
310
- const filePaths = msg.filePaths;
311
- if (!filePaths) continue;
312
-
313
- try {
314
- // 解析 filePaths(如果是字符串则解析,如果是数组则直接使用)
315
- const parsedFiles = typeof filePaths === 'string' ? JSON.parse(filePaths) : filePaths;
316
-
317
- if (Array.isArray(parsedFiles)) {
318
- // 将所有文件添加到 Map 中,以 uid 为 key 去重
319
- parsedFiles.forEach((file: any) => {
320
- if (file && file.uid) {
321
- filesMap.set(file.uid, file);
322
- }
323
- });
324
- }
325
- } catch (error) {
326
- console.warn('[HeadlessChat] 解析 filePaths 失败:', error, filePaths);
327
- }
328
- }
329
-
330
- return Array.from(filesMap.values());
331
- }, [currentChatData?.messages]);
332
-
333
- // 文件工具函数已提取到 useFileManager hook 中
334
-
335
- // 文件同步逻辑已由 useFileManager hook 处理
336
-
337
- // =================================================================
338
- // Side Effects (useEffect) - 副作用钩子
339
- // =================================================================
340
-
341
- /**
342
- * 跟踪 activeSessionId 的变化:
343
- * 1. 清理上一个无消息的临时会话
344
- * 2. 更新推荐问题
345
- */
346
- useEffect(() => {
347
- // 切换会话时,检查上一个会话是否为临时且无消息
348
- if (prevActiveSessionId.current && prevActiveSessionId.current !== activeSessionId) {
349
- const prevId = prevActiveSessionId.current;
350
- const prevConv = conversationList.find(c => c.sessionId === prevId && c.isNew);
351
- const prevChat = chatData.find(c => c.id === prevId && c.isNew);
352
- const prevHasMsg = prevChat && prevChat.messages && prevChat.messages.length > 0;
353
- // 如果是临时的且没有消息,则自动删除
354
- if (prevConv && !prevHasMsg) {
355
- setConversationList(list => list.filter(c => c.sessionId !== prevId));
356
- setChatData(list => list.filter(c => c.id !== prevId));
357
- }
358
- }
359
- prevActiveSessionId.current = activeSessionId;
360
-
361
- // 更新推荐问题为当前对话的最后一个推荐问题
362
- const historyRQ =
363
- currentChatData.messages && currentChatData.messages.length > 0
364
- ? currentChatData.messages[currentChatData.messages.length - 1].recommendQuestion
365
- : [];
366
- setRecommandQuestions(historyRQ);
367
- }, [activeSessionId, conversationList, chatData, currentChatData.messages]);
368
-
369
- /**
370
- * 1. useEffect 只拉助手列表,自动新建会话
371
- */
372
- useEffect(() => {
373
- setAppStatus(prev => ({ ...prev, app: 'initializing' }));
374
-
375
- if (token) {
376
- handleConversationCreate({ configId });
377
- }
378
- setAppStatus(prev => ({ ...prev, app: 'ready' }));
379
- }, [url, token, configId]);
380
-
381
- /**
382
- * 当 activeSessionId 变化时,获取对应的聊天记录
383
- */
384
- useEffect(() => {
385
- if (!activeSessionId) return;
386
- setAppStatus(prev => ({ ...prev, display: 'loading' }));
387
-
388
- setAppStatus(prev => ({ ...prev, display: 'ready' }));
389
- }, [activeSessionId, url, token]);
390
-
391
- /**
392
- * 自动发送初始消息
393
- * 当 activeSessionId 设置且组件准备好后,如果有 initialMessage,就自动发送
394
- */
395
- const hasSentInitialMessage = useRef(false);
396
- const initialMessageRef = useRef<string | undefined>(initialMessage);
397
-
398
- // 更新 ref,确保始终使用最新的 initialMessage
399
- useEffect(() => {
400
- initialMessageRef.current = initialMessage;
401
- }, [initialMessage]);
402
-
403
- useEffect(() => {
404
- // 确保只在组件初始化时发送一次,且 activeSessionId 已设置,且应用状态为 ready
405
- // 适配两种模式:
406
- // 1. 直接有token:组件挂载时 token 已存在,立即创建会话并发送
407
- // 2. 需要登录:登录成功后组件才开始渲染,此时 token 已有值,创建会话并发送
408
- if (
409
- initialMessageRef.current &&
410
- activeSessionId &&
411
- appStatus.app === 'ready' &&
412
- appStatus.display === 'ready' &&
413
- !hasSentInitialMessage.current
414
- ) {
415
- hasSentInitialMessage.current = true;
416
- // 延迟一下确保组件完全准备好
417
- setTimeout(() => {
418
- handleSenderSend({ content: initialMessageRef.current }, () => {});
419
- }, 100);
420
- }
421
- }, [activeSessionId, appStatus.app, appStatus.display, initialMessage]);
422
-
423
- // 文件角标逻辑已移除,upload action 不需要角标
424
- useEffect(() => {
425
- getFeedbackList({ url, token }, data => {
426
- setFeedBackList(data);
427
- });
428
- }, []);
429
-
430
- /**
431
- * 实时同步 fileStatuses 到当前消息的 currentFiles,便于消息区细致显示每个文件的处理状态
432
- */
433
- React.useEffect(() => {
434
- if (!fileStatuses.length) return;
435
- setChatData(chatList => {
436
- if (!chatList[0]) return chatList;
437
- const { messages } = chatList[0];
438
- for (let i = messages.length - 1; i >= 0; i--) {
439
- if (messages[i].istype === 'user') {
440
- const oldFiles = messages[i].currentFiles || [];
441
- messages[i].currentFiles = fileStatuses.map((f: any) => {
442
- const old = oldFiles.find((of: any) => of.uid === f.uid);
443
- return {
444
- name: f.file?.name || f.name,
445
- size: f.file?.size || f.size,
446
- type: f.file?.type || f.type,
447
- status: f.status,
448
- uid: f.uid,
449
- url: f.url || old?.url || '', // 优先用已有 url
450
- };
451
- });
452
- break;
453
- }
454
- }
455
- return [...chatList];
456
- });
457
- }, [fileStatuses]);
458
-
459
- // =================================================================
460
- // Core Functions - 核心功能函数
461
- // =================================================================
462
-
463
- // 1. 在组件作用域定义控制器和轮询停止标志
464
- let uploadController: AbortController | null = null;
465
- let stopPoll: (() => void) | null = null;
466
-
467
- /**
468
- * 轮询文件解析状态(使用统一的 hook)
469
- */
470
- const pollFileStatus = (
471
- uids: string[],
472
- onStatusUpdate: (serverStatuses: any[]) => void,
473
- onComplete: () => void,
474
- onFail: (errorMsg: string) => void
475
- ) => {
476
- stopPoll = pollFileStatusHook(uids, {
477
- onStatusUpdate,
478
- onComplete,
479
- onFail,
480
- });
481
- };
482
-
483
- /**
484
- * 设置消息的反馈结果(赞/踩)
485
- * @param {string} queryId - 消息ID
486
- * @param {number} result - 反馈结果 (1: 赞, -1: 踩)
487
- */
488
- const setFeed = (queryId: any, restult: any) => {
489
- setChatData(chatList => {
490
- const newList = [...chatList];
491
- if (!newList[0]) return newList;
492
- newList[0] = {
493
- ...newList[0],
494
- messages: newList[0].messages.map((item: any) => {
495
- if (item.queryId === queryId) {
496
- return {
497
- ...item,
498
- feedbackResult: restult,
499
- };
500
- }
501
- return item;
502
- }),
503
- };
504
- return newList;
505
- });
506
- };
507
-
508
- /**
509
- * 获取指定queryId的推荐问题
510
- * @param {string} queryId - 消息ID
511
- */
512
- const fetchRecommendQuestions = async (queryId: string) => {
513
- if (!queryId) return;
514
- try {
515
- const res = await request.get(`${url}/qa/ai/recommendQuestion?queryId=${queryId}`, {
516
- headers: { Authorization: token },
517
- });
518
- setRecommandQuestions(res.data?.data || []);
519
- } catch (e) {
520
- onError?.(e);
521
- setRecommandQuestions([]);
522
- }
523
- };
524
-
525
- /**
526
- * 处理重新发送消息逻辑
527
- * 重发时应该使用上一次用户的提问内容,而不是AI的回复内容
528
- */
529
- function handleReSenderSend(data: any) {
530
- const { audioUrl, filePaths, queryId } = data;
531
- if (!queryId) return;
532
-
533
- // 从当前对话的消息列表中找到对应的用户消息
534
- const messages = currentChatData.messages || [];
535
- let userMessage: any = null;
536
-
537
- // 首先尝试通过 queryId 找到对应的消息
538
- const targetMessageIndex = messages.findIndex((msg: any) => msg.queryId === queryId);
539
-
540
- if (targetMessageIndex !== -1) {
541
- const targetMessage = messages[targetMessageIndex];
542
- // 如果找到的是AI消息,向前查找对应的用户消息
543
- if (targetMessage.istype === 'ai') {
544
- // 从当前位置向前查找用户消息
545
- for (let i = targetMessageIndex - 1; i >= 0; i--) {
546
- if (messages[i].istype === 'user') {
547
- userMessage = messages[i];
548
- break;
549
- }
550
- }
551
- } else if (targetMessage.istype === 'user') {
552
- // 如果找到的就是用户消息,直接使用
553
- userMessage = targetMessage;
554
- }
555
- } else {
556
- // 如果没找到对应queryId的消息,尝试找到最后一条用户消息
557
- for (let i = messages.length - 1; i >= 0; i--) {
558
- if (messages[i].istype === 'user') {
559
- userMessage = messages[i];
560
- break;
561
- }
562
- }
563
- }
564
-
565
- // 如果找不到用户消息,则使用传入的content作为兜底
566
- const content = userMessage?.content || data.content;
567
- if (!content) return;
568
-
569
- // 优先使用用户消息中的文件信息
570
- const userFilePaths = userMessage?.filePaths || filePaths;
571
- const _fileUids = (
572
- typeof userFilePaths === 'string' && userFilePaths
573
- ? JSON.parse(userFilePaths)
574
- : userFilePaths || []
575
- ).map((item: any) => item.uid);
576
-
577
- const now = Date.now();
578
- setLastEmptyMessage({ now });
579
- if (!activeSessionId) return;
580
- setAppStatus(pre => {
581
- return {
582
- ...pre,
583
- display: 'processing',
584
- sender: 'processing',
585
- };
586
- });
587
-
588
- // 清除上一条AI消息的引用数据,避免重复显示(保留正文内容)
589
- if (targetMessageIndex !== -1 && messages[targetMessageIndex]?.istype === 'ai') {
590
- setChatData((chatList: any[]) => {
591
- if (!chatList[0]) return chatList;
592
- const current = chatList[0];
593
- const currentMessages = current.messages || [];
594
- if (targetMessageIndex >= currentMessages.length) return chatList;
595
-
596
- const newMessages = currentMessages.slice();
597
- // 清除引用数据(知识库 / 网络 / 图谱 / 数据库 / 思维链),但保留上一条 AI 的正文内容,
598
- // 保持 status 为 Done,这样 reset_chat 中的 isRestart 检测能正确工作
599
- newMessages[targetMessageIndex] = {
600
- ...newMessages[targetMessageIndex],
601
- // 不再清空 content,避免上一条回答在新问题发送时被“抹掉”
602
- content: newMessages[targetMessageIndex].content,
603
- reference: '[]', // 清空知识库引用
604
- webReference: '[]', // 清空网络引用
605
- graphReference: null, // 清空图谱引用
606
- databaseReference: null, // 清空数据库引用
607
- status: 2, // 保持为 Done 状态,这样当流式数据第一次返回时,isRestart 检测能正确工作
608
- chain: undefined, // 清空思维链数据
609
- };
610
-
611
- const newChat0 = { ...current, messages: newMessages };
612
- return [newChat0, ...chatList.slice(1)];
613
- });
614
- }
615
-
616
- data.clearFn && data.clearFn();
617
- setConversationList(list =>
618
- list.map(c => (c.sessionId === activeSessionId ? { ...c, gmtModified: now } : c))
619
- );
620
-
621
- // 使用用户消息的queryId,如果没有则使用传入的queryId
622
- const userQueryId = userMessage?.queryId || queryId;
623
-
624
- api_startChat_re(
625
- {
626
- configId: configId ?? currentChatData.configId ?? null,
627
- content,
628
- fileUids: _fileUids,
629
- lastDate: now,
630
- name: currentChatData.label || '',
631
- queryId: userQueryId,
632
- sessionId: activeSessionId,
633
- type: audioUrl ? 'audioUrl' : 'text',
634
- audioUrl: userMessage?.audioUrl || audioUrl,
635
- sysType: 'TEMPORARY',
636
- enableThinking: !!senderSwitchValues.reasoning,
637
- enableWebsearch: !!senderSwitchValues.netSearch,
638
- qaChannel: senderSwitchValues.qaChannel,
639
- } as any,
640
- () => {
641
- fetchRecommendQuestions(userQueryId);
642
- }
643
- );
644
- }
645
-
646
- /**
647
- * 处理消息发送(核心逻辑)
648
- * 1. 包含文件:先上传文件,成功后再发消息
649
- * 2. 新建会话:先调用创建会话接口,成功后再发消息
650
- * 3. 普通消息:直接发送
651
- * @param {object} data - 消息数据
652
- */
653
- async function handleSenderSend(data: any, clearFn: () => void) {
654
- const queryId = 'query-' + uid(32);
655
- // 1. 立即插入空壳消息
656
- let localCurrentFiles = undefined;
657
- if (data.files && data.files.length > 0) {
658
- localCurrentFiles = data.files.map((fileItem: any) => ({
659
- name: fileItem.file.name,
660
- size: fileItem.file.size,
661
- type: fileItem.file.type,
662
- filePath: fileItem.filePath || '',
663
- convertedFilePath: fileItem.convertedFilePath || '',
664
- uid: fileItem.uid || '',
665
- }));
666
- }
667
- addEmptyMessage({
668
- content: data.content || data.text || '',
669
- queryId,
670
- currentFiles: localCurrentFiles,
671
- filePaths: localCurrentFiles ? JSON.stringify(localCurrentFiles) : undefined,
672
- });
673
- setConversationList(list => {
674
- const newList = list
675
- .map(c =>
676
- c.sessionId === activeSessionId ? { ...c, isNew: false, gmtModified: Date.now() } : c
677
- )
678
- .sort((a, b) => b.gmtModified - a.gmtModified);
679
- setTimeout(() => {
680
- setActiveSessionId(activeSessionId);
681
- }, 300);
682
- return newList;
683
- });
684
- // 2. 有文件时,先上传并轮询,全部解析成功后再发起AI请求
685
- if (data.files && data.files.length > 0) {
686
- setAppStatus(pre => ({ ...pre, sender: 'uploading', display: 'uploading' }));
687
- uploadController = new AbortController();
688
- resetStopFlag(); // 使用 hook 提供的重置函数
689
- const clientFileUids = data.files.map(
690
- () => `rc-upload-${Date.now()}-${Math.random().toString(36).slice(2)}`
691
- );
692
- const initialFileStatuses = data.files.map((fileItem: any, index: number) => ({
693
- ...fileItem,
694
- uid: clientFileUids[index],
695
- status: 'uploading',
696
- }));
697
- setFileStatuses(initialFileStatuses);
698
- const formData = new FormData();
699
- data.files.forEach((fileItem: any) => {
700
- formData.append('files', fileItem.file);
701
- });
702
- const sessionIdStr = activeSessionId ? String(activeSessionId) : '';
703
- formData.append('sessionId', sessionIdStr);
704
- formData.append('uids', clientFileUids.join(','));
705
- try {
706
- const response = await request.post(
707
- `${url}/index/knowledgeBase/file/uploadFiles`,
708
- formData,
709
- {
710
- headers: {
711
- Authorization: token,
712
- 'Content-Type': 'multipart/form-data',
713
- },
714
- signal: uploadController.signal,
715
- }
716
- );
717
- if (stoppedRef.current) return;
718
- if (
719
- response.data.success &&
720
- Array.isArray(response.data.data) &&
721
- response.data.data.length > 0
722
- ) {
723
- // === 新增:合并后端返回字段到 fileStatuses ===
724
- setFileStatuses(prev => {
725
- return prev.map(localFile => {
726
- const serverFile = response.data.data.find((f: any) => f.uid === localFile.uid);
727
- return serverFile ? { ...localFile, ...serverFile } : localFile;
728
- });
729
- });
730
- setAppStatus(pre => ({ ...pre, sender: 'processing', display: 'analyzing' }));
731
- setFileStatuses(prev => prev.map(f => ({ ...f, status: 'parsing' })));
732
- const uploadedFilesData = response.data.data;
733
- const serverUids = uploadedFilesData.map((f: any) => f.uid);
734
- pollFileStatus(
735
- serverUids,
736
- serverStatuses => {
737
- setFileStatuses(currentLocalStatuses => {
738
- return currentLocalStatuses.map(localFile => {
739
- const correspondingServerFile = serverStatuses.find(
740
- (sf: any) => sf.uid === localFile.uid
741
- );
742
- if (correspondingServerFile) {
743
- // 使用 fileParseStatus 判断文件解析状态:1:正常 2:解析中 3:解析成功 4:解析失败
744
- // 兼容旧数据,优先使用 fileParseStatus,如果没有则使用 status
745
- const parseStatus = correspondingServerFile.fileParseStatus ?? correspondingServerFile.status;
746
- switch (parseStatus) {
747
- case 3:
748
- return { ...localFile, status: 'done' };
749
- case 4:
750
- return { ...localFile, status: 'error' };
751
- case 1:
752
- case 2:
753
- default:
754
- return { ...localFile, status: 'parsing' };
755
- }
756
- }
757
- return localFile;
758
- });
759
- });
760
- // === 新增:全部完成时清空 sender 区并合并文件 ===
761
- // 使用 fileParseStatus 判断:所有文件解析成功(3)或解析失败(4)时停止轮询
762
- const allDone =
763
- serverStatuses.length > 0 &&
764
- serverStatuses.every((file: any) => {
765
- const parseStatus = file.fileParseStatus ?? file.status;
766
- return parseStatus === 3 || parseStatus === 4; // 3:解析成功 4:解析失败
767
- });
768
- if (allDone) {
769
- setFileStatuses([]);
770
- // 上传完成后合并新文件到 uploadedFiles,保证结构统一
771
- const map = new Map();
772
- (uploadedFilesData || []).forEach((item: any) => {
773
- map.set(item.id, item);
774
- });
775
- setFileManagerData(prev => {
776
- const r = mergeFiles(prev.uploadedFiles, uploadedFilesData);
777
-
778
- return {
779
- uploadedFiles: r.map(item => {
780
- return {
781
- ...item,
782
- pdfPages: map.get(item.id)?.pdfPages || 0, // 保留后端返回的 pdfPages 字段
783
- };
784
- }),
785
- };
786
- });
787
- }
788
- },
789
- // onComplete: 全部解析成功后才发起AI请求
790
- () => {
791
- clearFn?.();
792
- setAppStatus(pre => ({ ...pre, sender: 'processing', display: 'processing' }));
793
- // === 新增:回填 filePath 到 fileStatuses ===
794
- setFileStatuses(prev => {
795
- return prev.map(localFile => {
796
- const serverFile = uploadedFilesData.find((f: any) => f.uid === localFile.uid);
797
-
798
- if (serverFile) {
799
- return {
800
- ...localFile,
801
- ...serverFile, // 合并后端所有字段
802
- url: serverFile.filePath, // 兼容 url 字段
803
- filePath: serverFile.filePath,
804
- name: serverFile.fileName || localFile.name,
805
- convertedFilePath:
806
- serverFile.convertedFilePath || localFile.convertedFilePath,
807
- };
808
- }
809
- return localFile;
810
- });
811
- });
812
- // === 同步 currentFiles 字段到 chatData ===
813
- setChatData(chatList => {
814
- if (!chatList[0]) return chatList;
815
- const { messages } = chatList[0];
816
- for (let i = messages.length - 1; i >= 0; i--) {
817
- if (messages[i].istype === 'user') {
818
- const oldFiles = messages[i].currentFiles || [];
819
- messages[i].currentFiles = oldFiles.map((localFile: any) => {
820
- const serverFile = uploadedFilesData.find(
821
- (f: any) => f.uid === localFile.uid
822
- );
823
- return serverFile ? { ...localFile, ...serverFile } : localFile;
824
- });
825
- break;
826
- }
827
- }
828
- return [...chatList];
829
- });
830
- // === 全部完成时清空 sender 区并合并文件 ===
831
- setFileStatuses([]);
832
- // 上传完成后合并新文件到 uploadedFiles,保证结构统一
833
- const map = new Map();
834
- (uploadedFilesData || []).forEach((item: any) => {
835
- map.set(item.id, item);
836
- });
837
- setFileManagerData(prev => {
838
- const r = mergeFiles(prev.uploadedFiles, uploadedFilesData);
839
-
840
- return {
841
- uploadedFiles: r.map(item => {
842
- return {
843
- ...item,
844
- pdfPages: map.get(item.id)?.pdfPages || 0, // 保留后端返回的 pdfPages 字段
845
- };
846
- }),
847
- };
848
- });
849
- const now = Date.now();
850
- api_startChat_re(
851
- {
852
- configId: configId || currentChatData.configId,
853
- content: data.content || data.text || '',
854
- fileUids: serverUids,
855
- lastDate: now,
856
- name: currentChatData.label || '',
857
- queryId: queryId,
858
- sessionId: String(activeSessionId || ''),
859
- type: 'text',
860
- audioUrl: '',
861
- sysType: 'TEMPORARY',
862
- enableThinking: !!senderSwitchValues.reasoning,
863
- enableWebsearch: !!senderSwitchValues.netSearch,
864
- qaChannel: senderSwitchValues.qaChannel,
865
- } as any,
866
- () => {
867
- fetchRecommendQuestions(queryId);
868
- }
869
- );
870
- },
871
- (errorMsg: string) => {
872
- setAppStatus(pre => ({ ...pre, display: 'ready', sender: 'ready' }));
873
- setFileStatuses(prev =>
874
- prev.map(f => ({ ...f, status: 'error', message: errorMsg }))
875
- );
876
- }
877
- );
878
- } else {
879
- const errorMsg = response.data.errorMsg || '文件上传失败';
880
- setAppStatus(pre => ({ ...pre, display: 'error', sender: 'ready' }));
881
- setFileStatuses(prev => prev.map(f => ({ ...f, status: 'error', message: errorMsg })));
882
- }
883
- } catch (error) {
884
- setAppStatus(pre => ({ ...pre, display: 'error', sender: 'ready' }));
885
- setFileStatuses(prev => prev.map(f => ({ ...f, status: 'error', message: '网络错误' })));
886
- }
887
- return;
888
- }
889
- // 3. 无文件,直接发起AI请求
890
- if (!activeSessionId) return;
891
- setAppStatus(pre => ({ ...pre, display: 'processing', sender: 'processing' }));
892
- const now = Date.now();
893
- setConversationList(list =>
894
- list.map(c => (c.sessionId === activeSessionId ? { ...c, gmtModified: now } : c))
895
- );
896
- clearFn?.();
897
- const requestConfigId = configId ?? currentChatData.configId ?? null;
898
- console.log('[HeadlessChat] handleSenderSend - 发送请求 configId:', {
899
- propsConfigId: configId,
900
- currentChatDataConfigId: currentChatData.configId,
901
- requestConfigId,
902
- });
903
- api_startChat_re(
904
- {
905
- configId: requestConfigId,
906
- content: data.content || data.text || '',
907
- fileUids: [],
908
- lastDate: now,
909
- name: currentChatData.label || '',
910
- queryId: queryId,
911
- sessionId: activeSessionId,
912
- type: 'text',
913
- audioUrl: '',
914
- sysType: 'TEMPORARY',
915
- enableThinking: !!senderSwitchValues.reasoning,
916
- enableWebsearch: !!senderSwitchValues.netSearch,
917
- qaChannel: senderSwitchValues.qaChannel,
918
- } as any,
919
- () => {
920
- fetchRecommendQuestions(queryId);
921
- }
922
- );
923
- }
924
-
925
- // =================================================================
926
- // Event Handlers - 事件处理器
927
- // =================================================================
928
-
929
- /**
930
- * 处理点赞反馈
931
- */
932
- function handleThumbsup(data: any) {
933
- if (data.restult == 1) {
934
- handleCancelFeedBack({ url, token }, { queryId: data.queryId }, () => {
935
- setFeed(data.queryId, null);
936
- });
937
- } else {
938
- handleFeedBack({ url, token }, { restult: 1, queryId: data.queryId }, () => {
939
- setFeed(data.queryId, 1);
940
- });
941
- }
942
- }
943
-
944
- /**
945
- * 处理新建一个临时会话
946
- */
947
- function handleConversationCreate(data: any) {
948
- const sessionId = uid(32);
949
- // 优先用 props.configId,使用 ?? 确保空字符串也能正确传递
950
- const effectiveConfigId = configId ?? data?.configId ?? '';
951
- console.log('[HeadlessChat] handleConversationCreate - configId 解析:', {
952
- propsConfigId: configId,
953
- dataConfigId: data?.configId,
954
- effectiveConfigId,
955
- });
956
- const newConversation = {
957
- sessionId,
958
- label: '未命名会话',
959
- gmtModified: Date.now(),
960
- searchConfigDTO: {},
961
- filePath: '',
962
- configId: effectiveConfigId,
963
- isNew: true,
964
- };
965
- setConversationList(list => [{ ...newConversation, messages: [] }, ...list]);
966
- setChatData(list => [{ id: sessionId, messages: [], ...newConversation }, ...list]);
967
- setActiveSessionId(sessionId);
968
- // 自动触发新建会话接口
969
-
970
- if (token && url) {
971
- request
972
- .post(
973
- `${url}/qa/dialogue/create`,
974
- {
975
- configId: effectiveConfigId,
976
- label: `来自内嵌应用${uid(8)}`,
977
- sessionId,
978
- sysType: 'TEMPORARY',
979
- },
980
- {
981
- headers: { Authorization: token },
982
- }
983
- )
984
- .then(res => {
985
- const newSession = res.data.data;
986
- if (newSession?.sessionId) {
987
- setConversationList(list => [
988
- { ...newSession, messages: [] },
989
- ...list.filter(c => c.sessionId !== sessionId),
990
- ]);
991
- setChatData(list => [
992
- { id: newSession.sessionId, messages: [], ...newSession },
993
- ...list.filter(c => c.id !== sessionId),
994
- ]);
995
- setActiveSessionId(newSession.sessionId);
996
- }
997
- })
998
- .catch(err => {
999
- onError?.(err);
1000
- });
1001
- }
1002
- }
1003
-
1004
- /**
1005
- * 处理文件选择
1006
- */
1007
- const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
1008
- const files = e.target.files;
1009
- if (files && files.length > 0) {
1010
- const fileArray = Array.from(files);
1011
-
1012
- // 应用上传限制配置验证(优先使用 ref,如果 ref 未设置则使用 dynamicSenderConfig)
1013
- const configSource = senderConfigRef.current || dynamicSenderConfig;
1014
- const existingFiles = uploadedFilesRef.current || [];
1015
-
1016
- // 检查是否有上传限制配置
1017
- const hasUploadLimitConfig =
1018
- configSource &&
1019
- (configSource.upload_size_limit !== undefined ||
1020
- configSource.upload_number_limit !== undefined ||
1021
- (configSource.upload_file_type_limit &&
1022
- configSource.upload_file_type_limit.length > 0));
1023
-
1024
- if (hasUploadLimitConfig) {
1025
- // 提取上传限制相关配置
1026
- const uploadConfig = {
1027
- upload_size_limit: configSource.upload_size_limit,
1028
- upload_number_limit: configSource.upload_number_limit,
1029
- upload_file_type_limit: configSource.upload_file_type_limit,
1030
- upload_limit_message: configSource.upload_limit_message,
1031
- };
1032
-
1033
- const validationResult = validateFileUpload(fileArray, existingFiles, uploadConfig);
1034
-
1035
- if (!validationResult.valid) {
1036
- // 显示错误提示
1037
- showValidationErrors(validationResult);
1038
- // 只保留通过验证的文件
1039
- const validFiles = fileArray.filter(
1040
- file => !validationResult.rejectedFiles.includes(file)
1041
- );
1042
-
1043
- if (validFiles.length === 0) {
1044
- // 所有文件都被拒绝,清空 input 并返回
1045
- if (fileInputRef.current) {
1046
- fileInputRef.current.value = '';
1047
- }
1048
- return;
1049
- }
1050
-
1051
- // 使用通过验证的文件
1052
- fileArray.splice(0, fileArray.length, ...validFiles);
1053
- }
1054
- }
1055
-
1056
- // 收集所有已经存在的文件名(用于检查重复)
1057
- const existingFileNames = new Set<string>(
1058
- fileManagerData.uploadedFiles.map((f: any) => (f.name || f.file?.name || '') as string)
1059
- );
1060
-
1061
- const newFiles: { file: File; type: string }[] = [];
1062
- const duplicateFileNames = new Set<string>();
1063
-
1064
- // 遍历新选择的文件,筛选出重复项和有效项
1065
- fileArray.forEach(file => {
1066
- if (existingFileNames.has(file.name)) {
1067
- duplicateFileNames.add(file.name);
1068
- } else {
1069
- newFiles.push({
1070
- file,
1071
- type: file.type.startsWith('image/') ? ('image' as const) : ('document' as const),
1072
- });
1073
- existingFileNames.add(file.name);
1074
- }
1075
- });
1076
-
1077
- // 如果有重复,发出警告
1078
- if (duplicateFileNames.size > 0) {
1079
- message.warning(`不能上传同名文件: ${Array.from(duplicateFileNames).join(', ')}`);
1080
- }
1081
-
1082
- // 将有效的文件通过 setUploadedFilesRef 设置到 aichat 内部
1083
- if (newFiles.length > 0) {
1084
- if (setUploadedFilesRef.current) {
1085
- setUploadedFilesRef.current(newFiles);
1086
- } else {
1087
- // 如果 ref 还没有设置,等待一下再试
1088
- setTimeout(() => {
1089
- if (setUploadedFilesRef.current) {
1090
- setUploadedFilesRef.current(newFiles);
1091
- }
1092
- }, 100);
1093
- }
1094
- }
1095
- }
1096
- // 清空 input,以便可以重复选择同一文件
1097
- if (fileInputRef.current) {
1098
- fileInputRef.current.value = '';
1099
- }
1100
- };
1101
-
1102
- const [is_download, setIs_download] = useState(false);
1103
-
1104
- const getConfigById = async (params: any) => {
1105
- try {
1106
- const res: any = await axios.get(
1107
- `${getUrlPrefix()}/qa/search/config/getById?${new URLSearchParams(params).toString()}`,
1108
- { headers: { Authorization: token } }
1109
- );
1110
- console.log('resslkdjgalsg', res);
1111
- if (res?.data?.success && res?.data?.data?.configJson) {
1112
- const config = JSON.parse(res.data.data.configJson);
1113
- setIs_download(config.is_download);
1114
- }
1115
- } catch (error) {}
1116
- };
1117
-
1118
- useEffect(() => {
1119
- if (!configId) return;
1120
- getConfigById({ configId });
1121
- }, [configId]);
1122
-
1123
- /**
1124
- * 处理会话列表项点击
1125
- */
1126
- function handleItemClick(data: any) {
1127
- if (data?.sessionId && data.sessionId !== activeSessionId) {
1128
- setActiveSessionId(data.sessionId);
1129
- setAppStatus(prev => ({ ...prev, sender: 'ready' }));
1130
- // 点击会话时,使用其最后一条AI消息的推荐问题
1131
- const conv = chatData.find(c => c.id === data.sessionId);
1132
- if (conv && conv.messages && conv.messages.length > 0) {
1133
- const lastAiMsg = [...conv.messages].reverse().find((m: any) => m.istype === 'ai');
1134
- if (lastAiMsg && lastAiMsg.recommendQuestion) {
1135
- setRecommandQuestions(lastAiMsg.recommendQuestion);
1136
- } else {
1137
- setRecommandQuestions([]);
1138
- }
1139
- } else {
1140
- setRecommandQuestions([]);
1141
- }
1142
- }
1143
- }
1144
-
1145
- // =================================================================
1146
- // Local State Updaters - 本地状态更新 (供事件发射器使用)
1147
- // =================================================================
1148
-
1149
- const handleFeedDownConfirm = (data: any) => {
1150
- handleFeedBack({ url, token }, { ...data, ...feedParam, restult: 0 }, () => {
1151
- setFeed(feedParam.queryId, 0);
1152
- });
1153
- };
1154
-
1155
- // =================================================================
1156
- // Event Emitter - 事件分发器
1157
- // =================================================================
1158
- /**
1159
- * 统一事件分发器,连接业务逻辑与所有子组件的事件
1160
- * @param {string} eventName - 事件名称
1161
- * @param {any} data - 事件数据
1162
- */
1163
- const api_getFileStatusByUid = async (data: any) => {
1164
- try {
1165
- const res: any = await axios.get(
1166
- `${getUrlPrefix()}/index/knowledgeBase/file/getFileStatusByUids?uids=${data.data.uids}`,
1167
- { headers: { Authorization: token } }
1168
- );
1169
- console.log('resslkdjgalsg', res);
1170
- return res?.data?.data;
1171
- } catch (error) {}
1172
- };
1173
- const referenceFile_question_upload = async (data: any) => {
1174
- if (fileViewTypes.includes(data.file_type)) {
1175
- // 优先使用 metadata.source,否则使用 url 或 convertedFilePath
1176
- const previewUrl = data.metadata?.source
1177
- ? `${TempBaseUrl}${data.metadata.source}`
1178
- : data.url || data.convertedFilePath || data.filePath;
1179
- setCurFileInfo({
1180
- ...data,
1181
- parse_url: previewUrl,
1182
- });
1183
-
1184
- setDrawerType('preview');
1185
- setOpen(true);
1186
- return;
1187
- }
1188
- try {
1189
- const res: any = await api_getFileStatusByUid({
1190
- data: { uids: data.uid },
1191
- config: {
1192
- url: getUrlPrefix(),
1193
- token: configId,
1194
- enableMock: false,
1195
- },
1196
- });
1197
- if (res?.length) {
1198
- const d = res[0];
1199
- setCurFileInfo({
1200
- ...data,
1201
- parse_url: d.convertedFilePath,
1202
- });
1203
-
1204
- setDrawerType('preview');
1205
- setOpen(true);
1206
- }
1207
- } catch (error) {}
1208
- };
1209
- const mergedEventsEmit = (eventName: string, data: any) => {
1210
- console.log(`[Event] ${eventName}`, data);
1211
- switch (eventName) {
1212
- case 'TempKnowledgeBase':
1213
- tempKnowledgeBaseCheck.current = data;
1214
- break;
1215
- case 'reference_file:click':
1216
- if (data.file_type === 'image') return;
1217
-
1218
- if (!data.parse_url) {
1219
- if (!data.uid) {
1220
- if (data.references) return;
1221
- return message.warning('文件还未解析完成,请稍后预览');
1222
- }
1223
- referenceFile_question_upload(data);
1224
- return;
1225
- }
1226
- setCurFileInfo({
1227
- ...data,
1228
- file_type: data.type,
1229
- file_name: data.file,
1230
- });
1231
- setDrawerType('preview');
1232
- setOpen(true);
1233
-
1234
- break;
1235
- case 'referenceFile_question':
1236
- referenceFile_question_upload(data.data);
1237
- break;
1238
- case 'retrive_tag:click':
1239
- if (data?.graph?.id) {
1240
- //图谱溯源
1241
- setDrawerType('graphPreview');
1242
- setCurFileInfo({ ...data.graph, traceNode: data.traceNode });
1243
- setOpen(true);
1244
- return;
1245
- }
1246
- if (!data?.tagInfo && !data?.file && !data?.referenceDoc) return;
1247
- const curFile = data?.referenceDoc || data?.file || data?.tagInfo;
1248
- const { pdfPages, parsedFilePath, order_num, metadata, tags } = curFile;
1249
- if (curFile.type == 'video') {
1250
- setCurFileInfo({
1251
- ...metadata,
1252
- displayType: 'retrive',
1253
- });
1254
- setDrawerType('video');
1255
- setOpen(true);
1256
- return;
1257
- }
1258
-
1259
- const id = curFile.id || order_num || 'Unknown ID';
1260
- // 解析 source 字段
1261
- const sourceParts = metadata.source.split('/');
1262
- const fileName = sourceParts[sourceParts.length - 1] || '';
1263
- const fileParts = fileName.split('.');
1264
- const label = fileParts.slice(0, -1).join('.') || 'Unknown Label';
1265
- const file_type = fileParts[fileParts.length - 1] || 'Unknown Type';
1266
-
1267
- setContent({
1268
- id,
1269
- title: label,
1270
- file_name: fileName,
1271
- file_type: file_type,
1272
- file_source: getMarkExcludeType(file_type)
1273
- ? `${TempBaseUrl}${metadata.source}`
1274
- : parsedFilePath,
1275
- metadata: metadata,
1276
- pdfPages: pdfPages,
1277
- });
1278
- setDrawerType('mark');
1279
- setOpen(true);
1280
- break;
1281
- // --- 对话列表事件 ---
1282
- case 'conversation:item_click':
1283
- handleItemClick(data);
1284
- break;
1285
-
1286
- case 'files:finished_animation_complete':
1287
- setFileStatuses([]);
1288
- break;
1289
-
1290
- case 'conversation:create':
1291
- handleConversationCreate(data);
1292
- break;
1293
- case 'conversation:new_assistant_change':
1294
- // headlessChat 不需要处理助手切换
1295
- break;
1296
-
1297
- // --- 发送器事件 ---
1298
- case 'sender:send':
1299
- handleSenderSend(data, data.clearFn);
1300
- break;
1301
- case 'sender:send_recommandQuestion':
1302
- // 点击推荐问题,视作一次普通发送
1303
- handleSenderSend(data, data.clearFn);
1304
- break;
1305
- case 'sender:action_upload':
1306
- // 触发文件上传按钮点击,打开文件选择对话框
1307
- if (fileInputRef.current) {
1308
- fileInputRef.current.click();
1309
- }
1310
- break;
1311
- case 'fileManager:change':
1312
- // 接收核心组件提供的文件管理方法引用
1313
- if (data) {
1314
- setUploadedFilesRef.current = data.setUploadedFiles;
1315
- removeFileRef.current = data.removeFile;
1316
- // 保存上传限制配置和已上传文件列表引用,供 handleFileSelect 使用
1317
- senderConfigRef.current = data?.senderConfig;
1318
- uploadedFilesRef.current = Array.isArray(data?.uploadedFiles) ? data.uploadedFiles : [];
1319
- }
1320
- break;
1321
- case 'sender:stop':
1322
- setStopFlag(); // 使用 hook 提供的停止函数
1323
- if (uploadController) {
1324
- uploadController.abort();
1325
- uploadController = null;
1326
- }
1327
- if (stopPoll) {
1328
- stopPoll();
1329
- stopPoll = null;
1330
- }
1331
- setAppStatus(pre => ({ ...pre, display: 'ready', sender: 'ready' }));
1332
- setFileStatuses([]);
1333
- stopStream?.();
1334
- break;
1335
- case 'sender:clear':
1336
- data.clearFn?.();
1337
- break;
1338
- case 'sender:configChange':
1339
- // 配置项变化,记录最新 switch 状态
1340
- if (data && data.all) {
1341
- setSenderSwitchValues(data.all);
1342
- }
1343
- break;
1344
- case 'chatbox:follow_up_question_click': {
1345
- // 新链路:来自 ChatMessageAdapter 的追问点击
1346
- const content = (data?.question ?? data?.content ?? '').toString();
1347
- if (!content) break;
1348
- handleSenderSend({ content }, () => {});
1349
- break;
1350
- }
1351
- case 'chatbox:copy': {
1352
- let text = data?.content || '';
1353
- if (!text) break;
1354
- // 过滤掉 [retrive-tag]...[/retrive-tag] 标签及内容
1355
- text = text.replace(/\[retrive-tag[^\]]*\][\s\S]*?\[\/retrive-tag\]/g, '');
1356
- // 直接使用 Clipboard API,避免依赖 event.currentTarget
1357
- const copyByClipboardApi = async (t: string) => {
1358
- try {
1359
- await navigator.clipboard.writeText(t);
1360
- message.success('已复制到剪贴板');
1361
- return true;
1362
- } catch (_) {
1363
- return false;
1364
- }
1365
- };
1366
- const fallbackCopy = (t: string) => {
1367
- const textarea = document.createElement('textarea');
1368
- textarea.value = t;
1369
- textarea.style.position = 'fixed';
1370
- textarea.style.opacity = '0';
1371
- document.body.appendChild(textarea);
1372
- textarea.focus();
1373
- textarea.select();
1374
- try {
1375
- document.execCommand('copy');
1376
- message.success('已复制到剪贴板');
1377
- } catch (_) {
1378
- message.error('复制失败');
1379
- }
1380
- document.body.removeChild(textarea);
1381
- };
1382
- copyByClipboardApi(text).then(ok => {
1383
- if (!ok) fallbackCopy(text);
1384
- });
1385
- break;
1386
- }
1387
- case 'chatbox:repeat':
1388
- handleReSenderSend(data);
1389
- break;
1390
- case 'chatbox:like':
1391
- handleThumbsup({ queryId: data?.queryId, restult: data?.result });
1392
- break;
1393
- case 'chatbox:dislike':
1394
- if (data?.result === 0) {
1395
- handleCancelFeedBack({ url, token }, { queryId: data.queryId }, () => {
1396
- setFeed(data.queryId, null);
1397
- });
1398
- } else {
1399
- setFeedParam({ queryId: data?.queryId });
1400
- setOpenFeed(true);
1401
- }
1402
- break;
1403
-
1404
- // --- 消息卡片事件 ---
1405
- case 'action_copy:click':
1406
- if (data) {
1407
- toCopy(data.content, data.event);
1408
- }
1409
- break;
1410
- case 'action_retry':
1411
- handleReSenderSend(data);
1412
- break;
1413
- case 'action_thumbsup':
1414
- handleThumbsup(data);
1415
- break;
1416
- case 'references:click': {
1417
- // 使用 AiChat 内置的右侧栏事件
1418
- const Content = () => {
1419
- // const safe = (() => {
1420
- // try {
1421
- // return typeof data === 'string' ? data : JSON.stringify(data, null, 2);
1422
- // } catch (e) {
1423
- // return String(data);
1424
- // }
1425
- // })();
1426
- return (
1427
- <ReferenceBar
1428
- type={DrawerType.REFERENCELIST}
1429
- data={data}
1430
- token={token}
1431
- is_download={is_download}
1432
- />
1433
- );
1434
- };
1435
- const setContentEvent = new CustomEvent('aichat:right_set_content', {
1436
- detail: { content: <Content /> },
1437
- });
1438
- window.dispatchEvent(setContentEvent);
1439
- const openEvent = new CustomEvent('aichat:right_set', {
1440
- detail: { collapsed: false },
1441
- });
1442
- window.dispatchEvent(openEvent);
1443
- break;
1444
- }
1445
- case 'action_thumbsdown':
1446
- if (data.restult === 0) {
1447
- handleCancelFeedBack({ url, token }, { queryId: data.queryId }, () => {
1448
- setFeed(data.queryId, null);
1449
- });
1450
- } else {
1451
- setFeedParam(data);
1452
- setOpenFeed(true);
1453
- }
1454
- break;
1455
- // --- 文件管理器上传文件删除事件,透传到业务层 ---
1456
- case 'uploaded_file:removeFromTemp': {
1457
- console.log('[DEBUG] mergedEventsEmit uploaded_file:removeFromTemp 事件', data);
1458
-
1459
- const uid = data?.file?.uid;
1460
- if (!uid) {
1461
- console.warn('[DEBUG] 缺少uid,无法删除临时文件', data);
1462
- break;
1463
- }
1464
- // 获取当前对话最后一条用户消息的 queryId
1465
- const lastUserMsg = [...(currentChatData?.messages || [])]
1466
- .reverse()
1467
- .find((msg: any) => msg.istype === 'user');
1468
- const queryId = lastUserMsg?.queryId;
1469
- console.log('[DEBUG] mergedEventsEmit 获取到 queryId', queryId, lastUserMsg);
1470
-
1471
- // 使用统一的文件删除处理函数
1472
- handleRemoveFromTemp(uid, queryId);
1473
- break;
1474
- }
1475
- case 'uploaded_file:item_click': {
1476
- // 处理文件列表项点击,触发预览
1477
- const file = data?.file;
1478
- if (!file) break;
1479
-
1480
- // 获取文件信息
1481
- const fileName = file.name || file.file?.name || '';
1482
- const fileExt = fileName.split('.').pop()?.toLowerCase() || '';
1483
- const fileType = file.type || fileExt;
1484
-
1485
- // 构建预览数据,参考 referenceFile_question_upload 的逻辑
1486
- const previewData = {
1487
- ...file,
1488
- file_type: fileType,
1489
- file_name: fileName,
1490
- uid: file.uid,
1491
- url: file.url || file.preview,
1492
- convertedFilePath: file.convertedFilePath,
1493
- metadata: file.metadata || { source: file.url || file.preview },
1494
- };
1495
-
1496
- // 如果是图片等可直接预览的类型,直接打开预览
1497
- if (fileViewTypes.includes(fileExt)) {
1498
- // 关闭文件列表 Popover,避免与预览 Drawer 重叠
1499
- setFileListPopoverOpenRef.current?.(false);
1500
- setCurFileInfo({
1501
- ...previewData,
1502
- parse_url:
1503
- previewData.url || previewData.metadata?.source
1504
- ? `${TempBaseUrl}${previewData.metadata.source}`
1505
- : previewData.url || previewData.convertedFilePath || '',
1506
- });
1507
- setDrawerType('preview');
1508
- setOpen(true);
1509
- break;
1510
- }
1511
-
1512
- // 如果有转换后的文件路径,直接使用
1513
- if (previewData.convertedFilePath) {
1514
- // 关闭文件列表 Popover,避免与预览 Drawer 重叠
1515
- setFileListPopoverOpenRef.current?.(false);
1516
- setCurFileInfo({
1517
- ...previewData,
1518
- parse_url: previewData.convertedFilePath,
1519
- });
1520
- setDrawerType('preview');
1521
- setOpen(true);
1522
- break;
1523
- }
1524
-
1525
- // 如果有 uid,尝试获取文件状态(参考 referenceFile_question_upload)
1526
- if (previewData.uid) {
1527
- api_getFileStatusByUid({
1528
- data: { uids: previewData.uid },
1529
- config: {
1530
- url: getUrlPrefix(),
1531
- token: configId || token,
1532
- enableMock: false,
1533
- },
1534
- })
1535
- .then((res: any) => {
1536
- // 关闭文件列表 Popover,避免与预览 Drawer 重叠
1537
- setFileListPopoverOpenRef.current?.(false);
1538
- if (res?.length) {
1539
- const fileStatus = res[0];
1540
- setCurFileInfo({
1541
- ...previewData,
1542
- parse_url: fileStatus.convertedFilePath || previewData.url || '',
1543
- });
1544
- setDrawerType('preview');
1545
- setOpen(true);
1546
- } else {
1547
- // 如果没有获取到状态,尝试直接使用 url
1548
- if (previewData.url) {
1549
- setCurFileInfo({
1550
- ...previewData,
1551
- parse_url: previewData.url,
1552
- });
1553
- setDrawerType('preview');
1554
- setOpen(true);
1555
- }
1556
- }
1557
- })
1558
- .catch((error: any) => {
1559
- console.error('获取文件状态失败:', error);
1560
- // 关闭文件列表 Popover
1561
- setFileListPopoverOpenRef.current?.(false);
1562
- // 失败时尝试直接使用 url
1563
- if (previewData.url) {
1564
- setCurFileInfo({
1565
- ...previewData,
1566
- parse_url: previewData.url,
1567
- });
1568
- setDrawerType('preview');
1569
- setOpen(true);
1570
- }
1571
- });
1572
- } else if (previewData.url) {
1573
- // 没有 uid 但有 url,直接使用
1574
- // 关闭文件列表 Popover,避免与预览 Drawer 重叠
1575
- setFileListPopoverOpenRef.current?.(false);
1576
- setCurFileInfo({
1577
- ...previewData,
1578
- parse_url: previewData.url,
1579
- });
1580
- setDrawerType('preview');
1581
- setOpen(true);
1582
- }
1583
- break;
1584
- }
1585
-
1586
- default:
1587
- // 其他未处理事件可继续向上层抛出
1588
- eventsEmit?.(eventName, data);
1589
- }
1590
- };
1591
-
1592
- // =================================================================
1593
- // Component & UI Configuration - 组件及UI配置
1594
- // =================================================================
1595
-
1596
- /**
1597
- * Sidebar 配置 - headlessChat 不需要左侧历史对话栏
1598
- */
1599
- const sidebar = undefined;
1600
-
1601
- /**
1602
- * 业务层自定义组件
1603
- */
1604
- const businessCustomComponents: { [key: string]: any } = {
1605
- AiChatBox: (msg: any, idx: number) => {
1606
- const isLastMessage = idx === (currentChatData?.messages?.length || 0) - 1;
1607
-
1608
- // 根据消息的 status 和 appStatus 来确定 displayStatus
1609
- let displayStatus = 'ready';
1610
- if (isLastMessage) {
1611
- // 优先使用消息的 status 字段
1612
- if (msg.status !== undefined) {
1613
- switch (msg.status) {
1614
- case 0: // StatusType.Pending
1615
- displayStatus = 'thinking';
1616
- break;
1617
- case 1: // StatusType.Process - 对话正文输出中
1618
- displayStatus = 'processing';
1619
- break;
1620
- case 2: // StatusType.Done - 整个对话完成
1621
- displayStatus = 'ready';
1622
- break;
1623
- case 3: // StatusType.Error - 整个对话出现异常
1624
- displayStatus = 'error';
1625
- break;
1626
- case 4: // StatusType.ThoughtChain - 思维链输出中
1627
- displayStatus = 'thinking';
1628
- break;
1629
- default:
1630
- displayStatus = appStatus.display;
1631
- }
1632
- } else {
1633
- // 如果没有 status 字段,使用 appStatus.display
1634
- displayStatus = appStatus.display;
1635
- }
1636
- }
1637
- // 将推荐问题强制转换为数组,避免切换会话时报 .map 错误
1638
- let safeFollowUps: string[] = [];
1639
- if (Array.isArray(recommandQuestions)) {
1640
- safeFollowUps = recommandQuestions as string[];
1641
- } else if (typeof recommandQuestions === 'string') {
1642
- try {
1643
- safeFollowUps = JSON.parse(recommandQuestions) || [];
1644
- } catch {
1645
- safeFollowUps = [];
1646
- }
1647
- }
1648
- // 保证传入 ChatMessageAdapter 的 reference/webReference/graphReference 始终是有效的 JSON 字符串
1649
- const safeReference = (() => {
1650
- const r = (msg as any)?.reference;
1651
- if (!r) return '[]';
1652
- if (typeof r === 'string') {
1653
- try {
1654
- JSON.parse(r);
1655
- return r;
1656
- } catch {
1657
- return '[]';
1658
- }
1659
- }
1660
- try {
1661
- return JSON.stringify(r);
1662
- } catch {
1663
- return '[]';
1664
- }
1665
- })();
1666
- const safeWebReference = (() => {
1667
- const r = (msg as any)?.webReference;
1668
- if (!r) return '[]';
1669
- if (typeof r === 'string') {
1670
- try {
1671
- JSON.parse(r);
1672
- return r;
1673
- } catch {
1674
- return '[]';
1675
- }
1676
- }
1677
- try {
1678
- return JSON.stringify(r);
1679
- } catch {
1680
- return '[]';
1681
- }
1682
- })();
1683
- const safeGraphReference = (() => {
1684
- const r = (msg as any)?.graphReference;
1685
- if (!r) return '[]';
1686
- if (typeof r === 'string') {
1687
- try {
1688
- JSON.parse(r);
1689
- return r;
1690
- } catch {
1691
- return '[]';
1692
- }
1693
- }
1694
- try {
1695
- return JSON.stringify(r);
1696
- } catch {
1697
- return '[]';
1698
- }
1699
- })();
1700
- // databaseReference 直接透传,交由 rtext 内部解析并渲染数据库召回表格
1701
- const safeDatabaseReference = (msg as any)?.databaseReference;
1702
-
1703
- // 从 chain 数组中提取 chainRespTime(累加所有节点的 chainRespTime 作为总时间)
1704
- // 如果 msg 已经有 chainRespTime,优先使用;否则从 chain 数组中累加
1705
- const extractChainRespTime = (() => {
1706
- // 优先使用已有的 chainRespTime
1707
- if (msg?.chainRespTime || (msg as any)?.reply?.chainRespTime) {
1708
- return msg?.chainRespTime ?? (msg as any)?.reply?.chainRespTime;
1709
- }
1710
- // 从 chain 数组中累加所有节点的 chainRespTime
1711
- const chain = msg?.chain || (msg as any)?.reply?.chain;
1712
- if (Array.isArray(chain) && chain.length > 0) {
1713
- const totalTime = chain.reduce((sum: number, node: any) => {
1714
- const time = node?.chainRespTime ?? node?.respTime;
1715
- if (time !== null && time !== undefined && time > 0) {
1716
- return sum + time;
1717
- }
1718
- return sum;
1719
- }, 0);
1720
- return totalTime > 0 ? totalTime : undefined;
1721
- }
1722
- return undefined;
1723
- })();
1724
-
1725
- return (
1726
- <div>
1727
- <ChatMessageAdapter
1728
- key={`${msg?.queryId || msg?.id || idx}-${msg?.istype || 'unknown'}`}
1729
- {...msg}
1730
- referenceMode="button"
1731
- reference={safeReference}
1732
- webReference={safeWebReference}
1733
- graphReference={safeGraphReference}
1734
- databaseReference={safeDatabaseReference}
1735
- contentType="stream"
1736
- displayStatus={displayStatus}
1737
- eventsEmit={mergedEventsEmit}
1738
- // 仅最后一条 AI 消息展示追问
1739
- isLast={isLastMessage && msg?.istype === 'ai'}
1740
- followUpQuestions={isLastMessage && msg?.istype === 'ai' ? safeFollowUps : []}
1741
- defaultAnswer={
1742
- currentChatData?.searchConfigDTO?.defaultAnswer ||
1743
- '不知道什么原因我们没能查到你要的问题*-*'
1744
- }
1745
- styles={styles}
1746
- // 开启思维链 UI 展示(rtext 1.4.2+)
1747
- // enableCot: 1 代表支持思维链,0 代表不支持
1748
- // 如果是 1,哪怕一个思维链节点都没有也要把思维链的UI渲染出来
1749
- enableThoughtChain={msg?.enableCot === 1 || (msg as any)?.reply?.enableCot === 1}
1750
- chain={msg?.chain}
1751
- thoughtChainNodes={msg?.thoughtChainNodes} // 实时思维链节点(优先使用)
1752
- thoughtChainStatus={msg?.status}
1753
- enableCot={msg?.enableCot ?? (msg as any)?.reply?.enableCot}
1754
- chainRespTime={extractChainRespTime}
1755
- />
1756
- {!!msg?.resultType && (
1757
- <div
1758
- style={{ display: 'flex', justifyContent: 'center', ...(disclaimers?.style || {}) }}
1759
- >
1760
- {msg?.resultType == 2
1761
- ? disclaimers?.faqText || disclaimers?.text
1762
- : disclaimers?.text}
1763
- </div>
1764
- )}
1765
- </div>
1766
- );
1767
- },
1768
- LogoBox: () => <div className="text-2xl w-full text-center font-bold">智能助手</div>,
1769
- DisplayLoading: () => <DisplayLoading />,
1770
- DisplayError: () => <DisplayError />,
1771
- AppError: () => <AppError />,
1772
- AppLoading: () => <AppLoading />,
1773
- UserChatBox: (msg: any, idx: number) => {
1774
- return (
1775
- <ChatMessageAdapter
1776
- key={`${msg?.queryId || msg?.id || idx}-user`}
1777
- {...msg}
1778
- referenceMode="button"
1779
- contentType="plainText"
1780
- isUser={true}
1781
- displayStatus="ready"
1782
- eventsEmit={mergedEventsEmit}
1783
- styles={styles}
1784
- fileManagerData={fileManagerData}
1785
- />
1786
- );
1787
- },
1788
- WelcomeComponent: () => (
1789
- <GientechNewChatWelcome
1790
- eventsEmit={mergedEventsEmit}
1791
- assistantList={assistantList}
1792
- styles={styles}
1793
- // defaultSelect={newAssistantId || assistantList[0]?.id}
1794
- />
1795
- ),
1796
- };
1797
-
1798
- /**
1799
- * 合并外部传入和业务默认的自定义组件,外部优先
1800
- */
1801
- const mergedCustomComponents: { [key: string]: any } = { ...businessCustomComponents };
1802
- if (rest.CustomComponents) {
1803
- Object.keys(rest.CustomComponents).forEach(key => {
1804
- const val = rest.CustomComponents?.[key];
1805
- if (val !== undefined) {
1806
- mergedCustomComponents[key] = val;
1807
- }
1808
- });
1809
- }
1810
- const tempKnowledgeBaseCheck = useRef(true);
1811
-
1812
- const uploadedFiles = useMemo(() => {
1813
- return (
1814
- allFilesFromQuery.length > 0 ? allFilesFromQuery : fileManagerData.uploadedFiles || []
1815
- ) as any[];
1816
- }, [allFilesFromQuery, fileManagerData]);
1817
- // 使用统一的文件展示工具 Hook
1818
- // 使用 allFilesFromQuery(从 query.filePaths 收集的所有文件)而不是 fileManagerData.uploadedFiles
1819
- const { FileDisplayTools, setFileListPopoverOpen } = useFileDisplayTools({
1820
- fileManagerData: {
1821
- uploadedFiles,
1822
- },
1823
- styles,
1824
- eventsEmit: mergedEventsEmit,
1825
- });
1826
- // 保存 setFileListPopoverOpen 到 ref,以便在 mergedEventsEmit 中访问
1827
- setFileListPopoverOpenRef.current = setFileListPopoverOpen;
1828
-
1829
- // =================================================================
1830
- // Render - 渲染
1831
- // =================================================================
1832
- return (
1833
- <>
1834
- {/* 隐藏的文件上传input */}
1835
- <input
1836
- ref={fileInputRef}
1837
- type="file"
1838
- multiple
1839
- accept="image/*,.pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.txt,.md,.json,.csv,.zip,.rar,.7z"
1840
- style={{ display: 'none' }}
1841
- onChange={handleFileSelect}
1842
- />
1843
-
1844
- <WrappedComponent
1845
- activeSessionId={activeSessionId}
1846
- status={appStatus}
1847
- chatData={currentChatData}
1848
- sidebar={sidebar}
1849
- recommandQuestions={[]}
1850
- eventsEmit={mergedEventsEmit}
1851
- styles={styles}
1852
- senderConfig={dynamicSenderConfig}
1853
- fileUploadStatus={fileStatuses}
1854
- CustomComponents={mergedCustomComponents}
1855
- rightbarWidth={'400px'}
1856
- chatHeader={{
1857
- title: rest.title || '智能助手',
1858
- tools: FileDisplayTools,
1859
- }}
1860
- />
1861
- <FeedBackModal
1862
- open={openFeed}
1863
- feedBackList={feedBackList}
1864
- setOpen={setOpenFeed}
1865
- handleConfirm={handleFeedDownConfirm}
1866
- />
1867
- <ConfigProvider
1868
- drawer={{
1869
- styles: {
1870
- body: { padding: 0 },
1871
- header: { display: 'none' },
1872
- },
1873
- }}
1874
- >
1875
- <Drawer
1876
- autoFocus={false}
1877
- onClose={() => setOpen(false)}
1878
- open={open}
1879
- width={drawerType === 'graphPreview' ? '100%' : 720}
1880
- className="overflow-x-hidden"
1881
- destroyOnClose
1882
- afterOpenChange={open => {
1883
- if (!open) {
1884
- setContent(null);
1885
- }
1886
- }}
1887
- >
1888
- {drawerType === 'preview' && (
1889
- <DrawerPreview curFileInfo={curFileInfo} onClose={setOpen} token={token} />
1890
- )}
1891
- {drawerType === 'mark' && (
1892
- <DrawerContent
1893
- content={content as any}
1894
- onClose={() => setOpen(false)}
1895
- token={token}
1896
- />
1897
- )}
1898
- </Drawer>
1899
- </ConfigProvider>
1900
- </>
1901
- );
1902
- };
1903
- }