@lobehub/chat 1.98.2 → 1.99.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 (456) hide show
  1. package/.cursor/rules/backend-architecture.mdc +93 -17
  2. package/.cursor/rules/cursor-ux.mdc +45 -35
  3. package/.cursor/rules/project-introduce.mdc +72 -6
  4. package/.cursor/rules/rules-attach.mdc +16 -7
  5. package/.eslintrc.js +10 -0
  6. package/CHANGELOG.md +27 -0
  7. package/apps/desktop/README.md +7 -0
  8. package/apps/desktop/electron-builder.js +5 -0
  9. package/apps/desktop/package.json +2 -1
  10. package/apps/desktop/src/main/const/dir.ts +3 -0
  11. package/apps/desktop/src/main/controllers/UploadFileCtr.ts +13 -8
  12. package/apps/desktop/src/main/core/App.ts +8 -0
  13. package/apps/desktop/src/main/core/StaticFileServerManager.ts +221 -0
  14. package/apps/desktop/src/main/services/fileSrv.ts +231 -44
  15. package/apps/desktop/src/main/utils/next-electron-rsc.ts +36 -5
  16. package/changelog/v1.json +9 -0
  17. package/docs/development/database-schema.dbml +70 -0
  18. package/locales/ar/common.json +2 -0
  19. package/locales/ar/components.json +35 -0
  20. package/locales/ar/error.json +2 -0
  21. package/locales/ar/image.json +100 -0
  22. package/locales/ar/metadata.json +4 -0
  23. package/locales/ar/modelProvider.json +1 -0
  24. package/locales/ar/models.json +15 -0
  25. package/locales/ar/plugin.json +22 -0
  26. package/locales/ar/providers.json +3 -0
  27. package/locales/ar/setting.json +5 -0
  28. package/locales/bg-BG/common.json +2 -0
  29. package/locales/bg-BG/components.json +35 -0
  30. package/locales/bg-BG/error.json +2 -0
  31. package/locales/bg-BG/image.json +100 -0
  32. package/locales/bg-BG/metadata.json +4 -0
  33. package/locales/bg-BG/modelProvider.json +1 -0
  34. package/locales/bg-BG/models.json +15 -0
  35. package/locales/bg-BG/plugin.json +22 -0
  36. package/locales/bg-BG/providers.json +3 -0
  37. package/locales/bg-BG/setting.json +5 -0
  38. package/locales/de-DE/common.json +2 -0
  39. package/locales/de-DE/components.json +35 -0
  40. package/locales/de-DE/error.json +2 -0
  41. package/locales/de-DE/image.json +100 -0
  42. package/locales/de-DE/metadata.json +4 -0
  43. package/locales/de-DE/modelProvider.json +1 -0
  44. package/locales/de-DE/models.json +15 -0
  45. package/locales/de-DE/plugin.json +22 -0
  46. package/locales/de-DE/providers.json +3 -0
  47. package/locales/de-DE/setting.json +5 -0
  48. package/locales/en-US/common.json +2 -0
  49. package/locales/en-US/components.json +35 -0
  50. package/locales/en-US/error.json +2 -0
  51. package/locales/en-US/image.json +100 -0
  52. package/locales/en-US/metadata.json +4 -0
  53. package/locales/en-US/modelProvider.json +1 -0
  54. package/locales/en-US/models.json +15 -0
  55. package/locales/en-US/plugin.json +22 -0
  56. package/locales/en-US/providers.json +3 -0
  57. package/locales/en-US/setting.json +5 -0
  58. package/locales/es-ES/common.json +2 -0
  59. package/locales/es-ES/components.json +35 -0
  60. package/locales/es-ES/error.json +2 -0
  61. package/locales/es-ES/image.json +100 -0
  62. package/locales/es-ES/metadata.json +4 -0
  63. package/locales/es-ES/modelProvider.json +1 -0
  64. package/locales/es-ES/models.json +15 -0
  65. package/locales/es-ES/plugin.json +22 -0
  66. package/locales/es-ES/providers.json +3 -0
  67. package/locales/es-ES/setting.json +5 -0
  68. package/locales/fa-IR/common.json +2 -0
  69. package/locales/fa-IR/components.json +35 -0
  70. package/locales/fa-IR/error.json +2 -0
  71. package/locales/fa-IR/image.json +100 -0
  72. package/locales/fa-IR/metadata.json +4 -0
  73. package/locales/fa-IR/modelProvider.json +1 -0
  74. package/locales/fa-IR/models.json +15 -0
  75. package/locales/fa-IR/plugin.json +22 -0
  76. package/locales/fa-IR/providers.json +3 -0
  77. package/locales/fa-IR/setting.json +5 -0
  78. package/locales/fr-FR/common.json +2 -0
  79. package/locales/fr-FR/components.json +35 -0
  80. package/locales/fr-FR/error.json +2 -0
  81. package/locales/fr-FR/image.json +100 -0
  82. package/locales/fr-FR/metadata.json +4 -0
  83. package/locales/fr-FR/modelProvider.json +1 -0
  84. package/locales/fr-FR/models.json +15 -0
  85. package/locales/fr-FR/plugin.json +22 -0
  86. package/locales/fr-FR/providers.json +3 -0
  87. package/locales/fr-FR/setting.json +5 -0
  88. package/locales/it-IT/common.json +2 -0
  89. package/locales/it-IT/components.json +35 -0
  90. package/locales/it-IT/error.json +2 -0
  91. package/locales/it-IT/image.json +100 -0
  92. package/locales/it-IT/metadata.json +4 -0
  93. package/locales/it-IT/modelProvider.json +1 -0
  94. package/locales/it-IT/models.json +15 -0
  95. package/locales/it-IT/plugin.json +22 -0
  96. package/locales/it-IT/providers.json +3 -0
  97. package/locales/it-IT/setting.json +5 -0
  98. package/locales/ja-JP/common.json +2 -0
  99. package/locales/ja-JP/components.json +35 -0
  100. package/locales/ja-JP/error.json +2 -0
  101. package/locales/ja-JP/image.json +100 -0
  102. package/locales/ja-JP/metadata.json +4 -0
  103. package/locales/ja-JP/modelProvider.json +1 -0
  104. package/locales/ja-JP/models.json +15 -0
  105. package/locales/ja-JP/plugin.json +22 -0
  106. package/locales/ja-JP/providers.json +3 -0
  107. package/locales/ja-JP/setting.json +5 -0
  108. package/locales/ko-KR/common.json +2 -0
  109. package/locales/ko-KR/components.json +35 -0
  110. package/locales/ko-KR/error.json +2 -0
  111. package/locales/ko-KR/image.json +100 -0
  112. package/locales/ko-KR/metadata.json +4 -0
  113. package/locales/ko-KR/modelProvider.json +1 -0
  114. package/locales/ko-KR/models.json +15 -0
  115. package/locales/ko-KR/plugin.json +22 -0
  116. package/locales/ko-KR/providers.json +3 -0
  117. package/locales/ko-KR/setting.json +5 -0
  118. package/locales/nl-NL/common.json +2 -0
  119. package/locales/nl-NL/components.json +35 -0
  120. package/locales/nl-NL/error.json +2 -0
  121. package/locales/nl-NL/image.json +100 -0
  122. package/locales/nl-NL/metadata.json +4 -0
  123. package/locales/nl-NL/modelProvider.json +1 -0
  124. package/locales/nl-NL/models.json +15 -0
  125. package/locales/nl-NL/plugin.json +22 -0
  126. package/locales/nl-NL/providers.json +3 -0
  127. package/locales/nl-NL/setting.json +5 -0
  128. package/locales/pl-PL/common.json +2 -0
  129. package/locales/pl-PL/components.json +35 -0
  130. package/locales/pl-PL/error.json +2 -0
  131. package/locales/pl-PL/image.json +100 -0
  132. package/locales/pl-PL/metadata.json +4 -0
  133. package/locales/pl-PL/modelProvider.json +1 -0
  134. package/locales/pl-PL/models.json +15 -0
  135. package/locales/pl-PL/plugin.json +22 -0
  136. package/locales/pl-PL/providers.json +3 -0
  137. package/locales/pl-PL/setting.json +5 -0
  138. package/locales/pt-BR/common.json +2 -0
  139. package/locales/pt-BR/components.json +35 -0
  140. package/locales/pt-BR/error.json +2 -0
  141. package/locales/pt-BR/image.json +100 -0
  142. package/locales/pt-BR/metadata.json +4 -0
  143. package/locales/pt-BR/modelProvider.json +1 -0
  144. package/locales/pt-BR/models.json +15 -0
  145. package/locales/pt-BR/plugin.json +22 -0
  146. package/locales/pt-BR/providers.json +3 -0
  147. package/locales/pt-BR/setting.json +5 -0
  148. package/locales/ru-RU/common.json +2 -0
  149. package/locales/ru-RU/components.json +35 -0
  150. package/locales/ru-RU/error.json +2 -0
  151. package/locales/ru-RU/image.json +100 -0
  152. package/locales/ru-RU/metadata.json +4 -0
  153. package/locales/ru-RU/modelProvider.json +1 -0
  154. package/locales/ru-RU/models.json +15 -0
  155. package/locales/ru-RU/plugin.json +22 -0
  156. package/locales/ru-RU/providers.json +3 -0
  157. package/locales/ru-RU/setting.json +5 -0
  158. package/locales/tr-TR/common.json +2 -0
  159. package/locales/tr-TR/components.json +35 -0
  160. package/locales/tr-TR/error.json +2 -0
  161. package/locales/tr-TR/image.json +100 -0
  162. package/locales/tr-TR/metadata.json +4 -0
  163. package/locales/tr-TR/modelProvider.json +1 -0
  164. package/locales/tr-TR/models.json +15 -0
  165. package/locales/tr-TR/plugin.json +22 -0
  166. package/locales/tr-TR/providers.json +3 -0
  167. package/locales/tr-TR/setting.json +5 -0
  168. package/locales/vi-VN/common.json +2 -0
  169. package/locales/vi-VN/components.json +35 -0
  170. package/locales/vi-VN/error.json +2 -0
  171. package/locales/vi-VN/image.json +100 -0
  172. package/locales/vi-VN/metadata.json +4 -0
  173. package/locales/vi-VN/modelProvider.json +1 -0
  174. package/locales/vi-VN/models.json +15 -0
  175. package/locales/vi-VN/plugin.json +22 -0
  176. package/locales/vi-VN/providers.json +3 -0
  177. package/locales/vi-VN/setting.json +5 -0
  178. package/locales/zh-CN/common.json +2 -0
  179. package/locales/zh-CN/components.json +35 -0
  180. package/locales/zh-CN/error.json +2 -0
  181. package/locales/zh-CN/image.json +100 -0
  182. package/locales/zh-CN/metadata.json +4 -0
  183. package/locales/zh-CN/modelProvider.json +1 -0
  184. package/locales/zh-CN/models.json +15 -0
  185. package/locales/zh-CN/plugin.json +22 -0
  186. package/locales/zh-CN/providers.json +3 -0
  187. package/locales/zh-CN/setting.json +5 -0
  188. package/locales/zh-TW/common.json +2 -0
  189. package/locales/zh-TW/components.json +35 -0
  190. package/locales/zh-TW/error.json +2 -0
  191. package/locales/zh-TW/image.json +100 -0
  192. package/locales/zh-TW/metadata.json +4 -0
  193. package/locales/zh-TW/modelProvider.json +1 -0
  194. package/locales/zh-TW/models.json +15 -0
  195. package/locales/zh-TW/plugin.json +22 -0
  196. package/locales/zh-TW/providers.json +3 -0
  197. package/locales/zh-TW/setting.json +5 -0
  198. package/package.json +11 -4
  199. package/packages/electron-server-ipc/src/events/file.ts +3 -1
  200. package/packages/electron-server-ipc/src/types/file.ts +15 -0
  201. package/src/app/[variants]/(main)/_layout/Desktop/SideBar/TopActions.tsx +11 -1
  202. package/src/app/[variants]/(main)/image/@menu/components/AspectRatioSelect/index.tsx +73 -0
  203. package/src/app/[variants]/(main)/image/@menu/components/SeedNumberInput/index.tsx +39 -0
  204. package/src/app/[variants]/(main)/image/@menu/components/SizeSelect/index.tsx +89 -0
  205. package/src/app/[variants]/(main)/image/@menu/default.tsx +11 -0
  206. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/AspectRatioSelect.tsx +24 -0
  207. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/DimensionControlGroup.tsx +107 -0
  208. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ImageNum.tsx +290 -0
  209. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ImageUpload.tsx +504 -0
  210. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ImageUrl.tsx +18 -0
  211. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ImageUrlsUpload.tsx +19 -0
  212. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ModelSelect.tsx +155 -0
  213. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/MultiImagesUpload/ImageManageModal.tsx +415 -0
  214. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/MultiImagesUpload/index.tsx +732 -0
  215. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/SeedNumberInput.tsx +24 -0
  216. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/SizeSelect.tsx +17 -0
  217. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/SizeSliderInput.tsx +15 -0
  218. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/StepsSliderInput.tsx +11 -0
  219. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/constants.ts +1 -0
  220. package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/index.tsx +93 -0
  221. package/src/app/[variants]/(main)/image/@topic/default.tsx +17 -0
  222. package/src/app/[variants]/(main)/image/@topic/features/Topics/NewTopicButton.tsx +64 -0
  223. package/src/app/[variants]/(main)/image/@topic/features/Topics/SkeletonList.tsx +34 -0
  224. package/src/app/[variants]/(main)/image/@topic/features/Topics/TopicItem.tsx +136 -0
  225. package/src/app/[variants]/(main)/image/@topic/features/Topics/TopicItemContainer.tsx +91 -0
  226. package/src/app/[variants]/(main)/image/@topic/features/Topics/TopicList.tsx +57 -0
  227. package/src/app/[variants]/(main)/image/@topic/features/Topics/TopicUrlSync.tsx +37 -0
  228. package/src/app/[variants]/(main)/image/@topic/features/Topics/index.tsx +19 -0
  229. package/src/app/[variants]/(main)/image/NotSupportClient.tsx +153 -0
  230. package/src/app/[variants]/(main)/image/_layout/Desktop/Container.tsx +35 -0
  231. package/src/app/[variants]/(main)/image/_layout/Desktop/RegisterHotkeys.tsx +10 -0
  232. package/src/app/[variants]/(main)/image/_layout/Desktop/index.tsx +30 -0
  233. package/src/app/[variants]/(main)/image/_layout/Mobile/index.tsx +14 -0
  234. package/src/app/[variants]/(main)/image/_layout/type.ts +7 -0
  235. package/src/app/[variants]/(main)/image/features/GenerationFeed/BatchItem.tsx +196 -0
  236. package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/ActionButtons.tsx +60 -0
  237. package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/ElapsedTime.tsx +90 -0
  238. package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/ErrorState.tsx +65 -0
  239. package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/LoadingState.tsx +43 -0
  240. package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/SuccessState.tsx +49 -0
  241. package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/index.tsx +156 -0
  242. package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/styles.ts +51 -0
  243. package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/types.ts +39 -0
  244. package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/utils.ts +11 -0
  245. package/src/app/[variants]/(main)/image/features/GenerationFeed/index.tsx +97 -0
  246. package/src/app/[variants]/(main)/image/features/ImageWorkspace/Content.tsx +48 -0
  247. package/src/app/[variants]/(main)/image/features/ImageWorkspace/EmptyState.tsx +37 -0
  248. package/src/app/[variants]/(main)/image/features/ImageWorkspace/SkeletonList.tsx +50 -0
  249. package/src/app/[variants]/(main)/image/features/ImageWorkspace/index.tsx +23 -0
  250. package/src/app/[variants]/(main)/image/features/PromptInput/Title.tsx +38 -0
  251. package/src/app/[variants]/(main)/image/features/PromptInput/index.tsx +114 -0
  252. package/src/app/[variants]/(main)/image/layout.tsx +19 -0
  253. package/src/app/[variants]/(main)/image/loading.tsx +3 -0
  254. package/src/app/[variants]/(main)/image/page.tsx +47 -0
  255. package/src/app/[variants]/(main)/settings/system-agent/index.tsx +2 -1
  256. package/src/chains/summaryGenerationTitle.ts +25 -0
  257. package/src/components/ImageItem/index.tsx +9 -6
  258. package/src/{features/Conversation/Error → components/InvalidAPIKey}/APIKeyForm/Bedrock.tsx +3 -4
  259. package/src/{features/Conversation/Error → components/InvalidAPIKey}/APIKeyForm/ProviderApiKeyForm.tsx +5 -4
  260. package/src/components/InvalidAPIKey/APIKeyForm/index.tsx +108 -0
  261. package/src/{features/Conversation/Error → components/InvalidAPIKey}/APIKeyForm/useApiKey.ts +2 -1
  262. package/src/components/InvalidAPIKey/index.tsx +30 -0
  263. package/src/components/KeyValueEditor/index.tsx +203 -0
  264. package/src/components/KeyValueEditor/utils.ts +42 -0
  265. package/src/config/aiModels/fal.ts +52 -0
  266. package/src/config/aiModels/index.ts +3 -0
  267. package/src/config/aiModels/openai.ts +20 -6
  268. package/src/config/llm.ts +6 -0
  269. package/src/config/modelProviders/fal.ts +21 -0
  270. package/src/config/modelProviders/index.ts +3 -0
  271. package/src/config/paramsSchemas/fal/flux-kontext-dev.ts +8 -0
  272. package/src/config/paramsSchemas/fal/flux-pro-kontext.ts +11 -0
  273. package/src/config/paramsSchemas/fal/flux-schnell.ts +9 -0
  274. package/src/config/paramsSchemas/fal/imagen4.ts +10 -0
  275. package/src/config/paramsSchemas/openai/gpt-image-1.ts +10 -0
  276. package/src/const/hotkeys.ts +2 -2
  277. package/src/const/image.ts +6 -0
  278. package/src/const/settings/systemAgent.ts +1 -0
  279. package/src/database/client/migrations.json +27 -0
  280. package/src/database/migrations/0026_add_autovacuum_tuning.sql +2 -0
  281. package/src/database/migrations/0027_ai_image.sql +47 -0
  282. package/src/database/migrations/meta/0027_snapshot.json +6003 -0
  283. package/src/database/migrations/meta/_journal.json +7 -0
  284. package/src/database/models/__tests__/asyncTask.test.ts +7 -5
  285. package/src/database/models/__tests__/file.test.ts +287 -0
  286. package/src/database/models/__tests__/generation.test.ts +786 -0
  287. package/src/database/models/__tests__/generationBatch.test.ts +614 -0
  288. package/src/database/models/__tests__/generationTopic.test.ts +411 -0
  289. package/src/database/models/aiModel.ts +2 -0
  290. package/src/database/models/asyncTask.ts +1 -1
  291. package/src/database/models/file.ts +28 -20
  292. package/src/database/models/generation.ts +197 -0
  293. package/src/database/models/generationBatch.ts +212 -0
  294. package/src/database/models/generationTopic.ts +131 -0
  295. package/src/database/repositories/aiInfra/index.test.ts +151 -1
  296. package/src/database/repositories/aiInfra/index.ts +28 -19
  297. package/src/database/repositories/tableViewer/index.test.ts +1 -1
  298. package/src/database/schemas/file.ts +8 -0
  299. package/src/database/schemas/generation.ts +127 -0
  300. package/src/database/schemas/index.ts +1 -0
  301. package/src/database/schemas/relations.ts +45 -1
  302. package/src/database/type.ts +2 -0
  303. package/src/database/utils/idGenerator.ts +3 -0
  304. package/src/features/Conversation/Error/ChatInvalidApiKey.tsx +39 -0
  305. package/src/features/Conversation/Error/InvalidAccessCode.tsx +2 -2
  306. package/src/features/Conversation/Error/index.tsx +3 -3
  307. package/src/features/ImageSidePanel/index.tsx +83 -0
  308. package/src/features/ImageTopicPanel/index.tsx +79 -0
  309. package/src/features/PluginDevModal/MCPManifestForm/CollapsibleSection.tsx +62 -0
  310. package/src/features/PluginDevModal/MCPManifestForm/QuickImportSection.tsx +158 -0
  311. package/src/features/PluginDevModal/MCPManifestForm/index.tsx +99 -155
  312. package/src/features/PluginStore/McpList/Detail/Settings/index.tsx +5 -2
  313. package/src/hooks/useDownloadImage.ts +31 -0
  314. package/src/hooks/useFetchGenerationTopics.ts +13 -0
  315. package/src/hooks/useHotkeys/imageScope.ts +48 -0
  316. package/src/libs/mcp/client.ts +55 -22
  317. package/src/libs/mcp/types.ts +42 -6
  318. package/src/libs/model-runtime/BaseAI.ts +3 -1
  319. package/src/libs/model-runtime/ModelRuntime.test.ts +80 -0
  320. package/src/libs/model-runtime/ModelRuntime.ts +15 -1
  321. package/src/libs/model-runtime/UniformRuntime/index.ts +4 -1
  322. package/src/libs/model-runtime/fal/index.test.ts +442 -0
  323. package/src/libs/model-runtime/fal/index.ts +88 -0
  324. package/src/libs/model-runtime/openai/index.test.ts +396 -2
  325. package/src/libs/model-runtime/openai/index.ts +129 -3
  326. package/src/libs/model-runtime/runtimeMap.ts +2 -0
  327. package/src/libs/model-runtime/types/image.ts +25 -0
  328. package/src/libs/model-runtime/types/type.ts +1 -0
  329. package/src/libs/model-runtime/utils/openaiCompatibleFactory/index.ts +10 -0
  330. package/src/libs/standard-parameters/index.ts +1 -0
  331. package/src/libs/standard-parameters/meta-schema.test.ts +214 -0
  332. package/src/libs/standard-parameters/meta-schema.ts +147 -0
  333. package/src/libs/swr/index.ts +1 -0
  334. package/src/libs/trpc/async/asyncAuth.ts +29 -8
  335. package/src/libs/trpc/async/context.ts +42 -4
  336. package/src/libs/trpc/async/index.ts +17 -4
  337. package/src/libs/trpc/async/init.ts +8 -0
  338. package/src/libs/trpc/client/lambda.ts +19 -2
  339. package/src/locales/default/common.ts +2 -0
  340. package/src/locales/default/components.ts +35 -0
  341. package/src/locales/default/error.ts +2 -0
  342. package/src/locales/default/image.ts +100 -0
  343. package/src/locales/default/index.ts +2 -0
  344. package/src/locales/default/metadata.ts +4 -0
  345. package/src/locales/default/modelProvider.ts +2 -0
  346. package/src/locales/default/plugin.ts +22 -0
  347. package/src/locales/default/setting.ts +5 -0
  348. package/src/middleware.ts +1 -0
  349. package/src/server/modules/ElectronIPCClient/index.ts +9 -1
  350. package/src/server/modules/S3/index.ts +15 -0
  351. package/src/server/routers/async/caller.ts +9 -1
  352. package/src/server/routers/async/image.ts +253 -0
  353. package/src/server/routers/async/index.ts +2 -0
  354. package/src/server/routers/lambda/aiProvider.test.ts +1 -0
  355. package/src/server/routers/lambda/generation.test.ts +267 -0
  356. package/src/server/routers/lambda/generation.ts +86 -0
  357. package/src/server/routers/lambda/generationBatch.test.ts +376 -0
  358. package/src/server/routers/lambda/generationBatch.ts +56 -0
  359. package/src/server/routers/lambda/generationTopic.test.ts +508 -0
  360. package/src/server/routers/lambda/generationTopic.ts +93 -0
  361. package/src/server/routers/lambda/image.ts +248 -0
  362. package/src/server/routers/lambda/index.ts +8 -0
  363. package/src/server/routers/tools/mcp.ts +15 -0
  364. package/src/server/services/file/__tests__/index.test.ts +135 -0
  365. package/src/server/services/file/impls/local.test.ts +153 -52
  366. package/src/server/services/file/impls/local.ts +70 -46
  367. package/src/server/services/file/impls/s3.test.ts +114 -0
  368. package/src/server/services/file/impls/s3.ts +40 -0
  369. package/src/server/services/file/impls/type.ts +10 -0
  370. package/src/server/services/file/index.ts +14 -0
  371. package/src/server/services/generation/index.ts +239 -0
  372. package/src/server/services/mcp/index.ts +20 -2
  373. package/src/services/__tests__/generation.test.ts +40 -0
  374. package/src/services/__tests__/generationBatch.test.ts +36 -0
  375. package/src/services/__tests__/generationTopic.test.ts +72 -0
  376. package/src/services/electron/file.ts +3 -1
  377. package/src/services/generation.ts +16 -0
  378. package/src/services/generationBatch.ts +25 -0
  379. package/src/services/generationTopic.ts +28 -0
  380. package/src/services/image.ts +33 -0
  381. package/src/services/mcp.ts +12 -7
  382. package/src/services/upload.ts +43 -9
  383. package/src/store/aiInfra/slices/aiProvider/action.ts +25 -5
  384. package/src/store/aiInfra/slices/aiProvider/initialState.ts +1 -0
  385. package/src/store/aiInfra/slices/aiProvider/selectors.ts +3 -0
  386. package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +5 -5
  387. package/src/store/chat/slices/message/action.ts +2 -2
  388. package/src/store/chat/slices/translate/action.ts +1 -1
  389. package/src/store/global/initialState.ts +9 -0
  390. package/src/store/global/selectors/systemStatus.ts +8 -0
  391. package/src/store/image/index.ts +2 -0
  392. package/src/store/image/initialState.ts +25 -0
  393. package/src/store/image/selectors.ts +4 -0
  394. package/src/store/image/slices/createImage/action.test.ts +330 -0
  395. package/src/store/image/slices/createImage/action.ts +134 -0
  396. package/src/store/image/slices/createImage/initialState.ts +9 -0
  397. package/src/store/image/slices/createImage/selectors.test.ts +114 -0
  398. package/src/store/image/slices/createImage/selectors.ts +9 -0
  399. package/src/store/image/slices/generationBatch/action.test.ts +495 -0
  400. package/src/store/image/slices/generationBatch/action.ts +303 -0
  401. package/src/store/image/slices/generationBatch/initialState.ts +13 -0
  402. package/src/store/image/slices/generationBatch/reducer.test.ts +568 -0
  403. package/src/store/image/slices/generationBatch/reducer.ts +101 -0
  404. package/src/store/image/slices/generationBatch/selectors.test.ts +307 -0
  405. package/src/store/image/slices/generationBatch/selectors.ts +36 -0
  406. package/src/store/image/slices/generationConfig/action.test.ts +351 -0
  407. package/src/store/image/slices/generationConfig/action.ts +295 -0
  408. package/src/store/image/slices/generationConfig/hooks.test.ts +304 -0
  409. package/src/store/image/slices/generationConfig/hooks.ts +118 -0
  410. package/src/store/image/slices/generationConfig/index.ts +1 -0
  411. package/src/store/image/slices/generationConfig/initialState.ts +37 -0
  412. package/src/store/image/slices/generationConfig/selectors.test.ts +204 -0
  413. package/src/store/image/slices/generationConfig/selectors.ts +25 -0
  414. package/src/store/image/slices/generationTopic/action.test.ts +687 -0
  415. package/src/store/image/slices/generationTopic/action.ts +319 -0
  416. package/src/store/image/slices/generationTopic/index.ts +2 -0
  417. package/src/store/image/slices/generationTopic/initialState.ts +14 -0
  418. package/src/store/image/slices/generationTopic/reducer.test.ts +198 -0
  419. package/src/store/image/slices/generationTopic/reducer.ts +66 -0
  420. package/src/store/image/slices/generationTopic/selectors.test.ts +103 -0
  421. package/src/store/image/slices/generationTopic/selectors.ts +15 -0
  422. package/src/store/image/store.ts +42 -0
  423. package/src/store/image/utils/size.ts +51 -0
  424. package/src/store/tool/slices/customPlugin/action.ts +10 -1
  425. package/src/store/tool/slices/mcpStore/action.ts +6 -4
  426. package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +4 -0
  427. package/src/store/user/slices/settings/selectors/systemAgent.ts +2 -0
  428. package/src/types/aiModel.ts +8 -3
  429. package/src/types/aiProvider.ts +1 -0
  430. package/src/types/asyncTask.ts +2 -0
  431. package/src/types/files/index.ts +5 -0
  432. package/src/types/generation/index.ts +80 -0
  433. package/src/types/hotkey.ts +2 -0
  434. package/src/types/plugins/mcp.ts +2 -6
  435. package/src/types/tool/plugin.ts +8 -0
  436. package/src/types/user/settings/keyVaults.ts +5 -0
  437. package/src/types/user/settings/systemAgent.ts +1 -0
  438. package/src/utils/client/downloadFile.ts +33 -4
  439. package/src/utils/number.test.ts +105 -0
  440. package/src/utils/number.ts +25 -0
  441. package/src/utils/server/__tests__/geo.test.ts +6 -3
  442. package/src/utils/storeDebug.test.ts +152 -0
  443. package/src/utils/storeDebug.ts +16 -7
  444. package/src/utils/time.test.ts +259 -0
  445. package/src/utils/time.ts +18 -0
  446. package/src/utils/units.ts +61 -0
  447. package/src/utils/url.test.ts +358 -9
  448. package/src/utils/url.ts +105 -3
  449. package/{vitest.server.config.ts → vitest.config.server.ts} +3 -0
  450. package/.cursor/rules/i18n/i18n-auto-attached.mdc +0 -6
  451. package/src/features/Conversation/Error/APIKeyForm/index.tsx +0 -105
  452. package/src/features/Conversation/Error/InvalidAPIKey.tsx +0 -16
  453. package/src/features/PluginDevModal/MCPManifestForm/EnvEditor.tsx +0 -227
  454. /package/.cursor/rules/{i18n/i18n.mdc → i18n.mdc} +0 -0
  455. /package/src/app/[variants]/(main)/settings/system-agent/features/{createForm.tsx → SystemAgentForm.tsx} +0 -0
  456. /package/src/{features/Conversation/Error → components/InvalidAPIKey}/APIKeyForm/LoadingContext.ts +0 -0
