Formats de transcription
Tous les formats de transcription et de sous-titres que Potato lit : Whisper, WhisperX, Deepgram, AssemblyAI, AWS Transcribe, SRT, WebVTT, TTML, sous-titres YouTube, CTM, Praat TextGrid et ELAN EAF, ainsi que les fichiers annexes et le modèle de tours normalisé.
Potato lit 21 entrées de transcription et de sous-titres et les convertit toutes vers le même modèle de tours avant tout affichage. Quel que soit ce qu'a produit votre chaîne de reconnaissance vocale ou votre outil de sous-titrage, vous pouvez y pointer Potato sans écrire de script de conversion. Cette page est la référence de ce qui fonctionne, de la façon dont chaque format est reconnu et de ce que chacun apporte. Pour le pas-à-pas, voir Comment annoter des transcriptions Whisper et Comment annoter des sous-titres YouTube.
Un fichier SRT annexe affiché en bulles de locuteur, avec une question rattachée à chaque tour
Potato ne transcrit pas
La reconnaissance automatique de la parole et la diarisation ont lieu avant que Potato ne voie quoi que ce soit. Lancez d'abord Whisper, WhisperX, pyannote ou une API cloud ; Potato ingère le résultat. Rien sur cette page n'exécute de modèle.
Note: Le mode Think-Aloud exécute bien un modèle Whisper local, mais à une autre fin : il enregistre les annotateurs qui parlent pendant qu'ils travaillent. C'est une fonction de capture, pas d'ingestion de transcriptions.
La détection se fait sur le contenu, pas sur l'extension
Potato inspecte ce qu'il y a dans le fichier plutôt que de se fier à son nom. Un fichier WebVTT nommé captions.txt est toujours analysé comme du WebVTT. Conséquence pratique : la même transcription fonctionne aussi bien incorporée dans votre fichier de données que lue depuis un fichier annexe sur le disque, sans changement de configuration.
Formats pris en charge
Sorties de reconnaissance vocale
| Format | Détecté par | Locuteurs | Temps par mot |
|---|---|---|---|
| Whisper JSON | Tableau segments | Non | Oui, avec --word_timestamps |
| WhisperX / JSON diarisé | segments avec speaker | Oui | Oui |
| whisper.cpp JSON | Tableau transcription | Non | Non |
| Whisper TSV | En-tête start/end/text | Non | Non |
| AWS Transcribe | results.items ou results.audio_segments | Oui | Oui |
| Deepgram | results.channels ou results.utterances | Oui, avec diarize=true | Oui |
| AssemblyAI | text plus words/utterances | Oui, avec speaker_labels | Oui |
| Rev.ai | Tableau monologues | Oui | Oui |
| SPoRC | Lignes turn_text/turnText | Oui, inférés | Non |
Sous-titres
| Format | Détecté par | Locuteurs |
|---|---|---|
SubRip (.srt) | Flèches de bloc, séparateur ,mmm | Par un préfixe Name: |
WebVTT (.vtt) | En-tête WEBVTT | Par des balises <v Name> ou un préfixe Name: |
SubStation Alpha (.ass, .ssa) | [Script Info] / Dialogue: | Par le champ Name |
| TTML / DFXP | Élément racine <tt> | Par un attribut speaker/agent |
| YouTube srv1/srv2/srv3 | XML <transcript><text> | Par un préfixe Name: |
| YouTube json3 | Tableau events | Aucun ; les sous-titres automatiques n'en portent pas |
SubRip et WebVTT couvrent l'essentiel de ce que vous rencontrerez. TTML apparaît dans les archives de diffusion et dans les exports d'outils professionnels de sous-titrage.
Alignement et annotation linguistique
| Format | Détecté par | Locuteurs |
|---|---|---|
| NIST CTM | Colonnes séparées par des espaces, début et durée numériques | Par le champ de canal |
| Praat TextGrid | File type = "ooTextFile" | Une couche par locuteur |
| ELAN EAF | Racine ANNOTATION_DOCUMENT | Par PARTICIPANT, sinon l'identifiant de couche |
Les sérialisations longue et courte de TextGrid sont toutes deux analysées. Pour les fichiers ELAN, Potato résout ALIGNABLE_ANNOTATION et REF_ANNOTATION contre la table TIME_ORDER et lit la référence au média dans l'en-tête.
Chaque couche du TextGrid devient un locuteur, et les intervalles vides entre elles sont ignorés
Tout le reste
Trois formes génériques complètent les 21 :
- Une simple liste de dictionnaires
{speaker, start, end, text}. - Un objet
{"audio": ..., "turns": [...]}. - Un paragraphe brut sans aucun horodatage, affiché comme une seule bulle.
Non pris en charge
Aucun analyseur n'existe pour ceux-ci. Convertissez-les d'abord.
- SAMI (
.smi), MicroDVD (.sub), SubViewer (.sbv) - Transcriber (
.trs), EXMARaLDA, CHAT/CHILDES (.cha) - Les sorties natives de Montreal Forced Aligner et de Gentle. Exportez plutôt en CTM ou TextGrid depuis ces outils.
- Azure Speech, Google Speech-to-Text et le
verbose_jsonde l'API Whisper dans des enveloppes inhabituelles - Les fichiers de diarisation RTTM seuls
La confiance au niveau du mot est analysée et conservée dans le modèle de données quand la source la fournit, mais il n'existe pour l'instant aucune interface pour la consulter.
Le modèle de tours normalisé
Tous les formats ci-dessus deviennent ceci :
{
"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 et confidence n'apparaissent que si la source les portait. speaker vaut null pour les tours non diarisés, qui s'affichent comme Unassigned avec un sélecteur pour que les annotateurs les complètent.
Les sous-titres automatiques YouTube arrivent sans locuteurs, donc chaque tour reste Unassigned jusqu'à ce qu'un annotateur en choisisse un
turn_id est la clé de persistance des annotations par tour et des attributions de locuteur. Elle vient d'une chaîne turn_id ou step_id explicite dans la source quand il y en a une, sinon de t{index}. Le même fichier produit toujours les mêmes identifiants, donc les annotations survivent à un rechargement.
Warning: Les unités de temps diffèrent d'un outil à l'autre. Whisper et Deepgram utilisent des secondes en virgule flottante ; AssemblyAI, les décalages de whisper.cpp et la sortie TSV de Whisper utilisent des millisecondes entières. Potato convertit à la frontière pour que tout ce qui suit soit en secondes. Si votre propre prétraitement mélange les deux, les temps ressortent 1000 fois faux.
Fichiers annexes
Une valeur de champ qui est un chemin court d'une seule ligne se terminant par une extension de transcription connue est lue depuis le disque au lieu d'être traitée comme du texte. Ainsi, la disposition que votre outil de reconnaissance vocale a déjà produite, avec les fichiers médias à côté de leur .srt ou .json, fonctionne sans étape de prétraitement :
{
"id": "int_001",
"conversation": {
"audio": "media/int_001.mp3",
"transcript": "media/int_001.srt"
}
}Les chemins sont résolus relativement à task_dir et passent par la même validation de sécurité que tout autre chemin configuré, donc un fichier de données ne peut pas lire en dehors du projet.
Extensions reconnues : .srt .vtt .webvtt .json .json3 .srv1 .srv2 .srv3 .ttml .dfxp .xml .ass .ssa .tsv .ctm .TextGrid .eaf .txt
Si vos données contiennent réellement des transcriptions d'une ligne qui ressemblent à des noms de fichiers, désactivez l'heuristique :
display_options:
transcript_is_path: auto # auto (default) | true | falseConfiguration
Affichage : audio_dialogue
L'affichage de dialogue audio présente les tours en bulles de locuteur synchronisées avec l'audio, avec un bouton de lecture sur chaque tour.
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| Option | Par défaut | Effet |
|---|---|---|
audio_key | audio | Sous-clé de la valeur du champ contenant l'URL ou le chemin de l'audio. |
turns_key | turns | Sous-clé contenant la liste des tours. Accepte aussi segments. |
speaker_key / text_key | speaker / text | Clés par tour. |
speakers | [] | Liste de {id, name, color, side}. Les locuteurs absents de la liste reçoivent une couleur déterministe et un côté alterné. |
allow_speaker_assignment | auto | auto active l'attribution au clic quand il y a des tours non diarisés ou une liste à corriger. true la force, false la désactive. |
transcript_is_path | auto | Indique s'il faut lire la valeur du champ comme un chemin vers un fichier annexe. |
show_timestamps | true | Affiche mm:ss–mm:ss sur chaque tour. |
scroll_height | 480px | Hauteur du panneau de transcription défilant. |
playback_rates | [1, 1.25, 1.5, 2] | Options du sélecteur de vitesse. |
Schémas
Depuis la 2.7.1, speech_transcript, voice_interaction et tiered_annotation lisent tous une transcription directement dans l'enregistrement de l'instance et acceptent tous les formats de cette page. Auparavant, seul l'affichage audio_dialogue le faisait.
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: turnsL'annotation en couches peut préremplir une couche à partir de la transcription, de sorte que les annotateurs corrigent un alignement existant plutôt que de resegmenter la parole à la main :
- 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"Les annotations préremplies ne sont pas écrites tant que l'annotateur n'a pas fait une vraie modification, donc rien n'est attribué à quelqu'un qui a seulement ouvert l'instance.
Construire un fichier de données avec potato transcripts
Pointez le convertisseur vers un dossier de sorties de reconnaissance vocale et il écrit un fichier de données prêt à annoter :
# 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 rend compte de ce qu'il a trouvé sans rien écrire, ce qui est le moyen le plus rapide de repérer un dossier contenant le mauvais fichier de sortie Whisper :
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.
| Option | Rôle |
|---|---|
-o, --output | Où écrire. Obligatoire sauf avec --dry-run. |
--format | json (par défaut) ou jsonl. |
--media-dir | Dossier de médias à apparier par nom de base. |
--media-url-prefix | URL de base des médias au lieu de fichiers locaux. |
--field | Champ de l'item où va la transcription. Par défaut conversation. |
--id-prefix | Chaîne ajoutée devant chaque identifiant généré. |
--speaker-key | Clé source contenant l'étiquette de locuteur. |
-r, --recursive | Parcourt les sous-dossiers. |
--dry-run | Indique le format détecté et le nombre de tours par fichier. |
--emit-config | Imprime aussi un fragment de config.yaml correspondant. |
-q, --quiet | Supprime le rapport fichier par fichier. |
Les identifiants d'item viennent du nom de fichier privé d'une extension de média finale, donc interview_01.mp3.json de Whisper devient interview_01 et non interview_01.mp3.
Réexporter
Les annotations en couches s'exportent vers ELAN EAF et Praat TextGrid, donc une transcription peut faire l'aller-retour : l'ingérer, l'annoter dans Potato, l'exporter, l'affiner dans ELAN ou Praat, puis relire le résultat.
python -m potato.export --config config.yaml --format eaf --output ./out/
python -m potato.export --config config.yaml --format textgrid --output ./out/Les deux exportateurs partent de la sortie de tiered_annotation. Les autres schémas s'exportent via les formats standard.
Dépannage
| Symptôme | Ce qui s'est passé |
|---|---|
| Tout apparaît comme une seule grosse bulle | Le format n'a pas été reconnu et est retombé sur le repli « paragraphe brut ». Lancez potato transcripts <file> --dry-run ; s'il annonce plain text, les temps n'ont jamais été analysés. Le fichier est généralement un .txt de Whisper, qui n'a aucun horodatage, plutôt que le .json ou le .srt. |
| Aucun locuteur, tout est Unassigned | La source ne porte aucune étiquette de locuteur. Whisper seul ne diarise pas, et les sous-titres automatiques YouTube non plus. Lancez la diarisation en amont ou laissez les annotateurs attribuer les locuteurs dans l'interface. |
| Les temps sont 1000 fois faux | Secondes et millisecondes ont été mélangées en amont. Les offsets de whisper.cpp, AssemblyAI et le TSV de Whisper sont tous en millisecondes. |
| Le chemin de la transcription s'affiche comme le texte | Le fichier annexe n'a pas pu être lu, donc le chemin a été affiché comme contenu. Vérifiez qu'il se résout sous task_dir. Les journaux du serveur indiquent la raison précise. |
| Une transcription d'une ligne est lue comme un nom de fichier | Mettez transcript_is_path: false sur le champ d'affichage. |
Projet d'exemple
examples/audio/transcript-formats/ dans le dépôt Potato affiche six formats côte à côte, chacun chargé depuis un fichier annexe : SubRip, WebVTT, Whisper JSON, YouTube json3, Praat TextGrid et Deepgram. Les six produisent les mêmes bulles de locuteur.
python potato/flask_server.py start examples/audio/transcript-formats/config.yaml -p 8000La même tâche existe en conception téléchargeable : Ingestion de formats de transcription.
Pour les détails d'implémentation, voir la documentation source.
Pour aller plus loin
- Comment annoter des transcriptions Whisper, le pas-à-pas complet
- Comment annoter des sous-titres YouTube, pour les sous-titres et leurs limites
- Annotation de dialogue, l'affichage en bulles de locuteur
- Annotation audio, la segmentation de forme d'onde à partir de zéro
- Concevoir des formats de données pour l'annotation