@lobehub/lobehub 2.0.0-next.170 → 2.0.0-next.172

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 (43) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +8 -8
  3. package/README.zh-CN.md +8 -8
  4. package/changelog/v1.json +18 -0
  5. package/docs/development/database-schema.dbml +33 -0
  6. package/locales/ar/models.json +12 -0
  7. package/locales/bg-BG/models.json +12 -0
  8. package/locales/de-DE/models.json +12 -0
  9. package/locales/en-US/models.json +12 -0
  10. package/locales/es-ES/models.json +12 -0
  11. package/locales/fa-IR/models.json +12 -0
  12. package/locales/fr-FR/models.json +12 -0
  13. package/locales/it-IT/models.json +12 -0
  14. package/locales/ja-JP/models.json +12 -0
  15. package/locales/ko-KR/models.json +12 -0
  16. package/locales/nl-NL/models.json +12 -0
  17. package/locales/pl-PL/models.json +12 -0
  18. package/locales/pt-BR/models.json +12 -0
  19. package/locales/ru-RU/models.json +12 -0
  20. package/locales/tr-TR/models.json +12 -0
  21. package/locales/vi-VN/models.json +12 -0
  22. package/locales/zh-CN/models.json +12 -0
  23. package/locales/zh-TW/models.json +12 -0
  24. package/package.json +1 -1
  25. package/packages/database/migrations/0062_add_more_index.sql +15 -0
  26. package/packages/database/migrations/meta/0062_snapshot.json +8960 -0
  27. package/packages/database/migrations/meta/_journal.json +7 -0
  28. package/packages/database/src/core/migrations.json +42 -20
  29. package/packages/database/src/schemas/apiKey.ts +17 -13
  30. package/packages/database/src/schemas/asyncTask.ts +16 -12
  31. package/packages/database/src/schemas/chatGroup.ts +5 -1
  32. package/packages/database/src/schemas/file.ts +24 -23
  33. package/packages/database/src/schemas/generation.ts +90 -72
  34. package/packages/database/src/schemas/message.ts +1 -0
  35. package/packages/database/src/schemas/rag.ts +6 -1
  36. package/packages/model-bank/src/aiModels/aihubmix.ts +74 -2
  37. package/packages/model-bank/src/aiModels/ollamacloud.ts +11 -0
  38. package/packages/model-bank/src/aiModels/openai.ts +74 -5
  39. package/packages/model-bank/src/aiModels/zenmux.ts +74 -0
  40. package/packages/model-runtime/src/const/models.ts +2 -0
  41. package/packages/model-runtime/src/core/contextBuilders/openai.ts +6 -2
  42. package/src/server/routers/lambda/image.ts +6 -6
  43. package/src/server/routers/lambda/user.ts +12 -4
@@ -434,6 +434,13 @@
434
434
  "when": 1765540257262,
435
435
  "tag": "0061_add_document_and_memory_index",
436
436
  "breakpoints": true
437
+ },
438
+ {
439
+ "idx": 62,
440
+ "version": "7",
441
+ "when": 1765728439737,
442
+ "tag": "0062_add_more_index",
443
+ "breakpoints": true
437
444
  }
438
445
  ],
439
446
  "version": "6"
@@ -949,28 +949,50 @@
949
949
  },
