import React, { useEffect, useState } from "react"; import { Dialog, DialogTitle, DialogContent, DialogActions, Stack, Box, Typography, TextField, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, Tooltip, } from "@mui/material"; import { Info as InfoIcon } from "@mui/icons-material"; import { PrimaryButton, SecondaryButton } from "../ui"; import type { VideoGenerationSettings } from "../types"; interface VideoRegenerateModalProps { open: boolean; onClose: () => void; onGenerate: (settings: VideoGenerationSettings) => void; initialPrompt: string; initialResolution?: "480p" | "720p"; initialSeed?: number | null; // Add context props sceneTitle?: string; bible?: any; analysis?: any; } export const VideoRegenerateModal: React.FC = ({ open, onClose, onGenerate, initialPrompt, initialResolution = "480p", initialSeed = -1, sceneTitle, bible, analysis, }) => { // Use a more intelligent default prompt based on context if available const [prompt, setPrompt] = useState(initialPrompt); // Update prompt when modal opens - build enhanced prompt from context useEffect(() => { if (open) { // Always build an enhanced prompt from available context const parts = []; // Add scene context if (sceneTitle) parts.push(`Scene: ${sceneTitle}`); // Add bible/persona context if (bible?.host_persona) parts.push(`Host Persona: ${bible.host_persona}`); if (bible?.tone) parts.push(`Tone: ${bible.tone}`); if (bible?.visual_style) parts.push(`Visual Style: ${bible.visual_style}`); if (bible?.background) parts.push(`Background: ${bible.background}`); // Add analysis context if (analysis?.content_type) parts.push(`Content Type: ${analysis.content_type}`); if (analysis?.audience) parts.push(`Target: ${analysis.audience}`); if (analysis?.guestName) parts.push(`Guest: ${analysis.guestName}`); if (analysis?.keyTakeaways?.length) parts.push(`Key: ${analysis.keyTakeaways[0]}`); // Build enhanced prompt let smartPrompt = ""; if (parts.length > 0) { smartPrompt = `Professional podcast video. ${parts.join(". ")}. Cinematic lighting, high detail, 4k quality, smooth subtle motion.`; } else { // Fallback to initial prompt smartPrompt = initialPrompt || "Professional podcast scene with subtle movement"; } setPrompt(smartPrompt); } }, [open, sceneTitle, bible, analysis]); const [resolution, setResolution] = useState<"480p" | "720p">(initialResolution); const [seed, setSeed] = useState(initialSeed != null && initialSeed !== -1 ? String(initialSeed) : ""); const [maskImageUrl, setMaskImageUrl] = useState(""); const handleGenerate = () => { const parsedSeed = seed.trim() === "" ? undefined : Number.isNaN(Number(seed)) ? undefined : Number(seed); const settings: VideoGenerationSettings = { prompt: prompt.trim(), resolution, seed: parsedSeed, maskImageUrl: maskImageUrl.trim() || undefined, }; onGenerate(settings); }; return ( Configure Video Generation Fine-tune how this scene is animated. InfiniteTalk is audio-driven, so use the prompt to describe the visual look and feel you want while keeping it concise. {/* Prompt */} Visual prompt setPrompt(e.target.value)} placeholder="Short description of how the scene should look (lighting, mood, camera feel, etc.)" variant="outlined" InputProps={{ sx: { bgcolor: "rgba(15,23,42,0.9)", color: "white", "& .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(148,163,184,0.4)", }, "&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(125,211,252,0.8)", }, }, }} InputLabelProps={{ sx: { color: "rgba(148,163,184,0.9)" }, }} /> Example: "Modern podcast studio with soft lighting, the host framed center, gentle camera movement." {/* Resolution */} Resolution & quality setResolution(e.target.value as "480p" | "720p")} > } label={ 480p (Recommended) Faster render, lower cost, great for previews & social } /> } label={ 720p (Higher quality) Sharper video, slightly higher cost and render time } /> {/* Seed & advanced options */} Seed (optional) setSeed(e.target.value)} placeholder="Random each time if left empty" InputProps={{ sx: { bgcolor: "rgba(15,23,42,0.9)", color: "white", "& .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(148,163,184,0.4)", }, "&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(125,211,252,0.8)", }, }, }} /> Use the same seed to get a similar animation style across multiple scenes. Mask image URL (optional) setMaskImageUrl(e.target.value)} placeholder="e.g. /api/podcast/images/your_avatar_mask.png" InputProps={{ sx: { bgcolor: "rgba(15,23,42,0.9)", color: "white", "& .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(148,163,184,0.4)", }, "&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "rgba(125,211,252,0.8)", }, }, }} /> Optional: limit animation to a specific region (e.g. face) by providing a mask image URL. Leave empty to animate the whole frame. Estimated cost at 480p is lower than 720p. You'll only be billed for successful renders. Cancel Generate Video ); }