@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
@@ -1,940 +1,180 @@
|
|
1
|
-
// @vitest-environment node
|
2
1
|
import { eq, inArray } from 'drizzle-orm/expressions';
|
3
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
4
|
-
|
5
|
-
import {
|
6
|
-
|
7
|
-
|
8
|
-
messages,
|
9
|
-
sessionGroups,
|
10
|
-
sessions,
|
11
|
-
topics,
|
12
|
-
users,
|
13
|
-
} from '@/database/schemas';
|
14
|
-
import { getTestDBInstance } from '@/database/server/core/dbForTest';
|
15
|
-
import { CURRENT_CONFIG_VERSION } from '@/migrations';
|
16
|
-
import { ImporterEntryData } from '@/types/importer';
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
|
+
|
4
|
+
import { getTestDB } from '@/database/models/__tests__/_util';
|
5
|
+
import * as Schema from '@/database/schemas';
|
6
|
+
import { ImportPgDataStructure } from '@/types/export';
|
17
7
|
|
18
8
|
import { DataImporterRepos } from '../index';
|
19
|
-
import
|
9
|
+
import agentsData from './fixtures/agents.json';
|
10
|
+
import agentsToSessionsData from './fixtures/agentsToSessions.json';
|
11
|
+
import topicsData from './fixtures/topic.json';
|
12
|
+
import userSettingsData from './fixtures/userSettings.json';
|
20
13
|
|
21
|
-
const
|
14
|
+
const clientDB = await getTestDB();
|
22
15
|
|
23
16
|
const userId = 'test-user-id';
|
24
17
|
let importer: DataImporterRepos;
|
25
18
|
|
26
19
|
beforeEach(async () => {
|
27
|
-
await
|
20
|
+
await clientDB.delete(Schema.users);
|
28
21
|
|
29
22
|
// 创建测试数据
|
30
|
-
await
|
31
|
-
await tx.insert(users).values({ id: userId });
|
23
|
+
await clientDB.transaction(async (tx) => {
|
24
|
+
await tx.insert(Schema.users).values({ id: userId });
|
32
25
|
});
|
33
26
|
|
34
|
-
importer = new DataImporterRepos(
|
27
|
+
importer = new DataImporterRepos(clientDB, userId);
|
28
|
+
});
|
29
|
+
afterEach(async () => {
|
30
|
+
await clientDB.delete(Schema.users);
|
35
31
|
});
|
36
32
|
|
37
33
|
describe('DataImporter', () => {
|
38
|
-
describe('import
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
sessionGroups: [
|
43
|
-
{ id: 'group1', name: 'Group 1', createdAt: 1715186011586, updatedAt: 1715186015053 },
|
44
|
-
{ id: 'group2', name: 'Group 2', createdAt: 1715186011586, updatedAt: 1715186015053 },
|
45
|
-
],
|
46
|
-
};
|
47
|
-
|
48
|
-
const result = await importer.importData(data);
|
49
|
-
|
50
|
-
expect(result.sessionGroups.added).toBe(2);
|
51
|
-
expect(result.sessionGroups.skips).toBe(0);
|
52
|
-
expect(result.sessionGroups.errors).toBe(0);
|
53
|
-
|
54
|
-
const groups = await serverDB.query.sessionGroups.findMany({
|
55
|
-
where: eq(sessionGroups.userId, userId),
|
56
|
-
});
|
57
|
-
expect(groups).toHaveLength(2);
|
58
|
-
});
|
59
|
-
|
60
|
-
it('should skip existing session groups and return correct result', async () => {
|
61
|
-
await serverDB
|
62
|
-
.insert(sessionGroups)
|
63
|
-
.values({ clientId: 'group1', name: 'Existing Group', userId });
|
34
|
+
describe('import userSettings', () => {
|
35
|
+
const data = userSettingsData as ImportPgDataStructure;
|
36
|
+
it('should import userSettings correctly', async () => {
|
37
|
+
const result = await importer.importPgData(data);
|
64
38
|
|
65
|
-
|
66
|
-
|
67
|
-
sessionGroups: [
|
68
|
-
{ id: 'group1', name: 'Group 1', createdAt: 1715186011586, updatedAt: 1715186015053 },
|
69
|
-
{ id: 'group2', name: 'Group 2', createdAt: 1715186011586, updatedAt: 1715186015053 },
|
70
|
-
],
|
71
|
-
};
|
39
|
+
expect(result.success).toBe(true);
|
40
|
+
expect(result.results.userSettings).toMatchObject({ added: 1, errors: 0, skips: 0 });
|
72
41
|
|
73
|
-
const
|
74
|
-
|
75
|
-
expect(result.sessionGroups.added).toBe(1);
|
76
|
-
expect(result.sessionGroups.skips).toBe(1);
|
77
|
-
expect(result.sessionGroups.errors).toBe(0);
|
78
|
-
});
|
79
|
-
});
|
80
|
-
|
81
|
-
describe('import sessions', () => {
|
82
|
-
it('should import sessions and return correct result', async () => {
|
83
|
-
const data: ImporterEntryData = {
|
84
|
-
version: CURRENT_CONFIG_VERSION,
|
85
|
-
sessions: [
|
86
|
-
{
|
87
|
-
id: 'session1',
|
88
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
89
|
-
updatedAt: '2023-01-01',
|
90
|
-
type: 'agent',
|
91
|
-
config: {
|
92
|
-
model: 'abc',
|
93
|
-
chatConfig: {} as any,
|
94
|
-
params: {},
|
95
|
-
systemRole: 'abc',
|
96
|
-
tts: {} as any,
|
97
|
-
},
|
98
|
-
meta: {
|
99
|
-
title: 'Session 1',
|
100
|
-
},
|
101
|
-
},
|
102
|
-
{
|
103
|
-
id: 'session2',
|
104
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
105
|
-
updatedAt: '2023-01-01',
|
106
|
-
type: 'agent',
|
107
|
-
config: {
|
108
|
-
model: 'abc',
|
109
|
-
chatConfig: {} as any,
|
110
|
-
params: {},
|
111
|
-
systemRole: 'abc',
|
112
|
-
tts: {} as any,
|
113
|
-
},
|
114
|
-
meta: {
|
115
|
-
title: 'Session 2',
|
116
|
-
},
|
117
|
-
},
|
118
|
-
],
|
119
|
-
};
|
120
|
-
|
121
|
-
const result = await importer.importData(data);
|
122
|
-
|
123
|
-
expect(result.sessions.added).toBe(2);
|
124
|
-
expect(result.sessions.skips).toBe(0);
|
125
|
-
expect(result.sessions.errors).toBe(0);
|
126
|
-
|
127
|
-
const importedSessions = await serverDB.query.sessions.findMany({
|
128
|
-
where: eq(sessions.userId, userId),
|
42
|
+
const res = await clientDB.query.userSettings.findMany({
|
43
|
+
where: eq(Schema.userSettings.id, userId),
|
129
44
|
});
|
130
|
-
expect(
|
45
|
+
expect(res).toHaveLength(1);
|
46
|
+
expect(res[0].general).toEqual({ fontSize: 12 });
|
47
|
+
});
|
131
48
|
|
132
|
-
|
133
|
-
|
49
|
+
it('should merge exist userSettings correctly', async () => {
|
50
|
+
await clientDB.transaction(async (tx) => {
|
51
|
+
await tx.insert(Schema.userSettings).values({ id: userId, general: { fontSize: 24 } });
|
52
|
+
await tx
|
53
|
+
.update(Schema.userSettings)
|
54
|
+
.set({ general: { fontSize: 24 } })
|
55
|
+
.where(eq(Schema.userSettings.id, userId));
|
134
56
|
});
|
135
57
|
|
136
|
-
|
58
|
+
const result = await importer.importPgData(data);
|
137
59
|
|
138
|
-
|
139
|
-
expect(
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
const data: ImporterEntryData = {
|
146
|
-
version: CURRENT_CONFIG_VERSION,
|
147
|
-
sessions: [
|
148
|
-
{
|
149
|
-
id: 'session1',
|
150
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
151
|
-
updatedAt: '2023-01-01',
|
152
|
-
type: 'agent',
|
153
|
-
config: {
|
154
|
-
model: 'abc',
|
155
|
-
chatConfig: {} as any,
|
156
|
-
params: {},
|
157
|
-
systemRole: 'abc',
|
158
|
-
tts: {} as any,
|
159
|
-
},
|
160
|
-
meta: {
|
161
|
-
title: 'Session 1',
|
162
|
-
},
|
163
|
-
},
|
164
|
-
{
|
165
|
-
id: 'session2',
|
166
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
167
|
-
updatedAt: '2023-01-01',
|
168
|
-
type: 'agent',
|
169
|
-
config: {
|
170
|
-
model: 'abc',
|
171
|
-
chatConfig: {} as any,
|
172
|
-
params: {},
|
173
|
-
systemRole: 'abc',
|
174
|
-
tts: {} as any,
|
175
|
-
},
|
176
|
-
meta: {
|
177
|
-
title: 'Session 2',
|
178
|
-
},
|
179
|
-
},
|
180
|
-
],
|
181
|
-
};
|
182
|
-
|
183
|
-
const result = await importer.importData(data);
|
184
|
-
|
185
|
-
expect(result.sessions.added).toBe(1);
|
186
|
-
expect(result.sessions.skips).toBe(1);
|
187
|
-
expect(result.sessions.errors).toBe(0);
|
188
|
-
});
|
189
|
-
|
190
|
-
it('should associate imported sessions with session groups', async () => {
|
191
|
-
const data: ImporterEntryData = {
|
192
|
-
version: CURRENT_CONFIG_VERSION,
|
193
|
-
sessionGroups: [
|
194
|
-
{ id: 'group1', name: 'Group 1', createdAt: 1715186011586, updatedAt: 1715186015053 },
|
195
|
-
{ id: 'group2', name: 'Group 2', createdAt: 1715186011586, updatedAt: 1715186015053 },
|
196
|
-
],
|
197
|
-
sessions: [
|
198
|
-
{
|
199
|
-
id: 'session1',
|
200
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
201
|
-
updatedAt: '2023-01-01',
|
202
|
-
type: 'agent',
|
203
|
-
group: 'group1',
|
204
|
-
config: {
|
205
|
-
model: 'abc',
|
206
|
-
chatConfig: {} as any,
|
207
|
-
params: {},
|
208
|
-
systemRole: 'abc',
|
209
|
-
tts: {} as any,
|
210
|
-
},
|
211
|
-
meta: {
|
212
|
-
title: 'Session 1',
|
213
|
-
},
|
214
|
-
},
|
215
|
-
{
|
216
|
-
id: 'session2',
|
217
|
-
group: 'group2',
|
218
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
219
|
-
updatedAt: '2023-01-01',
|
220
|
-
type: 'agent',
|
221
|
-
config: {
|
222
|
-
model: 'abc',
|
223
|
-
chatConfig: {} as any,
|
224
|
-
params: {},
|
225
|
-
systemRole: 'abc',
|
226
|
-
tts: {} as any,
|
227
|
-
},
|
228
|
-
meta: {
|
229
|
-
title: 'Session 2',
|
230
|
-
},
|
231
|
-
},
|
232
|
-
{
|
233
|
-
id: 'session3',
|
234
|
-
group: 'group4',
|
235
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
236
|
-
updatedAt: '2023-01-01',
|
237
|
-
type: 'agent',
|
238
|
-
config: {
|
239
|
-
model: 'abc',
|
240
|
-
chatConfig: {} as any,
|
241
|
-
params: {},
|
242
|
-
systemRole: 'abc',
|
243
|
-
tts: {} as any,
|
244
|
-
},
|
245
|
-
meta: {
|
246
|
-
title: 'Session 3',
|
247
|
-
},
|
248
|
-
},
|
249
|
-
],
|
250
|
-
};
|
251
|
-
|
252
|
-
const result = await importer.importData(data);
|
253
|
-
|
254
|
-
expect(result.sessionGroups.added).toBe(2);
|
255
|
-
expect(result.sessionGroups.skips).toBe(0);
|
256
|
-
|
257
|
-
expect(result.sessions.added).toBe(3);
|
258
|
-
expect(result.sessions.skips).toBe(0);
|
259
|
-
|
260
|
-
// session 1 should be associated with group 1
|
261
|
-
const session1 = await serverDB.query.sessions.findFirst({
|
262
|
-
where: eq(sessions.clientId, 'session1'),
|
263
|
-
with: { group: true },
|
60
|
+
expect(result.success).toBe(true);
|
61
|
+
expect(result.results.userSettings).toMatchObject({
|
62
|
+
updated: 1,
|
63
|
+
errors: 0,
|
64
|
+
skips: 0,
|
65
|
+
added: 0,
|
264
66
|
});
|
265
|
-
expect(session1?.group).toBeDefined();
|
266
67
|
|
267
|
-
|
268
|
-
|
269
|
-
where: eq(sessions.clientId, 'session3'),
|
270
|
-
with: { group: true },
|
68
|
+
const res = await clientDB.query.userSettings.findMany({
|
69
|
+
where: eq(Schema.userSettings.id, userId),
|
271
70
|
});
|
272
|
-
expect(
|
71
|
+
expect(res).toHaveLength(1);
|
72
|
+
expect(res[0].general).toEqual({ fontSize: 12 });
|
273
73
|
});
|
74
|
+
});
|
274
75
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
{
|
280
|
-
id: 'session1',
|
281
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
282
|
-
updatedAt: '2023-01-01',
|
283
|
-
type: 'agent',
|
284
|
-
config: {
|
285
|
-
model: 'abc',
|
286
|
-
chatConfig: {} as any,
|
287
|
-
params: {},
|
288
|
-
systemRole: 'Test Agent 1',
|
289
|
-
tts: {} as any,
|
290
|
-
},
|
291
|
-
meta: {
|
292
|
-
title: 'Session 1',
|
293
|
-
},
|
294
|
-
},
|
295
|
-
{
|
296
|
-
id: 'session2',
|
297
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
298
|
-
updatedAt: '2023-01-01',
|
299
|
-
type: 'agent',
|
300
|
-
config: {
|
301
|
-
model: 'def',
|
302
|
-
chatConfig: {} as any,
|
303
|
-
params: {},
|
304
|
-
systemRole: 'Test Agent 2',
|
305
|
-
tts: {} as any,
|
306
|
-
},
|
307
|
-
meta: {
|
308
|
-
title: 'Session 2',
|
309
|
-
},
|
310
|
-
},
|
311
|
-
],
|
312
|
-
};
|
313
|
-
|
314
|
-
await importer.importData(data);
|
315
|
-
|
316
|
-
// 验证是否为每个 session 创建了对应的 agent
|
317
|
-
const agentCount = await serverDB.query.agents.findMany({
|
318
|
-
where: eq(agents.userId, userId),
|
319
|
-
});
|
320
|
-
expect(agentCount).toHaveLength(2);
|
76
|
+
describe('import agents and sessions', () => {
|
77
|
+
it('should import return correct result', async () => {
|
78
|
+
const data = agentsData as ImportPgDataStructure;
|
79
|
+
const result = await importer.importPgData(data);
|
321
80
|
|
322
|
-
|
323
|
-
|
324
|
-
where: eq(agents.systemRole, 'Test Agent 1'),
|
325
|
-
});
|
326
|
-
expect(agent1?.model).toBe('abc');
|
81
|
+
expect(result.success).toBe(true);
|
82
|
+
expect(result.results.agents).toMatchObject({ added: 1, errors: 0, skips: 0 });
|
327
83
|
|
328
|
-
const
|
329
|
-
where: eq(agents.
|
84
|
+
const agentRes = await clientDB.query.agents.findMany({
|
85
|
+
where: eq(Schema.agents.userId, userId),
|
330
86
|
});
|
331
|
-
|
332
|
-
|
333
|
-
// 验证 agentsToSessions 关联是否正确建立
|
334
|
-
const session1 = await serverDB.query.sessions.findFirst({
|
335
|
-
where: eq(sessions.clientId, 'session1'),
|
87
|
+
const sessionRes = await clientDB.query.sessions.findMany({
|
88
|
+
where: eq(Schema.sessions.userId, userId),
|
336
89
|
});
|
337
|
-
const
|
338
|
-
where: eq(agentsToSessions.
|
339
|
-
with: { agent: true },
|
90
|
+
const agentsToSessionRes = await clientDB.query.agentsToSessions.findMany({
|
91
|
+
where: eq(Schema.agentsToSessions.userId, userId),
|
340
92
|
});
|
341
93
|
|
342
|
-
expect(
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
where: eq(agentsToSessions.sessionId, session2?.id!),
|
349
|
-
with: { agent: true },
|
94
|
+
expect(agentRes).toHaveLength(1);
|
95
|
+
expect(sessionRes).toHaveLength(1);
|
96
|
+
expect(agentsToSessionRes).toHaveLength(1);
|
97
|
+
expect(agentsToSessionRes[0]).toMatchObject({
|
98
|
+
agentId: agentRes[0].id,
|
99
|
+
sessionId: sessionRes[0].id,
|
350
100
|
});
|
351
101
|
|
352
|
-
expect(
|
102
|
+
expect(agentRes[0].clientId).toEqual(agentsData.data.agents[0].id);
|
103
|
+
expect(sessionRes[0].clientId).toEqual(agentsData.data.sessions[0].id);
|
353
104
|
});
|
354
105
|
|
355
|
-
it('should
|
356
|
-
|
357
|
-
await importer.
|
358
|
-
sessions: [
|
359
|
-
{
|
360
|
-
id: 'session1',
|
361
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
362
|
-
updatedAt: '2023-01-01',
|
363
|
-
type: 'agent',
|
364
|
-
config: {
|
365
|
-
model: 'abc',
|
366
|
-
chatConfig: {} as any,
|
367
|
-
params: {},
|
368
|
-
systemRole: 'Test Agent 1',
|
369
|
-
tts: {} as any,
|
370
|
-
},
|
371
|
-
meta: {
|
372
|
-
title: 'Session 1',
|
373
|
-
},
|
374
|
-
},
|
375
|
-
],
|
376
|
-
version: CURRENT_CONFIG_VERSION,
|
377
|
-
});
|
106
|
+
it('should skip duplicated data by default', async () => {
|
107
|
+
const data = agentsData as ImportPgDataStructure;
|
108
|
+
const result = await importer.importPgData(data);
|
378
109
|
|
379
|
-
|
380
|
-
|
381
|
-
sessions: [
|
382
|
-
{
|
383
|
-
id: 'session1',
|
384
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
385
|
-
updatedAt: '2023-01-01',
|
386
|
-
type: 'agent',
|
387
|
-
config: {
|
388
|
-
model: 'abc',
|
389
|
-
chatConfig: {} as any,
|
390
|
-
params: {},
|
391
|
-
systemRole: 'Test Agent 1',
|
392
|
-
tts: {} as any,
|
393
|
-
},
|
394
|
-
meta: {
|
395
|
-
title: 'Session 1',
|
396
|
-
},
|
397
|
-
},
|
398
|
-
],
|
399
|
-
version: CURRENT_CONFIG_VERSION,
|
400
|
-
});
|
110
|
+
expect(result.success).toBe(true);
|
111
|
+
expect(result.results.agents).toMatchObject({ added: 1, errors: 0, skips: 0 });
|
401
112
|
|
402
|
-
//
|
403
|
-
const
|
404
|
-
|
113
|
+
// import again to make sure it skip duplicated by default
|
114
|
+
const result2 = await importer.importPgData(data);
|
115
|
+
expect(result2.success).toBe(true);
|
116
|
+
expect(result2.results).toEqual({
|
117
|
+
agents: { added: 0, errors: 0, skips: 1, updated: 0 },
|
118
|
+
agentsToSessions: { added: 0, errors: 0, skips: 1, updated: 0 },
|
119
|
+
sessions: { added: 0, errors: 0, skips: 1, updated: 0 },
|
405
120
|
});
|
406
|
-
expect(agentCount).toHaveLength(1);
|
407
121
|
});
|
408
|
-
});
|
409
122
|
|
410
|
-
|
411
|
-
|
412
|
-
const
|
413
|
-
version: CURRENT_CONFIG_VERSION,
|
414
|
-
topics: [
|
415
|
-
{
|
416
|
-
id: 'topic1',
|
417
|
-
title: 'Topic 1',
|
418
|
-
createdAt: 1715186011586,
|
419
|
-
updatedAt: 1715186015053,
|
420
|
-
sessionId: 'session1',
|
421
|
-
},
|
422
|
-
{
|
423
|
-
id: 'topic2',
|
424
|
-
title: 'Topic 2',
|
425
|
-
createdAt: 1715186011586,
|
426
|
-
updatedAt: 1715186015053,
|
427
|
-
sessionId: 'session2',
|
428
|
-
},
|
429
|
-
],
|
430
|
-
sessions: [
|
431
|
-
{
|
432
|
-
id: 'session1',
|
433
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
434
|
-
updatedAt: '2023-01-01',
|
435
|
-
type: 'agent',
|
436
|
-
config: {
|
437
|
-
model: 'abc',
|
438
|
-
chatConfig: {} as any,
|
439
|
-
params: {},
|
440
|
-
systemRole: 'abc',
|
441
|
-
tts: {} as any,
|
442
|
-
},
|
443
|
-
meta: {
|
444
|
-
title: 'Session 1',
|
445
|
-
},
|
446
|
-
},
|
447
|
-
{
|
448
|
-
id: 'session2',
|
449
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
450
|
-
updatedAt: '2023-01-01',
|
451
|
-
type: 'agent',
|
452
|
-
config: {
|
453
|
-
model: 'abc',
|
454
|
-
chatConfig: {} as any,
|
455
|
-
params: {},
|
456
|
-
systemRole: 'abc',
|
457
|
-
tts: {} as any,
|
458
|
-
},
|
459
|
-
meta: {
|
460
|
-
title: 'Session 2',
|
461
|
-
},
|
462
|
-
},
|
463
|
-
],
|
464
|
-
};
|
465
|
-
|
466
|
-
const result = await importer.importData(data);
|
467
|
-
|
468
|
-
expect(result.topics.added).toBe(2);
|
469
|
-
expect(result.topics.skips).toBe(0);
|
470
|
-
expect(result.topics.errors).toBe(0);
|
471
|
-
|
472
|
-
const importedTopics = await serverDB.query.topics.findMany({
|
473
|
-
where: eq(topics.userId, userId),
|
474
|
-
});
|
475
|
-
expect(importedTopics).toHaveLength(2);
|
476
|
-
});
|
123
|
+
it('should import without agentToSessions error', async () => {
|
124
|
+
const data = agentsToSessionsData as ImportPgDataStructure;
|
125
|
+
const result = await importer.importPgData(data);
|
477
126
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
const data: ImporterEntryData = {
|
482
|
-
version: CURRENT_CONFIG_VERSION,
|
483
|
-
topics: [
|
484
|
-
{ id: 'topic1', title: 'Topic 1', createdAt: 1715186011586, updatedAt: 1715186015053 },
|
485
|
-
{ id: 'topic2', title: 'Topic 2', createdAt: 1715186011586, updatedAt: 1715186015053 },
|
486
|
-
],
|
487
|
-
};
|
488
|
-
|
489
|
-
const result = await importer.importData(data);
|
490
|
-
expect(result.topics.added).toBe(1);
|
491
|
-
expect(result.topics.skips).toBe(1);
|
492
|
-
expect(result.topics.errors).toBe(0);
|
493
|
-
});
|
127
|
+
expect(result.success).toBe(true);
|
128
|
+
expect(result.results.agentsToSessions).toMatchObject({ added: 9, errors: 0, skips: 0 });
|
494
129
|
|
495
|
-
|
496
|
-
const
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
updatedAt: '2023-01-01',
|
503
|
-
type: 'agent',
|
504
|
-
config: {
|
505
|
-
model: 'abc',
|
506
|
-
chatConfig: {} as any,
|
507
|
-
params: {},
|
508
|
-
systemRole: 'abc',
|
509
|
-
tts: {} as any,
|
510
|
-
},
|
511
|
-
meta: {
|
512
|
-
title: 'Session 1',
|
513
|
-
},
|
514
|
-
},
|
515
|
-
],
|
516
|
-
topics: [
|
517
|
-
{
|
518
|
-
id: 'topic1',
|
519
|
-
title: 'Topic 1',
|
520
|
-
createdAt: 1715186011586,
|
521
|
-
updatedAt: 1715186015053,
|
522
|
-
sessionId: 'session1',
|
523
|
-
},
|
524
|
-
{ id: 'topic2', title: 'Topic 2', createdAt: 1715186011586, updatedAt: 1715186015053 },
|
525
|
-
],
|
526
|
-
};
|
527
|
-
|
528
|
-
await importer.importData(data);
|
529
|
-
|
530
|
-
// topic1 should be associated with session1
|
531
|
-
const [topic1] = await serverDB
|
532
|
-
.select({ sessionClientId: sessions.clientId })
|
533
|
-
.from(topics)
|
534
|
-
.where(eq(topics.clientId, 'topic1'))
|
535
|
-
.leftJoin(sessions, eq(topics.sessionId, sessions.id));
|
536
|
-
|
537
|
-
expect(topic1?.sessionClientId).toBe('session1');
|
538
|
-
|
539
|
-
// topic2 should not have session
|
540
|
-
const topic2 = await serverDB.query.topics.findFirst({
|
541
|
-
where: eq(topics.clientId, 'topic2'),
|
542
|
-
with: { session: true },
|
130
|
+
// import again to make sure it skip duplicated by default
|
131
|
+
const result2 = await importer.importPgData(data);
|
132
|
+
expect(result2.success).toBe(true);
|
133
|
+
expect(result2.results).toEqual({
|
134
|
+
agents: { added: 0, errors: 0, skips: 9, updated: 0 },
|
135
|
+
agentsToSessions: { added: 0, errors: 0, skips: 9, updated: 0 },
|
136
|
+
sessions: { added: 0, errors: 0, skips: 9, updated: 0 },
|
543
137
|
});
|
544
|
-
expect(topic2?.session).toBeNull();
|
545
138
|
});
|
546
139
|
});
|
547
140
|
|
548
|
-
describe('import
|
549
|
-
it('should import
|
550
|
-
const
|
551
|
-
|
552
|
-
messages: [
|
553
|
-
{
|
554
|
-
id: 'msg1',
|
555
|
-
content: 'Message 1',
|
556
|
-
role: 'user',
|
557
|
-
createdAt: 1715186011586,
|
558
|
-
updatedAt: 1715186015053,
|
559
|
-
sessionId: 'session1',
|
560
|
-
topicId: 'topic1',
|
561
|
-
},
|
562
|
-
{
|
563
|
-
id: 'msg2',
|
564
|
-
content: 'Message 2',
|
565
|
-
role: 'assistant',
|
566
|
-
createdAt: 1715186011586,
|
567
|
-
updatedAt: 1715186015053,
|
568
|
-
sessionId: 'session1',
|
569
|
-
topicId: 'topic1',
|
570
|
-
parentId: 'msg1',
|
571
|
-
},
|
572
|
-
],
|
573
|
-
sessions: [
|
574
|
-
{
|
575
|
-
id: 'session1',
|
576
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
577
|
-
updatedAt: '2023-01-01',
|
578
|
-
type: 'agent',
|
579
|
-
config: {
|
580
|
-
model: 'abc',
|
581
|
-
chatConfig: {} as any,
|
582
|
-
params: {},
|
583
|
-
systemRole: 'abc',
|
584
|
-
tts: {} as any,
|
585
|
-
},
|
586
|
-
meta: {
|
587
|
-
title: 'Session 1',
|
588
|
-
},
|
589
|
-
},
|
590
|
-
],
|
591
|
-
topics: [
|
592
|
-
{
|
593
|
-
id: 'topic1',
|
594
|
-
title: 'Topic 1',
|
595
|
-
createdAt: 1715186011586,
|
596
|
-
updatedAt: 1715186015053,
|
597
|
-
sessionId: 'session1',
|
598
|
-
},
|
599
|
-
],
|
600
|
-
};
|
601
|
-
|
602
|
-
const result = await importer.importData(data);
|
603
|
-
|
604
|
-
expect(result.messages.added).toBe(2);
|
605
|
-
expect(result.messages.skips).toBe(0);
|
606
|
-
expect(result.messages.errors).toBe(0);
|
607
|
-
|
608
|
-
const importedMessages = await serverDB.query.messages.findMany({
|
609
|
-
where: eq(messages.userId, userId),
|
610
|
-
});
|
611
|
-
expect(importedMessages).toHaveLength(2);
|
612
|
-
});
|
141
|
+
describe('import message and topic', () => {
|
142
|
+
it('should import return correct result', async () => {
|
143
|
+
const exportData = topicsData as ImportPgDataStructure;
|
144
|
+
const result = await importer.importPgData(exportData);
|
613
145
|
|
614
|
-
|
615
|
-
|
616
|
-
clientId: 'msg1',
|
617
|
-
content: 'Existing Message',
|
618
|
-
role: 'user',
|
619
|
-
userId,
|
620
|
-
});
|
146
|
+
expect(result.success).toBe(true);
|
147
|
+
expect(result.results.messages).toMatchObject({ added: 6, errors: 0, skips: 0 });
|
621
148
|
|
622
|
-
const
|
623
|
-
|
624
|
-
messages: [
|
625
|
-
{
|
626
|
-
id: 'msg1',
|
627
|
-
content: 'Message 1',
|
628
|
-
role: 'user',
|
629
|
-
createdAt: 1715186011586,
|
630
|
-
updatedAt: 1715186015053,
|
631
|
-
},
|
632
|
-
{
|
633
|
-
id: 'msg2',
|
634
|
-
content: 'Message 2',
|
635
|
-
role: 'assistant',
|
636
|
-
createdAt: 1715186011586,
|
637
|
-
updatedAt: 1715186015053,
|
638
|
-
},
|
639
|
-
],
|
640
|
-
};
|
641
|
-
|
642
|
-
const result = await importer.importData(data);
|
643
|
-
|
644
|
-
expect(result.messages.added).toBe(1);
|
645
|
-
expect(result.messages.skips).toBe(1);
|
646
|
-
expect(result.messages.errors).toBe(0);
|
647
|
-
});
|
648
|
-
|
649
|
-
it('should associate imported messages with sessions and topics', async () => {
|
650
|
-
const data: ImporterEntryData = {
|
651
|
-
version: CURRENT_CONFIG_VERSION,
|
652
|
-
sessions: [
|
653
|
-
{
|
654
|
-
id: 'session1',
|
655
|
-
createdAt: '2022-05-14T18:18:10.494Z',
|
656
|
-
updatedAt: '2023-01-01',
|
657
|
-
type: 'agent',
|
658
|
-
config: {
|
659
|
-
model: 'abc',
|
660
|
-
chatConfig: {} as any,
|
661
|
-
params: {},
|
662
|
-
systemRole: 'abc',
|
663
|
-
tts: {} as any,
|
664
|
-
},
|
665
|
-
meta: {
|
666
|
-
title: 'Session 1',
|
667
|
-
},
|
668
|
-
},
|
669
|
-
],
|
670
|
-
topics: [
|
671
|
-
{
|
672
|
-
id: 'topic1',
|
673
|
-
title: 'Topic 1',
|
674
|
-
createdAt: 1715186011586,
|
675
|
-
updatedAt: 1715186015053,
|
676
|
-
sessionId: 'session1',
|
677
|
-
},
|
678
|
-
],
|
679
|
-
messages: [
|
680
|
-
{
|
681
|
-
id: 'msg1',
|
682
|
-
content: 'Message 1',
|
683
|
-
role: 'user',
|
684
|
-
createdAt: 1715186011586,
|
685
|
-
updatedAt: 1715186015053,
|
686
|
-
sessionId: 'session1',
|
687
|
-
topicId: 'topic1',
|
688
|
-
},
|
689
|
-
{
|
690
|
-
id: 'msg2',
|
691
|
-
content: 'Message 2',
|
692
|
-
role: 'assistant',
|
693
|
-
createdAt: 1715186011586,
|
694
|
-
updatedAt: 1715186015053,
|
695
|
-
sessionId: 'session1',
|
696
|
-
topicId: 'topic1',
|
697
|
-
parentId: 'msg1',
|
698
|
-
},
|
699
|
-
{
|
700
|
-
id: 'msg3',
|
701
|
-
content: 'Message 3',
|
702
|
-
role: 'user',
|
703
|
-
createdAt: 1715186011586,
|
704
|
-
updatedAt: 1715186015053,
|
705
|
-
},
|
706
|
-
],
|
707
|
-
};
|
708
|
-
|
709
|
-
await importer.importData(data);
|
710
|
-
|
711
|
-
// msg1 and msg2 should be associated with session1 and topic1
|
712
|
-
const [msg1, msg2] = await serverDB.query.messages.findMany({
|
713
|
-
where: inArray(messages.clientId, ['msg1', 'msg2']),
|
714
|
-
with: {
|
715
|
-
session: true,
|
716
|
-
topic: true,
|
717
|
-
},
|
149
|
+
const messageRes = await clientDB.query.messages.findMany({
|
150
|
+
where: eq(Schema.agents.userId, userId),
|
718
151
|
});
|
719
|
-
|
720
|
-
|
721
|
-
expect(msg1.topic?.clientId).toBe('topic1');
|
722
|
-
expect(msg2.session?.clientId).toBe('session1');
|
723
|
-
expect(msg2.topic?.clientId).toBe('topic1');
|
724
|
-
|
725
|
-
// msg3 should not have session and topic
|
726
|
-
const msg3 = await serverDB.query.messages.findFirst({
|
727
|
-
where: eq(messages.clientId, 'msg3'),
|
728
|
-
with: {
|
729
|
-
session: true,
|
730
|
-
topic: true,
|
731
|
-
},
|
152
|
+
const topicRes = await clientDB.query.topics.findMany({
|
153
|
+
where: eq(Schema.sessions.userId, userId),
|
732
154
|
});
|
733
|
-
expect(msg3?.session).toBeNull();
|
734
|
-
expect(msg3?.topic).toBeNull();
|
735
|
-
});
|
736
155
|
|
737
|
-
|
738
|
-
|
739
|
-
version: CURRENT_CONFIG_VERSION,
|
740
|
-
messages: [
|
741
|
-
{
|
742
|
-
id: 'msg1',
|
743
|
-
content: 'Message 1',
|
744
|
-
role: 'user',
|
745
|
-
createdAt: 1715186011586,
|
746
|
-
updatedAt: 1715186015053,
|
747
|
-
},
|
748
|
-
{
|
749
|
-
id: 'msg2',
|
750
|
-
content: 'Message 2',
|
751
|
-
role: 'assistant',
|
752
|
-
createdAt: 1715186011586,
|
753
|
-
updatedAt: 1715186015053,
|
754
|
-
parentId: 'msg1',
|
755
|
-
},
|
756
|
-
],
|
757
|
-
};
|
758
|
-
|
759
|
-
await importer.importData(data);
|
760
|
-
|
761
|
-
const msg2 = await serverDB.query.messages.findFirst({
|
762
|
-
where: eq(messages.clientId, 'msg2'),
|
763
|
-
with: { parent: true },
|
764
|
-
});
|
156
|
+
expect(topicRes).toHaveLength(1);
|
157
|
+
expect(messageRes).toHaveLength(6);
|
765
158
|
|
766
|
-
expect(
|
159
|
+
expect(topicRes[0].clientId).toEqual(topicsData.data.topics[0].id);
|
160
|
+
expect(
|
161
|
+
messageRes.find((msg) => msg.content === topicsData.data.messages[0].content)?.clientId,
|
162
|
+
).toEqual(topicsData.data.messages[0].id);
|
767
163
|
});
|
768
164
|
|
769
|
-
it('should
|
770
|
-
|
165
|
+
it('should only return non-zero result', async () => {
|
166
|
+
const exportData = topicsData as ImportPgDataStructure;
|
167
|
+
const result = await importer.importPgData(exportData);
|
771
168
|
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
content: 'hello',
|
781
|
-
files: [],
|
782
|
-
sessionId: 'inbox',
|
783
|
-
topicId: '2wcF8yaS',
|
784
|
-
createdAt: 1714236590340,
|
785
|
-
id: 'DCG1G1EH',
|
786
|
-
updatedAt: 1714236590340,
|
787
|
-
extra: {},
|
788
|
-
},
|
789
|
-
{
|
790
|
-
role: 'assistant',
|
791
|
-
content: '...',
|
792
|
-
parentId: 'DCG1G1EH',
|
793
|
-
sessionId: 'inbox',
|
794
|
-
topicId: '2wcF8yaS',
|
795
|
-
createdAt: 1714236590441,
|
796
|
-
id: 'gY41w5vQ',
|
797
|
-
updatedAt: 1714236590518,
|
798
|
-
error: {
|
799
|
-
body: {
|
800
|
-
error: {
|
801
|
-
message: "model 'mixtral' not found, try pulling it first",
|
802
|
-
name: 'ResponseError',
|
803
|
-
status_code: 404,
|
804
|
-
},
|
805
|
-
provider: 'ollama',
|
806
|
-
},
|
807
|
-
message:
|
808
|
-
'Error requesting Ollama service, please troubleshoot or retry based on the following information',
|
809
|
-
type: 'OllamaBizError',
|
810
|
-
},
|
811
|
-
extra: { fromModel: 'mixtral', fromProvider: 'ollama' },
|
812
|
-
},
|
813
|
-
{
|
814
|
-
role: 'user',
|
815
|
-
content: 'hello',
|
816
|
-
files: [],
|
817
|
-
sessionId: 'a5fefc88-f6c1-44fb-9e98-3d366b1ed589',
|
818
|
-
topicId: 'v38snJ0A',
|
819
|
-
createdAt: 1717080410895,
|
820
|
-
id: 'qOIxEGEB',
|
821
|
-
updatedAt: 1717080410895,
|
822
|
-
extra: {},
|
823
|
-
},
|
824
|
-
{
|
825
|
-
role: 'assistant',
|
826
|
-
content: '...',
|
827
|
-
parentId: 'qOIxEGEB',
|
828
|
-
sessionId: 'a5fefc88-f6c1-44fb-9e98-3d366b1ed589',
|
829
|
-
topicId: 'v38snJ0A',
|
830
|
-
createdAt: 1717080410970,
|
831
|
-
id: 'w28FcqY5',
|
832
|
-
updatedAt: 1717080411485,
|
833
|
-
error: {
|
834
|
-
body: { error: { errorType: 'NoOpenAIAPIKey' }, provider: 'openai' },
|
835
|
-
message: 'OpenAI API Key is empty, please add a custom OpenAI API Key',
|
836
|
-
type: 'NoOpenAIAPIKey',
|
837
|
-
},
|
838
|
-
extra: { fromModel: 'gpt-3.5-turbo', fromProvider: 'openai' },
|
839
|
-
},
|
840
|
-
],
|
841
|
-
sessionGroups: [
|
842
|
-
{
|
843
|
-
name: 'Writter',
|
844
|
-
sort: 0,
|
845
|
-
createdAt: 1706114744425,
|
846
|
-
id: 'XlUbvOvL',
|
847
|
-
updatedAt: 1706114747468,
|
848
|
-
},
|
849
|
-
],
|
850
|
-
sessions: [
|
851
|
-
{
|
852
|
-
config: {
|
853
|
-
model: 'gpt-3.5-turbo',
|
854
|
-
params: {
|
855
|
-
frequency_penalty: 0,
|
856
|
-
presence_penalty: 0,
|
857
|
-
temperature: 0.6,
|
858
|
-
top_p: 1,
|
859
|
-
},
|
860
|
-
plugins: [],
|
861
|
-
systemRole:
|
862
|
-
"You are a LobeChat technical operator 🍐🐊. You now need to write a developer's guide for LobeChat as a guide for them to develop LobeChat. This guide will include several sections, and you need to output the corresponding document content based on the user's input.\n\nHere is the technical introduction of LobeChat\n\n LobeChat is an AI conversation application built with the Next.js framework. It uses a series of technology stacks to implement various functions and features.\n\n\n ## Basic Technology Stack\n\n The core technology stack of LobeChat is as follows:\n\n - **Framework**: We chose [Next.js](https://nextjs.org/), a powerful React framework that provides key features such as server-side rendering, routing framework, and Router Handler for our project.\n - **Component Library**: We use [Ant Design (antd)](https://ant.design/) as the basic component library, and introduce [lobe-ui](https://github.com/lobehub/lobe-ui) as our business component library.\n - **State Management**: We use [zustand](https://github.com/pmndrs/zustand), a lightweight and easy-to-use state management library.\n - **Network Request**: We adopt [swr](https://swr.vercel.app/), a React Hooks library for data fetching.\n - **Routing**: We directly use the routing solution provided by [Next.js](https://nextjs.org/) itself.\n - **Internationalization**: We use [i18next](https://www.i18next.com/) to implement multi-language support for the application.\n - **Styling**: We use [antd-style](https://github.com/ant-design/antd-style), a CSS-in-JS library that is compatible with Ant Design.\n - **Unit Testing**: We use [vitest](https://github.com/vitejs/vitest) for unit testing.\n\n ## Folder Directory Structure\n\n The folder directory structure of LobeChat is as follows:\n\n \\`\\`\\`bash\n src\n ├── app # Main logic and state management related code of the application\n ├── components # Reusable UI components\n ├── config # Application configuration files, including client environment variables and server environment variables\n ├── const # Used to define constants, such as action types, route names, etc.\n ├── features # Function modules related to business functions, such as Agent settings, plugin development pop-ups, etc.\n ├── hooks # Custom utility Hooks reused throughout the application\n ├── layout # Layout components of the application, such as navigation bar, sidebar, etc.\n ├── locales # Language files for internationalization\n ├── services # Encapsulated backend service interfaces, such as HTTP requests\n ├── store # Zustand store for state management\n ├── types # TypeScript type definition files\n └── utils # Common utility functions\n \\`\\`\\`\n",
|
863
|
-
tts: {
|
864
|
-
showAllLocaleVoice: false,
|
865
|
-
sttLocale: 'auto',
|
866
|
-
ttsService: 'openai',
|
867
|
-
voice: { openai: 'alloy' },
|
868
|
-
},
|
869
|
-
chatConfig: {
|
870
|
-
autoCreateTopicThreshold: 2,
|
871
|
-
displayMode: 'chat',
|
872
|
-
enableAutoCreateTopic: true,
|
873
|
-
historyCount: 1,
|
874
|
-
},
|
875
|
-
},
|
876
|
-
group: 'XlUbvOvL',
|
877
|
-
meta: {
|
878
|
-
avatar: '📝',
|
879
|
-
description:
|
880
|
-
'LobeChat is an AI conversation application built with the Next.js framework. I will help you write the development documentation for LobeChat.',
|
881
|
-
tags: [
|
882
|
-
'Development Documentation',
|
883
|
-
'Technical Introduction',
|
884
|
-
'next-js',
|
885
|
-
'react',
|
886
|
-
'lobe-chat',
|
887
|
-
],
|
888
|
-
title: 'LobeChat Technical Documentation Expert',
|
889
|
-
},
|
890
|
-
type: 'agent',
|
891
|
-
createdAt: '2024-01-24T16:43:12.164Z',
|
892
|
-
id: 'a5fefc88-f6c1-44fb-9e98-3d366b1ed589',
|
893
|
-
updatedAt: '2024-01-24T16:46:15.226Z',
|
894
|
-
pinned: false,
|
895
|
-
},
|
896
|
-
],
|
897
|
-
topics: [
|
898
|
-
{
|
899
|
-
title: 'Default Topic',
|
900
|
-
sessionId: 'inbox',
|
901
|
-
createdAt: 1714236590531,
|
902
|
-
id: '2wcF8yaS',
|
903
|
-
updatedAt: 1714236590531,
|
904
|
-
},
|
905
|
-
{
|
906
|
-
title: 'Default Topic',
|
907
|
-
sessionId: 'a5fefc88-f6c1-44fb-9e98-3d366b1ed589',
|
908
|
-
createdAt: 1717080410825,
|
909
|
-
id: 'v38snJ0A',
|
910
|
-
updatedAt: 1717080410825,
|
911
|
-
},
|
912
|
-
],
|
913
|
-
version: mockImportData.version,
|
914
|
-
});
|
915
|
-
|
916
|
-
expect(result).toEqual({
|
917
|
-
sessionGroups: { added: 1, errors: 0, skips: 0 },
|
918
|
-
sessions: { added: 1, errors: 0, skips: 0 },
|
919
|
-
topics: { added: 2, errors: 0, skips: 0 },
|
920
|
-
messages: { added: 4, errors: 0, skips: 0 },
|
921
|
-
});
|
169
|
+
expect(result.success).toBe(true);
|
170
|
+
expect(result.results).toEqual({
|
171
|
+
agents: { added: 1, errors: 0, skips: 0, updated: 0 },
|
172
|
+
agentsToSessions: { added: 1, errors: 0, skips: 0, updated: 0 },
|
173
|
+
messagePlugins: { added: 1, errors: 0, skips: 0, updated: 0 },
|
174
|
+
messages: { added: 6, errors: 0, skips: 0, updated: 0 },
|
175
|
+
sessions: { added: 1, errors: 0, skips: 0, updated: 0 },
|
176
|
+
topics: { added: 1, errors: 0, skips: 0, updated: 0 },
|
922
177
|
});
|
923
|
-
|
924
|
-
|
925
|
-
const result = await importer.importData({
|
926
|
-
...(mockImportData.state as any),
|
927
|
-
version: mockImportData.version,
|
928
|
-
});
|
929
|
-
|
930
|
-
expect(result).toEqual({
|
931
|
-
sessionGroups: { added: 2, errors: 0, skips: 0 },
|
932
|
-
sessions: { added: 15, errors: 0, skips: 0 },
|
933
|
-
topics: { added: 4, errors: 0, skips: 0 },
|
934
|
-
messages: { added: 32, errors: 0, skips: 0 },
|
935
|
-
});
|
936
|
-
});
|
937
|
-
},
|
938
|
-
{ timeout: 15000 },
|
939
|
-
);
|
178
|
+
});
|
179
|
+
});
|
940
180
|
});
|