@lobehub/chat 1.11.8 → 1.12.0

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 (440) 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 +46 -3
  7. package/locales/ar/common.json +1 -0
  8. package/locales/ar/components.json +2 -0
  9. package/locales/ar/error.json +1 -0
  10. package/locales/ar/file.json +91 -0
  11. package/locales/ar/knowledgeBase.json +31 -0
  12. package/locales/ar/portal.json +1 -0
  13. package/locales/bg-BG/chat.json +46 -3
  14. package/locales/bg-BG/common.json +1 -0
  15. package/locales/bg-BG/components.json +2 -0
  16. package/locales/bg-BG/error.json +1 -0
  17. package/locales/bg-BG/file.json +91 -0
  18. package/locales/bg-BG/knowledgeBase.json +31 -0
  19. package/locales/bg-BG/portal.json +1 -0
  20. package/locales/de-DE/chat.json +46 -3
  21. package/locales/de-DE/common.json +1 -0
  22. package/locales/de-DE/components.json +2 -0
  23. package/locales/de-DE/error.json +1 -0
  24. package/locales/de-DE/file.json +91 -0
  25. package/locales/de-DE/knowledgeBase.json +31 -0
  26. package/locales/de-DE/portal.json +1 -0
  27. package/locales/en-US/chat.json +46 -3
  28. package/locales/en-US/common.json +1 -0
  29. package/locales/en-US/components.json +2 -0
  30. package/locales/en-US/error.json +1 -0
  31. package/locales/en-US/file.json +91 -0
  32. package/locales/en-US/knowledgeBase.json +31 -0
  33. package/locales/en-US/portal.json +1 -0
  34. package/locales/es-ES/chat.json +46 -3
  35. package/locales/es-ES/common.json +1 -0
  36. package/locales/es-ES/components.json +2 -0
  37. package/locales/es-ES/error.json +1 -0
  38. package/locales/es-ES/file.json +91 -0
  39. package/locales/es-ES/knowledgeBase.json +31 -0
  40. package/locales/es-ES/portal.json +1 -0
  41. package/locales/fr-FR/chat.json +46 -3
  42. package/locales/fr-FR/common.json +1 -0
  43. package/locales/fr-FR/components.json +2 -0
  44. package/locales/fr-FR/error.json +1 -0
  45. package/locales/fr-FR/file.json +91 -0
  46. package/locales/fr-FR/knowledgeBase.json +31 -0
  47. package/locales/fr-FR/portal.json +1 -0
  48. package/locales/it-IT/chat.json +46 -3
  49. package/locales/it-IT/common.json +1 -0
  50. package/locales/it-IT/components.json +2 -0
  51. package/locales/it-IT/error.json +1 -0
  52. package/locales/it-IT/file.json +91 -0
  53. package/locales/it-IT/knowledgeBase.json +31 -0
  54. package/locales/it-IT/portal.json +1 -0
  55. package/locales/ja-JP/chat.json +46 -3
  56. package/locales/ja-JP/common.json +1 -0
  57. package/locales/ja-JP/components.json +2 -0
  58. package/locales/ja-JP/error.json +1 -0
  59. package/locales/ja-JP/file.json +91 -0
  60. package/locales/ja-JP/knowledgeBase.json +31 -0
  61. package/locales/ja-JP/portal.json +1 -0
  62. package/locales/ko-KR/chat.json +46 -3
  63. package/locales/ko-KR/common.json +1 -0
  64. package/locales/ko-KR/components.json +2 -0
  65. package/locales/ko-KR/error.json +1 -0
  66. package/locales/ko-KR/file.json +91 -0
  67. package/locales/ko-KR/knowledgeBase.json +31 -0
  68. package/locales/ko-KR/portal.json +1 -0
  69. package/locales/nl-NL/chat.json +46 -3
  70. package/locales/nl-NL/common.json +1 -0
  71. package/locales/nl-NL/components.json +2 -0
  72. package/locales/nl-NL/error.json +1 -0
  73. package/locales/nl-NL/file.json +91 -0
  74. package/locales/nl-NL/knowledgeBase.json +31 -0
  75. package/locales/nl-NL/portal.json +1 -0
  76. package/locales/pl-PL/chat.json +46 -3
  77. package/locales/pl-PL/common.json +1 -0
  78. package/locales/pl-PL/components.json +2 -0
  79. package/locales/pl-PL/error.json +1 -0
  80. package/locales/pl-PL/file.json +91 -0
  81. package/locales/pl-PL/knowledgeBase.json +31 -0
  82. package/locales/pl-PL/portal.json +1 -0
  83. package/locales/pt-BR/chat.json +46 -3
  84. package/locales/pt-BR/common.json +1 -0
  85. package/locales/pt-BR/components.json +2 -0
  86. package/locales/pt-BR/error.json +1 -0
  87. package/locales/pt-BR/file.json +91 -0
  88. package/locales/pt-BR/knowledgeBase.json +31 -0
  89. package/locales/pt-BR/portal.json +1 -0
  90. package/locales/ru-RU/chat.json +46 -3
  91. package/locales/ru-RU/common.json +1 -0
  92. package/locales/ru-RU/components.json +2 -0
  93. package/locales/ru-RU/error.json +1 -0
  94. package/locales/ru-RU/file.json +91 -0
  95. package/locales/ru-RU/knowledgeBase.json +31 -0
  96. package/locales/ru-RU/portal.json +1 -0
  97. package/locales/tr-TR/chat.json +46 -3
  98. package/locales/tr-TR/common.json +1 -0
  99. package/locales/tr-TR/components.json +2 -0
  100. package/locales/tr-TR/error.json +1 -0
  101. package/locales/tr-TR/file.json +91 -0
  102. package/locales/tr-TR/knowledgeBase.json +31 -0
  103. package/locales/tr-TR/portal.json +1 -0
  104. package/locales/vi-VN/chat.json +46 -3
  105. package/locales/vi-VN/common.json +1 -0
  106. package/locales/vi-VN/components.json +2 -0
  107. package/locales/vi-VN/error.json +1 -0
  108. package/locales/vi-VN/file.json +91 -0
  109. package/locales/vi-VN/knowledgeBase.json +31 -0
  110. package/locales/vi-VN/portal.json +1 -0
  111. package/locales/zh-CN/chat.json +46 -3
  112. package/locales/zh-CN/common.json +1 -0
  113. package/locales/zh-CN/components.json +2 -0
  114. package/locales/zh-CN/error.json +1 -0
  115. package/locales/zh-CN/file.json +91 -0
  116. package/locales/zh-CN/knowledgeBase.json +31 -0
  117. package/locales/zh-CN/portal.json +1 -0
  118. package/locales/zh-TW/chat.json +46 -3
  119. package/locales/zh-TW/common.json +1 -0
  120. package/locales/zh-TW/components.json +2 -0
  121. package/locales/zh-TW/error.json +1 -0
  122. package/locales/zh-TW/file.json +91 -0
  123. package/locales/zh-TW/knowledgeBase.json +31 -0
  124. package/locales/zh-TW/portal.json +1 -0
  125. package/package.json +3 -2
  126. package/scripts/migrateServerDB/docker.cjs +6 -0
  127. package/scripts/migrateServerDB/errorHint.js +17 -0
  128. package/scripts/migrateServerDB/index.ts +6 -0
  129. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/Content.tsx +37 -0
  130. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/index.tsx +87 -0
  131. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/style.ts +4 -0
  132. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileItem/utils.ts +28 -0
  133. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/FileList.tsx +41 -0
  134. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/FilePreview/index.tsx +40 -0
  135. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/SendMore.tsx +1 -1
  136. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/index.tsx +7 -22
  137. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/TextArea.tsx +1 -1
  138. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +2 -4
  139. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/File.tsx +72 -0
  140. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/Image.tsx +74 -0
  141. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/index.tsx +39 -0
  142. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/FileItem/style.ts +1 -0
  143. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/index.tsx +33 -0
  144. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/Container.tsx +41 -0
  145. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/index.tsx +154 -0
  146. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Send.tsx +34 -0
  147. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/index.tsx +24 -11
  148. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/components/UploadDetail/UploadStatus.tsx +71 -0
  149. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/components/UploadDetail/index.tsx +49 -0
  150. package/src/app/(main)/chat/(workspace)/@portal/FilePreview/index.tsx +26 -0
  151. package/src/app/(main)/chat/(workspace)/@portal/Home/Files/FileList/Item.tsx +53 -0
  152. package/src/app/(main)/chat/(workspace)/@portal/Home/Files/FileList/index.tsx +50 -0
  153. package/src/app/(main)/chat/(workspace)/@portal/Home/Files/index.tsx +21 -0
  154. package/src/app/(main)/chat/(workspace)/@portal/Home/index.tsx +2 -0
  155. package/src/app/(main)/chat/(workspace)/@portal/router.tsx +4 -0
  156. package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/KnowledgeTag.tsx +41 -0
  157. package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Tags.tsx +7 -2
  158. package/src/app/(main)/chat/(workspace)/_layout/Desktop/HotKeys.tsx +1 -1
  159. package/src/app/(main)/files/(content)/@menu/default.tsx +27 -0
  160. package/src/app/(main)/files/(content)/@menu/features/FileMenu/index.tsx +97 -0
  161. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/EmptyStatus.tsx +53 -0
  162. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/Item/Content.tsx +175 -0
  163. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/Item/index.tsx +69 -0
  164. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/KnowledgeBaseList.tsx +30 -0
  165. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/SkeletonList.tsx +57 -0
  166. package/src/app/(main)/files/(content)/@menu/features/KnowledgeBase/index.tsx +54 -0
  167. package/src/app/(main)/files/(content)/@modal/(.)[id]/FileDetail.tsx +16 -0
  168. package/src/app/(main)/files/(content)/@modal/(.)[id]/FilePreview.tsx +15 -0
  169. package/src/app/(main)/files/(content)/@modal/(.)[id]/FullscreenModal.tsx +85 -0
  170. package/src/app/(main)/files/(content)/@modal/(.)[id]/page.tsx +19 -0
  171. package/src/app/(main)/files/(content)/@modal/default.tsx +3 -0
  172. package/src/app/(main)/files/(content)/NotSupportClient.tsx +152 -0
  173. package/src/app/(main)/files/(content)/_layout/Desktop/index.tsx +28 -0
  174. package/src/app/(main)/files/(content)/_layout/Mobile.tsx +47 -0
  175. package/src/app/(main)/files/(content)/_layout/type.ts +7 -0
  176. package/src/app/(main)/files/(content)/layout.tsx +18 -0
  177. package/src/app/(main)/files/(content)/page.tsx +14 -0
  178. package/src/app/(main)/files/[id]/Header.tsx +63 -0
  179. package/src/app/(main)/files/[id]/page.tsx +44 -0
  180. package/src/app/(main)/files/features/FileDetail.tsx +93 -0
  181. package/src/app/(main)/files/hooks/useFileCategory.ts +9 -0
  182. package/src/app/(main)/files/layout.tsx +12 -0
  183. package/src/app/(main)/files/loading.tsx +21 -0
  184. package/src/app/(main)/repos/[id]/@menu/Head/index.tsx +33 -0
  185. package/src/app/(main)/repos/[id]/@menu/Menu/index.tsx +56 -0
  186. package/src/app/(main)/repos/[id]/@menu/default.tsx +25 -0
  187. package/src/app/(main)/repos/[id]/_layout/Desktop/index.tsx +25 -0
  188. package/src/app/(main)/repos/[id]/_layout/Mobile.tsx +47 -0
  189. package/src/app/(main)/repos/[id]/_layout/type.ts +6 -0
  190. package/src/app/(main)/repos/[id]/hooks/useKnowledgeItem.ts +7 -0
  191. package/src/app/(main)/repos/[id]/layout.tsx +13 -0
  192. package/src/app/(main)/repos/[id]/page.tsx +18 -0
  193. package/src/app/(main)/repos/layout.tsx +13 -0
  194. package/src/app/(main)/repos/page.tsx +5 -0
  195. package/src/app/trpc/async/[trpc]/route.ts +28 -0
  196. package/src/chains/abstractChunk.ts +19 -0
  197. package/src/chains/answerWithContext.ts +34 -0
  198. package/src/chains/rewriteQuery.ts +22 -0
  199. package/src/components/DragUpload/index.tsx +6 -99
  200. package/src/components/DragUpload/useDragUpload.tsx +146 -0
  201. package/src/components/FeatureList/index.tsx +64 -0
  202. package/src/components/FileParsingStatus/index.tsx +230 -0
  203. package/src/components/ImageItem/index.tsx +10 -2
  204. package/src/components/KnowledgeIcon/index.tsx +28 -0
  205. package/src/config/app.ts +6 -1
  206. package/src/config/featureFlags/schema.ts +1 -1
  207. package/src/config/modelProviders/bedrock.ts +5 -5
  208. package/src/const/file.ts +1 -0
  209. package/src/const/url.ts +1 -0
  210. package/src/database/client/models/file.ts +8 -2
  211. package/src/database/server/migrations/0005_pgvector.sql +2 -0
  212. package/src/database/server/migrations/0006_add_knowledge_base.sql +307 -0
  213. package/src/database/server/migrations/meta/0005_snapshot.json +2119 -0
  214. package/src/database/server/migrations/meta/0006_snapshot.json +3006 -0
  215. package/src/database/server/migrations/meta/_journal.json +14 -0
  216. package/src/database/server/models/__tests__/_test_template.ts +155 -0
  217. package/src/database/server/models/__tests__/agent.test.ts +226 -0
  218. package/src/database/server/models/__tests__/asyncTask.test.ts +176 -0
  219. package/src/database/server/models/__tests__/chunk.test.ts +336 -0
  220. package/src/database/server/models/__tests__/file.test.ts +317 -29
  221. package/src/database/server/models/__tests__/fixtures/embedding.ts +568 -0
  222. package/src/database/server/models/__tests__/knowledgeBase.test.ts +132 -0
  223. package/src/database/server/models/__tests__/message.test.ts +7 -4
  224. package/src/database/server/models/_template.ts +10 -1
  225. package/src/database/server/models/agent.ts +165 -0
  226. package/src/database/server/models/asyncTask.ts +96 -0
  227. package/src/database/server/models/chunk.ts +203 -0
  228. package/src/database/server/models/embedding.ts +47 -0
  229. package/src/database/server/models/file.ts +231 -12
  230. package/src/database/server/models/knowledgeBase.ts +94 -0
  231. package/src/database/server/models/message.ts +156 -30
  232. package/src/database/server/models/user.ts +12 -1
  233. package/src/database/server/schemas/lobechat/agent.ts +93 -0
  234. package/src/database/server/schemas/lobechat/discover.ts +1 -1
  235. package/src/database/server/schemas/lobechat/file.ts +118 -1
  236. package/src/database/server/schemas/lobechat/index.ts +5 -1
  237. package/src/database/server/schemas/lobechat/message.ts +169 -0
  238. package/src/database/server/schemas/lobechat/rag.ts +51 -0
  239. package/src/database/server/schemas/lobechat/relations.ts +68 -48
  240. package/src/database/server/schemas/lobechat/session.ts +77 -0
  241. package/src/database/server/schemas/lobechat/topic.ts +32 -0
  242. package/src/database/server/schemas/lobechat/user.ts +40 -25
  243. package/src/database/server/utils/idGenerator.ts +1 -0
  244. package/src/features/ChatInput/ActionBar/Clear.tsx +1 -1
  245. package/src/features/ChatInput/ActionBar/Knowledge/Dropdown.tsx +160 -0
  246. package/src/features/ChatInput/ActionBar/Knowledge/ListItem.tsx +52 -0
  247. package/src/features/ChatInput/ActionBar/Knowledge/index.tsx +54 -0
  248. package/src/features/ChatInput/ActionBar/Tools/index.tsx +1 -1
  249. package/src/features/ChatInput/ActionBar/Upload/ClientMode.tsx +52 -0
  250. package/src/features/ChatInput/ActionBar/Upload/ServerMode.tsx +104 -0
  251. package/src/features/ChatInput/ActionBar/Upload/index.tsx +8 -0
  252. package/src/features/ChatInput/ActionBar/config.ts +14 -5
  253. package/src/features/ChatInput/useSend.ts +16 -7
  254. package/src/features/Conversation/Messages/Assistant/FileChunks/Item/index.tsx +51 -0
  255. package/src/features/Conversation/Messages/Assistant/FileChunks/Item/style.ts +38 -0
  256. package/src/features/Conversation/Messages/Assistant/FileChunks/index.tsx +76 -0
  257. package/src/features/Conversation/Messages/Assistant/index.tsx +13 -4
  258. package/src/features/Conversation/Messages/Default.tsx +4 -0
  259. package/src/features/Conversation/Messages/User/BelowMessage.tsx +78 -0
  260. package/src/features/Conversation/Messages/User/FileListViewer/Item.tsx +53 -0
  261. package/src/features/Conversation/Messages/User/FileListViewer/index.tsx +21 -0
  262. package/src/{components/FileList/FileListViewer.tsx → features/Conversation/Messages/User/ImageFileListViewer.tsx} +10 -2
  263. package/src/features/Conversation/Messages/{User.tsx → User/index.tsx} +11 -2
  264. package/src/features/Conversation/Messages/index.ts +8 -3
  265. package/src/features/Conversation/components/ChatItem/index.tsx +33 -10
  266. package/src/features/Conversation/components/InboxWelcome/QuestionSuggest.tsx +1 -1
  267. package/src/features/Conversation/types/index.tsx +1 -0
  268. package/src/features/FileManager/ChunkDrawer/ChunkList/ChunkItem.tsx +61 -0
  269. package/src/features/FileManager/ChunkDrawer/ChunkList/index.tsx +42 -0
  270. package/src/features/FileManager/ChunkDrawer/Content.tsx +38 -0
  271. package/src/features/FileManager/ChunkDrawer/Loading/index.tsx +16 -0
  272. package/src/features/FileManager/ChunkDrawer/SimilaritySearchList/Item.tsx +62 -0
  273. package/src/features/FileManager/ChunkDrawer/SimilaritySearchList/index.tsx +31 -0
  274. package/src/features/FileManager/ChunkDrawer/index.tsx +48 -0
  275. package/src/features/FileManager/FileList/EmptyStatus.tsx +153 -0
  276. package/src/features/FileManager/FileList/FileListItem/ChunkTag.tsx +35 -0
  277. package/src/features/FileManager/FileList/FileListItem/DropdownMenu.tsx +150 -0
  278. package/src/features/FileManager/FileList/FileListItem/index.tsx +211 -0
  279. package/src/features/FileManager/FileList/FileSkeleton.tsx +25 -0
  280. package/src/features/FileManager/FileList/ToolBar/Config.tsx +28 -0
  281. package/src/features/FileManager/FileList/ToolBar/MultiSelectActions.tsx +152 -0
  282. package/src/features/FileManager/FileList/ToolBar/index.tsx +114 -0
  283. package/src/features/FileManager/FileList/index.tsx +143 -0
  284. package/src/features/FileManager/FileList/useCheckTaskStatus.ts +27 -0
  285. package/src/features/FileManager/Header/FilesSearchBar.tsx +41 -0
  286. package/src/features/FileManager/Header/UploadFileButton.tsx +79 -0
  287. package/src/features/FileManager/Header/index.tsx +39 -0
  288. package/src/features/FileManager/UploadDock/Item.tsx +124 -0
  289. package/src/features/FileManager/UploadDock/index.tsx +183 -0
  290. package/src/features/FileManager/index.tsx +38 -0
  291. package/src/features/FileSidePanel/index.tsx +79 -0
  292. package/src/features/FileViewer/NotSupport/index.tsx +54 -0
  293. package/src/features/FileViewer/PDFViewer/HighlightLayer.tsx +81 -0
  294. package/src/features/FileViewer/PDFViewer/index.tsx +93 -0
  295. package/src/features/FileViewer/PDFViewer/style.ts +20 -0
  296. package/src/features/FileViewer/PDFViewer/useResizeObserver.ts +33 -0
  297. package/src/features/FileViewer/TXTViewer/index.tsx +41 -0
  298. package/src/features/FileViewer/index.tsx +45 -0
  299. package/src/features/KnowledgeBaseModal/AddFilesToKnowledgeBase/SelectForm.tsx +115 -0
  300. package/src/features/KnowledgeBaseModal/AddFilesToKnowledgeBase/index.tsx +43 -0
  301. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/Action.tsx +103 -0
  302. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/EditCustomPlugin.tsx +55 -0
  303. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/PluginTag.tsx +58 -0
  304. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/index.tsx +70 -0
  305. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/List.tsx +49 -0
  306. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Loading.tsx +13 -0
  307. package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/index.tsx +39 -0
  308. package/src/features/KnowledgeBaseModal/CreateNew/CreateForm.tsx +73 -0
  309. package/src/features/KnowledgeBaseModal/CreateNew/index.tsx +35 -0
  310. package/src/features/KnowledgeBaseModal/index.ts +3 -0
  311. package/src/libs/langchain/loaders/pdf/index.ts +2 -2
  312. package/src/libs/trpc/async/asyncAuth.ts +24 -0
  313. package/src/libs/trpc/async/index.ts +10 -0
  314. package/src/libs/trpc/async/init.ts +11 -0
  315. package/src/libs/trpc/client/async.ts +14 -0
  316. package/src/libs/trpc/client/index.ts +1 -0
  317. package/src/libs/trpc/client/lambda.ts +9 -0
  318. package/src/libs/trpc/middleware/keyVaults.ts +18 -0
  319. package/src/libs/unstructured/__tests__/index.test.ts +0 -10
  320. package/src/libs/unstructured/index.ts +6 -11
  321. package/src/locales/default/chat.ts +47 -3
  322. package/src/locales/default/common.ts +1 -0
  323. package/src/locales/default/components.ts +2 -0
  324. package/src/locales/default/error.ts +6 -1
  325. package/src/locales/default/file.ts +92 -0
  326. package/src/locales/default/index.ts +4 -0
  327. package/src/locales/default/knowledgeBase.ts +31 -0
  328. package/src/locales/default/portal.ts +1 -0
  329. package/src/middleware.ts +3 -0
  330. package/src/server/asyncContext.ts +40 -0
  331. package/src/server/modules/ContentChunk/index.ts +135 -0
  332. package/src/server/modules/S3/index.ts +30 -5
  333. package/src/server/routers/async/caller.ts +27 -0
  334. package/src/server/routers/async/file.ts +247 -0
  335. package/src/server/routers/async/index.ts +12 -0
  336. package/src/server/routers/lambda/_template.ts +77 -0
  337. package/src/server/routers/lambda/agent.ts +159 -0
  338. package/src/server/routers/lambda/chunk.ts +189 -0
  339. package/src/server/routers/lambda/file.ts +129 -5
  340. package/src/server/routers/lambda/index.ts +6 -0
  341. package/src/server/routers/lambda/knowledgeBase.ts +79 -0
  342. package/src/server/routers/lambda/message.ts +6 -0
  343. package/src/server/routers/lambda/session.ts +0 -25
  344. package/src/server/routers/lambda/user.ts +5 -1
  345. package/src/server/services/chunk/index.ts +74 -0
  346. package/src/server/utils/files.ts +9 -0
  347. package/src/services/__tests__/chat.test.ts +18 -20
  348. package/src/services/__tests__/{upload.test.ts → upload_legacy.test.ts} +1 -1
  349. package/src/services/agent.ts +45 -0
  350. package/src/services/chat.ts +17 -15
  351. package/src/services/file/client.test.ts +1 -50
  352. package/src/services/file/client.ts +12 -25
  353. package/src/services/file/server.ts +25 -3
  354. package/src/services/file/type.ts +7 -4
  355. package/src/services/knowledgeBase.ts +34 -0
  356. package/src/services/message/client.test.ts +1 -1
  357. package/src/services/message/client.ts +29 -3
  358. package/src/services/message/index.ts +0 -2
  359. package/src/services/message/server.ts +9 -3
  360. package/src/services/message/type.ts +1 -13
  361. package/src/services/rag.ts +29 -0
  362. package/src/services/session/server.ts +1 -1
  363. package/src/services/upload.ts +89 -84
  364. package/src/services/upload_legacy.ts +104 -0
  365. package/src/services/user/client.ts +7 -2
  366. package/src/services/user/server.ts +6 -2
  367. package/src/services/user/type.ts +3 -2
  368. package/src/store/agent/slices/chat/action.ts +90 -18
  369. package/src/store/agent/slices/chat/initialState.ts +1 -0
  370. package/src/store/agent/slices/chat/selectors.ts +58 -0
  371. package/src/store/chat/slices/builtinTool/action.test.ts +2 -2
  372. package/src/store/chat/slices/builtinTool/action.ts +2 -2
  373. package/src/store/chat/slices/message/action.test.ts +2 -1
  374. package/src/store/chat/slices/message/action.ts +102 -26
  375. package/src/store/chat/slices/message/actions/rag.ts +148 -0
  376. package/src/store/chat/slices/message/initialState.ts +7 -0
  377. package/src/store/chat/slices/message/reducer.ts +6 -2
  378. package/src/store/chat/slices/message/selectors.ts +38 -3
  379. package/src/store/chat/slices/plugin/action.ts +8 -2
  380. package/src/store/chat/slices/portal/action.ts +8 -0
  381. package/src/store/chat/slices/portal/initialState.ts +3 -0
  382. package/src/store/chat/slices/portal/selectors.ts +8 -2
  383. package/src/store/file/initialState.ts +5 -1
  384. package/src/store/file/reducers/uploadFileList.ts +133 -0
  385. package/src/store/file/selectors.ts +3 -0
  386. package/src/store/file/slices/chat/action.test.ts +90 -90
  387. package/src/store/file/slices/chat/action.ts +164 -109
  388. package/src/store/file/slices/chat/initialState.ts +7 -2
  389. package/src/store/file/slices/chat/selectors.test.ts +84 -61
  390. package/src/store/file/slices/chat/selectors.ts +22 -32
  391. package/src/store/file/slices/chunk/action.ts +36 -0
  392. package/src/store/file/slices/chunk/index.ts +3 -0
  393. package/src/store/file/slices/chunk/initialState.ts +15 -0
  394. package/src/store/file/slices/chunk/selectors.ts +10 -0
  395. package/src/store/file/slices/fileManager/action.ts +187 -0
  396. package/src/store/file/slices/fileManager/index.ts +3 -0
  397. package/src/store/file/slices/fileManager/initialState.ts +18 -0
  398. package/src/store/file/slices/fileManager/selectors.ts +58 -0
  399. package/src/store/file/slices/tts/action.test.ts +1 -1
  400. package/src/store/file/slices/tts/action.ts +2 -2
  401. package/src/store/file/slices/upload/action.ts +164 -0
  402. package/src/store/file/store.ts +12 -1
  403. package/src/store/knowledgeBase/index.ts +2 -0
  404. package/src/store/knowledgeBase/initialState.ts +7 -0
  405. package/src/store/knowledgeBase/selectors.ts +1 -0
  406. package/src/store/knowledgeBase/slices/content/action.ts +27 -0
  407. package/src/store/knowledgeBase/slices/content/index.ts +1 -0
  408. package/src/store/knowledgeBase/slices/crud/action.ts +78 -0
  409. package/src/store/knowledgeBase/slices/crud/index.ts +3 -0
  410. package/src/store/knowledgeBase/slices/crud/initialState.ts +12 -0
  411. package/src/store/knowledgeBase/slices/crud/selectors.ts +7 -0
  412. package/src/store/knowledgeBase/store.ts +30 -0
  413. package/src/store/serverConfig/selectors.test.ts +1 -1
  414. package/src/store/user/slices/preference/selectors.ts +8 -0
  415. package/src/store/user/slices/settings/selectors/systemAgent.ts +2 -0
  416. package/src/tools/dalle/Render/Item/ImageFileItem.tsx +3 -23
  417. package/src/types/agent/index.ts +9 -0
  418. package/src/types/asyncTask.ts +31 -0
  419. package/src/types/chunk/document.ts +9 -0
  420. package/src/types/chunk/index.ts +52 -0
  421. package/src/types/files/index.ts +35 -0
  422. package/src/types/files/list.ts +44 -0
  423. package/src/types/files/upload.ts +91 -0
  424. package/src/types/knowledgeBase/index.ts +45 -0
  425. package/src/types/message/index.ts +54 -5
  426. package/src/types/rag.ts +16 -0
  427. package/src/utils/filter.test.ts +2 -0
  428. package/src/utils/server/auth.ts +23 -0
  429. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/LocalFiles.tsx +0 -46
  430. package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files.tsx +0 -19
  431. package/src/components/FileList/EditableFileList.tsx +0 -47
  432. package/src/components/FileList/index.ts +0 -2
  433. package/src/components/FileList/type.tsx +0 -7
  434. package/src/database/server/schemas/lobechat/chat.ts +0 -331
  435. package/src/features/ChatInput/ActionBar/FileUpload.tsx +0 -69
  436. package/src/features/ChatInput/useChatInput.ts +0 -45
  437. package/src/features/FileList/EditableFileList.tsx +0 -31
  438. package/src/features/FileList/FileListPreviewer.tsx +0 -17
  439. package/src/features/FileList/index.tsx +0 -2
  440. package/src/types/files.ts +0 -42