950
950
  {
951
951
  "sql": [
952
- "ALTER TABLE \"user_memories\" ADD COLUMN \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
953
- "\nALTER TABLE \"user_memories_contexts\" ADD COLUMN \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
954
- "\nALTER TABLE \"user_memories_experiences\" ADD COLUMN \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
955
- "\nALTER TABLE \"user_memories_identities\" ADD COLUMN \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
956
- "\nALTER TABLE \"user_memories_preferences\" ADD COLUMN \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
957
- "\nCREATE INDEX \"agents_user_id_idx\" ON \"agents\" USING btree (\"user_id\");",
958
- "\nCREATE INDEX \"documents_source_type_idx\" ON \"documents\" USING btree (\"source_type\");",
959
- "\nCREATE INDEX \"documents_user_id_idx\" ON \"documents\" USING btree (\"user_id\");",
960
- "\nCREATE INDEX \"files_user_id_idx\" ON \"files\" USING btree (\"user_id\");",
961
- "\nCREATE INDEX \"users_created_at_idx\" ON \"users\" USING btree (\"created_at\");",
962
- "\nCREATE INDEX \"users_banned_true_created_at_idx\" ON \"users\" USING btree (\"created_at\") WHERE \"users\".\"banned\" = true;",
963
- "\nCREATE INDEX \"user_memories_user_id_index\" ON \"user_memories\" USING btree (\"user_id\");",
964
- "\nCREATE INDEX \"user_memories_contexts_user_id_index\" ON \"user_memories_contexts\" USING btree (\"user_id\");",
965
- "\nCREATE INDEX \"user_memories_experiences_user_id_index\" ON \"user_memories_experiences\" USING btree (\"user_id\");",
966
- "\nCREATE INDEX \"user_memories_experiences_user_memory_id_index\" ON \"user_memories_experiences\" USING btree (\"user_memory_id\");",
967
- "\nCREATE INDEX \"user_memories_identities_user_id_index\" ON \"user_memories_identities\" USING btree (\"user_id\");",
968
- "\nCREATE INDEX \"user_memories_identities_user_memory_id_index\" ON \"user_memories_identities\" USING btree (\"user_memory_id\");",
969
- "\nCREATE INDEX \"user_memories_preferences_user_id_index\" ON \"user_memories_preferences\" USING btree (\"user_id\");",
970
- "\nCREATE INDEX \"user_memories_preferences_user_memory_id_index\" ON \"user_memories_preferences\" USING btree (\"user_memory_id\");"
952
+ "ALTER TABLE \"user_memories\" ADD COLUMN IF NOT EXISTS \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
953
+ "\nALTER TABLE \"user_memories_contexts\" ADD COLUMN IF NOT EXISTS \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
954
+ "\nALTER TABLE \"user_memories_experiences\" ADD COLUMN IF NOT EXISTS \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
955
+ "\nALTER TABLE \"user_memories_identities\" ADD COLUMN IF NOT EXISTS \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
956
+ "\nALTER TABLE \"user_memories_preferences\" ADD COLUMN IF NOT EXISTS \"captured_at\" timestamp with time zone DEFAULT now() NOT NULL;",
957
+ "\nCREATE INDEX IF NOT EXISTS \"agents_user_id_idx\" ON \"agents\" USING btree (\"user_id\");",
958
+ "\nCREATE INDEX IF NOT EXISTS \"documents_source_type_idx\" ON \"documents\" USING btree (\"source_type\");",
959
+ "\nCREATE INDEX IF NOT EXISTS \"documents_user_id_idx\" ON \"documents\" USING btree (\"user_id\");",
960
+ "\nCREATE INDEX IF NOT EXISTS \"files_user_id_idx\" ON \"files\" USING btree (\"user_id\");",
961
+ "\nCREATE INDEX IF NOT EXISTS \"users_created_at_idx\" ON \"users\" USING btree (\"created_at\");",
962
+ "\nCREATE INDEX IF NOT EXISTS \"users_banned_true_created_at_idx\" ON \"users\" USING btree (\"created_at\") WHERE \"users\".\"banned\" = true;",
963
+ "\nCREATE INDEX IF NOT EXISTS \"user_memories_user_id_index\" ON \"user_memories\" USING btree (\"user_id\");",
964
+ "\nCREATE INDEX IF NOT EXISTS \"user_memories_contexts_user_id_index\" ON \"user_memories_contexts\" USING btree (\"user_id\");",
965
+ "\nCREATE INDEX IF NOT EXISTS \"user_memories_experiences_user_id_index\" ON \"user_memories_experiences\" USING btree (\"user_id\");",
966
+ "\nCREATE INDEX IF NOT EXISTS \"user_memories_experiences_user_memory_id_index\" ON \"user_memories_experiences\" USING btree (\"user_memory_id\");",
967
+ "\nCREATE INDEX IF NOT EXISTS \"user_memories_identities_user_id_index\" ON \"user_memories_identities\" USING btree (\"user_id\");",
968
+ "\nCREATE INDEX IF NOT EXISTS \"user_memories_identities_user_memory_id_index\" ON \"user_memories_identities\" USING btree (\"user_memory_id\");",
969
+ "\nCREATE INDEX IF NOT EXISTS \"user_memories_preferences_user_id_index\" ON \"user_memories_preferences\" USING btree (\"user_id\");",
970
+ "\nCREATE INDEX IF NOT EXISTS \"user_memories_preferences_user_memory_id_index\" ON \"user_memories_preferences\" USING btree (\"user_memory_id\");\n"
971
971
  ],
972
972
  "bps": true,
973
973
  "folderMillis": 1765540257262,
974
- "hash": "2cc13eba2a174ebf18ac32a3ae673338a3dd46ec37a22108a7783a80f44a5286"
974
+ "hash": "444e28eed827bdf52b836a0d284c1cc946ce4e687c94044ddcd8c18fe68fdec5"
975
+ },
976
+ {
977
+ "sql": [
978
+ "CREATE INDEX IF NOT EXISTS \"api_keys_user_id_idx\" ON \"api_keys\" USING btree (\"user_id\");",
979
+ "\nCREATE INDEX IF NOT EXISTS \"async_tasks_user_id_idx\" ON \"async_tasks\" USING btree (\"user_id\");",
980
+ "\nCREATE INDEX IF NOT EXISTS \"chat_groups_group_id_idx\" ON \"chat_groups\" USING btree (\"group_id\");",
981
+ "\nCREATE INDEX IF NOT EXISTS \"global_files_creator_idx\" ON \"global_files\" USING btree (\"creator\");",
982
+ "\nCREATE INDEX IF NOT EXISTS \"knowledge_base_files_kb_id_idx\" ON \"knowledge_base_files\" USING btree (\"knowledge_base_id\");",
983
+ "\nCREATE INDEX IF NOT EXISTS \"knowledge_bases_user_id_idx\" ON \"knowledge_bases\" USING btree (\"user_id\");",
984
+ "\nCREATE INDEX IF NOT EXISTS \"generation_batches_user_id_idx\" ON \"generation_batches\" USING btree (\"user_id\");",
985
+ "\nCREATE INDEX IF NOT EXISTS \"generation_batches_topic_id_idx\" ON \"generation_batches\" USING btree (\"generation_topic_id\");",
986
+ "\nCREATE INDEX IF NOT EXISTS \"generation_topics_user_id_idx\" ON \"generation_topics\" USING btree (\"user_id\");",
987
+ "\nCREATE INDEX IF NOT EXISTS \"generations_user_id_idx\" ON \"generations\" USING btree (\"user_id\");",
988
+ "\nCREATE INDEX IF NOT EXISTS \"generations_batch_id_idx\" ON \"generations\" USING btree (\"generation_batch_id\");",
989
+ "\nCREATE INDEX IF NOT EXISTS \"messages_group_id_idx\" ON \"messages\" USING btree (\"group_id\");",
990
+ "\nCREATE INDEX IF NOT EXISTS \"document_chunks_document_id_idx\" ON \"document_chunks\" USING btree (\"document_id\");",
991
+ "\nCREATE INDEX IF NOT EXISTS \"document_chunks_chunk_id_idx\" ON \"document_chunks\" USING btree (\"chunk_id\");",
992
+ "\nCREATE INDEX IF NOT EXISTS \"embeddings_user_id_idx\" ON \"embeddings\" USING btree (\"user_id\");\n"
993
+ ],
994
+ "bps": true,
995
+ "folderMillis": 1765728439737,
996
+ "hash": "ba6a6beff2ad39419ec4aa7887539c9db0472e13f9242cb8780ff96eec450268"
975
997
  }
