@lobehub/chat 1.84.27 → 1.85.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 (48) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/docs/development/database-schema.dbml +59 -1
  4. package/package.json +2 -1
  5. package/packages/file-loaders/package.json +5 -1
  6. package/packages/file-loaders/src/loadFile.ts +51 -1
  7. package/packages/file-loaders/src/loaders/docx/index.ts +16 -1
  8. package/packages/file-loaders/src/loaders/excel/index.ts +30 -2
  9. package/packages/file-loaders/src/loaders/pdf/__snapshots__/index.test.ts.snap +1 -1
  10. package/packages/file-loaders/src/loaders/pdf/index.ts +52 -12
  11. package/packages/file-loaders/src/loaders/pptx/index.ts +32 -1
  12. package/packages/file-loaders/src/loaders/text/index.test.ts +1 -1
  13. package/packages/file-loaders/src/loaders/text/index.ts +13 -1
  14. package/packages/file-loaders/test/__snapshots__/loaders.test.ts.snap +41 -0
  15. package/packages/file-loaders/test/loaders.test.ts +20 -0
  16. package/packages/file-loaders/test/setup.ts +17 -0
  17. package/packages/file-loaders/vitest.config.ts +14 -0
  18. package/src/const/file.ts +8 -1
  19. package/src/database/client/migrations.json +23 -1
  20. package/src/database/migrations/0022_add_documents.sql +49 -0
  21. package/src/database/migrations/meta/0022_snapshot.json +5340 -0
  22. package/src/database/migrations/meta/_journal.json +7 -0
  23. package/src/database/models/_template.ts +1 -1
  24. package/src/database/models/document.ts +54 -0
  25. package/src/database/models/message.ts +25 -0
  26. package/src/database/repositories/tableViewer/index.test.ts +1 -1
  27. package/src/database/schemas/document.ts +104 -0
  28. package/src/database/schemas/index.ts +1 -0
  29. package/src/database/schemas/relations.ts +34 -2
  30. package/src/database/schemas/topic.ts +31 -8
  31. package/src/database/utils/idGenerator.ts +1 -0
  32. package/src/features/ChatInput/Desktop/FilePreview/FileItem/Content.tsx +1 -1
  33. package/src/features/ChatInput/Desktop/FilePreview/FileItem/index.tsx +10 -10
  34. package/src/features/ChatInput/components/UploadDetail/UploadStatus.tsx +2 -2
  35. package/src/features/Conversation/Actions/Error.tsx +2 -2
  36. package/src/libs/trpc/lambda/context.ts +7 -0
  37. package/src/prompts/files/file.ts +6 -4
  38. package/src/server/routers/lambda/document.ts +36 -0
  39. package/src/server/routers/lambda/index.ts +2 -0
  40. package/src/server/services/document/index.ts +66 -0
  41. package/src/server/services/mcp/index.ts +0 -4
  42. package/src/services/rag.ts +4 -0
  43. package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +2 -2
  44. package/src/store/chat/slices/aiChat/actions/rag.ts +2 -3
  45. package/src/store/file/slices/chat/action.ts +3 -51
  46. package/src/types/document/index.ts +172 -0
  47. package/src/types/message/chat.ts +1 -0
  48. package/src/features/ChatInput/Desktop/FilePreview/FileItem/style.ts +0 -4
@@ -197,13 +197,13 @@ describe('chatRAG actions', () => {
197
197
  expect(result.current.internal_shouldUseRAG()).toBe(true);
198
198
  });
199
199
 
