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

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 (522) 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-BlAyZ4S3.js +943 -0
  18. package/assets/index-CzZQWA2P.js +1 -0
  19. package/{dist/assets/index-CpSzj-Sx.js → assets/index-DHK_n74G.js} +58 -73
  20. package/assets/index-DPA1HCWQ.js +1372 -0
  21. package/assets/index-DPyRygOA.js +745 -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/{dist/assets/style-CfNUqKAA.js → assets/style-D8ou48dh.js} +7 -7
  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/style2.css +0 -1
  66. package/dist/chat.js +0 -1
  67. package/dist/chatCompare.js +0 -1
  68. package/dist/database.js +0 -20
  69. package/dist/index.js +0 -1
  70. package/dist/modelManage.js +0 -1
  71. package/dist/package.json +0 -73
  72. package/dist/streamFilesReader.js +0 -1
  73. package/dist/worker/pdf.worker.min.js +0 -22
  74. package/doc_assets/images/1.png +0 -0
  75. package/doc_assets/images/3.png +0 -0
  76. package/doc_assets/images/component-screenshot.png +0 -1
  77. 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
  78. 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
  79. 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
  80. package/eslint.config.js +0 -92
  81. package/index.html +0 -13
  82. package/package.json.demo-backup +0 -109
  83. package/postcss.config.cjs +0 -19
  84. package/public/icons/answerAwartar.png +0 -0
  85. package/public/icons/docx-file.png +0 -0
  86. package/public/icons/folder.png +0 -0
  87. package/public/icons/html.png +0 -0
  88. package/public/icons/image.png +0 -0
  89. package/public/icons/jpg-file.png +0 -0
  90. package/public/icons/json.png +0 -0
  91. package/public/icons/md.png +0 -0
  92. package/public/icons/pdf.png +0 -0
  93. package/public/icons/pptx.png +0 -0
  94. package/public/icons/questionAwartar.png +0 -0
  95. package/public/icons/sheets.png +0 -0
  96. package/public/icons/txt.png +0 -0
  97. package/public/icons/xlsx.png +0 -0
  98. package/public/vite.svg +0 -1
  99. package/rag/assets/index.Bd0tNzw0.js +0 -2797
  100. package/rag/assets/index.D6t67hlu.css +0 -1
  101. package/rag/assets/left.KBHV5h7q.jpg +0 -0
  102. package/rag/assets/worker-BbpylX7l.DptbXke_.js +0 -13
  103. package/release-it.json +0 -21
  104. package/scripts/README.md +0 -133
  105. package/scripts/build-demo.js +0 -88
  106. package/scripts/check-changelog.cjs +0 -124
  107. package/scripts/check-version.cjs +0 -49
  108. package/scripts/decrypt-api-key.js +0 -95
  109. package/scripts/demo-selector.js +0 -216
  110. package/scripts/dev-demo.js +0 -85
  111. package/scripts/open-file.cjs +0 -61
  112. package/scripts/preview-demo.js +0 -130
  113. package/scripts/run-demo.bat +0 -34
  114. package/src/assets/img/close.png +0 -0
  115. package/src/assets/img/database.png +0 -0
  116. package/src/assets/img/downArrow.png +0 -0
  117. package/src/assets/img/downLoad.png +0 -0
  118. package/src/assets/img/excel.png +0 -0
  119. package/src/assets/img/graphIcon.png +0 -0
  120. package/src/assets/img/img.png +0 -0
  121. package/src/assets/img/pdf.png +0 -0
  122. package/src/assets/img/ppt.png +0 -0
  123. package/src/assets/img/search.svg +0 -3
  124. package/src/assets/img/selected.svg +0 -4
  125. package/src/assets/img/singleQa.png +0 -0
  126. package/src/assets/img/txt.png +0 -0
  127. package/src/assets/img/webSearch.png +0 -0
  128. package/src/assets/img/word.png +0 -0
  129. package/src/assets/login/homeBg.png +0 -0
  130. package/src/assets/login/left.jpg +0 -0
  131. package/src/assets/login/logoImg.png +0 -0
  132. package/src/examples/ConversationAssistantPage/index.tsx +0 -42
  133. package/src/examples/LoginPage/index.tsx +0 -20
  134. package/src/examples/chat/components/DrawerGraphPreview.tsx +0 -78
  135. package/src/examples/chat/index.tsx +0 -171
  136. package/src/examples/chat/logo03.png +0 -0
  137. package/src/examples/chatCompare/icons/rag_think.svg +0 -8
  138. package/src/examples/chatCompare/icons/wenda_lianwangsousuo.svg +0 -9
  139. package/src/examples/chatCompare/index.tsx +0 -154
  140. package/src/examples/gientechStreamFilesReader/index.tsx +0 -979
  141. package/src/examples/headlessChat/assets/mind.svg +0 -6
  142. package/src/examples/headlessChat/assets/net.svg +0 -7
  143. package/src/examples/headlessChat/index.tsx +0 -298
  144. package/src/examples/knowledgebaseDetails/index.tsx +0 -119
  145. package/src/examples/ragDatabaseDataPage/index.tsx +0 -40
  146. package/src/examples/ragDatabaseIdPage/index.tsx +0 -126
  147. package/src/examples/ragDatabasePage/index.tsx +0 -36
  148. package/src/examples/ragModelManagePage/index.tsx +0 -107
  149. package/src/examples/ragModelManagePage/style.css +0 -7
  150. package/src/examples/ragSearchPage/index.tsx +0 -0
  151. package/src/examples/ragSensitiveWordsPage/index.tsx +0 -117
  152. package/src/examples/ragSensitiveWordsPage/style.css +0 -16
  153. package/src/examples/sensitiveId/index.tsx +0 -41
  154. package/src/examples/streamFiles/index.tsx +0 -417
  155. package/src/examples/utils/demo_setting_pannel.ts +0 -0
  156. package/src/lib_enter.ts +0 -44
  157. package/src/main.tsx +0 -5
  158. package/src/main.tsx.backup +0 -5
  159. package/src/modules/CHAT_UNIFICATION_PLAN.md +0 -324
  160. package/src/modules/assistantConfig/assets/databse.svg +0 -6
  161. package/src/modules/assistantConfig/assets/empty.png +0 -0
  162. package/src/modules/assistantConfig/assets/graph.svg +0 -4
  163. package/src/modules/assistantConfig/assets/sensitive.svg +0 -5
  164. package/src/modules/assistantConfig/components/Database.tsx +0 -171
  165. package/src/modules/assistantConfig/components/Graph.tsx +0 -177
  166. package/src/modules/assistantConfig/components/Knowledge.tsx +0 -276
  167. package/src/modules/assistantConfig/components/NotFoundContent.tsx +0 -21
  168. package/src/modules/assistantConfig/components/Paragraph.tsx +0 -51
  169. package/src/modules/assistantConfig/components/ParamsItem.tsx +0 -40
  170. package/src/modules/assistantConfig/components/ResourceBinderItem.tsx +0 -133
  171. package/src/modules/assistantConfig/components/SearchableSelector.tsx +0 -500
  172. package/src/modules/assistantConfig/components/Sensitive.tsx +0 -221
  173. package/src/modules/assistantConfig/components/SliderInput.tsx +0 -66
  174. package/src/modules/assistantConfig/constants.tsx +0 -75
  175. package/src/modules/assistantConfig/index.tsx +0 -785
  176. package/src/modules/assistantConfig/server.ts +0 -262
  177. package/src/modules/chat/AllFiles.tsx +0 -158
  178. package/src/modules/chat/Conversations/Item.tsx +0 -169
  179. package/src/modules/chat/Conversations/List.tsx +0 -210
  180. package/src/modules/chat/Conversations/groupByTime.ts +0 -39
  181. package/src/modules/chat/Conversations/index.tsx +0 -255
  182. package/src/modules/chat/ReferenceBar.tsx +0 -659
  183. package/src/modules/chat/constants.tsx +0 -66
  184. package/src/modules/chat/i18n.ts +0 -151
  185. package/src/modules/chat/i18n.tsx +0 -151
  186. package/src/modules/chat/icons/rag_think.svg +0 -8
  187. package/src/modules/chat/icons/wenda_lianwangsousuo.svg +0 -9
  188. package/src/modules/chat/index.tsx +0 -2400
  189. package/src/modules/chat/referenceCom/DeleteModal.tsx +0 -75
  190. package/src/modules/chat/referenceCom/DrawerContent.tsx +0 -136
  191. package/src/modules/chat/referenceCom/DrawerDatabase.tsx +0 -102
  192. package/src/modules/chat/referenceCom/DrawerGraphPreview.tsx +0 -86
  193. package/src/modules/chat/referenceCom/DrawerPreview.tsx +0 -73
  194. package/src/modules/chat/referenceCom/DrawerTitle.tsx +0 -26
  195. package/src/modules/chat/referenceCom/RenameModal.tsx +0 -86
  196. package/src/modules/chat/referenceCom/TagCom.tsx +0 -30
  197. package/src/modules/chat/style.css +0 -6
  198. package/src/modules/chat/style.less +0 -7
  199. package/src/modules/chat/types.ts +0 -17
  200. package/src/modules/chat/utils/index.ts +0 -348
  201. package/src/modules/chatCompare/UseChatCompareHooks.ts +0 -103
  202. package/src/modules/chatCompare/components/AichatCompareUseController.tsx +0 -754
  203. package/src/modules/chatCompare/components/AssistantSelector.tsx +0 -127
  204. package/src/modules/chatCompare/components/ChatInputer.tsx +0 -67
  205. package/src/modules/chatCompare/components/ChatInstance.tsx +0 -426
  206. package/src/modules/chatCompare/components/ChatItem.tsx +0 -556
  207. package/src/modules/chatCompare/components/Sender/FileCardCommon.tsx +0 -97
  208. package/src/modules/chatCompare/components/Sender/FileUpload.tsx +0 -89
  209. package/src/modules/chatCompare/components/Sender/FilesDisplay.tsx +0 -309
  210. package/src/modules/chatCompare/components/Sender/VoiceInput.tsx +0 -80
  211. package/src/modules/chatCompare/components/Sender/contexts/BadgeContext.tsx +0 -36
  212. package/src/modules/chatCompare/components/Sender/fileIcon.tsx +0 -100
  213. package/src/modules/chatCompare/components/Sender/index.tsx +0 -850
  214. package/src/modules/chatCompare/components/UseChatInstanceHooks.ts +0 -406
  215. package/src/modules/chatCompare/components/UseScrollHooks.ts +0 -36
  216. package/src/modules/chatCompare/components/components/AllFiles.tsx +0 -156
  217. package/src/modules/chatCompare/components/components/DeleteModal.tsx +0 -75
  218. package/src/modules/chatCompare/components/components/DrawerContent.tsx +0 -138
  219. package/src/modules/chatCompare/components/components/DrawerDatabase.tsx +0 -110
  220. package/src/modules/chatCompare/components/components/DrawerGraphPreview.tsx +0 -95
  221. package/src/modules/chatCompare/components/components/DrawerPreview.tsx +0 -75
  222. package/src/modules/chatCompare/components/components/DrawerTitle.tsx +0 -26
  223. package/src/modules/chatCompare/components/components/DrawerVideo.tsx +0 -85
  224. package/src/modules/chatCompare/components/components/ReferenceBar.tsx +0 -659
  225. package/src/modules/chatCompare/components/components/RenameModal.tsx +0 -86
  226. package/src/modules/chatCompare/components/components/TagCom.tsx +0 -30
  227. package/src/modules/chatCompare/components/defaultStyleSet.tsx +0 -148
  228. package/src/modules/chatCompare/components/server.ts +0 -208
  229. package/src/modules/chatCompare/components/serverFn.ts +0 -172
  230. package/src/modules/chatCompare/components/style.less +0 -97
  231. package/src/modules/chatCompare/components/useFileManager.ts +0 -173
  232. package/src/modules/chatCompare/components/utils.ts +0 -31
  233. package/src/modules/chatCompare/data.ts +0 -842
  234. package/src/modules/chatCompare/index.tsx +0 -537
  235. package/src/modules/chatCompare/utils/AiChat.types.tsx +0 -110
  236. package/src/modules/chatCompare/utils/constants.tsx +0 -70
  237. package/src/modules/chatCompare/utils/fileUploadValidator.ts +0 -183
  238. package/src/modules/chatCompare/utils/icons/rag_think.svg +0 -8
  239. package/src/modules/chatCompare/utils/icons/wenda_lianwangsousuo.svg +0 -9
  240. package/src/modules/chatCompare/utils/index.ts +0 -46
  241. package/src/modules/database/CreateModal.tsx +0 -402
  242. package/src/modules/database/assets/Doris.png +0 -0
  243. package/src/modules/database/assets/PostgreSQL.png +0 -0
  244. package/src/modules/database/assets/SQLServer.png +0 -0
  245. package/src/modules/database/assets/database_connect.svg +0 -66
  246. package/src/modules/database/assets/database_upload.svg +0 -29
  247. package/src/modules/database/assets/empty.png +0 -0
  248. package/src/modules/database/index.tsx +0 -477
  249. package/src/modules/database/server.ts +0 -196
  250. package/src/modules/databaseId/CustomCom.tsx +0 -156
  251. package/src/modules/databaseId/EditConfig.tsx +0 -280
  252. package/src/modules/databaseId/UploadDrawer.tsx +0 -535
  253. package/src/modules/databaseId/assets/aiOptimize.svg +0 -10
  254. package/src/modules/databaseId/assets/empty.png +0 -0
  255. package/src/modules/databaseId/assets/template.svg +0 -6
  256. package/src/modules/databaseId/assets/upload.svg +0 -9
  257. package/src/modules/databaseId/assets/useTemp.svg +0 -6
  258. package/src/modules/databaseId/i18n.ts +0 -360
  259. package/src/modules/databaseId/index.tsx +0 -855
  260. package/src/modules/databaseId/server.ts +0 -286
  261. package/src/modules/databaseId/style.css +0 -5
  262. package/src/modules/databaseTable/EditRowDrawer.tsx +0 -124
  263. package/src/modules/databaseTable/index.tsx +0 -359
  264. package/src/modules/databaseTable/server.ts +0 -180
  265. package/src/modules/headlessChat/ReferenceBar.tsx +0 -783
  266. package/src/modules/headlessChat/constants.tsx +0 -54
  267. package/src/modules/headlessChat/index.tsx +0 -1903
  268. package/src/modules/headlessChat/referenceCom/DeleteModal.tsx +0 -75
  269. package/src/modules/headlessChat/referenceCom/DrawerContent.tsx +0 -136
  270. package/src/modules/headlessChat/referenceCom/DrawerDatabase.tsx +0 -102
  271. package/src/modules/headlessChat/referenceCom/DrawerGraphPreview.tsx +0 -86
  272. package/src/modules/headlessChat/referenceCom/DrawerPreview.tsx +0 -73
  273. package/src/modules/headlessChat/referenceCom/DrawerTitle.tsx +0 -26
  274. package/src/modules/headlessChat/referenceCom/RenameModal.tsx +0 -86
  275. package/src/modules/headlessChat/referenceCom/TagCom.tsx +0 -30
  276. package/src/modules/headlessChat/style.less +0 -3
  277. package/src/modules/headlessChat/types.ts +0 -23
  278. package/src/modules/headlessChat/utils/index.ts +0 -348
  279. package/src/modules/knowledgeBase/index.tsx +0 -58
  280. package/src/modules/knowledgeBase/server.ts +0 -196
  281. package/src/modules/knowledgebaseDetails/KnowledgeBaseDetails.tsx +0 -169
  282. package/src/modules/knowledgebaseDetails/components/KnowledgeBaseSummaryCard.tsx +0 -193
  283. package/src/modules/knowledgebaseDetails/components/fileManagementParts.tsx +0 -534
  284. package/src/modules/knowledgebaseDetails/components/index.ts +0 -3
  285. package/src/modules/knowledgebaseDetails/index.ts +0 -3
  286. package/src/modules/knowledgebaseDetails/modules/ConfigModule.tsx +0 -49
  287. package/src/modules/knowledgebaseDetails/modules/FaqModule.tsx +0 -47
  288. package/src/modules/knowledgebaseDetails/modules/KnowledgeParseModule.tsx +0 -771
  289. package/src/modules/knowledgebaseDetails/modules/RetrievalTestModule.tsx +0 -49
  290. package/src/modules/knowledgebaseDetails/modules/UploadManagementModule.tsx +0 -49
  291. package/src/modules/knowledgebaseDetails/modules/types.ts +0 -44
  292. package/src/modules/knowledgebaseDetails/modules-shim.d.ts +0 -14
  293. package/src/modules/knowledgebaseDetails/servers/analysis.ts +0 -5
  294. package/src/modules/knowledgebaseDetails/servers/index.ts +0 -318
  295. package/src/modules/login/components/Login/LoginBox/index.tsx +0 -105
  296. package/src/modules/login/components/Login/RegisterBox/index.tsx +0 -181
  297. package/src/modules/login/components/Login/index.tsx +0 -100
  298. package/src/modules/login/i18n.ts +0 -217
  299. package/src/modules/login/index.tsx +0 -113
  300. package/src/modules/login/style.css +0 -3
  301. package/src/modules/login/useServices.ts +0 -53
  302. package/src/modules/login/utils.ts +0 -42
  303. package/src/modules/modelManage/ConfigDrawer.tsx +0 -267
  304. package/src/modules/modelManage/ReplaceModal.tsx +0 -113
  305. package/src/modules/modelManage/assets/empty.png +0 -0
  306. package/src/modules/modelManage/const.ts +0 -51
  307. package/src/modules/modelManage/i18n.ts +0 -407
  308. package/src/modules/modelManage/index.tsx +0 -668
  309. package/src/modules/modelManage/server.ts +0 -231
  310. package/src/modules/nodegraph/index.tsx +0 -1
  311. package/src/modules/search/assets/Icon-history.svg +0 -8
  312. package/src/modules/search/assets/answerAwartar.png +0 -0
  313. package/src/modules/search/assets/doc.png +0 -0
  314. package/src/modules/search/assets/genera.gif +0 -0
  315. package/src/modules/search/assets/icon-robot.svg +0 -9
  316. package/src/modules/search/assets/icon-search-bar.svg +0 -14
  317. package/src/modules/search/assets/icon-sub-title.svg +0 -3
  318. package/src/modules/search/assets/icon-title.svg +0 -9
  319. package/src/modules/search/assets/icon-zoomOut.svg +0 -9
  320. package/src/modules/search/assets/iconAi.svg +0 -9
  321. package/src/modules/search/assets/pdf.png +0 -0
  322. package/src/modules/search/assets/ppt.png +0 -0
  323. package/src/modules/search/assets/search.svg +0 -3
  324. package/src/modules/search/assets/selected.svg +0 -4
  325. package/src/modules/search/assets/txt.png +0 -0
  326. package/src/modules/search/assets/xls.png +0 -0
  327. package/src/modules/search/components/AssisSelect.tsx +0 -137
  328. package/src/modules/search/components/Editor/ChatViewEditor.tsx +0 -261
  329. package/src/modules/search/components/Editor/aichat.css +0 -1
  330. package/src/modules/search/components/Editor/constant.ts +0 -13
  331. package/src/modules/search/components/Editor/index.tsx +0 -113
  332. package/src/modules/search/components/Editor/plugins/autofomatRules.ts +0 -332
  333. package/src/modules/search/components/Editor/plugins/convertImgPlugins.tsx +0 -20
  334. package/src/modules/search/components/Editor/plugins/createIndexes.tsx +0 -38
  335. package/src/modules/search/components/Editor/plugins/displayer.ts +0 -298
  336. package/src/modules/search/components/Editor/plugins/imageClick.tsx +0 -32
  337. package/src/modules/search/components/Editor/plugins/myplugin.tsx +0 -98
  338. package/src/modules/search/components/Editor/ui/avatar.tsx +0 -19
  339. package/src/modules/search/components/Editor/ui/blockquote-element.tsx +0 -21
  340. package/src/modules/search/components/Editor/ui/button.tsx +0 -58
  341. package/src/modules/search/components/Editor/ui/calendar.tsx +0 -68
  342. package/src/modules/search/components/Editor/ui/caption.tsx +0 -46
  343. package/src/modules/search/components/Editor/ui/checkbox.tsx +0 -27
  344. package/src/modules/search/components/Editor/ui/code-block-combobox.tsx +0 -188
  345. package/src/modules/search/components/Editor/ui/code-block-element.css +0 -434
  346. package/src/modules/search/components/Editor/ui/code-block-element.tsx +0 -39
  347. package/src/modules/search/components/Editor/ui/code-leaf.tsx +0 -24
  348. package/src/modules/search/components/Editor/ui/code-line-element.tsx +0 -10
  349. package/src/modules/search/components/Editor/ui/code-syntax-leaf.tsx +0 -21
  350. package/src/modules/search/components/Editor/ui/column-element.tsx +0 -30
  351. package/src/modules/search/components/Editor/ui/column-group-element.tsx +0 -94
  352. package/src/modules/search/components/Editor/ui/command.tsx +0 -75
  353. package/src/modules/search/components/Editor/ui/comment-avatar.tsx +0 -22
  354. package/src/modules/search/components/Editor/ui/comment-create-form.tsx +0 -37
  355. package/src/modules/search/components/Editor/ui/comment-item.tsx +0 -74
  356. package/src/modules/search/components/Editor/ui/comment-leaf.tsx +0 -49
  357. package/src/modules/search/components/Editor/ui/comment-more-dropdown.tsx +0 -42
  358. package/src/modules/search/components/Editor/ui/comment-reply-items.tsx +0 -22
  359. package/src/modules/search/components/Editor/ui/comment-resolve-button.tsx +0 -32
  360. package/src/modules/search/components/Editor/ui/comment-value.tsx +0 -34
  361. package/src/modules/search/components/Editor/ui/comments-popover.tsx +0 -63
  362. package/src/modules/search/components/Editor/ui/date-element.tsx +0 -83
  363. package/src/modules/search/components/Editor/ui/dialog.tsx +0 -63
  364. package/src/modules/search/components/Editor/ui/draggable.tsx +0 -177
  365. package/src/modules/search/components/Editor/ui/dropdown-menu.tsx +0 -180
  366. package/src/modules/search/components/Editor/ui/emoji-input-element.tsx +0 -85
  367. package/src/modules/search/components/Editor/ui/excalidraw-element.tsx +0 -28
  368. package/src/modules/search/components/Editor/ui/fixed-toolbar-buttons.tsx +0 -76
  369. package/src/modules/search/components/Editor/ui/fixed-toolbar.tsx +0 -8
  370. package/src/modules/search/components/Editor/ui/floating-toolbar-buttons.tsx +0 -51
  371. package/src/modules/search/components/Editor/ui/floating-toolbar.tsx +0 -77
  372. package/src/modules/search/components/Editor/ui/heading-element.tsx +0 -48
  373. package/src/modules/search/components/Editor/ui/highlight-leaf.tsx +0 -17
  374. package/src/modules/search/components/Editor/ui/hr-element.tsx +0 -30
  375. package/src/modules/search/components/Editor/ui/icons.tsx +0 -267
  376. package/src/modules/search/components/Editor/ui/image-element.tsx +0 -74
  377. package/src/modules/search/components/Editor/ui/inline-combobox.tsx +0 -368
  378. package/src/modules/search/components/Editor/ui/input.tsx +0 -25
  379. package/src/modules/search/components/Editor/ui/insert-dropdown-menu.tsx +0 -218
  380. package/src/modules/search/components/Editor/ui/kbd-leaf.tsx +0 -20
  381. package/src/modules/search/components/Editor/ui/link-element.tsx +0 -29
  382. package/src/modules/search/components/Editor/ui/link-floating-toolbar.tsx +0 -161
  383. package/src/modules/search/components/Editor/ui/list-element.tsx +0 -30
  384. package/src/modules/search/components/Editor/ui/mark-toolbar-button.tsx +0 -24
  385. package/src/modules/search/components/Editor/ui/media-embed-element.tsx +0 -133
  386. package/src/modules/search/components/Editor/ui/media-popover.tsx +0 -97
  387. package/src/modules/search/components/Editor/ui/mention-element.tsx +0 -43
  388. package/src/modules/search/components/Editor/ui/mention-input-element.tsx +0 -141
  389. package/src/modules/search/components/Editor/ui/mode-dropdown-menu.tsx +0 -93
  390. package/src/modules/search/components/Editor/ui/more-dropdown-menu.tsx +0 -67
  391. package/src/modules/search/components/Editor/ui/paragraph-element.tsx +0 -4
  392. package/src/modules/search/components/Editor/ui/placeholder.tsx +0 -52
  393. package/src/modules/search/components/Editor/ui/popover.tsx +0 -32
  394. package/src/modules/search/components/Editor/ui/resizable.tsx +0 -66
  395. package/src/modules/search/components/Editor/ui/separator.tsx +0 -25
  396. package/src/modules/search/components/Editor/ui/style.less +0 -12
  397. package/src/modules/search/components/Editor/ui/table-cell-element.tsx +0 -143
  398. package/src/modules/search/components/Editor/ui/table-element.tsx +0 -243
  399. package/src/modules/search/components/Editor/ui/table-row-element.tsx +0 -22
  400. package/src/modules/search/components/Editor/ui/tableValue.tsx +0 -135
  401. package/src/modules/search/components/Editor/ui/todo-list-element.tsx +0 -43
  402. package/src/modules/search/components/Editor/ui/toggle-element.tsx +0 -31
  403. package/src/modules/search/components/Editor/ui/toolbar.tsx +0 -157
  404. package/src/modules/search/components/Editor/ui/tooltip.tsx +0 -65
  405. package/src/modules/search/components/Editor/ui/turn-into-dropdown-menu.tsx +0 -160
  406. package/src/modules/search/components/Editor/ui/with-draggables.tsx +0 -175
  407. package/src/modules/search/components/FileList.tsx +0 -287
  408. package/src/modules/search/components/ImageGroupView/index.tsx +0 -85
  409. package/src/modules/search/components/ResultContent.tsx +0 -232
  410. package/src/modules/search/components/SearchInput.tsx +0 -232
  411. package/src/modules/search/components/SearchLanding.tsx +0 -74
  412. package/src/modules/search/components/SearchView.tsx +0 -563
  413. package/src/modules/search/components/SimpleEditor.tsx +0 -158
  414. package/src/modules/search/components/SimpleFileList.tsx +0 -215
  415. package/src/modules/search/index.tsx +0 -10
  416. package/src/modules/search/reademe.md +0 -1
  417. package/src/modules/search/servers/apis.tsx +0 -19
  418. package/src/modules/search/servers/index.ts +0 -184
  419. package/src/modules/search/style.less +0 -503
  420. package/src/modules/search/type.ts +0 -22
  421. package/src/modules/search/utils.ts +0 -34
  422. package/src/modules/sensitive/i18n.ts +0 -391
  423. package/src/modules/sensitive/index.tsx +0 -604
  424. package/src/modules/sensitive/sensitiveEditor.tsx +0 -543
  425. package/src/modules/sensitive/server.ts +0 -197
  426. package/src/modules/sensitiveId/AutoTag.tsx +0 -311
  427. package/src/modules/sensitiveId/UploadModal.tsx +0 -181
  428. package/src/modules/sensitiveId/VirtualWrap.tsx +0 -125
  429. package/src/modules/sensitiveId/index.tsx +0 -253
  430. package/src/modules/sensitiveId/server.ts +0 -142
  431. package/src/modules/streamFilesReader/GientechStreamReader.tsx +0 -1658
  432. package/src/modules/streamFilesReader/components/Header/Toolbar.tsx +0 -0
  433. package/src/modules/streamFilesReader/components/Header/index.tsx +0 -297
  434. package/src/modules/streamFilesReader/index.tsx +0 -3
  435. package/src/style.css +0 -6
  436. package/src/type.d.ts +0 -0
  437. package/src/utils/commonFn.tsx +0 -153
  438. package/src/utils/decryptApiKey.ts +0 -40
  439. package/src/utils/gientechCommon/components/AppError.tsx +0 -32
  440. package/src/utils/gientechCommon/components/AppLoading.tsx +0 -75
  441. package/src/utils/gientechCommon/components/DeleteModal.tsx +0 -75
  442. package/src/utils/gientechCommon/components/DisplayError.tsx +0 -33
  443. package/src/utils/gientechCommon/components/DisplayLoading.tsx +0 -38
  444. package/src/utils/gientechCommon/components/FeedBackModal.tsx +0 -319
  445. package/src/utils/gientechCommon/components/FileCardCommon.tsx +0 -82
  446. package/src/utils/gientechCommon/components/FileManager/index.tsx +0 -418
  447. package/src/utils/gientechCommon/components/FileManager/style.css +0 -5
  448. package/src/utils/gientechCommon/components/Messages/GientechNewChatWelcome.tsx +0 -583
  449. package/src/utils/gientechCommon/components/Messages/ReferenceCard.tsx +0 -359
  450. package/src/utils/gientechCommon/components/Messages/RetriveItem.tsx +0 -245
  451. package/src/utils/gientechCommon/components/Messages/WebRetriveItem.tsx +0 -209
  452. package/src/utils/gientechCommon/components/Messages/defaultBot.png +0 -0
  453. package/src/utils/gientechCommon/components/Messages/defaultStyleSet.tsx +0 -148
  454. package/src/utils/gientechCommon/components/Messages/defaultWeLogo.svg +0 -14
  455. package/src/utils/gientechCommon/components/RenameModal.tsx +0 -86
  456. package/src/utils/gientechCommon/components/style.less +0 -11
  457. package/src/utils/gientechCommon/configs/commonConfig.ts +0 -2
  458. package/src/utils/gientechCommon/configs/senderConfig.ts +0 -0
  459. package/src/utils/gientechCommon/configs/stylesConfig.ts +0 -142
  460. package/src/utils/gientechCommon/hooks/AichatUseController.tsx +0 -761
  461. package/src/utils/gientechCommon/hooks/style.less +0 -8
  462. package/src/utils/gientechCommon/hooks/useFileDisplayTools.tsx +0 -352
  463. package/src/utils/gientechCommon/hooks/useFileManager.ts +0 -169
  464. package/src/utils/gientechCommon/slate/converters/deserializers.ts +0 -763
  465. package/src/utils/gientechCommon/slate/converters/mockData.ts +0 -232
  466. package/src/utils/gientechCommon/slate/converters/slateConverters.ts +0 -258
  467. package/src/utils/gientechCommon/slate/richElements/index.tsx +0 -499
  468. package/src/utils/gientechCommon/utils/fileUtils.ts +0 -86
  469. package/src/utils/gientechCommon/utils/index.ts +0 -386
  470. package/src/utils/gientechCommon/utils/request.ts +0 -37
  471. package/src/utils/gientechCommon/utils/serverFn.ts +0 -172
  472. package/src/utils/index.tsx +0 -186
  473. package/src/utils/testconfigs/demologin/index.tsx +0 -32
  474. package/src/utils/testconfigs/index.ts +0 -66
  475. package/src/vite-env.d.ts +0 -49
  476. package/stats.html +0 -4949
  477. package/tailwind.config.js +0 -170
  478. package/tsconfig.app.json +0 -31
  479. package/tsconfig.app.tsbuildinfo +0 -11
  480. package/tsconfig.json +0 -17
  481. package/tsconfig.node.json +0 -23
  482. package/tsconfig.node.tsbuildinfo +0 -1
  483. package/vite.config.app.ts +0 -91
  484. package/vite.config.ts +0 -238
  485. /package/{dist/assets → assets}/Doris.png +0 -0
  486. /package/{dist/assets → assets}/PostgreSQL.png +0 -0
  487. /package/{dist/assets → assets}/SQLServer.png +0 -0
  488. /package/{dist/assets → assets}/empty.png +0 -0
  489. /package/{dist/assets → assets}/homeBg.png +0 -0
  490. /package/{dist/assets → assets}/index-CpW6Dhpp.js +0 -0
  491. /package/{dist/assets → assets}/left.jpg +0 -0
  492. /package/{dist/assets → assets}/logoImg.png +0 -0
  493. /package/{dist/assets → assets}/style.css +0 -0
  494. /package/{dist/assets → assets}/style3.css +0 -0
  495. /package/{dist/assets → assets}/style4.css +0 -0
  496. /package/{dist/assets → assets}/style5.css +0 -0
  497. /package/{dist/assets → assets}/worker-BbpylX7l.js +0 -0
  498. /package/{dist/assistantConfig.d.ts → assistantConfig.d.ts} +0 -0
  499. /package/{dist/chat.d.ts → chat.d.ts} +0 -0
  500. /package/{dist/chatCompare.d.ts → chatCompare.d.ts} +0 -0
  501. /package/{dist/database.d.ts → database.d.ts} +0 -0
  502. /package/{dist/databaseId.d.ts → databaseId.d.ts} +0 -0
  503. /package/{dist/databaseTable.d.ts → databaseTable.d.ts} +0 -0
  504. /package/{dist/icons → icons}/answerAwartar.png +0 -0
  505. /package/{dist/icons → icons}/docx-file.png +0 -0
  506. /package/{dist/icons → icons}/folder.png +0 -0
  507. /package/{dist/icons → icons}/html.png +0 -0
  508. /package/{dist/icons → icons}/image.png +0 -0
  509. /package/{dist/icons → icons}/jpg-file.png +0 -0
  510. /package/{dist/icons → icons}/json.png +0 -0
  511. /package/{dist/icons → icons}/md.png +0 -0
  512. /package/{dist/icons → icons}/pdf.png +0 -0
  513. /package/{dist/icons → icons}/pptx.png +0 -0
  514. /package/{dist/icons → icons}/questionAwartar.png +0 -0
  515. /package/{dist/icons → icons}/sheets.png +0 -0
  516. /package/{dist/icons → icons}/txt.png +0 -0
  517. /package/{dist/icons → icons}/xlsx.png +0 -0
  518. /package/{dist/index.d.ts → index.d.ts} +0 -0
  519. /package/{dist/modelManage.d.ts → modelManage.d.ts} +0 -0
  520. /package/{dist/sensitive.d.ts → sensitive.d.ts} +0 -0
  521. /package/{dist/streamFilesReader.d.ts → streamFilesReader.d.ts} +0 -0
  522. /package/{dist/vite.svg → vite.svg} +0 -0