976
998
  ]
@@ -1,23 +1,27 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix */
2
- import { boolean, integer, pgTable, text, varchar } from 'drizzle-orm/pg-core';
2
+ import { boolean, index, integer, pgTable, text, varchar } from 'drizzle-orm/pg-core';
3
3
  import { createInsertSchema } from 'drizzle-zod';
4
4
 
5
5
  import { timestamps, timestamptz } from './_helpers';
6
6
  import { users } from './user';
7
7
 
8
- export const apiKeys = pgTable('api_keys', {
9
- id: integer('id').primaryKey().generatedByDefaultAsIdentity(), // auto-increment primary key
10
- name: varchar('name', { length: 256 }).notNull(), // name of the API key
11
- key: varchar('key', { length: 256 }).notNull().unique(), // API key
12
- enabled: boolean('enabled').default(true), // whether the API key is enabled
13
- expiresAt: timestamptz('expires_at'), // expires time
14
- lastUsedAt: timestamptz('last_used_at'), // last used time
15
- userId: text('user_id')
16
- .references(() => users.id, { onDelete: 'cascade' })
17
- .notNull(), // belongs to user, when user is deleted, the API key will be deleted
8
+ export const apiKeys = pgTable(
9
+ 'api_keys',
10
+ {
11
+ id: integer('id').primaryKey().generatedByDefaultAsIdentity(), // auto-increment primary key
12
+ name: varchar('name', { length: 256 }).notNull(), // name of the API key
13
+ key: varchar('key', { length: 256 }).notNull().unique(), // API key
14
+ enabled: boolean('enabled').default(true), // whether the API key is enabled
15
+ expiresAt: timestamptz('expires_at'), // expires time
16
+ lastUsedAt: timestamptz('last_used_at'), // last used time
17
+ userId: text('user_id')
18
+ .references(() => users.id, { onDelete: 'cascade' })
19
+ .notNull(), // belongs to user, when user is deleted, the API key will be deleted
18
20
 
19
- ...timestamps,
20
- });
21
+ ...timestamps,
22
+ },
23
+ (t) => [index('api_keys_user_id_idx').on(t.userId)],
24
+ );
21
25
 
