@lobehub/chat 1.74.1 → 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 (91) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +2 -2
  3. package/README.zh-CN.md +2 -2
  4. package/changelog/v1.json +18 -0
  5. package/docs/developer/database-schema.dbml +54 -2
  6. package/docs/self-hosting/environment-variables/model-provider.mdx +9 -7
  7. package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +9 -7
  8. package/locales/ar/common.json +51 -0
  9. package/locales/ar/models.json +69 -3
  10. package/locales/ar/providers.json +6 -0
  11. package/locales/bg-BG/common.json +51 -0
  12. package/locales/bg-BG/models.json +69 -3
  13. package/locales/bg-BG/providers.json +6 -0
  14. package/locales/de-DE/common.json +51 -0
  15. package/locales/de-DE/models.json +69 -3
  16. package/locales/de-DE/providers.json +6 -0
  17. package/locales/en-US/common.json +51 -0
  18. package/locales/en-US/models.json +69 -3
  19. package/locales/en-US/providers.json +6 -3
  20. package/locales/es-ES/common.json +51 -0
  21. package/locales/es-ES/models.json +69 -3
  22. package/locales/es-ES/providers.json +6 -0
  23. package/locales/fa-IR/common.json +51 -0
  24. package/locales/fa-IR/models.json +69 -3
  25. package/locales/fa-IR/providers.json +6 -0
  26. package/locales/fr-FR/common.json +51 -0
  27. package/locales/fr-FR/models.json +69 -3
  28. package/locales/fr-FR/providers.json +6 -0
  29. package/locales/it-IT/common.json +51 -0
  30. package/locales/it-IT/models.json +69 -3
  31. package/locales/it-IT/providers.json +6 -0
  32. package/locales/ja-JP/common.json +51 -0
  33. package/locales/ja-JP/models.json +78 -4
  34. package/locales/ja-JP/providers.json +6 -0
  35. package/locales/ko-KR/common.json +51 -0
  36. package/locales/ko-KR/models.json +69 -3
  37. package/locales/ko-KR/providers.json +6 -0
  38. package/locales/nl-NL/common.json +51 -0
  39. package/locales/nl-NL/models.json +69 -3
  40. package/locales/nl-NL/providers.json +6 -0
  41. package/locales/pl-PL/common.json +51 -0
  42. package/locales/pl-PL/models.json +69 -3
  43. package/locales/pl-PL/providers.json +6 -0
  44. package/locales/pt-BR/common.json +51 -0
  45. package/locales/pt-BR/models.json +69 -3
  46. package/locales/pt-BR/providers.json +6 -0
  47. package/locales/ru-RU/common.json +51 -0
  48. package/locales/ru-RU/models.json +69 -3
  49. package/locales/ru-RU/providers.json +6 -0
  50. package/locales/tr-TR/common.json +51 -0
  51. package/locales/tr-TR/models.json +69 -3
  52. package/locales/tr-TR/providers.json +6 -0
  53. package/locales/vi-VN/common.json +51 -0
  54. package/locales/vi-VN/models.json +69 -3
  55. package/locales/vi-VN/providers.json +6 -0
  56. package/locales/zh-CN/common.json +53 -2
  57. package/locales/zh-CN/models.json +79 -13
  58. package/locales/zh-CN/providers.json +6 -4
  59. package/locales/zh-TW/common.json +51 -0
  60. package/locales/zh-TW/models.json +81 -4
  61. package/locales/zh-TW/providers.json +6 -0
  62. package/package.json +1 -1
  63. package/packages/web-crawler/src/utils/__tests__/withTimeout.test.ts +0 -1
  64. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/Checker.tsx +9 -1
  65. package/src/config/aiModels/qwen.ts +4 -4
  66. package/src/config/aiModels/volcengine.ts +2 -2
  67. package/src/database/client/db.ts +102 -11
  68. package/src/database/client/migrations.json +38 -8
  69. package/src/database/migrations/0018_add_client_id_for_entities.sql +32 -0
  70. package/src/database/migrations/meta/0018_snapshot.json +4212 -0
  71. package/src/database/migrations/meta/_journal.json +7 -0
  72. package/src/database/models/drizzleMigration.ts +23 -0
  73. package/src/database/schemas/agent.ts +48 -31
  74. package/src/database/schemas/file.ts +32 -16
  75. package/src/database/schemas/message.ts +91 -54
  76. package/src/database/schemas/rag.ts +65 -32
  77. package/src/database/schemas/session.ts +6 -3
  78. package/src/database/schemas/topic.ts +31 -24
  79. package/src/features/InitClientDB/ErrorResult.tsx +53 -32
  80. package/src/features/InitClientDB/features/DatabaseRepair/Backup.tsx +77 -0
  81. package/src/features/InitClientDB/features/DatabaseRepair/Diagnosis.tsx +98 -0
  82. package/src/features/InitClientDB/features/DatabaseRepair/Repair.tsx +220 -0
  83. package/src/features/InitClientDB/features/DatabaseRepair/index.tsx +85 -0
  84. package/src/features/ModelSwitchPanel/index.tsx +13 -7
  85. package/src/locales/default/common.ts +53 -1
  86. package/src/store/global/actions/clientDb.ts +19 -3
  87. package/src/store/global/initialState.ts +6 -1
  88. package/src/store/global/selectors/clientDB.ts +43 -0
  89. package/src/store/global/selectors/index.ts +1 -0
  90. package/src/store/user/slices/settings/selectors/general.test.ts +90 -0
  91. package/src/types/clientDB.ts +13 -0
