Communitygithub.com

auto-subtitle

Herramienta de transcripción: convierte archivos mp4/wav/flac a cues.json + SRT usando faster-whisper, con campos alineados a SubtitleCue de video-motion.

¿Qué es auto-subtitle?

auto-subtitle es una habilidad técnica para la transcripción automática de audio/video a subtítulos estructurados. Está diseñada para desarrolladores que trabajan con flujos de video-motion y necesitan generar archivos de subtítulos listos para integrar en una línea de tiempo. La habilidad utiliza faster-whisper con modelos como large-v3-turbo (descarga única) y produce dos artefactos: un archivo `<nombre>.cues.json` con el campo `subtitles` (array de objetos `{start, end, text}` en segundos con 3 decimales) y un archivo `<nombre>.srt` estándar. El proceso incluye tres niveles de verificación obligatoria (L1 estructural, L2 precisión contra texto de referencia, L3 conclusión) para garantizar calidad. Soporta los idiomas zh (predeterminado) y en, entre otros códigos de whisper, y se ejecuta desde la línea de comandos con un entorno virtual Python externo al repositorio para no inflar el proyecto. Está pensada para ser llamada cuando el usuario solicita 'subtítulos automáticos', 'transcripción de voz a texto', 'generar archivos de subtítulos' o 'faster-whisper'.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/TimeCraker/vibe-studio/tree/HEAD/skills/auto-subtitle

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

auto-subtitle — Transcripción automática de audio/video a SubtitleCue

Un solo comando para obtener subtítulos: ingresa un archivo de audio/video y obtén dos productos: <nombre>.cues.json + <nombre>.srt. El contrato de datos está alineado palabra por palabra con SubtitleCue de video-motion: {start, end, text}, en segundos, con 3 decimales, texto en una sola línea (las oraciones largas ya están divididas) — el array subtitles puede ir directamente a la línea de tiempo de video-motion.

Paso 1 · Confirmar material e idioma

  • Acepta mp4 / wav / flac (PyAV los decodifica directamente). Si hay error de decodificación → transcodificar primero: ffmpeg -i in.mp4 -vn -ac 1 -ar 16000 out.wav
  • Confirmar el idioma y pasar --lang: zh (predeterminado) / en y otros códigos de idioma de whisper.
  • Material que sea solo música/efectos de sonido NO necesita ejecutarse: VAD filtrará productos vacíos o extremadamente cortos (es una característica, no un error).
  • Si el material tiene un texto conocido (guión / diálogos / texto original), guardarlo como UTF-8 — será la referencia para la verificación L2 en el Paso 3, para evitar desviaciones.

Paso 2 · Ejecutar la transcripción

El venv no se incluye en el repositorio (artefacto de construcción de ~284 MB, ya cubierto por .gitignore con .venv/). Por convención, la plantilla de la habilidad no incluye artefactos de construcción, igual que la plantilla no incluye node_modules, por lo que el venv se crea fuera del repositorio, se construye una vez y todos los proyectos lo reutilizan:

python -m venv "$env:USERPROFILE\.cache\vibe-studio\asr-venv"
& "$env:USERPROFILE\.cache\vibe-studio\asr-venv\Scripts\python.exe" -m pip install -r skills/auto-subtitle/templates/asr/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
cd skills/auto-subtitle/templates/asr
& "$env:USERPROFILE\.cache\vibe-studio\asr-venv\Scripts\python.exe" transcribe.py <input.mp4|wav> --outdir <directorio de salida>
  • Modelo predeterminado: large-v3-turbo (~1.6 GB, descarga automática la primera vez, calidad aceptable para chino); para verificación rápida agregar --model small (~484 MB). El modelo se almacena en caché en ~/.cache/huggingface, descarga única y reutilización global.
  • Si la descarga del modelo falla, establecer HF_ENDPOINT para cambiar el origen: por defecto conexión directa oficial (verificado en agosto de 2026); alternativo como $env:HF_ENDPOINT="https://hf-mirror.com" (nota: con hub 1.x este mirror tiene problemas de compatibilidad con redirección 308, priorizar el oficial).
  • stdout: resumen en inglés de una línea segments=N cues=M total_audio=... model=... lang=... out=...; exit 0 éxito, 1 fallo.

Paso 3 · Verificación en tres niveles (obligatorio, no se puede omitir)

