@lobehub/chat 1.103.1 → 1.103.2

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 (79) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/apps/desktop/build/icon-beta.ico +0 -0
  3. package/apps/desktop/build/icon-dev.ico +0 -0
  4. package/apps/desktop/build/icon-nightly.ico +0 -0
  5. package/apps/desktop/build/icon.ico +0 -0
  6. package/apps/desktop/electron.vite.config.ts +4 -2
  7. package/apps/desktop/package.json +1 -0
  8. package/apps/desktop/src/main/appBrowsers.ts +2 -2
  9. package/apps/desktop/src/main/const/env.ts +5 -4
  10. package/apps/desktop/src/main/const/store.ts +1 -0
  11. package/apps/desktop/src/main/const/theme.ts +11 -0
  12. package/apps/desktop/src/main/controllers/BrowserWindowsCtr.ts +1 -1
  13. package/apps/desktop/src/main/controllers/NotificationCtr.ts +2 -4
  14. package/apps/desktop/src/main/controllers/SystemCtr.ts +4 -0
  15. package/apps/desktop/src/main/controllers/TrayMenuCtr.ts +5 -5
  16. package/apps/desktop/src/main/controllers/index.ts +1 -1
  17. package/apps/desktop/src/main/core/App.ts +9 -10
  18. package/apps/desktop/src/main/core/{Browser.ts → browser/Browser.ts} +129 -88
  19. package/apps/desktop/src/main/core/{BrowserManager.ts → browser/BrowserManager.ts} +13 -3
  20. package/apps/desktop/src/main/core/{StaticFileServerManager.ts → infrastructure/StaticFileServerManager.ts} +13 -7
  21. package/apps/desktop/src/main/core/{StoreManager.ts → infrastructure/StoreManager.ts} +1 -1
  22. package/apps/desktop/src/main/core/{UpdaterManager.ts → infrastructure/UpdaterManager.ts} +1 -1
  23. package/apps/desktop/src/main/core/{MenuManager.ts → ui/MenuManager.ts} +2 -2
  24. package/apps/desktop/src/main/core/{ShortcutManager.ts → ui/ShortcutManager.ts} +7 -1
  25. package/apps/desktop/src/main/core/{Tray.ts → ui/Tray.ts} +61 -59
  26. package/apps/desktop/src/main/core/{TrayManager.ts → ui/TrayManager.ts} +5 -5
  27. package/apps/desktop/src/main/shortcuts/config.ts +2 -2
  28. package/apps/desktop/src/main/types/store.ts +1 -0
  29. package/changelog/v1.json +12 -0
  30. package/docs/development/basic/add-new-image-model.mdx +162 -0
  31. package/docs/development/basic/add-new-image-model.zh-CN.mdx +162 -0
  32. package/docs/usage/providers/fal.mdx +1 -1
  33. package/docs/usage/providers/fal.zh-CN.mdx +1 -1
  34. package/package.json +66 -66
  35. package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/Portal.tsx +3 -1
  36. package/src/app/[variants]/(main)/chat/(workspace)/features/AgentSettings/index.tsx +4 -2
  37. package/src/app/[variants]/(main)/image/@menu/components/SeedNumberInput/index.tsx +1 -1
  38. package/src/app/[variants]/(main)/image/features/GenerationFeed/BatchItem.tsx +39 -3
  39. package/src/app/[variants]/(main)/image/features/GenerationFeed/ReferenceImages.tsx +122 -0
  40. package/src/config/aiModels/fal.ts +31 -7
  41. package/src/config/aiModels/openai.ts +10 -1
  42. package/src/features/ElectronTitlebar/WinControl/index.tsx +85 -90
  43. package/src/features/ElectronTitlebar/hooks/useWatchThemeUpdate.ts +10 -5
  44. package/src/features/ImageTopicPanel/index.tsx +0 -1
  45. package/src/features/PluginDevModal/index.tsx +3 -1
  46. package/src/features/User/__tests__/UserAvatar.test.tsx +5 -4
  47. package/src/libs/model-runtime/fal/index.ts +1 -1
  48. package/src/libs/model-runtime/types/image.ts +1 -1
  49. package/src/libs/model-runtime/utils/openaiCompatibleFactory/index.ts +1 -1
  50. package/src/libs/model-runtime/utils/response.ts +2 -0
  51. package/src/libs/model-runtime/utils/streams/google-ai.test.ts +46 -0
  52. package/src/libs/model-runtime/utils/streams/google-ai.ts +4 -4
  53. package/src/libs/model-runtime/utils/streams/vertex-ai.ts +6 -8
  54. package/src/libs/standard-parameters/{meta-schema.test.ts → index.test.ts} +1 -1
  55. package/src/libs/standard-parameters/index.ts +152 -1
  56. package/src/server/ld.test.ts +4 -3
  57. package/src/server/routers/async/image.ts +1 -1
  58. package/src/services/__tests__/chat.test.ts +3 -4
  59. package/src/store/chat/slices/message/selectors.test.ts +2 -3
  60. package/src/store/chat/slices/plugin/action.test.ts +2 -1
  61. package/src/store/image/slices/generationConfig/action.test.ts +2 -2
  62. package/src/store/image/slices/generationConfig/action.ts +1 -1
  63. package/src/store/image/slices/generationConfig/hooks.test.ts +2 -2
  64. package/src/store/image/slices/generationConfig/hooks.ts +1 -4
  65. package/src/store/image/slices/generationConfig/initialState.ts +2 -2
  66. package/src/store/image/slices/generationConfig/selectors.test.ts +2 -2
  67. package/src/store/image/slices/generationConfig/selectors.ts +1 -1
  68. package/src/store/user/slices/auth/selectors.test.ts +3 -2
  69. package/src/types/generation/index.ts +1 -0
  70. package/docs/development/basic/add-new-ai-image-model.mdx +0 -36
  71. package/docs/development/basic/add-new-ai-image-model.zh-CN.mdx +0 -0
  72. package/src/config/paramsSchemas/fal/flux-kontext-dev.ts +0 -8
  73. package/src/config/paramsSchemas/fal/flux-pro-kontext.ts +0 -11
  74. package/src/config/paramsSchemas/fal/flux-schnell.ts +0 -9
  75. package/src/config/paramsSchemas/fal/imagen4.ts +0 -10
  76. package/src/config/paramsSchemas/openai/gpt-image-1.ts +0 -10
  77. package/src/libs/standard-parameters/meta-schema.ts +0 -147
  78. /package/apps/desktop/src/main/core/{I18nManager.ts → infrastructure/I18nManager.ts} +0 -0
  79. /package/apps/desktop/src/main/core/{IoCContainer.ts → infrastructure/IoCContainer.ts} +0 -0
