@gientech/modual 1.3.0 → 1.3.2

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 (308) hide show
  1. package/README.md +129 -129
  2. package/{dist/assets/mysql.svg → assets/MySQL.svg} +14 -14
  3. package/{dist/assets → assets}/database.svg +11 -11
  4. package/{src/modules/database/assets → assets}/database_add.svg +53 -53
  5. package/{dist/assets → assets}/database_connect.svg +66 -66
  6. package/{dist/assets → assets}/database_upload.svg +29 -29
  7. package/{dist/assets → assets}/defaultWeLogo.svg +14 -14
  8. package/{dist/assets/index-DIm7RgkM.js → assets/index-D-dGaGjW.js} +93 -279
  9. package/assets/index-ldqIbm0x.js +1289 -0
  10. package/assets/style.css +1 -0
  11. package/assets/style3.css +1 -0
  12. package/{dist/chat.js → chat.js} +78 -78
  13. package/database.js +20 -0
  14. package/{dist/databaseId.js → databaseId.js} +1 -1
  15. package/{dist/databaseTable.js → databaseTable.js} +1 -1
  16. package/{dist/modelManage.js → modelManage.js} +1 -1
  17. package/package.json +39 -83
  18. package/{dist/sensitive.js → sensitive.js} +1 -1
  19. package/{dist/streamFilesReader.js → streamFilesReader.js} +11 -11
  20. package/{dist/worker → worker}/pdf.worker.min.js +21 -21
  21. package/.editorconfig +0 -38
  22. package/.prettierignore +0 -16
  23. package/.prettierrc +0 -17
  24. package/USAGE.md +0 -191
  25. package/bash.exe.stackdump +0 -40
  26. package/components.json +0 -21
  27. package/dist/README.md +0 -129
  28. package/dist/assets/database_add.svg +0 -53
  29. package/dist/assets/index-Bpnc4tRH.js +0 -1284
  30. package/dist/assets/style.css +0 -1
  31. package/dist/assets/style3.css +0 -1
  32. package/dist/database.js +0 -20
  33. package/dist/package.json +0 -56
  34. package/doc_assets/2.png +0 -0
  35. package/doc_assets/demo.md +0 -27
  36. package/doc_assets/demos/dist-app/assets/index.Dh-ZAS9Z.css +0 -2
  37. package/doc_assets/demos/dist-app/assets/index.Dv8KVW18.js +0 -23699
  38. package/doc_assets/demos/dist-app/assets/index.Dv8KVW18.js.map +0 -1
  39. package/doc_assets/demos/dist-app/index.html +0 -14
  40. package/doc_assets/demos/dist-app/vite.svg +0 -1
  41. package/doc_assets/images/1.png +0 -0
  42. package/doc_assets/images/3.png +0 -0
  43. package/doc_assets/images/component-screenshot.png +0 -1
  44. package/doc_assets/install.md +0 -5
  45. package/eslint.config.js +0 -92
  46. package/index.html +0 -13
  47. package/postcss.config.cjs +0 -19
  48. package/public/vite.svg +0 -1
  49. package/public/worker/pdf.worker.min.js +0 -22
  50. package/scripts/README.md +0 -133
  51. package/scripts/build-demo.js +0 -88
  52. package/scripts/demo-selector.js +0 -216
  53. package/scripts/dev-demo.js +0 -76
  54. package/scripts/preview-demo.js +0 -130
  55. package/scripts/run-demo.bat +0 -34
  56. package/src/assets/img/downArrow.png +0 -0
  57. package/src/assets/img/excel.png +0 -0
  58. package/src/assets/img/img.png +0 -0
  59. package/src/assets/img/pdf.png +0 -0
  60. package/src/assets/img/ppt.png +0 -0
  61. package/src/assets/img/txt.png +0 -0
  62. package/src/assets/img/word.png +0 -0
  63. package/src/assets/login/homeBg.png +0 -0
  64. package/src/assets/login/left.jpg +0 -0
  65. package/src/assets/login/logoImg.png +0 -0
  66. package/src/examples/LoginPage/index.tsx +0 -18
  67. package/src/examples/chat/components/DrawerGraphPreview.tsx +0 -77
  68. package/src/examples/chat/index.tsx +0 -179
  69. package/src/examples/gientechStreamFilesReader/index.tsx +0 -1016
  70. package/src/examples/ragDatabaseDataPage/index.tsx +0 -36
  71. package/src/examples/ragDatabaseIdPage/index.tsx +0 -44
  72. package/src/examples/ragDatabasePage/index.tsx +0 -36
  73. package/src/examples/ragModelManagePage/index.tsx +0 -37
  74. package/src/examples/ragSearchPage/index.tsx +0 -0
  75. package/src/examples/ragSensitiveWordsPage/index.tsx +0 -32
  76. package/src/examples/streamFiles/index.tsx +0 -384
  77. package/src/lib_enter.ts +0 -38
  78. package/src/main.tsx +0 -5
  79. package/src/main.tsx.backup +0 -5
  80. package/src/modules/chat/Conversations/Item.tsx +0 -167
  81. package/src/modules/chat/Conversations/List.tsx +0 -143
  82. package/src/modules/chat/Conversations/groupByTime.ts +0 -39
  83. package/src/modules/chat/Conversations/index.tsx +0 -212
  84. package/src/modules/chat/constants.tsx +0 -33
  85. package/src/modules/chat/index.tsx +0 -1836
  86. package/src/modules/chat/types.ts +0 -17
  87. package/src/modules/database/CreateModal.tsx +0 -398
  88. package/src/modules/database/assets/Doris.png +0 -0
  89. package/src/modules/database/assets/PostgreSQL.png +0 -0
  90. package/src/modules/database/assets/SQLServer.png +0 -0
  91. package/src/modules/database/assets/database.svg +0 -11
  92. package/src/modules/database/assets/database_connect.svg +0 -66
  93. package/src/modules/database/assets/database_upload.svg +0 -29
  94. package/src/modules/database/assets/empty.png +0 -0
  95. package/src/modules/database/assets/mysql.svg +0 -14
  96. package/src/modules/database/index.tsx +0 -466
  97. package/src/modules/database/server.ts +0 -196
  98. package/src/modules/databaseId/CustomCom.tsx +0 -156
  99. package/src/modules/databaseId/EditConfig.tsx +0 -268
  100. package/src/modules/databaseId/UploadDrawer.tsx +0 -520
  101. package/src/modules/databaseId/assets/aiOptimize.svg +0 -10
  102. package/src/modules/databaseId/assets/empty.png +0 -0
  103. package/src/modules/databaseId/assets/template.svg +0 -6
  104. package/src/modules/databaseId/assets/upload.svg +0 -9
  105. package/src/modules/databaseId/assets/useTemp.svg +0 -6
  106. package/src/modules/databaseId/index.tsx +0 -734
  107. package/src/modules/databaseId/server.ts +0 -286
  108. package/src/modules/databaseId/style.css +0 -5
  109. package/src/modules/databaseTable/EditRowDrawer.tsx +0 -119
  110. package/src/modules/databaseTable/index.tsx +0 -357
  111. package/src/modules/databaseTable/server.ts +0 -180
  112. package/src/modules/headlessChat/constants.tsx +0 -32
  113. package/src/modules/headlessChat/index.tsx +0 -1065
  114. package/src/modules/headlessChat/types.ts +0 -23
  115. package/src/modules/login/components/Login/LoginBox/index.tsx +0 -102
  116. package/src/modules/login/components/Login/RegisterBox/index.tsx +0 -180
  117. package/src/modules/login/components/Login/index.tsx +0 -100
  118. package/src/modules/login/index.tsx +0 -106
  119. package/src/modules/login/style.css +0 -3
  120. package/src/modules/login/useServices.ts +0 -53
  121. package/src/modules/login/utils.ts +0 -42
  122. package/src/modules/modelManage/ConfigDrawer.tsx +0 -249
  123. package/src/modules/modelManage/assets/empty.png +0 -0
  124. package/src/modules/modelManage/const.ts +0 -50
  125. package/src/modules/modelManage/index.tsx +0 -439
  126. package/src/modules/modelManage/server.ts +0 -185
  127. package/src/modules/nodegraph/index.tsx +0 -1
  128. package/src/modules/search/assets/Icon-history.svg +0 -8
  129. package/src/modules/search/assets/answerAwartar.png +0 -0
  130. package/src/modules/search/assets/doc.png +0 -0
  131. package/src/modules/search/assets/genera.gif +0 -0
  132. package/src/modules/search/assets/icon-robot.svg +0 -9
  133. package/src/modules/search/assets/icon-search-bar.svg +0 -14
  134. package/src/modules/search/assets/icon-sub-title.svg +0 -3
  135. package/src/modules/search/assets/icon-title.svg +0 -9
  136. package/src/modules/search/assets/icon-zoomOut.svg +0 -9
  137. package/src/modules/search/assets/iconAi.svg +0 -9
  138. package/src/modules/search/assets/pdf.png +0 -0
  139. package/src/modules/search/assets/ppt.png +0 -0
  140. package/src/modules/search/assets/search.svg +0 -3
  141. package/src/modules/search/assets/selected.svg +0 -4
  142. package/src/modules/search/assets/txt.png +0 -0
  143. package/src/modules/search/assets/xls.png +0 -0
  144. package/src/modules/search/components/AssisSelect.tsx +0 -137
  145. package/src/modules/search/components/Editor/ChatViewEditor.tsx +0 -261
  146. package/src/modules/search/components/Editor/aichat.css +0 -1
  147. package/src/modules/search/components/Editor/constant.ts +0 -13
  148. package/src/modules/search/components/Editor/index.tsx +0 -113
  149. package/src/modules/search/components/Editor/plugins/autofomatRules.ts +0 -332
  150. package/src/modules/search/components/Editor/plugins/convertImgPlugins.tsx +0 -20
  151. package/src/modules/search/components/Editor/plugins/createIndexes.tsx +0 -38
  152. package/src/modules/search/components/Editor/plugins/displayer.ts +0 -298
  153. package/src/modules/search/components/Editor/plugins/imageClick.tsx +0 -32
  154. package/src/modules/search/components/Editor/plugins/myplugin.tsx +0 -98
  155. package/src/modules/search/components/Editor/ui/avatar.tsx +0 -19
  156. package/src/modules/search/components/Editor/ui/blockquote-element.tsx +0 -21
  157. package/src/modules/search/components/Editor/ui/button.tsx +0 -58
  158. package/src/modules/search/components/Editor/ui/calendar.tsx +0 -68
  159. package/src/modules/search/components/Editor/ui/caption.tsx +0 -46
  160. package/src/modules/search/components/Editor/ui/checkbox.tsx +0 -27
  161. package/src/modules/search/components/Editor/ui/code-block-combobox.tsx +0 -188
  162. package/src/modules/search/components/Editor/ui/code-block-element.css +0 -434
  163. package/src/modules/search/components/Editor/ui/code-block-element.tsx +0 -39
  164. package/src/modules/search/components/Editor/ui/code-leaf.tsx +0 -24
  165. package/src/modules/search/components/Editor/ui/code-line-element.tsx +0 -10
  166. package/src/modules/search/components/Editor/ui/code-syntax-leaf.tsx +0 -21
  167. package/src/modules/search/components/Editor/ui/column-element.tsx +0 -30
  168. package/src/modules/search/components/Editor/ui/column-group-element.tsx +0 -94
  169. package/src/modules/search/components/Editor/ui/command.tsx +0 -75
  170. package/src/modules/search/components/Editor/ui/comment-avatar.tsx +0 -22
  171. package/src/modules/search/components/Editor/ui/comment-create-form.tsx +0 -37
  172. package/src/modules/search/components/Editor/ui/comment-item.tsx +0 -74
  173. package/src/modules/search/components/Editor/ui/comment-leaf.tsx +0 -49
  174. package/src/modules/search/components/Editor/ui/comment-more-dropdown.tsx +0 -42
  175. package/src/modules/search/components/Editor/ui/comment-reply-items.tsx +0 -22
  176. package/src/modules/search/components/Editor/ui/comment-resolve-button.tsx +0 -32
  177. package/src/modules/search/components/Editor/ui/comment-value.tsx +0 -34
  178. package/src/modules/search/components/Editor/ui/comments-popover.tsx +0 -63
  179. package/src/modules/search/components/Editor/ui/date-element.tsx +0 -83
  180. package/src/modules/search/components/Editor/ui/dialog.tsx +0 -63
  181. package/src/modules/search/components/Editor/ui/draggable.tsx +0 -177
  182. package/src/modules/search/components/Editor/ui/dropdown-menu.tsx +0 -180
  183. package/src/modules/search/components/Editor/ui/emoji-input-element.tsx +0 -85
  184. package/src/modules/search/components/Editor/ui/excalidraw-element.tsx +0 -28
  185. package/src/modules/search/components/Editor/ui/fixed-toolbar-buttons.tsx +0 -76
  186. package/src/modules/search/components/Editor/ui/fixed-toolbar.tsx +0 -8
  187. package/src/modules/search/components/Editor/ui/floating-toolbar-buttons.tsx +0 -51
  188. package/src/modules/search/components/Editor/ui/floating-toolbar.tsx +0 -77
  189. package/src/modules/search/components/Editor/ui/heading-element.tsx +0 -48
  190. package/src/modules/search/components/Editor/ui/highlight-leaf.tsx +0 -17
  191. package/src/modules/search/components/Editor/ui/hr-element.tsx +0 -30
  192. package/src/modules/search/components/Editor/ui/icons.tsx +0 -267
  193. package/src/modules/search/components/Editor/ui/image-element.tsx +0 -74
  194. package/src/modules/search/components/Editor/ui/inline-combobox.tsx +0 -368
  195. package/src/modules/search/components/Editor/ui/input.tsx +0 -25
  196. package/src/modules/search/components/Editor/ui/insert-dropdown-menu.tsx +0 -218
  197. package/src/modules/search/components/Editor/ui/kbd-leaf.tsx +0 -20
  198. package/src/modules/search/components/Editor/ui/link-element.tsx +0 -29
  199. package/src/modules/search/components/Editor/ui/link-floating-toolbar.tsx +0 -161
  200. package/src/modules/search/components/Editor/ui/list-element.tsx +0 -30
  201. package/src/modules/search/components/Editor/ui/mark-toolbar-button.tsx +0 -24
  202. package/src/modules/search/components/Editor/ui/media-embed-element.tsx +0 -133
  203. package/src/modules/search/components/Editor/ui/media-popover.tsx +0 -97
  204. package/src/modules/search/components/Editor/ui/mention-element.tsx +0 -43
  205. package/src/modules/search/components/Editor/ui/mention-input-element.tsx +0 -141
  206. package/src/modules/search/components/Editor/ui/mode-dropdown-menu.tsx +0 -93
  207. package/src/modules/search/components/Editor/ui/more-dropdown-menu.tsx +0 -67
  208. package/src/modules/search/components/Editor/ui/paragraph-element.tsx +0 -4
  209. package/src/modules/search/components/Editor/ui/placeholder.tsx +0 -52
  210. package/src/modules/search/components/Editor/ui/popover.tsx +0 -32
  211. package/src/modules/search/components/Editor/ui/resizable.tsx +0 -66
  212. package/src/modules/search/components/Editor/ui/separator.tsx +0 -25
  213. package/src/modules/search/components/Editor/ui/style.less +0 -12
  214. package/src/modules/search/components/Editor/ui/table-cell-element.tsx +0 -143
  215. package/src/modules/search/components/Editor/ui/table-element.tsx +0 -243
  216. package/src/modules/search/components/Editor/ui/table-row-element.tsx +0 -22
  217. package/src/modules/search/components/Editor/ui/tableValue.tsx +0 -135
  218. package/src/modules/search/components/Editor/ui/todo-list-element.tsx +0 -43
  219. package/src/modules/search/components/Editor/ui/toggle-element.tsx +0 -31
  220. package/src/modules/search/components/Editor/ui/toolbar.tsx +0 -157
  221. package/src/modules/search/components/Editor/ui/tooltip.tsx +0 -65
  222. package/src/modules/search/components/Editor/ui/turn-into-dropdown-menu.tsx +0 -160
  223. package/src/modules/search/components/Editor/ui/with-draggables.tsx +0 -175
  224. package/src/modules/search/components/FileList.tsx +0 -287
  225. package/src/modules/search/components/ImageGroupView/index.tsx +0 -85
  226. package/src/modules/search/components/ResultContent.tsx +0 -232
  227. package/src/modules/search/components/SearchInput.tsx +0 -232
  228. package/src/modules/search/components/SearchLanding.tsx +0 -74
  229. package/src/modules/search/components/SearchView.tsx +0 -563
  230. package/src/modules/search/components/SimpleEditor.tsx +0 -158
  231. package/src/modules/search/components/SimpleFileList.tsx +0 -215
  232. package/src/modules/search/index.tsx +0 -10
  233. package/src/modules/search/reademe.md +0 -1
  234. package/src/modules/search/servers/apis.tsx +0 -19
  235. package/src/modules/search/servers/index.ts +0 -184
  236. package/src/modules/search/style.less +0 -503
  237. package/src/modules/search/type.ts +0 -22
  238. package/src/modules/search/utils.ts +0 -34
  239. package/src/modules/sensitive/index.tsx +0 -313
  240. package/src/modules/sensitive/server.ts +0 -122
  241. package/src/modules/streamFilesReader/GientechStreamReader.tsx +0 -1555
  242. package/src/modules/streamFilesReader/components/Header/Toolbar.tsx +0 -0
  243. package/src/modules/streamFilesReader/components/Header/index.tsx +0 -297
  244. package/src/modules/streamFilesReader/index.tsx +0 -3
  245. package/src/style.css +0 -6
  246. package/src/type.d.ts +0 -0
  247. package/src/utils/commonFn.tsx +0 -111
  248. package/src/utils/gientechCommon/components/AppError.tsx +0 -32
  249. package/src/utils/gientechCommon/components/AppLoading.tsx +0 -75
  250. package/src/utils/gientechCommon/components/DeleteModal.tsx +0 -75
  251. package/src/utils/gientechCommon/components/DisplayError.tsx +0 -33
  252. package/src/utils/gientechCommon/components/DisplayLoading.tsx +0 -38
  253. package/src/utils/gientechCommon/components/FeedBackModal.tsx +0 -310
  254. package/src/utils/gientechCommon/components/FileCardCommon.tsx +0 -82
  255. package/src/utils/gientechCommon/components/FileManager/index.tsx +0 -390
  256. package/src/utils/gientechCommon/components/FileManager/style.css +0 -5
  257. package/src/utils/gientechCommon/components/Messages/GientechNewChatWelcome.tsx +0 -296
  258. package/src/utils/gientechCommon/components/Messages/ReferenceCard.tsx +0 -339
  259. package/src/utils/gientechCommon/components/Messages/RetriveItem.tsx +0 -245
  260. package/src/utils/gientechCommon/components/Messages/WebRetriveItem.tsx +0 -209
  261. package/src/utils/gientechCommon/components/Messages/defaultBot.png +0 -0
  262. package/src/utils/gientechCommon/components/Messages/defaultStyleSet.tsx +0 -148
  263. package/src/utils/gientechCommon/components/Messages/defaultWeLogo.svg +0 -14
  264. package/src/utils/gientechCommon/components/RenameModal.tsx +0 -86
  265. package/src/utils/gientechCommon/components/style.less +0 -11
  266. package/src/utils/gientechCommon/configs/commonConfig.ts +0 -2
  267. package/src/utils/gientechCommon/configs/senderConfig.ts +0 -0
  268. package/src/utils/gientechCommon/configs/stylesConfig.ts +0 -142
  269. package/src/utils/gientechCommon/hooks/AichatUseController.tsx +0 -339
  270. package/src/utils/gientechCommon/slate/converters/deserializers.ts +0 -763
  271. package/src/utils/gientechCommon/slate/converters/mockData.ts +0 -232
  272. package/src/utils/gientechCommon/slate/converters/slateConverters.ts +0 -258
  273. package/src/utils/gientechCommon/slate/richElements/index.tsx +0 -499
  274. package/src/utils/gientechCommon/utils/request.ts +0 -37
  275. package/src/utils/gientechCommon/utils/serverFn.ts +0 -172
  276. package/src/utils/index.tsx +0 -126
  277. package/src/utils/testconfigs/demologin/index.tsx +0 -32
  278. package/src/utils/testconfigs/index.ts +0 -53
  279. package/src/vite-env.d.ts +0 -11
  280. package/stats.html +0 -4949
  281. package/tailwind.config.js +0 -170
  282. package/tsconfig.app.json +0 -30
  283. package/tsconfig.app.tsbuildinfo +0 -11
  284. package/tsconfig.json +0 -13
  285. package/tsconfig.node.json +0 -22
  286. package/tsconfig.node.tsbuildinfo +0 -1
  287. package/vite.config.ts +0 -177
  288. package/workflows/release.yml +0 -60
  289. /package/{dist/assets → assets}/Doris.png +0 -0
  290. /package/{dist/assets → assets}/PostgreSQL.png +0 -0
  291. /package/{dist/assets → assets}/SQLServer.png +0 -0
  292. /package/{dist/assets → assets}/_commonjsHelpers-gnU0ypJ3.js +0 -0
  293. /package/{dist/assets → assets}/circle-alert-g2Y6zAjt.js +0 -0
  294. /package/{dist/assets → assets}/empty.png +0 -0
  295. /package/{dist/assets → assets}/index-CEK88UzR.js +0 -0
  296. /package/{dist/assets → assets}/index-CpW6Dhpp.js +0 -0
  297. /package/{dist/assets → assets}/plus-omCUN0e3.js +0 -0
  298. /package/{dist/assets → assets}/style2.css +0 -0
  299. /package/{dist/assets → assets}/styled-components.browser.esm-DPkS13KC.js +0 -0
  300. /package/{dist/assets → assets}/x-vPcWt3fC.js +0 -0
  301. /package/{dist/chat.d.ts → chat.d.ts} +0 -0
  302. /package/{dist/database.d.ts → database.d.ts} +0 -0
  303. /package/{dist/databaseId.d.ts → databaseId.d.ts} +0 -0
  304. /package/{dist/databaseTable.d.ts → databaseTable.d.ts} +0 -0
  305. /package/{dist/modelManage.d.ts → modelManage.d.ts} +0 -0
  306. /package/{dist/sensitive.d.ts → sensitive.d.ts} +0 -0
  307. /package/{dist/streamFilesReader.d.ts → streamFilesReader.d.ts} +0 -0
  308. /package/{dist/vite.svg → vite.svg} +0 -0