@@ -0,0 +1,31 @@
1
+ export default {
2
+ addToKnowledgeBase: {
3
+ addSuccess: '文件添加成功,<1>立即查看</1>',
4
+ confirm: '添加',
5
+ id: {
6
+ placeholder: '请选择要添加的知识库',
7
+ required: '请选择知识库',
8
+ title: '目标知识库',
9
+ },
10
+ title: '添加到知识库',
11
+ totalFiles: '已选择 {{count}} 个文件',
12
+ },
13
+ createNew: {
14
+ confirm: '新建',
15
+ description: {
16
+ placeholder: '知识库简介(选填)',
17
+ },
18
+ formTitle: '基本信息',
19
+ name: {
20
+ placeholder: '知识库名称',
21
+ required: '请填写知识库名称',
22
+ },
23
+ title: '新建知识库',
24
+ },
25
+ tab: {
26
+ files: '文档',
27
+ settings: '设置',
28
+ testing: '召回测试',
29
+ },
30
+ title: '知识库',
31
+ };
@@ -6,5 +6,6 @@ export default {
6
6
  summaryTooltip: '总结当前内容',
7
7
  },
8
8
  emptyArtifactList: '当前 Artifacts 列表为空,请在会话中按需使用插件后再查看',
9
+ files: '文件',
9
10
  title: '工作区',
