mirror of
https://github.com/basketikun/infinite-canvas.git
synced 2026-08-05 00:34:22 +08:00
feat: add seedance media params and model visibility
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import type { AiConfig } from "@/stores/use-config-store";
|
||||
|
||||
export const SEEDANCE_REFERENCE_LIMITS = {
|
||||
images: 9,
|
||||
videos: 3,
|
||||
audios: 3,
|
||||
imageMaxBytes: 30 * 1024 * 1024,
|
||||
videoMaxBytes: 50 * 1024 * 1024,
|
||||
audioMaxBytes: 15 * 1024 * 1024,
|
||||
};
|
||||
|
||||
export const seedanceResolutionOptions = [
|
||||
{ value: "480p", label: "480p" },
|
||||
{ value: "720p", label: "720p" },
|
||||
{ value: "1080p", label: "1080p" },
|
||||
] as const;
|
||||
|
||||
export const seedanceRatioOptions = [
|
||||
{ value: "16:9", label: "横屏" },
|
||||
{ value: "9:16", label: "竖屏" },
|
||||
{ value: "1:1", label: "方形" },
|
||||
{ value: "4:3", label: "标准横屏" },
|
||||
{ value: "3:4", label: "标准竖屏" },
|
||||
{ value: "21:9", label: "宽银幕" },
|
||||
{ value: "adaptive", label: "自适应" },
|
||||
] as const;
|
||||
|
||||
export const seedanceDurationOptions = [-1, 4, 5, 6, 8, 10, 12, 15] as const;
|
||||
|
||||
const seedancePixels = {
|
||||
"480p": {
|
||||
"16:9": "864x496",
|
||||
"4:3": "752x560",
|
||||
"1:1": "640x640",
|
||||
"3:4": "560x752",
|
||||
"9:16": "496x864",
|
||||
"21:9": "992x432",
|
||||
},
|
||||
"720p": {
|
||||
"16:9": "1280x720",
|
||||
"4:3": "1112x834",
|
||||
"1:1": "960x960",
|
||||
"3:4": "834x1112",
|
||||
"9:16": "720x1280",
|
||||
"21:9": "1470x630",
|
||||
},
|
||||
"1080p": {
|
||||
"16:9": "1920x1080",
|
||||
"4:3": "1664x1248",
|
||||
"1:1": "1440x1440",
|
||||
"3:4": "1248x1664",
|
||||
"9:16": "1080x1920",
|
||||
"21:9": "2206x946",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export function isSeedanceVideoConfig(config: Pick<AiConfig, "model" | "videoModel" | "baseUrl">) {
|
||||
return isSeedanceVideoModel(config.model || config.videoModel) || isArkPlanBaseUrl(config.baseUrl);
|
||||
}
|
||||
|
||||
export function isSeedanceVideoModel(model: string) {
|
||||
const value = model.toLowerCase();
|
||||
return value.includes("seedance") || value.includes("doubao-seedance");
|
||||
}
|
||||
|
||||
export function isSeedanceFastModel(model: string) {
|
||||
const value = model.toLowerCase();
|
||||
return isSeedanceVideoModel(value) && value.includes("fast");
|
||||
}
|
||||
|
||||
export function isArkPlanBaseUrl(baseUrl: string) {
|
||||
return baseUrl.toLowerCase().includes("ark.cn-beijing.volces.com/api/plan/v3") || baseUrl.toLowerCase().includes("/api/plan/v3");
|
||||
}
|
||||
|
||||
export function normalizeSeedanceResolution(value: string, model = "") {
|
||||
const normalized = normalizeResolutionToken(value);
|
||||
if (isSeedanceFastModel(model) && normalized === "1080p") return "720p";
|
||||
return seedanceResolutionOptions.some((item) => item.value === normalized) ? normalized : "720p";
|
||||
}
|
||||
|
||||
export function normalizeResolutionToken(value: string) {
|
||||
if (value === "low") return "480p";
|
||||
if (value === "auto" || value === "high" || value === "medium") return "720p";
|
||||
const resolution = String(value || "").replace(/p$/i, "") || "720";
|
||||
return `${resolution}p`;
|
||||
}
|
||||
|
||||
export function normalizeSeedanceDuration(value: string) {
|
||||
if (String(value).trim() === "-1") return -1;
|
||||
const seconds = Math.floor(Number(value) || 5);
|
||||
return Math.max(4, Math.min(15, seconds));
|
||||
}
|
||||
|
||||
export function normalizeSeedanceRatio(value: string) {
|
||||
if (!value || value === "auto" || value === "adaptive") return "adaptive";
|
||||
if (seedanceRatioOptions.some((item) => item.value === value)) return value;
|
||||
const match = value.match(/^(\d+)x(\d+)$/);
|
||||
if (!match) return "adaptive";
|
||||
const width = Number(match[1]);
|
||||
const height = Number(match[2]);
|
||||
if (!width || !height) return "adaptive";
|
||||
const ratio = width / height;
|
||||
const options = [
|
||||
["16:9", 16 / 9],
|
||||
["4:3", 4 / 3],
|
||||
["1:1", 1],
|
||||
["3:4", 3 / 4],
|
||||
["9:16", 9 / 16],
|
||||
["21:9", 21 / 9],
|
||||
] as const;
|
||||
return options.reduce((best, item) => (Math.abs(item[1] - ratio) < Math.abs(best[1] - ratio) ? item : best), options[0])[0];
|
||||
}
|
||||
|
||||
export function seedancePixelLabel(resolution: string, ratio: string) {
|
||||
const normalizedResolution = normalizeSeedanceResolution(resolution) as keyof typeof seedancePixels;
|
||||
const normalizedRatio = normalizeSeedanceRatio(ratio) as keyof (typeof seedancePixels)[typeof normalizedResolution] | "adaptive";
|
||||
if (normalizedRatio === "adaptive") return "自动匹配";
|
||||
return seedancePixels[normalizedResolution][normalizedRatio] || "";
|
||||
}
|
||||
|
||||
export function boolConfig(value: string | undefined, fallback: boolean) {
|
||||
if (value === "true") return true;
|
||||
if (value === "false") return false;
|
||||
return fallback;
|
||||
}
|
||||
Reference in New Issue
Block a user