104 lines
3.9 KiB
TypeScript
104 lines
3.9 KiB
TypeScript
export const VIDEO_DURATION_AUTO = -1;
|
|
export const VIDEO_DURATION_MIN = 4;
|
|
export const VIDEO_DURATION_MAX = 15;
|
|
export const VIDEO_DURATION_MAX_SEEDANCE_25 = 30;
|
|
export const VIDEO_DURATION_DEFAULT = 5;
|
|
export const VIDEO_DURATION_OPTIONS = Array.from(
|
|
{ length: VIDEO_DURATION_MAX - VIDEO_DURATION_MIN + 1 },
|
|
(_, index) => VIDEO_DURATION_MIN + index
|
|
);
|
|
|
|
export const VIDEO_RATIO_DEFAULT = "9:16";
|
|
export const VIDEO_RATIOS = ["9:16", "16:9", "1:1", "4:3", "3:4", "21:9", "adaptive"] as const;
|
|
|
|
export const VIDEO_RESOLUTION_DEFAULT = "720p";
|
|
export const VIDEO_RESOLUTIONS = ["720p", "1080p", "480p"] as const;
|
|
export const VIDEO_FAST_RESOLUTIONS = ["720p", "480p"] as const;
|
|
|
|
export const SEEDANCE_20_MODEL = "doubao-seedance-2-0-260128";
|
|
export const SEEDANCE_25_MODEL = "doubao-seedance-2-5-260628";
|
|
export const SEEDANCE_MODELS = [
|
|
{ id: SEEDANCE_20_MODEL, label: "Seedance 2.0" },
|
|
{ id: SEEDANCE_25_MODEL, label: "Seedance 2.5" }
|
|
] as const;
|
|
|
|
export type SeedanceModel = (typeof SEEDANCE_MODELS)[number]["id"];
|
|
|
|
type VideoDurationOptions = {
|
|
allowAuto?: boolean;
|
|
model?: string;
|
|
};
|
|
|
|
export function clampVideoDuration(
|
|
value: unknown,
|
|
fallback = VIDEO_DURATION_DEFAULT,
|
|
options: VideoDurationOptions = {}
|
|
) {
|
|
const duration = Number(value);
|
|
if (!Number.isFinite(duration)) return fallback;
|
|
const rounded = Math.round(duration);
|
|
if (options.allowAuto !== false && rounded === VIDEO_DURATION_AUTO) return VIDEO_DURATION_AUTO;
|
|
return Math.min(seedanceMaximumOutputDuration(options.model), Math.max(VIDEO_DURATION_MIN, rounded));
|
|
}
|
|
|
|
export function normalizeVideoDuration(value: unknown, model?: string) {
|
|
if (value === undefined || value === null || value === "") return undefined;
|
|
return clampVideoDuration(value, VIDEO_DURATION_DEFAULT, { model });
|
|
}
|
|
|
|
export function seedanceMaximumOutputDuration(model?: string) {
|
|
return isSeedance25Model(model) ? VIDEO_DURATION_MAX_SEEDANCE_25 : VIDEO_DURATION_MAX;
|
|
}
|
|
|
|
export function seedanceDurationOptions(model?: string) {
|
|
const maximum = seedanceMaximumOutputDuration(model);
|
|
return Array.from({ length: maximum - VIDEO_DURATION_MIN + 1 }, (_, index) => VIDEO_DURATION_MIN + index);
|
|
}
|
|
|
|
export function normalizeSeedanceModel(value: unknown, fallback: SeedanceModel = SEEDANCE_20_MODEL): SeedanceModel {
|
|
const normalized = String(value || "").trim();
|
|
return isSupportedSeedanceModel(normalized) ? normalized : fallback;
|
|
}
|
|
|
|
export function isSupportedSeedanceModel(value: unknown): value is SeedanceModel {
|
|
const normalized = String(value || "").trim();
|
|
return SEEDANCE_MODELS.some((model) => model.id === normalized);
|
|
}
|
|
|
|
export function isSeedance25Model(model?: string) {
|
|
return String(model || "").trim() === SEEDANCE_25_MODEL;
|
|
}
|
|
|
|
export function normalizeVideoRatio(value: unknown, fallback = VIDEO_RATIO_DEFAULT) {
|
|
const ratio = String(value || "").trim();
|
|
if (isSupportedVideoRatio(ratio)) return ratio;
|
|
return isSupportedVideoRatio(fallback) ? fallback : VIDEO_RATIO_DEFAULT;
|
|
}
|
|
|
|
export function normalizeVideoResolution(
|
|
value: unknown,
|
|
model?: string,
|
|
fallback = VIDEO_RESOLUTION_DEFAULT
|
|
) {
|
|
const resolutions = supportedVideoResolutions(model);
|
|
const resolution = String(value || "").trim();
|
|
if (isSupportedVideoResolution(resolution, model)) return resolution;
|
|
return (resolutions as readonly string[]).includes(fallback) ? fallback : VIDEO_RESOLUTION_DEFAULT;
|
|
}
|
|
|
|
export function supportedVideoResolutions(model?: string) {
|
|
return isSeedanceFastModel(model) ? VIDEO_FAST_RESOLUTIONS : VIDEO_RESOLUTIONS;
|
|
}
|
|
|
|
export function isSeedanceFastModel(model?: string) {
|
|
return String(model || "").toLowerCase().replace(/\./g, "-").includes("seedance-2-0-fast");
|
|
}
|
|
|
|
function isSupportedVideoRatio(value: string): value is (typeof VIDEO_RATIOS)[number] {
|
|
return VIDEO_RATIOS.includes(value as (typeof VIDEO_RATIOS)[number]);
|
|
}
|
|
|
|
function isSupportedVideoResolution(value: string, model?: string) {
|
|
return (supportedVideoResolutions(model) as readonly string[]).includes(value);
|
|
}
|