From 538b24a2fdfbab4fbbba205fb53e716f60901eb1 Mon Sep 17 00:00:00 2001 From: kang Date: Wed, 27 May 2026 23:08:22 +0800 Subject: [PATCH] auto-save 2026-05-27 23:08 (~5) --- .memory/worklog.json | 13 ++-- .../src/components/nodes/VideoConfigNode.vue | 63 ++++++++++++++++++- web/canvas-app/src/hooks/useApi.js | 3 +- web/canvas-app/src/stores/models.js | 2 +- web/canvas-app/src/stores/pinia/models.js | 2 +- 5 files changed, 72 insertions(+), 11 deletions(-) diff --git a/.memory/worklog.json b/.memory/worklog.json index a6362b8..723c2bf 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -1,11 +1,5 @@ { "entries": [ - { - "files_changed": 1, - "message": "Codex 会话活跃 · 最近命令:codex · 分支 main · 1 项未提交变更 · 最近提交:fix: center scaled workbench vertically", - "ts": "2026-05-20T12:15:32Z", - "type": "session-heartbeat" - }, { "files_changed": 2, "hash": "bd64b94", @@ -3199,6 +3193,13 @@ "message": "chore: harden production deploy scripts", "hash": "b6a7e7b", "files_changed": 2 + }, + { + "ts": "2026-05-27T23:02:52+08:00", + "type": "commit", + "message": "auto-save 2026-05-27 23:01 (~5)", + "hash": "d7f72f6", + "files_changed": 5 } ] } diff --git a/web/canvas-app/src/components/nodes/VideoConfigNode.vue b/web/canvas-app/src/components/nodes/VideoConfigNode.vue index 83a04b4..07dcc59 100644 --- a/web/canvas-app/src/components/nodes/VideoConfigNode.vue +++ b/web/canvas-app/src/components/nodes/VideoConfigNode.vue @@ -74,6 +74,19 @@ + +
+ 清晰度 + + + +
+
@@ -154,7 +167,7 @@ import { useVideoGeneration } from '../../hooks' import { updateNode, removeNode, duplicateNode, addNode, addEdge, nodes, edges } from '../../stores/canvas' import NodeHandleMenu from './NodeHandleMenu.vue' import { useModelStore } from '../../stores/pinia' -import { getModelRatioOptions, getModelDurationOptions, getModelConfig, DEFAULT_VIDEO_MODEL } from '../../stores/models' +import { getModelRatioOptions, getModelDurationOptions, getModelResolutionOptions, getModelConfig, DEFAULT_VIDEO_MODEL } from '../../stores/models' // 使用 Pinia store 获取模型选项(根据渠道过滤) const modelStore = useModelStore() @@ -170,12 +183,25 @@ const { updateNodeInternals } = useVueFlow() // Video generation hook | 视频生成 hook const { loading, error, status, video: generatedVideo, progress, createVideoTaskOnly } = useVideoGeneration() +const currentModelDefaultResolution = (modelKey) => { + const config = getModelConfig(modelKey) + return config?.defaultParams?.resolution || config?.defaultResolution || config?.resolutions?.[0] || '720p' +} + +const normalizeResolutionForModel = (modelKey, resolution) => { + const options = getModelResolutionOptions(modelKey) + const allowed = options.map(option => option.key) + if (resolution && allowed.includes(resolution)) return resolution + return currentModelDefaultResolution(modelKey) +} + // Local state | 本地状态 const showHandleMenu = ref(false) const isGenerating = ref(false) // 任务创建中状态 const localModel = ref(props.data?.model || DEFAULT_VIDEO_MODEL) const localRatio = ref(props.data?.ratio || '16:9') const localDuration = ref(props.data?.dur || 5) +const localResolution = ref(props.data?.resolution || currentModelDefaultResolution(props.data?.model || DEFAULT_VIDEO_MODEL)) // Label editing state | Label 编辑状态 const isEditingLabel = ref(false) @@ -244,6 +270,11 @@ const durationOptions = computed(() => { return getModelDurationOptions(localModel.value) }) +// Resolution options based on model | 基于模型的清晰度选项 +const resolutionOptions = computed(() => { + return getModelResolutionOptions(localModel.value) +}) + // Handle model selection | 处理模型选择 const handleModelSelect = (key) => { localModel.value = key @@ -258,6 +289,9 @@ const handleModelSelect = (key) => { localDuration.value = config.defaultParams.duration updates.dur = config.defaultParams.duration } + const nextResolution = currentModelDefaultResolution(key) + localResolution.value = nextResolution + updates.resolution = nextResolution updateNode(props.id, updates) } @@ -284,6 +318,12 @@ const handleDurationSelect = (key) => { updateNode(props.id, { dur: key }) } +// Handle resolution selection | 处理清晰度选择 +const handleResolutionSelect = (key) => { + localResolution.value = key + updateNode(props.id, { resolution: key }) +} + // Get connected inputs by role | 根据角色获取连接的输入 const getConnectedInputs = () => { const connectedEdges = edges.value.filter(e => e.target === props.id) @@ -411,6 +451,11 @@ const handleGenerate = async () => { params.dur = localDuration.value } + // Add resolution | 添加清晰度 + if (localResolution.value) { + params.resolution = localResolution.value + } + // 只创建任务,获取 taskId,不在这里轮询 const { taskId: newTaskId, url } = await createVideoTaskOnly(params) @@ -492,7 +537,14 @@ onMounted(() => { // 使用 store 中的默认模型或第一个可用模型 const selected = availableModels.find(m => m.key === modelStore.selectedVideoModel)?.key localModel.value = selected || availableModels[0]?.key || DEFAULT_VIDEO_MODEL - updateNode(props.id, { model: localModel.value }) + localResolution.value = normalizeResolutionForModel(localModel.value, localResolution.value) + updateNode(props.id, { model: localModel.value, resolution: localResolution.value }) + } else { + const nextResolution = normalizeResolutionForModel(localModel.value, localResolution.value) + if (nextResolution !== localResolution.value || !props.data?.resolution) { + localResolution.value = nextResolution + updateNode(props.id, { resolution: nextResolution }) + } } }) @@ -500,6 +552,13 @@ onMounted(() => { watch(() => props.data?.model, (newModel) => { if (newModel && newModel !== localModel.value) { localModel.value = newModel + localResolution.value = normalizeResolutionForModel(newModel, props.data?.resolution || localResolution.value) + } +}) + +watch(() => props.data?.resolution, (newResolution) => { + if (newResolution && newResolution !== localResolution.value) { + localResolution.value = normalizeResolutionForModel(localModel.value, newResolution) } }) diff --git a/web/canvas-app/src/hooks/useApi.js b/web/canvas-app/src/hooks/useApi.js index 913c115..5b2985c 100644 --- a/web/canvas-app/src/hooks/useApi.js +++ b/web/canvas-app/src/hooks/useApi.js @@ -282,7 +282,8 @@ export const useVideoGeneration = () => { first_image: firstFile ? { kind: 'keyframe', frame_idx: 0 } : null, last_image: lastFrameIdx !== null ? { kind: 'keyframe', frame_idx: lastFrameIdx } : null, model: params.model || 'seedance', - size: normalizeVideoSize(params.ratio || params.size) + size: normalizeVideoSize(params.ratio || params.size), + resolution: params.resolution || '720p' }) }) const created = newestGeneratedVideo(updated) diff --git a/web/canvas-app/src/stores/models.js b/web/canvas-app/src/stores/models.js index 888ed61..c42e264 100644 --- a/web/canvas-app/src/stores/models.js +++ b/web/canvas-app/src/stores/models.js @@ -150,7 +150,7 @@ export const getModelDurationOptions = (modelKey) => { */ export const getModelResolutionOptions = (modelKey) => { const model = getModelConfig(modelKey) || VIDEO_MODELS.find(m => m.key === modelKey) - if (model?.resolutionOptions) { + if (model?.resolutionOptions?.length) { return model.resolutionOptions } if (!model?.resolutions) return SEEDANCE_RESOLUTION_OPTIONS diff --git a/web/canvas-app/src/stores/pinia/models.js b/web/canvas-app/src/stores/pinia/models.js index 34fb7c6..d24aa2e 100644 --- a/web/canvas-app/src/stores/pinia/models.js +++ b/web/canvas-app/src/stores/pinia/models.js @@ -173,7 +173,7 @@ const normalizeRuntimeVideoModel = (item) => { const sizeOptions = normalizeRuntimeSizeOptions(item.size_options) const durationOptions = normalizeRuntimeDurationOptions(item.duration_options) const resolutionOptions = normalizeRuntimeResolutionOptions(item.resolution_options) - const resolutions = resolutionOptions.map(option => option.key) + const resolutions = resolutionOptions.length ? resolutionOptions.map(option => option.key) : ['720p'] const defaultResolution = item.default_resolution || resolutions[0] || '720p' return { label: item.label || item.model || key,