Formatos de transcripción
Todos los formatos de transcripción y subtítulos que Potato lee: Whisper, WhisperX, Deepgram, AssemblyAI, AWS Transcribe, SRT, WebVTT, TTML, subtítulos de YouTube, CTM, Praat TextGrid y ELAN EAF, además de archivos adyacentes y el modelo de turnos normalizado.
Potato lee 21 entradas de transcripción y subtítulos, y convierte todas al mismo modelo de turnos antes de mostrar nada. Sea lo que sea lo que produjo tu flujo de ASR o tu herramienta de subtitulado, puedes apuntar Potato a ello sin escribir un script de conversión. Esta página es la referencia de qué funciona, cómo se reconoce cada formato y qué aporta cada uno. Para el recorrido paso a paso, consulta Cómo anotar transcripciones de Whisper y Cómo anotar subtítulos de YouTube.
Un archivo SRT adyacente mostrado como burbujas de hablante, con una pregunta adjunta a cada turno
Potato no transcribe
El reconocimiento de voz y la diarización de hablantes ocurren antes de que Potato vea nada. Ejecuta primero Whisper, WhisperX, pyannote o una API en la nube; Potato ingiere el resultado. Nada de esta página ejecuta un modelo.
Note: El modo Think-Aloud sí ejecuta un modelo Whisper local, pero con otro propósito: graba a los anotadores hablando mientras trabajan. Eso es una función de captura, no de ingesta de transcripciones.
La detección va por contenido, no por extensión
Potato inspecciona lo que hay dentro del archivo en lugar de fiarse de su nombre. Un archivo WebVTT llamado captions.txt se sigue analizando como WebVTT. La consecuencia práctica es que la misma transcripción funciona incrustada en tu archivo de datos o leída desde un archivo adyacente en disco, sin cambiar la configuración.
Formatos admitidos
Salida de ASR
| Formato | Se detecta por | Hablantes | Tiempos por palabra |
|---|---|---|---|
| Whisper JSON | Array segments | No | Sí, con --word_timestamps |
| WhisperX / JSON diarizado | segments con speaker | Sí | Sí |
| whisper.cpp JSON | Array transcription | No | No |
| Whisper TSV | Cabecera start/end/text | No | No |
| AWS Transcribe | results.items o results.audio_segments | Sí | Sí |
| Deepgram | results.channels o results.utterances | Sí, con diarize=true | Sí |
| AssemblyAI | text más words/utterances | Sí, con speaker_labels | Sí |
| Rev.ai | Array monologues | Sí | Sí |
| SPoRC | Filas turn_text/turnText | Sí, inferidos | No |
Subtítulos y rótulos
| Formato | Se detecta por | Hablantes |
|---|---|---|
SubRip (.srt) | Flechas de bloque, separador ,mmm | Por un prefijo Name: |
WebVTT (.vtt) | Cabecera WEBVTT | Por etiquetas <v Name> o un prefijo Name: |
SubStation Alpha (.ass, .ssa) | [Script Info] / Dialogue: | Por el campo Name |
| TTML / DFXP | Elemento raíz <tt> | Por un atributo speaker/agent |
| YouTube srv1/srv2/srv3 | XML <transcript><text> | Por un prefijo Name: |
| YouTube json3 | Array events | Ninguno; los subtítulos automáticos no traen hablantes |
SubRip y WebVTT cubren casi todo lo que te encontrarás. TTML aparece en archivos de difusión y en exportaciones de herramientas profesionales de subtitulado.
Alineación y anotación lingüística
| Formato | Se detecta por | Hablantes |
|---|---|---|
| NIST CTM | Columnas separadas por espacios, inicio y duración numéricos | Por el campo de canal |
| Praat TextGrid | File type = "ooTextFile" | Una capa por hablante |
| ELAN EAF | Raíz ANNOTATION_DOCUMENT | Por PARTICIPANT, si no, el id de la capa |
Se analizan tanto la serialización larga como la corta de TextGrid. Para archivos de ELAN, Potato resuelve ALIGNABLE_ANNOTATION y REF_ANNOTATION contra la tabla TIME_ORDER y lee la referencia al material desde la cabecera.
Cada capa del TextGrid se convierte en un hablante, y los intervalos vacíos entre ellas se omiten
Todo lo demás
Tres formas genéricas completan las 21:
- Una lista simple de diccionarios
{speaker, start, end, text}. - Un objeto
{"audio": ..., "turns": [...]}. - Un párrafo llano sin tiempos, que se muestra como una única burbuja.
No admitidos
No existe analizador para estos. Conviértelos antes.
- SAMI (
.smi), MicroDVD (.sub), SubViewer (.sbv) - Transcriber (
.trs), EXMARaLDA, CHAT/CHILDES (.cha) - Salida nativa de Montreal Forced Aligner y Gentle. Exporta desde ellos a CTM o TextGrid.
- Azure Speech, Google Speech-to-Text y
verbose_jsonde la API de Whisper dentro de envoltorios poco habituales - Archivos de diarización RTTM por sí solos
La confianza a nivel de palabra se analiza y se conserva en el modelo de datos siempre que la fuente la proporcione, pero por ahora no hay interfaz para verla.
El modelo de turnos normalizado
Todos los formatos anteriores se convierten en esto:
{
"audio": "media/interview_01.mp3",
"turns": [
{
"turn_id": "t0",
"speaker": "host",
"start": 0.0,
"end": 6.5,
"text": "Welcome back.",
"words": [{"word": "Welcome", "start": 0.0, "end": 0.4, "confidence": 0.99}],
"confidence": 0.97
}
]
}words y confidence solo aparecen cuando la fuente los traía. speaker es null en los turnos sin diarizar, que se muestran como Unassigned con un selector para que los anotadores lo rellenen.
Los subtítulos automáticos de YouTube llegan sin hablantes, así que cada turno queda como Unassigned hasta que un anotador elige uno
turn_id es la clave de persistencia de las anotaciones por turno y de las asignaciones de hablante. Sale de una cadena turn_id o step_id explícita en la fuente cuando la hay, y si no, de t{índice}. El mismo archivo produce siempre los mismos identificadores, así que las anotaciones sobreviven a una recarga.
Warning: Las unidades de tiempo varían entre herramientas. Whisper y Deepgram usan segundos en coma flotante; AssemblyAI, los desplazamientos de whisper.cpp y la salida TSV de Whisper usan milisegundos enteros. Potato convierte en la frontera para que todo lo que viene después esté en segundos. Si tu propio preprocesado mezcla ambos, los tiempos salen 1000 veces mal.
Archivos adyacentes
Un valor de campo que sea una ruta corta de una sola línea terminada en una extensión de transcripción conocida se lee desde disco en lugar de tratarse como texto. Así, la disposición que ya produjo tu herramienta de ASR, con los archivos de audio junto a su .srt o .json, funciona sin ningún paso de preprocesado:
{
"id": "int_001",
"conversation": {
"audio": "media/int_001.mp3",
"transcript": "media/int_001.srt"
}
}Las rutas se resuelven relativas a task_dir y pasan por la misma validación de seguridad de rutas que cualquier otra ruta configurada, así que un archivo de datos no puede leer fuera del proyecto.
Extensiones reconocidas: .srt .vtt .webvtt .json .json3 .srv1 .srv2 .srv3 .ttml .dfxp .xml .ass .ssa .tsv .ctm .TextGrid .eaf .txt
Si tus datos contienen realmente transcripciones de una línea que parecen nombres de archivo, desactiva la heurística:
display_options:
transcript_is_path: auto # auto (default) | true | falseConfiguración
Visualización: audio_dialogue
La visualización de diálogo con audio muestra los turnos como burbujas de hablante sincronizadas con el audio, con un botón de reproducción en cada turno.
instance_display:
fields:
- key: conversation
type: audio_dialogue
label: "Transcript"
span_target: true
display_options:
audio_key: audio
turns_key: turns
speaker_key: speaker
text_key: text
transcript_is_path: auto
show_timestamps: true
allow_speaker_assignment: auto
scroll_height: 460px| Opción | Valor por defecto | Qué hace |
|---|---|---|
audio_key | audio | Subclave del valor del campo que contiene la URL o ruta del audio. |
turns_key | turns | Subclave que contiene la lista de turnos. También acepta segments. |
speaker_key / text_key | speaker / text | Claves por turno. |
speakers | [] | Lista de {id, name, color, side}. Los hablantes no listados reciben un color determinista y un lado alterno. |
allow_speaker_assignment | auto | auto activa la asignación por clic cuando hay turnos sin diarizar o una lista que corregir. true la fuerza, false la desactiva. |
transcript_is_path | auto | Si el valor del campo debe leerse como ruta a un archivo adyacente. |
show_timestamps | true | Muestra mm:ss–mm:ss en cada turno. |
scroll_height | 480px | Altura del panel de transcripción con desplazamiento. |
playback_rates | [1, 1.25, 1.5, 2] | Opciones del selector de velocidad. |
Esquemas
Desde la versión 2.7.1, speech_transcript, voice_interaction y tiered_annotation leen la transcripción directamente del registro de la instancia y aceptan todos los formatos de esta página. Antes solo lo hacía la visualización audio_dialogue.
annotation_schemes:
- annotation_type: speech_transcript
name: transcript_review
description: "Mark transcription errors"
segments_key: segments # record field holding the transcript
- annotation_type: voice_interaction
name: barge_in
description: "Mark overlaps and barge-in"
turns_key: turnsLa anotación por capas puede prerrellenar una capa a partir de la transcripción, de modo que los anotadores corrijan una alineación existente en lugar de volver a segmentar el habla a mano:
- annotation_type: tiered_annotation
name: tiers
source_field: audio_url
media_type: audio
transcript_field: asr_output # opt-in; omit to start from a blank timeline
transcript_tier: utterance # defaults to the first tier
tiers:
- name: utterance
labels:
- name: speech
color: "#7c3aed"Las anotaciones sembradas no se escriben hasta que el anotador hace una edición real, así que no se atribuye nada a alguien que solo abrió la instancia.
Construir un archivo de datos con potato transcripts
Apunta el conversor a una carpeta de salida de ASR y escribe un archivo de datos listo para anotar:
# Pair transcripts to media by basename
potato transcripts ./whisper_out --media-dir ./audio -o data/interviews.json
# Media served from elsewhere
potato transcripts './captions/*.vtt' \
--media-url-prefix https://cdn.example.org/audio -o data/talks.json
# What did it detect? Writes nothing.
potato transcripts ./whisper_out --dry-run--dry-run informa de lo que ha encontrado sin escribir nada, que es la forma más rápida de detectar una carpeta con el archivo de salida de Whisper equivocado:
Scanned 3 file(s):
talk_01.srt SRT 2 turns 5.0s 2 speaker(s): Alice, Bob
talk_02.vtt WebVTT 1 turns 3.0s undiarized
talk_03.json whisper.cpp JSON 1 turns 2.4s undiarized
3 item(s), 4 turn(s).
1 item(s) have no media. Pass --media-dir or --media-url-prefix to enable playback.
| Opción | Para qué sirve |
|---|---|
-o, --output | Dónde escribir. Obligatorio salvo con --dry-run. |
--format | json (por defecto) o jsonl. |
--media-dir | Carpeta de material que emparejar por nombre base. |
--media-url-prefix | URL base del material en lugar de archivos locales. |
--field | Campo del ítem donde va la transcripción. Por defecto conversation. |
--id-prefix | Cadena que se antepone a cada id generado. |
--speaker-key | Clave de origen que contiene la etiqueta de hablante. |
-r, --recursive | Recorre subcarpetas. |
--dry-run | Informa del formato detectado y del número de turnos por archivo. |
--emit-config | Además, imprime un fragmento de config.yaml correspondiente. |
-q, --quiet | Silencia el informe por archivo. |
Los identificadores de ítem salen del nombre de archivo quitando una extensión de material final, así que interview_01.mp3.json de Whisper se convierte en interview_01 y no en interview_01.mp3.
Exportar de vuelta
Las anotaciones por capas se exportan a ELAN EAF y Praat TextGrid, así que una transcripción puede hacer ida y vuelta: ingerirla, anotarla en Potato, exportarla, refinarla en ELAN o Praat y volver a leer el resultado.
python -m potato.export --config config.yaml --format eaf --output ./out/
python -m potato.export --config config.yaml --format textgrid --output ./out/Ambos exportadores parten de la salida de tiered_annotation. Los demás esquemas se exportan mediante los formatos estándar.
Resolución de problemas
| Síntoma | Qué ha pasado |
|---|---|
| Todo aparece como una única burbuja | No se reconoció el formato y cayó en el respaldo de párrafo llano. Ejecuta potato transcripts <file> --dry-run; si informa plain text, los tiempos nunca se analizaron. Normalmente el archivo es un .txt de Whisper, que no tiene tiempos, en lugar del .json o el .srt. |
| Sin hablantes, todo aparece como Unassigned | La fuente no trae etiquetas de hablante. Whisper por sí solo no diariza, y los subtítulos automáticos de YouTube tampoco. Ejecuta la diarización antes o deja que los anotadores asignen hablantes en la interfaz. |
| Los tiempos están 1000 veces mal | Se mezclaron segundos y milisegundos antes. Los offsets de whisper.cpp, AssemblyAI y el TSV de Whisper están en milisegundos. |
| La ruta de la transcripción aparece como el texto | No se pudo leer el archivo adyacente, así que se mostró la ruta como contenido. Comprueba que se resuelve dentro de task_dir. Los registros del servidor indican el motivo concreto. |
| Una transcripción de una línea se lee como nombre de archivo | Pon transcript_is_path: false en el campo de visualización. |
Proyecto de ejemplo
examples/audio/transcript-formats/ en el repositorio de Potato muestra seis formatos en paralelo, cada uno cargado desde un archivo adyacente: SubRip, WebVTT, Whisper JSON, YouTube json3, Praat TextGrid y Deepgram. Los seis producen las mismas burbujas de hablante.
python potato/flask_server.py start examples/audio/transcript-formats/config.yaml -p 8000La misma tarea está disponible como diseño de muestra descargable: Ingesta de formatos de transcripción.
Para detalles de implementación, consulta la documentación de origen.
Lecturas adicionales
- Cómo anotar transcripciones de Whisper, el recorrido de principio a fin
- Cómo anotar subtítulos de YouTube, para subtítulos y sus limitaciones
- Anotación de diálogo, la visualización de burbujas de hablante
- Anotación de audio, segmentación de la forma de onda desde cero
- Diseñar formatos de datos para anotación