OpenCut/propuesta_tecnica.md

45 KiB

Propuesta Técnica — Agente Conversacional para Edición de Video

Proyecto Expoandes | Introducción a la Ingeniería de Sistemas y Computación


0. Tabla de contenidos

  1. Resumen del proyecto
  2. Problema y solución
  3. Diferenciador competitivo
  4. Arquitectura general
  5. Stack tecnológico completo
  6. Capa de abstracción de proveedores (clave)
  7. Detalle de tools del agente (skills)
  8. Flujos de usuario end-to-end
  9. Plan de desarrollo (Scrum)
  10. Consideraciones de performance y costos
  11. Estrategia de demo para feria
  12. Riesgos y mitigaciones
  13. Apéndices técnicos

1. Resumen del proyecto

Nombre tentativo: [Por definir]

Una línea: Un editor de video web con un agente conversacional que entiende lenguaje natural y edita por ti. Lo que Cursor es a VSCode, esto es a CapCut.

Entregable: MVP funcional desplegado en web, con un agente capaz de ejecutar al menos 8 "skills" de edición a partir de instrucciones en lenguaje natural.


2. Problema y solución

Problema identificado

Los creadores de contenido pequeños y medianos (YouTubers, tiktokers, podcasters, educadores, periodistas estudiantes) invierten entre 3 y 5 horas editando cada pieza de contenido. La mayor parte de ese tiempo se consume en tareas mecánicas:

  • Cortar silencios y muletillas ("eh", "emm", "o sea")
  • Encontrar los mejores momentos en grabaciones largas
  • Generar subtítulos con estilo
  • Reformatear entre aspect ratios (horizontal → vertical)
  • Aplicar corrección de color básica
  • Sincronizar cortes con música

Las herramientas actuales resuelven piezas aisladas pero todas exigen aprender una interfaz compleja y ejecutar cada acción manualmente.

Solución

Un editor de video con un agente conversacional autónomo que ejecuta estas tareas por instrucción en lenguaje natural, pero mantiene siempre la edición manual tradicional como respaldo.

Ejemplo concreto:

Usuario: "Tengo un video de 5 minutos de mí explicando el proyecto. Hazme un reel de 30 segundos con los mejores momentos, subtítulos amarillos estilo TikTok, y formato vertical siguiendo mi cara."

Agente: [transcribe → analiza escenas → identifica momentos de alta energía → corta → reencuadra dinámicamente → renderiza subtítulos → entrega]


3. Diferenciador competitivo

Producto Edición manual Agente conversacional Multimodal Open source base
CapCut / Premiere
Descript ⚠️ (via transcripción)
Opus Clip ⚠️ (automático fijo) ⚠️
Runway ⚠️
DeeVid.ai / Sora (genera)
Nuestra propuesta

El moat técnico: esto no es una caja negra que genera contenido y ya — es un editor de video completo donde el usuario mantiene control total. Lo que Cursor es a VSCode, NeuralCut es a CapCut: un agente autónomo que opera sobre una herramienta real, no un generador sin ventana de edición. El usuario puede hablarle en lenguaje natural Y editar manualmente en la misma interfaz.


4. Arquitectura general

╔══════════════════════════════════════════════════════════╗
║                    NAVEGADOR DEL USUARIO                  ║
║                                                            ║
║  ┌────────────────────────┐  ┌────────────────────────┐  ║
║  │   UI NeuralCut (web)   │  │   Panel de chat nuevo  │  ║
║  │                         │  │                         │  ║
║  │  • Timeline multi-pista│  │  • Historial de chat   │  ║
║  │  • Preview             │  │  • Input de texto      │  ║
║  │  • Media bin           │  │  • Streaming response  │  ║
║  │  • Efectos             │  │  • Approvals inline    │  ║
║  └───────────┬────────────┘  └───────────┬────────────┘  ║
║              │                             │               ║
║              └─────────────┬───────────────┘               ║
║                            ▼                               ║
║  ┌───────────────────────────────────────────────────┐   ║
║  │            ZUSTAND STORES (estado único)          │   ║
║  │  editorStore · timelineStore · mediaStore         │   ║
║  │  playbackStore · chatStore · agentStore           │   ║
║  └───────────────────────────────────────────────────┘   ║
║                            │                               ║
║         ┌──────────────────┼──────────────────┐           ║
║         ▼                  ▼                  ▼           ║
║  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   ║
║  │ FFmpeg.wasm  │  │  MediaBunny  │  │  WebCodecs   │   ║
║  │ (operaciones │  │  (extracción │  │  (decode/    │   ║
║  │  complejas)  │  │   rápida)    │  │   encode)    │   ║
║  └──────────────┘  └──────────────┘  └──────────────┘   ║
║                                                            ║
║  ┌───────────────────────────────────────────────────┐   ║
║  │  STORAGE: IndexedDB + OPFS (ya en NeuralCut)      │   ║
║  └───────────────────────────────────────────────────┘   ║
╚══════════════════════════════════════════════════════════╝
                             │
                             ▼ (HTTPS)
