←

Generar subtitulos .srt y .vtt desde transcripcion

Contexto

Despues de transcribir un video con Whisper, tenia segmentos con timestamps y texto. Necesitaba exportar a formatos de subtitulos estandar (.srt para reproductores, .vtt para web) en ambos idiomas.

Lo que aprendi

La unica diferencia real entre SRT y VTT es el separador de milisegundos y el header:

def format_timestamp_srt(seconds: float) -> str:
    """SRT usa coma: 00:01:23,456"""
    h = int(seconds // 3600)
    m = int((seconds % 3600) // 60)
    s = int(seconds % 60)
    ms = int((seconds % 1) * 1000)
    return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"

def format_timestamp_vtt(seconds: float) -> str:
    """VTT usa punto: 00:01:23.456"""
    h = int(seconds // 3600)
    m = int((seconds % 3600) // 60)
    s = int(seconds % 60)
    ms = int((seconds % 1) * 1000)
    return f"{h:02d}:{m:02d}:{s:02d}.{ms:03d}"

El formato SRT es:

1
00:00:02,500 --> 00:00:05,800
The circuit breaker prevents cascading failures

2
00:00:06,100 --> 00:00:09,300
When the NVR stops responding we stop calling it

VTT agrega un header obligatorio:

def write_vtt(segments: list[dict], output_path: str, text_key: str = "source"):
    with open(output_path, "w", encoding="utf-8") as f:
        f.write("WEBVTT\n\n")  # Header obligatorio
        for i, seg in enumerate(segments, 1):
            start = format_timestamp_vtt(seg["start"])
            end = format_timestamp_vtt(seg["end"])
            text = seg.get(text_key, "")
            f.write(f"{i}\n{start} --> {end}\n{text}\n\n")

Para generar ambos idiomas, uso un text_key que selecciona entre "source" (ingles) y "translated" (espanol):

def write_all(segments, output_dir, base_name, source_lang="en", target_lang="es"):
    base = os.path.join(output_dir, f"{base_name}_{source_lang}")
    write_srt(segments, f"{base}.srt", "source")
    write_vtt(segments, f"{base}.vtt", "source")

    if target_lang and any("translated" in seg for seg in segments):
        base = os.path.join(output_dir, f"{base_name}_{target_lang}")
        write_srt(segments, f"{base}.srt", "translated")
        write_vtt(segments, f"{base}.vtt", "translated")

Por que importa

SRT es el formato universal que entienden VLC, mpv, y la mayoria de reproductores. VTT es el estandar web para <track> en HTML5 video. Con ambos cubres el 99% de los casos de uso.