@lobehub/chat 1.74.2 → 1.74.3

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 (85) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/changelog/v1.json +9 -0
  3. package/docs/developer/database-schema.dbml +54 -2
  4. package/locales/ar/common.json +51 -0
  5. package/locales/ar/models.json +69 -3
  6. package/locales/ar/providers.json +6 -0
  7. package/locales/bg-BG/common.json +51 -0
  8. package/locales/bg-BG/models.json +69 -3
  9. package/locales/bg-BG/providers.json +6 -0
  10. package/locales/de-DE/common.json +51 -0
  11. package/locales/de-DE/models.json +69 -3
  12. package/locales/de-DE/providers.json +6 -0
  13. package/locales/en-US/common.json +51 -0
  14. package/locales/en-US/models.json +69 -3
  15. package/locales/en-US/providers.json +6 -3
  16. package/locales/es-ES/common.json +51 -0
  17. package/locales/es-ES/models.json +69 -3
  18. package/locales/es-ES/providers.json +6 -0
  19. package/locales/fa-IR/common.json +51 -0
  20. package/locales/fa-IR/models.json +69 -3
  21. package/locales/fa-IR/providers.json +6 -0
  22. package/locales/fr-FR/common.json +51 -0
  23. package/locales/fr-FR/models.json +69 -3
  24. package/locales/fr-FR/providers.json +6 -0
  25. package/locales/it-IT/common.json +51 -0
  26. package/locales/it-IT/models.json +69 -3
  27. package/locales/it-IT/providers.json +6 -0
  28. package/locales/ja-JP/common.json +51 -0
  29. package/locales/ja-JP/models.json +78 -4
  30. package/locales/ja-JP/providers.json +6 -0
  31. package/locales/ko-KR/common.json +51 -0
  32. package/locales/ko-KR/models.json +69 -3
  33. package/locales/ko-KR/providers.json +6 -0
  34. package/locales/nl-NL/common.json +51 -0
  35. package/locales/nl-NL/models.json +69 -3
  36. package/locales/nl-NL/providers.json +6 -0
  37. package/locales/pl-PL/common.json +51 -0
  38. package/locales/pl-PL/models.json +69 -3
  39. package/locales/pl-PL/providers.json +6 -0
  40. package/locales/pt-BR/common.json +51 -0
  41. package/locales/pt-BR/models.json +69 -3
  42. package/locales/pt-BR/providers.json +6 -0
  43. package/locales/ru-RU/common.json +51 -0
  44. package/locales/ru-RU/models.json +69 -3
  45. package/locales/ru-RU/providers.json +6 -0
  46. package/locales/tr-TR/common.json +51 -0
  47. package/locales/tr-TR/models.json +69 -3
  48. package/locales/tr-TR/providers.json +6 -0
  49. package/locales/vi-VN/common.json +51 -0
  50. package/locales/vi-VN/models.json +69 -3
  51. package/locales/vi-VN/providers.json +6 -0
  52. package/locales/zh-CN/common.json +53 -2
  53. package/locales/zh-CN/models.json +79 -13
  54. package/locales/zh-CN/providers.json +6 -4
  55. package/locales/zh-TW/common.json +51 -0
  56. package/locales/zh-TW/models.json +81 -4
  57. package/locales/zh-TW/providers.json +6 -0
  58. package/package.json +1 -1
  59. package/packages/web-crawler/src/utils/__tests__/withTimeout.test.ts +0 -1
  60. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/Checker.tsx +4 -0
  61. package/src/database/client/db.ts +102 -11
  62. package/src/database/client/migrations.json +38 -8
  63. package/src/database/migrations/0018_add_client_id_for_entities.sql +32 -0
  64. package/src/database/migrations/meta/0018_snapshot.json +4212 -0
  65. package/src/database/migrations/meta/_journal.json +7 -0
  66. package/src/database/models/drizzleMigration.ts +23 -0
  67. package/src/database/schemas/agent.ts +48 -31
  68. package/src/database/schemas/file.ts +32 -16
  69. package/src/database/schemas/message.ts +91 -54
  70. package/src/database/schemas/rag.ts +65 -32
  71. package/src/database/schemas/session.ts +6 -3
  72. package/src/database/schemas/topic.ts +31 -24
  73. package/src/features/InitClientDB/ErrorResult.tsx +53 -32
  74. package/src/features/InitClientDB/features/DatabaseRepair/Backup.tsx +77 -0
  75. package/src/features/InitClientDB/features/DatabaseRepair/Diagnosis.tsx +98 -0
  76. package/src/features/InitClientDB/features/DatabaseRepair/Repair.tsx +220 -0
  77. package/src/features/InitClientDB/features/DatabaseRepair/index.tsx +85 -0
  78. package/src/features/ModelSwitchPanel/index.tsx +13 -7
  79. package/src/locales/default/common.ts +53 -1
  80. package/src/store/global/actions/clientDb.ts +19 -3
  81. package/src/store/global/initialState.ts +6 -1
  82. package/src/store/global/selectors/clientDB.ts +43 -0
  83. package/src/store/global/selectors/index.ts +1 -0
  84. package/src/store/user/slices/settings/selectors/general.test.ts +90 -0
  85. package/src/types/clientDB.ts +13 -0
