ai-chatbot/lib/canvas/video-reference-selection.ts

90 lines
2.5 KiB
TypeScript

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<T extends VideoReferenceEdge>(
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<T extends VideoReferenceEdge>(
edges: T[],
sourceId: string,
targetId: string
) {
return edges.filter(
(edge) => !(edge.source === sourceId && edge.target === targetId)
);
}
export function toggleVideoReferenceEdge<T extends VideoReferenceEdge>(
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()];
}