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