diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f2c91..6fd8f5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ + [修复] 修复 Gemini 调用格式生图未传递尺寸比例配置的问题。 + [新增] 新增GitHub Pages 前端静态站点发布 workflow。 + [新增] 图片切图支持等分线直接拖拽调整,并可新增、删除和重置横向 / 纵向切图线。 ++ [修复] 修复前端 TypeScript 构建报错。 ++ [修复] 修复画布生成配置切换文本/视频/音频模式时模型仍显示为生图模型的问题。 ++ [调整] Docker 运行镜像改为 nginx 静态托管。 ## v0.5.0 - 2026-07-05 diff --git a/docs/content/docs/progress/pending-test.mdx b/docs/content/docs/progress/pending-test.mdx index e60e63a..a36f16a 100644 --- a/docs/content/docs/progress/pending-test.mdx +++ b/docs/content/docs/progress/pending-test.mdx @@ -28,3 +28,4 @@ description: 当前版本已实现但仍需人工验证的变更项 - Docker 部署:运行镜像从 Node serve 改为 nginx 静态托管,需验证前端路由刷新回退。 - 环境变量:移除过期的后端 `.env.example` 示例文件。 - 生图工作台:修复失败图片点击重试后只保存在页面状态、刷新或跳转后丢失的问题,重试成功结果会写入本地图片存储和生成记录。 +- 画布生成配置:修复切换文本/视频/音频模式时模型选择仍显示为生图模型(gpt-image-2)的问题,切换模式后应自动匹配对应能力的默认模型。 diff --git a/web/src/components/canvas/canvas-config-node-panel.tsx b/web/src/components/canvas/canvas-config-node-panel.tsx index fc0d90b..8eb2283 100644 --- a/web/src/components/canvas/canvas-config-node-panel.tsx +++ b/web/src/components/canvas/canvas-config-node-panel.tsx @@ -3,7 +3,7 @@ import { Image as ImageIcon, LoaderCircle, MessageSquare, Music2, Play, Settings import { Button, Segmented } from "antd"; import { ModelPicker } from "@/components/model-picker"; -import { defaultConfig, useConfigStore, useEffectiveConfig, type AiConfig } from "@/stores/use-config-store"; +import { defaultConfig, modelMatchesCapability, useConfigStore, useEffectiveConfig, type AiConfig } from "@/stores/use-config-store"; import { canvasThemes } from "@/lib/canvas-theme"; import { useThemeStore } from "@/stores/use-theme-store"; import { CanvasImageSettingsPopover } from "./canvas-image-settings-popover"; @@ -144,9 +144,16 @@ function InputChip({ label, value, style }: { label: string; value: string; styl function buildNodeConfig(globalConfig: AiConfig, node: CanvasNodeData, mode: CanvasGenerationMode): AiConfig { const defaultModel = mode === "image" ? globalConfig.imageModel : mode === "video" ? globalConfig.videoModel : mode === "audio" ? globalConfig.audioModel : globalConfig.textModel; + const fallbackModel = mode === "image" ? defaultConfig.imageModel : mode === "video" ? defaultConfig.videoModel : mode === "audio" ? defaultConfig.audioModel : defaultConfig.textModel; + const currentModel = node.metadata?.model; + const model = currentModel && modelMatchesCapability(currentModel, mode) + ? currentModel + : defaultModel && modelMatchesCapability(defaultModel, mode) + ? defaultModel + : fallbackModel; return { ...globalConfig, - model: node.metadata?.model || defaultModel || (mode === "audio" ? defaultConfig.audioModel : globalConfig.model || defaultConfig.model), + model, quality: node.metadata?.quality || globalConfig.quality || defaultConfig.quality, size: node.metadata?.size || globalConfig.size || defaultConfig.size, videoSeconds: node.metadata?.seconds || globalConfig.videoSeconds || defaultConfig.videoSeconds, diff --git a/web/src/components/canvas/canvas-node-prompt-panel.tsx b/web/src/components/canvas/canvas-node-prompt-panel.tsx index d1c25fa..aff57e2 100644 --- a/web/src/components/canvas/canvas-node-prompt-panel.tsx +++ b/web/src/components/canvas/canvas-node-prompt-panel.tsx @@ -3,7 +3,7 @@ import { ArrowUp, LoaderCircle, Square } from "lucide-react"; import { Button } from "antd"; import { ModelPicker } from "@/components/model-picker"; -import { defaultConfig, useConfigStore, useEffectiveConfig, type AiConfig } from "@/stores/use-config-store"; +import { defaultConfig, modelMatchesCapability, useConfigStore, useEffectiveConfig, type AiConfig } from "@/stores/use-config-store"; import { canvasThemes } from "@/lib/canvas-theme"; import { useThemeStore } from "@/stores/use-theme-store"; import { CanvasImageSettingsPopover } from "./canvas-image-settings-popover"; @@ -132,9 +132,16 @@ function defaultMode(type: CanvasNodeData["type"]): CanvasNodeGenerationMode { function buildNodeConfig(globalConfig: AiConfig, node: CanvasNodeData, mode: CanvasNodeGenerationMode): AiConfig { const defaultModel = mode === "image" ? globalConfig.imageModel : mode === "video" ? globalConfig.videoModel : mode === "audio" ? globalConfig.audioModel : globalConfig.textModel; + const fallbackModel = mode === "image" ? defaultConfig.imageModel : mode === "video" ? defaultConfig.videoModel : mode === "audio" ? defaultConfig.audioModel : defaultConfig.textModel; + const currentModel = node.metadata?.model; + const model = currentModel && modelMatchesCapability(currentModel, mode) + ? currentModel + : defaultModel && modelMatchesCapability(defaultModel, mode) + ? defaultModel + : fallbackModel; return { ...globalConfig, - model: node.metadata?.model || defaultModel || (mode === "audio" ? defaultConfig.audioModel : globalConfig.model || defaultConfig.model), + model, quality: node.metadata?.quality || globalConfig.quality || defaultConfig.quality, size: node.metadata?.size || globalConfig.size || defaultConfig.size, videoSeconds: node.metadata?.seconds || globalConfig.videoSeconds || defaultConfig.videoSeconds,