200
- it('should return true if has user files', () => {
200
+ it('should return false if has user files', () => {
201
201
  const { result } = renderHook(() => useChatStore());
202
202
 
203
203
  vi.spyOn(agentSelectors, 'hasEnabledKnowledge').mockReturnValue(false);
204
204
  vi.spyOn(chatSelectors, 'currentUserFiles').mockReturnValue([{ id: 'file-1' }] as any);
205
205
 
206
- expect(result.current.internal_shouldUseRAG()).toBe(true);
206
+ expect(result.current.internal_shouldUseRAG()).toBeFalsy();
207
207
  });
208
208
 
209
209
  it('should return false if no knowledge or files', () => {
@@ -130,9 +130,8 @@ export const chatRag: StateCreator<ChatStore, [['zustand/devtools', never]], [],
130
130
  return rewriteQuery;
131
131
  },
132
132
  internal_shouldUseRAG: () => {
133
- const userFiles = chatSelectors.currentUserFiles(get()).map((f) => f.id);
134
- // if there is relative files or enabled knowledge, try with ragQuery
135
- return hasEnabledKnowledge() || userFiles.length > 0;
133
+ // if there is enabled knowledge, try with ragQuery
134
+ return hasEnabledKnowledge();
136
135
  },
137
136
 
138
137
  internal_toggleMessageRAGLoading: (loading, id) => {
@@ -7,14 +7,10 @@ import { fileService } from '@/services/file';
7
7
  import { ServerService } from '@/services/file/server';
8
8
  import { ragService } from '@/services/rag';
9
9
  import { UPLOAD_NETWORK_ERROR } from '@/services/upload';
10
- import { userService } from '@/services/user';
11
- import { useAgentStore } from '@/store/agent';
12
10
  import {
13
11
  UploadFileListDispatch,
14
12
  uploadFileListReducer,
15
13
  } from '@/store/file/reducers/uploadFileList';
16
- import { useUserStore } from '@/store/user';
17
- import { preferenceSelectors } from '@/store/user/selectors';
18
14
  import { FileListItem } from '@/types/files';
19
15
  import { UploadFileItem } from '@/types/files/upload';
20
16
  import { isChunkingUnsupported } from '@/utils/isChunkingUnsupported';
@@ -97,7 +93,7 @@ export const createFileSlice: StateCreator<
97
93
  },
98
94
 
99
95
  uploadChatFiles: async (rawFiles) => {
100
- const { dispatchChatUploadFileList, startAsyncTask } = get();
96
+ const { dispatchChatUploadFileList } = get();
101
97
  // 0. skip file in blacklist
102
98
  const files = rawFiles.filter((file) => !FILE_UPLOAD_BLACKLIST.includes(file.name));
103
99
  // 1. add files with base64
@@ -154,52 +150,8 @@ export const createFileSlice: StateCreator<
154
150
  // image don't need to be chunked and embedding
155
151
  if (isChunkingUnsupported(file.type)) return;
156
152
 
157
- // 3. auto chunk and embedding
158
- dispatchChatUploadFileList({
159
- id: fileResult.id,
160
- type: 'updateFile',
161
- // make the taks empty to hint the user that the task is starting but not triggered
162
- value: { tasks: {} },
163
- });
164
-
165
- await startAsyncTask(
166
- fileResult.id,
167
- async (id) => {
168
- const data = await ragService.createParseFileTask(id);
169
- if (!data || !data.id) throw new Error('failed to createParseFileTask');
170
-
171
- // run the assignment
172
- useAgentStore
173
- .getState()
174
- .addFilesToAgent([id], false)
175
- .then(() => {
176
- // trigger the tip if it's the first time
177
- if (!preferenceSelectors.shouldTriggerFileInKnowledgeBaseTip(useUserStore.getState()))
178
- return;
179
-
180
- userService.updateGuide({ uploadFileInKnowledgeBase: true });
181
- });
182
-
183
- return data.id;
184
- },
185
-
186
- (fileItem) => {
187
- dispatchChatUploadFileList({
188
- id: fileResult.id,
189
- type: 'updateFile',
190
- value: {
191
- tasks: {
192
- chunkCount: fileItem.chunkCount,
193
- chunkingError: fileItem.chunkingError,
194
- chunkingStatus: fileItem.chunkingStatus,
195
- embeddingError: fileItem.embeddingError,
196
- embeddingStatus: fileItem.embeddingStatus,
197
- finishEmbedding: fileItem.finishEmbedding,
198
- },
199
- },
200
- });
201
- },
202
- );
153
+ const data = await ragService.parseFileContent(fileResult.id);
154
+ console.log(data);
203
155
  });
204
156
 
205
157
  await Promise.all(pools);
@@ -0,0 +1,172 @@
1
+ /**
2
+ * 在 LobeChat 中的文档对象
3
+ */
4
+ export interface LobeDocument {
5
+ /**
6
+ * 文件内容
7
+ */
8
+ content: string | null;
9
+ /**
10
+ * 文件创建时间戳。
11
+ */
12
+ createdAt: Date;
13
+
14
+ /**
15
+ * 文件类型或扩展名
16
+ */
17
+ fileType: string;
18
+
19
+ /**
20
+ * 原始文件名。
21
+ */
22
+ filename: string;
23
+
24
+ id: string;
25
+
26
+ /**
27
+ * 文件级别的元数据。
28
+ * 例如从文件属性中提取的标题、作者,或整个文件加载失败时的错误。
29
+ */
30
+ metadata: {
31
+ /**
32
+ * 允许添加其他文件级别的元数据。
33
+ */
34
+ [key: string]: any;
35
+ /**
36
+ * 文档作者 (如果可用)。
37
+ */
38
+ author?: string;
39
+ /**
40
+ * 如果整个文件加载失败,记录错误信息。
41
+ */
42
+ error?: string;
43
+ };
44
+
45
+ /**
46
+ * 包含文档中所有逻辑页面/块的数组。
47
+ * 顺序通常对应文件中的自然顺序。
48
+ */
49
+ pages?: LobeDocumentPage[];
50
+
51
+ /**
52
+ * 原始文件的完整路径。
53
+ */
54
+ source: string;
55
+
56
+ /**
57
+ * 文档标题 (如果可用)。
58
+ */
59
+ title?: string;
60
+
61
+ /**
62
+ * 整个文档的总字符数 (所有 Page 的 charCount 之和)。
63
+ * 需要在所有 Page 加载和计算后得出。
64
+ */
65
+ totalCharCount: number;
66
+
67
+ /**
68
+ * 整个文档的总行数 (所有 Page 的 lineCount 之和)。
69
+ * 需要在所有 Page 加载和计算后得出。
70
+ */
71
+ totalLineCount: number;
72
+
73
+ /**
74
+ * 文件最后修改时间戳。
75
+ */
76
+ updatedAt: Date;
77
+ }
78
+
79
+ /**
80
+ * 代表文件中的一个逻辑单元/页面/块。
81
+ */
82
+ export interface LobeDocumentPage {
83
+ /**
84
+ * 此页/块内容的字符数。
85
+ */
86
+ charCount: number;
87
+
88
+ /**
89
+ * 此页/块内容的行数。
90
+ */
91
+ lineCount: number;
92
+
93
+ /**
94
+ * 与此页/块相关的元数据。
95
+ */
96
+ metadata: {
97
+ /**
98
+ * 允许添加其他特定于页/块的元数据。
99
+ */
100
+ [key: string]: any;
101
+
102
+ /**
103
+ * 如果原始文件单元被进一步分割成块,这是当前块的索引。
104
+ */
105
+ chunkIndex?: number;
106
+
107
+ /**
108
+ * 处理此页/块时发生的错误。
109
+ */
110
+ error?: string;
111
+
112
+ /**
113
+ * 此页/块在原始文件中的结束行号。
114
+ */
115
+ lineNumberEnd?: number;
116
+
117
+ /**
118
+ * 此页/块在原始文件中的起始行号。
119
+ */
120
+ lineNumberStart?: number;
121
+
122
+ /**
123
+ * 页码 (适用于 PDF, DOCX)。
124
+ */
125
+ pageNumber?: number;
126
+
127
+ /**
128
+ * 与此页/块相关的章节标题。
129
+ */
130
+ sectionTitle?: string;
131
+
132
+ /**
133
+ * 工作表名称 (适用于 XLSX)。
134
+ */
135
+ sheetName?: string;
136
+
137
+ /**
138
+ * 幻灯片编号 (适用于 PPTX)。
139
+ */
140
+ slideNumber?: number;
141
+
142
+ /**
143
+ * 如果原始文件单元被进一步分割成块,这是该单元的总块数。
144
+ */
145
+ totalChunks?: number;
146
+ };
147
+
148
+ /**
149
+ * 此页/块的核心文本内容。
150
+ */
151
+ pageContent: string;
152
+ }
153
+
154
+ /**
155
+ * 文档来源类型
156
+ */
157
+ export enum DocumentSourceType {
158
+ /**
159
+ * 来自 API 的内容
160
+ */
161
+ API = 'api',
162
+
163
+ /**
164
+ * 本地或上传的文件
165
+ */
166
+ FILE = 'file',
167
+
168
+ /**
169
+ * 网页内容
170
+ */
171
+ WEB = 'web',
172
+ }
@@ -31,6 +31,7 @@ export interface ChatTTS {
31
31
  }
32
32
 
33
33
  export interface ChatFileItem {
34
+ content?: string;
34
35
  fileType: string;
35
36
  id: string;
36
37
  name: string;
@@ -1,4 +0,0 @@
1
- export const FILE_ITEM_SIZE = 200;
2
-
3
- // 8px on each side
4
- export const IMAGE_FILE_SIZE = 200 - 2 * 8;