import type { VideoCanvasReferenceBehavior, VideoCanvasReferenceSelectionConfig, } from "@/lib/video-canvas/config"; import type { VideoGenerationMode } from "@/types/ai"; export type VideoReferenceEdge = { id: string; source: string; target: string; }; export type VideoReferenceToggleAction = "add" | "limit" | "remove"; function normalizeModelIdentity(value: string) { return value.toLowerCase().replace(/[\s._-]+/g, ""); } export function resolveVideoReferenceSelectionRule( config: VideoCanvasReferenceSelectionConfig, modelIdentity: string, ): VideoCanvasReferenceBehavior { const normalizedIdentity = normalizeModelIdentity(modelIdentity); const matchedRule = config.modelRules.find((rule) => { const normalizedPattern = normalizeModelIdentity(rule.modelPattern); return normalizedPattern && normalizedIdentity.includes(normalizedPattern); }); const rule = matchedRule || config.defaultRule; return { autoExit: rule.autoExit, hideActionAtLimit: rule.hideActionAtLimit, maxImages: rule.maxImages, mode: rule.mode, }; } export function resolveVideoReferenceToggleAction( referenceEdges: T[], sourceId: string, targetId: string, maxReferences: number, ): VideoReferenceToggleAction { if ( referenceEdges.some( (edge) => edge.source === sourceId && edge.target === targetId, ) ) { return "remove"; } const referenceCount = referenceEdges.filter( (edge) => edge.target === targetId, ).length; return referenceCount >= Math.max(1, Math.round(maxReferences)) ? "limit" : "add"; } export function selectVideoReferenceImages( images: string[], mode: VideoGenerationMode, maxReferenceImages = 4, ) { if (mode === "text-to-video" || mode === "audio-to-video") return []; if (mode === "first-frame") return images.slice(0, 1); if (mode === "first-last-frame") return images.slice(0, 2); return images.slice(0, Math.max(1, Math.round(maxReferenceImages))); } export function removeVideoReferenceEdge( edges: T[], sourceId: string, targetId: string ) { return edges.filter( (edge) => !(edge.source === sourceId && edge.target === targetId) ); } export function toggleVideoReferenceEdge( edges: T[], sourceId: string, targetId: string, createEdge: () => T ) { const connected = edges.some( (edge) => edge.source === sourceId && edge.target === targetId ); return connected ? removeVideoReferenceEdge(edges, sourceId, targetId) : [...edges, createEdge()]; }