fix(canvas): 视频设置 - 按渠道能力隐藏尺寸并联动分辨率宽高
This commit is contained in:
@@ -498,10 +498,10 @@ export function buildGenerationConfig(config: AiConfig, node: CanvasNodeData | u
|
||||
comfyBridge,
|
||||
model,
|
||||
quality: generationDefaults.quality || requestedConfig.quality,
|
||||
size: generationDefaults.size || requestedConfig.size,
|
||||
size: generationDefaults.size ?? requestedConfig.size,
|
||||
transparentBackground: generationDefaults.transparentBackground || (requestedConfig.transparentBackground === "true" ? "true" : "false"),
|
||||
videoSeconds: generationDefaults.videoSeconds || requestedConfig.videoSeconds,
|
||||
vquality: generationDefaults.vquality || requestedConfig.vquality,
|
||||
vquality: generationDefaults.vquality ?? requestedConfig.vquality,
|
||||
videoGenerateAudio: generationDefaults.videoGenerateAudio || requestedConfig.videoGenerateAudio,
|
||||
videoWatermark: generationDefaults.videoWatermark || requestedConfig.videoWatermark,
|
||||
videoArkPrivateAssetUpload: requestedConfig.videoArkPrivateAssetUpload,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ModelProtocol } from "@/lib/model-protocols";
|
||||
import type { ModelProtocol, ModelProtocolWorkflow } from "@/lib/model-protocols";
|
||||
|
||||
export type ModelCapabilityConfig = {
|
||||
version: number;
|
||||
@@ -335,6 +335,22 @@ export function defaultModelCapabilityConfig(protocol?: ModelProtocol, model = "
|
||||
return { version: 1, text, image: defaultImageCapabilityConfig(protocol, model), video };
|
||||
}
|
||||
|
||||
export function pluginWorkflowCapabilityConfig(protocol: ModelProtocol, workflow: ModelProtocolWorkflow): ModelCapabilityConfig | undefined {
|
||||
if (workflow.capability !== "image" && workflow.capability !== "video") return undefined;
|
||||
const fallback = defaultModelCapabilityConfig(protocol, workflow.id);
|
||||
const fields: WorkflowVideoFieldLike[] = workflow.parameters.map((parameter) => ({
|
||||
fieldName: parameter.name,
|
||||
source: parameter.mapping,
|
||||
fieldType: parameter.type,
|
||||
options: parameter.values,
|
||||
defaultValue: workflow.defaults?.[parameter.name],
|
||||
}));
|
||||
if (workflow.capability === "image") {
|
||||
return { ...fallback, image: workflowImageCapabilityConfig(fields, fallback.image!) };
|
||||
}
|
||||
return { ...fallback, video: workflowVideoCapabilityConfig(fields, fallback.video!) };
|
||||
}
|
||||
|
||||
export function modelCapabilityConfigFor(config: { channels: Array<{ id: string; models: string[]; modelCosts?: Array<{ model: string; capabilityConfig?: ModelCapabilityConfig; protocol?: ModelProtocol }> }> }, model: string) {
|
||||
const separator = model.indexOf("::");
|
||||
const channelId = separator >= 0 ? model.slice(0, separator) : "";
|
||||
@@ -900,12 +916,16 @@ export function imageSizeRequest(profile: ImageCapabilityConfig, value?: string)
|
||||
|
||||
export function normalizeVideoValue(profile: VideoCapabilityConfig, value: { seconds?: string; ratio?: string; resolution?: string }) {
|
||||
const duration = profile.duration.selection === "enum" ? ((profile.duration.values || []).includes(Number(value.seconds)) ? Number(value.seconds) : profile.duration.default) : normalizeRangeDuration(profile, Number(value.seconds));
|
||||
const ratio = profile.ratios.includes(value.ratio || "") ? value.ratio! : profile.defaultRatio;
|
||||
const ratio = resolveVideoRatioValue(profile, value.ratio);
|
||||
// 前端状态历史上保存过 `720`,而能力配置和供应商通常使用 `720p`;统一按能力中的原始值返回,避免被误判为不支持。
|
||||
const resolution = resolveVideoResolutionValue(profile, value.resolution);
|
||||
return { seconds: String(duration), ratio, resolution };
|
||||
}
|
||||
|
||||
export function resolveVideoRatioValue(profile: VideoCapabilityConfig, value: string | undefined) {
|
||||
return profile.ratios.includes(value || "") ? value! : profile.defaultRatio || profile.ratios[0] || "";
|
||||
}
|
||||
|
||||
export function resolveVideoResolutionValue(profile: VideoCapabilityConfig, value: string | undefined) {
|
||||
return videoResolutionRequest(profile, value) || profile.defaultResolution || profile.resolutions[0] || "";
|
||||
}
|
||||
|
||||
@@ -38,3 +38,29 @@ export function formatVideoResolutionLabel(value: string | number | undefined) {
|
||||
if (/^\d+$/.test(normalized)) return `${normalized}P`;
|
||||
return normalized.replace(/^(\d+)p/i, "$1P");
|
||||
}
|
||||
|
||||
export function videoDimensionsForRatioAndResolution(ratio: string | undefined, resolution: string | number | undefined) {
|
||||
const ratioMatch = String(ratio || "")
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace("×", "x")
|
||||
.match(/^(\d+(?:\.\d+)?)(?::|x)(\d+(?:\.\d+)?)$/);
|
||||
if (!ratioMatch) return undefined;
|
||||
|
||||
const ratioWidth = Number(ratioMatch[1]);
|
||||
const ratioHeight = Number(ratioMatch[2]);
|
||||
if (!Number.isFinite(ratioWidth) || !Number.isFinite(ratioHeight) || ratioWidth <= 0 || ratioHeight <= 0) return undefined;
|
||||
|
||||
const normalizedResolution = normalizeVideoResolution(resolution);
|
||||
const resolutionMatch = normalizedResolution.match(/^(\d+)(?:p)?/i);
|
||||
const shortEdge = Number(resolutionMatch?.[1]);
|
||||
if (!Number.isFinite(shortEdge) || shortEdge <= 0) return undefined;
|
||||
|
||||
const aspect = ratioWidth / ratioHeight;
|
||||
if (aspect >= 1) return { width: evenDimension(shortEdge * aspect), height: shortEdge };
|
||||
return { width: shortEdge, height: evenDimension(shortEdge / aspect) };
|
||||
}
|
||||
|
||||
function evenDimension(value: number) {
|
||||
return Math.max(2, Math.round(value / 2) * 2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user