@gientech/modual 1.3.3 → 1.3.4

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 (307) hide show
  1. package/README.md +129 -129
  2. package/{dist/assets → assets}/database.svg +11 -11
  3. package/{src/modules/database/assets → assets}/database_add.svg +53 -53
  4. package/{dist/assets → assets}/database_connect.svg +66 -66
  5. package/{dist/assets → assets}/database_upload.svg +29 -29
  6. package/{dist/assets → assets}/defaultWeLogo.svg +14 -14
  7. package/{dist/assets/index-mPgEc8KC.js → assets/index-CDNF071H.js} +38 -38
  8. package/{dist/assets/index-XvC_4jDB.js → assets/index-Ce4td48i.js} +20 -20
  9. package/{dist/assets → assets}/mysql.svg +14 -14
  10. package/{dist/chat.js → chat.js} +2 -2
  11. package/database.js +20 -0
  12. package/{dist/databaseId.js → databaseId.js} +1 -1
  13. package/{dist/databaseTable.js → databaseTable.js} +1 -1
  14. package/{dist/modelManage.js → modelManage.js} +1 -1
  15. package/package.json +39 -83
  16. package/{dist/sensitive.js → sensitive.js} +1 -1
  17. package/{dist/streamFilesReader.js → streamFilesReader.js} +10 -10
  18. package/{dist/worker → worker}/pdf.worker.min.js +21 -21
  19. package/.editorconfig +0 -38
  20. package/.prettierignore +0 -16
  21. package/.prettierrc +0 -17
  22. package/USAGE.md +0 -191
  23. package/bash.exe.stackdump +0 -40
  24. package/components.json +0 -21
  25. package/dist/README.md +0 -129
  26. package/dist/assets/database_add.svg +0 -53
  27. package/dist/database.js +0 -20
  28. package/dist/package.json +0 -56
  29. package/doc_assets/2.png +0 -0
  30. package/doc_assets/demo.md +0 -27
  31. package/doc_assets/demos/dist-app/assets/index.Dh-ZAS9Z.css +0 -2
  32. package/doc_assets/demos/dist-app/assets/index.Dv8KVW18.js +0 -23699
  33. package/doc_assets/demos/dist-app/assets/index.Dv8KVW18.js.map +0 -1
  34. package/doc_assets/demos/dist-app/index.html +0 -14
  35. package/doc_assets/demos/dist-app/vite.svg +0 -1
  36. package/doc_assets/images/1.png +0 -0
  37. package/doc_assets/images/3.png +0 -0
  38. package/doc_assets/images/component-screenshot.png +0 -1
  39. package/doc_assets/install.md +0 -5
  40. package/eslint.config.js +0 -92
  41. package/index.html +0 -13
  42. package/postcss.config.cjs +0 -19
  43. package/public/vite.svg +0 -1
  44. package/public/worker/pdf.worker.min.js +0 -22
  45. package/scripts/README.md +0 -133
  46. package/scripts/build-demo.js +0 -88
  47. package/scripts/demo-selector.js +0 -216
  48. package/scripts/dev-demo.js +0 -76
  49. package/scripts/preview-demo.js +0 -130
  50. package/scripts/run-demo.bat +0 -34
  51. package/src/assets/img/downArrow.png +0 -0
  52. package/src/assets/img/excel.png +0 -0
  53. package/src/assets/img/img.png +0 -0
  54. package/src/assets/img/pdf.png +0 -0
  55. package/src/assets/img/ppt.png +0 -0
  56. package/src/assets/img/txt.png +0 -0
  57. package/src/assets/img/word.png +0 -0
  58. package/src/assets/login/homeBg.png +0 -0
  59. package/src/assets/login/left.jpg +0 -0
  60. package/src/assets/login/logoImg.png +0 -0
  61. package/src/examples/LoginPage/index.tsx +0 -18
  62. package/src/examples/aaa/index.tsx +0 -3758
  63. package/src/examples/chat/components/DrawerGraphPreview.tsx +0 -78
  64. package/src/examples/chat/index.tsx +0 -190
  65. package/src/examples/gientechStreamFilesReader/index.tsx +0 -1016
  66. package/src/examples/ragDatabaseDataPage/index.tsx +0 -36
  67. package/src/examples/ragDatabaseIdPage/index.tsx +0 -44
  68. package/src/examples/ragDatabasePage/index.tsx +0 -36
  69. package/src/examples/ragModelManagePage/index.tsx +0 -37
  70. package/src/examples/ragSearchPage/index.tsx +0 -0
  71. package/src/examples/ragSensitiveWordsPage/index.tsx +0 -32
  72. package/src/examples/streamFiles/index.tsx +0 -384
  73. package/src/lib_enter.ts +0 -38
  74. package/src/main.tsx +0 -5
  75. package/src/main.tsx.backup +0 -5
  76. package/src/modules/chat/Conversations/Item.tsx +0 -167
  77. package/src/modules/chat/Conversations/List.tsx +0 -143
  78. package/src/modules/chat/Conversations/groupByTime.ts +0 -39
  79. package/src/modules/chat/Conversations/index.tsx +0 -212
  80. package/src/modules/chat/constants.tsx +0 -33
  81. package/src/modules/chat/data.txt +0 -82
  82. package/src/modules/chat/index.tsx +0 -1908
  83. package/src/modules/chat/types.ts +0 -17
  84. package/src/modules/database/CreateModal.tsx +0 -398
  85. package/src/modules/database/assets/Doris.png +0 -0
  86. package/src/modules/database/assets/PostgreSQL.png +0 -0
  87. package/src/modules/database/assets/SQLServer.png +0 -0
  88. package/src/modules/database/assets/database.svg +0 -11
  89. package/src/modules/database/assets/database_connect.svg +0 -66
  90. package/src/modules/database/assets/database_upload.svg +0 -29
  91. package/src/modules/database/assets/empty.png +0 -0
  92. package/src/modules/database/assets/mysql.svg +0 -14
  93. package/src/modules/database/index.tsx +0 -466
  94. package/src/modules/database/server.ts +0 -196
  95. package/src/modules/databaseId/CustomCom.tsx +0 -156
  96. package/src/modules/databaseId/EditConfig.tsx +0 -268
  97. package/src/modules/databaseId/UploadDrawer.tsx +0 -520
  98. package/src/modules/databaseId/assets/aiOptimize.svg +0 -10
  99. package/src/modules/databaseId/assets/empty.png +0 -0
  100. package/src/modules/databaseId/assets/template.svg +0 -6
  101. package/src/modules/databaseId/assets/upload.svg +0 -9
  102. package/src/modules/databaseId/assets/useTemp.svg +0 -6
  103. package/src/modules/databaseId/index.tsx +0 -734
  104. package/src/modules/databaseId/server.ts +0 -286
  105. package/src/modules/databaseId/style.css +0 -5
  106. package/src/modules/databaseTable/EditRowDrawer.tsx +0 -119
  107. package/src/modules/databaseTable/index.tsx +0 -357
  108. package/src/modules/databaseTable/server.ts +0 -180
  109. package/src/modules/headlessChat/constants.tsx +0 -32
  110. package/src/modules/headlessChat/index.tsx +0 -1065
  111. package/src/modules/headlessChat/types.ts +0 -23
  112. package/src/modules/login/components/Login/LoginBox/index.tsx +0 -102
  113. package/src/modules/login/components/Login/RegisterBox/index.tsx +0 -180
  114. package/src/modules/login/components/Login/index.tsx +0 -100
  115. package/src/modules/login/index.tsx +0 -106
  116. package/src/modules/login/style.css +0 -3
  117. package/src/modules/login/useServices.ts +0 -53
  118. package/src/modules/login/utils.ts +0 -42
  119. package/src/modules/modelManage/ConfigDrawer.tsx +0 -249
  120. package/src/modules/modelManage/assets/empty.png +0 -0
  121. package/src/modules/modelManage/const.ts +0 -50
  122. package/src/modules/modelManage/index.tsx +0 -439
  123. package/src/modules/modelManage/server.ts +0 -185
  124. package/src/modules/nodegraph/index.tsx +0 -1
  125. package/src/modules/search/assets/Icon-history.svg +0 -8
  126. package/src/modules/search/assets/answerAwartar.png +0 -0
  127. package/src/modules/search/assets/doc.png +0 -0
  128. package/src/modules/search/assets/genera.gif +0 -0
  129. package/src/modules/search/assets/icon-robot.svg +0 -9
  130. package/src/modules/search/assets/icon-search-bar.svg +0 -14
  131. package/src/modules/search/assets/icon-sub-title.svg +0 -3
  132. package/src/modules/search/assets/icon-title.svg +0 -9
  133. package/src/modules/search/assets/icon-zoomOut.svg +0 -9
  134. package/src/modules/search/assets/iconAi.svg +0 -9
  135. package/src/modules/search/assets/pdf.png +0 -0
  136. package/src/modules/search/assets/ppt.png +0 -0
  137. package/src/modules/search/assets/search.svg +0 -3
  138. package/src/modules/search/assets/selected.svg +0 -4
  139. package/src/modules/search/assets/txt.png +0 -0
  140. package/src/modules/search/assets/xls.png +0 -0
  141. package/src/modules/search/components/AssisSelect.tsx +0 -137
  142. package/src/modules/search/components/Editor/ChatViewEditor.tsx +0 -261
  143. package/src/modules/search/components/Editor/aichat.css +0 -1
  144. package/src/modules/search/components/Editor/constant.ts +0 -13
  145. package/src/modules/search/components/Editor/index.tsx +0 -113
  146. package/src/modules/search/components/Editor/plugins/autofomatRules.ts +0 -332
  147. package/src/modules/search/components/Editor/plugins/convertImgPlugins.tsx +0 -20
  148. package/src/modules/search/components/Editor/plugins/createIndexes.tsx +0 -38
  149. package/src/modules/search/components/Editor/plugins/displayer.ts +0 -298
  150. package/src/modules/search/components/Editor/plugins/imageClick.tsx +0 -32
  151. package/src/modules/search/components/Editor/plugins/myplugin.tsx +0 -98
  152. package/src/modules/search/components/Editor/ui/avatar.tsx +0 -19
  153. package/src/modules/search/components/Editor/ui/blockquote-element.tsx +0 -21
  154. package/src/modules/search/components/Editor/ui/button.tsx +0 -58
  155. package/src/modules/search/components/Editor/ui/calendar.tsx +0 -68
  156. package/src/modules/search/components/Editor/ui/caption.tsx +0 -46
  157. package/src/modules/search/components/Editor/ui/checkbox.tsx +0 -27
  158. package/src/modules/search/components/Editor/ui/code-block-combobox.tsx +0 -188
  159. package/src/modules/search/components/Editor/ui/code-block-element.css +0 -434
  160. package/src/modules/search/components/Editor/ui/code-block-element.tsx +0 -39
  161. package/src/modules/search/components/Editor/ui/code-leaf.tsx +0 -24
  162. package/src/modules/search/components/Editor/ui/code-line-element.tsx +0 -10
  163. package/src/modules/search/components/Editor/ui/code-syntax-leaf.tsx +0 -21
  164. package/src/modules/search/components/Editor/ui/column-element.tsx +0 -30
  165. package/src/modules/search/components/Editor/ui/column-group-element.tsx +0 -94
  166. package/src/modules/search/components/Editor/ui/command.tsx +0 -75
  167. package/src/modules/search/components/Editor/ui/comment-avatar.tsx +0 -22
  168. package/src/modules/search/components/Editor/ui/comment-create-form.tsx +0 -37
  169. package/src/modules/search/components/Editor/ui/comment-item.tsx +0 -74
  170. package/src/modules/search/components/Editor/ui/comment-leaf.tsx +0 -49
  171. package/src/modules/search/components/Editor/ui/comment-more-dropdown.tsx +0 -42
  172. package/src/modules/search/components/Editor/ui/comment-reply-items.tsx +0 -22
  173. package/src/modules/search/components/Editor/ui/comment-resolve-button.tsx +0 -32
  174. package/src/modules/search/components/Editor/ui/comment-value.tsx +0 -34
  175. package/src/modules/search/components/Editor/ui/comments-popover.tsx +0 -63
  176. package/src/modules/search/components/Editor/ui/date-element.tsx +0 -83
  177. package/src/modules/search/components/Editor/ui/dialog.tsx +0 -63
  178. package/src/modules/search/components/Editor/ui/draggable.tsx +0 -177
  179. package/src/modules/search/components/Editor/ui/dropdown-menu.tsx +0 -180
  180. package/src/modules/search/components/Editor/ui/emoji-input-element.tsx +0 -85
  181. package/src/modules/search/components/Editor/ui/excalidraw-element.tsx +0 -28
  182. package/src/modules/search/components/Editor/ui/fixed-toolbar-buttons.tsx +0 -76
  183. package/src/modules/search/components/Editor/ui/fixed-toolbar.tsx +0 -8
  184. package/src/modules/search/components/Editor/ui/floating-toolbar-buttons.tsx +0 -51
  185. package/src/modules/search/components/Editor/ui/floating-toolbar.tsx +0 -77
  186. package/src/modules/search/components/Editor/ui/heading-element.tsx +0 -48
  187. package/src/modules/search/components/Editor/ui/highlight-leaf.tsx +0 -17
  188. package/src/modules/search/components/Editor/ui/hr-element.tsx +0 -30
  189. package/src/modules/search/components/Editor/ui/icons.tsx +0 -267
  190. package/src/modules/search/components/Editor/ui/image-element.tsx +0 -74
  191. package/src/modules/search/components/Editor/ui/inline-combobox.tsx +0 -368
  192. package/src/modules/search/components/Editor/ui/input.tsx +0 -25
  193. package/src/modules/search/components/Editor/ui/insert-dropdown-menu.tsx +0 -218
  194. package/src/modules/search/components/Editor/ui/kbd-leaf.tsx +0 -20
  195. package/src/modules/search/components/Editor/ui/link-element.tsx +0 -29
  196. package/src/modules/search/components/Editor/ui/link-floating-toolbar.tsx +0 -161
  197. package/src/modules/search/components/Editor/ui/list-element.tsx +0 -30
  198. package/src/modules/search/components/Editor/ui/mark-toolbar-button.tsx +0 -24
  199. package/src/modules/search/components/Editor/ui/media-embed-element.tsx +0 -133
  200. package/src/modules/search/components/Editor/ui/media-popover.tsx +0 -97
  201. package/src/modules/search/components/Editor/ui/mention-element.tsx +0 -43
  202. package/src/modules/search/components/Editor/ui/mention-input-element.tsx +0 -141
  203. package/src/modules/search/components/Editor/ui/mode-dropdown-menu.tsx +0 -93
  204. package/src/modules/search/components/Editor/ui/more-dropdown-menu.tsx +0 -67
  205. package/src/modules/search/components/Editor/ui/paragraph-element.tsx +0 -4
  206. package/src/modules/search/components/Editor/ui/placeholder.tsx +0 -52
  207. package/src/modules/search/components/Editor/ui/popover.tsx +0 -32
  208. package/src/modules/search/components/Editor/ui/resizable.tsx +0 -66
  209. package/src/modules/search/components/Editor/ui/separator.tsx +0 -25
  210. package/src/modules/search/components/Editor/ui/style.less +0 -12
  211. package/src/modules/search/components/Editor/ui/table-cell-element.tsx +0 -143
  212. package/src/modules/search/components/Editor/ui/table-element.tsx +0 -243
  213. package/src/modules/search/components/Editor/ui/table-row-element.tsx +0 -22
  214. package/src/modules/search/components/Editor/ui/tableValue.tsx +0 -135
  215. package/src/modules/search/components/Editor/ui/todo-list-element.tsx +0 -43
  216. package/src/modules/search/components/Editor/ui/toggle-element.tsx +0 -31
  217. package/src/modules/search/components/Editor/ui/toolbar.tsx +0 -157
  218. package/src/modules/search/components/Editor/ui/tooltip.tsx +0 -65
  219. package/src/modules/search/components/Editor/ui/turn-into-dropdown-menu.tsx +0 -160
  220. package/src/modules/search/components/Editor/ui/with-draggables.tsx +0 -175
  221. package/src/modules/search/components/FileList.tsx +0 -287
  222. package/src/modules/search/components/ImageGroupView/index.tsx +0 -85
  223. package/src/modules/search/components/ResultContent.tsx +0 -232
  224. package/src/modules/search/components/SearchInput.tsx +0 -232
  225. package/src/modules/search/components/SearchLanding.tsx +0 -74
  226. package/src/modules/search/components/SearchView.tsx +0 -563
  227. package/src/modules/search/components/SimpleEditor.tsx +0 -158
  228. package/src/modules/search/components/SimpleFileList.tsx +0 -215
  229. package/src/modules/search/index.tsx +0 -10
  230. package/src/modules/search/reademe.md +0 -1
  231. package/src/modules/search/servers/apis.tsx +0 -19
  232. package/src/modules/search/servers/index.ts +0 -184
  233. package/src/modules/search/style.less +0 -503
  234. package/src/modules/search/type.ts +0 -22
  235. package/src/modules/search/utils.ts +0 -34
  236. package/src/modules/sensitive/index.tsx +0 -313
  237. package/src/modules/sensitive/server.ts +0 -122
  238. package/src/modules/streamFilesReader/GientechStreamReader.tsx +0 -1555
  239. package/src/modules/streamFilesReader/components/Header/Toolbar.tsx +0 -0
  240. package/src/modules/streamFilesReader/components/Header/index.tsx +0 -297
  241. package/src/modules/streamFilesReader/index.tsx +0 -3
  242. package/src/style.css +0 -6
  243. package/src/type.d.ts +0 -0
  244. package/src/utils/commonFn.tsx +0 -111
  245. package/src/utils/gientechCommon/components/AppError.tsx +0 -32
  246. package/src/utils/gientechCommon/components/AppLoading.tsx +0 -75
  247. package/src/utils/gientechCommon/components/DeleteModal.tsx +0 -75
  248. package/src/utils/gientechCommon/components/DisplayError.tsx +0 -33
  249. package/src/utils/gientechCommon/components/DisplayLoading.tsx +0 -38
  250. package/src/utils/gientechCommon/components/FeedBackModal.tsx +0 -310
  251. package/src/utils/gientechCommon/components/FileCardCommon.tsx +0 -82
  252. package/src/utils/gientechCommon/components/FileManager/index.tsx +0 -390
  253. package/src/utils/gientechCommon/components/FileManager/style.css +0 -5
  254. package/src/utils/gientechCommon/components/Messages/GientechNewChatWelcome.tsx +0 -296
  255. package/src/utils/gientechCommon/components/Messages/ReferenceCard.tsx +0 -339
  256. package/src/utils/gientechCommon/components/Messages/RetriveItem.tsx +0 -245
  257. package/src/utils/gientechCommon/components/Messages/WebRetriveItem.tsx +0 -209
  258. package/src/utils/gientechCommon/components/Messages/defaultBot.png +0 -0
  259. package/src/utils/gientechCommon/components/Messages/defaultStyleSet.tsx +0 -148
  260. package/src/utils/gientechCommon/components/Messages/defaultWeLogo.svg +0 -14
  261. package/src/utils/gientechCommon/components/RenameModal.tsx +0 -86
  262. package/src/utils/gientechCommon/components/style.less +0 -11
  263. package/src/utils/gientechCommon/configs/commonConfig.ts +0 -2
  264. package/src/utils/gientechCommon/configs/senderConfig.ts +0 -0
  265. package/src/utils/gientechCommon/configs/stylesConfig.ts +0 -142
  266. package/src/utils/gientechCommon/hooks/AichatUseController.tsx +0 -345
  267. package/src/utils/gientechCommon/slate/converters/deserializers.ts +0 -763
  268. package/src/utils/gientechCommon/slate/converters/mockData.ts +0 -232
  269. package/src/utils/gientechCommon/slate/converters/slateConverters.ts +0 -258
  270. package/src/utils/gientechCommon/slate/richElements/index.tsx +0 -499
  271. package/src/utils/gientechCommon/utils/request.ts +0 -37
  272. package/src/utils/gientechCommon/utils/serverFn.ts +0 -172
  273. package/src/utils/index.tsx +0 -126
  274. package/src/utils/testconfigs/demologin/index.tsx +0 -32
  275. package/src/utils/testconfigs/index.ts +0 -53
  276. package/src/vite-env.d.ts +0 -11
  277. package/stats.html +0 -4949
  278. package/tailwind.config.js +0 -170
  279. package/tsconfig.app.json +0 -30
  280. package/tsconfig.app.tsbuildinfo +0 -11
  281. package/tsconfig.json +0 -13
  282. package/tsconfig.node.json +0 -22
  283. package/tsconfig.node.tsbuildinfo +0 -1
  284. package/vite.config.ts +0 -177
  285. package/workflows/release.yml +0 -60
  286. /package/{dist/assets → assets}/Doris.png +0 -0
  287. /package/{dist/assets → assets}/PostgreSQL.png +0 -0
  288. /package/{dist/assets → assets}/SQLServer.png +0 -0
  289. /package/{dist/assets → assets}/_commonjsHelpers-gnU0ypJ3.js +0 -0
  290. /package/{dist/assets → assets}/circle-alert-g2Y6zAjt.js +0 -0
  291. /package/{dist/assets → assets}/empty.png +0 -0
  292. /package/{dist/assets → assets}/index-CEK88UzR.js +0 -0
  293. /package/{dist/assets → assets}/index-CpW6Dhpp.js +0 -0
  294. /package/{dist/assets → assets}/plus-omCUN0e3.js +0 -0
  295. /package/{dist/assets → assets}/style.css +0 -0
  296. /package/{dist/assets → assets}/style2.css +0 -0
  297. /package/{dist/assets → assets}/style3.css +0 -0
  298. /package/{dist/assets → assets}/styled-components.browser.esm-DPkS13KC.js +0 -0
  299. /package/{dist/assets → assets}/x-vPcWt3fC.js +0 -0
  300. /package/{dist/chat.d.ts → chat.d.ts} +0 -0
  301. /package/{dist/database.d.ts → database.d.ts} +0 -0
  302. /package/{dist/databaseId.d.ts → databaseId.d.ts} +0 -0
  303. /package/{dist/databaseTable.d.ts → databaseTable.d.ts} +0 -0
  304. /package/{dist/modelManage.d.ts → modelManage.d.ts} +0 -0
  305. /package/{dist/sensitive.d.ts → sensitive.d.ts} +0 -0
  306. /package/{dist/streamFilesReader.d.ts → streamFilesReader.d.ts} +0 -0
  307. /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
- }