@lobehub/chat 1.11.9 → 1.12.1

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 (356) hide show
  1. package/.github/workflows/release.yml +2 -1
  2. package/.github/workflows/test.yml +2 -1
  3. package/CHANGELOG.md +50 -0
  4. package/Dockerfile.database +2 -0
  5. package/docs/self-hosting/advanced/knowledge-base.zh-CN.mdx +65 -0
  6. package/locales/ar/chat.json +13 -3
  7. package/locales/ar/components.json +2 -0
  8. package/locales/bg-BG/chat.json +13 -3
  9. package/locales/bg-BG/components.json +2 -0
  10. package/locales/de-DE/chat.json +13 -3
  11. package/locales/de-DE/components.json +2 -0
  12. package/locales/en-US/chat.json +13 -3
  13. package/locales/en-US/components.json +2 -0
  14. package/locales/es-ES/chat.json +13 -3
  15. package/locales/es-ES/components.json +2 -0
  16. package/locales/fr-FR/chat.json +13 -3
  17. package/locales/fr-FR/components.json +2 -0
  18. package/locales/it-IT/chat.json +13 -3
  19. package/locales/it-IT/components.json +2 -0
  20. package/locales/ja-JP/chat.json +13 -3
  21. package/locales/ja-JP/components.json +2 -0
  22. package/locales/ko-KR/chat.json +13 -3
  23. package/locales/ko-KR/components.json +2 -0
  24. package/locales/nl-NL/chat.json +13 -3
  25. package/locales/nl-NL/components.json +2 -0
  26. package/locales/pl-PL/chat.json +13 -3
  27. package/locales/pl-PL/components.json +2 -0
  28. package/locales/pt-BR/chat.json +13 -3
  29. package/locales/pt-BR/components.json +2 -0
  30. package/locales/ru-RU/chat.json +13 -3
  31. package/locales/ru-RU/components.json +2 -0
  32. package/locales/tr-TR/chat.json +13 -3
  33. package/locales/tr-TR/components.json +2 -0
  34. package/locales/vi-VN/chat.json +13 -3
  35. package/locales/vi-VN/components.json +2 -0
  36. package/locales/zh-CN/chat.json +13 -3
  37. package/locales/zh-CN/components.json +2 -0
  38. package/locales/zh-TW/chat.json +13 -3
  39. package/locales/zh-TW/components.json +2 -0
  40. package/package.json +3 -2
  41. package/scripts/migrateServerDB/docker.cjs +6 -0
  42. package/scripts/migrateServerDB/errorHint.js +17 -0
  43. package/scripts/migrateServerDB/index.ts +6 -0
  44. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/Content.tsx +37 -0
  45. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/index.tsx +87 -0
  46. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/style.ts +4 -0
  47. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/utils.ts +28 -0
  48. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileList.tsx +41 -0
  49. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/index.tsx +40 -0
  50. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/SendMore.tsx +1 -1
  51. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/index.tsx +7 -22
  52. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/TextArea.tsx +1 -1
  53. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +2 -4
  54. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/File.tsx +72 -0
  55. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/Image.tsx +74 -0
  56. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/index.tsx +39 -0
  57. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/style.ts +1 -0
  58. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/index.tsx +33 -0
  59. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/Container.tsx +41 -0
  60. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/index.tsx +154 -0
  61. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Send.tsx +34 -0
  62. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/index.tsx +24 -11
  63. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/components/UploadDetail/UploadStatus.tsx +71 -0
  64. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/components/UploadDetail/index.tsx +49 -0
  65. package/src/app/(main)/chat/(workspace)/@portal/FilePreview/index.tsx +26 -0
  66. package/src/app/(main)/chat/(workspace)/@portal/Home/Files/FileList/Item.tsx +53 -0
  67. package/src/app/(main)/chat/(workspace)/@portal/Home/Files/FileList/index.tsx +50 -0
  68. package/src/app/(main)/chat/(workspace)/@portal/Home/Files/index.tsx +21 -0
  69. package/src/app/(main)/chat/(workspace)/@portal/Home/index.tsx +2 -0
  70. package/src/app/(main)/chat/(workspace)/@portal/router.tsx +4 -0
  71. package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/KnowledgeTag.tsx +41 -0
  72. package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Tags.tsx +7 -2
  73. package/src/app/(main)/chat/(workspace)/_layout/Desktop/HotKeys.tsx +1 -1
  74. package/src/app/(main)/files/(content)/@menu/default.tsx +27 -0
  75. package/src/app/(main)/files/(content)/@menu/features/FileMenu/index.tsx +97 -0
  76. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/EmptyStatus.tsx +53 -0
  77. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/Item/Content.tsx +175 -0
  78. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/Item/index.tsx +69 -0
  79. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/KnowledgeBaseList.tsx +30 -0
  80. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/SkeletonList.tsx +57 -0
  81. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/index.tsx +54 -0
  82. package/src/app/(main)/files/(content)/@modal/(.)[id]/FileDetail.tsx +16 -0
  83. package/src/app/(main)/files/(content)/@modal/(.)[id]/FilePreview.tsx +15 -0
  84. package/src/app/(main)/files/(content)/@modal/(.)[id]/FullscreenModal.tsx +85 -0
  85. package/src/app/(main)/files/(content)/@modal/(.)[id]/page.tsx +19 -0
  86. package/src/app/(main)/files/(content)/@modal/default.tsx +3 -0
  87. package/src/app/(main)/files/(content)/NotSupportClient.tsx +152 -0
  88. package/src/app/(main)/files/(content)/_layout/Desktop/index.tsx +28 -0
  89. package/src/app/(main)/files/(content)/_layout/Mobile.tsx +47 -0
  90. package/src/app/(main)/files/(content)/_layout/type.ts +7 -0
  91. package/src/app/(main)/files/(content)/layout.tsx +18 -0
  92. package/src/app/(main)/files/(content)/page.tsx +14 -0
  93. package/src/app/(main)/files/[id]/Header.tsx +63 -0
  94. package/src/app/(main)/files/[id]/page.tsx +44 -0
  95. package/src/app/(main)/files/features/FileDetail.tsx +93 -0
  96. package/src/app/(main)/files/hooks/useFileCategory.ts +9 -0
  97. package/src/app/(main)/files/layout.tsx +12 -0
  98. package/src/app/(main)/files/loading.tsx +21 -0
  99. package/src/app/(main)/repos/[id]/@menu/Head/index.tsx +33 -0
  100. package/src/app/(main)/repos/[id]/@menu/Menu/index.tsx +56 -0
  101. package/src/app/(main)/repos/[id]/@menu/default.tsx +25 -0
  102. package/src/app/(main)/repos/[id]/_layout/Desktop/index.tsx +25 -0
  103. package/src/app/(main)/repos/[id]/_layout/Mobile.tsx +47 -0
  104. package/src/app/(main)/repos/[id]/_layout/type.ts +6 -0
  105. package/src/app/(main)/repos/[id]/hooks/useKnowledgeItem.ts +7 -0
  106. package/src/app/(main)/repos/[id]/layout.tsx +13 -0
  107. package/src/app/(main)/repos/[id]/page.tsx +18 -0
  108. package/src/app/(main)/repos/layout.tsx +13 -0
  109. package/src/app/(main)/repos/page.tsx +5 -0
  110. package/src/app/trpc/async/[trpc]/route.ts +28 -0
  111. package/src/chains/abstractChunk.ts +19 -0
  112. package/src/chains/answerWithContext.ts +34 -0
  113. package/src/chains/rewriteQuery.ts +22 -0
  114. package/src/components/DragUpload/index.tsx +6 -99
  115. package/src/components/DragUpload/useDragUpload.tsx +146 -0
  116. package/src/components/FeatureList/index.tsx +64 -0
  117. package/src/components/FileParsingStatus/index.tsx +230 -0
  118. package/src/components/ImageItem/index.tsx +10 -2
  119. package/src/components/KnowledgeIcon/index.tsx +28 -0
  120. package/src/config/app.ts +6 -1
  121. package/src/config/featureFlags/schema.ts +1 -1
  122. package/src/const/file.ts +1 -0
  123. package/src/const/url.ts +1 -0
  124. package/src/database/client/models/file.ts +8 -2
  125. package/src/database/server/migrations/0005_pgvector.sql +2 -0
  126. package/src/database/server/migrations/0006_add_knowledge_base.sql +307 -0
  127. package/src/database/server/migrations/0007_fix_embedding_table.sql +18 -0
  128. package/src/database/server/migrations/meta/0005_snapshot.json +2119 -0
  129. package/src/database/server/migrations/meta/0006_snapshot.json +3006 -0
  130. package/src/database/server/migrations/meta/0007_snapshot.json +3012 -0
  131. package/src/database/server/migrations/meta/_journal.json +21 -0
  132. package/src/database/server/models/__tests__/_test_template.ts +155 -0
  133. package/src/database/server/models/__tests__/agent.test.ts +226 -0
  134. package/src/database/server/models/__tests__/asyncTask.test.ts +176 -0
  135. package/src/database/server/models/__tests__/chunk.test.ts +336 -0
  136. package/src/database/server/models/__tests__/file.test.ts +317 -29
  137. package/src/database/server/models/__tests__/fixtures/embedding.ts +568 -0
  138. package/src/database/server/models/__tests__/knowledgeBase.test.ts +132 -0
  139. package/src/database/server/models/__tests__/message.test.ts +7 -4
  140. package/src/database/server/models/_template.ts +10 -1
  141. package/src/database/server/models/agent.ts +165 -0
  142. package/src/database/server/models/asyncTask.ts +96 -0
  143. package/src/database/server/models/chunk.ts +203 -0
  144. package/src/database/server/models/embedding.ts +50 -0
  145. package/src/database/server/models/file.ts +231 -12
  146. package/src/database/server/models/knowledgeBase.ts +94 -0
  147. package/src/database/server/models/message.ts +156 -30
  148. package/src/database/server/models/user.ts +12 -1
  149. package/src/database/server/schemas/lobechat/agent.ts +93 -0
  150. package/src/database/server/schemas/lobechat/discover.ts +1 -1
  151. package/src/database/server/schemas/lobechat/file.ts +118 -1
  152. package/src/database/server/schemas/lobechat/index.ts +5 -1
  153. package/src/database/server/schemas/lobechat/message.ts +169 -0
  154. package/src/database/server/schemas/lobechat/rag.ts +53 -0
  155. package/src/database/server/schemas/lobechat/relations.ts +68 -48
  156. package/src/database/server/schemas/lobechat/session.ts +77 -0
  157. package/src/database/server/schemas/lobechat/topic.ts +32 -0
  158. package/src/database/server/schemas/lobechat/user.ts +40 -25
  159. package/src/database/server/utils/idGenerator.ts +1 -0
  160. package/src/features/ChatInput/ActionBar/Clear.tsx +1 -1
  161. package/src/features/ChatInput/ActionBar/Knowledge/Dropdown.tsx +160 -0
  162. package/src/features/ChatInput/ActionBar/Knowledge/ListItem.tsx +52 -0
  163. package/src/features/ChatInput/ActionBar/Knowledge/index.tsx +54 -0
  164. package/src/features/ChatInput/ActionBar/Tools/index.tsx +1 -1
  165. package/src/features/ChatInput/ActionBar/Upload/ClientMode.tsx +52 -0
  166. package/src/features/ChatInput/ActionBar/Upload/ServerMode.tsx +104 -0
  167. package/src/features/ChatInput/ActionBar/Upload/index.tsx +8 -0
  168. package/src/features/ChatInput/ActionBar/config.ts +14 -5
  169. package/src/features/ChatInput/useSend.ts +16 -7
  170. package/src/features/Conversation/Messages/Assistant/FileChunks/Item/index.tsx +51 -0
  171. package/src/features/Conversation/Messages/Assistant/FileChunks/Item/style.ts +38 -0
  172. package/src/features/Conversation/Messages/Assistant/FileChunks/index.tsx +76 -0
  173. package/src/features/Conversation/Messages/Assistant/index.tsx +13 -4
  174. package/src/features/Conversation/Messages/Default.tsx +4 -0
  175. package/src/features/Conversation/Messages/User/BelowMessage.tsx +78 -0
  176. package/src/features/Conversation/Messages/User/FileListViewer/Item.tsx +53 -0
  177. package/src/features/Conversation/Messages/User/FileListViewer/index.tsx +21 -0
  178. package/src/{components/FileList/FileListViewer.tsx → features/Conversation/Messages/User/ImageFileListViewer.tsx} +10 -2
  179. package/src/features/Conversation/Messages/{User.tsx → User/index.tsx} +11 -2
  180. package/src/features/Conversation/Messages/index.ts +8 -3
  181. package/src/features/Conversation/components/ChatItem/index.tsx +33 -10
  182. package/src/features/Conversation/components/InboxWelcome/QuestionSuggest.tsx +1 -1
  183. package/src/features/Conversation/types/index.tsx +1 -0
  184. package/src/features/FileManager/ChunkDrawer/ChunkList/ChunkItem.tsx +61 -0
  185. package/src/features/FileManager/ChunkDrawer/ChunkList/index.tsx +42 -0
  186. package/src/features/FileManager/ChunkDrawer/Content.tsx +38 -0
  187. package/src/features/FileManager/ChunkDrawer/Loading/index.tsx +16 -0
  188. package/src/features/FileManager/ChunkDrawer/SimilaritySearchList/Item.tsx +62 -0
  189. package/src/features/FileManager/ChunkDrawer/SimilaritySearchList/index.tsx +31 -0
  190. package/src/features/FileManager/ChunkDrawer/index.tsx +48 -0
  191. package/src/features/FileManager/FileList/EmptyStatus.tsx +153 -0
  192. package/src/features/FileManager/FileList/FileListItem/ChunkTag.tsx +35 -0
  193. package/src/features/FileManager/FileList/FileListItem/DropdownMenu.tsx +150 -0
  194. package/src/features/FileManager/FileList/FileListItem/index.tsx +211 -0
  195. package/src/features/FileManager/FileList/FileSkeleton.tsx +25 -0
  196. package/src/features/FileManager/FileList/ToolBar/Config.tsx +28 -0
  197. package/src/features/FileManager/FileList/ToolBar/MultiSelectActions.tsx +152 -0
  198. package/src/features/FileManager/FileList/ToolBar/index.tsx +114 -0
  199. package/src/features/FileManager/FileList/index.tsx +143 -0
  200. package/src/features/FileManager/FileList/useCheckTaskStatus.ts +27 -0
  201. package/src/features/FileManager/Header/FilesSearchBar.tsx +41 -0
  202. package/src/features/FileManager/Header/UploadFileButton.tsx +79 -0
  203. package/src/features/FileManager/Header/index.tsx +39 -0
  204. package/src/features/FileManager/UploadDock/Item.tsx +124 -0
  205. package/src/features/FileManager/UploadDock/index.tsx +183 -0
  206. package/src/features/FileManager/index.tsx +38 -0
  207. package/src/features/FileSidePanel/index.tsx +79 -0
  208. package/src/features/FileViewer/NotSupport/index.tsx +54 -0
  209. package/src/features/FileViewer/PDFViewer/HighlightLayer.tsx +81 -0
  210. package/src/features/FileViewer/PDFViewer/index.tsx +93 -0
  211. package/src/features/FileViewer/PDFViewer/style.ts +20 -0
  212. package/src/features/FileViewer/PDFViewer/useResizeObserver.ts +33 -0
  213. package/src/features/FileViewer/TXTViewer/index.tsx +41 -0
  214. package/src/features/FileViewer/index.tsx +45 -0
  215. package/src/features/KnowledgeBaseModal/AddFilesToKnowledgeBase/SelectForm.tsx +115 -0
  216. package/src/features/KnowledgeBaseModal/AddFilesToKnowledgeBase/index.tsx +43 -0
  217. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/Action.tsx +103 -0
  218. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/EditCustomPlugin.tsx +55 -0
  219. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/PluginTag.tsx +58 -0
  220. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/index.tsx +70 -0
  221. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/List.tsx +49 -0
  222. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Loading.tsx +13 -0
  223. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/index.tsx +39 -0
  224. package/src/features/KnowledgeBaseModal/CreateNew/CreateForm.tsx +73 -0
  225. package/src/features/KnowledgeBaseModal/CreateNew/index.tsx +35 -0
  226. package/src/features/KnowledgeBaseModal/index.ts +3 -0
  227. package/src/libs/langchain/loaders/pdf/index.ts +2 -2
  228. package/src/libs/trpc/async/asyncAuth.ts +24 -0
  229. package/src/libs/trpc/async/index.ts +10 -0
  230. package/src/libs/trpc/async/init.ts +11 -0
  231. package/src/libs/trpc/client/async.ts +14 -0
  232. package/src/libs/trpc/client/index.ts +1 -0
  233. package/src/libs/trpc/client/lambda.ts +9 -0
  234. package/src/libs/trpc/middleware/keyVaults.ts +18 -0
  235. package/src/libs/unstructured/__tests__/index.test.ts +0 -10
  236. package/src/libs/unstructured/index.ts +6 -11
  237. package/src/locales/default/chat.ts +47 -3
  238. package/src/locales/default/common.ts +1 -0
  239. package/src/locales/default/components.ts +2 -0
  240. package/src/locales/default/error.ts +6 -1
  241. package/src/locales/default/file.ts +92 -0
  242. package/src/locales/default/index.ts +4 -0
  243. package/src/locales/default/knowledgeBase.ts +31 -0
  244. package/src/locales/default/portal.ts +1 -0
  245. package/src/middleware.ts +3 -0
  246. package/src/server/asyncContext.ts +40 -0
  247. package/src/server/modules/ContentChunk/index.ts +135 -0
  248. package/src/server/modules/S3/index.ts +30 -5
  249. package/src/server/routers/async/caller.ts +27 -0
  250. package/src/server/routers/async/file.ts +247 -0
  251. package/src/server/routers/async/index.ts +12 -0
  252. package/src/server/routers/lambda/_template.ts +77 -0
  253. package/src/server/routers/lambda/agent.ts +159 -0
  254. package/src/server/routers/lambda/chunk.ts +189 -0
  255. package/src/server/routers/lambda/file.ts +129 -5
  256. package/src/server/routers/lambda/index.ts +6 -0
  257. package/src/server/routers/lambda/knowledgeBase.ts +79 -0
  258. package/src/server/routers/lambda/message.ts +6 -0
  259. package/src/server/routers/lambda/session.ts +0 -25
  260. package/src/server/routers/lambda/user.ts +5 -1
  261. package/src/server/services/chunk/index.ts +74 -0
  262. package/src/server/utils/files.ts +9 -0
  263. package/src/services/__tests__/chat.test.ts +18 -20
  264. package/src/services/__tests__/{upload.test.ts → upload_legacy.test.ts} +1 -1
  265. package/src/services/agent.ts +45 -0
  266. package/src/services/chat.ts +17 -15
  267. package/src/services/file/client.test.ts +1 -50
  268. package/src/services/file/client.ts +12 -25
  269. package/src/services/file/server.ts +25 -3
  270. package/src/services/file/type.ts +7 -4
  271. package/src/services/knowledgeBase.ts +34 -0
  272. package/src/services/message/client.test.ts +1 -1
  273. package/src/services/message/client.ts +29 -3
  274. package/src/services/message/index.ts +0 -2
  275. package/src/services/message/server.ts +9 -3
  276. package/src/services/message/type.ts +1 -13
  277. package/src/services/rag.ts +29 -0
  278. package/src/services/session/server.ts +1 -1
  279. package/src/services/upload.ts +89 -84
  280. package/src/services/upload_legacy.ts +104 -0
  281. package/src/services/user/client.ts +7 -2
  282. package/src/services/user/server.ts +6 -2
  283. package/src/services/user/type.ts +3 -2
  284. package/src/store/agent/slices/chat/action.ts +90 -18
  285. package/src/store/agent/slices/chat/initialState.ts +1 -0
  286. package/src/store/agent/slices/chat/selectors.ts +58 -0
  287. package/src/store/chat/slices/builtinTool/action.test.ts +2 -2
  288. package/src/store/chat/slices/builtinTool/action.ts +2 -2
  289. package/src/store/chat/slices/message/action.test.ts +2 -1
  290. package/src/store/chat/slices/message/action.ts +102 -26
  291. package/src/store/chat/slices/message/actions/rag.ts +148 -0
  292. package/src/store/chat/slices/message/initialState.ts +7 -0
  293. package/src/store/chat/slices/message/reducer.ts +6 -2
  294. package/src/store/chat/slices/message/selectors.ts +38 -3
  295. package/src/store/chat/slices/plugin/action.ts +8 -2
  296. package/src/store/chat/slices/portal/action.ts +8 -0
  297. package/src/store/chat/slices/portal/initialState.ts +3 -0
  298. package/src/store/chat/slices/portal/selectors.ts +8 -2
  299. package/src/store/file/initialState.ts +5 -1
  300. package/src/store/file/reducers/uploadFileList.ts +133 -0
  301. package/src/store/file/selectors.ts +3 -0
  302. package/src/store/file/slices/chat/action.test.ts +90 -90
  303. package/src/store/file/slices/chat/action.ts +164 -109
  304. package/src/store/file/slices/chat/initialState.ts +7 -2
  305. package/src/store/file/slices/chat/selectors.test.ts +84 -61
  306. package/src/store/file/slices/chat/selectors.ts +22 -32
  307. package/src/store/file/slices/chunk/action.ts +36 -0
  308. package/src/store/file/slices/chunk/index.ts +3 -0
  309. package/src/store/file/slices/chunk/initialState.ts +15 -0
  310. package/src/store/file/slices/chunk/selectors.ts +10 -0
  311. package/src/store/file/slices/fileManager/action.ts +187 -0
  312. package/src/store/file/slices/fileManager/index.ts +3 -0
  313. package/src/store/file/slices/fileManager/initialState.ts +18 -0
  314. package/src/store/file/slices/fileManager/selectors.ts +58 -0
  315. package/src/store/file/slices/tts/action.test.ts +1 -1
  316. package/src/store/file/slices/tts/action.ts +2 -2
  317. package/src/store/file/slices/upload/action.ts +164 -0
  318. package/src/store/file/store.ts +12 -1
  319. package/src/store/knowledgeBase/index.ts +2 -0
  320. package/src/store/knowledgeBase/initialState.ts +7 -0
  321. package/src/store/knowledgeBase/selectors.ts +1 -0
  322. package/src/store/knowledgeBase/slices/content/action.ts +27 -0
  323. package/src/store/knowledgeBase/slices/content/index.ts +1 -0
  324. package/src/store/knowledgeBase/slices/crud/action.ts +78 -0
  325. package/src/store/knowledgeBase/slices/crud/index.ts +3 -0
  326. package/src/store/knowledgeBase/slices/crud/initialState.ts +12 -0
  327. package/src/store/knowledgeBase/slices/crud/selectors.ts +7 -0
  328. package/src/store/knowledgeBase/store.ts +30 -0
  329. package/src/store/serverConfig/selectors.test.ts +1 -1
  330. package/src/store/user/slices/preference/selectors.ts +8 -0
  331. package/src/store/user/slices/settings/selectors/systemAgent.ts +2 -0
  332. package/src/tools/dalle/Render/Item/ImageFileItem.tsx +3 -23
  333. package/src/types/agent/index.ts +9 -0
  334. package/src/types/asyncTask.ts +31 -0
  335. package/src/types/chunk/document.ts +9 -0
  336. package/src/types/chunk/index.ts +52 -0
  337. package/src/types/files/index.ts +35 -0
  338. package/src/types/files/list.ts +44 -0
  339. package/src/types/files/upload.ts +91 -0
  340. package/src/types/knowledgeBase/index.ts +45 -0
  341. package/src/types/message/index.ts +54 -5
  342. package/src/types/rag.ts +16 -0
  343. package/src/utils/filter.test.ts +2 -0
  344. package/src/utils/server/auth.ts +23 -0
  345. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/LocalFiles.tsx +0 -46
  346. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files.tsx +0 -19
  347. package/src/components/FileList/EditableFileList.tsx +0 -47
  348. package/src/components/FileList/index.ts +0 -2
  349. package/src/components/FileList/type.tsx +0 -7
  350. package/src/database/server/schemas/lobechat/chat.ts +0 -331
  351. package/src/features/ChatInput/ActionBar/FileUpload.tsx +0 -69
  352. package/src/features/ChatInput/useChatInput.ts +0 -45
  353. package/src/features/FileList/EditableFileList.tsx +0 -31
  354. package/src/features/FileList/FileListPreviewer.tsx +0 -17
  355. package/src/features/FileList/index.tsx +0 -2
  356. package/src/types/files.ts +0 -42