@@ -1 +1,152 @@
1
- export * from './meta-schema';
1
+ import type { Simplify } from 'type-fest';
2
+ import { z } from 'zod';
3
+
4
+ export const MAX_SEED = 2 ** 31 - 1;
5
+
6
+ // 定义顶层的元规范 - 平铺结构
7
+ export const ModelParamsMetaSchema = z.object({
8
+ aspectRatio: z
9
+ .object({
10
+ default: z.string(),
11
+ description: z.string().optional(),
12
+ enum: z.array(z.string()),
13
+ type: z.literal('string').optional(),
14
+ })
15
+ .optional(),
16
+
17
+ cfg: z
18
+ .object({
19
+ default: z.number(),
20
+ description: z.string().optional(),
21
+ max: z.number(),
22
+ min: z.number(),
23
+ step: z.number(),
24
+ type: z.literal('number').optional(),
25
+ })
26
+ .optional(),
27
+
28
+ height: z
29
+ .object({
30
+ default: z.number(),
31
+ description: z.string().optional(),
32
+ max: z.number(),
33
+ min: z.number(),
34
+ step: z.number().optional().default(1),
35
+ type: z.literal('number').optional(),
36
+ })
37
+ .optional(),
38
+
39
+ imageUrl: z
40
+ .object({
41
+ default: z.string().nullable().optional(),
42
+ description: z.string().optional(),
43
+ type: z.tuple([z.literal('string'), z.literal('null')]).optional(),
44
+ })
45
+ .optional(),
46
+
47
+ imageUrls: z
48
+ .object({
49
+ default: z.array(z.string()),
50
+ description: z.string().optional(),
51
+ type: z.literal('array').optional(),
52
+ })
53
+ .optional(),
54
+
55
+ /**
56
+ * Prompt 是唯一一个每个模型都有的参数
57
+ */
58
+ prompt: z.object({
59
+ default: z.string().optional().default(''),
60
+ description: z.string().optional(),
61
+ type: z.literal('string').optional(),
62
+ }),
63
+
64
+ seed: z
65
+ .object({
66
+ default: z.number().nullable().default(null),
67
+ description: z.string().optional(),
68
+ max: z.number().optional().default(MAX_SEED),
69
+ min: z.number().optional().default(0),
70
+ type: z.tuple([z.literal('number'), z.literal('null')]).optional(),
71
+ })
72
+ .optional(),
73
+
74
+ size: z
75
+ .object({
76
+ default: z.string(),
77
+ description: z.string().optional(),
78
+ enum: z.array(z.string()),
79
+ type: z.literal('string').optional(),
80
+ })
81
+ .optional(),
82
+
83
+ steps: z
84
+ .object({
85
+ default: z.number(),
86
+ description: z.string().optional(),
87
+ max: z.number(),
88
+ min: z.number(),
89
+ step: z.number().optional().default(1),
90
+ type: z.literal('number').optional(),
91
+ })
92
+ .optional(),
93
+
94
+ width: z
95
+ .object({
96
+ default: z.number(),
97
+ description: z.string().optional(),
98
+ max: z.number(),
99
+ min: z.number(),
100
+ step: z.number().optional().default(1),
101
+ type: z.literal('number').optional(),
102
+ })
103
+ .optional(),
104
+ });
105
+ // 导出推断出的类型,供定义对象使用
106
+ export type ModelParamsSchema = z.input<typeof ModelParamsMetaSchema>;
107
+ export type ModelParamsOutputSchema = z.output<typeof ModelParamsMetaSchema>;
108
+ export type ModelParamsKeys = Simplify<keyof ModelParamsOutputSchema>;
109
+
110
+ type TypeMapping<T> = T extends 'string'
111
+ ? string
112
+ : T extends 'number'
113
+ ? number
114
+ : T extends ['number', 'null']
115
+ ? number | null
116
+ : T extends ['string', 'null']
117
+ ? string | null
118
+ : T extends 'string'
119
+ ? string
120
+ : T extends 'boolean'
121
+ ? boolean
122
+ : never;
123
+ type TypeType<K extends ModelParamsKeys> = NonNullable<ModelParamsOutputSchema[K]>['type'];
124
+ type DefaultType<K extends ModelParamsKeys> = NonNullable<ModelParamsOutputSchema[K]>['default'];
125
+ type _StandardImageGenerationParameters<P extends ModelParamsKeys = ModelParamsKeys> = {
126
+ [key in P]: NonNullable<TypeType<key>> extends 'array'
127
+ ? DefaultType<key>
128
+ : TypeMapping<TypeType<key>>;
129
+ };
130
+
131
+ export type RuntimeImageGenParams = Pick<_StandardImageGenerationParameters, 'prompt'> &
132
+ Partial<Omit<_StandardImageGenerationParameters, 'prompt'>>;
133
+ export type RuntimeImageGenParamsKeys = keyof RuntimeImageGenParams;
134
+ export type RuntimeImageGenParamsValue = RuntimeImageGenParams[RuntimeImageGenParamsKeys];
135
+
136
+ // 验证函数
137
+ export function validateModelParamsSchema(paramsSchema: unknown): ModelParamsOutputSchema {
138
+ return ModelParamsMetaSchema.parse(paramsSchema);
139
+ }
140
+
141
+ /**
142
+ * 从参数定义对象提取默认值
143
+ */
144
+ export function extractDefaultValues(paramsSchema: ModelParamsSchema) {
145
+ // 部分默认值从 ModelParamsMetaSchema 中获取
146
+ const schemaWithDefault = ModelParamsMetaSchema.parse(paramsSchema);
147
+ return Object.fromEntries(
148
+ Object.entries(schemaWithDefault).map(([key, value]) => {
149
+ return [key, value.default];
150
+ }),
151
+ ) as RuntimeImageGenParams;
152
+ }
@@ -1,6 +1,7 @@
1
1
  // @vitest-environment node