22
26
  export const insertApiKeySchema = createInsertSchema(apiKeys);
23
27
 
@@ -1,23 +1,27 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix */
2
- import { integer, jsonb, pgTable, text, uuid } from 'drizzle-orm/pg-core';
2
+ import { index, integer, jsonb, pgTable, text, uuid } from 'drizzle-orm/pg-core';
3
3
 
4
4
  import { timestamps } from './_helpers';
5
5
  import { users } from './user';
6
6
 
7
- export const asyncTasks = pgTable('async_tasks', {
8
- id: uuid('id').defaultRandom().primaryKey(),
9
- type: text('type'),
7
+ export const asyncTasks = pgTable(
8
+ 'async_tasks',
9
+ {
10
+ id: uuid('id').defaultRandom().primaryKey(),
11
+ type: text('type'),
10
12
 
11
- status: text('status'),
12
- error: jsonb('error'),
13
+ status: text('status'),
14
+ error: jsonb('error'),
13
15
 
14
- userId: text('user_id')
15
- .references(() => users.id, { onDelete: 'cascade' })
16
- .notNull(),
17
- duration: integer('duration'),
16
+ userId: text('user_id')
17
+ .references(() => users.id, { onDelete: 'cascade' })
18
+ .notNull(),
19
+ duration: integer('duration'),
18
20
 
19
- ...timestamps,
20
- });
21
+ ...timestamps,
22
+ },
23
+ (t) => [index('async_tasks_user_id_idx').on(t.userId)],
24
+ );
21
25
 
22
26
  export type NewAsyncTaskItem = typeof asyncTasks.$inferInsert;
23
27
  export type AsyncTaskSelectItem = typeof asyncTasks.$inferSelect;
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix */
2
2
  import {
3
3
  boolean,
4
+ index,
4
5
  integer,
5
6
  jsonb,
6
7
  pgTable,
@@ -45,7 +46,10 @@ export const chatGroups = pgTable(
45
46
 
46
47
  ...timestamps,
47
48
  },
48
- (t) => [uniqueIndex('chat_groups_client_id_user_id_unique').on(t.clientId, t.userId)],
49
+ (t) => [
50
+ uniqueIndex('chat_groups_client_id_user_id_unique').on(t.clientId, t.userId),
51
+ index('chat_groups_group_id_idx').on(t.groupId),
52
+ ],
49
53
  );
50
54
 
51
55
  export const insertChatGroupSchema = createInsertSchema(chatGroups);
@@ -23,18 +23,22 @@ import { accessedAt, createdAt, timestamps } from './_helpers';
23
23
  import { asyncTasks } from './asyncTask';
24
24
  import { users } from './user';
25
25
 
