rough-cut: corte automático para Premiere Pro
Configuración única: ver INSTALL.md en la raíz del kit. Con el plugin, la línea de configuración es
bash "${CLAUDE_PLUGIN_ROOT}/install.sh" --data "${CLAUDE_PLUGIN_DATA}"; con una instalación manual (las cuatro carpetas skills/ copiadas una al lado de la otra en ~/.claude/skills/), ejecute bash install.sh desde la raíz del kit.
Los scripts residen en la carpeta scripts/ de este skill.
Alcance
- SÍ: un XML de Final Cut Pro 7 (XMEML,
.xml) cuya línea de tiempo ya tiene eliminados las repeticiones, falsos inicios, tropiezos, palabras de relleno y largos silencios; un informe en markdown; marcadores rojos en lo que queda por decidir. - NO: modificar el clip, transcodificar, exportar el video, etalonar, mezclar, elegir entre dos tomas más allá de reformulaciones obvias (eso es decisión del editor).
Regla central: el clip original NUNCA se modifica
El skill solo escribe junto al clip:
<clip>_Derush_v1.xml: la edición a importar (FCP7 / XMEML);<clip>_Derush_v1.report.md,<clip>_Derush_v1.log.txt;<clip>_Derush_v1_work/: la carpeta de trabajo, que se conserva (transcripciones, cortes intermedios).
El XML apunta al clip por ruta absoluta (file://localhost/...): Premiere solo lo referencia. Una nueva pasada crea v2, v3... sin sobrescribir nada.
Lo que hace el usuario (3 pasos)
- En Premiere: importar el clip, ejecutar la transcripción (Panel de texto > Transcribir), guardar el proyecto. La transcripción queda DENTRO del
.prproj: nunca pedir al usuario que la exporte. - Dar a Claude la ruta del clip y el guion de referencia del video si lo hay (texto plano, Markdown, un Google Doc, una página de Notion, cualquier cosa legible). El guion solo sirve para saber si una repetición es deliberada. Sin guion, la pasada sigue funcionando; las repeticiones deliberadas se convierten en banderas en lugar de cortes.
- Importar el
.xml(Archivo > Importar). Aparece una secuenciaDerush_vN, ya editada: los cortes están ausentes de la línea de tiempo (los clips van uno tras otro, no hay nada que cerrar), y las dudas permanecen como clips activos con un marcador rojo.
No preguntar nada más: el idioma, el tipo de clip y las opciones se deducen (ver más abajo), y solo vale la pena hacer una pregunta cuando el tipo de clip es realmente ambiguo.
Idioma
Todo lo específico del idioma (palabras de relleno, frases de falso inicio, patrones de pizarra, conectores huérfanos, aperturas a cortar, alucinaciones de whisper, los textos de razón de los marcadores) vive en languages/<code>.json, nunca en el código. El francés (fr) y el inglés (en) están integrados. El idioma se elige mediante --lang <código>, o el idioma registrado en la transcripción, o en. Detalles y cómo añadir un idioma: references/languages.md.
Pipeline v2: selección de tomas (la ruta normal)
Detectar defectos por sí solo (v1, más abajo) alcanza como máximo un 57% de recall porque whisper silenciosamente deduplica tomas repetidas: su decodificador anti-bucle trata una oración repetida palabra por palabra como una alucinación y la transcribe una sola vez. Esto no se puede arreglar con configuración. La transcripción de Premiere conserva cada toma, palabra por palabra, y sus inicios de palabra no se desplazan después de largos silencios (los de whisper sí). Por lo tanto:
| Paso | Herramienta | Función |
|---|---|---|
| 1 | extract_prproj_transcript.py project.prproj words_premiere.json [--rush CLIP.MOV] | .prproj a words_premiere.json (fuente PRIMARIA). Código de salida 2 si el proyecto no tiene transcripción: pedir al usuario que la ejecute y guarde el proyecto. Alternativa: parse_premiere_transcript.py en una exportación JSON manual |
| 2 | extract_audio.py + transcribe.py | whisper = SEGUNDA OPINIÓN (verificar el texto, nunca los límites) |
| 2b | calibrate_premiere_times.py | realinea la transcripción de Premiere con el audio. Ejecutarlo en CADA corte bruto, justo después de la extracción de audio (no hace nada cuando la transcripción está a tiempo). Mide el desplazamiento por correlación cruzada, ventana por ventana; se ha visto un desfase de 1,8 s al final de un clip de 21 min. Síntoma si se olvida: silence_cuts.py reporta docenas de "ruido sospechoso" |
| 3 | Claude en contexto | análisis semántico: detectar repeticiones, falsos inicios y tropiezos comparando la transcripción de Premiere con el guion y con whisper. Reglas más abajo |
| 4 | silence_cuts.py | silencios >= 1,0 s entre palabras de Premiere, finales de palabra realineados al nivel de sonido, guardia de enumeración (pausas cortas entre dos bloques cortos = ritmo deliberado), zona ruidosa: bandera o corte (ver más abajo). Los valores por defecto están calibrados contra ediciones terminadas: no cambiarlos sin volver a medir (ver references/lessons.md, "Measuring") |
| 5 | apply_takes.py <work> | las tomas decididas en el paso 3 se escriben en takes.json (índices de palabra; los límites o cortes establecidos a mano en segundos son opcionales). El script pone los límites en valles de energía, los fusiona con los silencios, funde los fragmentos mudos que quedan entre dos cortes, realinea cada borde de clip al sonido real, y marca un sonido aislado de menos de 0,25 s en un borde de clip, escribiendo cuts_final.json. protect (mantener un silencio) solo si el usuario lo pide |
| 6 | build_premiere_xml.py | XMEML. Opción meta["audio_file"]: apuntar el audio a un WAV procesado de longitud completa (ver Límites conocidos). Varios clips: un XML por clip, luego merge_xml.py output.xml "name" a.xml b.xml = una sola secuencia, de principio a fin |
| 6b | la edición, transcrita de nuevo | verificación de extremo a extremo: concatenar los intervalos conservados de audio.wav, ejecutar whisper en él, y LEER el texto con los puntos de corte. Detecta lo que otras comprobaciones pasan por alto: silencios dejados en la edición (un clip de 8 s para 3 palabras), palabras recortadas, una toma fallida superviviente |
| 7 | qc_repeat_scan.py | comprobación determinista: código de salida 2 si sobrevive en la edición un 5-grama repetido en 30 s, o si dos palabras que siguen a una pausa o un corte ya se dijeron menos de 8 s de edición antes (una toma repetida con una variante). Cada acierto se verifica contra el guion y de oído (hear.py): retoma superviviente (conservar la ÚLTIMA) O retórica deliberada (anáfora, enumeraciones) |
| 7b | montage_qc.py <work> | el audio de la edición se transcribe y se lee clip por clip, palabras de Premiere (P) contra whisper (W): código de salida 2 en un espacio en blanco > 1,6 s o un fragmento < 1 s. Un borde dudoso se verifica con hear.py audio.wav 12.3-14.0 ... (whisper en porciones aisladas) |
| 8 | report_v2.py | informe: duración de la EDICIÓN y del clip, tomas, dudas; --notes para "conservado a propósito" y pasajes que tocan los puntos sensibles del guion |
Paso 3, las reglas de decisión
Reglas duras:
- texto repetido: conservar la ÚLTIMA toma (incluso si es menos limpia que una anterior);
- tropiezo: conservar la pieza consecutiva más larga;
- duda:
flag, nuncadisable. Infra-cortar siempre es mejor que sobre-cortar: añadir un corte es fácil, recuperar un pasaje perdido es un infierno. - los límites del corte se ajustan a las palabras de Premiere, con aproximadamente 0,15 s de aire antes de la primera palabra conservada.
Reglas aprendidas de ediciones reales:
- Cualquier isla de menos de 2 s apretada entre dos cortes de toma se escucha (
hear.py). Casi siempre es un falso inicio. Nunca juzgarla por el texto de Premiere: un suspiro puede transportar palabras en Premiere, y una alucinación de whisper del tipo "Gracias por ver" significa que no hay palabras en absoluto. - Un silencio con ruido que no es una oración del guion (un comentario al margen, un "aquí vamos", manejar la cámara) se corta, no se marca.
- Un abridor de relleno al inicio de una oración (la lista de "openers" del archivo de idioma, por ejemplo "So," o "Bueno,") se corta.
- El tartamudeo textual dentro de una oración ("Es es") se deshabilita. Pero un nombre repetido a ambos lados de un punto ("menos documentado que Nikon. Nikon tiene muchos documentos") no es un tartamudeo: Premiere puede haberlo escrito como un doble. Escuchar la porción antes de cualquier corte de una sola palabra.
- Conector huérfano (un "Y / Entonces / Pero" aislado) justo antes de un silencio de corte se incluye en el corte. Lo mismo va para cualquier palabra de falso inicio solitaria apretada entre un corte y una pausa seguida de otro ataque.
- Una palabra sin sentido en la transcripción de Premiere sin equivalente en whisper dentro de un comentario redundante es un tropiezo: al menos marcarlo.
- Frase de relleno que no aporta información y repite la siguiente oración: marcar solo (es editorial).
- Una "retoma" puede ser el final de la oración anterior, mal fechado por Premiere (una palabra de 5 s de duración). El texto de whisper de la edición lo muestra.
- Premiere a veces divide una oración en dos: un "falso inicio" de dos palabras puede ser el inicio de la siguiente oración.
- Premiere omite pequeñas palabras murmuradas: cortar una oración repetida puede dejar un inicio huérfano. Escuchar la porción primero; establecer el límite a mano (6º elemento de una entrada en
takes.json). - Una sola palabra duplicada ("el el"): el límite puede comerse la palabra anterior, porque Premiere fecha ambas en el mismo aliento. Escuchar la unión (
ffmpeg atrimde las dos piezas conservadas, luegohear.py). - Una costura entre dos clips: el final del clip 1 y el inicio del clip 2 se escuchan juntos. Una oración comenzada al final del clip 1 y repetida al inicio del clip 2 se corta desde su primera palabra.
- Instrucciones habladas a la cámara para el editor ("esto es para ti, pon algunos gráficos aquí") se cortan como instrucciones y se listan en el informe, porque dicen dónde ilustrar.
- Después de cortar una toma, escuchar el ataque de la toma conservada (una primera palabra puede perderse cuando Premiere tiene dos de ellas).
La transcripción de Premiere está dentro del .prproj
El .prproj es XML comprimido con gzip que contiene un bloque
<ExternallyProvidedTranscriptDocument><TranscriptData Encoding="base64">, cuya carga útil es un búfer FlatBuffers. extract_prproj_transcript.py lo decodifica:
Segment -> f0 i64 start_ticks, f3 vector<Word>, f4 string language
Word -> f0 i64 start_ticks, f1 i64 duration_ticks, f2 string text, f3 f32 confidence
Premiere ticks = 254016000000 por segundo
Los elementos con texto vacío son las PAUSAS marcadas por Premiere (su duración cubre todo el silencio). El script los elimina; de lo contrario, cada espacio entre palabras es 0 y silence_cuts.py no encuentra nada (síntoma: "gaps > 1s: 0" y palabras de 39 s de duración).
Varios clips en un proyecto: el .prproj contiene una transcripción POR clip. --rush NAME.MOV elige la que coincide con la duración del clip (sin ella, la más larga, con una advertencia). Compara el inicio de la última palabra, con un margen de deriva del 0,3% de la duración. Verificar que el recuento de palabras difiere de un clip a otro. Una carpeta de trabajo por clip, luego merge_xml.py.
Dos trampas en esta transcripción:
- Puede derivar en relación con el archivo: paso 2b. Los cortes están en TIEMPO del archivo (eso es lo que lee el XML), por lo que las palabras se corrigen, nunca al revés.
- Las duraciones de las palabras pueden tragarse el silencio que sigue: el silencio ya no existe entre palabras y ya no se corta.
silence_cuts.pydevuelve esas palabras a su final real (trim_overflow). Nunca confiar en un final de palabra de Premiere; solo los inicios son fiables.
Más trampas (palabras fechadas dentro de un silencio, fragmentos mudos, islas diminutas): references/lessons.md.
Límites de corte de toma: en el valle de energía más cercano del inicio de la palabra, con 0,12 s de aire antes del ataque de la palabra conservada. Describir los cortes por índices de palabras, no en segundos: sobreviven a una realineación.
El pipeline v1 (más abajo) sigue siendo el plan de respaldo cuando no hay transcripción de Premiere (advertir que probablemente se perderán las repeticiones palabra por palabra).
Requisitos de la máquina
Comprobados al inicio; si falta algo, señalar a INSTALL.md (references/whisper-setup.md solo para whisper).
brew install whisper-cpp ffmpeg
mkdir -p ~/Models/whisper
curl -L -o ~/Models/whisper/ggml-large-v3-turbo.bin \
https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin
Python 3 con numpy (nada más). Sin clave de API, sin cuenta, nada sale de la máquina después de la descarga del modelo.
Pipeline v1 (plan de respaldo, 8 etapas)
Ejecutado por scripts/derush.py. Cada etapa escribe en <clip>_Derush_vN_work/, junto al clip, nunca se elimina (la reanudación y la inspección siguen siendo posibles).
| # | Script | Función |
|---|---|---|
| 1 | derush.py (punto de entrada) | metadatos de ffprobe, número de versión |
| 2 | extract_audio.py | ffmpeg a audio.wav 16 kHz mono |
| 3 | transcribe.py | whisper.cpp a transcript.json |
| 4 | mechanical_cuts.py | listas de palabras y patrones del archivo de idioma a cuts_mechanical.json |
| 5 | análisis semántico (Claude) | a cuts_semantic.json (ver más abajo) |
| 6 | merge_cuts.py | fusionar, ajustar a palabras, puntuaciones a cuts_final.json |
| 7 | build_premiere_xml.py | a .xml (XMEML / FCP7) |
| 8 | build_report.py | a .report.md |
Etapa 5: análisis semántico
El script escribe prompt_semantic.txt y se detiene. Esa es la ruta normal: Claude, ejecutando el skill, entonces hace lo siguiente.
- leer
prompt_semantic.txtpor completo; - analizar la transcripción siguiendo las reglas del prompt;
- escribir el JSON en
cuts_semantic.json(ruta dada en el prompt); - reanudar:
derush.py <clip> --resume-from=6 --work-dir=<work>.
Si cuts_semantic.json ya existe, la etapa se omite.
Decisiones de tres niveles (la filosofía del skill)
Cada corte propuesto tiene una confianza entre 0 y 1.
disable: el pasaje se elimina de la línea de tiempo, no se desactiva.build_spine_clips()construye la secuencia por sustracción: solo los intervalos conservados permanecen, uno tras otro, y la duración de la secuencia es la suma de los intervalos conservados. El equivalente a una "eliminación en cadena" ya aplicada. Umbrales: >= 0,85 para un corte mecánico, >= 0,92 para un corte semántico (un LLM a menudo sobrepasa sus límites).flag(0,6 a 0,85): sin corte. El pasaje permanece como un clip activo, con un marcador de secuencia rojo ("DOUBT (conf X): razón") en el lugar correcto. El usuario decide.ignore(< 0,6): nada, para no saturar la línea de tiempo.
Nunca invertir estas semánticas. Entregar clips desactivados y atenuados para eliminar a mano traslada el trabajo al usuario en lugar de eliminarlo: la promesa es una secuencia directamente utilizable.
Tipos de corte
filler: palabras de relleno ("um", "uh"...) e inicio de oración ...
[truncado para traducción]