/* Tab: Generar Clips (workspace) — kie.ai Gemini Omni */ function GenerateClipsTab() { const [prompt, setPrompt] = React.useState(""); const [duration, setDuration] = React.useState(8); const [aspectRatio, setAspectRatio] = React.useState("16:9"); const [generateAudio, setGenAudio] = React.useState(true); const [generating, setGenerating] = React.useState(false); const [clips, setClips] = React.useState([]); const [loading, setLoading] = React.useState(true); const [preview, setPreview] = React.useState(null); const [genError, setGenError] = React.useState(""); React.useEffect(() => { fetchClips(); }, []); React.useEffect(() => { const hasProcessing = clips.some((c) => c.status === "processing"); if (!hasProcessing) return; const id = setInterval(fetchClips, 4000); return () => clearInterval(id); }, [clips]); async function fetchClips() { try { const r = await fetch("/api/workspace/clips", { credentials: "same-origin" }); if (r.ok) { const d = await r.json(); setClips(d.clips || []); } } finally { setLoading(false); } } async function handleGenerate() { if (!prompt.trim() || generating) return; setGenerating(true); setGenError(""); try { const r = await fetch("/api/workspace/clips/generate", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "same-origin", body: JSON.stringify({ prompt: prompt.trim(), duration, aspect_ratio: aspectRatio, generate_audio: generateAudio }), }); const d = await r.json(); if (r.ok && d.success) { setClips((prev) => [d.clip, ...prev]); } else { setGenError(d.detail || "Error al iniciar la generación"); } } catch { setGenError("Error de conexión"); } finally { setGenerating(false); } } async function handleDelete(id) { const r = await fetch(`/api/workspace/clips/${id}`, { method: "DELETE", credentials: "same-origin" }); if (r.ok) { setClips((prev) => prev.filter((c) => c.id !== id)); if (preview && preview.id === id) setPreview(null); } } function handleKeyDown(e) { if ((e.ctrlKey || e.metaKey) && e.key === "Enter") handleGenerate(); } const processing = clips.filter((c) => c.status === "processing").length; return (
{/* ── Left panel ── */}