@@ -1,2400 +0,0 @@
1
- import React, { useEffect, useState, useMemo, useRef } from 'react';
2
- import axios from 'axios';
3
- import {
4
- AiChat,
5
- type AppStatusManager,
6
- validateFileUpload,
7
- showValidationErrors,
8
- } from '@mxmweb/aichat';
9
-
10
- /** 与 @mxmweb/aichat 的 locale 一致,支持中/英/日 */
11
- export type AIChatLocale = 'zh' | 'en' | 'ja';
12
- /** 与 @mxmweb/aichat 的 messages 结构一致,用于部分覆盖内置文案 */
13
- export type AIChatMessagesPartial = Partial<Record<string, unknown>>;
14
- import { ChatMessageAdapter } from '@mxmweb/rtext';
15
- import { ConfigProvider, Drawer, message } from 'antd';
16
- import { uid } from 'uid';
17
- import { History } from 'lucide-react';
18
-
19
- import { defaultTheme, deepMergeTheme, type Styles } from '@mxmweb/zui';
20
- import { DefaultSenderConfig } from './constants';
21
- import { getGientechChatMessages, GientechChatI18nProvider } from './i18n';
22
- import GientechConversationPanel from './Conversations';
23
- import { convertQueryReplyPairListToMessages, toCopy } from '../../utils/commonFn';
24
- import {
25
- getFeedbackList,
26
- handleCancelFeedBack,
27
- handleDeleteConversation,
28
- handleFeedBack,
29
- handleRename,
30
- handleCreateConversation,
31
- } from '../../utils/gientechCommon/utils/serverFn';
32
-
33
- import GientechNewChatWelcome from '../../utils/gientechCommon/components/Messages/GientechNewChatWelcome';
34
- import AichatUseController from '../../utils/gientechCommon/hooks/AichatUseController';
35
- import { useFileManager } from '../../utils/gientechCommon/hooks/useFileManager';
36
- import { useFileDisplayTools } from '../../utils/gientechCommon/hooks/useFileDisplayTools';
37
- import FeedBackModal from '../../utils/gientechCommon/components/FeedBackModal';
38
- import AppLoading from '../../utils/gientechCommon/components/AppLoading';
39
- import DisplayLoading from '../../utils/gientechCommon/components/DisplayLoading';
40
- import AppError from '../../utils/gientechCommon/components/AppError';
41
- import DisplayError from '../../utils/gientechCommon/components/DisplayError';
42
- import { mergeFiles } from '../../utils/gientechCommon/utils/fileUtils';
43
- import { RenameModal } from '../../utils/gientechCommon/components/RenameModal';
44
- import { DeleteModal } from '../../utils/gientechCommon/components/DeleteModal';
45
- import { ReferenceBar } from './ReferenceBar';
46
- import '@mxmweb/rtext/style.css';
47
- import '@mxmweb/aichat/style.css';
48
- import '@mxmweb/zui/style.css';
49
- import './style.css';
50
- import { fileViewTypes, getUrlPrefix, TempBaseUrl } from './utils';
51
- import DrawerPreview from './referenceCom/DrawerPreview';
52
- import { AllFiles } from './AllFiles';
53
- import { getTypeByName } from '@/utils';
54
- export enum DrawerType {
55
- REFERENCELIST = 'referencelist',
56
- ALLFILELIST = 'allFileList',
57
- }
58
-
59
- interface SenderConfig {
60
- actions?: Array<{
61
- name: string;
62
- icon?: React.ReactNode;
63
- badgeCount?: number;
64
- enabled?: boolean;
65
- [key: string]: any;
66
- }>;
67
- switchs?: Array<{
68
- name: string;
69
- label: string;
70
- enabled?: boolean;
71
- [key: string]: any;
72
- }>;
73
- [key: string]: any;
74
- }
75
-
76
- // 自定义组件接口
77
- interface CustomComponents {
78
- LogoBox?: React.ComponentType<any> | null;
79
- AiChatBox?: React.ComponentType<any>;
80
- UserChatBox?: React.ComponentType<any>;
81
- WelcomeComponent?: React.ComponentType<any>;
82
- DisplayLoading?: React.ComponentType<any>;
83
- DisplayError?: React.ComponentType<any>;
84
- AppError?: React.ComponentType<any>;
85
- AppLoading?: React.ComponentType<any>;
86
- [key: string]: React.ComponentType<any> | null | undefined;
87
- }
88
-
89
- interface GientechChatAdopterProps {
90
- token: string;
91
- url?: string;
92
- CSRFToken?: string;
93
- styles?: Styles;
94
- eventsEmit?: (eventName: string, data: any) => void;
95
- CustomComponents?: CustomComponents;
96
- senderConfig?: SenderConfig;
97
- appLoadingConfig?: {
98
- title?: string;
99
- subtitle?: string;
100
- };
101
- /** 界面语言:中文(zh)、英文(en)、日文(ja),默认 zh */
102
- locale?: AIChatLocale;
103
- /** 部分覆盖内置文案,与 locale 合并后传给 AiChat(结构见 @mxmweb/aichat 的 AIChatMessages) */
104
- messages?: AIChatMessagesPartial;
105
- [key: string]: any;
106
- }
107
-
108
- export interface SidebarTabConfig {
109
- key: string;
110
- type: 'custom' | 'form';
111
- label: string;
112
- icon: React.ReactNode;
113
- enabled?: boolean;
114
- component?: React.ReactNode; // type=custom
115
- formConfig?: any[]; // type=form
116
- initialValues?: Record<string, any>;
117
- onChange?: (values: any) => void;
118
- [key: string]: any;
119
- }
120
-
121
- export default function withGientechChatAdopter(WrappedComponent = AiChat) {
122
- /**
123
- * GientechChatAdopter 高阶组件
124
- * 封装了与Gientech后端服务的接口对接、状态管理、事件处理等核心业务逻辑
125
- * @param {React.ComponentType} WrappedComponent - 需要包裹的基础聊天组件,默认为 AiChat
126
- */
127
- return function GientechChatAdopter({
128
- token,
129
- url = 'http://localhost:8888',
130
- styles,
131
- CSRFToken,
132
- eventsEmit,
133
- scrollOld,
134
- locale = 'zh',
135
- messages,
136
- ...rest
137
- }: GientechChatAdopterProps) {
138
- // 统一归一化样式:使用 UI 库的 deepMergeTheme
139
- const normalizedStyles: Styles = useMemo(() => {
140
- const baseStyles: Styles = { theme: defaultTheme, mode: 'light' };
141
- return deepMergeTheme(baseStyles, styles);
142
- }, [styles]);
143
- const [isRenameModalOpen, setisRenameModalOpen] = useState(false);
144
- const [isRemoveModalOpen, setisRemoveModalOpen] = useState(false);
145
- const [curEditData, setCurEditData] = useState<any>(null);
146
- const [open, setOpen] = useState(false);
147
- const [drawerType, setDrawerType] = useState<string>('mark');
148
- const [curFileInfo, setCurFileInfo] = useState({
149
- url: '',
150
- parse_url: '',
151
- file_type: '',
152
- file_name: '',
153
- });
154
- // =================================================================
155
- // State Management - 状态管理
156
- // =================================================================
157
- const [conversationList, setConversationList] = useState<any[]>([]); // 对话列表
158
- // 会话列表分页状态
159
- const [convPageNo, setConvPageNo] = useState<number>(1);
160
- const [convPageSize] = useState<number>(16);
161
- const [convTotal, setConvTotal] = useState<number>(0);
162
- const [convLoading, setConvLoading] = useState<boolean>(false);
163
- const [chatData, setChatData] = useState<any[]>([]); // 所有对话的聊天记录
164
- const [activeSessionId, setActiveSessionId] = useState<string | undefined>(undefined); // 当前激活的对话ID
165
- const [recommandQuestions, setRecommandQuestions] = useState<any[]>([]); // 推荐问题列表
166
- const [assistantList, setAssistantList] = useState<any[]>([]); // 智能体(助手)列表
167
- const [newAssistantId, setNewAssistantId] = useState<string | undefined>(undefined); // 新建对话时选择的智能体ID
168
- const [appStatus, setAppStatus] = useState<AppStatusManager>({
169
- display: 'ready', // 主聊天区域状态: ready, loading, processing, error, uploading
170
- sender: 'ready', // 发送器状态: ready, processing, error, uploading
171
- app: 'initializing', // 应用整体状态: initializing, ready, error
172
- });
173
-
174
- // 发送器配置支持外部传入
175
- // 深度合并工具,customConfig 有的字段覆盖 defaultConfig
176
- function deepMerge(defaultConfig: any, customConfig: any): any {
177
- if (!customConfig) return defaultConfig;
178
- const result: any = Array.isArray(defaultConfig) ? [...defaultConfig] : { ...defaultConfig };
179
- for (const key in customConfig) {
180
- if (
181
- customConfig[key] !== undefined &&
182
- customConfig[key] !== null &&
183
- Object.prototype.hasOwnProperty.call(customConfig, key)
184
- ) {
185
- // 特殊处理 actions 数组:合并而不是替换
186
- if (
187
- key === 'actions' &&
188
- Array.isArray(defaultConfig[key]) &&
189
- Array.isArray(customConfig[key])
190
- ) {
191
- // 创建一个以 name 为 key 的 Map,优先使用 customConfig 中的 action
192
- const actionsMap = new Map();
193
- // 先添加 defaultConfig 中的 actions
194
- defaultConfig[key].forEach((action: any) => {
195
- if (action.name) {
196
- actionsMap.set(action.name, action);
197
- }
198
- });
199
- // 然后用 customConfig 中的 actions 覆盖或添加
200
- customConfig[key].forEach((action: any) => {
201
- if (action.name) {
202
- actionsMap.set(action.name, action);
203
- }
204
- });
205
- result[key] = Array.from(actionsMap.values());
206
- } else if (
207
- typeof defaultConfig[key] === 'object' &&
208
- defaultConfig[key] !== null &&
209
- !Array.isArray(defaultConfig[key]) &&
210
- typeof customConfig[key] === 'object' &&
211
- customConfig[key] !== null &&
212
- !Array.isArray(customConfig[key])
213
- ) {
214
- result[key] = deepMerge(defaultConfig[key], customConfig[key]);
215
- } else {
216
- result[key] = customConfig[key];
217
- }
218
- }
219
- }
220
- return result;
221
- }
222
-
223
- // 发送器配置支持外部传入,merge 默认和外部;按 locale 设置开关/按钮文案
224
- const gientechMessages = useMemo(() => getGientechChatMessages(locale), [locale]);
225
-
226
- const buildSenderConfigWithLocale = useMemo(() => {
227
- const msgs = gientechMessages;
228
- const baseWithLabels = {
229
- ...DefaultSenderConfig,
230
- switchs: (DefaultSenderConfig.switchs ?? []).map((sw: any) => ({
231
- ...sw,
232
- label: sw.name === 'netSearch' ? msgs.sender.netSearch : msgs.sender.deepThinking,
233
- })),
234
- actions: (DefaultSenderConfig.actions ?? []).map((ac: any) => ({
235
- ...ac,
236
- tip: ac.name === 'upload' ? msgs.sender.fileUpload : ac.tip,
237
- })),
238
- };
239
- return baseWithLabels;
240
- }, [locale, gientechMessages]);
241
-
242
- const [dynamicSenderConfig, setDynamicSenderConfig] = useState(() =>
243
- deepMerge(buildSenderConfigWithLocale, rest.senderConfig)
244
- );
245
-
246
- // 监听 locale / 外部 senderConfig 变化自动 merge(保留 badge 等运行时状态)
247
- useEffect(() => {
248
- const msgs = gientechMessages;
249
- const base = {
250
- ...DefaultSenderConfig,
251
- switchs: (DefaultSenderConfig.switchs ?? []).map((sw: any) => ({
252
- ...sw,
253
- label: sw.name === 'netSearch' ? msgs.sender.netSearch : msgs.sender.deepThinking,
254
- })),
255
- actions: (DefaultSenderConfig.actions ?? []).map((ac: any) => ({
256
- ...ac,
257
- tip: ac.name === 'upload' ? msgs.sender.fileUpload : ac.tip,
258
- })),
259
- };
260
- setDynamicSenderConfig((prev: any) => {
261
- const next = deepMerge(base, rest.senderConfig);
262
- if (Array.isArray(prev.actions) && Array.isArray(next.actions)) {
263
- next.actions = next.actions.map((a: any, i: number) => {
264
- const p = prev.actions?.[i];
265
- if (p && p.name === a.name && p.badgeCount !== undefined)
266
- return { ...a, badgeCount: p.badgeCount };
267
- return a;
268
- });
269
- }
270
- return next;
271
- });
272
- }, [locale, rest.senderConfig, gientechMessages]);
273
- // 使用统一的文件管理 Hook
274
- const {
275
- fileStatuses,
276
- setFileStatuses,
277
- pollFileStatus: pollFileStatusHook,
278
- handleRemoveFromTemp,
279
- resetStopFlag,
280
- setStopFlag,
281
- stoppedRef,
282
- getTempFileList,
283
- setFileManagerData,
284
- fileManagerData,
285
- } = useFileManager({
286
- url,
287
- token,
288
- CSRFToken,
289
- activeSessionId,
290
- chatData,
291
- });
292
-
293
- // 新增:全局管理助手选中状态,彻底解决子组件重建跳回默认
294
- const [selectedAssistantId, setSelectedAssistantId] = React.useState(() => {
295
- if (!assistantList || assistantList.length === 0) return undefined;
296
- const defaultItem = assistantList.find(item => item.isDefault);
297
- return defaultItem ? defaultItem.id : assistantList[0]?.id;
298
- });
299
-
300
- // 监听 assistantList 变化,自动选中默认助手
301
- React.useEffect(() => {
302
- if (!assistantList || assistantList.length === 0) return;
303
- const exists = assistantList.some(item => item.id === selectedAssistantId);
304
- if (!selectedAssistantId || !exists) {
305
- const defaultItem = assistantList.find(item => item.isDefault);
306
- setSelectedAssistantId(defaultItem ? defaultItem.id : assistantList[0].id);
307
- }
308
- }, [assistantList]);
309
-
310
- // 新增:记录 sender switchs 的选中状态
311
- const [senderSwitchValues, setSenderSwitchValues] = useState<{ [key: string]: boolean }>({});
312
-
313
- // =================================================================
314
- // Refs - 引用
315
- // =================================================================
316
- const prevActiveSessionId = useRef<string | undefined>(undefined); // 记录上一个激活的对话ID,用于对比变化
317
- const setUploadedFilesRef = useRef<(files: any[]) => void>(undefined); // 引用核心组件的文件上传方法
318
- const removeFileRef = useRef<(fileObj: any, idx: number, _type: string) => void>(undefined); // 引用核心组件的文件移除方法
319
- const fileInputRef = useRef<HTMLInputElement>(null); // 文件上传input引用
320
- const senderConfigRef = useRef<SenderConfig | undefined>(undefined); // 引用核心组件的上传限制配置
321
- const uploadedFilesRef = useRef<any[]>([]); // 引用核心组件的已上传文件列表
322
- const [pendingFiles, setPendingFiles] = useState<any[]>([]);
323
- const [feedParam, setFeedParam] = useState<{
324
- queryId?: number | string | undefined;
325
- restult?: number;
326
- }>({});
327
- const [openFeed, setOpenFeed] = useState(false);
328
- const [feedBackList, setFeedBackList] = useState<any>([]);
329
- const [fileManagerOpen, setFileManagerOpen] = useState(false);
330
-
331
- const {
332
- api_startChat_re,
333
- addEmptyMessage,
334
- setLastEmptyMessage,
335
- stopStream,
336
- cancelStreamBySessionId,
337
- } = AichatUseController({
338
- baseUrl: url,
339
- CSRFToken: CSRFToken,
340
- token,
341
- setChatData,
342
- activeSessionId,
343
- setAppStatus,
344
- setConversationList,
345
- });
346
-
347
- // =================================================================
348
- // Memoized Values - 缓存计算值
349
- // =================================================================
350
-
351
- /**
352
- * 将智能体列表转换为以ID为键的Map,便于快速查找
353
- */
354
- const assistantMap = useMemo(() => {
355
- const map: Record<string, any> = {};
356
- (assistantList || []).forEach(item => {
357
- map[item.id] = item;
358
- });
359
- return map;
360
- }, [assistantList]);
361
-
362
- /**
363
- * 根据 activeSessionId 从 chatData 中筛选出当前对话的数据, 并合并智能体信息
364
- */
365
- const currentChatData = useMemo(() => {
366
- const data = chatData.find((c: any) => c.id === activeSessionId) || {
367
- id: activeSessionId,
368
- messages: [],
369
- };
370
- const assistantInfo = data.configId ? assistantMap[data.configId] : null;
371
- return {
372
- ...data,
373
- assistantInfo,
374
- };
375
- }, [chatData, activeSessionId, assistantMap]);
376
- useEffect(() => {
377
- console.log('currentChatData', currentChatData);
378
- }, [currentChatData]);
379
- const is_download = useMemo(() => {
380
- if (currentChatData.configId && assistantMap) {
381
- const curAssist = assistantMap[currentChatData.configId];
382
- if (curAssist?.configJson) {
383
- const config = JSON.parse(curAssist.configJson);
384
- return config.is_download;
385
- }
386
- return false;
387
- } else {
388
- return false;
389
- }
390
- }, [currentChatData.configId, assistantMap]);
391
-
392
- const is_enableThinking = useMemo(() => {
393
- //console.log('is_enableThinking',currentChatData.configId,assistantMap,newAssistantId)
394
- if ((currentChatData.configId || newAssistantId) && assistantMap) {
395
- const curAssist = assistantMap[currentChatData.configId];
396
- if (curAssist?.configJson) {
397
- const config = JSON.parse(curAssist.configJson);
398
- console.log('is_enableThinking', currentChatData.configId, assistantMap, newAssistantId);
399
- return config.thinking ? true : false;
400
- } else {
401
- // const curAssist = assistantMap[newAssistantId]
402
- //console.log('newAssistantId',newAssistantId)
403
- if (newAssistantId) {
404
- const curAssist = assistantMap[newAssistantId];
405
- if (curAssist?.configJson) {
406
- const config = JSON.parse(curAssist.configJson);
407
- return config.thinking ? true : false;
408
- }
409
- }
410
- }
411
- }
412
- return false;
413
- }, [currentChatData.configId, assistantMap, newAssistantId]);
414
-
415
- // 文件工具函数已提取到 useFileManager hook 中
416
-
417
- // =================================================================
418
- // Side Effects (useEffect) - 副作用钩子
419
- // =================================================================
420
-
421
- /**
422
- * 跟踪 activeSessionId 的变化:
423
- * 1. 清理上一个无消息的临时会话
424
- * 2. 更新推荐问题
425
- */
426
- useEffect(() => {
427
- // 切换会话时,检查上一个会话是否为临时且无消息
428
- if (prevActiveSessionId.current && prevActiveSessionId.current !== activeSessionId) {
429
- const prevId = prevActiveSessionId.current;
430
- const prevConv = conversationList.find(c => c.sessionId === prevId && c.isNew);
431
- const prevChat = chatData.find(c => c.id === prevId && c.isNew);
432
- const prevHasMsg = prevChat && prevChat.messages && prevChat.messages.length > 0;
433
- // 如果是临时的且没有消息,则自动删除
434
- if (prevConv && !prevHasMsg) {
435
- setConversationList(list => list.filter(c => c.sessionId !== prevId));
436
- setChatData(list => list.filter(c => c.id !== prevId));
437
- }
438
- }
439
- prevActiveSessionId.current = activeSessionId;
440
-
441
- // 更新推荐问题为当前对话的最后一个推荐问题
442
- const historyRQ =
443
- currentChatData.messages && currentChatData.messages.length > 0
444
- ? currentChatData.messages[currentChatData.messages.length - 1].recommendQuestion
445
- : [];
446
- setRecommandQuestions(historyRQ);
447
- }, [activeSessionId, conversationList, chatData, currentChatData.messages]);
448
-
449
- /**
450
- * 拉取会话列表分页
451
- */
452
- const fetchConversationPage = async (pageNo: number) => {
453
- if (convLoading) return;
454
- setConvLoading(true);
455
- try {
456
- const res = await axios.get(
457
- `${url}/qa/dialogue/list?pageNo=${pageNo}&pageSize=${convPageSize}&sysType=INT_SESSION`,
458
- { headers: { Authorization: token } }
459
- );
460
- const records = res?.data?.data?.records || [];
461
- const total = res?.data?.data?.total || 0;
462
- setConvTotal(total);
463
- setConversationList(prev => {
464
- // 去重合并(以 sessionId 为准)
465
- const map = new Map<string, any>();
466
- [...prev, ...records].forEach((it: any) => {
467
- map.set(it.sessionId, it);
468
- });
469
- return Array.from(map.values());
470
- });
471
- setConvPageNo(pageNo);
472
- } catch (_) {
473
- // 忽略,错误态交由上层处理
474
- } finally {
475
- setConvLoading(false);
476
- }
477
- };
478
-
479
- /**
480
- * 首次加载:并发拉取助手列表与会话第一页
481
- */
482
- useEffect(() => {
483
- setAppStatus(prev => ({ ...prev, app: 'initializing' }));
484
- // 助手列表
485
- axios
486
- .get(`${url}/qa/search/config/helper/list?pageNo=1&pageSize=3000`, {
487
- headers: { Authorization: token },
488
- })
489
- .then(assistantRes => {
490
- setAssistantList(assistantRes.data.data || []);
491
- })
492
- .catch(() => {});
493
-
494
- // 会话第一页
495
- fetchConversationPage(1)
496
- .then(() => {
497
- if (!activeSessionId) {
498
- handleConversationCreate({});
499
- }
500
- setAppStatus(prev => ({ ...prev, app: 'ready' }));
501
- })
502
- .catch(() => {
503
- setAppStatus(prev => ({ ...prev, app: 'error' }));
504
- });
505
- }, []);
506
-
507
- /**
508
- * 当 activeSessionId 变化时,获取对应的聊天记录
509
- */
510
- useEffect(() => {
511
- if (!activeSessionId) return;
512
-
513
- setAppStatus(prev => ({ ...prev, display: 'loading' }));
514
- getTempFileList(activeSessionId);
515
- axios
516
- .get(`${url}/qa/dialogue/getDialogBySessionId?sessionId=${activeSessionId}`, {
517
- headers: { Authorization: token },
518
- })
519
- .then(res => {
520
- if (!res.data.data) {
521
- setAppStatus(prev => ({ ...prev, display: 'ready' }));
522
- return;
523
- }
524
- // 解析消息数据
525
- const queryReplyPairList = res.data.data?.queryReplyPairList || [];
526
- const messages = convertQueryReplyPairListToMessages(queryReplyPairList);
527
- const {
528
- sessionId,
529
- searchConfigDTO,
530
- filePath,
531
- configId,
532
- reference,
533
- webReference,
534
- uploadedFiles,
535
- fileList,
536
- currentFiles,
537
- } = res.data.data;
538
-
539
- // === 文件数据补全 ===
540
- // 1. reference(AI消息)
541
- if (messages.length > 0) {
542
- // 找到最后一条 AI 消息的索引(从后往前找)
543
- const lastAiIndex =
544
- messages.length - 1 - [...messages].reverse().findIndex(m => m.istype === 'ai');
545
-
546
- // 确保找到的是有效的 AI 消息
547
- if (
548
- lastAiIndex >= 0 &&
549
- lastAiIndex < messages.length &&
550
- messages[lastAiIndex].istype === 'ai'
551
- ) {
552
- if (reference) {
553
- messages[lastAiIndex].reference = reference;
554
- }
555
- if (webReference) {
556
- messages[lastAiIndex].webReference = webReference;
557
- }
558
- }
559
- }
560
- // 2. currentFiles/fileList/uploadedFiles(user消息)
561
- const filesData = currentFiles || fileList || uploadedFiles;
562
- if (filesData && messages.length > 0) {
563
- const lastUserIdx = [...messages].reverse().findIndex(m => m.istype === 'user');
564
- if (lastUserIdx !== -1) {
565
- console.log(messages[messages.length - 1 - lastUserIdx].currentFiles, 'filesData');
566
- messages[messages.length - 1 - lastUserIdx].currentFiles = filesData;
567
- }
568
- }
569
-
570
- // 更新对话列表中的对应项的元数据
571
- const item = conversationList.find(item => item.sessionId === sessionId);
572
- if (item) {
573
- // console.log(item,'你大爷')
574
- setConversationList(list =>
575
- list.map(item =>
576
- item.sessionId === sessionId
577
- ? { ...item, searchConfigDTO, filePath, configId }
578
- : item
579
- )
580
- );
581
- }
582
-
583
- // 构造当前对话的完整数据
584
- const conversationConfig = {
585
- configId: res.data.data.configId,
586
- filePath: res.data.data.filePath,
587
- searchConfigDTO: res.data.data.searchConfigDTO || {},
588
- sessionId: res.data.data.sessionId,
589
- label: res.data.data.label,
590
- kbId: res.data.data.kbId,
591
- };
592
-
593
- // 更新聊天数据
594
- setChatData(prev => {
595
- const others = prev.filter((c: any) => c.id !== activeSessionId);
596
-
597
- const newChatData = [
598
- { id: activeSessionId, messages, ...conversationConfig },
599
- ...others,
600
- ];
601
- return newChatData;
602
- });
603
- setAppStatus(prev => ({ ...prev, display: 'ready' }));
604
- })
605
- .catch(err => {
606
- console.error('获取聊天数据失败:', err);
607
- if (err.response && err.response.status === 404) {
608
- // 404 表示会话在后端不存在,按新建会话处理
609
- handleConversationCreate({});
610
- }
611
- setAppStatus(prev => ({ ...prev, display: 'error' }));
612
- });
613
- }, [activeSessionId, url, token]);
614
-
615
- /**
616
- * 监听文件数据变化,更新Sender上的角标
617
- */
618
- useEffect(() => {
619
- const totalFiles = fileManagerData.uploadedFiles.length;
620
- setDynamicSenderConfig((prev: any) => {
621
- const actions = Array.isArray(prev.actions) ? prev.actions : [];
622
- const newConfig = {
623
- ...prev,
624
- actions: actions.map((action: any) =>
625
- action.name === 'history' ? { ...action, badgeCount: totalFiles } : action
626
- ),
627
- };
628
- return newConfig;
629
- });
630
- }, [fileManagerData.uploadedFiles]);
631
- useEffect(() => {
632
- getFeedbackList({ url, token }, data => {
633
- setFeedBackList(data);
634
- });
635
- }, []);
636
-
637
- /**
638
- * 实时同步 fileStatuses 到当前消息的 currentFiles,便于消息区细致显示每个文件的处理状态
639
- */
640
- React.useEffect(() => {
641
- if (!fileStatuses.length) return;
642
- setChatData(chatList => {
643
- if (!chatList[0]) return chatList;
644
- const { messages } = chatList[0];
645
- for (let i = messages.length - 1; i >= 0; i--) {
646
- if (messages[i].istype === 'user') {
647
- const oldFiles = messages[i].currentFiles || [];
648
- messages[i].currentFiles = fileStatuses.map((f: any) => {
649
- const old = oldFiles.find((of: any) => of.uid === f.uid);
650
- return {
651
- name: f.file?.name || f.name,
652
- size: f.file?.size || f.size,
653
- type: f.file?.type || f.type,
654
- status: f.status,
655
- uid: f.uid,
656
- url: f.url || old?.url || '', // 优先用已有 url
657
- };
658
- });
659
- break;
660
- }
661
- }
662
- return [...chatList];
663
- });
664
- }, [fileStatuses]);
665
-
666
- // =================================================================
667
- // Core Functions - 核心功能函数
668
- // =================================================================
669
-
670
- // 1. 在组件作用域定义控制器和轮询停止标志
671
- let uploadController: AbortController | null = null;
672
- let stopPoll: (() => void) | null = null;
673
-
674
- /**
675
- * 轮询文件解析状态(使用统一的 hook)
676
- */
677
- const pollFileStatus = (
678
- uids: string[],
679
- onStatusUpdate: (serverStatuses: any[]) => void,
680
- onComplete: () => void,
681
- onFail: (errorMsg: string) => void
682
- ) => {
683
- stopPoll = pollFileStatusHook(uids, {
684
- onStatusUpdate,
685
- onComplete,
686
- onFail,
687
- });
688
- };
689
-
690
- /**
691
- * 设置消息的反馈结果(赞/踩)
692
- * @param {string} queryId - 消息ID
693
- * @param {number} result - 反馈结果 (1: 赞, -1: 踩)
694
- */
695
- const setFeed = (queryId: any, restult: any) => {
696
- setChatData(chatList => {
697
- const newList = [...chatList];
698
- if (!newList[0]) return newList;
699
- newList[0] = {
700
- ...newList[0],
701
- messages: newList[0].messages.map((item: any) => {
702
- if (item.queryId === queryId) {
703
- return {
704
- ...item,
705
- feedbackResult: restult,
706
- };
707
- }
708
- return item;
709
- }),
710
- };
711
- return newList;
712
- });
713
- };
714
-
715
- /**
716
- * 获取指定queryId的推荐问题
717
- * @param {string} queryId - 消息ID
718
- */
719
- const fetchRecommendQuestions = async (queryId: string) => {
720
- if (!queryId) return;
721
- try {
722
- // 需要携带当前 configId
723
- const configId =
724
- currentChatData?.configId || assistantMap?.[currentChatData?.configId || '']?.id || '';
725
- const res = await axios.get(
726
- `${url}/qa/ai/recommendQuestion?queryId=${queryId}&configId=${configId || ''}`.replace(
727
- /\?&/,
728
- '?'
729
- ),
730
- {
731
- headers: { Authorization: token },
732
- }
733
- );
734
- setRecommandQuestions(res.data?.data || []);
735
- } catch (e) {
736
- setRecommandQuestions([]);
737
- }
738
- };
739
-
740
- /**
741
- * 处理重新发送消息逻辑
742
- */
743
- function handleReSenderSend(data: any) {
744
- const { content, audioUrl, filePaths, queryId } = data;
745
- if (!activeSessionId || !queryId) return;
746
-
747
- // 从当前会话中按 queryId 定位本次 AI 回复
748
- const msgs = currentChatData?.messages || [];
749
- const aiIdx = msgs.findIndex(
750
- (m: any) => m?.queryId === queryId && (m?.istype === 'ai' || m?.isUser === false)
751
- );
752
-
753
- // 回溯上一条用户消息
754
- let userMsg: any | undefined;
755
- if (aiIdx > 0) {
756
- for (let i = aiIdx - 1; i >= 0; i -= 1) {
757
- const m = msgs[i];
758
- if (m?.istype === 'user' || m?.isUser === true) {
759
- userMsg = m;
760
- break;
761
- }
762
- }
763
- }
764
-
765
- const question = userMsg?.content ?? content;
766
- if (!question) return;
767
-
768
- const sourceFilePaths = userMsg?.filePaths ?? filePaths;
769
- const _fileUids = (
770
- typeof sourceFilePaths === 'string' && sourceFilePaths
771
- ? JSON.parse(sourceFilePaths)
772
- : sourceFilePaths || []
773
- ).map((item: any) => item.uid);
774
- const now = Date.now();
775
- setLastEmptyMessage({ now });
776
- setAppStatus(pre => {
777
- return {
778
- ...pre,
779
- display: 'processing',
780
- sender: 'processing',
781
- };
782
- });
783
-
784
- // 清除上一条AI消息的引用数据,避免重复显示(保留正文内容)
785
- if (aiIdx >= 0 && msgs[aiIdx]) {
786
- setChatData((chatList: any[]) => {
787
- if (!chatList[0]) return chatList;
788
- const current = chatList[0];
789
- const messages = current.messages || [];
790
- if (aiIdx >= messages.length) return chatList;
791
-
792
- const newMessages = messages.slice();
793
- // 清除引用数据(知识库 / 网络 / 图谱 / 数据库 / 思维链),但保留上一条 AI 的正文内容,
794
- // 保持 status 为 Done,这样 reset_chat 中的 isRestart 检测能正确工作
795
- newMessages[aiIdx] = {
796
- ...newMessages[aiIdx],
797
- // 不再清空 content,避免上一条回答在新问题发送时被“抹掉”
798
- content: newMessages[aiIdx].content,
799
- reference: '[]', // 清空知识库引用
800
- webReference: '[]', // 清空网络引用
801
- graphReference: null, // 清空图谱引用
802
- databaseReference: null, // 清空数据库引用
803
- status: 2, // 保持为 Done 状态,这样当流式数据第一次返回时,isRestart 检测能正确工作
804
- chain: undefined, // 清空思维链数据
805
- };
806
-
807
- const newChat0 = { ...current, messages: newMessages };
808
- return [newChat0, ...chatList.slice(1)];
809
- });
810
- }
811
-
812
- data.clearFn && data.clearFn();
813
- setConversationList(list =>
814
- list.map(c => (c.sessionId === activeSessionId ? { ...c, gmtModified: now } : c))
815
- );
816
-
817
- api_startChat_re(
818
- {
819
- configId: currentChatData.configId,
820
- content: question,
821
- fileUids: _fileUids,
822
- lastDate: now,
823
- name: currentChatData.label || '',
824
- queryId: queryId,
825
- sessionId: String(activeSessionId || ''),
826
- type: (userMsg?.audioUrl ?? audioUrl) ? 'audioUrl' : 'text',
827
- audioUrl: (userMsg?.audioUrl ?? audioUrl) || '',
828
- enableThinking: !!senderSwitchValues.reasoning,
829
- enableWebsearch: !!senderSwitchValues.netSearch,
830
- qaChannel: senderSwitchValues.qaChannel,
831
- tempKnowledgeBaseCheck: tempKnowledgeBaseCheck.current,
832
- } as any,
833
- gmtModified => {
834
- // 只在AI回复完成后请求推荐问题
835
- fetchRecommendQuestions(queryId);
836
- }
837
- );
838
- }
839
-
840
- // 提取发消息逻辑,确保只有有sessionId时才调用
841
- async function handleSenderSend(data: any, clearFn: () => void) {
842
- // 如果发送器当前不在 ready 状态(如 loading / processing / uploading),禁止再次发送
843
- if (appStatus.sender !== 'ready') {
844
- message.warning('当前对话正在处理中,请稍候再发送新的问题');
845
- return;
846
- }
847
- // 找到当前会话
848
- if (!activeSessionId) return;
849
- const openEvent = new CustomEvent('aichat:right_set', {
850
- detail: { collapsed: true },
851
- });
852
- window.dispatchEvent(openEvent);
853
- const conv = conversationList.find(c => c.sessionId === activeSessionId);
854
- //console.log('zheli是啥',conv)
855
- if (conv && conv.isNew) {
856
- // 还没落库,先调 create
857
- let createSuccess = false;
858
- // 优先用用户选择的助手newAssistantId,否则用当前会话的configId
859
- const configIdToUse = newAssistantId || conv.configId;
860
- // 用用户输入内容截取20字作为label
861
- const labelToUse =
862
- data && data.content ? data.content.slice(0, 20) : conv.label || '未命名会话';
863
- await new Promise<void>((resolve, reject) => {
864
- handleCreateConversation(
865
- { url, token, CSRFToken },
866
- {
867
- label: labelToUse,
868
- sessionId: conv.sessionId,
869
- sysType: 'INT_SESSION',
870
- configId: configIdToUse,
871
- },
872
- (res: any) => {
873
- if (res && res.data && res.data.sessionId) {
874
- // create成功,标记已落库并更新label/configId
875
- setConversationList(list =>
876
- list.map(c =>
877
- c.sessionId === conv.sessionId
878
- ? { ...c, isNew: false, configId: configIdToUse, label: labelToUse }
879
- : c
880
- )
881
- );
882
- setChatData(list =>
883
- list.map(c =>
884
- c.id === conv.sessionId
885
- ? { ...c, isNew: false, configId: configIdToUse, label: labelToUse }
886
- : c
887
- )
888
- );
889
- createSuccess = true;
890
- resolve();
891
- } else {
892
- message.error('创建会话失败,请重试');
893
- reject();
894
- }
895
- }
896
- );
897
- });
898
- if (!createSuccess) return;
899
- // 继续发消息
900
- sendMessageWithSessionId(activeSessionId as string, data, clearFn, configIdToUse);
901
- return;
902
- }
903
- // 已落库,直接发消息
904
- sendMessageWithSessionId(activeSessionId as string, data, clearFn);
905
- }
906
-
907
- // 修改sendMessageWithSessionId,发消息时用本地会话的configId
908
- function sendMessageWithSessionId(
909
- sessionId: string,
910
- data: any,
911
- clearFn: () => void,
912
- configIdOverride?: string
913
- ) {
914
- const queryId = 'query-' + uid(32);
915
- // 优先用参数传递的 configId
916
- const conv = conversationList.find(c => c.sessionId === sessionId);
917
- const configIdToUse = configIdOverride || conv?.configId || currentChatData.configId;
918
- console.log('助手配置详情', configIdToUse);
919
-
920
- // === 数据流保障:明确保留内容格式,不进行任何 trim 或替换处理 ===
921
- // 确保换行符、空格等格式完整保留,直接传递到后端
922
- const rawContent = data.content || data.text || '';
923
- const preservedContent = typeof rawContent === 'string' ? rawContent : String(rawContent);
924
-
925
- const label = preservedContent ? preservedContent.slice(0, 20) : '未命名会话';
926
- let localCurrentFiles = undefined;
927
- if (data.files && data.files.length > 0) {
928
- localCurrentFiles = data.files.map((fileItem: any) => ({
929
- name: fileItem.file.name,
930
- size: fileItem.file.size,
931
- type: fileItem.file.type,
932
- filePath: fileItem.filePath || '',
933
- convertedFilePath: fileItem.convertedFilePath || '',
934
- uid: fileItem.uid || '',
935
- }));
936
- }
937
- console.log('本地文件上传', data.files);
938
- addEmptyMessage({
939
- content: preservedContent, // 使用保留格式的内容,确保换行和空格完整保留
940
- queryId,
941
- currentFiles: localCurrentFiles,
942
- filePaths: localCurrentFiles ? JSON.stringify(localCurrentFiles) : undefined,
943
- });
944
- // === 新增:如果当前会话是未命名且isNew,首次提问后自动改名并去除isNew ===
945
- setConversationList(list =>
946
- list.map(c =>
947
- c.sessionId === sessionId && c.label === '未命名会话' && c.isNew
948
- ? { ...c, label, gmtModified: Date.now(), isNew: false }
949
- : c
950
- )
951
- );
952
- setChatData(list =>
953
- list.map(c =>
954
- c.id === sessionId && c.label === '未命名会话' && c.isNew
955
- ? { ...c, label, isNew: false }
956
- : c
957
- )
958
- );
959
- // 2. 文件上传逻辑 ---
960
- if (data.files && data.files.length > 0) {
961
- setAppStatus(pre => ({ ...pre, sender: 'uploading', display: 'uploading' }));
962
- uploadController = new AbortController();
963
- resetStopFlag(); // 使用 hook 提供的重置函数
964
- const clientFileUids = data.files.map(
965
- () => `rc-upload-${Date.now()}-${Math.random().toString(36).slice(2)}`
966
- );
967
- const initialFileStatuses = data.files.map((fileItem: any, index: number) => ({
968
- ...fileItem,
969
- uid: clientFileUids[index],
970
- status: 'uploading',
971
- }));
972
- setFileStatuses(initialFileStatuses);
973
- const formData = new FormData();
974
- data.files.forEach((fileItem: any) => {
975
- formData.append('files', fileItem.file);
976
- });
977
- const sessionIdStr = String(sessionId || '');
978
- formData.append('sessionId', sessionIdStr);
979
- formData.append('uids', clientFileUids.join(','));
980
- axios
981
- .post(`${url}/index/knowledgeBase/file/uploadFiles`, formData, {
982
- headers: {
983
- Authorization: token,
984
- 'Content-Type': 'multipart/form-data',
985
- },
986
- signal: uploadController.signal,
987
- })
988
- .then(response => {
989
- console.log('文件上传的打印结果', response);
990
- console.log('文件上传响应详情:', {
991
- status: response.status,
992
- success: response.data?.success,
993
- dataType: Array.isArray(response.data?.data) ? 'array' : typeof response.data?.data,
994
- dataLength: Array.isArray(response.data?.data) ? response.data.data.length : 'N/A',
995
- errorMsg: response.data?.errorMsg,
996
- errorCode: response.data?.errorCode,
997
- fullResponse: response.data,
998
- });
999
-
1000
- if (stoppedRef.current) return;
1001
-
1002
- // 检查响应数据结构 - 严格按照 headlessChat 的逻辑:必须有有效数据才继续
1003
- const responseData = response.data?.data;
1004
- const isSuccess = response.data?.success === true;
1005
- const isValidData = Array.isArray(responseData) && responseData.length > 0;
1006
-
1007
- if (isSuccess && isValidData) {
1008
- // 后端返回了有效数据,使用后端数据
1009
- const uploadedFilesData = responseData;
1010
- const serverUids = uploadedFilesData.map((f: any) => f.uid);
1011
-
1012
- // === 合并后端返回字段到 fileStatuses ===
1013
- setFileStatuses(prev => {
1014
- return prev.map(localFile => {
1015
- const serverFile = responseData.find((f: any) => f.uid === localFile.uid);
1016
- return serverFile ? { ...localFile, ...serverFile } : localFile;
1017
- });
1018
- });
1019
-
1020
- setAppStatus(pre => ({ ...pre, sender: 'processing', display: 'analyzing' }));
1021
- setFileStatuses(prev => prev.map(f => ({ ...f, status: 'parsing' })));
1022
-
1023
- pollFileStatus(
1024
- serverUids,
1025
- (serverStatuses: any[]) => {
1026
- // 添加空值检查,防止 serverStatuses 为 null 或 undefined
1027
- if (!serverStatuses || !Array.isArray(serverStatuses)) {
1028
- console.warn('pollFileStatus 回调返回的 serverStatuses 无效:', serverStatuses);
1029
- return;
1030
- }
1031
-
1032
- setFileStatuses(currentLocalStatuses => {
1033
- return currentLocalStatuses.map(localFile => {
1034
- const correspondingServerFile = serverStatuses.find(
1035
- (sf: any) => sf && sf.uid === localFile.uid
1036
- );
1037
- if (correspondingServerFile) {
1038
- // 使用 fileParseStatus 判断文件解析状态:1:正常 2:解析中 3:解析成功 4:解析失败
1039
- // 兼容旧数据,优先使用 fileParseStatus,如果没有则使用 status
1040
- const parseStatus =
1041
- correspondingServerFile.fileParseStatus ?? correspondingServerFile.status;
1042
- switch (parseStatus) {
1043
- case 3:
1044
- return { ...localFile, status: 'done' };
1045
- case 4:
1046
- return { ...localFile, status: 'error' };
1047
- case 1:
1048
- case 2:
1049
- default:
1050
- return { ...localFile, status: 'parsing' };
1051
- }
1052
- }
1053
- return localFile;
1054
- });
1055
- });
1056
- // === 新增:全部完成时清空 sender 区 ===
1057
- // 使用 fileParseStatus 判断:所有文件解析成功(3)或解析失败(4)时停止轮询
1058
- const allDone =
1059
- Array.isArray(serverStatuses) &&
1060
- serverStatuses.length > 0 &&
1061
- serverStatuses.every((file: any) => {
1062
- if (!file) return false;
1063
- const parseStatus = file.fileParseStatus ?? file.status;
1064
- return parseStatus === 3 || parseStatus === 4; // 3:解析成功 4:解析失败
1065
- });
1066
- if (allDone) {
1067
- setFileStatuses([]);
1068
- // 上传完成后合并新文件到 uploadedFiles,保证结构统一
1069
- const map = new Map();
1070
- (serverStatuses || []).forEach((item: any) => {
1071
- map.set(item.id, item);
1072
- });
1073
- setFileManagerData(prev => {
1074
- const r = mergeFiles(prev.uploadedFiles, uploadedFilesData);
1075
-
1076
- return {
1077
- uploadedFiles: r.map(item => {
1078
- return {
1079
- ...item,
1080
- pdfPages: map.get(item.id)?.pdfPages || 0, // 保留后端返回的 pdfPages 字段
1081
- };
1082
- }),
1083
- };
1084
- });
1085
- }
1086
- },
1087
- // onComplete: 全部解析成功后才发起AI请求
1088
- () => {
1089
- clearFn?.();
1090
- setAppStatus(pre => ({ ...pre, sender: 'processing', display: 'processing' }));
1091
- // === 新增:回填 filePath 到 fileStatuses ===
1092
- setFileStatuses(prev => {
1093
- return prev.map(localFile => {
1094
- const serverFile = uploadedFilesData.find(
1095
- (f: any) => f.uid === localFile.uid
1096
- );
1097
-
1098
- if (serverFile) {
1099
- return {
1100
- ...localFile,
1101
- ...serverFile, // 合并后端所有字段
1102
- url: serverFile.filePath, // 兼容 url 字段
1103
- filePath: serverFile.filePath,
1104
- name: serverFile.fileName || localFile.name,
1105
- convertedFilePath:
1106
- serverFile.convertedFilePath || localFile.convertedFilePath,
1107
- };
1108
- }
1109
- return localFile;
1110
- });
1111
- });
1112
- // === 同步 currentFiles 字段到 chatData ===
1113
- setChatData(chatList => {
1114
- if (!chatList[0]) return chatList;
1115
- const { messages } = chatList[0];
1116
- for (let i = messages.length - 1; i >= 0; i--) {
1117
- if (messages[i].istype === 'user') {
1118
- const oldFiles = messages[i].currentFiles || [];
1119
- messages[i].currentFiles = oldFiles.map((localFile: any) => {
1120
- const serverFile = uploadedFilesData.find(
1121
- (f: any) => f.uid === localFile.uid
1122
- );
1123
- return serverFile ? { ...localFile, ...serverFile } : localFile;
1124
- });
1125
- break;
1126
- }
1127
- }
1128
- return [...chatList];
1129
- });
1130
- // === 发起AI请求 ===
1131
- const now = Date.now();
1132
- api_startChat_re(
1133
- {
1134
- configId: configIdToUse,
1135
- content: preservedContent, // 使用保留格式的内容,确保换行和空格完整传递到后端
1136
- fileUids: serverUids,
1137
- lastDate: now,
1138
- name: label,
1139
- queryId: queryId,
1140
- sessionId: String(sessionId || ''),
1141
- type: 'text',
1142
- audioUrl: '',
1143
- enableThinking: !!senderSwitchValues.reasoning,
1144
- enableWebsearch: !!senderSwitchValues.netSearch,
1145
- qaChannel: senderSwitchValues.qaChannel,
1146
- tempKnowledgeBaseCheck: tempKnowledgeBaseCheck.current,
1147
- } as any,
1148
- gmtModified => {
1149
- fetchRecommendQuestions(queryId);
1150
- }
1151
- );
1152
- },
1153
- (errorMsg: string) => {
1154
- setAppStatus(pre => ({ ...pre, display: 'ready', sender: 'ready' }));
1155
- setFileStatuses(prev =>
1156
- prev.map(f => ({ ...f, status: 'error', message: errorMsg }))
1157
- );
1158
- }
1159
- );
1160
- } else {
1161
- // 详细的错误信息
1162
- let errorMsg = '文件上传失败';
1163
- if (response.data?.errorMsg) {
1164
- errorMsg = response.data.errorMsg;
1165
- } else if (!isSuccess) {
1166
- errorMsg = `上传失败: success=${response.data?.success}`;
1167
- } else if (!isValidData) {
1168
- if (!Array.isArray(responseData)) {
1169
- errorMsg = `上传失败: 返回数据格式错误,期望数组,实际为 ${typeof responseData}`;
1170
- } else if (responseData.length === 0) {
1171
- errorMsg = '上传失败: 返回数据为空';
1172
- }
1173
- }
1174
-
1175
- console.error('文件上传失败详情:', {
1176
- errorMsg,
1177
- response: response.data,
1178
- isSuccess,
1179
- isValidData,
1180
- });
1181
-
1182
- message.error(errorMsg);
1183
- setAppStatus(pre => ({ ...pre, display: 'error', sender: 'ready' }));
1184
- setFileStatuses(prev =>
1185
- prev.map(f => ({ ...f, status: 'error', message: errorMsg }))
1186
- );
1187
- }
1188
- })
1189
- .catch(error => {
1190
- // 检查是否为文件大小超限错误 (413)
1191
- if (error?.response?.status === 413) {
1192
- if (error?.response?.statusText.includes('Request Entity Too Large')) {
1193
- message.error('文件超过最大可上传限制');
1194
- }
1195
- } else {
1196
- // 其他错误显示通用网络错误提示
1197
- message.error('网络错误');
1198
- }
1199
-
1200
- setAppStatus(pre => ({ ...pre, display: 'error', sender: 'ready' }));
1201
- setFileStatuses(prev =>
1202
- prev.map(f => ({ ...f, status: 'error', message: '网络错误' }))
1203
- );
1204
- });
1205
- return;
1206
- }
1207
- // 3. 无文件,直接发起AI请求
1208
- setAppStatus(pre => ({ ...pre, display: 'processing', sender: 'processing' }));
1209
- const now = Date.now();
1210
- setConversationList(list =>
1211
- list.map(c => (c.sessionId === sessionId ? { ...c, gmtModified: now } : c))
1212
- );
1213
- clearFn?.();
1214
- api_startChat_re(
1215
- {
1216
- configId: configIdToUse,
1217
- content: preservedContent, // 使用保留格式的内容,确保换行和空格完整传递到后端
1218
- fileUids: [],
1219
- lastDate: now,
1220
- name: label,
1221
- queryId: queryId,
1222
- sessionId: String(sessionId || ''),
1223
- type: 'text',
1224
- audioUrl: '',
1225
- enableThinking: !!senderSwitchValues.reasoning,
1226
- enableWebsearch: !!senderSwitchValues.netSearch,
1227
- qaChannel: senderSwitchValues.qaChannel,
1228
- tempKnowledgeBaseCheck: tempKnowledgeBaseCheck.current,
1229
- } as any,
1230
- gmtModified => {
1231
- fetchRecommendQuestions(queryId);
1232
- }
1233
- );
1234
- }
1235
-
1236
- // =================================================================
1237
- // Event Handlers - 事件处理器
1238
- // =================================================================
1239
-
1240
- /**
1241
- * 处理点赞反馈
1242
- */
1243
- function handleThumbsup(data: any) {
1244
- if (data.restult == 1) {
1245
- handleCancelFeedBack({ url, token, CSRFToken }, { queryId: data.queryId }, () => {
1246
- setFeed(data.queryId, null);
1247
- });
1248
- } else {
1249
- handleFeedBack({ url, token, CSRFToken }, { restult: 1, queryId: data.queryId }, () => {
1250
- setFeed(data.queryId, 1);
1251
- });
1252
- }
1253
- }
1254
-
1255
- /**
1256
- * 处理新建一个临时会话
1257
- */
1258
- function handleConversationCreate(data: any) {
1259
- const sessionId = uid(32);
1260
- // 新会话对象,等待用户输入后再发起创建请求
1261
- const newConversation = {
1262
- sessionId,
1263
- label: '未命名会话',
1264
- gmtModified: Date.now(),
1265
- searchConfigDTO: {},
1266
- filePath: '',
1267
- configId: '',
1268
- isNew: true, // 标记为新会话
1269
- };
1270
- // 在列表顶部插入新会话
1271
- setConversationList(list => [{ ...newConversation, messages: [] }, ...list]);
1272
- setChatData(list => [{ id: sessionId, messages: [], ...newConversation }, ...list]);
1273
- // 激活新会话
1274
- setActiveSessionId(sessionId);
1275
- }
1276
-
1277
- /**
1278
- * 处理会话列表项点击
1279
- */
1280
- function handleItemClick(data: any) {
1281
- if (data?.sessionId && data.sessionId !== activeSessionId) {
1282
- // 如果切换会话时,有正在进行的流式请求(且请求属于当前会话),则取消它
1283
- // 这样可以防止在流式输出开始前切换会话时,后续数据写入错误的会话
1284
- if (activeSessionId) {
1285
- cancelStreamBySessionId(activeSessionId);
1286
- }
1287
- setActiveSessionId(data.sessionId);
1288
- setAppStatus(prev => ({ ...prev, sender: 'ready' }));
1289
- // 点击会话时,使用其最后一条AI消息的推荐问题
1290
- const conv = chatData.find(c => c.id === data.sessionId);
1291
- if (conv && conv.messages && conv.messages.length > 0) {
1292
- const lastAiMsg = [...conv.messages].reverse().find((m: any) => m.istype === 'ai');
1293
- if (lastAiMsg && lastAiMsg.recommendQuestion) {
1294
- setRecommandQuestions(lastAiMsg.recommendQuestion);
1295
- } else {
1296
- setRecommandQuestions([]);
1297
- }
1298
- } else {
1299
- setRecommandQuestions([]);
1300
- }
1301
- }
1302
- }
1303
-
1304
- // =================================================================
1305
- // Async Data Operations - 异步数据操作 (供事件发射器使用)
1306
- // =================================================================
1307
-
1308
- /**
1309
- * 异步删除会话接口
1310
- */
1311
- const async_deleteConversation = async (sessionId: string) => {
1312
- return new Promise((resolve, reject) => {
1313
- handleDeleteConversation({ url, token, CSRFToken }, { sessionId }, (res: any) => {
1314
- if (res) {
1315
- message.success('删除成功!');
1316
- resolve(res);
1317
- } else {
1318
- message.error('删除失败!');
1319
- reject(res);
1320
- }
1321
- });
1322
- });
1323
- };
1324
- /**
1325
- * 异步刷新会话列表接口
1326
- */
1327
- const async_refreshConversationList = async () => {
1328
- try {
1329
- // 重置为第一页
1330
- setConversationList([]);
1331
- setConvTotal(0);
1332
- await fetchConversationPage(1);
1333
- return [];
1334
- } catch (e) {
1335
- message.error('刷新会话列表失败');
1336
- throw e;
1337
- }
1338
- };
1339
-
1340
- /**
1341
- * 异步重命名会话接口
1342
- */
1343
- const async_renameConversation = async (sessionId: string, newLabel: string) => {
1344
- return new Promise((resolve, reject) => {
1345
- handleRename({ url, token, CSRFToken }, { label: newLabel, sessionId }, res => {
1346
- if (res) {
1347
- // 成功后立即更新本地状态
1348
- const now = Date.now();
1349
- setConversationList(list =>
1350
- list.map(item =>
1351
- item.sessionId === sessionId ? { ...item, label: newLabel, gmtModified: now } : item
1352
- )
1353
- );
1354
- // 同步更新 chatData,确保 currentChatData?.label 也能更新
1355
- setChatData(list =>
1356
- list.map(item => (item.id === sessionId ? { ...item, label: newLabel } : item))
1357
- );
1358
- message.success('重命名成功!');
1359
- resolve(res);
1360
- } else {
1361
- message.error('重命名失败');
1362
- reject(res);
1363
- }
1364
- });
1365
- });
1366
- };
1367
-
1368
- // =================================================================
1369
- // Local State Updaters - 本地状态更新 (供事件发射器使用)
1370
- // =================================================================
1371
-
1372
- /**
1373
- * 从本地状态中移除会话项
1374
- */
1375
- const fn_removeItemFromList = (sessionId: string) => {
1376
- setConversationList(list => {
1377
- const newList = list.filter(c => c.sessionId !== sessionId);
1378
- // 如果删除的是当前会话,则激活列表中的第一个
1379
- if (activeSessionId === sessionId) {
1380
- if (newList.length > 0) {
1381
- setActiveSessionId(newList[0].sessionId);
1382
- } else {
1383
- // 如果列表空了,则新建一个
1384
- handleConversationCreate({});
1385
- }
1386
- }
1387
- return newList;
1388
- });
1389
- };
1390
-
1391
- /**
1392
- * 在本地状态中重命名会话项
1393
- */
1394
- const fn_renameItemInList = (sessionId: string, newLabel: string) => {
1395
- const now = Date.now();
1396
- setConversationList(list =>
1397
- list.map(item =>
1398
- item.sessionId === sessionId ? { ...item, label: newLabel, gmtModified: now } : item
1399
- )
1400
- );
1401
- // 同步更新 chatData,确保 currentChatData?.label 也能更新
1402
- setChatData(list =>
1403
- list.map(item => (item.id === sessionId ? { ...item, label: newLabel } : item))
1404
- );
1405
- };
1406
-
1407
- const handleFeedDownConfirm = (data: any) => {
1408
- handleFeedBack({ url, token, CSRFToken }, { ...data, ...feedParam, restult: 0 }, () => {
1409
- setFeed(feedParam.queryId, 0);
1410
- });
1411
- };
1412
-
1413
- const editDialog = (data: any) => {
1414
- const newLabel = data.new_name;
1415
- const oldLabel = curEditData.data.label;
1416
- if (newLabel && newLabel !== oldLabel) {
1417
- curEditData
1418
- .async_renameConversation(newLabel)
1419
- .then(() => {
1420
- curEditData.fn_renameItemInList(newLabel);
1421
- setisRenameModalOpen(false);
1422
- })
1423
- .catch(() => {
1424
- // 重命名失败
1425
- });
1426
- } else {
1427
- setisRenameModalOpen(false);
1428
- }
1429
- };
1430
-
1431
- const editRemove = (data: any) => {
1432
- curEditData
1433
- .async_deleteConversation()
1434
- .then(() => {
1435
- curEditData.fn_removeItemFromList();
1436
- setisRemoveModalOpen(false);
1437
- })
1438
- .catch(() => {
1439
- // 删除失败
1440
- });
1441
- };
1442
-
1443
- const handleEvent = (type: string, data?: any) => {
1444
- console.log(type, data);
1445
- switch (type) {
1446
- case 'close_remove':
1447
- setisRemoveModalOpen(false);
1448
- break;
1449
- case 'close_rename':
1450
- setisRenameModalOpen(false);
1451
- break;
1452
- case 'ok_rename':
1453
- editDialog(data);
1454
- break;
1455
- case 'ok_remove':
1456
- editRemove(data);
1457
- break;
1458
- }
1459
- };
1460
-
1461
- // =================================================================
1462
- // Event Emitter - 事件分发器
1463
- // =================================================================
1464
-
1465
- const getDataBaseData = async ({ url, params, replacePredataFunction }: any) => {
1466
- try {
1467
- const res = await axios.post(url, params, {
1468
- headers: { Authorization: token },
1469
- });
1470
- const data = res?.data?.data?.data;
1471
- if (data) {
1472
- replacePredataFunction(data);
1473
- }
1474
- } catch (error) {
1475
- console.log('error', error);
1476
- }
1477
- };
1478
- const api_getFileStatusByUid = async (data: any) => {
1479
- try {
1480
- const res: any = await axios.get(
1481
- `${getUrlPrefix()}/index/knowledgeBase/file/getFileStatusByUids?uids=${data.data.uids}`,
1482
- { headers: { Authorization: token } }
1483
- );
1484
- console.log('resslkdjgalsg', res);
1485
- return res?.data?.data;
1486
- } catch (error) {}
1487
- };
1488
- const referenceFile_question_upload = async (data: any) => {
1489
- try {
1490
- const res: any = await api_getFileStatusByUid({
1491
- data: { uids: data.uid },
1492
- config: {
1493
- url: getUrlPrefix(),
1494
- token,
1495
- enableMock: false,
1496
- },
1497
- });
1498
- if (res?.length) {
1499
- const d = res[0];
1500
- const _fileType = getTypeByName(d.convertedFilePath);
1501
- if (_fileType === 'pdf' && !d.pdfPages) {
1502
- return message.warning('文件还未解析完成,请稍后预览');
1503
- } else if (d.convertedFilePath) {
1504
- setCurFileInfo({
1505
- ...data,
1506
- parse_url: d.convertedFilePath,
1507
- pdfPages: d.pdfPages,
1508
- });
1509
-
1510
- setDrawerType('preview');
1511
- setOpen(true);
1512
- } else {
1513
- return message.warning('文件解析失败');
1514
- }
1515
- }
1516
- } catch (error) {}
1517
- };
1518
- const tempKnowledgeBaseCheck = useRef(false);
1519
- /**
1520
- * 统一事件分发器,连接业务逻辑与所有子组件的事件
1521
- * @param {string} eventName - 事件名称
1522
- * @param {any} data - 事件数据
1523
- */
1524
- const mergedEventsEmit = (eventName: string, data: any) => {
1525
- console.log(`[Event] ${eventName}`, data);
1526
- switch (eventName) {
1527
- case 'TempKnowledgeBase':
1528
- tempKnowledgeBaseCheck.current = data;
1529
- break;
1530
- case 'reference_file:click':
1531
- if (data.file_type === 'image') return;
1532
-
1533
- const toPreview = (params?: any) => {
1534
- setCurFileInfo({
1535
- ...data,
1536
- file_type: data.type,
1537
- file_name: data.file,
1538
- ...params,
1539
- });
1540
- setDrawerType('preview');
1541
- setOpen(true);
1542
- };
1543
- const _parseType = getTypeByName(data?.parse_url || '');
1544
- const previewUrl = data.metadata?.source
1545
- ? `${TempBaseUrl}${data.metadata.source}`
1546
- : data.filePath || data.url || data.convertedFilePath || '';
1547
- const _sourceType = getTypeByName(previewUrl);
1548
- const toFetchPreview = () => {
1549
- if (!data.uid) {
1550
- if (data.references) return;
1551
- return message.warning('文件还未解析完成,请稍后预览');
1552
- } else {
1553
- referenceFile_question_upload(data);
1554
- }
1555
- };
1556
-
1557
- // 如果是可以直接展示源文件的
1558
- if (fileViewTypes.includes(_sourceType)) {
1559
- const previewUrl = data.metadata?.source
1560
- ? `${TempBaseUrl}${data.metadata.source}`
1561
- : data.url || data.convertedFilePath || data.filePath;
1562
- if (_sourceType === 'pdf') {
1563
- if (data.pdfPages) {
1564
- toPreview({ parse_url: previewUrl });
1565
- } else {
1566
- // pdf但是无pdfPages,并且是可以预览源文件的
1567
- toFetchPreview();
1568
- }
1569
- } else {
1570
- toPreview({ parse_url: previewUrl });
1571
- }
1572
- } else {
1573
- if (_parseType === 'pdf') {
1574
- if (data.pdfPages) {
1575
- toPreview();
1576
- } else {
1577
- // pdf但是无pdfPages,并且是不可以预览源文件的
1578
- toFetchPreview();
1579
- }
1580
- } else {
1581
- if (data.parse_url) {
1582
- toPreview();
1583
- } else {
1584
- // 非pdf但是未获得解析地址
1585
- toFetchPreview();
1586
- }
1587
- }
1588
- }
1589
-
1590
- break;
1591
- case 'conversations:load_more': {
1592
- const hasMore = conversationList.length < convTotal;
1593
- if (hasMore && !convLoading) {
1594
- fetchConversationPage(convPageNo + 1);
1595
- }
1596
- break;
1597
- }
1598
- case 'retrieve-sql-data:pagingation_click':
1599
- const { page, pageSize, fetchUrl, source, replacePredataFunction } = data;
1600
- getDataBaseData({
1601
- url: `${url}${fetchUrl}`,
1602
- replacePredataFunction,
1603
- params: { pageNo: page, pageSize, convertedFilePath: source, stream: false },
1604
- });
1605
- break;
1606
- case 'web_referenceFile_title:click':
1607
- if (!data?.data?.link) return console.error('没有网页地址');
1608
- window.open(data.data.link, '_blank');
1609
- break;
1610
- // --- 对话列表事件 ---
1611
- case 'conversation:item_click':
1612
- handleItemClick(data);
1613
- break;
1614
-
1615
- case 'files:finished_animation_complete':
1616
- setFileStatuses([]);
1617
- break;
1618
-
1619
- case 'conversation:create':
1620
- handleConversationCreate(data);
1621
- break;
1622
- case 'conversation:new_assistant_change':
1623
- setNewAssistantId(data.assistantId);
1624
- break;
1625
- case 'conversations:rename_icon_clicked':
1626
- setCurEditData({
1627
- data,
1628
- async_renameConversation: (newLabel: string) =>
1629
- async_renameConversation(data.sessionId, newLabel),
1630
- fn_renameItemInList: (newLabel: string) =>
1631
- fn_renameItemInList(data.sessionId, newLabel),
1632
- });
1633
- setisRenameModalOpen(true);
1634
- break;
1635
- case 'conversations:delete_icon_clicked':
1636
- setCurEditData({
1637
- data,
1638
- async_deleteConversation: () => async_deleteConversation(data.sessionId),
1639
- async_refreshConversationList,
1640
- fn_removeItemFromList: () => fn_removeItemFromList(data.sessionId),
1641
- });
1642
- setisRemoveModalOpen(true);
1643
- break;
1644
- case 'sender:send':
1645
- handleSenderSend(data, data.clearFn);
1646
- break;
1647
- case 'sender:send_recommandQuestion': {
1648
- // 旧链路:来自 Sender 的推荐问题,可能已经在 AiChat 内转发为 sender:send
1649
- // 这里兜底处理,确保能直接触发发送
1650
- const content = (data?.content ?? '').toString();
1651
- if (!content) break;
1652
- handleSenderSend({ content }, () => {});
1653
- break;
1654
- }
1655
- case 'chatbox:follow_up_question_click': {
1656
- // 新链路:来自 ChatMessageAdapter 的追问点击
1657
- const content = (data?.question ?? data?.content ?? '').toString();
1658
- if (!content) break;
1659
- handleSenderSend({ content }, () => {});
1660
- break;
1661
- }
1662
- case 'sender:stop':
1663
- setStopFlag(); // 使用 hook 提供的停止函数
1664
- if (uploadController) {
1665
- uploadController.abort();
1666
- uploadController = null;
1667
- }
1668
- if (stopPoll) {
1669
- stopPoll();
1670
- stopPoll = null;
1671
- }
1672
- setAppStatus(pre => ({ ...pre, display: 'ready', sender: 'ready' }));
1673
- setFileStatuses([]);
1674
- stopStream?.();
1675
- break;
1676
- case 'sender:clear':
1677
- data.clearFn?.();
1678
- break;
1679
- case 'sender:configChange':
1680
- // 配置项变化,记录最新 switch 状态
1681
- if (data && data.all) {
1682
- setSenderSwitchValues(data.all);
1683
- }
1684
- break;
1685
- case 'sender:action_upload':
1686
- // 触发文件上传按钮点击,打开文件选择对话框
1687
- if (fileInputRef.current) {
1688
- fileInputRef.current.click();
1689
- }
1690
- break;
1691
- case 'sender:action_history':
1692
- // 打开文件管理器 Modal
1693
- setFileManagerOpen(true);
1694
- break;
1695
- case 'uploaded_file:item_click': {
1696
- // 处理文件列表项点击,关闭 Popover(chat 模块使用 AiChat 内置右侧栏,不需要预览 Drawer)
1697
- // 注意:setFileListPopoverOpen 由 useFileDisplayTools hook 管理,这里通过 eventsEmit 触发关闭
1698
- // 可以在这里添加其他处理逻辑,比如在右侧栏显示文件详情
1699
- break;
1700
- }
1701
-
1702
- // --- 消息卡片事件 ---
1703
- case 'action_copy:click':
1704
- if (data) {
1705
- toCopy(data.content, data.event);
1706
- }
1707
- break;
1708
- case 'chatbox:copy': {
1709
- let text = data?.content || '';
1710
- if (!text) break;
1711
- // 过滤掉 [retrive-tag]...[/retrive-tag] 标签及内容
1712
- text = text.replace(/\[retrive-tag[^\]]*\][\s\S]*?\[\/retrive-tag\]/g, '');
1713
- // 直接使用 Clipboard API,避免依赖 event.currentTarget
1714
- const copyByClipboardApi = async (t: string) => {
1715
- try {
1716
- await navigator.clipboard.writeText(t);
1717
- message.success('已复制到剪贴板');
1718
- return true;
1719
- } catch (_) {
1720
- return false;
1721
- }
1722
- };
1723
- const fallbackCopy = (t: string) => {
1724
- const textarea = document.createElement('textarea');
1725
- textarea.value = t;
1726
- textarea.style.position = 'fixed';
1727
- textarea.style.opacity = '0';
1728
- document.body.appendChild(textarea);
1729
- textarea.focus();
1730
- textarea.select();
1731
- try {
1732
- document.execCommand('copy');
1733
- message.success('已复制到剪贴板');
1734
- } catch (_) {
1735
- message.error('复制失败');
1736
- }
1737
- document.body.removeChild(textarea);
1738
- };
1739
- copyByClipboardApi(text).then(ok => {
1740
- if (!ok) fallbackCopy(text);
1741
- });
1742
- break;
1743
- }
1744
- case 'chatbox:repeat':
1745
- console.log(data, 'sdkflskdjflksdjfklsdjlfkjsdklfjsdklfjlks');
1746
- handleReSenderSend(data);
1747
- break;
1748
- case 'action_thumbsup':
1749
- handleThumbsup(data);
1750
- break;
1751
- case 'chatbox:like':
1752
- handleThumbsup({ queryId: data?.queryId, restult: data?.result });
1753
- break;
1754
- case 'action_thumbsdown':
1755
- if (data.restult === 0) {
1756
- handleCancelFeedBack({ url, token, CSRFToken }, { queryId: data.queryId }, () => {
1757
- setFeed(data.queryId, null);
1758
- });
1759
- } else {
1760
- setFeedParam(data);
1761
- setOpenFeed(true);
1762
- }
1763
- break;
1764
- case 'chatbox:dislike':
1765
- if (data?.result === 0) {
1766
- handleCancelFeedBack({ url, token, CSRFToken }, { queryId: data.queryId }, () => {
1767
- setFeed(data.queryId, null);
1768
- });
1769
- } else {
1770
- setFeedParam({ queryId: data?.queryId });
1771
- setOpenFeed(true);
1772
- }
1773
- break;
1774
- case 'action_retrive_tag':
1775
- // 处理 retrive-tag 点击事件,透传给父组件
1776
- eventsEmit?.('action_retrive_tag', data);
1777
- break;
1778
- case 'referenceFile_view':
1779
- // 处理文件预览事件,透传给父组件
1780
- eventsEmit?.('referenceFile_view', data);
1781
- break;
1782
- case 'referenceFile_question':
1783
- // 处理单文档对话事件,先处理预览,再透传给父组件
1784
- console.log(data, 'zhezhhzhzh');
1785
- // 调用预览处理函数
1786
- referenceFile_question_upload(data.data || data);
1787
- // 同时透传给父组件(如果需要)
1788
- eventsEmit?.('referenceFile_question', data);
1789
- break;
1790
- case 'referenceFile_download':
1791
- // 处理文件下载事件,透传给父组件
1792
- eventsEmit?.('referenceFile_download', data);
1793
- break;
1794
- case 'references:click':
1795
- case 'knowledge_base_view_all:click': {
1796
- // 使用 AiChat 内置的右侧栏事件
1797
- const Content = () => {
1798
- // const safe = (() => {
1799
- // try {
1800
- // return typeof data === 'string' ? data : JSON.stringify(data, null, 2);
1801
- // } catch (e) {
1802
- // return String(data);
1803
- // }
1804
- // })();
1805
- return eventName === 'references:click' ? (
1806
- <ReferenceBar
1807
- type={DrawerType.REFERENCELIST}
1808
- data={data}
1809
- token={token}
1810
- eventsEmit={eventsEmit}
1811
- is_download={is_download}
1812
- />
1813
- ) : (
1814
- <AllFiles fileData={data} token={token} />
1815
- );
1816
- };
1817
- const setContentEvent = new CustomEvent('aichat:right_set_content', {
1818
- detail: { content: <Content /> },
1819
- });
1820
- window.dispatchEvent(setContentEvent);
1821
- const openEvent = new CustomEvent('aichat:right_set', {
1822
- detail: { collapsed: false },
1823
- });
1824
- window.dispatchEvent(openEvent);
1825
- break;
1826
- }
1827
- case 'retrive_tag:click':
1828
- // 处理 retrive-tag 点击事件,透传给父组件
1829
- eventsEmit?.('retrive_tag:click', data);
1830
- break;
1831
- // --- 文件管理器事件 ---
1832
- case 'fileManager:change': {
1833
- // 保存核心组件传递的文件处理函数引用
1834
- if (typeof data?.setUploadedFiles === 'function') {
1835
- setUploadedFilesRef.current = data.setUploadedFiles;
1836
- removeFileRef.current = data.removeFile;
1837
- // 保存上传限制配置和已上传文件列表引用,供 handleFileSelect 使用
1838
- senderConfigRef.current = data?.senderConfig;
1839
- uploadedFilesRef.current = Array.isArray(data?.uploadedFiles) ? data.uploadedFiles : [];
1840
- // 同步待上传文件状态(从 AiChat 内部获取)
1841
- if (Array.isArray(data?.uploadedFiles)) {
1842
- setPendingFiles(data.uploadedFiles);
1843
- }
1844
- console.log('[DEBUG] fileManager:change 事件触发,setUploadedFilesRef 已设置', {
1845
- hasSetUploadedFiles: !!setUploadedFilesRef.current,
1846
- uploadedFilesCount: data?.uploadedFiles?.length || 0,
1847
- pendingFilesCount: data?.uploadedFiles?.length || 0,
1848
- hasSenderConfig: !!data?.senderConfig,
1849
- senderConfig: data?.senderConfig,
1850
- upload_number_limit: data?.senderConfig?.upload_number_limit,
1851
- upload_size_limit: data?.senderConfig?.upload_size_limit,
1852
- });
1853
- }
1854
- break;
1855
- }
1856
-
1857
- // --- 文件管理器上传文件删除事件,透传到业务层 ---
1858
- case 'uploaded_file:removeFromTemp': {
1859
- console.log('[DEBUG] mergedEventsEmit uploaded_file:removeFromTemp 事件', data);
1860
-
1861
- const uid = data?.file?.uid;
1862
- if (!uid) {
1863
- console.warn('[DEBUG] 缺少uid,无法删除临时文件', data);
1864
- break;
1865
- }
1866
- // 获取当前对话最后一条用户消息的 queryId
1867
- const lastUserMsg = [...(currentChatData?.messages || [])]
1868
- .reverse()
1869
- .find((msg: any) => msg.istype === 'user');
1870
- const queryId = lastUserMsg?.queryId;
1871
-
1872
- // 使用统一的文件删除处理函数
1873
- handleRemoveFromTemp(uid, queryId);
1874
- break;
1875
- }
1876
- case 'uploaded_file:remove_batch':
1877
- break;
1878
-
1879
- default:
1880
- // 其他未处理事件可继续向上层抛出
1881
- eventsEmit?.(eventName, data);
1882
- }
1883
- };
1884
-
1885
- // =================================================================
1886
- // Component & UI Configuration - 组件及UI配置
1887
- // =================================================================
1888
-
1889
- /**
1890
- * Sidebar 配置
1891
- */
1892
- const sidebar: SidebarTabConfig[] = [
1893
- {
1894
- key: 'conversations',
1895
- type: 'custom',
1896
- label: '对话历史',
1897
- icon: <History size={16} />,
1898
- enabled: true,
1899
- component: (
1900
- <GientechConversationPanel
1901
- data={conversationList}
1902
- assistantList={assistantList}
1903
- activedItem={activeSessionId || ''}
1904
- hasMore={conversationList.length < convTotal}
1905
- loadingMore={convLoading}
1906
- sortRules={[
1907
- { label: '当天', dayPeriod: 1 },
1908
- { label: '3天', dayPeriod: 3 },
1909
- { label: '7天', dayPeriod: 7 },
1910
- { label: '30天', dayPeriod: 30 },
1911
- ]}
1912
- eventsEmit={mergedEventsEmit}
1913
- styles={normalizedStyles.theme}
1914
- />
1915
- ),
1916
- },
1917
- ];
1918
-
1919
- /**
1920
- * 业务层自定义组件
1921
- */
1922
- const WelcomeComponent = React.useCallback(() => {
1923
- return (
1924
- <GientechNewChatWelcome
1925
- eventsEmit={mergedEventsEmit}
1926
- assistantList={assistantList}
1927
- styles={normalizedStyles}
1928
- selectedId={selectedAssistantId}
1929
- onSelectAssistant={setSelectedAssistantId}
1930
- productLogo={rest?.productLogo}
1931
- />
1932
- );
1933
- }, [mergedEventsEmit, assistantList, normalizedStyles, selectedAssistantId, rest?.productLogo]);
1934
-
1935
- const businessCustomComponents = React.useMemo(
1936
- () => ({
1937
- AiChatBox: (msg: any, idx: number) => {
1938
- const isLastMessage = idx === (currentChatData?.messages?.length || 0) - 1;
1939
-
1940
- // 根据消息的 status 和 appStatus 来确定 displayStatus
1941
- let displayStatus = 'ready';
1942
- if (isLastMessage) {
1943
- // 优先使用消息的 status 字段
1944
- if (msg.status !== undefined) {
1945
- switch (msg.status) {
1946
- case 0: // StatusType.Pending
1947
- displayStatus = 'thinking';
1948
- break;
1949
- case 1: // StatusType.Process - 对话正文输出中
1950
- displayStatus = 'processing';
1951
- break;
1952
- case 2: // StatusType.Done - 整个对话完成
1953
- displayStatus = 'ready';
1954
- break;
1955
- case 3: // StatusType.Error - 整个对话出现异常
1956
- displayStatus = 'error';
1957
- break;
1958
- case 4: // StatusType.ThoughtChain - 思维链输出中
1959
- displayStatus = 'thinking';
1960
- break;
1961
- default:
1962
- displayStatus = appStatus.display;
1963
- }
1964
- } else {
1965
- // 如果没有 status 字段,使用 appStatus.display
1966
- displayStatus = appStatus.display;
1967
- }
1968
- }
1969
- // 将推荐问题强制转换为数组,避免切换会话时报 .map 错误
1970
- let safeFollowUps: string[] = [];
1971
- if (Array.isArray(recommandQuestions)) {
1972
- safeFollowUps = recommandQuestions as string[];
1973
- } else if (typeof recommandQuestions === 'string') {
1974
- try {
1975
- safeFollowUps = JSON.parse(recommandQuestions) || [];
1976
- } catch {
1977
- safeFollowUps = [];
1978
- }
1979
- }
1980
- // 保证传入 ChatMessageAdapter 的 reference/webReference/graphReference 始终是有效的 JSON 字符串
1981
- const safeReference = (() => {
1982
- const r = (msg as any)?.reference;
1983
- if (!r) return '[]';
1984
- if (typeof r === 'string') {
1985
- try {
1986
- JSON.parse(r);
1987
- return r;
1988
- } catch {
1989
- return '[]';
1990
- }
1991
- }
1992
- try {
1993
- return JSON.stringify(r);
1994
- } catch {
1995
- return '[]';
1996
- }
1997
- })();
1998
- const safeWebReference = (() => {
1999
- const r = (msg as any)?.webReference;
2000
- if (!r) return '[]';
2001
- if (typeof r === 'string') {
2002
- try {
2003
- JSON.parse(r);
2004
- return r;
2005
- } catch {
2006
- return '[]';
2007
- }
2008
- }
2009
- try {
2010
- return JSON.stringify(r);
2011
- } catch {
2012
- return '[]';
2013
- }
2014
- })();
2015
- const safeGraphReference = (() => {
2016
- const r = (msg as any)?.graphReference;
2017
- if (!r) return '[]';
2018
- if (typeof r === 'string') {
2019
- try {
2020
- JSON.parse(r);
2021
- return r;
2022
- } catch {
2023
- return '[]';
2024
- }
2025
- }
2026
- try {
2027
- return JSON.stringify(r);
2028
- } catch {
2029
- return '[]';
2030
- }
2031
- })();
2032
- // databaseReference 在 rtext 内部会自行解析,这里直接透传原始结构即可(对象或字符串都支持)
2033
- const safeDatabaseReference = (msg as any)?.databaseReference;
2034
-
2035
- // 从 chain 数组中提取 chainRespTime(累加所有节点的 chainRespTime 作为总时间)
2036
- // 如果 msg 已经有 chainRespTime,优先使用;否则从 chain 数组中累加
2037
- const extractChainRespTime = (() => {
2038
- // 优先使用已有的 chainRespTime
2039
- if (msg?.chainRespTime || (msg as any)?.reply?.chainRespTime) {
2040
- return msg?.chainRespTime ?? (msg as any)?.reply?.chainRespTime;
2041
- }
2042
- // 从 chain 数组中累加所有节点的 chainRespTime
2043
- const chain = msg?.chain || (msg as any)?.reply?.chain;
2044
- if (Array.isArray(chain) && chain.length > 0) {
2045
- const totalTime = chain.reduce((sum: number, node: any) => {
2046
- const time = node?.chainRespTime ?? node?.respTime;
2047
- if (time !== null && time !== undefined && time > 0) {
2048
- return sum + time;
2049
- }
2050
- return sum;
2051
- }, 0);
2052
- return totalTime > 0 ? totalTime : undefined;
2053
- }
2054
- return undefined;
2055
- })();
2056
- return (
2057
- <ChatMessageAdapter
2058
- key={`${msg?.queryId || msg?.id || idx}-${msg?.istype || 'unknown'}`}
2059
- {...msg}
2060
- token={token}
2061
- streamUrl="/proxy/index/knowledgeBase/file/stream"
2062
- referenceMode="button"
2063
- reference={safeReference}
2064
- webReference={safeWebReference}
2065
- graphReference={safeGraphReference}
2066
- databaseReference={safeDatabaseReference}
2067
- contentType="stream" // 添加 contentType 确保 slateContent 能正确生成
2068
- displayStatus={displayStatus}
2069
- eventsEmit={mergedEventsEmit}
2070
- // 仅最后一条 AI 消息展示追问
2071
- isLast={isLastMessage && msg?.istype === 'ai'}
2072
- followUpQuestions={isLastMessage && msg?.istype === 'ai' ? safeFollowUps : []}
2073
- defaultAnswer={
2074
- currentChatData?.searchConfigDTO?.defaultAnswer ||
2075
- '不知道什么原因我们没能查到你要的问题*-*'
2076
- }
2077
- is_download={is_download}
2078
- styles={normalizedStyles as any}
2079
- // 开启思维链 UI 展示(rtext 1.4.2+)
2080
- // enableCot: 1 代表支持思维链,0 代表不支持
2081
- // 如果是 1,哪怕一个思维链节点都没有也要把思维链的UI渲染出来
2082
- enableThoughtChain
2083
- chain={msg?.chain}
2084
- thoughtChainNodes={msg?.thoughtChainNodes} // 实时思维链节点(优先使用)
2085
- thoughtChainStatus={msg?.status}
2086
- enableCot={msg?.enableCot ?? (msg as any)?.reply?.enableCot}
2087
- chainRespTime={extractChainRespTime}
2088
- />
2089
- );
2090
- },
2091
- LogoBox: (props: any) => {
2092
- if (props && props.LogoBox === null) return null;
2093
- if (props && typeof props.LogoBox === 'function') return <props.LogoBox />;
2094
- return <div className="text-2xl w-full text-center font-bold">小鲸智能助手</div>;
2095
- },
2096
- DisplayLoading: () => <DisplayLoading />,
2097
- DisplayError: () => <DisplayError />,
2098
- AppError: () => (
2099
- <AppError
2100
- msg="应用初始化失败"
2101
- subMsg="无法完成应用初始化,这可能是由于网络连接问题或服务配置错误导致的。请检查您的网络连接并重试。"
2102
- />
2103
- ),
2104
- AppLoading: () => (
2105
- <AppLoading
2106
- title={rest?.appLoadingConfig?.title}
2107
- subtitle={rest?.appLoadingConfig?.subtitle || ''}
2108
- />
2109
- ),
2110
- UserChatBox: (msg: any, idx: number) => {
2111
- return (
2112
- <ChatMessageAdapter
2113
- key={`${msg?.queryId || msg?.id || idx}-user`}
2114
- token={token}
2115
- streamUrl="/proxy/index/knowledgeBase/file/stream"
2116
- {...msg}
2117
- referenceMode="button"
2118
- contentType="plainText"
2119
- isUser={true}
2120
- displayStatus="ready"
2121
- eventsEmit={mergedEventsEmit}
2122
- styles={normalizedStyles as any}
2123
- fileManagerData={fileManagerData}
2124
- // 确保 currentFiles 被正确传递(用于渲染上传文件卡片)
2125
- currentFiles={msg?.currentFiles}
2126
- />
2127
- );
2128
- },
2129
- WelcomeComponent,
2130
- }),
2131
- [
2132
- WelcomeComponent,
2133
- currentChatData,
2134
- appStatus.display,
2135
- mergedEventsEmit,
2136
- normalizedStyles,
2137
- is_download,
2138
- fileManagerData,
2139
- ]
2140
- );
2141
-
2142
- /**
2143
- * 合并外部传入和业务默认的自定义组件,外部优先
2144
- */
2145
- const mergedCustomComponents: { [key: string]: any } = {
2146
- ...businessCustomComponents,
2147
- ...(rest.CustomComponents || {}),
2148
- };
2149
-
2150
- useEffect(() => {
2151
- setDynamicSenderConfig((prev: any) => {
2152
- const switchs = Array.isArray(prev.switchs)
2153
- ? prev.switchs.map((item: any) =>
2154
- item.name === 'reasoning' ? { ...item, enabled: true } : item
2155
- )
2156
- : [];
2157
- return {
2158
- ...prev,
2159
- switchs,
2160
- };
2161
- });
2162
- }, []);
2163
- // =================================================================
2164
- // Render - 渲染
2165
- // =================================================================
2166
-
2167
- const uploadedFiles = useMemo(() => {
2168
- return (fileManagerData.uploadedFiles || []) as any[];
2169
- }, [fileManagerData]);
2170
-
2171
- // 使用统一的文件展示工具 Hook
2172
- // 使用 allFilesFromQuery(从 query.filePaths 收集的所有文件)而不是 fileManagerData.uploadedFiles
2173
- const { FileDisplayTools } = useFileDisplayTools({
2174
- fileManagerData: {
2175
- uploadedFiles,
2176
- },
2177
- styles: normalizedStyles,
2178
- eventsEmit: mergedEventsEmit,
2179
- });
2180
-
2181
- // 处理文件选择
2182
- const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
2183
- const files = e.target.files;
2184
- if (files && files.length > 0) {
2185
- console.log('[DEBUG] handleFileSelect 触发', {
2186
- filesCount: files.length,
2187
- hasSetUploadedFilesRef: !!setUploadedFilesRef.current,
2188
- hasSenderConfig: !!senderConfigRef.current,
2189
- dynamicSenderConfig: dynamicSenderConfig,
2190
- dynamicSenderConfigKeys: dynamicSenderConfig ? Object.keys(dynamicSenderConfig) : [],
2191
- senderConfigRef: senderConfigRef.current,
2192
- senderConfigRefKeys: senderConfigRef.current ? Object.keys(senderConfigRef.current) : [],
2193
- });
2194
-
2195
- const fileArray = Array.from(files);
2196
-
2197
- // 应用上传限制配置验证
2198
- // 优先使用 senderConfigRef.current,但如果它没有上传限制字段,则使用 dynamicSenderConfig
2199
- let configSource: any = senderConfigRef.current;
2200
- if (
2201
- !configSource ||
2202
- (configSource.upload_size_limit === undefined &&
2203
- configSource.upload_number_limit === undefined &&
2204
- (!configSource.upload_file_type_limit ||
2205
- configSource.upload_file_type_limit.length === 0))
2206
- ) {
2207
- configSource = dynamicSenderConfig;
2208
- }
2209
- const existingFiles = uploadedFilesRef.current || [];
2210
-
2211
- console.log('[DEBUG] 验证配置检查', {
2212
- configSource,
2213
- upload_number_limit: configSource?.upload_number_limit,
2214
- upload_size_limit: configSource?.upload_size_limit,
2215
- existingFilesCount: existingFiles.length,
2216
- newFilesCount: fileArray.length,
2217
- });
2218
-
2219
- // 检查是否有上传限制配置(只要有一个限制配置存在就执行验证)
2220
- const hasUploadLimitConfig =
2221
- configSource &&
2222
- (configSource.upload_size_limit !== undefined ||
2223
- (configSource.upload_number_limit !== undefined &&
2224
- configSource.upload_number_limit > 0) ||
2225
- (configSource.upload_file_type_limit &&
2226
- configSource.upload_file_type_limit.length > 0));
2227
-
2228
- console.log('[DEBUG] 配置检查结果', {
2229
- hasUploadLimitConfig,
2230
- upload_number_limit: configSource?.upload_number_limit,
2231
- upload_size_limit: configSource?.upload_size_limit,
2232
- upload_file_type_limit: configSource?.upload_file_type_limit,
2233
- });
2234
-
2235
- if (hasUploadLimitConfig) {
2236
- // 提取上传限制相关配置
2237
- const uploadConfig = {
2238
- upload_size_limit: configSource.upload_size_limit,
2239
- upload_number_limit: configSource.upload_number_limit,
2240
- upload_file_type_limit: configSource.upload_file_type_limit,
2241
- upload_limit_message: configSource.upload_limit_message,
2242
- };
2243
-
2244
- console.log('[DEBUG] 执行文件验证', {
2245
- uploadConfig,
2246
- existingFilesCount: existingFiles.length,
2247
- newFilesCount: fileArray.length,
2248
- totalCount: existingFiles.length + fileArray.length,
2249
- });
2250
-
2251
- const validationResult = validateFileUpload(fileArray, existingFiles, uploadConfig);
2252
-
2253
- console.log('[DEBUG] 验证结果', {
2254
- valid: validationResult.valid,
2255
- errors: validationResult.errors,
2256
- rejectedFilesCount: validationResult.rejectedFiles.length,
2257
- });
2258
-
2259
- if (!validationResult.valid) {
2260
- // 显示错误提示
2261
- showValidationErrors(validationResult);
2262
- // 只保留通过验证的文件
2263
- const validFiles = fileArray.filter(
2264
- file => !validationResult.rejectedFiles.includes(file)
2265
- );
2266
-
2267
- if (validFiles.length === 0) {
2268
- // 所有文件都被拒绝,清空 input 并返回
2269
- if (fileInputRef.current) {
2270
- fileInputRef.current.value = '';
2271
- }
2272
- return;
2273
- }
2274
-
2275
- // 使用通过验证的文件
2276
- fileArray.splice(0, fileArray.length, ...validFiles);
2277
- }
2278
- }
2279
-
2280
- // 通过 setUploadedFilesRef 直接设置文件到 aichat 内部
2281
- // 这个 ref 在 fileManager:change 事件中设置
2282
- if (setUploadedFilesRef.current) {
2283
- const fileList = fileArray.map(file => ({
2284
- file,
2285
- type: file.type.startsWith('image/') ? ('image' as const) : ('document' as const),
2286
- status: 'pending' as const, // 添加 status 字段,确保文件可以正确显示
2287
- name: file.name, // 添加 name 字段,方便 FilesDisplay 使用
2288
- }));
2289
- console.log('[DEBUG] 通过 setUploadedFilesRef 设置文件', fileList);
2290
- setUploadedFilesRef.current(fileList);
2291
- } else {
2292
- console.warn('[DEBUG] setUploadedFilesRef 未设置,延迟重试');
2293
- // 如果 ref 还没有设置,延迟重试
2294
- setTimeout(() => {
2295
- if (setUploadedFilesRef.current) {
2296
- const fileList = fileArray.map(file => ({
2297
- file,
2298
- type: file.type.startsWith('image/') ? ('image' as const) : ('document' as const),
2299
- status: 'pending' as const, // 添加 status 字段,确保文件可以正确显示
2300
- name: file.name, // 添加 name 字段,方便 FilesDisplay 使用
2301
- }));
2302
- console.log('[DEBUG] 延迟后通过 setUploadedFilesRef 设置文件', fileList);
2303
- setUploadedFilesRef.current(fileList);
2304
- } else {
2305
- console.error('[DEBUG] 延迟后 setUploadedFilesRef 仍未设置');
2306
- }
2307
- }, 100);
2308
- }
2309
- }
2310
- // 清空 input,以便可以重复选择同一文件
2311
- if (fileInputRef.current) {
2312
- fileInputRef.current.value = '';
2313
- }
2314
- };
2315
-
2316
- return (
2317
- <GientechChatI18nProvider locale={locale}>
2318
- <div style={{ height: '100%', minWidth: '1116px', overflow: 'hidden' }}>
2319
- {/* 隐藏的文件上传input */}
2320
- <input
2321
- ref={fileInputRef}
2322
- type="file"
2323
- multiple
2324
- accept="image/*,.pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.txt,.md,.json,.csv,.zip,.rar,.7z"
2325
- style={{ display: 'none' }}
2326
- onChange={handleFileSelect}
2327
- />
2328
- {/* 右侧栏由 AiChat 内置事件控制,此处不再使用 antd Drawer */}
2329
-
2330
- <WrappedComponent
2331
- {...rest}
2332
- status={appStatus}
2333
- chatData={currentChatData}
2334
- sidebar={sidebar}
2335
- recommandQuestions={[]}
2336
- eventsEmit={mergedEventsEmit}
2337
- styles={normalizedStyles as any}
2338
- senderConfig={dynamicSenderConfig}
2339
- fileUploadStatus={fileStatuses}
2340
- CustomComponents={mergedCustomComponents}
2341
- activeSessionId={activeSessionId}
2342
- scrollOld={scrollOld}
2343
- rightbarWidth={'400px'}
2344
- locale={locale}
2345
- messages={messages}
2346
- disclaimer={rest.disclaimer ?? gientechMessages.disclaimer}
2347
- {...({
2348
- chatHeader: {
2349
- title: currentChatData?.label || gientechMessages.chatHeader.newConversation,
2350
- tools: FileDisplayTools,
2351
- },
2352
- } as any)}
2353
- />
2354
- <FeedBackModal
2355
- open={openFeed}
2356
- feedBackList={feedBackList}
2357
- setOpen={setOpenFeed}
2358
- handleConfirm={handleFeedDownConfirm}
2359
- />
2360
- <RenameModal
2361
- isModalOpen={isRenameModalOpen}
2362
- handleOk={handleEvent}
2363
- handleCancel={() => handleEvent('close_rename')}
2364
- data={curEditData?.data || {}}
2365
- />
2366
- <DeleteModal
2367
- isModalOpen={isRemoveModalOpen}
2368
- handleOk={handleEvent}
2369
- handleCancel={() => handleEvent('close_remove')}
2370
- data={curEditData?.data || {}}
2371
- />
2372
- <ConfigProvider
2373
- drawer={{
2374
- styles: {
2375
- body: { padding: 0 },
2376
- header: { display: 'none' },
2377
- },
2378
- }}
2379
- >
2380
- <Drawer
2381
- autoFocus={false}
2382
- onClose={() => setOpen(false)}
2383
- open={open}
2384
- width={drawerType === 'graphPreview' ? '100%' : 720}
2385
- className="overflow-x-hidden"
2386
- destroyOnClose
2387
- >
2388
- {drawerType === 'preview' && (
2389
- <DrawerPreview curFileInfo={curFileInfo} onClose={setOpen} token={token} />
2390
- )}
2391
- </Drawer>
2392
- </ConfigProvider>
2393
- </div>
2394
- </GientechChatI18nProvider>
2395
- );
2396
- };
2397
- }
2398
-
2399
- // 重新导出 registerPDFWorker,方便用户从 chat 模块引入
2400
- export { registerPDFWorker } from '@mxmweb/fviewer';