@lobehub/chat 1.76.1 → 1.77.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 (131) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/ar/common.json +13 -2
  4. package/locales/ar/error.json +10 -0
  5. package/locales/ar/models.json +9 -6
  6. package/locales/ar/setting.json +28 -0
  7. package/locales/bg-BG/common.json +13 -2
  8. package/locales/bg-BG/error.json +10 -0
  9. package/locales/bg-BG/models.json +9 -6
  10. package/locales/bg-BG/setting.json +28 -0
  11. package/locales/de-DE/common.json +13 -2
  12. package/locales/de-DE/error.json +10 -0
  13. package/locales/de-DE/models.json +9 -6
  14. package/locales/de-DE/setting.json +28 -0
  15. package/locales/en-US/common.json +13 -2
  16. package/locales/en-US/error.json +10 -0
  17. package/locales/en-US/models.json +9 -6
  18. package/locales/en-US/setting.json +28 -0
  19. package/locales/es-ES/common.json +13 -2
  20. package/locales/es-ES/error.json +10 -0
  21. package/locales/es-ES/models.json +9 -6
  22. package/locales/es-ES/setting.json +28 -0
  23. package/locales/fa-IR/common.json +13 -2
  24. package/locales/fa-IR/error.json +10 -0
  25. package/locales/fa-IR/models.json +9 -6
  26. package/locales/fa-IR/setting.json +28 -0
  27. package/locales/fr-FR/common.json +13 -2
  28. package/locales/fr-FR/error.json +10 -0
  29. package/locales/fr-FR/models.json +9 -6
  30. package/locales/fr-FR/setting.json +28 -0
  31. package/locales/it-IT/common.json +13 -2
  32. package/locales/it-IT/error.json +10 -0
  33. package/locales/it-IT/models.json +9 -6
  34. package/locales/it-IT/setting.json +28 -0
  35. package/locales/ja-JP/common.json +13 -2
  36. package/locales/ja-JP/error.json +10 -0
  37. package/locales/ja-JP/models.json +9 -6
  38. package/locales/ja-JP/setting.json +28 -0
  39. package/locales/ko-KR/common.json +13 -2
  40. package/locales/ko-KR/error.json +10 -0
  41. package/locales/ko-KR/models.json +9 -6
  42. package/locales/ko-KR/setting.json +28 -0
  43. package/locales/nl-NL/common.json +13 -2
  44. package/locales/nl-NL/error.json +10 -0
  45. package/locales/nl-NL/models.json +9 -6
  46. package/locales/nl-NL/setting.json +28 -0
  47. package/locales/pl-PL/common.json +13 -2
  48. package/locales/pl-PL/error.json +10 -0
  49. package/locales/pl-PL/models.json +9 -6
  50. package/locales/pl-PL/setting.json +28 -0
  51. package/locales/pt-BR/common.json +13 -2
  52. package/locales/pt-BR/error.json +10 -0
  53. package/locales/pt-BR/models.json +9 -6
  54. package/locales/pt-BR/setting.json +28 -0
  55. package/locales/ru-RU/common.json +13 -2
  56. package/locales/ru-RU/error.json +10 -0
  57. package/locales/ru-RU/models.json +9 -6
  58. package/locales/ru-RU/setting.json +28 -0
  59. package/locales/tr-TR/common.json +13 -2
  60. package/locales/tr-TR/error.json +10 -0
  61. package/locales/tr-TR/models.json +9 -6
  62. package/locales/tr-TR/setting.json +28 -0
  63. package/locales/vi-VN/common.json +13 -2
  64. package/locales/vi-VN/error.json +10 -0
  65. package/locales/vi-VN/models.json +9 -6
  66. package/locales/vi-VN/setting.json +28 -0
  67. package/locales/zh-CN/common.json +13 -2
  68. package/locales/zh-CN/error.json +10 -0
  69. package/locales/zh-CN/models.json +10 -7
  70. package/locales/zh-CN/setting.json +28 -0
  71. package/locales/zh-TW/common.json +13 -2
  72. package/locales/zh-TW/error.json +10 -0
  73. package/locales/zh-TW/models.json +9 -6
  74. package/locales/zh-TW/setting.json +28 -0
  75. package/package.json +1 -1
  76. package/src/app/[variants]/(main)/(mobile)/me/data/features/Category.tsx +2 -2
  77. package/src/app/[variants]/(main)/chat/features/Migration/UpgradeButton.tsx +2 -1
  78. package/src/app/[variants]/(main)/settings/common/features/Common.tsx +0 -44
  79. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +40 -14
  80. package/src/app/[variants]/(main)/settings/storage/Advanced.tsx +108 -0
  81. package/src/app/[variants]/(main)/settings/storage/IndexedDBStorage.tsx +55 -0
  82. package/src/app/[variants]/(main)/settings/storage/page.tsx +17 -0
  83. package/src/components/GroupIcon/index.tsx +25 -0
  84. package/src/components/IndexCard/index.tsx +143 -0
  85. package/src/components/ProgressItem/index.tsx +75 -0
  86. package/src/database/models/__tests__/session.test.ts +21 -0
  87. package/src/database/repositories/dataExporter/index.test.ts +330 -0
  88. package/src/database/repositories/dataExporter/index.ts +216 -0
  89. package/src/database/repositories/dataImporter/__tests__/fixtures/agents.json +65 -0
  90. package/src/database/repositories/dataImporter/__tests__/fixtures/agentsToSessions.json +541 -0
  91. package/src/database/repositories/dataImporter/__tests__/fixtures/topic.json +269 -0
  92. package/src/database/repositories/dataImporter/__tests__/fixtures/userSettings.json +18 -0
  93. package/src/database/repositories/dataImporter/__tests__/fixtures/with-client-id.json +778 -0
  94. package/src/database/repositories/dataImporter/__tests__/index.test.ts +120 -880
  95. package/src/database/repositories/dataImporter/deprecated/__tests__/index.test.ts +940 -0
  96. package/src/database/repositories/dataImporter/deprecated/index.ts +326 -0
  97. package/src/database/repositories/dataImporter/index.ts +684 -289
  98. package/src/database/server/models/session.ts +85 -9
  99. package/src/features/DataImporter/ImportDetail.tsx +203 -0
  100. package/src/features/DataImporter/SuccessResult.tsx +22 -6
  101. package/src/features/DataImporter/_deprecated.ts +43 -0
  102. package/src/features/DataImporter/config.ts +21 -0
  103. package/src/features/DataImporter/index.tsx +112 -31
  104. package/src/features/DevPanel/PostgresViewer/DataTable/index.tsx +6 -0
  105. package/src/features/User/UserPanel/useMenu.tsx +1 -36
  106. package/src/features/User/__tests__/useMenu.test.tsx +0 -2
  107. package/src/locales/default/common.ts +12 -1
  108. package/src/locales/default/error.ts +10 -0
  109. package/src/locales/default/setting.ts +28 -0
  110. package/src/server/routers/lambda/exporter.ts +25 -0
  111. package/src/server/routers/lambda/importer.ts +19 -3
  112. package/src/server/routers/lambda/index.ts +2 -0
  113. package/src/services/config.ts +80 -135
  114. package/src/services/export/_deprecated.ts +155 -0
  115. package/src/services/export/client.ts +15 -0
  116. package/src/services/export/index.ts +6 -0
  117. package/src/services/export/server.ts +9 -0
  118. package/src/services/export/type.ts +5 -0
  119. package/src/services/import/_deprecated.ts +42 -1
  120. package/src/services/import/client.test.ts +1 -1
  121. package/src/services/import/client.ts +30 -1
  122. package/src/services/import/server.ts +70 -2
  123. package/src/services/import/type.ts +10 -0
  124. package/src/store/global/initialState.ts +1 -0
  125. package/src/types/export.ts +11 -0
  126. package/src/types/exportConfig.ts +2 -0
  127. package/src/types/importer.ts +15 -0
  128. package/src/utils/client/exportFile.ts +21 -0
  129. package/vitest.config.ts +1 -1
  130. package/src/utils/config.ts +0 -109
  131. /package/src/database/repositories/dataImporter/{__tests__ → deprecated/__tests__}/fixtures/messages.json +0 -0