@@ -1,7 +1,14 @@
1
+ import { sql } from 'drizzle-orm';
1
2
  import { PgliteDatabase, drizzle } from 'drizzle-orm/pglite';
2
3
  import { Md5 } from 'ts-md5';
3
4
 
4
- import { ClientDBLoadingProgress, DatabaseLoadingState } from '@/types/clientDB';
5
+ import { DrizzleMigrationModel } from '@/database/models/drizzleMigration';
6
+ import {
7
+ ClientDBLoadingProgress,
8
+ DatabaseLoadingState,
9
+ MigrationSQL,
10
+ MigrationTableItem,
11
+ } from '@/types/clientDB';
5
12
  import { sleep } from '@/utils/sleep';
6
13
 
7
14
  import * as schema from '../schemas';
@@ -9,10 +16,17 @@ import migrations from './migrations.json';
9
16
 
10
17
  const pgliteSchemaHashCache = 'LOBE_CHAT_PGLITE_SCHEMA_HASH';
11
18
 
19
+ const DB_NAME = 'lobechat';
12
20
  type DrizzleInstance = PgliteDatabase<typeof schema>;
13
21
 
22
+ interface onErrorState {
23
+ error: Error;
24
+ migrationTableItems: MigrationTableItem[];
25
+ migrationsSQL: MigrationSQL[];
26
+ }
27
+
14
28
  export interface DatabaseLoadingCallbacks {
15
- onError?: (error: Error) => void;
29
+ onError?: (error: onErrorState) => void;
16
30
  onProgress?: (progress: ClientDBLoadingProgress) => void;
17
31
  onStateChange?: (state: DatabaseLoadingState) => void;
18
32
  }
@@ -152,8 +166,28 @@ export class DatabaseManager {
152
166
  hash = Md5.hashStr(JSON.stringify(migrations));
153
167
  // if hash is the same, no need to migrate
154
168
  if (hash === cacheHash) {
155
- this.isLocalDBSchemaSynced = true;
156
- return this.db;
169
+ try {
170
+ // 检查数据库中是否存在表
171
+ // 这里使用 pg_tables 系统表查询用户表数量
172
+ const tablesResult = await this.db.execute(
173
+ sql`
174
+ SELECT COUNT(*) as table_count
175
+ FROM information_schema.tables
176
+ WHERE table_schema = 'public'
177
+ `,
178
+ );
179
+
180
+ const tableCount = parseInt((tablesResult.rows[0] as any).table_count || '0', 10);
181
+
182
+ // 如果表数量大于0,则认为数据库已正确初始化
183
+ if (tableCount > 0) {
184
+ this.isLocalDBSchemaSynced = true;
185
+ return this.db;
186
+ }
187
+ } catch (error) {
188
+ console.warn('Error checking table existence, proceeding with migration', error);
189
+ // 如果查询失败,继续执行迁移以确保安全
190
+ }
157
191
  }
158
192
  }
159
193
 