@@ -41,9 +41,12 @@ export default {
41
41
  title: '初始化 PGlite 数据库',
42
42
  },
43
43
  error: {
44
- desc: '非常抱歉,Pglite 数据库初始化过程发生异常。请点击按钮重试。如多次重试后仍重复出错,请 <1>提交问题</1> ,我们将会第一时间帮你排查',
44
+ desc: '非常抱歉,Pglite 数据库初始化过程发生异常,请点击右侧按钮重试。如果你具有 SQL 运维经验,可以尝试点击下方自助解决按钮自行解决。如多次重试后仍重复出错,请点击左下方反馈问题,我们将会第一时间帮你排查',
45
45
  detail: '错误原因:[{{type}}] {{message}},明细如下:',
46
+ detailTitle: '错误原因',
47
+ report: '反馈问题',
46
48
  retry: '重试',
49
+ selfSolve: '自助解决',
47
50
  title: '数据库初始化失败',
48
51
  },
49
52
  initing: {
@@ -83,6 +86,55 @@ export default {
83
86
  desc: '立即想用',
84
87
  title: 'PGlite 数据库已就绪',
85
88
  },
89
+
90
+ solve: {
91
+ backup: {
92
+ backup: '备份',
93
+ backupSuccess: '备份成功',
94
+ desc: '导出当前数据库中的关键数据',
95
+ export: '导出全部数据',
96
+ exportDesc: '导出的数据将以JSON格式保存,可用于后续恢复或分析。',
97
+ reset: {
98
+ alert: '警告',
99
+ alertDesc: '以下操作可能会导致数据丢失。请确保您已备份重要数据后再继续。',
100
+ button: '完全重置数据库(删除所有数据)',
101
+ confirm: {
102
+ desc: '此操作将会删除所有数据并且不可撤销,确认继续吗?',
103
+ title: '确认重置数据库',
104
+ },
105
+ desc: '在迁移无法恢复的情况下重置数据库',
106
+ title: '数据库重置',
107
+ },
108
+ restore: '恢复',
109
+ restoreSuccess: '恢复成功',
110
+ title: '数据备份',
111
+ },
112
+ diagnosis: {
113
+ createdAt: '创建时间',
114
+ migratedAt: '迁移完成时间',
115
+ sql: '迁移SQL',
116
+ title: '迁移状态',
117
+ },
118
+ repair: {
119
+ desc: '手动管理迁移状态',
120
+ runSQL: '自定义执行',
121
+ sql: {
122
+ clear: '清空',
123
+ desc: '执行自定义SQL语句修复数据库问题',
124
+ markFinished: '标记为已完成',
125
+ placeholder: '输入SQL语句...',
126
+ result: '执行结果',
127
+ run: '执行',
128
+ title: 'SQL执行器',
129
+ },
130
+ title: '迁移控制',
131
+ },
132
+ tabs: {
133
+ backup: '备份恢复',
134
+ diagnosis: '诊断',
135
+ repair: '修复',
136
+ },
137
+ },
86
138
  },
87
139
  close: '关闭',
88
140
  contact: '联系我们',