@@ -0,0 +1,216 @@
1
+ import { and, eq, inArray } from 'drizzle-orm/expressions';
2
+ import pMap from 'p-map';
3
+
4
+ import * as EXPORT_TABLES from '@/database/schemas';
5
+ import { LobeChatDatabase } from '@/database/type';
6
+
7
+ interface BaseTableConfig {
8
+ table: keyof typeof EXPORT_TABLES;
9
+ type: 'base';
10
+ userField?: string;
11
+ }
12
+
13
+ export interface RelationTableConfig {
14
+ relations: {
15
+ field: string;
16
+ sourceField?: string;
17
+ sourceTable: keyof typeof EXPORT_TABLES;
18
+ }[];
19
+ table: keyof typeof EXPORT_TABLES;
20
+ type: 'relation';
21
+ }
22
+
23
+ export const DATA_EXPORT_CONFIG = {
24
+ baseTables: [
25
+ // { table: 'users', userField: 'id' },
26
+ { table: 'userSettings', userField: 'id' },
27
+ { table: 'userInstalledPlugins' },
28
+ { table: 'agents' },
29
+ // { table: 'agentsFiles' },
30
+ // { table: 'agentsKnowledgeBases' },
31
+ // { table: 'agentsToSessions' },
32
+ { table: 'aiModels' },
33
+ { table: 'aiProviders' },
34
+ // async tasks should not be included
35
+ // { table: 'asyncTasks' },
36
+ // { table: 'chunks' },
37
+ // { table: 'unstructuredChunks' },
38
+ // { table: 'embeddings' },
39
+ // { table: 'files' },
40
+ // { table: 'fileChunks' },
41
+ // { table: 'filesToSessions' },
42
+ // { table: 'knowledgeBases' },
43
+ // { table: 'knowledgeBaseFiles' },
44
+ { table: 'messageChunks' },
45
+ { table: 'messagePlugins' },
46
+ // { table: 'messageQueryChunks' },
47
+ // { table: 'messageQueries' },
48
+ { table: 'messageTranslates' },
49
+ // { table: 'messageTTS' },
50
+ { table: 'messages' },
51
+ // { table: 'messagesFiles' },
52
+
53
+ // next auth tables won't be included
54
+ // { table: 'nextauthAccounts' },
55
+ // { table: 'nextauthSessions' },
56
+ // { table: 'nextauthAuthenticators' },
57
+ // { table: 'nextauthVerificationTokens' },
58
+ { table: 'sessionGroups' },
59
+ { table: 'sessions' },
60
+ { table: 'threads' },
61
+ { table: 'topics' },
62
+ ] as BaseTableConfig[],
63
+ relationTables: [
64
+ // {
65
+ // relations: [{ field: 'hashId', sourceField: 'fileHash', sourceTable: 'files' }],
66
+ // table: 'globalFiles',
67
+ // },
68
+ {
69
+ relations: [
70
+ { field: 'agentId', sourceField: 'id', sourceTable: 'agents' },
71
+ { field: 'sessionId', sourceField: 'id', sourceTable: 'sessions' },
72
+ ],
73
+ table: 'agentsToSessions',
74
+ },
75
+
76
+ // {
77
+ // relations: [{ field: 'id', sourceField: 'id', sourceTable: 'messages' }],
78
+ // table: 'messagePlugins',
79
+ // },
80
+ ] as RelationTableConfig[],
81
+ };
82
+
83
+ export class DataExporterRepos {
84
+ private userId: string;
85
+ private db: LobeChatDatabase;
86
+
87
+ constructor(db: LobeChatDatabase, userId: string) {
88
+ this.db = db;
89
+ this.userId = userId;
90
+ }
91
+
92
+ private removeUserId(data: any[]) {
93
+ return data.map((item) => {
94
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
95
+ const { userId: _, ...rest } = item;
96
+ return rest;
97
+ });
98
+ }
99
+
100
+ private async queryTable(config: RelationTableConfig, existingData: Record<string, any[]>) {
101
+ const { table } = config;
102
+ const tableObj = EXPORT_TABLES[table];
103
+ if (!tableObj) throw new Error(`Table ${table} not found`);
104
+
105
+ try {
106
+ const conditions = [];
107
+
108
+ // 处理每个关联条件
109
+ for (const relation of config.relations) {
110
+ const sourceData = existingData[relation.sourceTable] || [];
111
+
112
+ // 如果源数据为空,这个表可能无法查询到任何数据
113
+ if (sourceData.length === 0) {
114
+ console.log(
115
+ `Source table ${relation.sourceTable} has no data, skipping query for ${table}`,
116
+ );
117
+ return [];
118
+ }
119
+
120
+ const sourceIds = sourceData.map((item) => item[relation.sourceField || 'id']);
121
+ conditions.push(inArray(tableObj[relation.field], sourceIds));
122
+ }
123
+
124
+ // 如果表有userId字段并且不是users表,添加用户过滤
125
+ if ('userId' in tableObj && table !== 'users' && !config.relations) {
126
+ conditions.push(eq(tableObj.userId, this.userId));
127
+ }
128
+
129
+ // 组合所有条件
130
+ const where = conditions.length === 1 ? conditions[0] : and(...conditions);
131
+
132
+ // @ts-expect-error query
133
+ const result = await this.db.query[table].findMany({ where });
134
+
135
+ // 只对使用 userId 查询的表移除 userId 字段
136
+ console.log(`Successfully exported table: ${table}, count: ${result.length}`);
137
+ return config.relations ? result : this.removeUserId(result);
138
+ } catch (error) {
139
+ console.error(`Error querying table ${table}:`, error);
140
+ return [];
141
+ }
142
+ }
143
+
144
+ private async queryBaseTables(config: BaseTableConfig) {
145
+ const { table } = config;
146
+ const tableObj = EXPORT_TABLES[table];
147
+ if (!tableObj) throw new Error(`Table ${table} not found`);
148
+
149
+ try {
150
+ // 如果有关联配置,使用关联查询
151
+
152
+ // 默认使用 userId 查询,特殊情况使用 userField
153
+ const userField = config.userField || 'userId';
154
+ const where = eq(tableObj[userField], this.userId);
155
+
156
+ // @ts-expect-error query
157
+ const result = await this.db.query[table].findMany({ where });
158
+
159
+ // 只对使用 userId 查询的表移除 userId 字段
160
+ console.log(`Successfully exported table: ${table}, count: ${result.length}`);
161
+ return this.removeUserId(result);
162
+ } catch (error) {
163
+ console.error(`Error querying table ${table}:`, error);
164
+ return [];
165
+ }
166
+ }
167
+
168
+ async export(concurrency = 10) {
169
+ const result: Record<string, any[]> = {};
170
+
171
+ // 1. 首先并发查询所有基础表
172
+ console.log('Querying base tables...');
173
+ const baseResults = await pMap(
174
+ DATA_EXPORT_CONFIG.baseTables,
175
+ async (config) => ({ data: await this.queryBaseTables(config), table: config.table }),
176
+ { concurrency },
177
+ );
178
+
179
+ // 更新结果集
180
+ baseResults.forEach(({ table, data }) => {
181
+ result[table] = data;
182
+ });
183
+
184
+ // 2. 然后并发查询所有关联表
185
+
186
+ const relationResults = await pMap(
187
+ DATA_EXPORT_CONFIG.relationTables,
188
+ async (config) => {
189
+ // 检查所有依赖的源表是否有数据
190
+ const allSourcesHaveData = config.relations.every(
191
+ (relation) => (result[relation.sourceTable] || []).length > 0,
192
+ );
193
+
194
+ if (!allSourcesHaveData) {
195
+ console.log(`Skipping table ${config.table} as some source tables have no data`);
196
+ return { data: [], table: config.table };
197
+ }
198
+
199
+ return {
200
+ data: await this.queryTable(config, result),
201
+ table: config.table,
202
+ };
203
+ },
204
+ { concurrency },
205
+ );
206
+
207
+ // 更新结果集
208
+ relationResults.forEach(({ table, data }) => {
209
+ result[table] = data;
210
+ });
211
+
212
+ console.log('finalResults:', result);
213
+
214
+ return result;
215
+ }
216
+ }
@@ -0,0 +1,65 @@
1
+ {
2
+ "data": {
3
+ "agents": [
4
+ {
5
+ "id": "agt_CSLkGPIXIQms",
6
+ "slug": "room-possible-somewhere-numeral",
7
+ "title": null,
8
+ "description": null,
9
+ "tags": [],
10
+ "avatar": null,
11
+ "backgroundColor": null,
12
+ "plugins": [],
13
+ "chatConfig": {
14
+ "searchMode": "off"
15
+ },
16
+ "fewShots": null,
17
+ "model": "gemini-2.0-flash-exp",
18
+ "params": {
19
+ "top_p": 1,
20
+ "temperature": 1,
21
+ "presence_penalty": 0,
22
+ "frequency_penalty": 0
23
+ },
24
+ "provider": "google",
25
+ "systemRole": "",
26
+ "tts": {
27
+ "voice": {
28
+ "openai": "alloy"
29
+ },
30
+ "sttLocale": "auto",
31
+ "ttsService": "openai",
32
+ "showAllLocaleVoice": false
33
+ },
34
+ "accessedAt": "2025-03-05T05:25:44.521Z",
35
+ "createdAt": "2025-03-05T05:25:44.522Z",
36
+ "updatedAt": "2025-03-05T05:25:44.522Z"
37
+ }
38
+ ],
39
+ "agentsToSessions": [
40
+ {
41
+ "agentId": "agt_CSLkGPIXIQms",
42
+ "sessionId": "ssn_WdL6m1mReqyb"
43
+ }
44
+ ],
45
+ "sessions": [
46
+ {
47
+ "id": "ssn_WdL6m1mReqyb",
48
+ "slug": "inbox-t",
49
+ "title": null,
50
+ "description": null,
51
+ "avatar": null,
52
+ "backgroundColor": null,
53
+ "type": "agent",
54
+ "groupId": null,
55
+ "clientId": null,
56
+ "pinned": false,
57
+ "accessedAt": "2025-03-05T05:25:44.521Z",
58
+ "createdAt": "2025-03-05T05:25:44.528Z",
59
+ "updatedAt": "2025-03-05T05:25:44.528Z"
60
+ }
61
+ ]
62
+ },
63
+ "mode": "pglite",
64
+ "schemaHash": "89e91285be422d5f44511c7405f57b57f8dfda4f0304126ae9b0f266e5fd60f1"
65
+ }