126 lines
4.3 KiB
TypeScript
126 lines
4.3 KiB
TypeScript
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;
|
|
}
|