@@ -31,8 +31,14 @@ export const clientDBSlice: StateCreator<
31
31
 
32
32
  const { initializeDB } = await import('@/database/client/db');
33
33
  await initializeDB({
34
- onError: (error) => {
35
- set({ initClientDBError: error });
34
+ onError: ({ error, migrationsSQL, migrationTableItems }) => {
35
+ set({
36
+ initClientDBError: error,
37
+ initClientDBMigrations: {
38
+ sqls: migrationsSQL,
39
+ tableRecords: migrationTableItems,
40
+ },
41
+ });
36
42
  },
37
43
  onProgress: (data) => {
38
44
  set({ initClientDBProcess: data });
@@ -43,8 +49,18 @@ export const clientDBSlice: StateCreator<
43
49
  },
44
50
  });
45
51
  },
46
- markPgliteEnabled: () => {
52
+ markPgliteEnabled: async () => {
47
53
  get().updateSystemStatus({ isEnablePglite: true });
54
+
55
+ if (navigator.storage && !!navigator.storage.persist) {
56
+ // 1. Check if persistent permission has been obtained
57
+ const isPersisted = await navigator.storage.persisted();
58
+
59
+ // 2. If the persistent permission has not been obtained, request permission
60
+ if (!isPersisted) {
61
+ await navigator.storage.persist();
62
+ }
63
+ }
48
64
  },
49
65
  useInitClientDB: (params) =>
50
66
  useOnlyFetchOnceSWR('initClientDB', () => get().initializeClientDB(params)),
@@ -1,7 +1,7 @@
1
1
  import type { ThemeMode } from 'antd-style';
2
2
  import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
3
3
 
4
- import { DatabaseLoadingState } from '@/types/clientDB';
4
+ import { DatabaseLoadingState, MigrationSQL, MigrationTableItem } from '@/types/clientDB';
5
5
  import { LocaleMode } from '@/types/locale';
6
6
  import { SessionDefaultGroup } from '@/types/session';
7
7
  import { AsyncLocalStorage } from '@/utils/localStorage';
@@ -73,6 +73,11 @@ export interface SystemStatus {
73
73
  export interface GlobalState {
74
74
  hasNewVersion?: boolean;
75
75
  initClientDBError?: Error;
76
+ initClientDBMigrations?: {
77
+ sqls: MigrationSQL[];
78
+ tableRecords: MigrationTableItem[];
79
+ };
80
+
76
81
  initClientDBProcess?: { costTime?: number; phase: 'wasm' | 'dependencies'; progress: number };
77
82
  /**
78
83
  * 客户端数据库初始化状态
@@ -0,0 +1,43 @@
1
+ import { GlobalState } from '@/store/global/initialState';
2
+
3
+ const initClientDBMigrationSqls = (s: GlobalState) => {
4
+ return s.initClientDBMigrations?.sqls || [];
5
+ };
6
+
7
+ const displayMigrationStatus = (s: GlobalState) => {
8
+ const sql = s.initClientDBMigrations?.sqls || [];
9
+ const tableRecords = s.initClientDBMigrations?.tableRecords || [];
10
+
11
+ return (
12
+ sql
13
+
14
+ .map((item, index) => {
15
+ const recordInTable = tableRecords.find((record) => record.hash === item.hash);
16
+ return {
17
+ createdAt: new Date(item.folderMillis),
18
+ desc: item.sql[0],
19
+ folderMillis: item.folderMillis,
20
+ id: item.hash,
21
+ index: index + 1,
22
+ migratedAt: recordInTable ? new Date(recordInTable.created_at) : undefined,
23
+ sql: item.sql,
24
+ status: !!recordInTable ? 'success' : 'error',
25
+ };
26
+ })
27
+ // 时间倒序
28
+ .sort((a, b) => b.folderMillis - a.folderMillis)
29
+ );
30
+ };
31
+
32
+ const errorMigrations = (s: GlobalState) => {
33
+ const sql = s.initClientDBMigrations?.sqls || [];
34
+ const tableRecords = s.initClientDBMigrations?.tableRecords || [];
35
+
36
+ return sql.filter((item) => !tableRecords.some((record) => record.hash === item.hash));
37
+ };
38
+
39
+ export const clientDBSelectors = {
40
+ displayMigrationStatus,
41
+ errorMigrations,
42
+ initClientDBMigrationSqls,
43
+ };
@@ -1,2 +1,3 @@
1
+ export * from './clientDB';
1
2
  export * from './general';
2
3
  export * from './systemStatus';
@@ -5,6 +5,20 @@ import { merge } from '@/utils/merge';
5
5
  import { userGeneralSettingsSelectors } from './general';
6
6
 
7
7
  describe('settingsSelectors', () => {
8
+ describe('generalConfig', () => {
9
+ it('should return general settings', () => {
10
+ const s: UserState = merge(initialState, {
11
+ settings: {
12
+ general: { fontSize: 12 },
13
+ },
14
+ });
15
+
16
+ const result = userGeneralSettingsSelectors.config(s as UserStore);
17
+
18
+ expect(result).toEqual({ fontSize: 12 });
19
+ });
20
+ });
21
+
8
22
  describe('fontSize', () => {
9
23
  it('should return the fontSize', () => {
10
24
  const s: UserState = merge(initialState, {
@@ -18,4 +32,80 @@ describe('settingsSelectors', () => {
18
32
  expect(result).toBe(12);
19
33
  });
20
34
  });
35
+
36
+ describe('neutralColor', () => {
37
+ it('should return undefined if general settings not exists', () => {
38
+ const s: UserState = merge(initialState, {
39
+ settings: {
40
+ general: undefined,
41
+ },
42
+ });
43
+
44
+ const result = userGeneralSettingsSelectors.neutralColor(s as UserStore);
45
+
46
+ expect(result).toBeUndefined();
47
+ });
48
+
49
+ it('should return undefined if neutralColor not set', () => {
50
+ const s: UserState = merge(initialState, {
51
+ settings: {
52
+ general: {},
53
+ },
54
+ });
55
+
56
+ const result = userGeneralSettingsSelectors.neutralColor(s as UserStore);
57
+
58
+ expect(result).toBeUndefined();
59
+ });
60
+
61
+ it('should return the neutralColor', () => {
62
+ const s: UserState = merge(initialState, {
63
+ settings: {
64
+ general: { neutralColor: '#000000' },
65
+ },
66
+ });
67
+
68
+ const result = userGeneralSettingsSelectors.neutralColor(s as UserStore);
69
+
70
+ expect(result).toBe('#000000');
71
+ });
72
+ });
73
+
74
+ describe('primaryColor', () => {
75
+ it('should return undefined if general settings not exists', () => {
76
+ const s: UserState = merge(initialState, {
77
+ settings: {
78
+ general: undefined,
79
+ },
80
+ });
81
+
82
+ const result = userGeneralSettingsSelectors.primaryColor(s as UserStore);
83
+
84
+ expect(result).toBeUndefined();
85
+ });
86
+
87
+ it('should return undefined if primaryColor not set', () => {
88
+ const s: UserState = merge(initialState, {
89
+ settings: {
90
+ general: {},
91
+ },
92
+ });
93
+
94
+ const result = userGeneralSettingsSelectors.primaryColor(s as UserStore);
95
+
96
+ expect(result).toBeUndefined();
97
+ });
98
+
99
+ it('should return the primaryColor', () => {
100
+ const s: UserState = merge(initialState, {
101
+ settings: {
102
+ general: { primaryColor: '#ffffff' },
103
+ },
104
+ });
105
+
106
+ const result = userGeneralSettingsSelectors.primaryColor(s as UserStore);
107
+
108
+ expect(result).toBe('#ffffff');
109
+ });
110
+ });
21
111
  });
@@ -27,3 +27,16 @@ export interface ClientDBLoadingProgress {
27
27
  }
28
28
 
29
29
  export type OnStageChange = (state: DatabaseLoadingState) => void;
30
+
31
+ export interface MigrationSQL {
32
+ bps: boolean;
33
+ folderMillis: number;
34
+ hash: string;
35
+ sql: string[];
36
+ }
37
+
38
+ export interface MigrationTableItem {
39
+ created_at: number;
40
+ hash: string;
41
+ id: number;
42
+ }