ai-chatbot/lib/video-canvas/video-motion.ts

64 lines
1.7 KiB
TypeScript

export type VideoCanvasMotionMention = {
custom: boolean;
id: string;
index: number;
label: string;
motionId: string;
offset: number;
previewUrl: string;
prompt: string;
};
function normalizeMotionMentionId(value: unknown) {
return String(value || "")
.trim()
.replace(/[^A-Za-z0-9_-]+/g, "-")
.slice(0, 120);
}
export function normalizeVideoCanvasMotionMentions(
value: unknown,
): VideoCanvasMotionMention[] {
if (!Array.isArray(value)) return [];
return value.slice(0, 100).flatMap((item, position) => {
if (!item || typeof item !== "object") return [];
const record = item as Record<string, unknown>;
const label = String(record.label || "").trim().slice(0, 100);
if (!label) return [];
const motionId =
normalizeMotionMentionId(record.motionId) || `motion-${position + 1}`;
return [{
custom: record.custom === true,
id:
normalizeMotionMentionId(record.id) ||
`motion-mention-${motionId}-${position + 1}`,
index: Math.max(
1,
Math.min(100, Math.round(Number(record.index) || position + 1)),
),
label,
motionId,
offset: Math.max(0, Math.round(Number(record.offset) || 0)),
previewUrl: String(record.previewUrl || "").trim().slice(0, 4096),
prompt: String(record.prompt || label).trim().slice(0, 2000) || label,
}];
});
}
export function composeVideoCanvasMotionPrompt(
prompt: string,
motionMentions: VideoCanvasMotionMention[],
) {
return [
String(prompt || "").trim(),
...motionMentions.map((mention) => {
const instruction = mention.prompt.trim() || mention.label;
return `运镜要求「${mention.label}」:${instruction}`;
}),
]
.filter(Boolean)
.join(" ");
}