26
- export const globalFiles = pgTable('global_files', {
27
- hashId: varchar('hash_id', { length: 64 }).primaryKey(),
28
- fileType: varchar('file_type', { length: 255 }).notNull(),
29
- size: integer('size').notNull(),
30
- url: text('url').notNull(),
31
- metadata: jsonb('metadata'),
32
- creator: text('creator')
33
- .references(() => users.id, { onDelete: 'set null' })
34
- .notNull(),
35
- createdAt: createdAt(),
36
- accessedAt: accessedAt(),
37
- });
26
+ export const globalFiles = pgTable(
27
+ 'global_files',
28
+ {
29
+ hashId: varchar('hash_id', { length: 64 }).primaryKey(),
30
+ fileType: varchar('file_type', { length: 255 }).notNull(),
31
+ size: integer('size').notNull(),
32
+ url: text('url').notNull(),
33
+ metadata: jsonb('metadata'),
34
+ creator: text('creator')
35
+ .references(() => users.id, { onDelete: 'set null' })
36
+ .notNull(),
37
+ createdAt: createdAt(),
38
+ accessedAt: accessedAt(),
39
+ },
40
+ (t) => [index('global_files_creator_idx').on(t.creator)],
41
+ );
38
42
 
39
43
  export type NewGlobalFile = typeof globalFiles.$inferInsert;
40
44
  export type GlobalFileItem = typeof globalFiles.$inferSelect;
@@ -190,12 +194,10 @@ export const knowledgeBases = pgTable(
190
194
 
191
195
  ...timestamps,
192
196
  },
193
- (t) => ({
194
- clientIdUnique: uniqueIndex('knowledge_bases_client_id_user_id_unique').on(
195
- t.clientId,
196
- t.userId,
197
- ),
198
- }),
197
+ (t) => [
198
+ uniqueIndex('knowledge_bases_client_id_user_id_unique').on(t.clientId, t.userId),
199
+ index('knowledge_bases_user_id_idx').on(t.userId),
200
+ ],
199
201
  );
200
202
 
201
203
  export const insertKnowledgeBasesSchema = createInsertSchema(knowledgeBases);
@@ -220,9 +222,8 @@ export const knowledgeBaseFiles = pgTable(
220
222
 
221
223
  createdAt: createdAt(),
222
224
  },
223
- (t) => ({
224
- pk: primaryKey({
225
- columns: [t.knowledgeBaseId, t.fileId],
226
- }),
227
- }),
225
+ (t) => [
226
+ primaryKey({ columns: [t.knowledgeBaseId, t.fileId] }),
227
+ index('knowledge_base_files_kb_id_idx').on(t.knowledgeBaseId),
228
+ ],
228
229
  );
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix */
2
2
  import { ImageGenerationAsset } from '@lobechat/types';
3
- import { integer, jsonb, pgTable, text, uuid, varchar } from 'drizzle-orm/pg-core';
3
+ import { index, integer, jsonb, pgTable, text, uuid, varchar } from 'drizzle-orm/pg-core';
4
4
  import { createInsertSchema } from 'drizzle-zod';
5
5
 
6
6
  import { idGenerator } from '../utils/idGenerator';
@@ -12,24 +12,28 @@ import { users } from './user';
12
12
  /**
13
13
  * Generation topics table - Used to organize and manage AI-generated content topics
14
14
  */
15
- export const generationTopics = pgTable('generation_topics', {
16
- id: text('id')
17
- .$defaultFn(() => idGenerator('generationTopics'))
18
- .notNull()
19
- .primaryKey(),
15
+ export const generationTopics = pgTable(
16
+ 'generation_topics',
17
+ {
18
+ id: text('id')
19
+ .$defaultFn(() => idGenerator('generationTopics'))
20
+ .notNull()
21
+ .primaryKey(),
20
22
 
21
- userId: text('user_id')
22
- .references(() => users.id, { onDelete: 'cascade' })
23
- .notNull(),
23
+ userId: text('user_id')
24
+ .references(() => users.id, { onDelete: 'cascade' })
25
+ .notNull(),
24
26
 
25
- /** Brief description of topic content, generated by LLM */
26
- title: text('title'),
27
+ /** Brief description of topic content, generated by LLM */
28
+ title: text('title'),
27
29
 
28
- /** Topic cover image URL */
29
- coverUrl: text('cover_url'),
30
+ /** Topic cover image URL */
31
+ coverUrl: text('cover_url'),
30
32
 
31
- ...timestamps,
32
- });
33
+ ...timestamps,
34
+ },
35
+ (t) => [index('generation_topics_user_id_idx').on(t.userId)],
36
+ );
33
37
 