@@ -0,0 +1,203 @@
1
+ import { ActionIcon, Icon } from '@lobehub/ui';
2
+ import { Button } from 'antd';
3
+ import { createStyles } from 'antd-style';
4
+ import fastDeepEqual from 'fast-deep-equal';
5
+ import { LucidePlus, LucideTrash } from 'lucide-react';
6
+ import { memo, useEffect, useRef, useState } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { Flexbox } from 'react-layout-kit';
9
+ import { v4 as uuidv4 } from 'uuid';
10
+
11
+ import { FormInput } from '@/components/FormInput';
12
+
13
+ import { KeyValueItem, localListToRecord, recordToLocalList } from './utils';
14
+
15
+ const useStyles = createStyles(({ css, token }) => ({
16
+ container: css`
17
+ position: relative;
18
+
19
+ width: 100%;
20
+ padding: 12px;
21
+ border: 1px solid ${token.colorBorderSecondary};
22
+ border-radius: ${token.borderRadiusLG}px;
23
+ `,
24
+ input: css`
25
+ font-family: ${token.fontFamilyCode};
26
+ font-size: 12px;
27
+ `,
28
+ row: css`
29
+ margin-block-end: 8px;
30
+
31
+ &:last-child {
32
+ margin-block-end: 0;
33
+ }
34
+ `,
35
+ title: css`
36
+ margin-block-end: 8px;
37
+ color: ${token.colorTextTertiary};
38
+ `,
39
+ }));
40
+
41
+ export interface KeyValueEditorProps {
42
+ addButtonText?: string;
43
+ deleteTooltip?: string;
44
+ duplicateKeyErrorText?: string;
45
+ keyPlaceholder?: string;
46
+ onChange?: (value: Record<string, string>) => void;
47
+ value?: Record<string, string>;
48
+ valuePlaceholder?: string;
49
+ }
50
+
51
+ const KeyValueEditor = memo<KeyValueEditorProps>(
52
+ ({
53
+ value,
54
+ onChange,
55
+ keyPlaceholder,
56
+ valuePlaceholder,
57
+ addButtonText,
58
+ duplicateKeyErrorText,
59
+ deleteTooltip,
60
+ }) => {
61
+ const { styles } = useStyles();
62
+ const { t } = useTranslation('components');
63
+ const [items, setItems] = useState<KeyValueItem[]>(() => recordToLocalList(value));
64
+ const prevValueRef = useRef<Record<string, string> | undefined>(undefined);
65
+
66
+ useEffect(() => {
67
+ const externalRecord = value || {};
68
+ if (!fastDeepEqual(externalRecord, prevValueRef.current)) {
69
+ setItems(recordToLocalList(externalRecord));
70
+ prevValueRef.current = externalRecord;
71
+ }
72
+ }, [value]);
73
+
74
+ const triggerChange = (newItems: KeyValueItem[]) => {
75
+ const keysCount: Record<string, number> = {};
76
+ newItems.forEach((item) => {
77
+ const trimmedKey = item.key.trim();
78
+ if (trimmedKey) {
79
+ keysCount[trimmedKey] = (keysCount[trimmedKey] || 0) + 1;
80
+ }
81
+ });
82
+ setItems(
83
+ newItems.map((item) => ({
84
+ ...item,
85
+ })),
86
+ );
87
+ onChange?.(localListToRecord(newItems));
88
+ };
89
+
90
+ const handleAdd = () => {
91
+ const newItems = [...items, { id: uuidv4(), key: '', value: '' }];
92
+ triggerChange(newItems);
93
+ };
94
+
95
+ const handleRemove = (id: string) => {
96
+ const newItems = items.filter((item) => item.id !== id);
97
+ triggerChange(newItems);
98
+ };
99
+
100
+ const handleKeyChange = (id: string, newKey: string) => {
101
+ const newItems = items.map((item) => (item.id === id ? { ...item, key: newKey } : item));
102
+ triggerChange(newItems);
103
+ };
104
+
105
+ const handleValueChange = (id: string, newValue: string) => {
106
+ const newItems = items.map((item) => (item.id === id ? { ...item, value: newValue } : item));
107
+ triggerChange(newItems);
108
+ };
109
+
110
+ const getDuplicateKeys = (currentItems: KeyValueItem[]): Set<string> => {
111
+ const keys = new Set<string>();
112
+ const duplicates = new Set<string>();
113
+ currentItems.forEach((item) => {
114
+ const trimmedKey = item.key.trim();
115
+ if (trimmedKey) {
116
+ if (keys.has(trimmedKey)) {
117
+ duplicates.add(trimmedKey);
118
+ } else {
119
+ keys.add(trimmedKey);
120
+ }
121
+ }
122
+ });
123
+ return duplicates;
124
+ };
125
+ const duplicateKeys = getDuplicateKeys(items);
126
+
127
+ return (
128
+ <div className={styles.container}>
129
+ <Flexbox className={styles.title} gap={8} horizontal>
130
+ <Flexbox flex={1}>{keyPlaceholder || t('KeyValueEditor.keyPlaceholder')}</Flexbox>
131
+ <Flexbox flex={2}>{valuePlaceholder || t('KeyValueEditor.valuePlaceholder')}</Flexbox>
132
+ <Flexbox style={{ width: 30 }} />
133
+ </Flexbox>
134
+ <Flexbox width={'100%'}>
135
+ {items.map((item) => {
136
+ const isDuplicate = item.key.trim() && duplicateKeys.has(item.key.trim());
137
+ return (
138
+ <Flexbox
139
+ align="flex-start"
140
+ className={styles.row}
141
+ gap={8}
142
+ horizontal
143
+ key={item.id}
144
+ width={'100%'}
145
+ >
146
+ <Flexbox flex={1} style={{ position: 'relative' }}>
147
+ <FormInput
148
+ className={styles.input}
149
+ onChange={(e) => handleKeyChange(item.id, e)}
150
+ placeholder={keyPlaceholder || t('KeyValueEditor.keyPlaceholder')}
151
+ status={isDuplicate ? 'error' : undefined}
152
+ value={item.key}
153
+ variant={'filled'}
154
+ />
155
+ {isDuplicate && (
156
+ <div
157
+ style={{
158
+ bottom: '-16px',
159
+ color: 'red',
160
+ fontSize: '12px',
161
+ position: 'absolute',
162
+ }}
163
+ >
164
+ {duplicateKeyErrorText || t('KeyValueEditor.duplicateKeyError')}
165
+ </div>
166
+ )}
167
+ </Flexbox>
168
+ <Flexbox flex={2}>
169
+ <FormInput
170
+ className={styles.input}
171
+ onChange={(value) => handleValueChange(item.id, value)}
172
+ placeholder={valuePlaceholder || t('KeyValueEditor.valuePlaceholder')}
173
+ value={item.value}
174
+ variant={'filled'}
175
+ />
176
+ </Flexbox>
177
+ <ActionIcon
178
+ icon={LucideTrash}
179
+ onClick={() => handleRemove(item.id)}
180
+ size={'small'}
181
+ style={{ marginTop: 4 }}
182
+ title={deleteTooltip || t('KeyValueEditor.deleteTooltip')}
183
+ />
184
+ </Flexbox>
185
+ );
186
+ })}
187
+ <Button
188
+ block
189
+ icon={<Icon icon={LucidePlus} />}
190
+ onClick={handleAdd}
191
+ size={'small'}
192
+ style={{ marginTop: items.length > 0 ? 16 : 8 }}
193
+ type="dashed"
194
+ >
195
+ {addButtonText || t('KeyValueEditor.addButton')}
196
+ </Button>
197
+ </Flexbox>
198
+ </div>
199
+ );
200
+ },
201
+ );
202
+
203
+ export default KeyValueEditor;
@@ -0,0 +1,42 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+
3
+ export interface KeyValueItem {
4
+ id: string;
5
+ key: string;
6
+ value: string;
7
+ }
8
+
9
+ export const recordToLocalList = (
10
+ record: Record<string, string> | undefined | null = {},
11
+ ): KeyValueItem[] =>
12
+ Object.entries(record || {}).map(([key, val]) => ({
13
+ id: uuidv4(),
14
+ key,
15
+ value: typeof val === 'string' ? val : '',
16
+ }));
17
+
18
+ export const localListToRecord = (
19
+ list: KeyValueItem[] | undefined | null = [],
20
+ ): Record<string, string> => {
21
+ const record: Record<string, string> = {};
22
+ const keys = new Set<string>();
23
+ (list || [])
24
+ .slice()
25
+ .reverse()
26
+ .forEach((item) => {
27
+ const trimmedKey = item.key.trim();
28
+ if (trimmedKey && !keys.has(trimmedKey)) {
29
+ record[trimmedKey] = typeof item.value === 'string' ? item.value : '';
30
+ keys.add(trimmedKey);
31
+ }
32
+ });
33
+ return Object.keys(record)
34
+ .reverse()
35
+ .reduce(
36
+ (acc, key) => {
37
+ acc[key] = record[key];
38
+ return acc;
39
+ },
40
+ {} as Record<string, string>,
41
+ );
42
+ };
@@ -0,0 +1,52 @@
1
+ import { AIImageModelCard } from '@/types/aiModel';
2
+
3
+ import { fluxKontextDevParamsSchema } from '../paramsSchemas/fal/flux-kontext-dev';
4
+ import { fluxProKontextParamsSchema } from '../paramsSchemas/fal/flux-pro-kontext';
5
+ import { fluxSchnellParamsSchema } from '../paramsSchemas/fal/flux-schnell';
6
+ import { imagen4ParamsSchema } from '../paramsSchemas/fal/imagen4';
7
+
8
+ const falImageModels: AIImageModelCard[] = [
9
+ {
10
+ description: 'Frontier image editing model.',
11
+ displayName: 'FLUX.1 Kontext Dev',
12
+ enabled: true,
13
+ id: 'flux-kontext/dev',
14
+ parameters: fluxKontextDevParamsSchema,
15
+ releasedAt: '2025-06-28',
16
+ type: 'image',
17
+ },
18
+ {
19
+ description:
20
+ 'FLUX.1 Kontext [pro] 能够处理文本和参考图像作为输入,无缝实现目标性的局部编辑和复杂的整体场景变换。',
21
+ displayName: 'FLUX.1 Kontext [pro]',
22
+ enabled: true,
23
+ id: 'flux-pro/kontext',
24
+ parameters: fluxProKontextParamsSchema,
25
+ releasedAt: '2025-05-01',
26
+ type: 'image',
27
+ },
28
+ {
29
+ description:
30
+ 'FLUX.1 [schnell] 是一个拥有120亿参数的流式转换器模型,能够在1到4步内从文本生成高质量图像,适合个人和商业用途。',
31
+ displayName: 'FLUX.1 Schnell',
32
+ enabled: true,
33
+ id: 'flux/schnell',
34
+ parameters: fluxSchnellParamsSchema,
35
+ releasedAt: '2024-08-01',
36
+ type: 'image',
37
+ },
38
+ {
39
+ description: 'Google 最高质量的图像生成模型',
40
+ displayName: 'Imagen 4',
41
+ enabled: true,
42
+ id: 'imagen4/preview',
43
+ organization: 'Deepmind',
44
+ parameters: imagen4ParamsSchema,
45
+ releasedAt: '2025-05-21',
46
+ type: 'image',
47
+ },
48
+ ];
49
+
50
+ export const allModels = [...falImageModels];
51
+
52
+ export default allModels;
@@ -10,6 +10,7 @@ import { default as bedrock } from './bedrock';
10
10
  import { default as cloudflare } from './cloudflare';
