@lobehub/chat 1.76.1 → 1.77.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.
- package/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/locales/ar/common.json +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- 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 +12 -1
- package/locales/zh-CN/error.json +10 -0
- package/locales/zh-CN/models.json +9 -6
- package/locales/zh-CN/setting.json +28 -0
- package/locales/zh-TW/common.json +12 -1
- 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 +1 -1
- 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 +133 -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/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/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 +0 -35
- package/src/features/User/__tests__/useMenu.test.tsx +0 -2
- package/src/locales/default/common.ts +11 -0
- 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
@@ -348,6 +348,33 @@ export default {
|
|
348
348
|
},
|
349
349
|
title: '主题设置',
|
350
350
|
},
|
351
|
+
storage: {
|
352
|
+
actions: {
|
353
|
+
export: {
|
354
|
+
button: '导出',
|
355
|
+
exportType: {
|
356
|
+
agent: '导出助手设定',
|
357
|
+
agentWithMessage: '导出助手和消息',
|
358
|
+
all: '导出全局设置和所有助手数据',
|
359
|
+
allAgent: '导出所有助手设定',
|
360
|
+
allAgentWithMessage: '导出所有助手和消息',
|
361
|
+
globalSetting: '导出全局设置',
|
362
|
+
},
|
363
|
+
title: '导出数据',
|
364
|
+
},
|
365
|
+
import: {
|
366
|
+
button: '导入',
|
367
|
+
title: '导入数据',
|
368
|
+
},
|
369
|
+
title: '高级操作',
|
370
|
+
},
|
371
|
+
desc: '当前浏览器中的存储用量',
|
372
|
+
embeddings: {
|
373
|
+
used: '向量存储',
|
374
|
+
},
|
375
|
+
title: '数据存储',
|
376
|
+
used: '存储用量',
|
377
|
+
},
|
351
378
|
submitAgentModal: {
|
352
379
|
button: '提交助手',
|
353
380
|
identifier: 'identifier 助手标识符',
|
@@ -441,6 +468,7 @@ export default {
|
|
441
468
|
'hotkey': '快捷键',
|
442
469
|
'llm': '语言模型',
|
443
470
|
'provider': 'AI 服务商',
|
471
|
+
'storage': '数据存储',
|
444
472
|
'sync': '云端同步',
|
445
473
|
'system-agent': '系统助手',
|
446
474
|
'tts': '语音服务',
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { DrizzleMigrationModel } from '@/database/models/drizzleMigration';
|
2
|
+
import { DataExporterRepos } from '@/database/repositories/dataExporter';
|
3
|
+
import { serverDB } from '@/database/server';
|
4
|
+
import { authedProcedure, router } from '@/libs/trpc';
|
5
|
+
import { ExportDatabaseData } from '@/types/export';
|
6
|
+
|
7
|
+
const exportProcedure = authedProcedure.use(async (opts) => {
|
8
|
+
const { ctx } = opts;
|
9
|
+
const dataExporterRepos = new DataExporterRepos(serverDB, ctx.userId);
|
10
|
+
const drizzleMigration = new DrizzleMigrationModel(serverDB);
|
11
|
+
|
12
|
+
return opts.next({
|
13
|
+
ctx: { dataExporterRepos, drizzleMigration },
|
14
|
+
});
|
15
|
+
});
|
16
|
+
|
17
|
+
export const exporterRouter = router({
|
18
|
+
exportData: exportProcedure.mutation(async ({ ctx }): Promise<ExportDatabaseData> => {
|
19
|
+
const data = await ctx.dataExporterRepos.export(5);
|
20
|
+
|
21
|
+
const schemaHash = await ctx.drizzleMigration.getLatestMigrationHash();
|
22
|
+
|
23
|
+
return { data, schemaHash };
|
24
|
+
}),
|
25
|
+
});
|
@@ -5,7 +5,8 @@ import { DataImporterRepos } from '@/database/repositories/dataImporter';
|
|
5
5
|
import { serverDB } from '@/database/server';
|
6
6
|
import { authedProcedure, router } from '@/libs/trpc';
|
7
7
|
import { S3 } from '@/server/modules/S3';
|
8
|
-
import {
|
8
|
+
import { ImportPgDataStructure } from '@/types/export';
|
9
|
+
import { ImportResultData, ImporterEntryData } from '@/types/importer';
|
9
10
|
|
10
11
|
const importProcedure = authedProcedure.use(async (opts) => {
|
11
12
|
const { ctx } = opts;
|
@@ -19,7 +20,7 @@ const importProcedure = authedProcedure.use(async (opts) => {
|
|
19
20
|
export const importerRouter = router({
|
20
21
|
importByFile: importProcedure
|
21
22
|
.input(z.object({ pathname: z.string() }))
|
22
|
-
.mutation(async ({ input, ctx }): Promise<
|
23
|
+
.mutation(async ({ input, ctx }): Promise<ImportResultData> => {
|
23
24
|
let data: ImporterEntryData | undefined;
|
24
25
|
|
25
26
|
try {
|
@@ -37,6 +38,10 @@ export const importerRouter = router({
|
|
37
38
|
});
|
38
39
|
}
|
39
40
|
|
41
|
+
if ('schemaHash' in data) {
|
42
|
+
return ctx.dataImporterService.importPgData(data as unknown as ImportPgDataStructure);
|
43
|
+
}
|
44
|
+
|
40
45
|
return ctx.dataImporterService.importData(data);
|
41
46
|
}),
|
42
47
|
|
@@ -52,7 +57,18 @@ export const importerRouter = router({
|
|
52
57
|
}),
|
53
58
|
}),
|
54
59
|
)
|
55
|
-
.mutation(async ({ input, ctx }): Promise<
|
60
|
+
.mutation(async ({ input, ctx }): Promise<ImportResultData> => {
|
56
61
|
return ctx.dataImporterService.importData(input.data);
|
57
62
|
}),
|
63
|
+
importPgByPost: importProcedure
|
64
|
+
.input(
|
65
|
+
z.object({
|
66
|
+
data: z.record(z.string(), z.array(z.any())),
|
67
|
+
mode: z.enum(['pglite', 'postgres']),
|
68
|
+
schemaHash: z.string(),
|
69
|
+
}),
|
70
|
+
)
|
71
|
+
.mutation(async ({ input, ctx }): Promise<ImportResultData> => {
|
72
|
+
return ctx.dataImporterService.importPgData(input);
|
73
|
+
}),
|
58
74
|
});
|
@@ -7,6 +7,7 @@ import { agentRouter } from './agent';
|
|
7
7
|
import { aiModelRouter } from './aiModel';
|
8
8
|
import { aiProviderRouter } from './aiProvider';
|
9
9
|
import { chunkRouter } from './chunk';
|
10
|
+
import { exporterRouter } from './exporter';
|
10
11
|
import { fileRouter } from './file';
|
11
12
|
import { importerRouter } from './importer';
|
12
13
|
import { knowledgeBaseRouter } from './knowledgeBase';
|
@@ -24,6 +25,7 @@ export const lambdaRouter = router({
|
|
24
25
|
aiModel: aiModelRouter,
|
25
26
|
aiProvider: aiProviderRouter,
|
26
27
|
chunk: chunkRouter,
|
28
|
+
exporter: exporterRouter,
|
27
29
|
file: fileRouter,
|
28
30
|
healthcheck: publicProcedure.query(() => "i'm live!"),
|
29
31
|
importer: importerRouter,
|
package/src/services/config.ts
CHANGED
@@ -1,162 +1,107 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
import {
|
4
|
-
import {
|
5
|
-
import {
|
6
|
-
import {
|
7
|
-
import {
|
8
|
-
import {
|
9
|
-
|
10
|
-
import {
|
11
|
-
import {
|
12
|
-
|
13
|
-
export interface ImportResult {
|
14
|
-
added: number;
|
15
|
-
errors: number;
|
16
|
-
skips: number;
|
17
|
-
}
|
18
|
-
export interface ImportResults {
|
19
|
-
messages?: ImportResult;
|
20
|
-
sessionGroups?: ImportResult;
|
21
|
-
sessions?: ImportResult;
|
22
|
-
topics?: ImportResult;
|
23
|
-
type?: string;
|
24
|
-
}
|
1
|
+
import dayjs from 'dayjs';
|
2
|
+
|
3
|
+
import { BRANDING_NAME } from '@/const/branding';
|
4
|
+
import { isDeprecatedEdition, isServerMode } from '@/const/version';
|
5
|
+
import { CURRENT_CONFIG_VERSION } from '@/migrations';
|
6
|
+
import { ImportPgDataStructure } from '@/types/export';
|
7
|
+
import { downloadFile } from '@/utils/client/downloadFile';
|
8
|
+
import { exportJSONFile } from '@/utils/client/exportFile';
|
9
|
+
|
10
|
+
import { exportService } from './export';
|
11
|
+
import { configService as deprecatedExportService } from './export/_deprecated';
|
25
12
|
|
26
|
-
/**
|
27
|
-
* @deprecated
|
28
|
-
*/
|
29
13
|
class ConfigService {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
14
|
+
exportAll = async () => {
|
15
|
+
// TODO: remove this in V2
|
16
|
+
if (isDeprecatedEdition) {
|
17
|
+
const config = await deprecatedExportService.exportAll();
|
18
|
+
const filename = `${BRANDING_NAME}-config-v${CURRENT_CONFIG_VERSION}.json`;
|
19
|
+
exportJSONFile(config, filename);
|
34
20
|
return;
|
35
21
|
}
|
36
22
|
|
37
|
-
|
38
|
-
|
39
|
-
}
|
40
|
-
|
41
|
-
await importService.importData(
|
42
|
-
{
|
43
|
-
messages: (config.state as any).messages || [],
|
44
|
-
sessionGroups: (config.state as any).sessionGroups || [],
|
45
|
-
sessions: (config.state as any).sessions || [],
|
46
|
-
topics: (config.state as any).topics || [],
|
47
|
-
version: config.version,
|
48
|
-
},
|
49
|
-
callbacks,
|
50
|
-
);
|
51
|
-
};
|
52
|
-
|
53
|
-
// TODO: Separate export feature into a new service like importService
|
54
|
-
|
55
|
-
/**
|
56
|
-
* export all agents
|
57
|
-
*/
|
58
|
-
exportAgents = async () => {
|
59
|
-
const agents = await sessionService.getSessionsByType('agent');
|
60
|
-
const sessionGroups = await sessionService.getSessionGroups();
|
61
|
-
|
62
|
-
const config = createConfigFile('agents', { sessionGroups, sessions: agents });
|
63
|
-
|
64
|
-
exportConfigFile(config, 'agents');
|
65
|
-
};
|
23
|
+
const { data, url } = await exportService.exportData();
|
24
|
+
const filename = `${dayjs().format('YYYY-MM-DD-hh-mm')}_${BRANDING_NAME}-data.json`;
|
66
25
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
const messages = await messageService.getAllMessages();
|
74
|
-
const topics = await topicService.getAllTopics();
|
26
|
+
// if url exists, means export data from server and upload the data to S3
|
27
|
+
// just need to download the file
|
28
|
+
if (url) {
|
29
|
+
await downloadFile(url, filename);
|
30
|
+
return;
|
31
|
+
}
|
75
32
|
|
76
|
-
|
33
|
+
// or export to file with the data
|
34
|
+
const result = await this.createDataStructure(data, isServerMode ? 'postgres' : 'pglite');
|
77
35
|
|
78
|
-
|
36
|
+
exportJSONFile(result, filename);
|
79
37
|
};
|
80
38
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
const topics = await topicService.getTopics({ sessionId: id });
|
90
|
-
|
91
|
-
const config = createConfigFile('singleSession', { messages, sessions: [session], topics });
|
92
|
-
|
93
|
-
exportConfigFile(config, `${session.meta?.title}-session`);
|
39
|
+
exportAgents = async () => {
|
40
|
+
// TODO: remove this in V2
|
41
|
+
if (isDeprecatedEdition) {
|
42
|
+
const config = await deprecatedExportService.exportAgents();
|
43
|
+
const filename = `${BRANDING_NAME}-agents-v${CURRENT_CONFIG_VERSION}.json`;
|
44
|
+
exportJSONFile(config, filename);
|
45
|
+
return;
|
46
|
+
}
|
94
47
|
};
|
95
48
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
if (!session) return;
|
102
|
-
|
103
|
-
const messages = await messageService.getMessages(sessionId, topicId);
|
104
|
-
const topics = await topicService.getTopics({ sessionId });
|
105
|
-
|
106
|
-
const topic = topics.find((item) => item.id === topicId);
|
107
|
-
if (!topic) return;
|
49
|
+
exportSingleAgent = async (agentId: string) => {
|
50
|
+
// TODO: remove this in V2
|
51
|
+
if (isDeprecatedEdition) {
|
52
|
+
const result = await deprecatedExportService.exportSingleAgent(agentId);
|
53
|
+
if (!result) return;
|
108
54
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
});
|
114
|
-
|
115
|
-
exportConfigFile(config, `${topic.title}-topic`);
|
55
|
+
const filename = `${BRANDING_NAME}-${result.title}-v${CURRENT_CONFIG_VERSION}.json`;
|
56
|
+
exportJSONFile(result.config, filename);
|
57
|
+
return;
|
58
|
+
}
|
116
59
|
};
|
117
60
|
|
118
|
-
|
119
|
-
|
120
|
-
if (
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
61
|
+
exportSessions = async () => {
|
62
|
+
// TODO: remove this in V2
|
63
|
+
if (isDeprecatedEdition) {
|
64
|
+
const config = await deprecatedExportService.exportSessions();
|
65
|
+
const filename = `${BRANDING_NAME}-sessions-v${CURRENT_CONFIG_VERSION}.json`;
|
66
|
+
exportJSONFile(config, filename);
|
67
|
+
return;
|
68
|
+
}
|
125
69
|
};
|
126
70
|
|
127
|
-
/**
|
128
|
-
* export settings
|
129
|
-
*/
|
130
71
|
exportSettings = async () => {
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
72
|
+
// TODO: remove this in V2
|
73
|
+
if (isDeprecatedEdition) {
|
74
|
+
const config = await deprecatedExportService.exportSessions();
|
75
|
+
const filename = `${BRANDING_NAME}-settings-v${CURRENT_CONFIG_VERSION}.json`;
|
76
|
+
exportJSONFile(config, filename);
|
77
|
+
return;
|
78
|
+
}
|
136
79
|
};
|
137
80
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
const sessionGroups = await sessionService.getSessionGroups();
|
144
|
-
const messages = await messageService.getAllMessages();
|
145
|
-
const topics = await topicService.getAllTopics();
|
146
|
-
const settings = this.getSettings();
|
147
|
-
|
148
|
-
const config = createConfigFile('all', { messages, sessionGroups, sessions, settings, topics });
|
81
|
+
exportSingleSession = async (sessionId: string) => {
|
82
|
+
// TODO: remove this in V2
|
83
|
+
if (isDeprecatedEdition) {
|
84
|
+
const data = await deprecatedExportService.exportSingleSession(sessionId);
|
85
|
+
if (!data) return;
|
149
86
|
|
150
|
-
|
87
|
+
const filename = `${BRANDING_NAME}-${data.title}-v${CURRENT_CONFIG_VERSION}.json`;
|
88
|
+
exportJSONFile(data.config, filename);
|
89
|
+
return;
|
90
|
+
}
|
151
91
|
};
|
152
92
|
|
153
|
-
private
|
154
|
-
|
155
|
-
|
156
|
-
|
93
|
+
private createDataStructure = async (
|
94
|
+
data: any,
|
95
|
+
mode: 'pglite' | 'postgres',
|
96
|
+
): Promise<ImportPgDataStructure> => {
|
97
|
+
const { default: json } = await import('@/database/client/migrations.json');
|
98
|
+
const latestHash = json.at(-1)?.hash;
|
99
|
+
if (!latestHash) {
|
100
|
+
throw new Error('Not find database sql hash');
|
101
|
+
}
|
157
102
|
|
158
|
-
|
159
|
-
|
103
|
+
return { data, mode, schemaHash: latestHash };
|
104
|
+
};
|
160
105
|
}
|
161
106
|
|
162
107
|
export const configService = new ConfigService();
|
@@ -0,0 +1,155 @@
|
|
1
|
+
import { Migration } from '@/migrations';
|
2
|
+
import { messageService } from '@/services/message';
|
3
|
+
import { sessionService } from '@/services/session';
|
4
|
+
import { topicService } from '@/services/topic';
|
5
|
+
import { useSessionStore } from '@/store/session';
|
6
|
+
import { sessionSelectors } from '@/store/session/selectors';
|
7
|
+
import { useUserStore } from '@/store/user';
|
8
|
+
import { settingsSelectors } from '@/store/user/selectors';
|
9
|
+
import {
|
10
|
+
ConfigFileAgents,
|
11
|
+
ConfigFileAll,
|
12
|
+
ConfigFileSessions,
|
13
|
+
ConfigFileSettings,
|
14
|
+
ConfigFileSingleSession,
|
15
|
+
ConfigModelMap,
|
16
|
+
ExportType,
|
17
|
+
} from '@/types/exportConfig';
|
18
|
+
|
19
|
+
type CreateConfigFileState<T extends ExportType> = ConfigModelMap[T]['state'];
|
20
|
+
|
21
|
+
type CreateConfigFile<T extends ExportType> = ConfigModelMap[T]['file'];
|
22
|
+
|
23
|
+
const createConfigFile = <T extends ExportType>(
|
24
|
+
type: T,
|
25
|
+
state: CreateConfigFileState<T>,
|
26
|
+
): CreateConfigFile<T> => {
|
27
|
+
switch (type) {
|
28
|
+
case 'agents': {
|
29
|
+
return {
|
30
|
+
exportType: 'agents',
|
31
|
+
state,
|
32
|
+
version: Migration.targetVersion,
|
33
|
+
} as ConfigFileAgents;
|
34
|
+
}
|
35
|
+
|
36
|
+
case 'sessions': {
|
37
|
+
return {
|
38
|
+
exportType: 'sessions',
|
39
|
+
state,
|
40
|
+
version: Migration.targetVersion,
|
41
|
+
} as ConfigFileSessions;
|
42
|
+
}
|
43
|
+
|
44
|
+
case 'settings': {
|
45
|
+
return {
|
46
|
+
exportType: 'settings',
|
47
|
+
state,
|
48
|
+
version: Migration.targetVersion,
|
49
|
+
} as ConfigFileSettings;
|
50
|
+
}
|
51
|
+
|
52
|
+
case 'singleSession': {
|
53
|
+
return {
|
54
|
+
exportType: 'sessions',
|
55
|
+
state,
|
56
|
+
version: Migration.targetVersion,
|
57
|
+
} as ConfigFileSingleSession;
|
58
|
+
}
|
59
|
+
|
60
|
+
case 'all': {
|
61
|
+
return {
|
62
|
+
exportType: 'all',
|
63
|
+
state,
|
64
|
+
version: Migration.targetVersion,
|
65
|
+
} as ConfigFileAll;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
throw new Error('缺少正确的导出类型,请检查实现...');
|
70
|
+
};
|
71
|
+
|
72
|
+
/**
|
73
|
+
* @deprecated
|
74
|
+
*/
|
75
|
+
export class ConfigService {
|
76
|
+
/**
|
77
|
+
* export all agents
|
78
|
+
*/
|
79
|
+
exportAgents = async () => {
|
80
|
+
const agents = await sessionService.getSessionsByType('agent');
|
81
|
+
const sessionGroups = await sessionService.getSessionGroups();
|
82
|
+
|
83
|
+
return createConfigFile('agents', { sessionGroups, sessions: agents });
|
84
|
+
};
|
85
|
+
|
86
|
+
/**
|
87
|
+
* export all sessions
|
88
|
+
*/
|
89
|
+
exportSessions = async () => {
|
90
|
+
const sessions = await sessionService.getSessionsByType();
|
91
|
+
const sessionGroups = await sessionService.getSessionGroups();
|
92
|
+
const messages = await messageService.getAllMessages();
|
93
|
+
const topics = await topicService.getAllTopics();
|
94
|
+
|
95
|
+
return createConfigFile('sessions', { messages, sessionGroups, sessions, topics });
|
96
|
+
};
|
97
|
+
|
98
|
+
/**
|
99
|
+
* export a session
|
100
|
+
*/
|
101
|
+
exportSingleSession = async (id: string) => {
|
102
|
+
const session = this.getSession(id);
|
103
|
+
if (!session) return;
|
104
|
+
|
105
|
+
const messages = await messageService.getAllMessagesInSession(id);
|
106
|
+
const topics = await topicService.getTopics({ sessionId: id });
|
107
|
+
|
108
|
+
const config = createConfigFile('singleSession', { messages, sessions: [session], topics });
|
109
|
+
return { config, title: `${session.meta?.title}-session` };
|
110
|
+
};
|
111
|
+
|
112
|
+
exportSingleAgent = async (id: string) => {
|
113
|
+
const agent = this.getAgent(id);
|
114
|
+
if (!agent) return;
|
115
|
+
|
116
|
+
const config = createConfigFile('agents', { sessionGroups: [], sessions: [agent] });
|
117
|
+
|
118
|
+
return { config, title: `${agent.meta?.title}-session` };
|
119
|
+
};
|
120
|
+
|
121
|
+
/**
|
122
|
+
* export settings
|
123
|
+
*/
|
124
|
+
exportSettings = async () => {
|
125
|
+
const settings = this.getSettings();
|
126
|
+
|
127
|
+
return createConfigFile('settings', { settings });
|
128
|
+
};
|
129
|
+
|
130
|
+
/**
|
131
|
+
* export all data
|
132
|
+
*/
|
133
|
+
exportAll = async () => {
|
134
|
+
const sessions = await sessionService.getSessionsByType();
|
135
|
+
const sessionGroups = await sessionService.getSessionGroups();
|
136
|
+
const messages = await messageService.getAllMessages();
|
137
|
+
const topics = await topicService.getAllTopics();
|
138
|
+
const settings = this.getSettings();
|
139
|
+
|
140
|
+
return createConfigFile('all', { messages, sessionGroups, sessions, settings, topics });
|
141
|
+
};
|
142
|
+
|
143
|
+
private getSettings = () => settingsSelectors.exportSettings(useUserStore.getState());
|
144
|
+
|
145
|
+
private getSession = (id: string) =>
|
146
|
+
sessionSelectors.getSessionById(id)(useSessionStore.getState());
|
147
|
+
|
148
|
+
private getAgent = (id: string) =>
|
149
|
+
sessionSelectors.getSessionById(id)(useSessionStore.getState());
|
150
|
+
}
|
151
|
+
|
152
|
+
/**
|
153
|
+
* @deprecated
|
154
|
+
*/
|
155
|
+
export const configService = new ConfigService();
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { clientDB } from '@/database/client/db';
|
2
|
+
import { DataExporterRepos } from '@/database/repositories/dataExporter';
|
3
|
+
import { BaseClientService } from '@/services/baseClientService';
|
4
|
+
|
5
|
+
export class ClientService extends BaseClientService {
|
6
|
+
private get dataExporterRepos(): DataExporterRepos {
|
7
|
+
return new DataExporterRepos(clientDB as any, this.userId);
|
8
|
+
}
|
9
|
+
|
10
|
+
exportData = async () => {
|
11
|
+
const data = await this.dataExporterRepos.export();
|
12
|
+
|
13
|
+
return { data, url: undefined };
|
14
|
+
};
|
15
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { lambdaClient } from '@/libs/trpc/client';
|
2
|
+
|
3
|
+
import { IExportService } from './type';
|
4
|
+
|
5
|
+
export class ServerService implements IExportService {
|
6
|
+
exportData: IExportService['exportData'] = async () => {
|
7
|
+
return await lambdaClient.exporter.exportData.mutate();
|
8
|
+
};
|
9
|
+
}
|
@@ -2,11 +2,25 @@ import { MessageModel } from '@/database/_deprecated/models/message';
|
|
2
2
|
import { SessionModel } from '@/database/_deprecated/models/session';
|
3
3
|
import { SessionGroupModel } from '@/database/_deprecated/models/sessionGroup';
|
4
4
|
import { TopicModel } from '@/database/_deprecated/models/topic';
|
5
|
-
import { ImportResult, ImportResults } from '@/services/config';
|
6
5
|
import { useUserStore } from '@/store/user';
|
6
|
+
import { ConfigFile } from '@/types/exportConfig';
|
7
7
|
import { ImportStage, ImporterEntryData, OnImportCallbacks } from '@/types/importer';
|
8
8
|
import { UserSettings } from '@/types/user/settings';
|
9
9
|
|
10
|
+
export interface ImportResult {
|
11
|
+
added: number;
|
12
|
+
errors: number;
|
13
|
+
skips: number;
|
14
|
+
updated?: number;
|
15
|
+
}
|
16
|
+
export interface ImportResults {
|
17
|
+
messages?: ImportResult;
|
18
|
+
sessionGroups?: ImportResult;
|
19
|
+
sessions?: ImportResult;
|
20
|
+
topics?: ImportResult;
|
21
|
+
type?: string;
|
22
|
+
}
|
23
|
+
|
10
24
|
export class ClientService {
|
11
25
|
importSettings = async (settings: UserSettings) => {
|
12
26
|
await useUserStore.getState().importAppSettings(settings);
|
@@ -71,4 +85,31 @@ export class ClientService {
|
|
71
85
|
skips: input.skips.length,
|
72
86
|
};
|
73
87
|
};
|
88
|
+
|
89
|
+
importConfigState = async (config: ConfigFile, callbacks?: OnImportCallbacks): Promise<void> => {
|
90
|
+
if (config.exportType === 'settings') {
|
91
|
+
await this.importSettings(config.state.settings);
|
92
|
+
callbacks?.onStageChange?.(ImportStage.Success);
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
|
96
|
+
if (config.exportType === 'all') {
|
97
|
+
await this.importSettings(config.state.settings);
|
98
|
+
}
|
99
|
+
|
100
|
+
await this.importData(
|
101
|
+
{
|
102
|
+
messages: (config.state as any).messages || [],
|
103
|
+
sessionGroups: (config.state as any).sessionGroups || [],
|
104
|
+
sessions: (config.state as any).sessions || [],
|
105
|
+
topics: (config.state as any).topics || [],
|
106
|
+
version: config.version,
|
107
|
+
},
|
108
|
+
callbacks,
|
109
|
+
);
|
110
|
+
};
|
111
|
+
|
112
|
+
importPgData = async () => {
|
113
|
+
throw new Error('Not implemented');
|
114
|
+
};
|
74
115
|
}
|
@@ -2,7 +2,7 @@ import { eq, inArray } from 'drizzle-orm';
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
3
3
|
|
4
4
|
import { clientDB, initializeDB } from '@/database/client/db';
|
5
|
-
import mockImportData from '@/database/repositories/dataImporter/__tests__/fixtures/messages.json';
|
5
|
+
import mockImportData from '@/database/repositories/dataImporter/deprecated/__tests__/fixtures/messages.json';
|
6
6
|
import {
|
7
7
|
agents,
|
8
8
|
agentsToSessions,
|