@lobehub/chat 1.76.0 → 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.
Files changed (135) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/Dockerfile +3 -2
  3. package/Dockerfile.database +3 -1
  4. package/Dockerfile.pglite +3 -1
  5. package/changelog/v1.json +18 -0
  6. package/locales/ar/common.json +12 -1
  7. package/locales/ar/error.json +10 -0
  8. package/locales/ar/models.json +12 -6
  9. package/locales/ar/setting.json +28 -0
  10. package/locales/bg-BG/common.json +12 -1
  11. package/locales/bg-BG/error.json +10 -0
  12. package/locales/bg-BG/models.json +12 -6
  13. package/locales/bg-BG/setting.json +28 -0
  14. package/locales/de-DE/common.json +12 -1
  15. package/locales/de-DE/error.json +10 -0
  16. package/locales/de-DE/models.json +12 -6
  17. package/locales/de-DE/setting.json +28 -0
  18. package/locales/en-US/common.json +12 -1
  19. package/locales/en-US/error.json +10 -0
  20. package/locales/en-US/models.json +12 -6
  21. package/locales/en-US/setting.json +28 -0
  22. package/locales/es-ES/common.json +12 -1
  23. package/locales/es-ES/error.json +10 -0
  24. package/locales/es-ES/models.json +12 -6
  25. package/locales/es-ES/setting.json +28 -0
  26. package/locales/fa-IR/common.json +12 -1
  27. package/locales/fa-IR/error.json +10 -0
  28. package/locales/fa-IR/models.json +12 -6
  29. package/locales/fa-IR/setting.json +28 -0
  30. package/locales/fr-FR/common.json +12 -1
  31. package/locales/fr-FR/error.json +10 -0
  32. package/locales/fr-FR/models.json +12 -6
  33. package/locales/fr-FR/setting.json +28 -0
  34. package/locales/it-IT/common.json +12 -1
  35. package/locales/it-IT/error.json +10 -0
  36. package/locales/it-IT/models.json +12 -6
  37. package/locales/it-IT/setting.json +28 -0
  38. package/locales/ja-JP/common.json +12 -1
  39. package/locales/ja-JP/error.json +10 -0
  40. package/locales/ja-JP/models.json +12 -6
  41. package/locales/ja-JP/setting.json +28 -0
  42. package/locales/ko-KR/common.json +12 -1
  43. package/locales/ko-KR/error.json +10 -0
  44. package/locales/ko-KR/models.json +12 -6
  45. package/locales/ko-KR/setting.json +28 -0
  46. package/locales/nl-NL/common.json +12 -1
  47. package/locales/nl-NL/error.json +10 -0
  48. package/locales/nl-NL/models.json +12 -6
  49. package/locales/nl-NL/setting.json +28 -0
  50. package/locales/pl-PL/common.json +12 -1
  51. package/locales/pl-PL/error.json +10 -0
  52. package/locales/pl-PL/models.json +12 -6
  53. package/locales/pl-PL/setting.json +28 -0
  54. package/locales/pt-BR/common.json +12 -1
  55. package/locales/pt-BR/error.json +10 -0
  56. package/locales/pt-BR/models.json +12 -6
  57. package/locales/pt-BR/setting.json +28 -0
  58. package/locales/ru-RU/common.json +12 -1
  59. package/locales/ru-RU/error.json +10 -0
  60. package/locales/ru-RU/models.json +12 -6
  61. package/locales/ru-RU/setting.json +28 -0
  62. package/locales/tr-TR/common.json +12 -1
  63. package/locales/tr-TR/error.json +10 -0
  64. package/locales/tr-TR/models.json +12 -6
  65. package/locales/tr-TR/setting.json +28 -0
  66. package/locales/vi-VN/common.json +12 -1
  67. package/locales/vi-VN/error.json +10 -0
  68. package/locales/vi-VN/models.json +12 -6
  69. package/locales/vi-VN/setting.json +28 -0
  70. package/locales/zh-CN/common.json +12 -1
  71. package/locales/zh-CN/error.json +10 -0
  72. package/locales/zh-CN/models.json +12 -6
  73. package/locales/zh-CN/setting.json +28 -0
  74. package/locales/zh-TW/common.json +12 -1
  75. package/locales/zh-TW/error.json +10 -0
  76. package/locales/zh-TW/models.json +12 -6
  77. package/locales/zh-TW/setting.json +28 -0
  78. package/package.json +1 -1
  79. package/src/app/[variants]/(main)/(mobile)/me/data/features/Category.tsx +1 -1
  80. package/src/app/[variants]/(main)/chat/features/Migration/UpgradeButton.tsx +2 -1
  81. package/src/app/[variants]/(main)/settings/common/features/Common.tsx +0 -44
  82. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +40 -14
  83. package/src/app/[variants]/(main)/settings/storage/Advanced.tsx +133 -0
  84. package/src/app/[variants]/(main)/settings/storage/IndexedDBStorage.tsx +55 -0
  85. package/src/app/[variants]/(main)/settings/storage/page.tsx +17 -0
  86. package/src/app/[variants]/(main)/settings/tts/features/const.tsx +4 -0
  87. package/src/components/GroupIcon/index.tsx +25 -0
  88. package/src/components/IndexCard/index.tsx +143 -0
  89. package/src/components/ProgressItem/index.tsx +75 -0
  90. package/src/config/aiModels/openai.ts +10 -0
  91. package/src/database/repositories/dataExporter/index.test.ts +330 -0
  92. package/src/database/repositories/dataExporter/index.ts +216 -0
  93. package/src/database/repositories/dataImporter/__tests__/fixtures/agents.json +65 -0
  94. package/src/database/repositories/dataImporter/__tests__/fixtures/agentsToSessions.json +541 -0
  95. package/src/database/repositories/dataImporter/__tests__/fixtures/topic.json +269 -0
  96. package/src/database/repositories/dataImporter/__tests__/fixtures/userSettings.json +18 -0
  97. package/src/database/repositories/dataImporter/__tests__/fixtures/with-client-id.json +778 -0
  98. package/src/database/repositories/dataImporter/__tests__/index.test.ts +120 -880
  99. package/src/database/repositories/dataImporter/deprecated/__tests__/index.test.ts +940 -0
  100. package/src/database/repositories/dataImporter/deprecated/index.ts +326 -0
  101. package/src/database/repositories/dataImporter/index.ts +684 -289
  102. package/src/features/DataImporter/ImportDetail.tsx +203 -0
  103. package/src/features/DataImporter/SuccessResult.tsx +22 -6
  104. package/src/features/DataImporter/_deprecated.ts +43 -0
  105. package/src/features/DataImporter/config.ts +21 -0
  106. package/src/features/DataImporter/index.tsx +112 -31
  107. package/src/features/DevPanel/PostgresViewer/DataTable/index.tsx +6 -0
  108. package/src/features/User/UserPanel/useMenu.tsx +0 -35
  109. package/src/features/User/__tests__/useMenu.test.tsx +0 -2
  110. package/src/locales/default/common.ts +11 -0
  111. package/src/locales/default/error.ts +10 -0
  112. package/src/locales/default/setting.ts +28 -0
  113. package/src/server/routers/lambda/exporter.ts +25 -0
  114. package/src/server/routers/lambda/importer.ts +19 -3
  115. package/src/server/routers/lambda/index.ts +2 -0
  116. package/src/services/config.ts +80 -135
  117. package/src/services/export/_deprecated.ts +155 -0
  118. package/src/services/export/client.ts +15 -0
  119. package/src/services/export/index.ts +6 -0
  120. package/src/services/export/server.ts +9 -0
  121. package/src/services/export/type.ts +5 -0
  122. package/src/services/import/_deprecated.ts +42 -1
  123. package/src/services/import/client.test.ts +1 -1
  124. package/src/services/import/client.ts +30 -1
  125. package/src/services/import/server.ts +70 -2
  126. package/src/services/import/type.ts +10 -0
  127. package/src/store/global/initialState.ts +1 -0
  128. package/src/types/export.ts +11 -0
  129. package/src/types/exportConfig.ts +2 -0
  130. package/src/types/importer.ts +15 -0
  131. package/src/types/user/settings/tts.ts +1 -1
  132. package/src/utils/client/exportFile.ts +21 -0
  133. package/vitest.config.ts +1 -1
  134. package/src/utils/config.ts +0 -109
  135. /package/src/database/repositories/dataImporter/{__tests__ → deprecated/__tests__}/fixtures/messages.json +0 -0