10
11
  };
package/src/middleware.ts CHANGED
@@ -14,6 +14,8 @@ export const config = {
14
14
  '/',
15
15
  '/chat(.*)',
16
16
  '/settings(.*)',
17
+ '/files(.*)',
18
+ '/repos(.*)',
17
19
  // ↓ cloud ↓
18
20
  ],
19
21
  };
@@ -46,6 +48,7 @@ const nextAuthMiddleware = NextAuthEdge.auth((req) => {
46
48
 
47
49
  const isProtectedRoute = createRouteMatcher([
48
50
  '/settings(.*)',
51
+ '/files(.*)',
49
52
  // ↓ cloud ↓
50
53
  ]);
51
54
 
@@ -0,0 +1,40 @@
1
+ import { NextRequest } from 'next/server';
2
+
3
+ import { JWTPayload, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
4
+ import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
5
+
6
+ export interface AsyncAuthContext {
7
+ jwtPayload: JWTPayload;
8
+ secret: string;
9
+ userId?: string | null;
10
+ }
11
+
12
+ /**
13
+ * Inner function for `createContext` where we create the context.
14
+ * This is useful for testing when we don't want to mock Next.js' request/response
15
+ */
16
+ export const createAsyncContextInner = async (params?: {
17
+ jwtPayload?: JWTPayload;
18
+ secret?: string;
19
+ userId?: string | null;
20
+ }): Promise<AsyncAuthContext> => ({
21
+ jwtPayload: params?.jwtPayload || {},
22
+ secret: params?.secret || '',
23
+ userId: params?.userId,
24
+ });
25
+
26
+ export type AsyncContext = Awaited<ReturnType<typeof createAsyncContextInner>>;
27
+
28
+ export const createAsyncRouteContext = async (request: NextRequest): Promise<AsyncContext> => {
29
+ // for API-response caching see https://trpc.io/docs/v11/caching
30
+
31
+ const authorization = request.headers.get('Authorization');
32
+ const lobeChatAuthorization = request.headers.get(LOBE_CHAT_AUTH_HEADER);
33
+
34
+ const secret = authorization?.split(' ')[1];
35
+ const gateKeeper = await KeyVaultsGateKeeper.initWithEnvKey();
36
+ const { plaintext } = await gateKeeper.decrypt(lobeChatAuthorization || '');
37
+
38
+ const { userId, payload } = JSON.parse(plaintext);
39
+ return createAsyncContextInner({ jwtPayload: payload, secret, userId });
40
+ };
@@ -0,0 +1,135 @@
1
+ import { ChunkingLoader } from 'src/libs/langchain';
2
+ import { Strategy } from 'unstructured-client/sdk/models/shared';
3
+
4
+ import { NewChunkItem, NewUnstructuredChunkItem } from '@/database/server/schemas/lobechat';
5
+ import { ChunkingStrategy, Unstructured } from '@/libs/unstructured';
6
+
7
+ export interface ChunkContentParams {
8
+ content: Uint8Array;
9
+ fileType: string;
10
+ filename: string;
11
+ mode?: 'fast' | 'hi-res';
12
+ }
13
+
14
+ interface ChunkResult {
15
+ chunks: NewChunkItem[];
16
+ unstructuredChunks?: NewUnstructuredChunkItem[];
17
+ }
18
+
19
+ export class ContentChunk {
20
+ private unstructuredClient: Unstructured;
21
+ private langchainClient: ChunkingLoader;
22
+
23
+ constructor() {
24
+ this.unstructuredClient = new Unstructured();
25
+ this.langchainClient = new ChunkingLoader();
26
+ }
27
+
28
+ isUsingUnstructured(params: ChunkContentParams) {
29
+ return params.fileType === 'application/pdf' && params.mode === 'hi-res';
30
+ }
31
+
32
+ async chunkContent(params: ChunkContentParams): Promise<ChunkResult> {
33
+ if (this.isUsingUnstructured(params))
34
+ return await this.chunkByUnstructured(params.filename, params.content);
35
+
36
+ return await this.chunkByLangChain(params.filename, params.content);
37
+ }
38
+
39
+ private chunkByUnstructured = async (
40
+ filename: string,
41
+ content: Uint8Array,
42
+ ): Promise<ChunkResult> => {
43
+ const result = await this.unstructuredClient.partition({
44
+ chunkingStrategy: ChunkingStrategy.ByPage,
45
+ fileContent: content,
46
+ filename,
47
+ strategy: Strategy.Auto,
48
+ });
49
+
50
+ // after finish partition, we need to filter out some elements
51
+ const documents = result.compositeElements
52
+ .filter((e) => !new Set(['PageNumber', 'Footer']).has(e.type))
53
+ .map((item, index): NewChunkItem => {
54
+ const {
55
+ text_as_html,
56
+ page_number,
57
+ page_name,
58
+ image_mime_type,
59
+ image_base64,
60
+ parent_id,
61
+ languages,
62
+ coordinates,
63
+ } = item.metadata;
64
+
65
+ return {
66
+ id: item.element_id,
67
+ index,
68
+ metadata: {
69
+ coordinates,
70
+ image_base64,
71
+ image_mime_type,
72
+ languages,
73
+ page_name,
74
+ page_number,
75
+ parent_id,
76
+ text_as_html,
77
+ },
78
+ text: item.text,
79
+ type: item.type,
80
+ };
81
+ });
82
+
83
+ const chunks = result.originElements
84
+ .filter((e) => !new Set(['PageNumber', 'Footer']).has(e.type))
85
+ .map((item, index): NewUnstructuredChunkItem => {
86
+ const {
87
+ text_as_html,
88
+ page_number,
89
+ page_name,
90
+ image_mime_type,
91
+ image_base64,
92
+ parent_id,
93
+ languages,
94
+ coordinates,
95
+ } = item.metadata;
96
+
97
+ return {
98
+ compositeId: item.compositeId,
99
+ id: item.element_id,
100
+ index,
101
+ metadata: {
102
+ coordinates,
103
+ image_base64,
104
+ image_mime_type,
105
+ languages,
106
+ page_name,
107
+ page_number,
108
+ text_as_html,
109
+ },
110
+ parentId: parent_id,
111
+ text: item.text,
112
+ type: item.type,
113
+ };
114
+ });
115
+
116
+ return { chunks: documents, unstructuredChunks: chunks };
117
+ };
118
+
119
+ private chunkByLangChain = async (
120
+ filename: string,
121
+ content: Uint8Array,
122
+ ): Promise<ChunkResult> => {
123
+ const res = await this.langchainClient.partitionContent(filename, content);
124
+
125
+ const documents = res.map((item, index) => ({
126
+ id: item.id,
127
+ index,
128
+ metadata: item.metadata,
129
+ text: item.pageContent,
130
+ type: 'LangChainElement',
131
+ }));
132
+
133
+ return { chunks: documents };
134
+ };
135
+ }
@@ -1,6 +1,7 @@
1
1
  import {
2
+ DeleteObjectCommand,
3
+ DeleteObjectsCommand,
2
4
  GetObjectCommand,
3
- ListObjectsCommand,
4
5
  PutObjectCommand,
5
6
  S3Client,
6
7
  } from '@aws-sdk/client-s3';
@@ -45,13 +46,22 @@ export class S3 {
45
46
  });
46
47
  }
47
48
 
48
- public async getImages(): Promise<FileType[]> {
49
- const command = new ListObjectsCommand({
49
+ public async deleteFile(key: string) {
50
+ const command = new DeleteObjectCommand({
50
51
  Bucket: this.bucket,
52
+ Key: key,
53
+ });
54
+
55
+ return this.client.send(command);
56
+ }
57
+
58
+ public async deleteFiles(keys: string[]) {
59
+ const command = new DeleteObjectsCommand({
60
+ Bucket: this.bucket,
61
+ Delete: { Objects: keys.map((key) => ({ Key: key })) },
51
62
  });
52
63
 
53
- const res = await this.client.send(command);
54
- return listFileSchema.parse(res.Contents);
64
+ return this.client.send(command);
55
65
  }
56
66
 
57
67
  public async getFileContent(key: string): Promise<string> {
@@ -69,6 +79,21 @@ export class S3 {
69
79
  return response.Body.transformToString();
70
80
  }
71
81
 
82
+ public async getFileByteArray(key: string): Promise<Uint8Array> {
83
+ const command = new GetObjectCommand({
84
+ Bucket: this.bucket,
85
+ Key: key,
86
+ });
87
+
88
+ const response = await this.client.send(command);
89
+
90
+ if (!response.Body) {
91
+ throw new Error(`No body in response with ${key}`);
92
+ }
93
+
94
+ return response.Body.transformToByteArray();
95
+ }
96
+
72
97
  public async createPreSignedUrl(key: string): Promise<string> {
73
98
  const command = new PutObjectCommand({
74
99
  ACL: this.setAcl ? 'public-read' : undefined,
@@ -0,0 +1,27 @@
1
+ import { createTRPCClient, httpBatchLink } from '@trpc/client';
2
+ import superjson from 'superjson';
3
+ import urlJoin from 'url-join';
4
+
5
+ import { appEnv } from '@/config/app';
6
+ import { serverDBEnv } from '@/config/db';
7
+ import { JWTPayload, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
8
+ import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
9
+
10
+ import type { AsyncRouter } from './index';
11
+
12
+ export const createAsyncServerClient = async (userId: string, payload: JWTPayload) => {
13
+ const gateKeeper = await KeyVaultsGateKeeper.initWithEnvKey();
14
+
15
+ return createTRPCClient<AsyncRouter>({
16
+ links: [
17
+ httpBatchLink({
18
+ headers: {
19
+ Authorization: `Bearer ${serverDBEnv.KEY_VAULTS_SECRET}`,
20
+ [LOBE_CHAT_AUTH_HEADER]: await gateKeeper.encrypt(JSON.stringify({ payload, userId })),
21
+ },
22
+ transformer: superjson,
23
+ url: urlJoin(appEnv.APP_URL!, '/trpc/async'),
24
+ }),
25
+ ],
26
+ });
27
+ };
@@ -0,0 +1,247 @@
1
+ import { TRPCError } from '@trpc/server';
2
+ import { chunk } from 'lodash-es';
3
+ import pMap from 'p-map';
4
+ import { z } from 'zod';
5
+
6
+ import { initAgentRuntimeWithUserPayload } from '@/app/api/chat/agentRuntime';
7
+ import { fileEnv } from '@/config/file';
8
+ import { DEFAULT_EMBEDDING_MODEL } from '@/const/settings';
9
+ import { ASYNC_TASK_TIMEOUT, AsyncTaskModel } from '@/database/server/models/asyncTask';
10
+ import { ChunkModel } from '@/database/server/models/chunk';
11
+ import { EmbeddingModel } from '@/database/server/models/embedding';
12
+ import { FileModel } from '@/database/server/models/file';
13
+ import { NewChunkItem, NewEmbeddingsItem } from '@/database/server/schemas/lobechat';
14
+ import { ModelProvider } from '@/libs/agent-runtime';
15
+ import { asyncAuthedProcedure, asyncRouter as router } from '@/libs/trpc/async';
16
+ import { S3 } from '@/server/modules/S3';
17
+ import { ChunkService } from '@/server/services/chunk';
18
+ import { AsyncTaskError, AsyncTaskErrorType, AsyncTaskStatus } from '@/types/asyncTask';
19
+ import { safeParseJSON } from '@/utils/safeParseJSON';
20
+
21
+ const fileProcedure = asyncAuthedProcedure.use(async (opts) => {
22
+ const { ctx } = opts;
23
+
24
+ return opts.next({
25
+ ctx: {
26
+ asyncTaskModel: new AsyncTaskModel(ctx.userId),
27
+ chunkModel: new ChunkModel(ctx.userId),
28
+ chunkService: new ChunkService(ctx.userId),
29
+ embeddingModel: new EmbeddingModel(ctx.userId),
30
+ fileModel: new FileModel(ctx.userId),
31
+ },
32
+ });
33
+ });
34
+
35
+ export const fileRouter = router({
36
+ embeddingChunks: fileProcedure
37
+ .input(
38
+ z.object({
39
+ fileId: z.string(),
40
+ model: z.string().default(DEFAULT_EMBEDDING_MODEL),
41
+ taskId: z.string(),
42
+ }),
43
+ )
44
+ .mutation(async ({ ctx, input }) => {
45
+ const file = await ctx.fileModel.findById(input.fileId);
46
+
47
+ if (!file) {
48
+ throw new TRPCError({ code: 'BAD_REQUEST', message: 'File not found' });
49
+ }
50
+
51
+ const asyncTask = await ctx.asyncTaskModel.findById(input.taskId);
52
+
53
+ if (!asyncTask) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Async Task not found' });
54
+
55
+ try {
56
+ const timeoutPromise = new Promise((_, reject) => {
57
+ setTimeout(() => {
58
+ reject({
59
+ body: { detail: 'embedding task is timeout, please try again' },
60
+ name: AsyncTaskErrorType.Timeout,
61
+ } as AsyncTaskError);
62
+ }, ASYNC_TASK_TIMEOUT);
63
+ });
64
+
65
+ const embeddingPromise = async () => {
66
+ // update the task status to success
67
+ await ctx.asyncTaskModel.update(input.taskId, {
68
+ status: AsyncTaskStatus.Processing,
69
+ });
70
+
71
+ const startAt = Date.now();
72
+
73
+ const CHUNK_SIZE = 50;
74
+ const CONCURRENCY = 10;
75
+
76
+ const chunks = await ctx.chunkModel.getChunksTextByFileId(input.fileId);
77
+ const requestArray = chunk(chunks, CHUNK_SIZE);
78
+
79
+ await pMap(
80
+ requestArray,
81
+ async (chunks, index) => {
82
+ const agentRuntime = await initAgentRuntimeWithUserPayload(
83
+ ModelProvider.OpenAI,
84
+ ctx.jwtPayload,
85
+ );
86
+
87
+ const number = index + 1;
88
+ console.log(`执行第 ${number} 个任务`);
89
+
90
+ console.time(`任务[${number}]: embeddings`);
91
+
92
+ const embeddings = await agentRuntime.embeddings({
93
+ dimensions: 1024,
94
+ input: chunks.map((c) => c.text),
95
+ model: input.model,
96
+ });
97
+ console.timeEnd(`任务[${number}]: embeddings`);
98
+
99
+ const items: NewEmbeddingsItem[] =
100
+ embeddings?.map((e) => ({
101
+ chunkId: chunks[e.index].id,
102
+ embeddings: e.embedding,
103
+ fileId: input.fileId,
104
+ model: input.model,
105
+ })) || [];
106
+
107
+ console.time(`任务[${number}]: insert db`);
108
+ await ctx.embeddingModel.bulkCreate(items);
109
+ console.timeEnd(`任务[${number}]: insert db`);
110
+ },
111
+ { concurrency: CONCURRENCY },
112
+ );
113
+
114
+ const duration = Date.now() - startAt;
115
+ // update the task status to success
116
+ await ctx.asyncTaskModel.update(input.taskId, {
117
+ duration,
118
+ status: AsyncTaskStatus.Success,
119
+ });
120
+
121
+ return { success: true };
122
+ };
123
+
124
+ // Race between the chunking process and the timeout
125
+ return await Promise.race([embeddingPromise(), timeoutPromise]);
126
+ } catch (e) {
127
+ console.error('embeddingChunks error', e);
128
+ await ctx.asyncTaskModel.update(input.taskId, {
129
+ error: e,
130
+ status: AsyncTaskStatus.Error,
131
+ });
132
+
133
+ return {
134
+ message: `File ${file.name}(${input.taskId}) failed to embedding: ${(e as Error).message}`,
135
+ success: false,
136
+ };
137
+ }
138
+ }),
139
+
140
+ parseFileToChunks: fileProcedure
141
+ .input(
142
+ z.object({
143
+ fileId: z.string(),
144
+ taskId: z.string(),
145
+ }),
146
+ )
147
+ .mutation(async ({ ctx, input }) => {
148
+ const file = await ctx.fileModel.findById(input.fileId);
149
+ if (!file) {
150
+ throw new TRPCError({ code: 'BAD_REQUEST', message: 'File not found' });
151
+ }
152
+
153
+ const s3 = new S3();
154
+
155
+ let content: Uint8Array | undefined;
156
+ try {
157
+ content = await s3.getFileByteArray(file.url);
158
+ } catch (e) {
159
+ console.error(e);
160
+ // if file not found, delete it from db
161
+ if ((e as any).Code === 'NoSuchKey') {
162
+ await ctx.fileModel.delete(input.fileId);
163
+ throw new TRPCError({ code: 'BAD_REQUEST', message: 'File not found' });
164
+ }
165
+ }
166
+
167
+ if (!content) return;
168
+
169
+ const asyncTask = await ctx.asyncTaskModel.findById(input.taskId);
170
+
171
+ if (!asyncTask) throw new TRPCError({ code: 'BAD_REQUEST', message: 'Async Task not found' });
172
+
173
+ try {
174
+ const startAt = Date.now();
175
+
176
+ const timeoutPromise = new Promise((_, reject) => {
177
+ setTimeout(() => {
178
+ reject({
179
+ body: { detail: 'chunking task is timeout, please try again' },
180
+ name: AsyncTaskErrorType.Timeout,
181
+ } as AsyncTaskError);
182
+ }, ASYNC_TASK_TIMEOUT);
183
+ });
184
+
185
+ const chunkingPromise = async () => {
186
+ const chunkService = ctx.chunkService;
187
+ // update the task status to processing
188
+ await ctx.asyncTaskModel.update(input.taskId, { status: AsyncTaskStatus.Processing });
189
+
190
+ // partition file to chunks
191
+ const chunkResult = await chunkService.chunkContent({
192
+ content,
193
+ fileType: file.fileType,
194
+ filename: file.name,
195
+ });
196
+
197
+ // after finish partition, we need to filter out some elements
198
+ const chunks = chunkResult.chunks.map(
199
+ (item): NewChunkItem => ({ ...item, userId: ctx.userId }),
200
+ );
201
+
202
+ const duration = Date.now() - startAt;
203
+
204
+ await ctx.chunkModel.bulkCreate(chunks, input.fileId);
205
+
206
+ if (chunkResult.unstructuredChunks) {
207
+ const unstructuredChunks = chunkResult.unstructuredChunks.map(
208
+ (item): NewChunkItem => ({ ...item, fileId: input.fileId, userId: ctx.userId }),
209
+ );
210
+ await ctx.chunkModel.bulkCreateUnstructuredChunks(unstructuredChunks);
211
+ }
212
+
213
+ // update the task status to success
214
+ await ctx.asyncTaskModel.update(input.taskId, {
215
+ duration,
216
+ status: AsyncTaskStatus.Success,
217
+ });
218
+
219
+ // if enable auto embedding, trigger the embedding task
220
+ if (fileEnv.CHUNKS_AUTO_EMBEDDING) {
221
+ await chunkService.asyncEmbeddingFileChunks(input.fileId, ctx.jwtPayload);
222
+ }
223
+
224
+ return { success: true };
225
+ };
226
+ // Race between the chunking process and the timeout
227
+ return await Promise.race([chunkingPromise(), timeoutPromise]);
228
+ } catch (e) {
229
+ const error = e as any;
230
+
231
+ const asyncTaskError: AsyncTaskError = error.body
232
+ ? { body: safeParseJSON(error.body) ?? error.body, name: error.name }
233
+ : { body: { detail: error.message }, name: (error as Error).name };
234
+
235
+ console.error('[Chunking Error]', asyncTaskError);
236
+ await ctx.asyncTaskModel.update(input.taskId, {
237
+ error: asyncTaskError,
238
+ status: AsyncTaskStatus.Error,
239
+ });
240
+
241
+ return {
242
+ message: `File ${file.name}(${input.taskId}) failed to chunking: ${(e as Error).message}`,
243
+ success: false,
244
+ };
245
+ }
246
+ }),
247
+ });
@@ -0,0 +1,12 @@
1
+ import { publicProcedure, asyncRouter as router } from '@/libs/trpc/async';
2
+
3
+ import { fileRouter } from './file';
4
+
5
+ export const asyncRouter = router({
6
+ file: fileRouter,
7
+ healthcheck: publicProcedure.query(() => "i'm live!"),
8
+ });
9
+
10
+ export type AsyncRouter = typeof asyncRouter;
11
+
12
+ export * from './caller';
@@ -0,0 +1,77 @@
1
+ import { z } from 'zod';
2
+
3
+ import { SessionGroupModel } from '@/database/server/models/sessionGroup';
4
+ import { insertSessionGroupSchema } from '@/database/server/schemas/lobechat';
5
+ import { authedProcedure, router } from '@/libs/trpc';
6
+ import { SessionGroupItem } from '@/types/session';
7
+
8
+ const sessionProcedure = authedProcedure.use(async (opts) => {
9
+ const { ctx } = opts;
10
+
11
+ return opts.next({
12
+ ctx: {
13
+ sessionGroupModel: new SessionGroupModel(ctx.userId),
14
+ },
15
+ });
16
+ });
17
+
18
+ export const sessionGroupRouter = router({
19
+ createSessionGroup: sessionProcedure
20
+ .input(
21
+ z.object({
22
+ name: z.string(),
23
+ sort: z.number().optional(),
24
+ }),
25
+ )
26
+ .mutation(async ({ input, ctx }) => {
27
+ const data = await ctx.sessionGroupModel.create({
28
+ name: input.name,
29
+ sort: input.sort,
30
+ });
31
+
32
+ return data?.id;
33
+ }),
34
+
35
+ getSessionGroup: sessionProcedure.query(async ({ ctx }): Promise<SessionGroupItem[]> => {
36
+ return ctx.sessionGroupModel.query() as any;
37
+ }),
38
+
39
+ removeAllSessionGroups: sessionProcedure.mutation(async ({ ctx }) => {
40
+ return ctx.sessionGroupModel.deleteAll();
41
+ }),
42
+
43
+ removeSessionGroup: sessionProcedure
44
+ .input(z.object({ id: z.string(), removeChildren: z.boolean().optional() }))
45
+ .mutation(async ({ input, ctx }) => {
46
+ return ctx.sessionGroupModel.delete(input.id);
47
+ }),
48
+
49
+ updateSessionGroup: sessionProcedure
50
+ .input(
51
+ z.object({
52
+ id: z.string(),
53
+ value: insertSessionGroupSchema.partial(),
54
+ }),
55
+ )
56
+ .mutation(async ({ input, ctx }) => {
57
+ return ctx.sessionGroupModel.update(input.id, input.value);
58
+ }),
59
+ updateSessionGroupOrder: sessionProcedure
60
+ .input(
61
+ z.object({
62
+ sortMap: z.array(
63
+ z.object({
64
+ id: z.string(),
65
+ sort: z.number(),
66
+ }),
67
+ ),
68
+ }),
69
+ )
70
+ .mutation(async ({ input, ctx }) => {
71
+ console.log('sortMap:', input.sortMap);
72
+
73
+ return ctx.sessionGroupModel.updateOrder(input.sortMap);
74
+ }),
75
+ });
76
+
77
+ export type SessionGroupRouter = typeof sessionGroupRouter;