╔══════════════════════════════════════════════════════════╗
║        CAPA DEL AGENTE (TypeScript — apps/web/)          ║
║                                                            ║
║  Orquestación, tool calling, streaming, estado:           ║
║                                                            ║
║  agent/orchestrator.ts → coordina LLM + tools            ║
║  agent/tools/*.ts       → definiciones de cada tool       ║
║  agent/prompts/         → system prompt y templates       ║
║  providers/             → abstracción de proveedores      ║
║  app/api/agent/         → Next.js API routes              ║
║                                                            ║
║  El agente es I/O-bound: llama APIs, parsea JSON,        ║
║  maneja streaming. No necesita Rust.                      ║
╚══════════════════════════════════════════════════════════╝
               │                              │
               │ cuando necesita               │ siempre
               │ procesamiento                 │ para LLMs
               │ pesado                        │ / APIs
               ▼                              ▼
╔════════════════════════╗    ╔══════════════════════════╗
║  rust/ — PROCESAMIENTO ║    ║  PROVEEDORES EXTERNOS     ║
║  (WASM, CPU-bound)     ║    ║                            ║
║                        ║    ║  ┌─────────────────────┐  ║
║  • compositor/         ║    ║  │ LOCAL (dev, gratis)  │  ║
║  • effects/            ║    ║  │ Qwen2.5-VL (Ollama) │  ║
║  • gpu/                ║    ║  │ whisper.cpp         │  ║
║  • masks/              ║    ║  │ Qwen3-8B           │  ║
║  • time/               ║    ║  └─────────────────────┘  ║
║  • bridge/             ║    ║  ┌─────────────────────┐  ║
║                        ║    ║  │ CLOUD (demo, rápido)│  ║
║  Detección de silencios║    ║  │ Gemini 2.5 Flash   │  ║
║  Detección de escenas  ║    ║  │ Claude Opus/Haiku   │  ║
║  Face tracking         ║    ║  │ Whisper API        │  ║
║  Beat detection        ║    ║  └─────────────────────┘  ║
╚════════════════════════╝    ╚══════════════════════════╝

5. Stack tecnológico completo

5.1. Frontend y base del editor

Tecnología Rol Justificación
Fork de OpenCut (NeuralCut) Base del editor CapCut open source (MIT, 48k★). Timeline, preview, storage ya funcionan. Nos permite enfocarnos en el agente.
Next.js 16 Framework React Ya viene en el fork. App Router, API routes, deploy trivial en Vercel.
React 19 UI Estándar.
Zustand State management Ya viene en OpenCut. Simple y reactivo.
Tailwind CSS Styling Ya viene en OpenCut.
shadcn/ui Componentes UI Para el panel de chat nuevo.
Bun Runtime / package manager Ya viene en OpenCut. 3-5x más rápido que npm.

5.1.1. Decisión arquitectónica: TypeScript para el agente, Rust para procesamiento

El agente conversacional (orquestación, tool calling, providers, streaming) se implementa en TypeScript dentro de apps/web/src/agent/. Las razones:

  • I/O-bound: el 90% del trabajo del agente es llamar APIs, esperar respuestas y parsear JSON. Rust no agrega valor acá.
  • Ecosistema maduro: Vercel AI SDK, Anthropic SDK, OpenAI SDK, streaming con ReadableStream — todo first-class en TS. En Rust no hay equivalentes.
  • WASM no tiene networking: para llamar a Gemini o Claude desde Rust+WASM habría que hacer un bridge a JS, lo cual es un roundtrip innecesario.
  • Iteración rápida: prompts y tool definitions cambian constantemente. Hot reload en TS vs compile time en Rust.

Rust (rust/) se reserva exclusivamente para procesamiento CPU-bound que corre en el browser via WASM: composición de video, efectos, detección de silencios/escenas, face tracking, beat detection. El agente en TS llama a estas funciones Rust cuando necesita poder de cálculo.

5.2. Procesamiento de video (client-side)

Tecnología Rol Notas
FFmpeg.wasm Operaciones complejas (cortes, filtros, export) Ya integrado en OpenCut. Lento pero universal.
MediaBunny Extracción de frames y conversiones rápidas 5x más rápido que FFmpeg.wasm en muchas operaciones. Remotion lo recomienda oficialmente desde 2025.
WebCodecs API Decode/encode con aceleración de hardware Nativo del browser. Más rápido que cualquier WASM.

5.3. IA — Capas del agente

Orquestador (LLM principal)

Proveedor Modelo recomendado Uso
Anthropic Claude Opus 4.7 Razonamiento complejo, tool calling confiable
Anthropic Claude Haiku 4.5 Decisiones simples y rápidas (más barato)
OpenAI GPT-5 Alternativa
Local Qwen3-8B Para desarrollo

Estrategia: usar Haiku para 80% de decisiones (rápidas/simples) y escalar a Opus solo para razonamiento complejo.

Video Understanding (la killer feature)

Proveedor Modelo Cuándo usarlo
Google Gemini 2.5 Flash Producción/demo. Procesa hasta 6h de video con timestamps nativos.
Google Gemini 2.5 Pro Casos complejos. Más caro.
Local Qwen2.5-VL-7B Desarrollo local. Gratis. Entiende video con timestamps nativamente.
Local Qwen2.5-VL-3B Laptops con menos recursos.

Transcripción (Speech-to-Text)

Proveedor Modelo Notas
OpenAI Whisper API $0.006/min. Más barato. Mejor accuracy en benchmarks.
OpenAI gpt-4o-transcribe Más preciso, más caro
AssemblyAI Universal-2 Mejor formateo, diarización incluida
Local whisper.cpp Gratis, corre en CPU decentemente
Local faster-whisper Más rápido en GPU

Visión computacional (detección)

Tecnología Rol
MediaPipe Tasks for Web Detección de caras, pose, manos — corre en el browser
ONNX Runtime Web + YOLO Detección de objetos general
TransNetV2 Detección avanzada de transiciones de escena

Audio

Tecnología Rol
Web Audio API Análisis nativo (RMS, silencios)
Essentia.js Detección de beats, tempo, tonalidad
FFmpeg silencedetect Detección alternativa de silencios

5.4. Backend y deploy

Tecnología Rol
Next.js API Routes Proxy a LLMs, no lógica pesada
Vercel Edge Functions Deploy gratis, global
Vercel Hosting

5.5. Storage

Tecnología Rol
IndexedDB + OPFS Primary (ya en OpenCut) — storage local persistente
Cloudflare R2 / Supabase Solo para compartir exports (opcional)

6. Capa de abstracción de proveedores (la joya del diseño)

Objetivo: poder alternar entre modelos locales (dev, gratis) y APIs (producción, rápido) sin cambiar código. Solo cambiando una variable de entorno.

6.1. Interfaces abstractas

// Interfaz común para todos los proveedores de visión multimodal
interface VisionProvider {
  analyzeVideo(
    videoPath: string,
    prompt: string,
    options?: { maxTokens?: number; temperature?: number }
  ): Promise<{
    response: string;
    timestamps?: Array<{ time: string; description: string }>;
    usage: { inputTokens: number; outputTokens: number; cost: number };
  }>;
  
  analyzeImages(
    images: string[],
    prompt: string
  ): Promise<{ response: string; usage: Usage }>;
}

// Interfaz común para STT
interface TranscriptionProvider {
  transcribe(
    audioPath: string,
    options?: { language?: string; wordTimestamps?: boolean }
  ): Promise<{
    text: string;
    segments: Array<{ start: number; end: number; text: string }>;
    words?: Array<{ word: string; start: number; end: number }>;
  }>;
}

// Interfaz común para el LLM orquestador
interface LLMProvider {
  chat(
    messages: Message[],
    tools?: Tool[],
    options?: ChatOptions
  ): AsyncGenerator<ChatChunk>;
}

6.2. Implementaciones intercambiables

// Cada proveedor implementa la misma interfaz
class GeminiVisionProvider implements VisionProvider { ... }
class QwenLocalVisionProvider implements VisionProvider { ... }
class ClaudeVisionProvider implements VisionProvider { ... }

class WhisperAPIProvider implements TranscriptionProvider { ... }
class WhisperLocalProvider implements TranscriptionProvider { ... }
class AssemblyAIProvider implements TranscriptionProvider { ... }

class ClaudeLLMProvider implements LLMProvider { ... }
class OpenAILLMProvider implements LLMProvider { ... }
class OllamaLLMProvider implements LLMProvider { ... }

6.3. Factory y configuración

// providers/factory.ts
export function getVisionProvider(): VisionProvider {
  const provider = process.env.VISION_PROVIDER || 'local';
  
  switch (provider) {
    case 'gemini':
      return new GeminiVisionProvider({
        apiKey: process.env.GEMINI_API_KEY!,
        model: 'gemini-2.5-flash'
      });
    case 'claude':
      return new ClaudeVisionProvider({
        apiKey: process.env.ANTHROPIC_API_KEY!,
        model: 'claude-opus-4-7'
      });
    case 'local':
      return new QwenLocalVisionProvider({
        endpoint: process.env.LOCAL_MODEL_ENDPOINT || 'http://localhost:11434',
        model: 'qwen2.5vl:7b'
      });
    default:
      throw new Error(`Unknown vision provider: ${provider}`);
  }
}

6.4. Uso desde el resto del código

// El resto del código NUNCA sabe qué proveedor está usando
import { getVisionProvider } from '@/providers';

async function findFunnyMoments(videoPath: string) {
  const vision = getVisionProvider(); // abstracto
  const result = await vision.analyzeVideo(
    videoPath,
    "Find all timestamps where someone is laughing"
  );
  return result.timestamps;
}

6.5. Configuración por ambiente

# .env.development (día a día de desarrollo)
VISION_PROVIDER=local
TRANSCRIPTION_PROVIDER=local
LLM_PROVIDER=local
LOCAL_MODEL_ENDPOINT=http://localhost:11434

# .env.demo (para feria y demos)
VISION_PROVIDER=gemini
TRANSCRIPTION_PROVIDER=whisper-api
LLM_PROVIDER=claude
GEMINI_API_KEY=...
OPENAI_API_KEY=...
ANTHROPIC_API_KEY=...

Resultado: cambias una variable, todo el código se adapta solo. 90% del desarrollo es gratis, demos finales usan APIs top.


7. Detalle de tools del agente

Cada tool es una función pura que el LLM puede invocar. Se definen con JSON Schema para que el LLM sepa cuándo llamarlas.

Tier 1 — Fundamentales (MVP must-have)

7.1. transcribe_video

{
  name: "transcribe_video",
  description: "Transcribe the audio of a video to text with timestamps",
  input: { video_id: string, language?: string },
  output: {
    segments: [{ start: number, end: number, text: string }],
    words: [{ word: string, start: number, end: number }]
  }
}

Implementación (TS → Whisper API o whisper.cpp local): el agente en TS llama al TranscriptionProvider que abstrae si es API o local.

7.2. detect_silences

{
  name: "detect_silences",
  description: "Find silent parts in audio (for auto-cutting)",
  input: { video_id: string, threshold_db?: number, min_duration?: number },
  output: { silences: [{ start: number, end: number, duration: number }] }
}

Implementación (TS → Web Audio API o Rust WASM): análisis de amplitud en browser, o detección precisa via WASM para archivos grandes.

7.3. detect_scenes

{
  name: "detect_scenes",
  description: "Split video into semantic scenes based on visual changes",
  input: { video_id: string, threshold?: number },
  output: { scenes: [{ start: number, end: number, id: string }] }
}

Implementación (TS → FFmpeg o Rust WASM): frame diff analysis. FFmpeg scene filter para rápido, Rust WASM para precisión.

7.4. cut_segment

{
  name: "cut_segment",
  description: "Cut a segment from the video and add it to the timeline",
  input: { video_id: string, start: number, end: number, track?: number },
  output: { clip_id: string, position: number }
}

Implementación (TS → Zustand store): manipula el timelineStore de NeuralCut directamente desde el agente en TS.

7.5. concat_segments

{
  name: "concat_segments",
  description: "Concatenate multiple segments in the timeline",
  input: { clip_ids: string[] },
  output: { composite_id: string, total_duration: number }
}

Tier 2 — Visión y comprensión

7.6. watch_video

{
  name: "watch_video",
  description: "Ask a question about the visual content of a video. Returns answer with relevant timestamps.",
  input: { video_id: string, question: string },
  output: {
    answer: string,
    relevant_timestamps: [{ time: string, reason: string }]
  }
}

Implementación: Gemini 2.5 Flash (o Qwen2.5-VL local). Esta es la killer feature. Gemini soporta context caching nativo: el video se sube una vez al importar al proyecto, y todas las queries posteriores contra ese video son instantáneas y más baratas. No hay re-upload.

7.7. take_screenshot

{
  name: "take_screenshot",
  description: "Extract a frame from the video at a specific timestamp",
  input: { video_id: string, timestamp: number },
  output: { image_path: string, description?: string }
}

Implementación: MediaBunny o WebCodecs.

7.8. describe_scene

{
  name: "describe_scene",
  description: "Get a text description of what's happening in a scene",
  input: { video_id: string, start: number, end: number },
  output: { description: string, objects: string[], actions: string[] }
}

Tier 3 — Operaciones creativas

7.9. generate_subtitles

{
  name: "generate_subtitles",
  description: "Generate and render styled subtitles",
  input: {
    video_id: string,
    style: "tiktok" | "youtube" | "clean" | "cinematic",
    language?: string,
    color?: string
  },
  output: { subtitle_track_id: string }
}

7.10. apply_lut

{
  name: "apply_lut",
  description: "Apply a color grading LUT to make video look more cinematic",
  input: {
    clip_id: string,
    mood: "warm" | "cool" | "cinematic" | "vintage" | "bright" | "moody"
  },
  output: { effect_id: string }
}

7.11. detect_faces

{
  name: "detect_faces",
  description: "Detect faces in video with bounding boxes per frame",
  input: { video_id: string, start?: number, end?: number },
  output: { faces_per_frame: [{ frame: number, boxes: BoundingBox[] }] }
}

Implementación (TS → MediaPipe Tasks for Web): corre en el browser, el agente en TS orquesta las llamadas.

7.12. auto_reframe

{
  name: "auto_reframe",
  description: "Convert video to a different aspect ratio tracking the main subject",
  input: { 
    video_id: string, 
    target_ratio: "9:16" | "1:1" | "4:5" | "16:9",
    tracking: "face" | "object" | "center"
  },
  output: { reframed_clip_id: string }
}

7.13. detect_beats

{
  name: "detect_beats",
  description: "Detect musical beats in an audio track",
  input: { audio_id: string },
  output: { beats: number[], bpm: number }
}

Implementación (TS → Essentia.js): corre en el browser via Web Worker para no bloquear el main thread.

Tier 4 — Inteligencia de alto nivel

7.14. suggest_highlights

{
  name: "suggest_highlights",
  description: "AI-powered analysis to find the most engaging moments in a video",
  input: { 
    video_id: string, 
    target_duration: number,
    criteria?: "energy" | "humor" | "information" | "visual"
  },
  output: {
    highlights: [{
      start: number,
      end: number,
      score: number,
      reason: string
    }]
  }
}

Este es el pipeline más impresionante. Combina:

  • Transcripción (palabras emocionales)
  • Análisis de audio (picos de volumen, risas)
  • Análisis de escena (cambios, caras, acción)
  • LLM que rankea todo

7.15. remove_filler_words

{
  name: "remove_filler_words",
  description: "Remove 'um', 'uh', 'like', and other filler words from video",
  input: { video_id: string, language?: string },
  output: { cuts_made: number, total_time_saved: number }
}

8. Flujos de usuario end-to-end

Flujo 1: Reel automático

Usuario sube video de 5 min → "hazme un reel vertical de 30s con 
los mejores momentos y subtítulos amarillos"
         │
         ▼
┌──────────────────────────────────────────────────────────┐
│ Agente razona:                                            │
│ "Necesito: analizar video, cortar momentos, reframe,     │
│  subtítulos"                                              │
└──────────────────────────────────────────────────────────┘
         │
         ▼
1. transcribe_video() ────────► transcripción con timestamps
         │
         ▼
2. detect_scenes() ───────────► 12 escenas identificadas
         │
         ▼
3. suggest_highlights(30s) ───► Top 5 momentos rankeados
         │
         ▼
4. Para cada highlight:
   - cut_segment(start, end)
         │
         ▼
5. concat_segments(ids) ──────► Reel de ~30s
         │
         ▼
6. auto_reframe("9:16", face) ► Vertical con tracking
         │
         ▼
7. generate_subtitles(tiktok, yellow) ► Subs estilizados
         │
         ▼
Preview renderizado → usuario aprueba → export final

Flujo 2: Pregunta abierta

Usuario: "¿En qué parte se ve mejor mi iluminación?"
         │
         ▼
Agente llama: watch_video(question="best lighting")
         │
         ▼
Gemini 2.5 / Qwen ve el video, responde:
"Entre 0:23 y 0:31 hay buena iluminación frontal natural. 
Después de 2:45 la luz se vuelve amarillenta."
         │
         ▼
Agente presenta respuesta + timestamps + screenshots

Flujo 3: Edición conversacional iterativa

Usuario: "hazme subtítulos"
Agente: generate_subtitles(default) → listo

Usuario: "más grandes y amarillos"
Agente: actualiza estilo del subtitle_track_id existente

Usuario: "quita la parte donde me equivoco"
Agente: watch_video("where does the person mess up?")
         → identifica timestamp 1:23-1:31
         → pide confirmación
         → cut_segment para remover

9. Plan de desarrollo (Scrum)

9.1. Infraestructura habilitadora inicial (antes de la primera feature)

Antes de implementar la primera feature de producto visible (transcribe_video), el equipo necesita montar una infraestructura mínima habilitadora. Esta capa no entrega todavía el valor completo al usuario, pero crea el canal por el cual el agente puede operar dentro del editor. Sin esto, cualquier tool real quedaría acoplada, improvisada o desconectada de la UI.

Objetivo

Tener un vertical slice técnico mínimo donde:

  • el usuario puede escribir en un panel de chat,
  • el frontend puede enviar ese mensaje al backend,
  • existe un orquestador básico que recibe la intención,
  • existe un registro de tools desacoplado,
  • el agente conoce cuál es el video activo del editor,
  • y una tool mock o real puede devolver un resultado visible en la interfaz.

Componentes de esta infraestructura

1. Superficie de interacción (UI mínima de chat)

  • ChatPanel
  • MessageList
  • InputArea
  • estado de loading, error y mensajes

2. Canal cliente-servidor

  • app/api/agent/chat/route.ts
  • contrato claro de request/response
  • streaming opcional al inicio, respuesta simple como mínimo

3. Orquestador básico del agente

  • agent/orchestrator.ts
  • recibe mensajes + contexto actual
  • decide entre respuesta directa o ejecución de una tool
  • puede arrancar con lógica simple antes del tool calling completo por LLM

4. Registro y contrato de tools

  • agent/tools/index.ts
  • interfaz común para tools
  • schema de input/output
  • executor desacoplado por tool

5. Capa de providers

  • interfaces abstractas (TranscriptionProvider, VisionProvider, LLMProvider)
  • factories por ambiente
  • posibilidad de usar mock/local/cloud sin cambiar el resto del código

6. Estado agéntico y conversacional

  • chatStore
  • agentStore
  • mensajes, estado de ejecución, resultados y errores

7. Integración con el editor actual

  • lectura del video seleccionado o activo
  • validación de que exista media cargada
  • paso de video_id o referencia equivalente a las tools

8. Tipos y contratos compartidos

  • mensajes de chat
  • tool calls
  • tool results
  • transcript segments
  • estado de ejecución del agente

Entregable esperado de esta fase

Al final de esta fase, el equipo debe poder demostrar:

“Escribo en el panel de chat, el mensaje viaja al endpoint del agente, el orquestador procesa la intención y devuelve una respuesta visible en la UI usando una tool mock o una tool real simple.”

Esto no reemplaza la primera feature de producto; la habilita.

9.2. Equipo y roles

  • Scrum Master: coordina reuniones, remueve bloqueos
  • Product Owner: prioriza backlog, dueño de la visión
  • Dev Frontend (2): UI, NeuralCut, panel de chat
  • Dev Backend/IA (1-2): agente (TS), tools, capa de proveedores

9.3. Sprints propuestos (asumiendo ~14 semanas)

Sprint Duración Objetivo Entregable
0 1 semana Setup + aprendizaje NeuralCut corriendo local. Ollama + Qwen funcionando. Cada dev hizo "hola mundo" con APIs.
1 1 semana Empatizar 8-10 entrevistas a creadores de contenido. Mapa de empatía. Declaración del problema validada.
2 1 semana Ideación + diseño Wireframes del panel de chat. Diseño de la capa de abstracción. Decisión de scope de tools.
3 1 semana Infraestructura habilitadora ChatPanel mínimo funcional, chatStore/agentStore, endpoint /api/agent/chat, orquestador básico, registro de tools, tipos compartidos, integración con video activo.
4 1 semana Primer vertical slice real transcribe_video conectada end-to-end con provider real o local, respuesta visible en chat y timestamps persistidos en estado.
5 1 semana Tier 1 tools detect_silences, detect_scenes, cut_segment, concat_segments sobre la base ya creada.
6 1 semana Video understanding watch_video + take_screenshot + describe_scene. Primera demo "wow".
7 1 semana Creative tools generate_subtitles, apply_lut, detect_faces.
8 1 semana Reframe + beats auto_reframe (MediaPipe), detect_beats (Essentia).
9 1 semana Pipeline inteligente suggest_highlights + remove_filler_words.
10 1 semana Refinamiento UX Streaming de respuestas, aprobaciones inline, undo/redo agéntico.
11 1 semana Testing con usuarios 5-10 sesiones de usability testing. Ajustes.
12 1 semana Performance + deploy Optimización, caching, deploy a Vercel.
13 1 semana Preparación feria Videos de ejemplo pre-procesados, afiche, guión de demo.
14 1 semana Buffer + Post Mortem Buffer para imprevistos. Reunión Post Mortem.

9.4. Backlog priorizado (primeras historias)

Infraestructura habilitadora (antes de Sprint 4):

  • Como usuario, veo un panel de chat integrado dentro del editor
  • Como usuario, puedo enviar un mensaje y recibir una respuesta visible del agente
  • Como sistema, el agente conoce cuál es el video activo del proyecto
  • Como sistema, las tools comparten un contrato estable de entrada y salida
  • Como equipo, podemos alternar entre providers mock, locales y cloud sin cambiar la lógica de negocio

Must-have (Sprint 3-5):

  • Como usuario, subo un video y el agente me lo transcribe
  • Como usuario, le pido cortar un segmento específico por timestamp
  • Como usuario, le pido que me identifique las escenas
  • Como usuario, le pregunto sobre el contenido del video y me responde

Should-have (Sprint 6-8):

  • Como usuario, le pido subtítulos con un estilo específico
  • Como usuario, le pido convertir a vertical siguiendo mi cara
  • Como usuario, le pido un resumen automático de los mejores momentos

Nice-to-have (Sprint 9+):

  • Como usuario, puedo deshacer acciones del agente
  • Como usuario, el agente me muestra un preview antes de aplicar cambios grandes
  • Como usuario, comparto el proyecto por URL

10. Consideraciones de performance y costos

10.1. Performance esperado

Operación Tiempo esperado Optimización
Transcripción Whisper API (5 min video) 15-30s Cachear resultado
Gemini 2.5 Flash análisis (2 min video) 10-20s Context caching
Qwen2.5-VL local (2 min video) 30-60s Quantization 4-bit
Corte + export FFmpeg.wasm (30s clip) 10-20s WebCodecs cuando sea posible
Auto-reframe (1 min) 20-40s Process en Web Worker

10.2. Costos de APIs (estimado para todo el semestre)

Servicio Uso estimado Costo estimado
Whisper API 50 horas video $18
Gemini 2.5 Flash ~500 análisis $15-30
Claude Opus ~2000 mensajes $20-40
Total ~$50-90 USD

Mitigaciones:

  • Usar modelos locales durante desarrollo (90% del tiempo)
  • Context caching en Gemini (subir video una vez, preguntar muchas)
  • Aprovechar créditos académicos (Anthropic, Google ofrecen)
  • Free tier generoso de Google AI Studio

10.3. Límites técnicos

  • Tamaño máximo de video en browser: ~500MB (limitación de memoria WebAssembly)
  • Duración máxima recomendada: 10 minutos por video
  • Exports simultáneos: 1 por pestaña
  • Contexto LLM: ~200k tokens suficientes para proyectos típicos

11. Estrategia de demo para feria

11.1. Setup del stand

  • Monitor grande (idealmente 27"+) mostrando la app en Chrome
  • Laptop secundaria corriendo Qwen local como fallback
  • 2-3 celulares listos para subir videos espontáneamente
  • Videos pre-procesados listos para casos demo "seguros"
  • Afiche con arquitectura visual + QR al URL live
  • Hoja de FAQ técnica para jurados técnicos

11.2. Casos demo (por nivel de engagement)

Quick (30s — para visitantes casuales)

"Mira, le hablas y edita". Sube video de 30s pre-cargado → "ponme subtítulos amarillos" → listo.

Medium (2 min — para visitantes interesados)

"Dame tu celular" → graban 30s → "hazme un reel vertical con los mejores momentos" → entrega.

Deep (5 min — para jurados técnicos)

Explicar: arquitectura, capa de abstracción (mostrar cambio local↔cloud en vivo), tool calling, video understanding.

11.3. Respuestas a preguntas esperadas del jurado

"¿Por qué forkear OpenCut en vez de hacerlo desde cero?"

Porque el valor diferencial no está en rehacer el timeline, está en el agente. Forkear nos permitió enfocar el 80% del esfuerzo en lo innovador. Es exactamente la misma decisión que Cursor tomó con VSCode. El fork se llama NeuralCut y estamos migrando lógica a Rust para performance.

"¿Qué pasa si las APIs fallan?"

Diseñamos una capa de abstracción de proveedores. Puedo alternar entre Gemini en la nube y Qwen2.5-VL local sin cambiar código, solo una variable de entorno. [Demostrar en vivo si hay tiempo.]

"¿Esto no existe ya?"

Hay piezas aisladas: Descript edita por transcripción, Opus Clip hace clips automáticos, Runway hace efectos. Nadie tiene un agente conversacional completo sobre un editor tradicional. Es la diferencia entre "feature de IA" y "agente autónomo".

"¿Cómo se monetiza?"

No es foco del proyecto académico, pero el modelo natural sería freemium: local y funciones básicas gratis, APIs premium con suscripción. El usuario objetivo (creadores pequeños) ya paga $10-20/mes por herramientas.

"¿Cuánto cuesta procesarar un video?"

Entre $0.05 y $0.15 por video de 5 minutos usando APIs de producción. Local es gratis pero más lento.


12. Riesgos y mitigaciones

Riesgo Probabilidad Impacto Mitigación
Curva de aprendizaje del codebase de NeuralCut Alta Alto Sprint 0 dedicado exclusivamente a exploración
APIs fallan durante demo Media Alto Fallback a modelos locales (capa de abstracción)
Videos grandes crashean el browser Alta Medio Limitar a <10 min, mostrar warnings, pre-comprimir
Modelo local muy lento en laptops del equipo Media Medio Quantization 4-bit, usar versión 3B en lugar de 7B
Costos de APIs se salen de presupuesto Baja Medio Dashboard de monitoring, límites por usuario, caching agresivo
Alguien del equipo se enferma/sale Media Alto Documentación exhaustiva, pair programming
Demasiado scope Alta Alto Scope definido por tiers — tier 1 es MVP, tier 4 es stretch
Tool calling poco confiable con modelos locales Media Medio Testear con Gemini/Claude en demo, fallback a respuestas pre-armadas

13. Apéndices técnicos

A. Setup de desarrollo paso a paso

# 1. Clonar NeuralCut (nuestro fork)
git clone <repo-url> NeuralCut
cd NeuralCut

# 2. Instalar dependencias
bun install

# 3. Configurar entorno local
cp apps/web/.env.example apps/web/.env.local

# 4. Levantar Docker (Postgres + Redis)
docker compose up -d

# 5. Correr la app (monorepo con Turbo)
bun dev:web
# → http://localhost:3000

# 6. (Opcional) Instalar Ollama para modelos locales
# Mac: brew install ollama
# Linux: curl -fsSL https://ollama.com/install.sh | sh
ollama pull qwen2.5vl:7b
ollama pull qwen3:8b        # para orquestador liviano

B. Estructura de carpetas propuesta

NeuralCut/
├── rust/                                    # Procesamiento pesado (CPU-bound)
│   ├── crates/
│   │   ├── bridge/                          # Puente Rust ↔ JS (WASM bindings)
│   │   ├── compositor/                      # Composición de video
│   │   ├── effects/                         # Filtros y efectos
│   │   ├── gpu/                             # Aceleración GPU
│   │   ├── masks/                           # Mascaramiento
│   │   └── time/                            # Manipulación de tiempo
│   └── wasm/                                # WASM build target
│
├── apps/
│   ├── web/                                 # UI shell + agente (Next.js 16 + React 19)
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── api/
│   │   │   │   │   ├── agent/chat/route.ts  # NUEVO: endpoint del agente (streaming)
│   │   │   │   │   └── tools/               # NUEVO: endpoints de tools
│   │   │   │   │       ├── transcribe/route.ts
│   │   │   │   │       ├── analyze/route.ts
│   │   │   │   │       └── highlights/route.ts
│   │   │   │   └── editor/                  # UI del editor (existente)
│   │   │   │
│   │   │   ├── components/
│   │   │   │   ├── chat/                    # NUEVO: panel de chat
│   │   │   │   │   ├── ChatPanel.tsx
│   │   │   │   │   ├── MessageList.tsx
│   │   │   │   │   ├── InputArea.tsx
│   │   │   │   │   └── ApprovalPrompt.tsx
│   │   │   │   ├── timeline/                # existente
│   │   │   │   └── preview/                 # existente (NO TOCAR)
│   │   │   │
│   │   │   ├── agent/                       # NUEVO: lógica del agente (TS)
│   │   │   │   ├── orchestrator.ts          #   loop principal: LLM → tool → LLM
│   │   │   │   ├── tools/                   #   definiciones de tools + ejecutores
│   │   │   │   │   ├── index.ts             #     registro de todas las tools
│   │   │   │   │   ├── transcribe.ts        #     → llama TranscriptionProvider
│   │   │   │   │   ├── detectSilences.ts    #     → Web Audio API o Rust (WASM)
│   │   │   │   │   ├── detectScenes.ts      #     → FFmpeg o Rust (WASM)
│   │   │   │   │   ├── cutSegment.ts        #     → Zustand store manipulation
│   │   │   │   │   ├── watchVideo.ts        #     → llama VisionProvider
│   │   │   │   │   ├── generateSubtitles.ts #     → TranscriptionProvider + render
│   │   │   │   │   └── ...
│   │   │   │   └── prompts/
│   │   │   │       └── system.ts            #     system prompt template
│   │   │   │
│   │   │   ├── providers/                   # NUEVO: capa de abstracción
│   │   │   │   ├── vision/
│   │   │   │   │   ├── types.ts
│   │   │   │   │   ├── gemini.ts
│   │   │   │   │   ├── qwen-local.ts
│   │   │   │   │   └── index.ts             # factory
│   │   │   │   ├── transcription/
│   │   │   │   │   ├── whisper-api.ts
│   │   │   │   │   ├── whisper-local.ts
│   │   │   │   │   └── index.ts
│   │   │   │   └── llm/
│   │   │   │       ├── claude.ts
│   │   │   │       ├── openai.ts
│   │   │   │       ├── ollama.ts
│   │   │   │       └── index.ts
│   │   │   │
│   │   │   ├── stores/                      # extiende stores existentes
│   │   │   │   ├── ... (existentes)
│   │   │   │   ├── chatStore.ts             # NUEVO
│   │   │   │   └── agentStore.ts            # NUEVO
│   │   │   │
│   │   │   └── lib/
│   │   │       ├── ffmpeg.ts                # wrapper sobre ffmpeg.wasm
│   │   │       ├── mediabunny.ts            # wrapper sobre MediaBunny
│   │   │       └── video-utils.ts
│   │   │
│   │   └── package.json
│   │
│   └── desktop/                             # UI shell (GPUI, futuro)
│
├── package.json                             # workspace root
├── turbo.json
└── docker-compose.yml

Regla de separación Rust ↔ TypeScript:

  • rust/ = CPU-bound: composición, efectos, GPU, detección de silencios/escenas, face tracking, beat detection. Compilado a WASM, llamado desde TS cuando se necesita poder de cálculo.
  • apps/web/src/agent/ = I/O-bound: orquestación del LLM, tool calling, streaming, manejo de estado del chat, definición de tools, provider abstraction. Todo lo que implica llamar APIs, parsear JSON, o manipular el Zustand store va acá.
  • apps/web/src/providers/ = integración con APIs externas (Gemini, Claude, Whisper, Ollama). Nunca en Rust porque WASM no tiene networking nativo.
  • apps/web/src/components/ = UI pura. Solo renderiza lo que los stores dictan.

C. System prompt del agente (borrador)

Eres un asistente experto en edición de video. Tu trabajo es entender 
lo que el usuario quiere hacer con su video y usar las herramientas 
disponibles para ejecutarlo.

PRINCIPIOS:
1. Antes de hacer cambios grandes, muestra un preview o pide confirmación
2. Si no tienes suficiente contexto, usa watch_video o describe_scene
3. Encadena tools lógicamente: primero analiza, después modifica
4. Reporta siempre qué hiciste y por qué

CONTEXTO ACTUAL DEL PROYECTO:
- Videos cargados: {media_list}
- Timeline actual: {timeline_summary}
- Duración total: {total_duration}

HERRAMIENTAS DISPONIBLES:
{tools_schema}

Cuando el usuario pida algo ambiguo, pregunta. Cuando algo sea destructivo,
confirma. Cuando puedas hacerlo con una sola tool, no lo compliques.

D. Ejemplo de integración con Ollama (modo local)

// providers/llm/ollama.ts
import type { LLMProvider, Message, Tool, ChatChunk } from './types';

export class OllamaLLMProvider implements LLMProvider {
  constructor(private config: { endpoint: string; model: string }) {}

  async *chat(
    messages: Message[],
    tools?: Tool[]
  ): AsyncGenerator<ChatChunk> {
    const response = await fetch(`${this.config.endpoint}/api/chat`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        model: this.config.model,
        messages,
        tools,
        stream: true
      })
    });

    const reader = response.body!.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      
      const chunk = decoder.decode(value);
      const lines = chunk.split('\n').filter(l => l.trim());
      
      for (const line of lines) {
        const data = JSON.parse(line);
        yield {
          content: data.message?.content || '',
          toolCalls: data.message?.tool_calls,
          done: data.done
        };
      }
    }
  }
}

E. Recursos y referencias


Cierre

Este documento es un mapa de ruta, no un contrato rígido. El scope se ajustará según el progreso real de cada sprint. La regla es: tier 1 es innegociable, tier 2 es el objetivo, tier 3-4 son bonus.

El éxito del proyecto se mide en tres ejes:

  1. ¿Funciona? El MVP ejecuta al menos 8 tools end-to-end.
  2. ¿Impresiona? El demo de feria genera el "wow" en visitantes.
  3. ¿Aprendimos? Aplicamos Design Thinking + Scrum de forma real, no de fachada.