34
38
  export const insertGenerationTopicSchema = createInsertSchema(generationTopics);
35
39
 
@@ -39,43 +43,50 @@ export type GenerationTopicItem = typeof generationTopics.$inferSelect;
39
43
  /**
40
44
  * Generation batches table - Stores configuration information for a single generation request
41
45
  */
42
- export const generationBatches = pgTable('generation_batches', {
43
- id: text('id')
44
- .$defaultFn(() => idGenerator('generationBatches'))
45
- .notNull()
46
- .primaryKey(),
46
+ export const generationBatches = pgTable(
47
+ 'generation_batches',
48
+ {
49
+ id: text('id')
50
+ .$defaultFn(() => idGenerator('generationBatches'))
51
+ .notNull()
52
+ .primaryKey(),
47
53
 
48
- userId: text('user_id')
49
- .references(() => users.id, { onDelete: 'cascade' })
50
- .notNull(),
54
+ userId: text('user_id')
55
+ .references(() => users.id, { onDelete: 'cascade' })
56
+ .notNull(),
51
57
 
52
- generationTopicId: text('generation_topic_id')
53
- .notNull()
54
- .references(() => generationTopics.id, { onDelete: 'cascade' }),
58
+ generationTopicId: text('generation_topic_id')
59
+ .notNull()
60
+ .references(() => generationTopics.id, { onDelete: 'cascade' }),
55
61
 
56
- /** Provider name */
57
- provider: text('provider').notNull(),
62
+ /** Provider name */
63
+ provider: text('provider').notNull(),
58
64
 
59
- /** Model name */
60
- model: text('model').notNull(),
65
+ /** Model name */
66
+ model: text('model').notNull(),
61
67
 
62
- /** Generation prompt */
63
- prompt: text('prompt').notNull(),
68
+ /** Generation prompt */
69
+ prompt: text('prompt').notNull(),
64
70
 
65
- /** Image width */
66
- width: integer('width'),
71
+ /** Image width */
72
+ width: integer('width'),
67
73
 
68
- /** Image height */
69
- height: integer('height'),
74
+ /** Image height */
75
+ height: integer('height'),
70
76
 
71
- /** Image aspect ratio */
72
- ratio: varchar('ratio', { length: 64 }),
77
+ /** Image aspect ratio */
78
+ ratio: varchar('ratio', { length: 64 }),
73
79
 
74
- /** Stores generation batch configuration for common settings that don't need indexing */
75
- config: jsonb('config'),
80
+ /** Stores generation batch configuration for common settings that don't need indexing */
81
+ config: jsonb('config'),
76
82
 
77
- ...timestamps,
78
- });
83
+ ...timestamps,
84
+ },
85
+ (t) => [
86
+ index('generation_batches_user_id_idx').on(t.userId),
87
+ index('generation_batches_topic_id_idx').on(t.generationTopicId),
88
+ ],
89
+ );
79
90
 
80
91
  export const insertGenerationBatchSchema = createInsertSchema(generationBatches);
81
92
 
