ai-chatbot/lib/video-canvas/tvstar-session.ts

72 lines
3.2 KiB
TypeScript

import { z } from "zod";
const boundedText = z.string().max(12_000);
const timestamp = z.number().int().nonnegative().max(8_640_000_000_000_000);
const referenceSchema = z.object({
id: z.string().max(200), title: z.string().max(256), url: z.string().max(4096),
type: z.enum(["image", "video"]), duration: z.number().optional(),
});
const nodeContextSchema = z.object({
id: z.string().max(200), title: z.string().max(256), type: z.string().max(100), description: boundedText,
});
const shotSchema = z.object({
shot: boundedText.default(""), duration: boundedText.default(""), scene: boundedText.default(""), sceneDescription: boundedText,
shotSize: boundedText.default(""), lighting: boundedText.default(""), dialogue: boundedText.default(""), backgroundMusic: boundedText.default(""),
voiceAndSfx: boundedText.default(""), cameraMovement: boundedText.default(""), imagePrompt: boundedText.default(""),
motionPrompt: boundedText.default(""), keyframeUrl: z.string().max(4096).default(""),
});
export const tvstarSessionSchema = z.object({
id: z.string().uuid(),
title: z.string().min(1).max(256),
goal: boundedText,
mode: z.enum(["full", "brainstorm", "script", "storyboard", "edit"]),
plan: z.object({
summary: boundedText, agentPlan: z.array(boundedText).max(30),
deliverables: z.array(boundedText).max(30), recommendedNodes: z.array(boundedText).max(30),
model: z.string().max(256).optional(),
}).optional(),
shots: z.array(shotSchema).max(12).optional(),
references: z.array(referenceSchema).max(6).optional(),
nodeContexts: z.array(nodeContextSchema).max(6).optional(),
messages: z.array(z.object({
id: z.string().max(200), role: z.enum(["user", "assistant"]),
content: boundedText, createdAt: timestamp,
})).max(500).optional(),
imageModelRef: z.string().max(256).optional(),
videoModelRef: z.string().max(256).optional(),
autoGenerate: z.boolean().optional(),
createdAt: timestamp,
updatedAt: timestamp,
pendingStage: z.enum(["plan", "shots", "submit"]).optional(),
runSubmitted: z.boolean().optional(),
preparedOnly: z.boolean().optional(),
groupId: z.string().max(200).optional(),
});
export type StoredTVstarSession = z.infer<typeof tvstarSessionSchema>;
export function mergeTVstarSessions<T extends { id: string; createdAt: number; updatedAt?: number }>(
local: T[], remote: T[]
): T[] {
const byId = new Map<string, T>();
for (const item of [...remote, ...local]) {
const previous = byId.get(item.id);
if (!previous || (item.updatedAt || item.createdAt) >= (previous.updatedAt || previous.createdAt)) {
byId.set(item.id, item);
}
}
return [...byId.values()].sort((a, b) => (b.updatedAt || b.createdAt) - (a.updatedAt || a.createdAt)).slice(0, 20);
}
export function publicTVstarSnapshot(session: StoredTVstarSession) {
return {
title: session.title,
goal: session.goal,
createdAt: session.createdAt,
messages: (session.messages || []).map(({ role, content, createdAt }) => ({ role, content, createdAt })),
plan: session.plan ? { summary: session.plan.summary, deliverables: session.plan.deliverables } : null,
shots: (session.shots || []).map(({ shot, duration, sceneDescription }) => ({ shot, duration, sceneDescription })),
};
}