@@ -23,7 +23,36 @@ export class ClientService extends BaseClientService implements IImportService {
23
23
  const duration = Date.now() - time;
24
24
 
25
25
  callbacks?.onStageChange?.(ImportStage.Success);
26
- callbacks?.onSuccess?.(result, duration);
26
+ callbacks?.onSuccess?.(result.results, duration);
27
+ } catch (e) {
28
+ console.error(e);
29
+ callbacks?.onStageChange?.(ImportStage.Error);
30
+ const error = e as Error;
31
+
32
+ callbacks?.onError?.({ code: 'ImportError', httpStatus: 0, message: error.message });
33
+ }
34
+ };
35
+
36
+ importPgData: IImportService['importPgData'] = async (
37
+ data,
38
+ { callbacks, overwriteExisting } = {},
39
+ ) => {
40
+ callbacks?.onStageChange?.(ImportStage.Importing);
41
+ const time = Date.now();
42
+ try {
43
+ const result = await this.dataImporter.importPgData(
44
+ data,
45
+ overwriteExisting ? 'override' : 'skip',
46
+ );
47
+
48
+ const duration = Date.now() - time;
49
+
50
+ callbacks?.onStageChange?.(ImportStage.Success);
51
+ if (result.success) {
52
+ callbacks?.onSuccess?.(result.results, duration);
53
+ } else {
54
+ callbacks?.onError?.({ code: 'ImportError', httpStatus: 0, message: result.error.message });
55
+ }
27
56
  } catch (e) {
28
57
  console.error(e);
29
58
  callbacks?.onStageChange?.(ImportStage.Error);
@@ -2,6 +2,7 @@ import { DefaultErrorShape } from '@trpc/server/unstable-core-do-not-import';
2
2
 
3
3
  import { edgeClient, lambdaClient } from '@/libs/trpc/client';
4
4
  import { useUserStore } from '@/store/user';
5
+ import { ImportPgDataStructure } from '@/types/export';
5
6
  import { ImportStage, OnImportCallbacks } from '@/types/importer';
6
7
  import { uuid } from '@/utils/uuid';
7
8
 
@@ -39,7 +40,7 @@ export class ServerService implements IImportService {
39
40
  const duration = Date.now() - time;
40
41
 
41
42
  callbacks?.onStageChange?.(ImportStage.Success);
42
- callbacks?.onSuccess?.(result, duration);
43
+ callbacks?.onSuccess?.(result.results, duration);
43
44
  } catch (e) {
44
45
  handleError(e);
45
46
  }
@@ -67,7 +68,74 @@ export class ServerService implements IImportService {
67
68
  const result = await lambdaClient.importer.importByFile.mutate({ pathname });
68
69
  const duration = Date.now() - time;
69
70
  callbacks?.onStageChange?.(ImportStage.Success);
70
- callbacks?.onSuccess?.(result, duration);
71
+ callbacks?.onSuccess?.(result.results, duration);
72
+ } catch (e) {
73
+ handleError(e);
74
+ }
75
+ };
76
+
77
+ importPgData: IImportService['importPgData'] = async (
78
+ data: ImportPgDataStructure,
79
+ {
80
+ callbacks,
81
+ }: {
82
+ callbacks?: OnImportCallbacks;
83
+ overwriteExisting?: boolean;
84
+ } = {},
85
+ ): Promise<void> => {
86
+ const handleError = (e: unknown) => {
87
+ callbacks?.onStageChange?.(ImportStage.Error);
88
+ const error = e as DefaultErrorShape;
89
+
90
+ callbacks?.onError?.({
91
+ code: error.data.code,
92
+ httpStatus: error.data.httpStatus,
93
+ message: error.message,
94
+ path: error.data.path,
95
+ });
96
+ };
97
+
98
+ const totalLength = Object.values(data.data)
99
+ .map((d) => d.length)
100
+ .reduce((a, b) => a + b, 0);
101
+
102
+ if (totalLength < 500) {
103
+ callbacks?.onStageChange?.(ImportStage.Importing);
104
+ const time = Date.now();
105
+ try {
106
+ const result = await lambdaClient.importer.importPgByPost.mutate(data);
107
+ const duration = Date.now() - time;
108
+
109
+ callbacks?.onStageChange?.(ImportStage.Success);
110
+ callbacks?.onSuccess?.(result.results, duration);
111
+ } catch (e) {
112
+ handleError(e);
113
+ }
114
+
115
+ return;
116
+ }
117
+
118
+ // if the data is too large, upload it to S3 and upload by file
119
+ const filename = `${uuid()}.json`;
120
+
121
+ const pathname = `import_config/${filename}`;
122
+
123
+ const url = await edgeClient.upload.createS3PreSignedUrl.mutate({ pathname });
124
+
125
+ try {
126
+ callbacks?.onStageChange?.(ImportStage.Uploading);
127
+ await this.uploadWithProgress(url, data, callbacks?.onFileUploading);
128
+ } catch {
129
+ throw new Error('Upload Error');
130
+ }
131
+
132
+ callbacks?.onStageChange?.(ImportStage.Importing);
133
+ const time = Date.now();
134
+ try {
135
+ const result = await lambdaClient.importer.importByFile.mutate({ pathname });
136
+ const duration = Date.now() - time;
137
+ callbacks?.onStageChange?.(ImportStage.Success);
138
+ callbacks?.onSuccess?.(result.results, duration);
71
139
  } catch (e) {
72
140
  handleError(e);
73
141
  }
@@ -1,7 +1,17 @@
1
+ import { ImportPgDataStructure } from '@/types/export';
1
2
  import { ImporterEntryData, OnImportCallbacks } from '@/types/importer';
2
3
  import { UserSettings } from '@/types/user/settings';
3
4
 
4
5
  export interface IImportService {
5
6
  importData(data: ImporterEntryData, callbacks?: OnImportCallbacks): Promise<void>;
7
+
8
+ importPgData(
9
+ data: ImportPgDataStructure,
10
+ options?: {
11
+ callbacks?: OnImportCallbacks;
12
+ overwriteExisting?: boolean;
13
+ },
14
+ ): Promise<void>;
15
+
6
16
  importSettings(settings: UserSettings): Promise<void>;
7
17
  }
@@ -30,6 +30,7 @@ export enum SettingsTabs {
30
30
  Hotkey = 'hotkey',
31
31
  LLM = 'llm',
32
32
  Provider = 'provider',
33
+ Storage = 'storage',
33
34
  Sync = 'sync',
34
35
  SystemAgent = 'system-agent',
35
36
  TTS = 'tts',
@@ -0,0 +1,11 @@
1
+ export interface ExportDatabaseData {
2
+ data: Record<string, object[]>;
3
+ schemaHash?: string;
4
+ url?: string;
5
+ }
6
+
7
+ export interface ImportPgDataStructure {
8
+ data: Record<string, object[]>;
9
+ mode: 'pglite' | 'postgres';
10
+ schemaHash: string;
11
+ }
@@ -3,6 +3,8 @@ import { LobeSessions, SessionGroupItem } from '@/types/session';
3
3
  import { ChatTopic } from '@/types/topic';
4
4
  import { UserSettings } from '@/types/user/settings';
5
5
 
6
+ // ---------- TODO: this file need to be deleted in V2 ---------- //
7
+
6
8
  /**
7
9
  * 导出方式
8
10
  * @enum ['agents', 'sessions', 'singleSession', 'settings', 'all']
@@ -146,3 +146,18 @@ export interface OnImportCallbacks {
146
146
  */
147
147
  onSuccess?: (results: ImportResults, duration: number) => void;
148
148
  }
149
+
150
+ // ------
151
+
152
+ export type ImportResultData = ImportSuccessResult | ImportErrorResult;
153
+
154
+ export interface ImportSuccessResult {
155
+ results: Record<string, any>;
156
+ success: true;
157
+ }
158
+
159
+ export interface ImportErrorResult {
160
+ error: { details?: string; message: string };
161
+ results: Record<string, any>;
162
+ success: false;
163
+ }
@@ -3,7 +3,7 @@ export type STTServer = 'openai' | 'browser';
3
3
  export interface UserTTSConfig {
4
4
  openAI: {
5
5
  sttModel: 'whisper-1';
6
- ttsModel: 'tts-1' | 'tts-1-hd';
6
+ ttsModel: 'gpt-4o-mini-tts' | 'tts-1' | 'tts-1-hd';
7
7
  };
8
8
  sttAutoStop: boolean;
9
9
  sttServer: STTServer;
@@ -18,3 +18,24 @@ export const exportFile = (content: string, filename?: string) => {
18
18
  URL.revokeObjectURL(url);
19
19
  a.remove();
20
20
  };
21
+
22
+ export const exportJSONFile = (data: object, fileName: string) => {
23
+ // 创建一个 Blob 对象
24
+ const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
25
+
26
+ // 创建一个 URL 对象,用于下载
27
+ const url = URL.createObjectURL(blob);
28
+
29
+ // 创建一个 <a> 元素,设置下载链接和文件名
30
+ const a = document.createElement('a');
31
+ a.href = url;
32
+ a.download = fileName;
33
+
34
+ // 触发 <a> 元素的点击事件,开始下载
35
+ document.body.append(a);
36
+ a.click();
37
+
38
+ // 下载完成后,清除 URL 对象
39
+ URL.revokeObjectURL(url);
40
+ a.remove();
41
+ };
package/vitest.config.ts CHANGED
@@ -31,7 +31,7 @@ export default defineConfig({
31
31
  '**/dist/**',
32
32
  '**/build/**',
33
33
  'src/database/server/**/**',
34
- 'src/database/repositories/dataImporter/**/**',
34
+ 'src/database/repositories/dataImporter/deprecated/**/**',
35
35
  ],
36
36
  globals: true,
37
37
  server: {
@@ -1,109 +0,0 @@
1
- import { notification } from '@/components/AntdStaticMethods';
2
- import { BRANDING_NAME } from '@/const/branding';
3
- import { CURRENT_CONFIG_VERSION, Migration } from '@/migrations';
4
- import {
5
- ConfigFile,
6
- ConfigFileAgents,
7
- ConfigFileAll,
8
- ConfigFileSessions,
9
- ConfigFileSettings,
10
- ConfigFileSingleSession,
11
- ConfigModelMap,
12
- ExportType,
13
- } from '@/types/exportConfig';
14
-
15
- export const exportConfigFile = (config: object, fileName?: string) => {
16
- const file = `${BRANDING_NAME}-${fileName || '-config'}-v${CURRENT_CONFIG_VERSION}.json`;
17
-
18
- // 创建一个 Blob 对象
19
- const blob = new Blob([JSON.stringify(config)], { type: 'application/json' });
20
-
21
- // 创建一个 URL 对象,用于下载
22
- const url = URL.createObjectURL(blob);
23
-
24
- // 创建一个 <a> 元素,设置下载链接和文件名
25
- const a = document.createElement('a');
26
- a.href = url;
27
- a.download = file;
28
-
29
- // 触发 <a> 元素的点击事件,开始下载
30
- document.body.append(a);
31
- a.click();
32
-
33
- // 下载完成后,清除 URL 对象
34
- URL.revokeObjectURL(url);
35
- a.remove();
36
- };
37
-
38
- export const importConfigFile = async (
39
- file: File,
40
- onConfigImport: (config: ConfigFile) => Promise<void>,
41
- ) => {
42
- const text = await file.text();
43
-
44
- try {
45
- const config = JSON.parse(text);
46
- const { state, version } = Migration.migrate(config);
47
-
48
- await onConfigImport({ ...config, state, version });
49
- } catch (error) {
50
- console.error(error);
51
- notification.error({
52
- description: `出错原因: ${(error as Error).message}`,
53
- message: '导入失败',
54
- });
55
- }
56
- };
57
-
58
- type CreateConfigFileState<T extends ExportType> = ConfigModelMap[T]['state'];
59
-
60
- type CreateConfigFile<T extends ExportType> = ConfigModelMap[T]['file'];
61
-
62
- export const createConfigFile = <T extends ExportType>(
63
- type: T,
64
- state: CreateConfigFileState<T>,
65
- ): CreateConfigFile<T> => {
66
- switch (type) {
67
- case 'agents': {
68
- return {
69
- exportType: 'agents',
70
- state,
71
- version: Migration.targetVersion,
72
- } as ConfigFileAgents;
73
- }
74
-
75
- case 'sessions': {
76
- return {
77
- exportType: 'sessions',
78
- state,
79
- version: Migration.targetVersion,
80
- } as ConfigFileSessions;
81
- }
82
-
83
- case 'settings': {
84
- return {
85
- exportType: 'settings',
86
- state,
87
- version: Migration.targetVersion,
88
- } as ConfigFileSettings;
89
- }
90
-
91
- case 'singleSession': {
92
- return {
93
- exportType: 'sessions',
94
- state,
95
- version: Migration.targetVersion,
96
- } as ConfigFileSingleSession;
97
- }
98
-
99
- case 'all': {
100
- return {
101
- exportType: 'all',
102
- state,
103
- version: Migration.targetVersion,
104
- } as ConfigFileAll;
105
- }
106
- }
107
-
108
- throw new Error('缺少正确的导出类型,请检查实现...');
109
- };