2
2
  import { describe, expect, it } from 'vitest';
3
3
 
4
+ import { BRANDING_NAME } from '@/const/branding';
4
5
  import { DEFAULT_LANG } from '@/const/locale';
5
6
 
6
7
  import { AUTHOR_LIST, Ld } from './ld';
@@ -57,7 +58,7 @@ describe('Ld', () => {
57
58
  });
58
59
 
59
60
  expect(webpage['@type']).toBe('WebPage');
60
- expect(webpage.name).toBe('Test Page · LobeChat');
61
+ expect(webpage.name).toBe(`Test Page · ${BRANDING_NAME}`);
61
62
  expect(webpage.description).toBe('Test Description');
62
63
  });
63
64
  });
@@ -79,7 +80,7 @@ describe('Ld', () => {
79
80
  const website = ld.genWebSite();
80
81
 
81
82
  expect(website['@type']).toBe('WebSite');
82
- expect(website.name).toBe('LobeChat');
83
+ expect(website.name).toBe(BRANDING_NAME);
83
84
  });
84
85
  });
85
86
 
@@ -95,7 +96,7 @@ describe('Ld', () => {
95
96
  });
96
97
 
97
98
  expect(article['@type']).toBe('Article');
98
- expect(article.headline).toBe('Test Article · LobeChat');
99
+ expect(article.headline).toBe(`Test Article · ${BRANDING_NAME}`);
99
100
  expect(article.author['@type']).toBe('Person');