@@ -88,36 +99,43 @@ export type GenerationBatchWithGenerations = GenerationBatchItem & {
88
99
  /**
89
100
  * Stores individual AI generation information
90
101
  */
91
- export const generations = pgTable('generations', {
92
- id: text('id')
93
- .$defaultFn(() => idGenerator('generations'))
94
- .notNull()
95
- .primaryKey(),
96
-
97
- userId: text('user_id')
98
- .references(() => users.id, { onDelete: 'cascade' })
99
- .notNull(),
100
-
101
- generationBatchId: varchar('generation_batch_id', { length: 64 })
102
- .notNull()
103
- .references(() => generationBatches.id, { onDelete: 'cascade' }),
104
-
105
- /** Associated async task ID */
106
- asyncTaskId: uuid('async_task_id').references(() => asyncTasks.id, {
107
- onDelete: 'set null',
108
- }),
109
-
110
- /** Associated generated file ID, deletes generation record when file is deleted */
111
- fileId: text('file_id').references(() => files.id, { onDelete: 'cascade' }),
112
-
113
- /** Generation seed value */
114
- seed: integer('seed'),
115
-
116
- /** Generated asset information, including S3 storage key, actual image dimensions, thumbnail key, etc. */
117
- asset: jsonb('asset').$type<ImageGenerationAsset>(),
118
-
119
- ...timestamps,
120
- });
102
+ export const generations = pgTable(
103
+ 'generations',
104
+ {
105
+ id: text('id')
106
+ .$defaultFn(() => idGenerator('generations'))
107
+ .notNull()
108
+ .primaryKey(),
109
+
110
+ userId: text('user_id')
111
+ .references(() => users.id, { onDelete: 'cascade' })
112
+ .notNull(),
113
+
114
+ generationBatchId: varchar('generation_batch_id', { length: 64 })
115
+ .notNull()
116
+ .references(() => generationBatches.id, { onDelete: 'cascade' }),
117
+
118
+ /** Associated async task ID */
119
+ asyncTaskId: uuid('async_task_id').references(() => asyncTasks.id, {
120
+ onDelete: 'set null',
121
+ }),
122
+
123
+ /** Associated generated file ID, deletes generation record when file is deleted */
124
+ fileId: text('file_id').references(() => files.id, { onDelete: 'cascade' }),
125
+
126
+ /** Generation seed value */
127
+ seed: integer('seed'),
128
+
129
+ /** Generated asset information, including S3 storage key, actual image dimensions, thumbnail key, etc. */
130
+ asset: jsonb('asset').$type<ImageGenerationAsset>(),
131
+
132
+ ...timestamps,
133
+ },
134
+ (t) => [
135
+ index('generations_user_id_idx').on(t.userId),
136
+ index('generations_batch_id_idx').on(t.generationBatchId),
137
+ ],
138
+ );
121
139
 
122
140
  export const insertGenerationSchema = createInsertSchema(generations);
123
141
 
@@ -137,6 +137,7 @@ export const messages = pgTable(
137
137
  index('messages_session_id_idx').on(table.sessionId),
138
138
  index('messages_thread_id_idx').on(table.threadId),
139
139
  index('messages_agent_id_idx').on(table.agentId),
140
+ index('messages_group_id_idx').on(table.groupId),
140
141
  ],
141
142
  );
142
143
 
@@ -82,6 +82,7 @@ export const embeddings = pgTable(
82
82
  uniqueIndex('embeddings_client_id_user_id_unique').on(t.clientId, t.userId),
83
83
  // improve delete embeddings query
84
84
  index('embeddings_chunk_id_idx').on(t.chunkId),
85
+ index('embeddings_user_id_idx').on(t.userId),
85
86
  ],
86
87
  );
87
88
 
@@ -111,7 +112,11 @@ export const documentChunks = pgTable(
111
112
 
112
113
  createdAt: createdAt(),
113
114
  },
114
- (t) => [primaryKey({ columns: [t.documentId, t.chunkId] })],
115
+ (t) => [
116
+ primaryKey({ columns: [t.documentId, t.chunkId] }),
117
+ index('document_chunks_document_id_idx').on(t.documentId),
118
+ index('document_chunks_chunk_id_idx').on(t.chunkId),
119
+ ],
115
120
  );
116
121
 
117
122
  export type NewDocumentChunk = typeof documentChunks.$inferInsert;
@@ -1,6 +1,80 @@
1
1
  import { AIChatModelCard } from '../types/aiModel';
2
2
 
