Skip to content

Cómo anotar subtítulos de YouTube

Cómo descargar subtítulos con yt-dlp y anotarlos en Potato, qué permiten y qué no los subtítulos automáticos, cómo gestionar el vídeo y qué comprobar antes de redistribuir material.

Descarga los subtítulos con yt-dlp y apunta Potato a los archivos. Lo primero que hay que saber: los subtítulos generados automáticamente no tienen puntuación ni etiquetas de hablante, y sus saltos de línea no significan nada, lo cual limita qué puedes anotar con sentido. Potato lee todos los formatos de subtítulos que emite yt-dlp. Consulta Formatos de transcripción para la lista completa.

Las plataformas de vídeo son una fuente amplia y cómoda de habla naturalista. El subtitulado convierte ese habla en texto, y el texto es pequeño, fácil de mover y fácil de anotar. El problema es que no todos los subtítulos son el mismo tipo de objeto, y tratarlos como si lo fueran es donde se tuercen la mayoría de los proyectos de anotación sobre subtítulos.

¿Cómo descargo los subtítulos?

yt-dlp obtiene subtítulos con o sin el material:

bash
# Human-written subtitles, if the uploader provided any
yt-dlp --write-subs --sub-langs en --skip-download <URL>
 
# Auto-generated captions
yt-dlp --write-auto-subs --sub-langs en --sub-format vtt --skip-download <URL>

Potato lee vtt, srt, json3, ttml y las variantes srv1, srv2 y srv3, así que cualquier --sub-format que elijas se analizará bien. Elige según lo que quieras conservar: json3 preserva los tiempos por palabra, mientras que WebVTT y SubRip son más fáciles de leer y editar a mano.

¿Qué diferencia hay entre subtítulos humanos y automáticos?

En un editor de texto se parecen y como material de anotación se comportan de forma muy distinta:

Subtítulos humanosSubtítulos automáticos
PuntuaciónNo, o poco fiable
Fronteras de oraciónSignificativasArbitrarias
HablantesA veces, con etiquetas <v Name>Nunca
Tiempos por palabraNoSí, en json3
LiteralidadA menudo condensados para leerseMás cerca de lo que se dijo

Ninguno es mejor en términos absolutos. Los subtítulos humanos se leen bien pero se editan para facilitar la lectura, así que eliminan muletillas, comprimen repeticiones y a veces reescriben una frase entera. Los automáticos están más cerca de lo literal, que es lo que quieres para cualquier cosa sobre cómo habla la gente de verdad, pero llegan como un flujo sin puntuar.

¿Qué puedo anotar sobre subtítulos automáticos?

No diseñes un esquema de anotación a nivel de oración sobre subtítulos automáticos. Sus fronteras de bloque caen donde se llenó la ventana de subtítulo, no donde terminó una oración. Un bloque en un archivo de subtítulos automáticos es un artefacto de visualización, no una unidad lingüística. Si pides a los anotadores que valoren oraciones, cada uno elegirá en silencio fronteras distintas, y tus cifras de acuerdo acabarán midiendo eso en lugar de lo que te interesaba.

Dos opciones viables:

  • Anota los bloques de subtítulo tal cual. Etiqueta cada bloque con lo que le corresponda y acepta que la unidad es arbitraria pero consistente. Sirve para tema, presencia de un fenómeno o cualquier cosa que se pueda juzgar sobre un fragmento.
  • Vuelve a segmentar antes. Pasa un modelo de restauración de puntuación o un sistema de ASR que puntúe, y vuelve a asignar tiempos. Más trabajo, pero obtienes unidades reales.

Si tienes subtítulos humanos, este problema casi desaparece. Las fronteras las colocó alguien leyendo, así que suelen respetar las cláusulas.

¿Y el vídeo?

Los subtítulos son pequeños y fáciles de redistribuir. El vídeo normalmente no. Tres opciones:

bash
# Media hosted somewhere your annotators can reach
potato transcripts ./captions --media-url-prefix https://cdn.example.org/video -o data/talks.json
 
# Media downloaded locally as audio only
yt-dlp -f 'ba' -x --audio-format mp3 -o './audio/%(id)s.%(ext)s' <URL>
potato transcripts ./captions --media-dir ./audio -o data/talks.json

La tercera opción es no tener material. Las transcripciones sin audio se anotan bien; los anotadores leen en lugar de escuchar. Si ese es tu plan, dilo en las instrucciones, porque si no los anotadores darán por hecho que la falta de reproductor es un fallo y lo reportarán como tal.

Warning: Comprueba tus derechos antes de redistribuir nada que no hayas creado. Descargar subtítulos o material para tu propia investigación es una cuestión distinta de servir ese material a un grupo de anotadores, y ahí influyen las condiciones de la plataforma, los derechos de autor y las normas de tu institución. Resuelve esto antes de montar el flujo de trabajo, no después.

¿Cómo monto la tarea?

El conversor escribe un archivo de datos con la transcripción ya normalizada:

bash
potato transcripts ./captions --media-dir ./audio -o data/talks.json
json
{
  "id": "talk_01",
  "conversation": {
    "audio": "audio/talk_01.mp3",
    "turns": [
      {"turn_id": "t0", "speaker": null, "start": 0.0, "end": 4.2,
       "text": "so the thing about caption windows is"}
    ]
  }
}

speaker: null es lo que te da un subtítulo automático. Esos turnos se muestran como Unassigned con un selector, así que los anotadores pueden atribuirlos mientras escuchan.

Tres turnos de subtítulos automáticos con fondo gris rayado, etiquetados como Unassigned con una flecha desplegable y una pregunta adjunta a cada turno.Los subtítulos automáticos no traen hablantes, así que cada bloque queda como Unassigned hasta que un anotador elige uno

yaml
annotation_task_name: "Talk Annotation"
task_dir: .
data_files:
  - data/talks.json
 
item_properties:
  id_key: id
  text_key: conversation
 
instance_display:
  fields:
    - key: conversation
      type: audio_dialogue
      label: "Captions"
      span_target: true
      display_options:
        show_timestamps: true
        allow_speaker_assignment: auto
 
annotation_schemes:
  - annotation_type: radio
    name: cue_topic
    description: "What is this caption window about?"
    labels: [setup, argument, example, aside]
    turn_level: true
    turn_binding:
      field: conversation

turn_level: true adjunta la pregunta a cada bloque en lugar de al vídeo entero, que es la unidad correcta cuando los bloques es todo lo que tienes. Ejecútalo:

bash
python potato/flask_server.py start config.yaml -p 8000

También puedes saltarte el conversor por completo y apuntar un archivo de datos a los archivos de subtítulos en disco. Consulta Cómo anotar transcripciones de Whisper, donde el resto del flujo es el mismo.

Lecturas adicionales