@@ -204,13 +238,11 @@ export class DatabaseManager {
204
238
 
205
239
  let db: typeof PGlite;
206
240
 
207
- const dbName = 'lobechat';
208
-
209
241
  // make db as web worker if worker is available
210
242
  // https://github.com/lobehub/lobe-chat/issues/5785
211
243
  if (typeof Worker !== 'undefined' && typeof navigator.locks !== 'undefined') {
212
244
  db = await initPgliteWorker({
213
- dbName,
245
+ dbName: DB_NAME,
214
246
  fsBundle: fsBundle as Blob,
215
247
  vectorBundlePath: DatabaseManager.VECTOR_CDN_URL,
216
248
  wasmModule,
@@ -219,7 +251,7 @@ export class DatabaseManager {
219
251
  // in edge runtime or test runtime, we don't have worker
220
252
  db = new PGlite({
221
253
  extensions: { vector },
222
- fs: typeof window === 'undefined' ? new MemoryFS(dbName) : new IdbFs(dbName),
254
+ fs: typeof window === 'undefined' ? new MemoryFS(DB_NAME) : new IdbFs(DB_NAME),
223
255
  relaxedDurability: true,
224
256
  wasmModule,
225
257
  });
@@ -241,10 +273,25 @@ export class DatabaseManager {
241
273
  this.initPromise = null;
242
274
  this.callbacks?.onStateChange?.(DatabaseLoadingState.Error);
243
275
  const error = e as Error;
276
+
277
+ // 查询迁移表数据
278
+ let migrationsTableData: MigrationTableItem[] = [];
279
+ try {
280
+ // 尝试查询迁移表
281
+ const drizzleMigration = new DrizzleMigrationModel(this.db as any);
282
+ migrationsTableData = await drizzleMigration.getMigrationList();
283
+ } catch (queryError) {
284
+ console.error('Failed to query migrations table:', queryError);
285
+ }
286
+
244
287
  this.callbacks?.onError?.({
245
- message: error.message,
246
- name: error.name,
247
- stack: error.stack,
288
+ error: {
289
+ message: error.message,
290
+ name: error.name,
291
+ stack: error.stack,
292
+ },
293
+ migrationTableItems: migrationsTableData,
294
+ migrationsSQL: migrations,
248
295
  });
249
296
 
250
297
  console.error(error);
@@ -271,6 +318,38 @@ export class DatabaseManager {
271
318
  },
272
319
  });
273
320
  }
321
+
322
+ async resetDatabase(): Promise<void> {
323
+ // 删除 IndexedDB 数据库
324
+ return new Promise<void>((resolve, reject) => {
325
+ // 检查 IndexedDB 是否可用
326
+ if (typeof indexedDB === 'undefined') {
327
+ console.warn('IndexedDB is not available, cannot delete database');
328
+ resolve();
329
+ return;
330
+ }
331
+
332
+ const dbName = `/pglite/${DB_NAME}`;
333
+ const request = indexedDB.deleteDatabase(dbName);
334
+
335
+ request.onsuccess = () => {
336
+ console.log(`✅ Database '${dbName}' reset successfully`);
337
+
338
+ // 清除本地存储的模式哈希
339
+ if (typeof localStorage !== 'undefined') {
340
+ localStorage.removeItem(pgliteSchemaHashCache);
341
+ }
342
+
343
+ resolve();
344
+ };
345
+
346
+ // eslint-disable-next-line unicorn/prefer-add-event-listener
347
+ request.onerror = (event) => {
348
+ console.error('❌ Error resetting database:', event);
349
+ reject(new Error(`Failed to reset database '${dbName}'`));
350
+ };
351
+ });
352
+ }
274
353
  }
275
354
 
276
355
  // 导出单例
@@ -282,3 +361,15 @@ export const clientDB = dbManager.createProxy();
282
361
  // 导出初始化方法,供应用启动时使用
283
362
  export const initializeDB = (callbacks?: DatabaseLoadingCallbacks) =>
284
363
  dbManager.initialize(callbacks);
364
+
365
+ export const resetClientDatabase = async () => {
366
+ await dbManager.resetDatabase();
367
+ };
368
+
369
+ export const updateMigrationRecord = async (migrationHash: string) => {
370
+ await clientDB.execute(
371
+ sql`INSERT INTO "drizzle"."__drizzle_migrations" ("hash", "created_at") VALUES (${migrationHash}, ${Date.now()});`,
372
+ );
373
+
374
+ await initializeDB();
375
+ };
@@ -223,10 +223,7 @@
223
223
  "hash": "9646161fa041354714f823d726af27247bcd6e60fa3be5698c0d69f337a5700b"
224
224
  },
225
225
  {
226
- "sql": [
227
- "DROP TABLE \"user_budgets\";",
228
- "\nDROP TABLE \"user_subscriptions\";"
229
- ],
226
+ "sql": ["DROP TABLE \"user_budgets\";", "\nDROP TABLE \"user_subscriptions\";"],
230
227
  "bps": true,
231
228
  "folderMillis": 1729699958471,
232
229
  "hash": "7dad43a2a25d1aec82124a4e53f8d82f8505c3073f23606c1dc5d2a4598eacf9"
@@ -298,9 +295,7 @@
298
295
  "hash": "845a692ceabbfc3caf252a97d3e19a213bc0c433df2689900135f9cfded2cf49"
299
296
  },
300
297
  {
301
- "sql": [
302
- "ALTER TABLE \"messages\" ADD COLUMN \"reasoning\" jsonb;"
303
- ],
298
+ "sql": ["ALTER TABLE \"messages\" ADD COLUMN \"reasoning\" jsonb;"],
304
299
  "bps": true,
305
300
  "folderMillis": 1737609172353,
306
301
  "hash": "2cb36ae4fcdd7b7064767e04bfbb36ae34518ff4bb1b39006f2dd394d1893868"
@@ -385,5 +380,40 @@
385
380
  "bps": true,
386
381
  "folderMillis": 1742269437903,
387
382
  "hash": "89e91285be422d5f44511c7405f57b57f8dfda4f0304126ae9b0f266e5fd60f1"
383
+ },
384
+ {
385
+ "sql": [
386
+ "ALTER TABLE \"session_groups\" DROP CONSTRAINT \"session_group_client_id_user_unique\";",
387
+ "\nALTER TABLE \"sessions\" DROP CONSTRAINT \"sessions_client_id_user_id_unique\";",
388
+ "\nALTER TABLE \"topics\" DROP CONSTRAINT \"topic_client_id_user_id_unique\";",
389
+ "\nALTER TABLE \"agents\" ADD COLUMN \"client_id\" text;",
390
+ "\nALTER TABLE \"files\" ADD COLUMN \"client_id\" text;",
391
+ "\nALTER TABLE \"knowledge_bases\" ADD COLUMN \"client_id\" text;",
392
+ "\nALTER TABLE \"message_plugins\" ADD COLUMN \"client_id\" text;",
393
+ "\nALTER TABLE \"message_queries\" ADD COLUMN \"client_id\" text;",
394
+ "\nALTER TABLE \"message_tts\" ADD COLUMN \"client_id\" text;",
395
+ "\nALTER TABLE \"message_translates\" ADD COLUMN \"client_id\" text;",
396
+ "\nALTER TABLE \"chunks\" ADD COLUMN \"client_id\" text;",
397
+ "\nALTER TABLE \"embeddings\" ADD COLUMN \"client_id\" text;",
398
+ "\nALTER TABLE \"unstructured_chunks\" ADD COLUMN \"client_id\" text;",
399
+ "\nALTER TABLE \"threads\" ADD COLUMN \"client_id\" text;",
400
+ "\nCREATE UNIQUE INDEX \"client_id_user_id_unique\" ON \"agents\" USING btree (\"client_id\",\"user_id\");",
401
+ "\nCREATE UNIQUE INDEX \"files_client_id_user_id_unique\" ON \"files\" USING btree (\"client_id\",\"user_id\");",
402
+ "\nCREATE UNIQUE INDEX \"knowledge_bases_client_id_user_id_unique\" ON \"knowledge_bases\" USING btree (\"client_id\",\"user_id\");",
403
+ "\nCREATE UNIQUE INDEX \"message_plugins_client_id_user_id_unique\" ON \"message_plugins\" USING btree (\"client_id\",\"user_id\");",
404
+ "\nCREATE UNIQUE INDEX \"message_queries_client_id_user_id_unique\" ON \"message_queries\" USING btree (\"client_id\",\"user_id\");",
405
+ "\nCREATE UNIQUE INDEX \"message_tts_client_id_user_id_unique\" ON \"message_tts\" USING btree (\"client_id\",\"user_id\");",
406
+ "\nCREATE UNIQUE INDEX \"message_translates_client_id_user_id_unique\" ON \"message_translates\" USING btree (\"client_id\",\"user_id\");",
407
+ "\nCREATE UNIQUE INDEX \"chunks_client_id_user_id_unique\" ON \"chunks\" USING btree (\"client_id\",\"user_id\");",
408
+ "\nCREATE UNIQUE INDEX \"embeddings_client_id_user_id_unique\" ON \"embeddings\" USING btree (\"client_id\",\"user_id\");",
409
+ "\nCREATE UNIQUE INDEX \"unstructured_chunks_client_id_user_id_unique\" ON \"unstructured_chunks\" USING btree (\"client_id\",\"user_id\");",
410
+ "\nCREATE UNIQUE INDEX \"session_groups_client_id_user_id_unique\" ON \"session_groups\" USING btree (\"client_id\",\"user_id\");",
411
+ "\nCREATE UNIQUE INDEX \"sessions_client_id_user_id_unique\" ON \"sessions\" USING btree (\"client_id\",\"user_id\");",
412
+ "\nCREATE UNIQUE INDEX \"threads_client_id_user_id_unique\" ON \"threads\" USING btree (\"client_id\",\"user_id\");",
413
+ "\nCREATE UNIQUE INDEX \"topics_client_id_user_id_unique\" ON \"topics\" USING btree (\"client_id\",\"user_id\");"
414
+ ],
415
+ "bps": true,
416
+ "folderMillis": 1742616026643,
417
+ "hash": "f885f1b1467b6564498f0d54ac2366c2d596f59bdd63a0feb63810c2ba346ae5"
388
418
  }
389
- ]
419
+ ]
@@ -0,0 +1,32 @@
1
+ ALTER TABLE "session_groups" DROP CONSTRAINT IF EXISTS "session_group_client_id_user_unique";--> statement-breakpoint
2
+ ALTER TABLE "sessions" DROP CONSTRAINT IF EXISTS "sessions_client_id_user_id_unique";--> statement-breakpoint
3
+ ALTER TABLE "topics" DROP CONSTRAINT IF EXISTS "topic_client_id_user_id_unique";--> statement-breakpoint
4
+
5
+ -- add client_id column
6
+ ALTER TABLE "agents" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
7
+ ALTER TABLE "files" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
8
+ ALTER TABLE "knowledge_bases" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
9
+ ALTER TABLE "message_plugins" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
10
+ ALTER TABLE "message_queries" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
11
+ ALTER TABLE "message_tts" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
12
+ ALTER TABLE "message_translates" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
13
+ ALTER TABLE "chunks" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
14
+ ALTER TABLE "embeddings" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
15
+ ALTER TABLE "unstructured_chunks" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
16
+ ALTER TABLE "threads" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
17
+
18
+ -- Create unique index(using IF NOT EXISTS)
19
+ CREATE UNIQUE INDEX IF NOT EXISTS "client_id_user_id_unique" ON "agents" USING btree ("client_id","user_id");--> statement-breakpoint
20
+ CREATE UNIQUE INDEX IF NOT EXISTS "files_client_id_user_id_unique" ON "files" USING btree ("client_id","user_id");--> statement-breakpoint
21
+ CREATE UNIQUE INDEX IF NOT EXISTS "knowledge_bases_client_id_user_id_unique" ON "knowledge_bases" USING btree ("client_id","user_id");--> statement-breakpoint
22
+ CREATE UNIQUE INDEX IF NOT EXISTS "message_plugins_client_id_user_id_unique" ON "message_plugins" USING btree ("client_id","user_id");--> statement-breakpoint
23
+ CREATE UNIQUE INDEX IF NOT EXISTS "message_queries_client_id_user_id_unique" ON "message_queries" USING btree ("client_id","user_id");--> statement-breakpoint
24
+ CREATE UNIQUE INDEX IF NOT EXISTS "message_tts_client_id_user_id_unique" ON "message_tts" USING btree ("client_id","user_id");--> statement-breakpoint
25
+ CREATE UNIQUE INDEX IF NOT EXISTS "message_translates_client_id_user_id_unique" ON "message_translates" USING btree ("client_id","user_id");--> statement-breakpoint
26
+ CREATE UNIQUE INDEX IF NOT EXISTS "chunks_client_id_user_id_unique" ON "chunks" USING btree ("client_id","user_id");--> statement-breakpoint
27
+ CREATE UNIQUE INDEX IF NOT EXISTS "embeddings_client_id_user_id_unique" ON "embeddings" USING btree ("client_id","user_id");--> statement-breakpoint
28
+ CREATE UNIQUE INDEX IF NOT EXISTS "unstructured_chunks_client_id_user_id_unique" ON "unstructured_chunks" USING btree ("client_id","user_id");--> statement-breakpoint
29
+ CREATE UNIQUE INDEX IF NOT EXISTS "session_groups_client_id_user_id_unique" ON "session_groups" USING btree ("client_id","user_id");--> statement-breakpoint
30
+ CREATE UNIQUE INDEX IF NOT EXISTS "sessions_client_id_user_id_unique" ON "sessions" USING btree ("client_id","user_id");--> statement-breakpoint
31
+ CREATE UNIQUE INDEX IF NOT EXISTS "threads_client_id_user_id_unique" ON "threads" USING btree ("client_id","user_id");--> statement-breakpoint
32
+ CREATE UNIQUE INDEX IF NOT EXISTS "topics_client_id_user_id_unique" ON "topics" USING btree ("client_id","user_id");