107 lines
3.5 KiB
TypeScript
107 lines
3.5 KiB
TypeScript
export type VideoDurationCostMap = Record<string, number>;
|
|
|
|
export type VideoImageGenConfigLike = {
|
|
creditCostPerVideo?: number | null;
|
|
videoDurationOptions?: number[] | null;
|
|
creditCostPerVideoByDuration?: Record<string, number> | null;
|
|
};
|
|
|
|
function normalizePositiveInteger(value: unknown) {
|
|
const normalized = Number(value);
|
|
if (!Number.isFinite(normalized)) return null;
|
|
const rounded = Math.round(normalized);
|
|
if (rounded < 1) return null;
|
|
return rounded;
|
|
}
|
|
|
|
export function normalizeVideoDurationOptions(value: unknown): number[] {
|
|
if (!Array.isArray(value)) return [];
|
|
|
|
return Array.from(
|
|
new Set(
|
|
value
|
|
.map((item) => normalizePositiveInteger(item))
|
|
.filter((item): item is number => item !== null)
|
|
)
|
|
).sort((left, right) => left - right);
|
|
}
|
|
|
|
export function normalizeVideoDurationCostMap(
|
|
value: unknown,
|
|
durationOptions?: readonly number[] | null
|
|
): VideoDurationCostMap | undefined {
|
|
if (!value || typeof value !== "object") return undefined;
|
|
|
|
const allowedDurations = Array.isArray(durationOptions)
|
|
? new Set(durationOptions.map((item) => String(item)))
|
|
: null;
|
|
const entries = Object.entries(value as Record<string, unknown>)
|
|
.map(([durationKey, costValue]) => {
|
|
const normalizedDuration = normalizePositiveInteger(durationKey);
|
|
const normalizedCost = Number(costValue);
|
|
if (normalizedDuration === null || !Number.isFinite(normalizedCost)) {
|
|
return null;
|
|
}
|
|
const durationText = String(normalizedDuration);
|
|
if (allowedDurations && !allowedDurations.has(durationText)) {
|
|
return null;
|
|
}
|
|
return [durationText, Math.max(0, Math.round(normalizedCost))] as const;
|
|
})
|
|
.filter((entry): entry is readonly [string, number] => Boolean(entry));
|
|
|
|
if (entries.length === 0) return undefined;
|
|
return Object.fromEntries(entries);
|
|
}
|
|
|
|
export function getConfiguredVideoDurationOptions(
|
|
config: VideoImageGenConfigLike | null | undefined
|
|
): number[] {
|
|
return normalizeVideoDurationOptions(config?.videoDurationOptions);
|
|
}
|
|
|
|
export function buildVideoDurationCostMap(params: {
|
|
durationOptions: readonly number[];
|
|
costMap?: unknown;
|
|
fallbackCost?: number | null | undefined;
|
|
}): VideoDurationCostMap | undefined {
|
|
const fallbackCost = Number.isFinite(Number(params.fallbackCost))
|
|
? Math.max(0, Math.round(Number(params.fallbackCost)))
|
|
: 0;
|
|
const normalizedCostMap =
|
|
normalizeVideoDurationCostMap(params.costMap, params.durationOptions) || {};
|
|
|
|
if (params.durationOptions.length === 0 && Object.keys(normalizedCostMap).length === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
return Object.fromEntries(
|
|
params.durationOptions.map((duration) => {
|
|
const key = String(duration);
|
|
return [key, normalizedCostMap[key] ?? fallbackCost];
|
|
})
|
|
);
|
|
}
|
|
|
|
export function getVideoCreditCostFromConfig(
|
|
config: VideoImageGenConfigLike | null | undefined,
|
|
duration?: number | null
|
|
): number {
|
|
const normalizedDuration = normalizePositiveInteger(duration);
|
|
const durationOptions = getConfiguredVideoDurationOptions(config);
|
|
const durationCostMap = normalizeVideoDurationCostMap(
|
|
config?.creditCostPerVideoByDuration,
|
|
durationOptions
|
|
);
|
|
|
|
if (normalizedDuration !== null && durationCostMap) {
|
|
const durationKey = String(normalizedDuration);
|
|
if (Object.prototype.hasOwnProperty.call(durationCostMap, durationKey)) {
|
|
return durationCostMap[durationKey] || 0;
|
|
}
|
|
}
|
|
|
|
const fallbackCost = Number(config?.creditCostPerVideo ?? 0);
|
|
return Number.isFinite(fallbackCost) ? Math.max(0, Math.round(fallbackCost)) : 0;
|
|
}
|