11
11
  import { default as cohere } from './cohere';
12
12
  import { default as deepseek } from './deepseek';
13
+ import { default as fal } from './fal';
13
14
  import { default as fireworksai } from './fireworksai';
14
15
  import { default as giteeai } from './giteeai';
15
16
  import { default as github } from './github';
@@ -85,6 +86,7 @@ export const LOBE_DEFAULT_MODEL_LIST = buildDefaultModelList({
85
86
  cloudflare,
86
87
  cohere,
87
88
  deepseek,
89
+ fal,
88
90
  fireworksai,
89
91
  giteeai,
90
92
  github,
@@ -141,6 +143,7 @@ export { default as bedrock } from './bedrock';
141
143
  export { default as cloudflare } from './cloudflare';
142
144
  export { default as cohere } from './cohere';
143
145
  export { default as deepseek } from './deepseek';
146
+ export { default as fal } from './fal';
144
147
  export { default as fireworksai } from './fireworksai';
145
148
  export { default as giteeai } from './giteeai';
146
149
  export { default as github } from './github';
@@ -1,10 +1,11 @@
1
+ import { gptImage1ParamsSchema } from '@/config/paramsSchemas/openai/gpt-image-1';
1
2
  import {
2
3
  AIChatModelCard,
3
4
  AIEmbeddingModelCard,
5
+ AIImageModelCard,
4
6
  AIRealtimeModelCard,
5
7
  AISTTModelCard,
6
8
  AITTSModelCard,
7
- AIText2ImageModelCard,
8
9
  } from '@/types/aiModel';
9
10
 
10
11
  export const openaiChatModels: AIChatModelCard[] = [
@@ -691,7 +692,8 @@ export const openaiChatModels: AIChatModelCard[] = [
691
692
  vision: true,
692
693
  },
693
694
  contextWindowTokens: 200_000,
694
- description: 'codex-mini-latest 是 o4-mini 的微调版本,专门用于 Codex CLI。对于直接通过 API 使用,我们推荐从 gpt-4.1 开始。',
695
+ description:
696
+ 'codex-mini-latest 是 o4-mini 的微调版本,专门用于 Codex CLI。对于直接通过 API 使用,我们推荐从 gpt-4.1 开始。',
695
697
  displayName: 'Codex mini',
696
698
  id: 'codex-mini-latest',
697
699
  maxOutput: 100_000,
@@ -713,7 +715,8 @@ export const openaiChatModels: AIChatModelCard[] = [
713
715
  vision: true,
714
716
  },
715
717
  contextWindowTokens: 8192,
716
- description: 'computer-use-preview 模型是专为“计算机使用工具”设计的专用模型,经过训练以理解并执行计算机相关任务。',
718
+ description:
719
+ 'computer-use-preview 模型是专为“计算机使用工具”设计的专用模型,经过训练以理解并执行计算机相关任务。',
717
720
  displayName: 'Computer Use Preview',
718
721
  id: 'computer-use-preview',
719
722
  maxOutput: 1024,
@@ -804,7 +807,8 @@ export const openaiSTTModels: AISTTModelCard[] = [
804
807
  },
805
808
  {
806
809
  contextWindowTokens: 16_000,
807
- description: 'GPT-4o Transcribe 是一种使用 GPT-4o 转录音频的语音转文本模型。与原始 Whisper 模型相比,它提高了单词错误率,并提高了语言识别和准确性。使用它来获得更准确的转录。',
810
+ description:
811
+ 'GPT-4o Transcribe 是一种使用 GPT-4o 转录音频的语音转文本模型。与原始 Whisper 模型相比,它提高了单词错误率,并提高了语言识别和准确性。使用它来获得更准确的转录。',
808
812
  displayName: 'GPT-4o Transcribe',
809
813
  id: 'gpt-4o-transcribe',
810
814
  maxOutput: 2000,
@@ -816,7 +820,8 @@ export const openaiSTTModels: AISTTModelCard[] = [
816
820
  },
817
821
  {
818
822
  contextWindowTokens: 16_000,
819
- description: 'GPT-4o Mini Transcribe 是一种使用 GPT-4o 转录音频的语音转文本模型。与原始 Whisper 模型相比,它提高了单词错误率,并提高了语言识别和准确性。使用它来获得更准确的转录。',
823
+ description:
824
+ 'GPT-4o Mini Transcribe 是一种使用 GPT-4o 转录音频的语音转文本模型。与原始 Whisper 模型相比,它提高了单词错误率,并提高了语言识别和准确性。使用它来获得更准确的转录。',
820
825
  displayName: 'GPT-4o Mini Transcribe',
821
826
  id: 'gpt-4o-mini-transcribe',
822
827
  maxOutput: 2000,
@@ -829,7 +834,7 @@ export const openaiSTTModels: AISTTModelCard[] = [
829
834
  ];
830
835
 
831
836
  // 图像生成模型
832
- export const openaiImageModels: AIText2ImageModelCard[] = [
837
+ export const openaiImageModels: AIImageModelCard[] = [
833
838
  {
834
839
  description:
835
840
  '最新的 DALL·E 模型,于2023年11月发布。支持更真实、准确的图像生成,具有更强的细节表现力',
@@ -852,6 +857,15 @@ export const openaiImageModels: AIText2ImageModelCard[] = [
852
857
  resolutions: ['256x256', '512x512', '1024x1024'],
853
858
  type: 'image',
854
859
  },
860
+ // https://platform.openai.com/docs/models/gpt-image-1
861
+ {
862
+ description: 'ChatGPT 原生多模态图片生成模型',
863
+ displayName: 'GPT Image 1',
864
+ enabled: true,
865
+ id: 'gpt-image-1',
866
+ parameters: gptImage1ParamsSchema,
867
+ type: 'image',
868
+ },
855
869
  ];
856
870
 
857
871
  // GPT-4o 和 GPT-4o-mini 实时模型
package/src/config/llm.ts CHANGED
@@ -163,6 +163,9 @@ export const getLLMConfig = () => {
163
163
  ENABLED_INFINIAI: z.boolean(),
164
164
  INFINIAI_API_KEY: z.string().optional(),
165
165
 
166
+ ENABLED_FAL: z.boolean(),
167
+ FAL_API_KEY: z.string().optional(),
168
+
166
169
  ENABLED_MODELSCOPE: z.boolean(),
167
170
  MODELSCOPE_API_KEY: z.string().optional(),
168
171
 
@@ -329,6 +332,9 @@ export const getLLMConfig = () => {
329
332
  ENABLED_INFINIAI: !!process.env.INFINIAI_API_KEY,
330
333
  INFINIAI_API_KEY: process.env.INFINIAI_API_KEY,
331
334
 
335
+ ENABLED_FAL: process.env.ENABLED_FAL !== '0',
336
+ FAL_API_KEY: process.env.FAL_API_KEY,
337
+
332
338
  ENABLED_MODELSCOPE: !!process.env.MODELSCOPE_API_KEY,
333
339
  MODELSCOPE_API_KEY: process.env.MODELSCOPE_API_KEY,
334
340
 
@@ -0,0 +1,21 @@
1
+ import { ModelProviderCard } from '@/types/llm';
2
+
3
+ /**
4
+ * @see https://fal.ai/models/fal-ai/flux/schnell
5
+ */
6
+ const Fal: ModelProviderCard = {
7
+ chatModels: [],
8
+ description: '面向开发者的生成式媒体平台',
9
+ enabled: true,
10
+ id: 'fal',
11
+ name: 'Fal',
12
+ settings: {
13
+ disableBrowserRequest: true,
14
+ showAddNewModel: false,
15
+ showChecker: false,
16
+ showModelFetcher: false,
17
+ },
18
+ url: 'https://fal.ai',
19
+ };
20
+
21
+ export default Fal;
@@ -10,6 +10,7 @@ import BedrockProvider from './bedrock';
10
10
  import CloudflareProvider from './cloudflare';
11
11
  import CohereProvider from './cohere';
12
12
  import DeepSeekProvider from './deepseek';
13
+ import FalProvider from './fal';
13
14
  import FireworksAIProvider from './fireworksai';
14
15
  import GiteeAIProvider from './giteeai';
15
16
  import GithubProvider from './github';
@@ -123,6 +124,7 @@ export const DEFAULT_MODEL_PROVIDER_LIST = [
123
124
  DeepSeekProvider,
124
125
  HuggingFaceProvider,
125
126
  OpenRouterProvider,
127
+ FalProvider,
126
128
  CloudflareProvider,
127
129
  GithubProvider,
128
130
  NovitaProvider,
@@ -185,6 +187,7 @@ export { default as BedrockProviderCard } from './bedrock';
185
187
  export { default as CloudflareProviderCard } from './cloudflare';
186
188
  export { default as CohereProviderCard } from './cohere';
187
189
  export { default as DeepSeekProviderCard } from './deepseek';
190
+ export { default as FalProviderCard } from './fal';
188
191
  export { default as FireworksAIProviderCard } from './fireworksai';
189
192
  export { default as GiteeAIProviderCard } from './giteeai';
190
193
  export { default as GithubProviderCard } from './github';
@@ -0,0 +1,8 @@
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
+ };
@@ -0,0 +1,11 @@
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
+ };
@@ -0,0 +1,9 @@
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
+ };
@@ -0,0 +1,10 @@
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
+ };
@@ -0,0 +1,10 @@
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
+ };
@@ -41,13 +41,13 @@ export const HOTKEYS_REGISTRATION: HotkeyRegistration = [
41
41
  group: HotkeyGroupEnum.Essential,
42
42
  id: HotkeyEnum.ToggleLeftPanel,
43
43
  keys: combineKeys([KeyEnum.Mod, KeyEnum.BracketLeft]),
44
- scopes: [HotkeyScopeEnum.Chat, HotkeyScopeEnum.Files],
44
+ scopes: [HotkeyScopeEnum.Chat, HotkeyScopeEnum.Files, HotkeyScopeEnum.Image],
45
45
  },
46
46
  {
47
47
  group: HotkeyGroupEnum.Essential,
48
48
  id: HotkeyEnum.ToggleRightPanel,
49
49
  keys: combineKeys([KeyEnum.Mod, KeyEnum.BracketRight]),
50
- scopes: [HotkeyScopeEnum.Chat],
50
+ scopes: [HotkeyScopeEnum.Chat, HotkeyScopeEnum.Image],
51
51
  },
52
52
  {
53
53
  group: HotkeyGroupEnum.Essential,
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 默认宽高比,当模型不支持原生宽高比时使用
3
+ */
4
+ export const DEFAULT_ASPECT_RATIO = '1:1';
5
+
6
+ export const PRESET_ASPECT_RATIOS = [DEFAULT_ASPECT_RATIO, '16:9', '9:16', '4:3', '3:4'];
@@ -22,6 +22,7 @@ export const DEFAULT_QUERY_REWRITE_SYSTEM_AGENT_ITEM: QueryRewriteSystemAgent =
22
22
 
23
23
  export const DEFAULT_SYSTEM_AGENT_CONFIG: UserSystemAgentConfig = {
24
24
  agentMeta: DEFAULT_SYSTEM_AGENT_ITEM,
25
+ generationTopic: DEFAULT_SYSTEM_AGENT_ITEM,
25
26
  historyCompress: DEFAULT_SYSTEM_AGENT_ITEM,
26
27
  queryRewrite: DEFAULT_QUERY_REWRITE_SYSTEM_AGENT_ITEM,
27
28
  thread: DEFAULT_SYSTEM_AGENT_ITEM,
@@ -514,5 +514,32 @@
514
514
  "bps": true,
515
515
  "folderMillis": 1749309388370,
516
516
  "hash": "39cea379f08ee4cb944875c0b67f7791387b508c2d47958bb4cd501ed1ef33eb"
517
+ },
518
+ {
519
+ "sql": [
520
+ "-- Migration to apply specific autovacuum settings to high-traffic tables\n-- This is crucial to prevent table and TOAST bloat for 'embeddings' and 'chunks'\n-- https://github.com/lobehub/lobe-chat/issues/8316\n\n-- Tuning for the 'embeddings' table\n-- Default scale factor (0.2) is too high, leading to infrequent vacuuming.\n-- Lowering to 2% to ensure frequent cleanup.\nALTER TABLE \"embeddings\" SET (autovacuum_vacuum_scale_factor = 0.02, autovacuum_vacuum_threshold = 1000);\n\n",
521
+ "\n\n-- Tuning for the 'chunks' table\n-- This table also experiences many updates/deletes and requires similar tuning.\nALTER TABLE \"chunks\" SET (autovacuum_vacuum_scale_factor = 0.02, autovacuum_vacuum_threshold = 1000);\n"
522
+ ],
523
+ "bps": true,
524
+ "folderMillis": 1752212281564,
525
+ "hash": "e445db851f792aac49482e04689569a37939f7d0a3851cbcdf10dc24e8943b2c"
526
+ },
527
+ {
528
+ "sql": [
529
+ "CREATE TABLE \"generation_batches\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"user_id\" text NOT NULL,\n\t\"generation_topic_id\" text NOT NULL,\n\t\"provider\" text NOT NULL,\n\t\"model\" text NOT NULL,\n\t\"prompt\" text NOT NULL,\n\t\"width\" integer,\n\t\"height\" integer,\n\t\"ratio\" varchar(64),\n\t\"config\" jsonb,\n\t\"accessed_at\" timestamp with time zone DEFAULT now() NOT NULL,\n\t\"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n\t\"updated_at\" timestamp with time zone DEFAULT now() NOT NULL\n);\n",
530
+ "\nCREATE TABLE \"generation_topics\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"user_id\" text NOT NULL,\n\t\"title\" text,\n\t\"cover_url\" text,\n\t\"accessed_at\" timestamp with time zone DEFAULT now() NOT NULL,\n\t\"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n\t\"updated_at\" timestamp with time zone DEFAULT now() NOT NULL\n);\n",
531
+ "\nCREATE TABLE \"generations\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"user_id\" text NOT NULL,\n\t\"generation_batch_id\" varchar(64) NOT NULL,\n\t\"async_task_id\" uuid,\n\t\"file_id\" text,\n\t\"seed\" integer,\n\t\"asset\" jsonb,\n\t\"accessed_at\" timestamp with time zone DEFAULT now() NOT NULL,\n\t\"created_at\" timestamp with time zone DEFAULT now() NOT NULL,\n\t\"updated_at\" timestamp with time zone DEFAULT now() NOT NULL\n);\n",
532
+ "\nALTER TABLE \"files\" ADD COLUMN \"source\" text;",
533
+ "\nALTER TABLE \"generation_batches\" ADD CONSTRAINT \"generation_batches_user_id_users_id_fk\" FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\") ON DELETE cascade ON UPDATE no action;",
534
+ "\nALTER TABLE \"generation_batches\" ADD CONSTRAINT \"generation_batches_generation_topic_id_generation_topics_id_fk\" FOREIGN KEY (\"generation_topic_id\") REFERENCES \"public\".\"generation_topics\"(\"id\") ON DELETE cascade ON UPDATE no action;",
535
+ "\nALTER TABLE \"generation_topics\" ADD CONSTRAINT \"generation_topics_user_id_users_id_fk\" FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\") ON DELETE cascade ON UPDATE no action;",
536
+ "\nALTER TABLE \"generations\" ADD CONSTRAINT \"generations_user_id_users_id_fk\" FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\") ON DELETE cascade ON UPDATE no action;",
537
+ "\nALTER TABLE \"generations\" ADD CONSTRAINT \"generations_generation_batch_id_generation_batches_id_fk\" FOREIGN KEY (\"generation_batch_id\") REFERENCES \"public\".\"generation_batches\"(\"id\") ON DELETE cascade ON UPDATE no action;",
538
+ "\nALTER TABLE \"generations\" ADD CONSTRAINT \"generations_async_task_id_async_tasks_id_fk\" FOREIGN KEY (\"async_task_id\") REFERENCES \"public\".\"async_tasks\"(\"id\") ON DELETE set null ON UPDATE no action;",
539
+ "\nALTER TABLE \"generations\" ADD CONSTRAINT \"generations_file_id_files_id_fk\" FOREIGN KEY (\"file_id\") REFERENCES \"public\".\"files\"(\"id\") ON DELETE cascade ON UPDATE no action;"
540
+ ],
541
+ "bps": true,
542
+ "folderMillis": 1752413805765,
543
+ "hash": "abed92b1356df6d7eb35c03f47fbbdcdaf25aefda750dc3e4963c1c2a0d38b54"
517
544
  }
518
545
  ]
@@ -7,6 +7,8 @@
7
7
  -- Lowering to 2% to ensure frequent cleanup.
8
8
  ALTER TABLE "embeddings" SET (autovacuum_vacuum_scale_factor = 0.02, autovacuum_vacuum_threshold = 1000);
9
9
 
10
+ --> statement-breakpoint
11
+
10
12
  -- Tuning for the 'chunks' table
11
13
  -- This table also experiences many updates/deletes and requires similar tuning.
12
14
  ALTER TABLE "chunks" SET (autovacuum_vacuum_scale_factor = 0.02, autovacuum_vacuum_threshold = 1000);
@@ -0,0 +1,47 @@
1
+ CREATE TABLE "generation_batches" (
2
+ "id" text PRIMARY KEY NOT NULL,
3
+ "user_id" text NOT NULL,
4
+ "generation_topic_id" text NOT NULL,
5
+ "provider" text NOT NULL,
6
+ "model" text NOT NULL,
7
+ "prompt" text NOT NULL,
8
+ "width" integer,
9
+ "height" integer,
10
+ "ratio" varchar(64),
11
+ "config" jsonb,
12
+ "accessed_at" timestamp with time zone DEFAULT now() NOT NULL,
13
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
14
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
15
+ );
16
+ --> statement-breakpoint
17
+ CREATE TABLE "generation_topics" (
18
+ "id" text PRIMARY KEY NOT NULL,
19
+ "user_id" text NOT NULL,
20
+ "title" text,
21
+ "cover_url" text,
22
+ "accessed_at" timestamp with time zone DEFAULT now() NOT NULL,
23
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
24
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
25
+ );
26
+ --> statement-breakpoint
27
+ CREATE TABLE "generations" (
28
+ "id" text PRIMARY KEY NOT NULL,
29
+ "user_id" text NOT NULL,
30
+ "generation_batch_id" varchar(64) NOT NULL,
31
+ "async_task_id" uuid,
32
+ "file_id" text,
33
+ "seed" integer,
34
+ "asset" jsonb,
35
+ "accessed_at" timestamp with time zone DEFAULT now() NOT NULL,
36
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
37
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
38
+ );
39
+ --> statement-breakpoint
40
+ ALTER TABLE "files" ADD COLUMN "source" text;--> statement-breakpoint
41
+ ALTER TABLE "generation_batches" ADD CONSTRAINT "generation_batches_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
42
+ ALTER TABLE "generation_batches" ADD CONSTRAINT "generation_batches_generation_topic_id_generation_topics_id_fk" FOREIGN KEY ("generation_topic_id") REFERENCES "public"."generation_topics"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
43
+ ALTER TABLE "generation_topics" ADD CONSTRAINT "generation_topics_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
44
+ ALTER TABLE "generations" ADD CONSTRAINT "generations_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
45
+ ALTER TABLE "generations" ADD CONSTRAINT "generations_generation_batch_id_generation_batches_id_fk" FOREIGN KEY ("generation_batch_id") REFERENCES "public"."generation_batches"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
46
+ ALTER TABLE "generations" ADD CONSTRAINT "generations_async_task_id_async_tasks_id_fk" FOREIGN KEY ("async_task_id") REFERENCES "public"."async_tasks"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
47
+ ALTER TABLE "generations" ADD CONSTRAINT "generations_file_id_files_id_fk" FOREIGN KEY ("file_id") REFERENCES "public"."files"("id") ON DELETE cascade ON UPDATE no action;