@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.
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/common.json +13 -2
- package/locales/ar/error.json +10 -0
- package/locales/ar/models.json +9 -6
- package/locales/ar/setting.json +28 -0
- package/locales/bg-BG/common.json +13 -2
- package/locales/bg-BG/error.json +10 -0
- package/locales/bg-BG/models.json +9 -6
- package/locales/bg-BG/setting.json +28 -0
- package/locales/de-DE/common.json +13 -2
- package/locales/de-DE/error.json +10 -0
- package/locales/de-DE/models.json +9 -6
- package/locales/de-DE/setting.json +28 -0
- package/locales/en-US/common.json +13 -2
- package/locales/en-US/error.json +10 -0
- package/locales/en-US/models.json +9 -6
- package/locales/en-US/setting.json +28 -0
- package/locales/es-ES/common.json +13 -2
- package/locales/es-ES/error.json +10 -0
- package/locales/es-ES/models.json +9 -6
- package/locales/es-ES/setting.json +28 -0
- package/locales/fa-IR/common.json +13 -2
- package/locales/fa-IR/error.json +10 -0
- package/locales/fa-IR/models.json +9 -6
- package/locales/fa-IR/setting.json +28 -0
- package/locales/fr-FR/common.json +13 -2
- package/locales/fr-FR/error.json +10 -0
- package/locales/fr-FR/models.json +9 -6
- package/locales/fr-FR/setting.json +28 -0
- package/locales/it-IT/common.json +13 -2
- package/locales/it-IT/error.json +10 -0
- package/locales/it-IT/models.json +9 -6
- package/locales/it-IT/setting.json +28 -0
- package/locales/ja-JP/common.json +13 -2
- package/locales/ja-JP/error.json +10 -0
- package/locales/ja-JP/models.json +9 -6
- package/locales/ja-JP/setting.json +28 -0
- package/locales/ko-KR/common.json +13 -2
- package/locales/ko-KR/error.json +10 -0
- package/locales/ko-KR/models.json +9 -6
- package/locales/ko-KR/setting.json +28 -0
- package/locales/nl-NL/common.json +13 -2
- package/locales/nl-NL/error.json +10 -0
- package/locales/nl-NL/models.json +9 -6
- package/locales/nl-NL/setting.json +28 -0
- package/locales/pl-PL/common.json +13 -2
- package/locales/pl-PL/error.json +10 -0
- package/locales/pl-PL/models.json +9 -6
- package/locales/pl-PL/setting.json +28 -0
- package/locales/pt-BR/common.json +13 -2
- package/locales/pt-BR/error.json +10 -0
- package/locales/pt-BR/models.json +9 -6
- package/locales/pt-BR/setting.json +28 -0
- package/locales/ru-RU/common.json +13 -2
- package/locales/ru-RU/error.json +10 -0
- package/locales/ru-RU/models.json +9 -6
- package/locales/ru-RU/setting.json +28 -0
- package/locales/tr-TR/common.json +13 -2
- package/locales/tr-TR/error.json +10 -0
- package/locales/tr-TR/models.json +9 -6
- package/locales/tr-TR/setting.json +28 -0
- package/locales/vi-VN/common.json +13 -2
- package/locales/vi-VN/error.json +10 -0
- package/locales/vi-VN/models.json +9 -6
- package/locales/vi-VN/setting.json +28 -0
- package/locales/zh-CN/common.json +13 -2
- package/locales/zh-CN/error.json +10 -0
- package/locales/zh-CN/models.json +10 -7
- package/locales/zh-CN/setting.json +28 -0
- package/locales/zh-TW/common.json +13 -2
- package/locales/zh-TW/error.json +10 -0
- package/locales/zh-TW/models.json +9 -6
- package/locales/zh-TW/setting.json +28 -0
- package/package.json +1 -1
- package/src/app/[variants]/(main)/(mobile)/me/data/features/Category.tsx +2 -2
- package/src/app/[variants]/(main)/chat/features/Migration/UpgradeButton.tsx +2 -1
- package/src/app/[variants]/(main)/settings/common/features/Common.tsx +0 -44
- package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +40 -14
- package/src/app/[variants]/(main)/settings/storage/Advanced.tsx +108 -0
- package/src/app/[variants]/(main)/settings/storage/IndexedDBStorage.tsx +55 -0
- package/src/app/[variants]/(main)/settings/storage/page.tsx +17 -0
- package/src/components/GroupIcon/index.tsx +25 -0
- package/src/components/IndexCard/index.tsx +143 -0
- package/src/components/ProgressItem/index.tsx +75 -0
- package/src/database/models/__tests__/session.test.ts +21 -0
- package/src/database/repositories/dataExporter/index.test.ts +330 -0
- package/src/database/repositories/dataExporter/index.ts +216 -0
- package/src/database/repositories/dataImporter/__tests__/fixtures/agents.json +65 -0
- package/src/database/repositories/dataImporter/__tests__/fixtures/agentsToSessions.json +541 -0
- package/src/database/repositories/dataImporter/__tests__/fixtures/topic.json +269 -0
- package/src/database/repositories/dataImporter/__tests__/fixtures/userSettings.json +18 -0
- package/src/database/repositories/dataImporter/__tests__/fixtures/with-client-id.json +778 -0
- package/src/database/repositories/dataImporter/__tests__/index.test.ts +120 -880
- package/src/database/repositories/dataImporter/deprecated/__tests__/index.test.ts +940 -0
- package/src/database/repositories/dataImporter/deprecated/index.ts +326 -0
- package/src/database/repositories/dataImporter/index.ts +684 -289
- package/src/database/server/models/session.ts +85 -9
- package/src/features/DataImporter/ImportDetail.tsx +203 -0
- package/src/features/DataImporter/SuccessResult.tsx +22 -6
- package/src/features/DataImporter/_deprecated.ts +43 -0
- package/src/features/DataImporter/config.ts +21 -0
- package/src/features/DataImporter/index.tsx +112 -31
- package/src/features/DevPanel/PostgresViewer/DataTable/index.tsx +6 -0
- package/src/features/User/UserPanel/useMenu.tsx +1 -36
- package/src/features/User/__tests__/useMenu.test.tsx +0 -2
- package/src/locales/default/common.ts +12 -1
- package/src/locales/default/error.ts +10 -0
- package/src/locales/default/setting.ts +28 -0
- package/src/server/routers/lambda/exporter.ts +25 -0
- package/src/server/routers/lambda/importer.ts +19 -3
- package/src/server/routers/lambda/index.ts +2 -0
- package/src/services/config.ts +80 -135
- package/src/services/export/_deprecated.ts +155 -0
- package/src/services/export/client.ts +15 -0
- package/src/services/export/index.ts +6 -0
- package/src/services/export/server.ts +9 -0
- package/src/services/export/type.ts +5 -0
- package/src/services/import/_deprecated.ts +42 -1
- package/src/services/import/client.test.ts +1 -1
- package/src/services/import/client.ts +30 -1
- package/src/services/import/server.ts +70 -2
- package/src/services/import/type.ts +10 -0
- package/src/store/global/initialState.ts +1 -0
- package/src/types/export.ts +11 -0
- package/src/types/exportConfig.ts +2 -0
- package/src/types/importer.ts +15 -0
- package/src/utils/client/exportFile.ts +21 -0
- package/vitest.config.ts +1 -1
- package/src/utils/config.ts +0 -109
- /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
|
+
}
|