3
3
  const aihubmixModels: AIChatModelCard[] = [
4
+ {
5
+ abilities: {
6
+ functionCall: true,
7
+ reasoning: true,
8
+ search: true,
9
+ structuredOutput: true,
10
+ vision: true,
11
+ },
12
+ contextWindowTokens: 400_000,
13
+ description: 'GPT-5.2 — 面向编码与 agentic 工作流的旗舰模型,提供更强推理与长上下文能力。',
14
+ displayName: 'GPT-5.2',
15
+ enabled: true,
16
+ id: 'gpt-5.2',
17
+ maxOutput: 128_000,
18
+ pricing: {
19
+ units: [
20
+ { name: 'textInput', rate: 1.75, strategy: 'fixed', unit: 'millionTokens' },
21
+ { name: 'textInput_cacheRead', rate: 0.175, strategy: 'fixed', unit: 'millionTokens' },
22
+ { name: 'textOutput', rate: 14, strategy: 'fixed', unit: 'millionTokens' },
23
+ ],
24
+ },
25
+ releasedAt: '2025-12-11',
26
+ settings: {
27
+ extendParams: ['gpt5_1ReasoningEffort', 'textVerbosity'],
28
+ searchImpl: 'params',
29
+ },
30
+ type: 'chat',
31
+ },
32
+ {
33
+ abilities: {
34
+ functionCall: true,
35
+ reasoning: true,
36
+ search: true,
37
+ vision: true,
38
+ },
39
+ contextWindowTokens: 400_000,
40
+ description:
41
+ 'GPT-5.2 pro:更聪明、更精确的 GPT-5.2 版本(Responses API Only),适合高难度问题与更长的多轮推理。',
42
+ displayName: 'GPT-5.2 pro',
43
+ id: 'gpt-5.2-pro',
44
+ maxOutput: 128_000,
45
+ pricing: {
46
+ units: [
47
+ { name: 'textInput', rate: 21, strategy: 'fixed', unit: 'millionTokens' },
48
+ { name: 'textOutput', rate: 168, strategy: 'fixed', unit: 'millionTokens' },
49
+ ],
50
+ },
51
+ releasedAt: '2025-12-11',
52
+ settings: {
53
+ searchImpl: 'params',
54
+ },
55
+ type: 'chat',
56
+ },
57
+ {
58
+ abilities: {
59
+ functionCall: true,
60
+ vision: true,
61
+ },
62
+ contextWindowTokens: 128_000,
63
+ description: 'GPT-5.2 Chat:ChatGPT 使用的 GPT-5.2 变体(chat-latest),用于体验最新对话改进。',
64
+ displayName: 'GPT-5.2 Chat',
65
+ enabled: true,
66
+ id: 'gpt-5.2-chat-latest',
67
+ maxOutput: 16_384,
68
+ pricing: {
69
+ units: [
70
+ { name: 'textInput', rate: 1.75, strategy: 'fixed', unit: 'millionTokens' },
71
+ { name: 'textInput_cacheRead', rate: 0.175, strategy: 'fixed', unit: 'millionTokens' },
72
+ { name: 'textOutput', rate: 14, strategy: 'fixed', unit: 'millionTokens' },
73
+ ],
74
+ },
75
+ releasedAt: '2025-12-11',
76
+ type: 'chat',
77
+ },
4
78
  {
5
79
  abilities: {
6
80
  functionCall: true,
@@ -13,7 +87,6 @@ const aihubmixModels: AIChatModelCard[] = [
13
87
  description:
14
88
  'GPT-5.1 — 针对编码和 agent 任务优化的旗舰模型,支持可配置的推理强度与更长上下文。',
15
89
  displayName: 'GPT-5.1',
16
- enabled: true,
17
90
  id: 'gpt-5.1',
18
91
  maxOutput: 128_000,
19
92
  pricing: {
@@ -38,7 +111,6 @@ const aihubmixModels: AIChatModelCard[] = [
38
111
  contextWindowTokens: 128_000,
39
112
  description: 'GPT-5.1 Chat:用于 ChatGPT 的 GPT-5.1 变体,适合聊天场景。',
40
113
  displayName: 'GPT-5.1 Chat',
41
- enabled: true,
42
114
  id: 'gpt-5.1-chat-latest',
43
115
  maxOutput: 16_384,
44
116
  pricing: {
@@ -1,6 +1,17 @@
1
1
  import { AIChatModelCard } from '../types/aiModel';
2
2
 
3
3
  const ollamaCloudModels: AIChatModelCard[] = [
4
+ {
5
+ abilities: {
6
+ functionCall: true,
7
+ },
8
+ contextWindowTokens: 262_144,
9
+ description:
10
+ 'Devstral 2 123B 模型,擅长使用工具探索代码库、编辑多个文件并为软件工程代理提供支持。',
11
+ displayName: 'Devstral 2',
12
+ id: 'devstral-2:123b',
13
+ type: 'chat',
14
+ },
4
15
  {
5
16
  abilities: {
6
17
  functionCall: true,