L1 Nivel de programa: JSON debe poder cargarse con json.load; subtitles es un array y cada elemento tiene exactamente los campos start/end/text; start < end y no decreciente entre elementos; números con 3 decimales; el end del último elemento ≤ duración de ffprobe + 1s. Las líneas de marca de tiempo del SRT deben coincidir con HH:MM:SS,mmm --> HH:MM:SS,mmm, numeración continua desde 1.

L2 Precisión: si hay texto conocido → comparación con difflib.SequenceMatcher (ambos lados sin puntuación ni espacios, normalizados), similitud general ≥0.85, por frase ≥0.70 (para ventanas de cues contiguos concatenados tomar el máximo, cubriendo división/fusión). Sin texto conocido → escuchar muestras: inicio / medio / final.

L2.5 Línea de tiempo (verificación de rutina): La ventana de los subtítulos debe alinearse con la ventana temporal a nivel de palabra; no debe haber subtítulos durante el silencio entre oraciones — auditar el espacio entre cues adyacentes: entre oraciones debe haber un espacio de silencio real >1s (gap=0 dentro de una oración es normal); no debe haber fragmentos de menos de 0.3s; el start del primer cue debe alinearse con el inicio del habla, el end del último cue no debe cortar el silencio final. Internamente, el script usa marcas de tiempo a nivel de palabra (start de la primera palabra / end de la última) para definir la ventana; este paso es una verificación a nivel de producto.

L3 Conclusión: todos aprobados = ALL GREEN; si hay elementos en rojo → corregir la división / re-ejecutar con parámetros VAD y re-verificar; si 2 rondas consecutivas en rojo → detenerse e informar, no ajustar a ciegas.

Paso 4 · Entrega

  • Informe: ruta absoluta de cues.json + número de cues + duración del audio + modelo/idioma + resultado de la verificación en tres niveles.
  • Integración con video-motion: el array subtitles se pega directamente en src/cues.ts del proyecto video-motion en cues.subtitles y ya funciona, sin conversión de campos.
  • Explícitamente no se hace (para iteraciones posteriores): diarización de hablantes, exportación de marcas de tiempo a nivel de palabra, traducción, voz TTS.

Paso 5 · Registrar comando para re-ejecución

Al final del informe de entrega, incluir el comando completo para re-ejecutar (ruta de entrada / --lang / --outdir / --model), para garantizar que la próxima sesión u otra persona pueda reproducirlo exactamente. Los productos (cues.json / srt) se colocan en el área de salida (este repositorio: products/, entre repositorios: raíz del proyecto output/) sin incluirse en git; el comando es el activo.

Límites y trampas

  • Consola GBK: el script imprime todo en inglés; al escribir archivos siempre usar explícitamente encoding="utf-8", en JSON ensure_ascii=False.
  • Reglas de división: si una línea tiene >20 caracteres, dividir en signos de puntuación (。!?;,、). Si no hay puntuación en la ventana, dividir de forma forzada asegurando que el último fragmento tenga al menos 3 caracteres (para evitar fragmentos de 1 carácter). Fragmentos <0.3s se fusionan con el anterior, sin superar el límite de 20 caracteres.
  • Las marcas de tiempo a nivel de palabra son la única fuente correcta para la ventana de subtítulos: las marcas de tiempo a nivel de segmento se tragan el silencio entre oraciones, haciendo que los subtítulos aparezcan aproximadamente un segmento de silencio antes (ya corregido, no revertir word_timestamps=False).
  • Inferencia int8 en CPU: para audio de 28s ≈ resultado en 1 minuto; para audio largo, estimar tiempo proporcionalmente. La primera ejecución con large-v3-turbo incluye descarga, dejar suficiente tiempo de espera.
  • En reconocimiento de chino, los números suelen convertirse a arábigos ("doscientos milisegundos" → "200 milisegundos"), diferencia normal en comparación L2, no es error de reconocimiento.

Enlace de entrega

El SRT/cues final debe archivarse junto con la fuente de la pista de audio original y la versión del modelo. No entregar solo un mp4 con subtítulos quemados. Al entregar el video, usar media-qc para verificar la ventana de subtítulos contra la duración real; la precisión aún se verifica contra el texto conocido o mediante escucha de muestras. La descarga del modelo predeterminado y la inferencia local no reemplazan la voz humana grabada.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills relacionados