@@ -1,13 +1,18 @@
1
1
  import { FilePreview } from '@/types/files';
2
+ import { UploadFileItem } from '@/types/files/upload';
2
3
 
3
4
  export interface ImageFileState {
5
+ chatUploadFileList: UploadFileItem[];
6
+ /**
7
+ * it should be removed after dalle plugin refactor
8
+ * @deprecated
9
+ */
4
10
  imagesMap: Record<string, FilePreview>;
5
- inputFilesList: string[];
6
11
  uploadingIds: string[];
7
12
  }
8
13
 
9
14
  export const initialImageFileState: ImageFileState = {
15
+ chatUploadFileList: [],
10
16
  imagesMap: {},
11
- inputFilesList: [],
12
17
  uploadingIds: [],
13
18
  };
@@ -1,78 +1,101 @@
1
- import { beforeEach, describe, expect, it } from 'vitest';
1
+ import { describe, expect, it } from 'vitest';
2
2
 
3
- import { FilesStoreState } from '../../initialState';
4
- import { filesSelectors } from './selectors';
3
+ import { FilesStoreState, initialState } from '@/store/file/initialState';
4
+ import { UPLOAD_STATUS_SET, UploadFileItem } from '@/types/files/upload';
5
5
 
6
- describe('filesSelectors', () => {
7
- let state: FilesStoreState;
6
+ import { fileChatSelectors, filesSelectors } from './selectors';
8
7
 
9
- beforeEach(() => {
10
- // 创建并初始化 state 的模拟实例
11
- state = {
12
- imagesMap: {
13
- '1': {
14
- id: '1',
15
- name: 'a',
16
- fileType: 'image/png',
17
- saveMode: 'local',
18
- base64Url: 'base64string1',
19
- url: 'blob:abc',
20
- },
21
- '2': {
22
- id: '2',
23
- name: 'b',
24
- fileType: 'image/png',
25
- saveMode: 'url',
26
- base64Url: 'base64string2',
27
- url: 'url2',
28
- },
29
- },
30
- uploadingIds: [],
31
- // 假设 '3' 是不存在的 ID
32
- inputFilesList: ['1', '2', '3'],
33
- };
8
+ describe('filesSelectors', () => {
9
+ describe('chatUploadFileList', () => {
10
+ it('should return the chatUploadFileList from state', () => {
11
+ const state = {
12
+ ...initialState,
13
+ chatUploadFileList: [{ id: '1' }] as UploadFileItem[],
14
+ } as FilesStoreState;
15
+ expect(filesSelectors.chatUploadFileList(state)).toEqual([{ id: '1' }]);
16
+ });
34
17
  });
35
18
 
36
- it('getImageDetailByList should return details for the provided list of image IDs', () => {
37
- const list = ['1', '2'];
38
- const details = filesSelectors.getImageDetailByList(list)(state);
39
- expect(details.length).toBe(2);
40
- expect(details[0].name).toBe('a');
41
- expect(details[1].name).toBe('b');
42
- });
19
+ describe('isImageUploading', () => {
20
+ it('should return true if there are uploading ids', () => {
21
+ const state = { uploadingIds: ['1', '2'] } as FilesStoreState;
22
+ expect(filesSelectors.isImageUploading(state)).toBe(true);
23
+ });
43
24
 
44
- it('imageDetailList should return details for the images in the inputFilesList', () => {
45
- const details = filesSelectors.imageDetailList(state);
46
- // '3' should be filtered due to not exist in map
47
- expect(details.length).toBe(2);
25
+ it('should return false if there are no uploading ids', () => {
26
+ const state = { uploadingIds: [] as string[] } as FilesStoreState;
27
+ expect(filesSelectors.isImageUploading(state)).toBe(false);
28
+ });
48
29
  });
30
+ });
49
31
 
50
- it('getImageUrlOrBase64ById should return the correct URL or Base64 based on saveMode', () => {
51
- const localImage = filesSelectors.getImageUrlOrBase64ById('1')(state);
52
- expect(localImage).toEqual({ id: '1', url: 'base64string1' });
32
+ describe('fileChatSelectors', () => {
33
+ describe('chatRawFileList', () => {
34
+ it('should return a list of raw files', () => {
35
+ const state = {
36
+ chatUploadFileList: [
37
+ { file: { name: 'test1.jpg' } },
38
+ { file: { name: 'test2.jpg' } },
39
+ ] as UploadFileItem[],
40
+ } as FilesStoreState;
53
41
 
54
- const serverImage = filesSelectors.getImageUrlOrBase64ById('2')(state);
55
- expect(serverImage).toEqual({ id: '2', url: 'url2' });
42
+ expect(fileChatSelectors.chatRawFileList(state)).toEqual([
43
+ { name: 'test1.jpg' },
44
+ { name: 'test2.jpg' },
45
+ ]);
46
+ });
47
+ });
56
48
 
57
- const nonExistentImage = filesSelectors.getImageUrlOrBase64ById('3')(state);
58
- expect(nonExistentImage).toBeUndefined();
49
+ describe('chatUploadFileList', () => {
50
+ it('should return the chatUploadFileList from state', () => {
51
+ const state = {
52
+ chatUploadFileList: [{ id: '1' }] as UploadFileItem[],
53
+ } as FilesStoreState;
54
+ expect(fileChatSelectors.chatUploadFileList(state)).toEqual([{ id: '1' }]);
55
+ });
59
56
  });
60
57
 
61
- it('getImageUrlOrBase64ByList should return the correct list of URLs or Base64 strings', () => {
62
- const list = ['1', '2', '3'];
63
- const urlsOrBase64s = filesSelectors.getImageUrlOrBase64ByList(list)(state);
64
- expect(urlsOrBase64s.length).toBe(2); // '3' 应该被过滤掉,因为它不存在
65
- expect(urlsOrBase64s[0].url).toBe('base64string1');
66
- expect(urlsOrBase64s[1].url).toBe('url2');
58
+ describe('chatUploadFileListHasItem', () => {
59
+ it('should return true if chatUploadFileList has items', () => {
60
+ const state = { chatUploadFileList: [{ id: '1' }] as UploadFileItem[] } as FilesStoreState;
61
+ expect(fileChatSelectors.chatUploadFileListHasItem(state)).toBe(true);
62
+ });
63
+
64
+ it('should return false if chatUploadFileList is empty', () => {
65
+ const state = { chatUploadFileList: [] as UploadFileItem[] } as FilesStoreState;
66
+ expect(fileChatSelectors.chatUploadFileListHasItem(state)).toBe(false);
67
+ });
67
68
  });
68
69
 
69
- it('imageUrlOrBase64List should return a list of image URLs or Base64 strings for all images in inputFilesList', () => {
70
- const urlsOrBase64s = filesSelectors.imageUrlOrBase64List(state);
71
- expect(urlsOrBase64s.length).toBe(2); // '3' 是不存在的 ID,所以应该被过滤掉
70
+ describe('isUploadingFiles', () => {
71
+ it('should return true if any file is in uploading status', () => {
72
+ const state = {
73
+ chatUploadFileList: [
74
+ { status: Array.from(UPLOAD_STATUS_SET)[0] },
75
+ { status: 'completed' },
76
+ ] as UploadFileItem[],
77
+ } as FilesStoreState;
78
+ expect(fileChatSelectors.isUploadingFiles(state)).toBe(true);
79
+ });
80
+
81
+ it('should return true if any file has unfinished embedding tasks', () => {
82
+ const state = {
83
+ chatUploadFileList: [
84
+ { status: 'success', tasks: { finishEmbedding: false } },
85
+ { status: 'success', tasks: { finishEmbedding: true } },
86
+ ] as UploadFileItem[],
87
+ } as FilesStoreState;
88
+ expect(fileChatSelectors.isUploadingFiles(state)).toBe(true);
89
+ });
72
90
 
73
- expect(urlsOrBase64s).toEqual([
74
- { id: '1', url: 'base64string1' }, // 本地保存的图像应该使用 base64 URL
75
- { id: '2', url: 'url2' }, // 服务器保存的图像应该使用普通 URL
76
- ]);
91
+ it('should return false if no files are uploading or have unfinished tasks', () => {
92
+ const state: FilesStoreState = {
93
+ chatUploadFileList: [
94
+ { status: 'success', tasks: { finishEmbedding: true } },
95
+ { status: 'success' },
96
+ ] as UploadFileItem[],
97
+ } as FilesStoreState;
98
+ expect(fileChatSelectors.isUploadingFiles(state)).toBe(false);
99
+ });
77
100
  });
78
101
  });
@@ -1,40 +1,30 @@
1
- import { FilesStoreState } from '../../initialState';
2
-
3
- const getImageDetailByList = (list: string[]) => (s: FilesStoreState) =>
4
- list
5
- .map((i) => s.imagesMap[i])
6
- .filter(Boolean)
7
- .map((i) => ({ ...i, loading: s.uploadingIds.includes(i.id) }));
8
-
9
- const imageDetailList = (s: FilesStoreState) => getImageDetailByList(s.inputFilesList)(s);
10
-
11
- const getImageUrlOrBase64ById =
12
- (id: string) =>
13
- (s: FilesStoreState): { id: string; url: string } | undefined => {
14
- const preview = s.imagesMap[id];
15
-
16
- if (!preview) return undefined;
17
-
18
- const url = preview.saveMode === 'local' ? (preview.base64Url as string) : preview.url;
1
+ import { UPLOAD_STATUS_SET } from '@/types/files/upload';
19
2
 
20
- return { id, url: url };
21
- };
3
+ import { FilesStoreState } from '../../initialState';
22
4
 
23
- const getImageUrlOrBase64ByList = (idList: string[]) => (s: FilesStoreState) =>
24
- idList.map((i) => getImageUrlOrBase64ById(i)(s)).filter(Boolean) as {
25
- id: string;
26
- url: string;
27
- }[];
5
+ const chatUploadFileList = (s: FilesStoreState) => s.chatUploadFileList;
6
+ const isImageUploading = (s: FilesStoreState) => s.uploadingIds.length > 0;
28
7
 
29
- const imageUrlOrBase64List = (s: FilesStoreState) => getImageUrlOrBase64ByList(s.inputFilesList)(s);
8
+ const chatRawFileList = (s: FilesStoreState) => s.chatUploadFileList.map((item) => item.file);
9
+ const chatUploadFileListHasItem = (s: FilesStoreState) => s.chatUploadFileList.length > 0;
30
10
 
31
- const isImageUploading = (s: FilesStoreState) => s.uploadingIds.length > 0;
11
+ const isUploadingFiles = (s: FilesStoreState) =>
12
+ s.chatUploadFileList.some(
13
+ (file) =>
14
+ // is file status in uploading
15
+ UPLOAD_STATUS_SET.has(file.status) ||
16
+ // or file has tasks but not finish embedding
17
+ (file.tasks && !file.tasks?.finishEmbedding),
18
+ );
32
19
 
33
20
  export const filesSelectors = {
34
- getImageDetailByList,
35
- getImageUrlOrBase64ById,
36
- getImageUrlOrBase64ByList,
37
- imageDetailList,
38
- imageUrlOrBase64List,
21
+ chatUploadFileList,
39
22
  isImageUploading,
40
23
  };
24
+
25
+ export const fileChatSelectors = {
26
+ chatRawFileList,
27
+ chatUploadFileList,
28
+ chatUploadFileListHasItem,
29
+ isUploadingFiles,
30
+ };
@@ -0,0 +1,36 @@
1
+ import { StateCreator } from 'zustand/vanilla';
2
+
3
+ import { ragService } from '@/services/rag';
4
+
5
+ import { FileStore } from '../../store';
6
+
7
+ export interface FileChunkAction {
8
+ closeChunkDrawer: () => void;
9
+ highlightChunks: (ids: string[]) => void;
10
+
11
+ openChunkDrawer: (id: string) => void;
12
+ semanticSearch: (text: string, fileId: string) => Promise<void>;
13
+ }
14
+
15
+ export const createFileChunkSlice: StateCreator<
16
+ FileStore,
17
+ [['zustand/devtools', never]],
18
+ [],
19
+ FileChunkAction
20
+ > = (set) => ({
21
+ closeChunkDrawer: () => {
22
+ set({ chunkDetailId: null, isSimilaritySearch: false, similaritySearchChunks: [] });
23
+ },
24
+ highlightChunks: (ids) => {
25
+ set({ highlightChunkIds: ids });
26
+ },
27
+ openChunkDrawer: (id) => {
28
+ set({ chunkDetailId: id });
29
+ },
30
+
31
+ semanticSearch: async (text, fileId) => {
32
+ set({ isSimilaritySearching: true });
33
+ const data = await ragService.semanticSearch(text, [fileId]);
34
+ set({ isSimilaritySearching: false, similaritySearchChunks: data });
35
+ },
36
+ });
@@ -0,0 +1,3 @@
1
+ export * from './action';
2
+ export * from './initialState';
3
+ export * from './selectors';
@@ -0,0 +1,15 @@
1
+ import { SemanticSearchChunk } from '@/types/chunk';
2
+
3
+ export interface FileChunkState {
4
+ chunkDetailId: string | null;
5
+ highlightChunkIds: string[];
6
+ isSimilaritySearch?: boolean;
7
+ isSimilaritySearching?: boolean;
8
+ similaritySearchChunks?: SemanticSearchChunk[];
9
+ }
10
+
11
+ export const initialFileChunkState: FileChunkState = {
12
+ chunkDetailId: null,
13
+ highlightChunkIds: [],
14
+ similaritySearchChunks: [],
15
+ };
@@ -0,0 +1,10 @@
1
+ // import { FileStore } from '../../store';
2
+ import { FilesStoreState } from '@/store/file/initialState';
3
+
4
+ const showSimilaritySearchResult = (s: FilesStoreState) => s.isSimilaritySearch;
5
+ const enabledChunkFileId = (s: FilesStoreState) => s.chunkDetailId;
6
+
7
+ export const fileChunkSelectors = {
8
+ enabledChunkFileId,
9
+ showSimilaritySearchResult,
10
+ };
@@ -0,0 +1,187 @@
1
+ import { SWRResponse, mutate } from 'swr';
2
+ import { StateCreator } from 'zustand/vanilla';
3
+
4
+ import { FILE_UPLOAD_BLACKLIST } from '@/const/file';
5
+ import { useClientDataSWR } from '@/libs/swr';
6
+ import { fileService } from '@/services/file';
7
+ import { ServerService } from '@/services/file/server';
8
+ import { ragService } from '@/services/rag';
9
+ import {
10
+ UploadFileListDispatch,
11
+ uploadFileListReducer,
12
+ } from '@/store/file/reducers/uploadFileList';
13
+ import { FileListItem, QueryFileListParams } from '@/types/files';
14
+
15
+ import { FileStore } from '../../store';
16
+
17
+ const serverFileService = new ServerService();
18
+
19
+ export interface FileManageAction {
20
+ dispatchDockFileList: (payload: UploadFileListDispatch) => void;
21
+ embeddingChunks: (fileIds: string[]) => Promise<void>;
22
+ parseFilesToChunks: (ids: string[], params?: { skipExist?: boolean }) => Promise<void>;
23
+ pushDockFileList: (files: File[], knowledgeBaseId?: string) => Promise<void>;
24
+
25
+ reParseFile: (id: string) => Promise<void>;
26
+ refreshFileList: () => Promise<void>;
27
+ removeAllFiles: () => Promise<void>;
28
+ removeFileItem: (id: string) => Promise<void>;
29
+ removeFiles: (ids: string[]) => Promise<void>;
30
+
31
+ toggleEmbeddingIds: (ids: string[], loading?: boolean) => void;
32
+ toggleParsingIds: (ids: string[], loading?: boolean) => void;
33
+
34
+ useFetchFileItem: (id?: string) => SWRResponse<FileListItem | undefined>;
35
+ useFetchFileManage: (params: QueryFileListParams) => SWRResponse<FileListItem[]>;
36
+ }
37
+
38
+ const FETCH_FILE_LIST_KEY = 'useFetchFileManage';
39
+
40
+ export const createFileManageSlice: StateCreator<
41
+ FileStore,
42
+ [['zustand/devtools', never]],
43
+ [],
44
+ FileManageAction
45
+ > = (set, get) => ({
46
+ dispatchDockFileList: (payload: UploadFileListDispatch) => {
47
+ const nextValue = uploadFileListReducer(get().dockUploadFileList, payload);
48
+ if (nextValue === get().dockUploadFileList) return;
49
+
50
+ set({ dockUploadFileList: nextValue }, false, `dispatchDockFileList/${payload.type}`);
51
+ },
52
+ embeddingChunks: async (fileIds: string[]) => {
53
+ // toggle file ids
54
+ get().toggleEmbeddingIds(fileIds);
55
+
56
+ // parse files
57
+ const pools = fileIds.map(async (id) => {
58
+ try {
59
+ await ragService.createEmbeddingChunksTask(id);
60
+ } catch (e) {
61
+ console.error(e);
62
+ }
63
+ });
64
+
65
+ await Promise.all(pools);
66
+ await get().refreshFileList();
67
+ get().toggleEmbeddingIds(fileIds, false);
68
+ },
69
+ parseFilesToChunks: async (ids: string[], params) => {
70
+ // toggle file ids
71
+ get().toggleParsingIds(ids);
72
+
73
+ // parse files
74
+ const pools = ids.map(async (id) => {
75
+ try {
76
+ await ragService.createParseFileTask(id, params?.skipExist);
77
+ } catch (e) {
78
+ console.error(e);
79
+ }
80
+ });
81
+
82
+ await Promise.all(pools);
83
+ await get().refreshFileList();
84
+ get().toggleParsingIds(ids, false);
85
+ },
86
+ pushDockFileList: async (rawFiles, knowledgeBaseId) => {
87
+ const { dispatchDockFileList } = get();
88
+
89
+ // 0. skip file in blacklist
90
+ const files = rawFiles.filter((file) => !FILE_UPLOAD_BLACKLIST.includes(file.name));
91
+
92
+ // 1. add files
93
+ dispatchDockFileList({
94
+ atStart: true,
95
+ files: files.map((file) => ({ file, id: file.name, status: 'pending' })),
96
+ type: 'addFiles',
97
+ });
98
+
99
+ const pools = files.map(async (file) => {
100
+ await get().uploadWithProgress({
101
+ file,
102
+ knowledgeBaseId,
103
+ onStatusUpdate: dispatchDockFileList,
104
+ });
105
+
106
+ await get().refreshFileList();
107
+ });
108
+
109
+ await Promise.all(pools);
110
+ },
111
+
112
+ reParseFile: async (id) => {
113
+ // toggle file ids
114
+ get().toggleParsingIds([id]);
115
+
116
+ await ragService.retryParseFile(id);
117
+
118
+ await get().refreshFileList();
119
+
120
+ get().toggleParsingIds([id], false);
121
+ },
122
+ refreshFileList: async () => {
123
+ await mutate([FETCH_FILE_LIST_KEY, get().queryListParams]);
124
+ },
125
+ removeAllFiles: async () => {
126
+ await fileService.removeAllFiles();
127
+ },
128
+ removeFileItem: async (id) => {
129
+ await fileService.removeFile(id);
130
+ await get().refreshFileList();
131
+ },
132
+
133
+ removeFiles: async (ids) => {
134
+ await fileService.removeFiles(ids);
135
+ await get().refreshFileList();
136
+ },
137
+ toggleEmbeddingIds: (ids, loading) => {
138
+ set((state) => {
139
+ const nextValue = new Set(state.creatingEmbeddingTaskIds);
140
+
141
+ ids.forEach((id) => {
142
+ if (typeof loading === 'undefined') {
143
+ if (nextValue.has(id)) nextValue.delete(id);
144
+ else nextValue.add(id);
145
+ } else {
146
+ if (loading) nextValue.add(id);
147
+ else nextValue.delete(id);
148
+ }
149
+ });
150
+
151
+ return { creatingEmbeddingTaskIds: Array.from(nextValue.values()) };
152
+ });
153
+ },
154
+ toggleParsingIds: (ids, loading) => {
155
+ set((state) => {
156
+ const nextValue = new Set(state.creatingChunkingTaskIds);
157
+
158
+ ids.forEach((id) => {
159
+ if (typeof loading === 'undefined') {
160
+ if (nextValue.has(id)) nextValue.delete(id);
161
+ else nextValue.add(id);
162
+ } else {
163
+ if (loading) nextValue.add(id);
164
+ else nextValue.delete(id);
165
+ }
166
+ });
167
+
168
+ return { creatingChunkingTaskIds: Array.from(nextValue.values()) };
169
+ });
170
+ },
171
+
172
+ useFetchFileItem: (id) =>
173
+ useClientDataSWR<FileListItem | undefined>(!id ? null : ['useFetchFileItem', id], () =>
174
+ serverFileService.getFileItem(id!),
175
+ ),
176
+
177
+ useFetchFileManage: (params) =>
178
+ useClientDataSWR<FileListItem[]>(
179
+ [FETCH_FILE_LIST_KEY, params],
180
+ () => serverFileService.getFiles(params),
181
+ {
182
+ onSuccess: (data) => {
183
+ set({ fileList: data, queryListParams: params });
184
+ },
185
+ },
186
+ ),
187
+ });
@@ -0,0 +1,3 @@
1
+ export * from './action';
2
+ export * from './initialState';
3
+ export * from './selectors';
@@ -0,0 +1,18 @@
1
+ import { FileListItem, QueryFileListParams } from '@/types/files';
2
+ import { UploadFileItem } from '@/types/files/upload';
3
+
4
+ export interface FileManagerState {
5
+ creatingChunkingTaskIds: string[];
6
+ creatingEmbeddingTaskIds: string[];
7
+ dockUploadFileList: UploadFileItem[];
8
+ fileDetail?: FileListItem;
9
+ fileList: FileListItem[];
10
+ queryListParams?: QueryFileListParams;
11
+ }
12
+
13
+ export const initialFileManagerState: FileManagerState = {
14
+ creatingChunkingTaskIds: [],
15
+ creatingEmbeddingTaskIds: [],
16
+ dockUploadFileList: [],
17
+ fileList: [],
18
+ };
@@ -0,0 +1,58 @@
1
+ // import { FileStore } from '../../store';
2
+ import { FilesStoreState } from '@/store/file/initialState';
3
+ import { FileUploadStatus } from '@/types/files/upload';
4
+
5
+ const uploadStatusArray = new Set(['uploading', 'pending', 'processing']);
6
+
7
+ const dockFileList = (s: FilesStoreState) => s.dockUploadFileList;
8
+ const dockRawFileList = (s: FilesStoreState) => s.dockUploadFileList.map((item) => item.file);
9
+ const getFileById = (id?: string | null) => (s: FilesStoreState) => {
10
+ if (!id) return;
11
+
12
+ return s.fileList.find((item) => item.id === id);
13
+ };
14
+
15
+ const isUploadingFiles = (s: FilesStoreState) =>
16
+ s.dockUploadFileList.some((file) => uploadStatusArray.has(file.status));
17
+
18
+ const overviewUploadingStatus = (s: FilesStoreState): FileUploadStatus => {
19
+ if (s.dockUploadFileList.length === 0) return 'pending';
20
+ if (s.dockUploadFileList.some((file) => uploadStatusArray.has(file.status))) {
21
+ return 'uploading';
22
+ }
23
+
24
+ return 'success';
25
+ };
26
+
27
+ const overviewUploadingProgress = (s: FilesStoreState) => {
28
+ const uploadFiles = s.dockUploadFileList.filter(
29
+ (file) => file.status === 'uploading' || file.status === 'pending',
30
+ );
31
+
32
+ if (uploadFiles.length === 0) return 100;
33
+
34
+ const totalPercent = uploadFiles.length * 100;
35
+ const currentPercent = uploadFiles.reduce(
36
+ (acc, file) => acc + (file.uploadState?.progress || 0),
37
+ 0,
38
+ );
39
+
40
+ return (currentPercent / totalPercent) * 100;
41
+ };
42
+
43
+ const isCreatingFileParseTask = (id: string) => (s: FilesStoreState) =>
44
+ s.creatingChunkingTaskIds.includes(id);
45
+
46
+ const isCreatingChunkEmbeddingTask = (id: string) => (s: FilesStoreState) =>
47
+ s.creatingEmbeddingTaskIds.includes(id);
48
+
49
+ export const fileManagerSelectors = {
50
+ dockFileList,
51
+ dockRawFileList,
52
+ getFileById,
53
+ isCreatingChunkEmbeddingTask,
54
+ isCreatingFileParseTask,
55
+ isUploadingFiles,
56
+ overviewUploadingProgress,
57
+ overviewUploadingStatus,
58
+ };
@@ -66,7 +66,7 @@ describe('TTSFileAction', () => {
66
66
  };
67
67
 
68
68
  // Mock the fileService.uploadFile to resolve with uploadedFileData
69
- vi.spyOn(fileService, 'createFile').mockResolvedValue(uploadedFileData);
69
+ vi.spyOn(fileService, 'createFile').mockResolvedValue({ id: uploadedFileData.id, url: '' });
70
70
 
71
71
  let fileId;
72
72
  await act(async () => {
@@ -2,7 +2,7 @@ import useSWR, { SWRResponse } from 'swr';
2
2
  import { StateCreator } from 'zustand/vanilla';
3
3
 
4
4
  import { fileService } from '@/services/file';
5
- import { uploadService } from '@/services/upload';
5
+ import { legacyUploadService } from '@/services/upload_legacy';
6
6
  import { FilePreview } from '@/types/files';
7
7
 
8
8
  import { FileStore } from '../../store';
@@ -42,7 +42,7 @@ export const createTTSFileSlice: StateCreator<
42
42
  },
43
43
  uploadTTSFile: async (file) => {
44
44
  try {
45
- const res = await uploadService.uploadFile({
45
+ const res = await legacyUploadService.uploadFile({
46
46
  createdAt: file.lastModified,
47
47
  data: await file.arrayBuffer(),
48
48
  fileType: file.type,