@@ -1,1065 +0,0 @@
1
- import React, { useEffect, useState, useMemo, useRef } from 'react';
2
- import AiChat, { AppStatusManager } from '@mxmweb/aichat';
3
- import request from '../../utils/gientechCommon/utils/request';
4
- import { isCancel } from 'axios';
5
- import dayjs from 'dayjs';
6
-
7
- import {
8
- getFeedbackList,
9
- handleCancelFeedBack,
10
- handleFeedBack,
11
- removeFilefromTempUpload,
12
- } from '../../utils/gientechCommon/utils/serverFn';
13
- import { getFileTypeByName, toCopy } from '../../utils/commonFn';
14
- import { uid } from 'uid';
15
-
16
- import AiChatBox from '../../utils/gientechCommon/components/Messages/AiChatBox';
17
- import UserChatBox from '../../utils/gientechCommon/components/Messages/UserChatBox';
18
- import GientechNewChatWelcome from '../../utils/gientechCommon/components/Messages/GientechNewChatWelcome';
19
- import AichatUseController from '../../utils/gientechCommon/hooks/AichatUseController';
20
- import FeedBackModal from '../../utils/gientechCommon/components/FeedBackModal';
21
- import { message, Modal } from 'antd';
22
- import FileManager from '../../utils/gientechCommon/components/FileManager';
23
- import AppLoading from '../../utils/gientechCommon/components/AppLoading';
24
- import DisplayLoading from '../../utils/gientechCommon/components/DisplayLoading';
25
- import AppError from '../../utils/gientechCommon/components/AppError';
26
- import DisplayError from '../../utils/gientechCommon/components/DisplayError';
27
- import { DefaultSenderConfig } from './constants';
28
- import { maxPollCount, maxPollInterval } from '../../utils/gientechCommon/configs/commonConfig';
29
- import { getNameFromFile } from '../../utils';
30
-
31
- interface UploadedFile {
32
- name: string;
33
- size: number;
34
- type: string;
35
- filePath: string;
36
- convertedFilePath?: string;
37
- uid: string;
38
- }
39
-
40
- interface EmptyMessageData {
41
- content: string;
42
- filePaths?: string;
43
- queryId: string;
44
- currentFiles?: UploadedFile[];
45
- }
46
-
47
- interface HeadlessChatAdopterProps {
48
- token: string;
49
- url?: string;
50
- configId?: string;
51
- useLogin?: boolean;
52
- styles?: any;
53
- welcomeContent?: string;
54
- onError?: (ems: any) => void;
55
- eventsEmit?: (eventName: string, data: any) => void;
56
- [key: string]: any;
57
- }
58
-
59
- export default function withHeadLessChatAdopter(WrappedComponent: React.ComponentType<any> = AiChat as any) {
60
- /**
61
- * GientechChatAdopter 高阶组件
62
- * 封装了与Gientech后端服务的接口对接、状态管理、事件处理等核心业务逻辑
63
- * @param {React.ComponentType} WrappedComponent - 需要包裹的基础聊天组件,默认为 AiChat
64
- */
65
- return function GientechChatAdopter({
66
- token,
67
- url = 'http://localhost:8888',
68
- welcomeContent = '欢迎来到小鲸智能助手,有什么能帮你的么?',
69
- styles,
70
- eventsEmit,
71
- onError,
72
- configId,
73
- ...rest
74
- }: HeadlessChatAdopterProps) {
75
- // =================================================================
76
- // State Management - 状态管理
77
- // =================================================================
78
- const [conversationList, setConversationList] = useState<any[]>([]); // 对话列表
79
- const [chatData, setChatData] = useState<any[]>([]); // 所有对话的聊天记录
80
- const [activeSessionId, setActiveSessionId] = useState<string | undefined>(undefined); // 当前激活的对话ID
81
- const [recommandQuestions, setRecommandQuestions] = useState<any[]>([]); // 推荐问题列表
82
- const [assistantList, setAssistantList] = useState<any[]>([]); // 智能体(助手)列表
83
- const [newAssistantId, setNewAssistantId] = useState<string | undefined>(undefined); // 新建对话时选择的智能体ID
84
- const [fileManagerOpen, setFileManagerOpen] = useState<boolean>(false); // 文件管理器抽屉的开关状态
85
- const [appStatus, setAppStatus] = useState<AppStatusManager>({
86
- display: 'ready', // 主聊天区域状态: ready, loading, processing, error, uploading
87
- sender: 'ready', // 发送器状态: ready, processing, error, uploading
88
- app: 'initializing', // 应用整体状态: initializing, ready, error
89
- });
90
- const [pendingFiles, setPendingFiles] = useState<any[]>([]); // 准备上传的文件列表
91
- const [dynamicSenderConfig, setDynamicSenderConfig] = useState(DefaultSenderConfig); // 动态的发送器配置
92
- const [fileStatuses, setFileStatuses] = useState<any[]>([]); // 用于跟踪每个上传文件的状态
93
- const [fileManagerData, setFileManagerData] = useState<{ uploadedFiles: any[] }>({
94
- uploadedFiles: [],
95
- });
96
- useEffect(() => {
97
- console.log('chatDatachatDatachatData', chatData);
98
- }, [chatData]);
99
- // =================================================================
100
- // Refs - 引用
101
- // =================================================================
102
- const prevActiveSessionId = useRef<string | undefined>(undefined); // 记录上一个激活的对话ID,用于对比变化
103
- const setUploadedFilesRef = useRef<(files: any[]) => void>(undefined); // 引用核心组件的文件上传方法
104
- const removeFileRef = useRef<(fileObj: any, idx: number, _type: string) => void>(undefined); // 引用核心组件的文件移除方法
105
-
106
- const [feedParam, setFeedParam] = useState<{
107
- queryId?: number | string | undefined;
108
- restult?: number;
109
- }>({});
110
- const [openFeed, setOpenFeed] = useState(false);
111
- const [feedBackList, setFeedBackList] = useState<any>([]);
112
- const stoppedRef = useRef(false);
113
-
114
- // =================================================================
115
- // Custom Hooks - 自定义钩子
116
- // =================================================================
117
- // 引入SSE控制器,封装了流式请求、消息管理等复杂逻辑
118
- const {
119
- api_startChat_re,
120
- addEmptyMessage,
121
- setLastEmptyMessage,
122
- stopStream,
123
- updateUserFilesMessage,
124
- } = AichatUseController({
125
- baseUrl: url,
126
- token,
127
- setChatData,
128
- activeSessionId,
129
- setAppStatus,
130
- setConversationList,
131
- });
132
-
133
- // =================================================================
134
- // Memoized Values - 缓存计算值
135
- // =================================================================
136
-
137
- // welcomeContent 伪消息唯一 id/time/queryId
138
- const welcomeMsgId = useRef(uid(32));
139
- const welcomeMsgQueryId = useRef(uid(32));
140
- const welcomeMsgTime = useRef(Date.now());
141
-
142
- /**
143
- * 将智能体列表转换为以ID为键的Map,便于快速查找
144
- */
145
- const assistantMap = useMemo(() => {
146
- const map: Record<string, any> = {};
147
- (assistantList || []).forEach(item => {
148
- map[item.id] = item;
149
- });
150
- return map;
151
- }, [assistantList]);
152
-
153
- /**
154
- * 根据 activeSessionId 从 chatData 中筛选出当前对话的数据, 并合并智能体信息
155
- */
156
- const currentChatData = useMemo(() => {
157
- let data = chatData.find((c: any) => c.id === activeSessionId) || {
158
- id: activeSessionId,
159
- messages: [],
160
- };
161
- let messages = data.messages || [];
162
- // 检查第一条是否已经是 welcome 消息,如果不是则插入
163
- if (welcomeContent && (messages.length === 0 || !messages[0]?.isDefault)) {
164
- messages = [
165
- {
166
- istype: 'ai',
167
- content: welcomeContent,
168
- time: welcomeMsgTime.current,
169
- clientSideId: welcomeMsgId.current,
170
- isWelcome: true,
171
- isDefault: true,
172
- queryId: welcomeMsgQueryId.current,
173
- },
174
- ...messages,
175
- ];
176
- }
177
- // 如果第一条已经是 isDefault: true 的欢迎消息,确保它的 isWelcome 字段存在
178
- if (messages[0]?.isDefault && !messages[0]?.isWelcome) {
179
- messages[0].isWelcome = true;
180
- }
181
- const assistantInfo = data.configId ? assistantMap[data.configId] : null;
182
- return {
183
- ...data,
184
- messages,
185
- assistantInfo,
186
- };
187
- }, [chatData, activeSessionId, assistantMap, welcomeContent]);
188
-
189
- /**
190
- * 用 useEffect 监听 currentChatData 自动同步
191
- */
192
- useEffect(() => {
193
- let uploaded: any[] = [];
194
- const lastAiMsg = [...(currentChatData.messages || [])]
195
- .reverse()
196
- .find((msg: any) => msg.istype === 'ai');
197
- if (lastAiMsg?.reference && lastAiMsg.resultType === 5) {
198
- try {
199
- const fileList = JSON.parse(lastAiMsg.reference);
200
- uploaded = fileList.map((f: any) => ({
201
- file: {
202
- name: f.name,
203
- size: Number(f.size?.replace('MB', '')) * 1024 * 1024 || 0,
204
- type: f.type,
205
- } as File,
206
- type: getFileTypeByName(f.name),
207
- status: 'uploaded' as const,
208
- url: f.filePath,
209
- convertedFilePath: f.convertedFilePath,
210
- uid: f.uid,
211
- preview: f.type === 'image' ? f.filePath : undefined,
212
- }));
213
- } catch (e) {}
214
- }
215
- // 只有 reference 有内容时才 set,避免无意义清空
216
- if (uploaded.length > 0) {
217
- setFileManagerData({ uploadedFiles: uploaded });
218
- }
219
- // 否则不 set,保持上一次的 uploadedFiles
220
- }, [currentChatData]);
221
-
222
- // =================================================================
223
- // Side Effects (useEffect) - 副作用钩子
224
- // =================================================================
225
-
226
- /**
227
- * 跟踪 activeSessionId 的变化:
228
- * 1. 清理上一个无消息的临时会话
229
- * 2. 更新推荐问题
230
- */
231
- useEffect(() => {
232
- // 切换会话时,检查上一个会话是否为临时且无消息
233
- if (prevActiveSessionId.current && prevActiveSessionId.current !== activeSessionId) {
234
- const prevId = prevActiveSessionId.current;
235
- const prevConv = conversationList.find(c => c.sessionId === prevId && c.isNew);
236
- const prevChat = chatData.find(c => c.id === prevId && c.isNew);
237
- const prevHasMsg = prevChat && prevChat.messages && prevChat.messages.length > 0;
238
- // 如果是临时的且没有消息,则自动删除
239
- if (prevConv && !prevHasMsg) {
240
- setConversationList(list => list.filter(c => c.sessionId !== prevId));
241
- setChatData(list => list.filter(c => c.id !== prevId));
242
- }
243
- }
244
- prevActiveSessionId.current = activeSessionId;
245
-
246
- // 更新推荐问题为当前对话的最后一个推荐问题
247
- const historyRQ =
248
- currentChatData.messages && currentChatData.messages.length > 0
249
- ? currentChatData.messages[currentChatData.messages.length - 1].recommendQuestion
250
- : [];
251
- setRecommandQuestions(historyRQ);
252
- }, [activeSessionId, conversationList, chatData, currentChatData.messages]);
253
-
254
- /**
255
- * 1. useEffect 只拉助手列表,自动新建会话
256
- */
257
- useEffect(() => {
258
- setAppStatus(prev => ({ ...prev, app: 'initializing' }));
259
-
260
- if ( token) {
261
- handleConversationCreate({ configId });
262
- }
263
- setAppStatus(prev => ({ ...prev, app: 'ready' }));
264
- }, [url, token, configId]);
265
-
266
- /**
267
- * 当 activeSessionId 变化时,获取对应的聊天记录
268
- */
269
- useEffect(() => {
270
- if (!activeSessionId) return;
271
- setAppStatus(prev => ({ ...prev, display: 'loading' }));
272
-
273
- setAppStatus(prev => ({ ...prev, display: 'ready' }));
274
- }, [activeSessionId, url, token]);
275
-
276
- /**
277
- * 监听文件数据变化,更新Sender上的角标
278
- */
279
- useEffect(() => {
280
- const totalFiles = fileManagerData.uploadedFiles.length;
281
- setDynamicSenderConfig(prev => {
282
- const newConfig = {
283
- ...prev,
284
- actions: prev.actions.map(action =>
285
- action.name === 'history' ? { ...action, badgeCount: totalFiles } : action
286
- ),
287
- };
288
- return newConfig;
289
- });
290
- }, [fileManagerData.uploadedFiles]);
291
- useEffect(() => {
292
- getFeedbackList({ url, token }, data => {
293
- setFeedBackList(data);
294
- });
295
- }, []);
296
- // =================================================================
297
- // Core Functions - 核心功能函数
298
- // =================================================================
299
-
300
- // 1. 在组件作用域定义控制器和轮询停止标志
301
- let uploadController: AbortController | null = null;
302
- let stopPoll: (() => void) | null = null;
303
-
304
- /**
305
- * 轮询文件解析状态
306
- * @param {string[]} uids - 文件UID列表
307
- * @param {(serverStatuses: any[]) => void} onStatusUpdate - 每次获取到新状态后的回调
308
- * @param {() => void} onComplete - 所有文件解析完成后的回调
309
- * @param {(errorMsg: string) => void} onFail - 轮询失败或超时的回调
310
- */
311
- const pollFileStatus = (
312
- uids: string[],
313
- onStatusUpdate: (serverStatuses: any[]) => void,
314
- onComplete: () => void,
315
- onFail: (errorMsg: string) => void
316
- ) => {
317
- const uidsString = uids.join(',');
318
- let pollCount = 0;
319
- //const maxPollCount = maxPollCount;
320
- stopPoll = () => {
321
- stoppedRef.current = true;
322
- };
323
-
324
- const checkStatus = async () => {
325
- if (stoppedRef.current) return;
326
- if (pollCount >= maxPollCount) {
327
- if (!stoppedRef.current) onFail('文件解析超时,请稍后重试');
328
- return;
329
- }
330
- pollCount++;
331
- try {
332
- const res = await request.get(
333
- `${url}/index/knowledgeBase/file/getFileStatusByUids?uids=${uidsString}`,
334
- {
335
- headers: { Authorization: token },
336
- }
337
- );
338
- if (stoppedRef.current) return;
339
- if (res.data.success) {
340
- const statuses = res.data.data;
341
- if (!stoppedRef.current) onStatusUpdate(statuses);
342
- const allDone = statuses.every((file: any) => file.status === 3);
343
- if (allDone) {
344
- if (!stoppedRef.current) onComplete();
345
- } else {
346
- if (!stoppedRef.current) setTimeout(checkStatus, maxPollInterval);
347
- }
348
- } else {
349
- if (!stoppedRef.current) onFail(res.data.errorMsg || '查询文件状态失败');
350
- }
351
- } catch (error) {
352
- onError?.(error);
353
- if (stoppedRef.current) return;
354
- onFail('查询文件状态时发生网络错误');
355
- }
356
- };
357
- checkStatus();
358
- };
359
-
360
- /**
361
- * 设置消息的反馈结果(赞/踩)
362
- * @param {string} queryId - 消息ID
363
- * @param {number} result - 反馈结果 (1: 赞, -1: 踩)
364
- */
365
- const setFeed = (queryId: any, restult: any) => {
366
- setChatData(chatList => {
367
- const newList = [...chatList];
368
- if (!newList[0]) return newList;
369
- newList[0] = {
370
- ...newList[0],
371
- messages: newList[0].messages.map((item: any) => {
372
- if (item.queryId === queryId) {
373
- return {
374
- ...item,
375
- feedbackResult: restult,
376
- };
377
- }
378
- return item;
379
- }),
380
- };
381
- return newList;
382
- });
383
- };
384
-
385
- /**
386
- * 获取指定queryId的推荐问题
387
- * @param {string} queryId - 消息ID
388
- */
389
- const fetchRecommendQuestions = async (queryId: string) => {
390
- if (!queryId) return;
391
- try {
392
- const res = await request.get(`${url}/qa/ai/recommendQuestion?queryId=${queryId}`, {
393
- headers: { Authorization: token },
394
- });
395
- setRecommandQuestions(res.data?.data || []);
396
- } catch (e) {
397
- onError?.(e);
398
- setRecommandQuestions([]);
399
- }
400
- };
401
-
402
- /**
403
- * 处理重新发送消息逻辑
404
- */
405
- function handleReSenderSend(data: any) {
406
- const { content, audioUrl, filePaths, queryId } = data;
407
- if (!content) return;
408
- const _fileUids = (
409
- typeof filePaths === 'string' && filePaths ? JSON.parse(filePaths) : filePaths || []
410
- ).map((item: any) => item.uid);
411
- const now = Date.now();
412
- setLastEmptyMessage({ now });
413
- if (!activeSessionId) return;
414
- setAppStatus(pre => {
415
- return {
416
- ...pre,
417
- display: 'processing',
418
- sender: 'processing',
419
- };
420
- });
421
-
422
- data.clearFn && data.clearFn();
423
- setConversationList(list =>
424
- list.map(c => (c.sessionId === activeSessionId ? { ...c, gmtModified: now } : c))
425
- );
426
- api_startChat_re(
427
- {
428
- configId: configId || currentChatData.configId,
429
- content,
430
- fileUids: _fileUids,
431
- lastDate: now,
432
- name: currentChatData.label || '',
433
- queryId: queryId,
434
- sessionId: activeSessionId,
435
- type: audioUrl ? 'audioUrl' : 'text',
436
- audioUrl,
437
- sysType: 'TEMPORARY',
438
- },
439
- gmtModified => {
440
- fetchRecommendQuestions(queryId);
441
- }
442
- );
443
- }
444
-
445
- /**
446
- * 处理消息发送(核心逻辑)
447
- * 1. 包含文件:先上传文件,成功后再发消息
448
- * 2. 新建会话:先调用创建会话接口,成功后再发消息
449
- * 3. 普通消息:直接发送
450
- * @param {object} data - 消息数据
451
- */
452
- async function handleSenderSend(data: any, clearFn: () => void) {
453
- const queryId = 'query-' + uid(32);
454
- // 1. 立即插入空壳消息
455
- let localCurrentFiles = undefined;
456
- if (data.files && data.files.length > 0) {
457
- localCurrentFiles = data.files.map((fileItem: any) => ({
458
- name: fileItem.file.name,
459
- size: fileItem.file.size,
460
- type: fileItem.file.type,
461
- filePath: fileItem.filePath || '',
462
- convertedFilePath: fileItem.convertedFilePath || '',
463
- uid: fileItem.uid || '',
464
- }));
465
- }
466
- addEmptyMessage({
467
- content: data.content || data.text || '',
468
- queryId,
469
- currentFiles: localCurrentFiles,
470
- filePaths: localCurrentFiles ? JSON.stringify(localCurrentFiles) : undefined,
471
- });
472
- setConversationList(list => {
473
- const newList = list
474
- .map(c =>
475
- c.sessionId === activeSessionId ? { ...c, isNew: false, gmtModified: Date.now() } : c
476
- )
477
- .sort((a, b) => b.gmtModified - a.gmtModified);
478
- setTimeout(() => {
479
- setActiveSessionId(activeSessionId);
480
- }, 300);
481
- return newList;
482
- });
483
- // 2. 有文件时,先上传并轮询,全部解析成功后再发起AI请求
484
- if (data.files && data.files.length > 0) {
485
- setAppStatus(pre => ({ ...pre, sender: 'uploading', display: 'uploading' }));
486
- uploadController = new AbortController();
487
- stoppedRef.current = false;
488
- const clientFileUids = data.files.map(
489
- () => `rc-upload-${Date.now()}-${Math.random().toString(36).slice(2)}`
490
- );
491
- const initialFileStatuses = data.files.map((fileItem: any, index: number) => ({
492
- ...fileItem,
493
- uid: clientFileUids[index],
494
- status: 'uploading',
495
- }));
496
- setFileStatuses(initialFileStatuses);
497
- const formData = new FormData();
498
- data.files.forEach((fileItem: any) => {
499
- formData.append('files', fileItem.file);
500
- });
501
- const sessionIdStr = activeSessionId ? String(activeSessionId) : '';
502
- formData.append('sessionId', sessionIdStr);
503
- formData.append('uids', clientFileUids.join(','));
504
- try {
505
- const response = await request.post(
506
- `${url}/index/knowledgeBase/file/uploadFiles`,
507
- formData,
508
- {
509
- headers: {
510
- Authorization: token,
511
- 'Content-Type': 'multipart/form-data',
512
- },
513
- signal: uploadController.signal,
514
- }
515
- );
516
- if (stoppedRef.current) return;
517
- if (
518
- response.data.success &&
519
- Array.isArray(response.data.data) &&
520
- response.data.data.length > 0
521
- ) {
522
- updateUserFilesMessage({
523
- currentFiles: response.data.data.map((item: any) => {
524
- return {
525
- filePath: item.filePath,
526
- name: item.fileName,
527
- type: getNameFromFile(item.fileName || item.fileName),
528
- };
529
- }),
530
- });
531
- setAppStatus(pre => ({ ...pre, sender: 'processing', display: 'analyzing' }));
532
- setFileStatuses(prev => prev.map(f => ({ ...f, status: 'parsing' })));
533
- const uploadedFilesData = response.data.data;
534
- const serverUids = uploadedFilesData.map((f: any) => f.uid);
535
- pollFileStatus(
536
- serverUids,
537
- serverStatuses => {
538
- setFileStatuses(currentLocalStatuses => {
539
- return currentLocalStatuses.map(localFile => {
540
- const correspondingServerFile = serverStatuses.find(
541
- (sf: any) => sf.uid === localFile.uid
542
- );
543
- if (correspondingServerFile) {
544
- switch (correspondingServerFile.status) {
545
- case 3:
546
- return { ...localFile, status: 'done' };
547
- case 4:
548
- return { ...localFile, status: 'error' };
549
- case 1:
550
- case 2:
551
- default:
552
- return { ...localFile, status: 'parsing' };
553
- }
554
- }
555
- return localFile;
556
- });
557
- });
558
- },
559
- // onComplete: 全部解析成功后才发起AI请求
560
- () => {
561
- clearFn?.();
562
- setAppStatus(pre => ({ ...pre, sender: 'processing', display: 'processing' }));
563
- setFileStatuses(prev => prev.map(f => ({ ...f, status: 'finished' })));
564
- const now = Date.now();
565
- api_startChat_re(
566
- {
567
- configId: configId || currentChatData.configId,
568
- content: data.content || data.text || '',
569
- fileUids: serverUids,
570
- lastDate: now,
571
- name: currentChatData.label || '',
572
- queryId: queryId,
573
- sessionId: String(activeSessionId || ''),
574
- type: 'text',
575
- audioUrl: '',
576
- sysType: 'TEMPORARY',
577
- },
578
- gmtModified => {
579
- fetchRecommendQuestions(queryId);
580
- }
581
- );
582
- },
583
- (errorMsg: string) => {
584
- setAppStatus(pre => ({ ...pre, display: 'ready', sender: 'ready' }));
585
- setFileStatuses(prev =>
586
- prev.map(f => ({ ...f, status: 'error', message: errorMsg }))
587
- );
588
- }
589
- );
590
- } else {
591
- const errorMsg = response.data.errorMsg || '文件上传失败';
592
- setAppStatus(pre => ({ ...pre, display: 'error', sender: 'ready' }));
593
- setFileStatuses(prev => prev.map(f => ({ ...f, status: 'error', message: errorMsg })));
594
- }
595
- } catch (error) {
596
- setAppStatus(pre => ({ ...pre, display: 'error', sender: 'ready' }));
597
- setFileStatuses(prev => prev.map(f => ({ ...f, status: 'error', message: '网络错误' })));
598
- }
599
- return;
600
- }
601
- // 3. 无文件,直接发起AI请求
602
- if (!activeSessionId) return;
603
- setAppStatus(pre => ({ ...pre, display: 'processing', sender: 'processing' }));
604
- const now = Date.now();
605
- setConversationList(list =>
606
- list.map(c => (c.sessionId === activeSessionId ? { ...c, gmtModified: now } : c))
607
- );
608
- clearFn?.();
609
- api_startChat_re(
610
- {
611
- configId: configId || currentChatData.configId,
612
- content: data.content || data.text || '',
613
- fileUids: [],
614
- lastDate: now,
615
- name: currentChatData.label || '',
616
- queryId: queryId,
617
- sessionId: activeSessionId,
618
- type: 'text',
619
- audioUrl: '',
620
- sysType: 'TEMPORARY',
621
- },
622
- gmtModified => {
623
- fetchRecommendQuestions(queryId);
624
- }
625
- );
626
- }
627
-
628
- // =================================================================
629
- // Event Handlers - 事件处理器
630
- // =================================================================
631
-
632
- /**
633
- * 处理点赞反馈
634
- */
635
- function handleThumbsup(data: any) {
636
- if (data.restult == 1) {
637
- handleCancelFeedBack({ url, token }, { queryId: data.queryId }, () => {
638
- setFeed(data.queryId, null);
639
- });
640
- } else {
641
- handleFeedBack({ url, token }, { restult: 1, queryId: data.queryId }, () => {
642
- setFeed(data.queryId, 1);
643
- });
644
- }
645
- }
646
-
647
- /**
648
- * 处理新建一个临时会话
649
- */
650
- function handleConversationCreate(data: any) {
651
- const sessionId = uid(32);
652
- // 优先用 props.configId
653
- const effectiveConfigId = configId || data?.configId || '';
654
- const newConversation = {
655
- sessionId,
656
- label: '未命名会话',
657
- gmtModified: Date.now(),
658
- searchConfigDTO: {},
659
- filePath: '',
660
- configId: effectiveConfigId,
661
- isNew: true,
662
- };
663
- setConversationList(list => [{ ...newConversation, messages: [] }, ...list]);
664
- setChatData(list => [{ id: sessionId, messages: [], ...newConversation }, ...list]);
665
- setActiveSessionId(sessionId);
666
- // 自动触发新建会话接口
667
-
668
- if ( token && url) {
669
- request
670
- .post(
671
- `${url}/qa/dialogue/create`,
672
- {
673
- configId: effectiveConfigId,
674
- label: `来自内嵌应用${uid(8)}`,
675
- sessionId,
676
- sysType: 'TEMPORARY',
677
- },
678
- {
679
- headers: { Authorization: token },
680
- }
681
- )
682
- .then(res => {
683
- const newSession = res.data.data;
684
- if (newSession?.sessionId) {
685
- setConversationList(list => [
686
- { ...newSession, messages: [] },
687
- ...list.filter(c => c.sessionId !== sessionId),
688
- ]);
689
- setChatData(list => [
690
- { id: newSession.sessionId, messages: [], ...newSession },
691
- ...list.filter(c => c.id !== sessionId),
692
- ]);
693
- setActiveSessionId(newSession.sessionId);
694
- }
695
- })
696
- .catch(err => {
697
- onError?.(err);
698
- });
699
- }
700
- }
701
-
702
- /**
703
- * 文件管理器:处理文件选择后的上传
704
- */
705
- const handleFileManagerUpload = (fileList: FileList) => {
706
- // 1. 收集所有已经存在的文件名
707
- const existingFileNames = new Set<string>([
708
- ...fileManagerData.uploadedFiles.map((f: any) => f.file.name as string),
709
- ...pendingFiles.map((f: any) => f.file.name as string),
710
- ]);
711
-
712
- const newFiles: { file: File; type: string; status: string; preview?: string }[] = [];
713
- const duplicateFileNames = new Set<string>();
714
-
715
- // 2. 遍历新选择的文件,筛选出重复项和有效项
716
- Array.from(fileList).forEach(file => {
717
- if (existingFileNames.has(file.name)) {
718
- duplicateFileNames.add(file.name);
719
- } else {
720
- newFiles.push({
721
- file,
722
- type: getFileTypeByName(file.name),
723
- status: 'pending',
724
- preview: file.type.startsWith('image') ? URL.createObjectURL(file) : undefined,
725
- });
726
- existingFileNames.add(file.name); // 添加到Set中,以防本次上传的文件之间有重复
727
- }
728
- });
729
-
730
- // 3. 如果有重复,发出警告
731
- if (duplicateFileNames.size > 0) {
732
- message.warning(`不能上传同名文件: ${Array.from(duplicateFileNames).join(', ')}`);
733
- }
734
-
735
- // 4. 将有效的文件添加到待上传列表
736
- if (newFiles.length > 0) {
737
- setPendingFiles(prev => [...prev, ...newFiles]);
738
- // 直接同步到核心发送器组件
739
- setUploadedFilesRef.current?.(newFiles);
740
- }
741
- };
742
-
743
- /**
744
- * 文件管理器:处理文件移除
745
- */
746
- const handleFileManagerRemove = (fileObj: any, idx: number, _type: string) => {
747
- removeFileRef.current?.(fileObj, idx, _type);
748
- };
749
-
750
- /**
751
- * 处理会话列表项点击
752
- */
753
- function handleItemClick(data: any) {
754
- if (data?.sessionId && data.sessionId !== activeSessionId) {
755
- setActiveSessionId(data.sessionId);
756
- setAppStatus(prev => ({ ...prev, sender: 'ready' }));
757
- // 点击会话时,使用其最后一条AI消息的推荐问题
758
- const conv = chatData.find(c => c.id === data.sessionId);
759
- if (conv && conv.messages && conv.messages.length > 0) {
760
- const lastAiMsg = [...conv.messages].reverse().find((m: any) => m.istype === 'ai');
761
- if (lastAiMsg && lastAiMsg.recommendQuestion) {
762
- setRecommandQuestions(lastAiMsg.recommendQuestion);
763
- } else {
764
- setRecommandQuestions([]);
765
- }
766
- } else {
767
- setRecommandQuestions([]);
768
- }
769
- }
770
- }
771
-
772
- // =================================================================
773
- // Local State Updaters - 本地状态更新 (供事件发射器使用)
774
- // =================================================================
775
-
776
- const handleFeedDownConfirm = (data: any) => {
777
- handleFeedBack({ url, token, }, { ...data, ...feedParam, restult: 0 }, () => {
778
- setFeed(feedParam.queryId, 0);
779
- });
780
- };
781
-
782
- // =================================================================
783
- // Event Emitter - 事件分发器
784
- // =================================================================
785
- /**
786
- * 统一事件分发器,连接业务逻辑与所有子组件的事件
787
- * @param {string} eventName - 事件名称
788
- * @param {any} data - 事件数据
789
- */
790
- const mergedEventsEmit = (eventName: string, data: any) => {
791
- console.log(`[Event] ${eventName}`, data);
792
- switch (eventName) {
793
- // --- 对话列表事件 ---
794
- case 'conversation:item_click':
795
- handleItemClick(data);
796
- break;
797
-
798
- case 'files:finished_animation_complete':
799
- setFileStatuses([]);
800
- break;
801
-
802
- case 'conversation:create':
803
- handleConversationCreate(data);
804
- break;
805
- case 'conversation:new_assistant_change':
806
- setNewAssistantId(data.assistantId);
807
- break;
808
-
809
- // --- 发送器事件 ---
810
- case 'sender:send':
811
- handleSenderSend(data, data.clearFn);
812
- break;
813
- case 'sender:send_recommandQuestion':
814
- // 点击推荐问题,视作一次普通发送
815
- handleSenderSend(data, data.clearFn);
816
- break;
817
- case 'sender:action_history':
818
- setFileManagerOpen(true);
819
- break;
820
- case 'sender:stop':
821
- stoppedRef.current = true;
822
- if (uploadController) {
823
- uploadController.abort();
824
- uploadController = null;
825
- }
826
- if (stopPoll) {
827
- stopPoll();
828
- stopPoll = null;
829
- }
830
- setAppStatus(pre => ({ ...pre, display: 'ready', sender: 'ready' }));
831
- setFileStatuses([]);
832
- stopStream?.();
833
- break;
834
- case 'sender:clear':
835
- data.clearFn?.();
836
- break;
837
- case 'sender:configChange':
838
- // 配置项变化,可在此处理
839
- break;
840
-
841
- // --- 消息卡片事件 ---
842
- case 'action_copy:click':
843
- if (data) {
844
- toCopy(data.content, data.event);
845
- }
846
- break;
847
- case 'action_retry':
848
- handleReSenderSend(data);
849
- break;
850
- case 'action_thumbsup':
851
- handleThumbsup(data);
852
- break;
853
- case 'action_thumbsdown':
854
- if (data.restult === 0) {
855
- handleCancelFeedBack({ url, token }, { queryId: data.queryId }, () => {
856
- setFeed(data.queryId, null);
857
- });
858
- } else {
859
- setFeedParam(data);
860
- setOpenFeed(true);
861
- }
862
- break;
863
- // --- 文件管理器上传文件删除事件,透传到业务层 ---
864
- case 'uploaded_file:removeFromTemp': {
865
- console.log('[DEBUG] mergedEventsEmit uploaded_file:removeFromTemp 事件', data);
866
-
867
- const uid = data?.file?.uid;
868
- if (!uid) {
869
- console.warn('[DEBUG] 缺少uid,无法删除临时文件', data);
870
- break;
871
- }
872
- // 获取当前对话最后一条 AI 消息的 queryId
873
- const lastAiMsg = [...(currentChatData.messages || [])]
874
- .reverse()
875
- .find((msg: any) => msg.istype === 'user');
876
- const queryId = lastAiMsg?.queryId;
877
- console.log('[DEBUG] mergedEventsEmit 获取到 queryId', queryId, lastAiMsg);
878
-
879
- removeFilefromTempUpload({ url, token }, { uid, queryId }, (success, res) => {
880
- console.log('[DEBUG] removeFilefromTempUpload 回调触发', { success, res });
881
- if (success) {
882
- message.success('文件已从临时知识库移除');
883
- // 用后端返回的新data数组(新文件列表)更新本地uploadedFiles
884
- //console.log('[DEBUG] removeFilefromTempUpload 回调 true,res:', res, Array.isArray(res.data && res.data.data));
885
- if (res && Array.isArray(res.data && res.data.data)) {
886
- const uploaded = res.data.data.map((f: any) => {
887
- const fileName = f.name || f.fileName || '';
888
- return {
889
- file: {
890
- name: fileName,
891
- size: Number(f.size?.replace('MB', '')) * 1024 * 1024 || 0,
892
- type: f.type,
893
- } as File,
894
- type: getFileTypeByName(fileName),
895
- status: 'uploaded' as const,
896
- url: f.filePath,
897
- convertedFilePath: f.convertedFilePath,
898
- uid: f.uid,
899
- preview: f.type === 'image' ? f.filePath : undefined,
900
- };
901
- });
902
- // console.log('[DEBUG] uploaded 构造完成:', uploaded, '当前 fileManagerData:', fileManagerData);
903
- setFileManagerData({ uploadedFiles: uploaded });
904
- } else {
905
- //console.log('[DEBUG] res.data.data 不是数组', res && res.data && res.data.data);
906
- }
907
- } else {
908
- console.log('[DEBUG] removeFilefromTempUpload 回调 false,res:', res);
909
- message.error('文件移除失败');
910
- }
911
- });
912
- break;
913
- }
914
- // --- 文件管理器事件 ---
915
- case 'fileManager:change': {
916
- const files = Array.isArray(data?.uploadedFiles) ? data.uploadedFiles : [];
917
- setPendingFiles(files);
918
- // 保存核心组件传递的文件处理函数引用
919
- if (typeof data?.setUploadedFiles === 'function') {
920
- setUploadedFilesRef.current = data.setUploadedFiles;
921
- removeFileRef.current = data.removeFile;
922
- }
923
- break;
924
- }
925
-
926
- default:
927
- // 其他未处理事件可继续向上层抛出
928
- eventsEmit?.(eventName, data);
929
- }
930
- };
931
-
932
- // =================================================================
933
- // Component & UI Configuration - 组件及UI配置
934
- // =================================================================
935
-
936
- /**
937
- * Sidebar 配置
938
- */
939
- const sidebar = undefined;
940
-
941
- /**
942
- * 业务层自定义组件
943
- */
944
- const businessCustomComponents: { [key: string]: any } = {
945
- AiChatBox: (msg: any, idx: number) => {
946
- const isLastMessage = idx === (currentChatData?.messages?.length || 0) - 1;
947
-
948
- // 根据消息的 status 和 appStatus 来确定 displayStatus
949
- let displayStatus = 'ready';
950
- if (isLastMessage) {
951
- // 优先使用消息的 status 字段
952
- if (msg.status !== undefined) {
953
- switch (msg.status) {
954
- case 0: // StatusType.Pending
955
- displayStatus = 'thinking';
956
- break;
957
- case 1: // StatusType.Process
958
- displayStatus = 'processing';
959
- break;
960
- case 2: // StatusType.Done
961
- displayStatus = 'ready';
962
- break;
963
- case 3: // StatusType.Error
964
- displayStatus = 'error';
965
- break;
966
- default:
967
- displayStatus = appStatus.display;
968
- }
969
- } else {
970
- // 如果没有 status 字段,使用 appStatus.display
971
- displayStatus = appStatus.display;
972
- }
973
- }
974
- // console.log('AiChatBox', msg);
975
- return (
976
- <AiChatBox
977
- {...msg}
978
- displayStatus={displayStatus}
979
- eventsEmit={mergedEventsEmit}
980
- defaultAnswer={
981
- currentChatData?.searchConfigDTO?.defaultAnswer ||
982
- '不知道什么原因我们没能查到你要的问题*-*'
983
- }
984
- styles={styles}
985
- from="headless"
986
- />
987
- );
988
- },
989
- LogoBox: () => <div className="text-2xl w-full text-center font-bold">小鲸智能助手</div>,
990
- DisplayLoading: () => <DisplayLoading />,
991
- DisplayError: () => <DisplayError />,
992
- AppError: () => <AppError />,
993
- AppLoading: () => <AppLoading />,
994
- UserChatBox: (msg: any, idx: number) => {
995
- // console.log('UserChatBox files:', msg.files, 'currentFiles:', msg.currentFiles, 'filePaths:', msg.filePaths);
996
- return (
997
- <UserChatBox
998
- {...msg}
999
- eventsEmit={mergedEventsEmit}
1000
- isLast={idx === (currentChatData?.messages?.length || 0) - 2}
1001
- styles={styles}
1002
- idx={idx}
1003
- />
1004
- );
1005
- },
1006
- WelcomeComponent: () => (
1007
- <GientechNewChatWelcome
1008
- eventsEmit={mergedEventsEmit}
1009
- assistantList={assistantList}
1010
- styles={styles}
1011
- // defaultSelect={newAssistantId || assistantList[0]?.id}
1012
- />
1013
- ),
1014
- };
1015
-
1016
- /**
1017
- * 合并外部传入和业务默认的自定义组件,外部优先
1018
- */
1019
- const mergedCustomComponents: { [key: string]: any } = { ...businessCustomComponents };
1020
- if (rest.CustomComponents) {
1021
- Object.keys(rest.CustomComponents).forEach(key => {
1022
- const val = rest.CustomComponents?.[key];
1023
- if (val !== undefined) {
1024
- mergedCustomComponents[key] = val;
1025
- }
1026
- });
1027
- }
1028
-
1029
- // =================================================================
1030
- // Render - 渲染
1031
- // =================================================================
1032
- return (
1033
- <>
1034
- <FileManager
1035
- open={fileManagerOpen}
1036
- onCancel={() => setFileManagerOpen(false)}
1037
- files={fileManagerData.uploadedFiles}
1038
- currentFiles={pendingFiles}
1039
- onUpload={handleFileManagerUpload}
1040
- onRemoveFile={handleFileManagerRemove}
1041
- styles={styles}
1042
- eventsEmit={mergedEventsEmit}
1043
- />
1044
-
1045
- <WrappedComponent
1046
- activeSessionId={activeSessionId}
1047
- status={appStatus}
1048
- chatData={currentChatData}
1049
- sidebar={sidebar}
1050
- recommandQuestions={recommandQuestions}
1051
- eventsEmit={mergedEventsEmit}
1052
- styles={styles}
1053
- senderConfig={dynamicSenderConfig}
1054
- fileUploadStatus={fileStatuses}
1055
- CustomComponents={mergedCustomComponents} />
1056
- <FeedBackModal
1057
- open={openFeed}
1058
- feedBackList={feedBackList}
1059
- setOpen={setOpenFeed}
1060
- handleConfirm={handleFeedDownConfirm}
1061
- />
1062
- </>
1063
- );
1064
- };
1065
- }