100
101
  });
101
102
  });
@@ -5,7 +5,7 @@ import { ASYNC_TASK_TIMEOUT, AsyncTaskModel } from '@/database/models/asyncTask'
5
5
  import { FileModel } from '@/database/models/file';
6
6
  import { GenerationModel } from '@/database/models/generation';
7
7
  import { AgentRuntimeErrorType } from '@/libs/model-runtime/error';
8
- import { RuntimeImageGenParams } from '@/libs/standard-parameters/meta-schema';
8
+ import { RuntimeImageGenParams } from '@/libs/standard-parameters/index';
9
9
  import { asyncAuthedProcedure, asyncRouter as router } from '@/libs/trpc/async';
10
10
  import { initAgentRuntimeWithUserPayload } from '@/server/modules/AgentRuntime';
11
11
  import { GenerationService } from '@/server/services/generation';
@@ -4,6 +4,7 @@ import { merge } from 'lodash-es';
4
4
  import OpenAI from 'openai';
5
5
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
6
6
 
7
+ import { DEFAULT_USER_AVATAR } from '@/const/meta';
7
8
  import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
8
9
  import {
9
10
  LobeAnthropicAI,
@@ -31,8 +32,6 @@ import { aiModelSelectors } from '@/store/aiInfra';
31
32
  import { useToolStore } from '@/store/tool';
32
33
  import { toolSelectors } from '@/store/tool/selectors';
33
34
  import { UserStore } from '@/store/user';
34
- import { useUserStore } from '@/store/user';
35
- import { modelConfigSelectors } from '@/store/user/selectors';
36
35
  import { UserSettingsState, initialSettingsState } from '@/store/user/slices/settings/initialState';
37
36
  import { DalleManifest } from '@/tools/dalle';
38
37
  import { WebBrowsingManifest } from '@/tools/web-browsing';
@@ -671,7 +670,7 @@ describe('ChatService', () => {
671
670
  updatedAt: 1702723964330,
672
671
  extra: {},
673
672
  meta: {
674
- avatar: '😀',
673
+ avatar: DEFAULT_USER_AVATAR,
675
674
  },
676
675
  },
677
676
  ] as ChatMessage[];
@@ -913,7 +912,7 @@ describe('ChatService', () => {
913
912
  updatedAt: 1702723964330,
914
913
  extra: {},
915
914
  meta: {
916
- avatar: '😀',
915
+ avatar: DEFAULT_USER_AVATAR,
917
916
  },
918
917
  },
919
918
  ] as ChatMessage[];
@@ -10,7 +10,6 @@ import { messageMapKey } from '@/store/chat/utils/messageMapKey';
10
10
  import { createServerConfigStore } from '@/store/serverConfig/store';
11
11
  import { LobeAgentConfig } from '@/types/agent';
12
12
  import { ChatMessage } from '@/types/message';
13
- import { MetaData } from '@/types/meta';
14
13
  import { merge } from '@/utils/merge';
15
14
 
16
15
  import { chatSelectors } from './selectors';
@@ -91,7 +90,7 @@ const mockedChats = [
91
90
  content: 'Function Message',
92
91
  role: 'tool',
93
92
  meta: {
94
- avatar: '🤯',
93
+ avatar: DEFAULT_INBOX_AVATAR,
95
94
  backgroundColor: 'rgba(0,0,0,0)',
96
95
  description: 'inbox.desc',
97
96
  title: 'inbox.title',
@@ -234,7 +233,7 @@ describe('chatSelectors', () => {
234
233
  content: 'Function Message',
235
234
  role: 'tool',
236
235
  meta: {
237
- avatar: '🤯',
236
+ avatar: DEFAULT_INBOX_AVATAR,
238
237
  backgroundColor: 'rgba(0,0,0,0)',
239
238
  description: 'inbox.desc',
240
239
  title: 'inbox.title',
@@ -2,6 +2,7 @@ import { act, renderHook } from '@testing-library/react';
2
2
  import { Mock, afterEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
4
  import { LOADING_FLAT } from '@/const/message';
5
+ import { DEFAULT_INBOX_AVATAR } from '@/const/meta';
5
6
  import { PLUGIN_SCHEMA_API_MD5_PREFIX, PLUGIN_SCHEMA_SEPARATOR } from '@/const/plugin';
6
7
  import { chatService } from '@/services/chat';
7
8
  import { messageService } from '@/services/message';
@@ -66,7 +67,7 @@ describe('ChatPluginAction', () => {
66
67
  {
67
68
  ...toolMessage,
68
69
  meta: {
69
- avatar: '🤯',
70
+ avatar: DEFAULT_INBOX_AVATAR,
70
71
  backgroundColor: 'rgba(0,0,0,0)',
71
72
  description: undefined,
72
73
  title: undefined,
@@ -1,12 +1,12 @@
1
1
  import { act, renderHook } from '@testing-library/react';
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
- import { fluxSchnellParamsSchema } from '@/config/paramsSchemas/fal/flux-schnell';
4
+ import { fluxSchnellParamsSchema } from '@/config/aiModels/fal';
5
5
  import {
6
6
  ModelParamsSchema,
7
7
  RuntimeImageGenParams,
8
8
  extractDefaultValues,
9
- } from '@/libs/standard-parameters/meta-schema';
9
+ } from '@/libs/standard-parameters/index';
10
10
  import { useImageStore } from '@/store/image';
11
11
  import { AIImageModelCard } from '@/types/aiModel';
12
12
 
@@ -6,7 +6,7 @@ import {
6
6
  RuntimeImageGenParamsKeys,
7
7
  RuntimeImageGenParamsValue,
8
8
  extractDefaultValues,
9
- } from '@/libs/standard-parameters/meta-schema';
9
+ } from '@/libs/standard-parameters/index';
10
10
  import { aiProviderSelectors, getAiInfraStoreState } from '@/store/aiInfra';
11
11
  import { AIImageModelCard } from '@/types/aiModel';
12
12
 
@@ -1,8 +1,8 @@
1
1
  import { act, renderHook } from '@testing-library/react';
2
2
  import { describe, expect, it, vi } from 'vitest';
3
3
 
4
- import { fluxSchnellParamsSchema } from '@/config/paramsSchemas/fal/flux-schnell';
5
- import { ModelParamsSchema, RuntimeImageGenParams } from '@/libs/standard-parameters/meta-schema';
4
+ import { fluxSchnellParamsSchema } from '@/config/aiModels/fal';
5
+ import { ModelParamsSchema, RuntimeImageGenParams } from '@/libs/standard-parameters/index';
6
6
  import { useImageStore } from '@/store/image';
7
7
  import { AIImageModelCard } from '@/types/aiModel';
8
8
 
@@ -1,10 +1,7 @@
1
1
  import { useCallback, useMemo } from 'react';
2
2
 
3
3
  import { DEFAULT_ASPECT_RATIO, PRESET_ASPECT_RATIOS } from '@/const/image';
4
- import {
5
- RuntimeImageGenParams,
6
- RuntimeImageGenParamsKeys,
7
- } from '@/libs/standard-parameters/meta-schema';
4
+ import { RuntimeImageGenParams, RuntimeImageGenParamsKeys } from '@/libs/standard-parameters/index';
8
5
 
9
6
  import { useImageStore } from '../../store';
10
7
  import { imageGenerationConfigSelectors } from './selectors';
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable sort-keys-fix/sort-keys-fix, typescript-sort-keys/interface */
2
- import { gptImage1ParamsSchema } from '@/config/paramsSchemas/openai/gpt-image-1';
2
+ import { gptImage1ParamsSchema } from '@/config/aiModels/openai';
3
3
  import { ModelProvider } from '@/libs/model-runtime/types/type';
4
4
  import {
5
5
  ModelParamsSchema,
6
6
  RuntimeImageGenParams,
7
7
  extractDefaultValues,
8
- } from '@/libs/standard-parameters/meta-schema';
8
+ } from '@/libs/standard-parameters/index';
9
9
 
10
10
  export const DEFAULT_AI_IMAGE_PROVIDER = ModelProvider.OpenAI;
11
11
  export const DEFAULT_AI_IMAGE_MODEL = 'gpt-image-1';
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, it, vi } from 'vitest';
2
2
 
3
- import { gptImage1ParamsSchema } from '@/config/paramsSchemas/openai/gpt-image-1';
4
- import { ModelParamsSchema, RuntimeImageGenParams } from '@/libs/standard-parameters/meta-schema';
3
+ import { gptImage1ParamsSchema } from '@/config/aiModels/openai';
4
+ import { ModelParamsSchema, RuntimeImageGenParams } from '@/libs/standard-parameters/index';
5
5
  import { ImageStore } from '@/store/image';
6
6
  import { initialState } from '@/store/image/initialState';
7
7
  import { AIImageModelCard } from '@/types/aiModel';
@@ -1,4 +1,4 @@
1
- import { RuntimeImageGenParamsKeys } from '@/libs/standard-parameters/meta-schema';
1
+ import { RuntimeImageGenParamsKeys } from '@/libs/standard-parameters/index';
2
2
 
3
3
  import { GenerationConfigState } from './initialState';
4
4
 
@@ -1,6 +1,7 @@
1
1
  import { t } from 'i18next';
2
2
  import { afterEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
+ import { BRANDING_NAME } from '@/const/branding';
4
5
  import { UserStore } from '@/store/user';
5
6
 
6
7
  import { authSelectors, userProfileSelectors } from './selectors';
@@ -44,7 +45,7 @@ describe('userProfileSelectors', () => {
44
45
  enableAuth: () => false,
45
46
  } as unknown as UserStore;
46
47
 
47
- expect(userProfileSelectors.displayUserName(store)).toBe('LobeChat');
48
+ expect(userProfileSelectors.displayUserName(store)).toBe(BRANDING_NAME);
48
49
  });
49
50
 
50
51
  it('should return user username when auth is disabled and is desktop', () => {
@@ -202,7 +203,7 @@ describe('userProfileSelectors', () => {
202
203
  enableAuth: () => false,
203
204
  } as unknown as UserStore;
204
205
 
205
- expect(userProfileSelectors.username(store)).toBe('LobeChat');
206
+ expect(userProfileSelectors.username(store)).toBe(BRANDING_NAME);
206
207
  });
207
208
 
208
209
  it('should return user username when auth is disabled and is desktop', () => {
@@ -39,6 +39,7 @@ export type GenerationAsset = ImageGenerationAsset;
39
39
 
40
40
  export interface GenerationConfig {
41
41
  prompt: string;
42
+ imageUrl?: string | null;
42
43
  imageUrls?: string[];
43
44
  width?: number;
44
45
  height?: number;
@@ -1,36 +0,0 @@
1
- # 添加新的 AI 图像模型
2
-
3
- ## 兼容 openai 请求格式的模型
4
-
5
- 指的是可以使用 openai SDK 进行请求,并且请求参数和和返回值和 dall-e 以及 gpt-image-x 系列一致。
6
-
7
- 以智谱的 CogView-4 为例,它是一个兼容 openai 请求格式的模型,可以按照以下步骤添加:
8
-
9
- 1. 在对应的 ai models 文件 `src/config/aiModels/zhipu.ts` 中,添加模型配置,例如:
10
-
11
- ```ts
12
- const zhipuImageModels: AIImageModelCard[] = [
13
- // 添加模型配置
14
- // https://bigmodel.cn/dev/howuse/image-generation-model/cogview-4
15
- {
16
- description:
17
- 'CogView-4 是智谱首个支持生成汉字的开源文生图模型,在语义理解、图像生成质量、中英文字生成能力等方面全面提升,支持任意长度的中英双语输入,能够生成在给定范围内的任意分辨率图像。',
18
- displayName: 'CogView-4',
19
- enabled: true,
20
- id: 'cogview-4',
21
- parameters: {
22
- prompt: {
23
- default: '',
24
- },
25
- size: {
26
- default: '1024x1024',
27
- enum: ['1024x1024', '768x1344', '864x1152', '1344x768', '1152x864', '1440x720', '720x1440'],
28
- },
29
- },
30
- releasedAt: '2025-03-04',
31
- type: 'image',
32
- },
33
- ];
34
- ```
35
-
36
- 2. 执行下 `npx i18n` 命令,更新模型描述的翻译文件
@@ -1,8 +0,0 @@
1
- import { type ModelParamsSchema } from '@/libs/standard-parameters/meta-schema';
2
-
3
- export const fluxKontextDevParamsSchema: ModelParamsSchema = {
4
- imageUrl: { default: null },
5
- prompt: { default: '' },
6
- seed: { default: null },
7
- steps: { default: 28, max: 50, min: 10 },
8
- };
@@ -1,11 +0,0 @@
1
- import { type ModelParamsSchema } from '@/libs/standard-parameters/meta-schema';
2
-
3
- export const fluxProKontextParamsSchema: ModelParamsSchema = {
4
- aspectRatio: {
5
- default: '1:1',
6
- enum: ['21:9', '16:9', '4:3', '3:2', '1:1', '2:3', '3:4', '9:16', '9:21'],
7
- },
8
- imageUrl: { default: null },
9
- prompt: { default: '' },
10
- seed: { default: null },
11
- };
@@ -1,9 +0,0 @@
1
- import { type ModelParamsSchema } from '@/libs/standard-parameters/meta-schema';
2
-
3
- export const fluxSchnellParamsSchema: ModelParamsSchema = {
4
- height: { default: 1024, max: 1536, min: 512, step: 1 },
5
- prompt: { default: '' },
6
- seed: { default: null },
7
- steps: { default: 4, max: 12, min: 1 },
8
- width: { default: 1024, max: 1536, min: 512, step: 1 },
9
- };
@@ -1,10 +0,0 @@
1
- import { type ModelParamsSchema } from '@/libs/standard-parameters/meta-schema';
2
-
3
- export const imagen4ParamsSchema: ModelParamsSchema = {
4
- aspectRatio: {
5
- default: '1:1',
6
- enum: ['1:1', '16:9', '9:16', '3:4', '4:3'],
7
- },
8
- prompt: { default: '' },
9
- seed: { default: null },
10
- };
@@ -1,10 +0,0 @@
1
- import { type ModelParamsSchema } from '@/libs/standard-parameters/meta-schema';
2
-
3
- export const gptImage1ParamsSchema: ModelParamsSchema = {
4
- imageUrls: { default: [] },
5
- prompt: { default: '' },
6
- size: {
7
- default: 'auto',
8
- enum: ['auto', '1024x1024', '1536x1024', '1024x1536'],
9
- },
10
- };
@@ -1,147 +0,0 @@
1
- import type { Simplify } from 'type-fest';
2
- import { z } from 'zod';
3
-
4
- export const MAX_SEED = 2 ** 31 - 1;
5
-
6
- // 定义顶层的元规范 - 平铺结构
7
- export const ModelParamsMetaSchema = z.object({
8
- aspectRatio: z
9
- .object({
10
- default: z.string(),
11
- description: z.string().optional(),
12
- enum: z.array(z.string()),
13
- type: z.literal('string').optional(),
14
- })
15
- .optional(),
16
-
17
- cfg: z
18
- .object({
19
- default: z.number(),
20
- description: z.string().optional(),
21
- max: z.number(),
22
- min: z.number(),
23
- step: z.number(),
24
- type: z.literal('number').optional(),
25
- })
26
- .optional(),
27
-
28
- height: z
29
- .object({
30
- default: z.number(),
31
- description: z.string().optional(),
32
- max: z.number(),
33
- min: z.number(),
34
- step: z.number().optional().default(1),
35
- type: z.literal('number').optional(),
36
- })
37
- .optional(),
38
-
39
- imageUrl: z
40
- .object({
41
- default: z.string().nullable().optional(),
42
- description: z.string().optional(),
43
- type: z.tuple([z.literal('string'), z.literal('null')]).optional(),
44
- })
45
- .optional(),
46
-
47
- imageUrls: z
48
- .object({
49
- default: z.array(z.string()),
50
- description: z.string().optional(),
51
- type: z.literal('array').optional(),
52
- })
53
- .optional(),
54
- /**
55
- * Prompt 是唯一一个每个模型都有的参数
56
- */
57
- prompt: z.object({
58
- default: z.string().optional().default(''),
59
- description: z.string().optional(),
60
- type: z.literal('string').optional(),
61
- }),
62
- seed: z
63
- .object({
64
- default: z.number().nullable().default(null),
65
- description: z.string().optional(),
66
- max: z.number().optional().default(MAX_SEED),
67
- min: z.number().optional().default(0),
68
- type: z.tuple([z.literal('number'), z.literal('null')]).optional(),
69
- })
70
- .optional(),
71
- size: z
72
- .object({
73
- default: z.string(),
74
- description: z.string().optional(),
75
- enum: z.array(z.string()),
76
- type: z.literal('string').optional(),
77
- })
78
- .optional(),
79
- steps: z
80
- .object({
81
- default: z.number(),
82
- description: z.string().optional(),
83
- max: z.number(),
84
- min: z.number(),
85
- step: z.number().optional().default(1),
86
- type: z.literal('number').optional(),
87
- })
88
- .optional(),
89
- width: z
90
- .object({
91
- default: z.number(),
92
- description: z.string().optional(),
93
- max: z.number(),
94
- min: z.number(),
95
- step: z.number().optional().default(1),
96
- type: z.literal('number').optional(),
97
- })
98
- .optional(),
99
- });
100
- // 导出推断出的类型,供定义对象使用
101
- export type ModelParamsSchema = z.input<typeof ModelParamsMetaSchema>;
102
- export type ModelParamsOutputSchema = z.output<typeof ModelParamsMetaSchema>;
103
- export type ModelParamsKeys = Simplify<keyof ModelParamsOutputSchema>;
104
-
105
- type TypeMapping<T> = T extends 'string'
106
- ? string
107
- : T extends 'number'
108
- ? number
109
- : T extends ['number', 'null']
110
- ? number | null
111
- : T extends ['string', 'null']
112
- ? string | null
113
- : T extends 'string'
114
- ? string
115
- : T extends 'boolean'
116
- ? boolean
117
- : never;
118
- type TypeType<K extends ModelParamsKeys> = NonNullable<ModelParamsOutputSchema[K]>['type'];
119
- type DefaultType<K extends ModelParamsKeys> = NonNullable<ModelParamsOutputSchema[K]>['default'];
120
- type _StandardImageGenerationParameters<P extends ModelParamsKeys = ModelParamsKeys> = {
121
- [key in P]: NonNullable<TypeType<key>> extends 'array'
122
- ? DefaultType<key>
123
- : TypeMapping<TypeType<key>>;
124
- };
125
-
126
- export type RuntimeImageGenParams = Pick<_StandardImageGenerationParameters, 'prompt'> &
127
- Partial<Omit<_StandardImageGenerationParameters, 'prompt'>>;
128
- export type RuntimeImageGenParamsKeys = keyof RuntimeImageGenParams;
129
- export type RuntimeImageGenParamsValue = RuntimeImageGenParams[RuntimeImageGenParamsKeys];
130
-
131
- // 验证函数
132
- export function validateModelParamsSchema(paramsSchema: unknown): ModelParamsOutputSchema {
133
- return ModelParamsMetaSchema.parse(paramsSchema);
134
- }
135
-
136
- /**
137
- * 从参数定义对象提取默认值
138
- */
139
- export function extractDefaultValues(paramsSchema: ModelParamsSchema) {
140
- // 部分默认值从 ModelParamsMetaSchema 中获取
141
- const schemaWithDefault = ModelParamsMetaSchema.parse(paramsSchema);
142
- return Object.fromEntries(
143
- Object.entries(schemaWithDefault).map(([key, value]) => {
144
- return [key, value.default];
145
- }),
146
- ) as RuntimeImageGenParams;
147
- }