Skip to content

Formati di trascrizione

Tutti i formati di trascrizione e sottotitoli che Potato legge: Whisper, WhisperX, Deepgram, AssemblyAI, AWS Transcribe, SRT, WebVTT, TTML, sottotitoli di YouTube, CTM, Praat TextGrid ed ELAN EAF, oltre ai file affiancati e al modello di turni normalizzato.

Potato legge 21 tipi di input tra trascrizioni e sottotitoli e li converte tutti nello stesso modello di turni prima di mostrare qualsiasi cosa. Qualunque cosa abbia prodotto la tua pipeline di riconoscimento vocale o il tuo strumento di sottotitolaggio, puoi puntarci Potato senza scrivere uno script di conversione. Questa pagina è il riferimento su cosa funziona, su come viene riconosciuto ogni formato e su cosa ciascuno porta con sé. Per il percorso passo passo, vedi Come annotare trascrizioni Whisper e Come annotare sottotitoli di YouTube.

Una trascrizione mostrata come fumetti colorati per parlante, ciascuno con il proprio pulsante di riproduzione, i tempi e una domanda di etichettatura per turno.Un file SRT affiancato mostrato come fumetti per parlante, con una domanda su ogni turno

Potato non trascrive

Il riconoscimento vocale e la diarizzazione dei parlanti avvengono prima che Potato veda qualcosa. Esegui prima Whisper, WhisperX, pyannote o un'API in cloud; Potato ne acquisisce il risultato. Niente in questa pagina esegue un modello.

Note: La modalità Think-Aloud esegue davvero un modello Whisper locale, ma con un altro scopo: registra chi annota mentre parla lavorando. È una funzione di cattura, non di acquisizione di trascrizioni.

Il riconoscimento avviene sul contenuto, non sull'estensione

Potato guarda cosa c'è dentro il file invece di fidarsi del nome. Un file WebVTT chiamato captions.txt viene comunque interpretato come WebVTT. La conseguenza pratica è che la stessa trascrizione funziona incorporata nel file di dati oppure letta da un file affiancato su disco, senza cambiare la configurazione.

Formati supportati

Output di riconoscimento vocale

FormatoRiconosciuto daParlantiTempi per parola
Whisper JSONArray segmentsNoSì, con --word_timestamps
WhisperX / JSON diarizzatosegments con speaker
whisper.cpp JSONArray transcriptionNoNo
Whisper TSVIntestazione start/end/textNoNo
AWS Transcriberesults.items o results.audio_segments
Deepgramresults.channels o results.utterancesSì, con diarize=true
AssemblyAItext più words/utterancesSì, con speaker_labels
Rev.aiArray monologues
SPoRCRighe turn_text/turnTextSì, dedottiNo

Sottotitoli

FormatoRiconosciuto daParlanti
SubRip (.srt)Frecce tra i tempi, separatore ,mmmDa un prefisso Name:
WebVTT (.vtt)Intestazione WEBVTTDa tag <v Name> o da un prefisso Name:
SubStation Alpha (.ass, .ssa)[Script Info] / Dialogue:Dal campo Name
TTML / DFXPElemento radice <tt>Da un attributo speaker/agent
YouTube srv1/srv2/srv3XML <transcript><text>Da un prefisso Name:
YouTube json3Array eventsNessuno; i sottotitoli automatici non ne hanno

SubRip e WebVTT coprono quasi tutto quello che incontrerai. TTML compare negli archivi televisivi e nelle esportazioni degli strumenti professionali di sottotitolaggio.

Allineamento e annotazione linguistica

FormatoRiconosciuto daParlanti
NIST CTMColonne separate da spazi, inizio e durata numericiDal campo di canale
Praat TextGridFile type = "ooTextFile"Un livello per parlante
ELAN EAFRadice ANNOTATION_DOCUMENTDa PARTICIPANT, altrimenti l'id del livello

Vengono interpretate sia la serializzazione lunga sia quella breve di TextGrid. Per i file ELAN, Potato risolve ALIGNABLE_ANNOTATION e REF_ANNOTATION rispetto alla tabella TIME_ORDER e legge il riferimento al media dall'intestazione.

Un Praat TextGrid mostrato come due parlanti chiamati fieldworker e speaker, uno per livello, senza gli intervalli di silenzio.Ogni livello del TextGrid diventa un parlante, e gli intervalli vuoti in mezzo vengono saltati

Tutto il resto

Tre forme generiche completano i 21:

  • Un semplice elenco di dizionari {speaker, start, end, text}.
  • Un oggetto {"audio": ..., "turns": [...]}.
  • Un paragrafo semplice senza alcun tempo, mostrato come un unico fumetto.

Non supportati

Per questi non esiste alcun parser. Convertili prima.

  • SAMI (.smi), MicroDVD (.sub), SubViewer (.sbv)
  • Transcriber (.trs), EXMARaLDA, CHAT/CHILDES (.cha)
  • Output nativi di Montreal Forced Aligner e Gentle. Esporta invece CTM o TextGrid da quegli strumenti.
  • Azure Speech, Google Speech-to-Text e il verbose_json dell'API Whisper dentro involucri inusuali
  • File di diarizzazione RTTM da soli

La confidenza a livello di parola viene letta e conservata nel modello dati quando la sorgente la fornisce, ma al momento non esiste un'interfaccia per visualizzarla.

Il modello di turni normalizzato

Tutti i formati elencati sopra diventano questo:

json
{
  "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 e confidence compaiono solo se la sorgente li portava. speaker è null per i turni non diarizzati, che appaiono come Unassigned con un selettore così che chi annota possa completarli.

Tre turni di trascrizione con sfondo grigio tratteggiato, ciascuno etichettato Unassigned con una freccia a discesa, perché il formato di origine non conteneva etichette di parlante.I sottotitoli automatici di YouTube arrivano senza parlanti, quindi ogni turno resta Unassigned finché qualcuno non ne sceglie uno

turn_id è la chiave di persistenza per le annotazioni per turno e per le assegnazioni di parlante. Deriva da una stringa turn_id o step_id esplicita nella sorgente quando c'è, altrimenti da t{indice}. Lo stesso file produce sempre gli stessi identificatori, quindi le annotazioni sopravvivono a un ricaricamento.

Warning: Le unità di tempo cambiano da strumento a strumento. Whisper e Deepgram usano secondi in virgola mobile; AssemblyAI, gli offset di whisper.cpp e l'output TSV di Whisper usano millisecondi interi. Potato converte al confine così che tutto il resto sia in secondi. Se il tuo pre-processing mescola i due, i tempi escono sbagliati di mille volte.

File affiancati

Un valore di campo che sia un percorso breve su una sola riga terminante con un'estensione di trascrizione nota viene letto da disco invece di essere trattato come testo. Così la disposizione che il tuo strumento di riconoscimento vocale ha già prodotto, con i file multimediali accanto al loro .srt o .json, funziona senza alcun passaggio di pre-elaborazione:

json
{
  "id": "int_001",
  "conversation": {
    "audio": "media/int_001.mp3",
    "transcript": "media/int_001.srt"
  }
}

I percorsi si risolvono rispetto a task_dir e passano dalla stessa validazione di sicurezza di ogni altro percorso configurato, quindi un file di dati non può leggere fuori dal progetto.

Estensioni riconosciute: .srt .vtt .webvtt .json .json3 .srv1 .srv2 .srv3 .ttml .dfxp .xml .ass .ssa .tsv .ctm .TextGrid .eaf .txt

Se i tuoi dati contengono davvero trascrizioni di una riga che sembrano nomi di file, disattiva l'euristica:

yaml
display_options:
  transcript_is_path: auto   # auto (default) | true | false

Configurazione

Visualizzazione: audio_dialogue

La visualizzazione a dialogo audio mostra i turni come fumetti per parlante sincronizzati con l'audio, con un pulsante di riproduzione su ogni turno.

yaml
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
OpzionePredefinitoCosa fa
audio_keyaudioSottochiave del valore di campo che contiene l'URL o il percorso dell'audio.
turns_keyturnsSottochiave che contiene l'elenco dei turni. Accetta anche segments.
speaker_key / text_keyspeaker / textChiavi per turno.
speakers[]Elenco di {id, name, color, side}. I parlanti non elencati ricevono un colore deterministico e un lato alternato.
allow_speaker_assignmentautoauto attiva l'assegnazione con un clic quando ci sono turni non diarizzati o un elenco da correggere. true la forza, false la disattiva.
transcript_is_pathautoSe leggere il valore del campo come percorso a un file affiancato.
show_timestampstrueMostra mm:ss–mm:ss su ogni turno.
scroll_height480pxAltezza del riquadro di trascrizione scorrevole.
playback_rates[1, 1.25, 1.5, 2]Opzioni nel selettore di velocità.

Schemi

Dalla 2.7.1, speech_transcript, voice_interaction e tiered_annotation leggono una trascrizione direttamente dal record dell'istanza e accettano tutti i formati di questa pagina. Prima lo faceva solo la visualizzazione audio_dialogue.

yaml
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: turns

L'annotazione a livelli può precompilare un livello a partire dalla trascrizione, così chi annota corregge un allineamento esistente invece di risegmentare il parlato a mano:

yaml
  - 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"

Le annotazioni precompilate non vengono salvate finché chi annota non fa una modifica vera, così nulla viene attribuito a chi si è limitato ad aprire l'istanza.

Costruire un file di dati con potato transcripts

Punta il convertitore a una cartella di output di riconoscimento vocale e scriverà un file di dati pronto per l'annotazione:

bash
# 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 riferisce cosa ha trovato senza scrivere niente, ed è il modo più rapido per accorgersi di una cartella con il file di output Whisper sbagliato:

text
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.
OpzioneA cosa serve
-o, --outputDove scrivere. Obbligatorio tranne che con --dry-run.
--formatjson (predefinito) o jsonl.
--media-dirCartella di file multimediali da abbinare per nome base.
--media-url-prefixURL di base dei media invece di file locali.
--fieldCampo dell'elemento in cui va la trascrizione. Predefinito conversation.
--id-prefixStringa anteposta a ogni id generato.
--speaker-keyChiave di origine che contiene l'etichetta di parlante.
-r, --recursivePercorre le sottocartelle.
--dry-runRiferisce il formato riconosciuto e il numero di turni per file.
--emit-configStampa anche un frammento di config.yaml corrispondente.
-q, --quietSilenzia il resoconto per file.

Gli identificatori degli elementi derivano dal nome del file privato di un'estensione multimediale finale, quindi interview_01.mp3.json di Whisper diventa interview_01 e non interview_01.mp3.

Esportare di nuovo

Le annotazioni a livelli si esportano in ELAN EAF e Praat TextGrid, quindi una trascrizione può fare andata e ritorno: acquisirla, annotarla in Potato, esportarla, rifinirla in ELAN o Praat e rileggere il risultato.

bash
python -m potato.export --config config.yaml --format eaf --output ./out/
python -m potato.export --config config.yaml --format textgrid --output ./out/

Entrambi gli esportatori partono dall'output di tiered_annotation. Gli altri schemi si esportano attraverso i formati standard.

Risoluzione dei problemi

SintomoCosa è successo
Tutto appare come un unico grande fumettoIl formato non è stato riconosciuto ed è ricaduto sul ripiego a paragrafo semplice. Esegui potato transcripts <file> --dry-run; se riporta plain text, i tempi non sono mai stati letti. Di solito il file è un .txt di Whisper, che non ha alcun tempo, invece del .json o del .srt.
Nessun parlante, tutto UnassignedLa sorgente non contiene etichette di parlante. Whisper da solo non diarizza, e nemmeno i sottotitoli automatici di YouTube. Esegui la diarizzazione a monte oppure lascia che chi annota assegni i parlanti nell'interfaccia.
I tempi sono sbagliati di mille volteSecondi e millisecondi sono stati mescolati a monte. Gli offsets di whisper.cpp, AssemblyAI e il TSV di Whisper sono tutti in millisecondi.
Il percorso della trascrizione appare come testoIl file affiancato non è stato leggibile, quindi il percorso è stato mostrato come contenuto. Verifica che si risolva dentro task_dir. I log del server indicano il motivo preciso.
Una trascrizione su una riga viene letta come nome di fileImposta transcript_is_path: false sul campo di visualizzazione.

Progetto di esempio

examples/audio/transcript-formats/ nel repository di Potato mostra sei formati affiancati, ciascuno caricato da un file esterno: SubRip, WebVTT, Whisper JSON, YouTube json3, Praat TextGrid e Deepgram. Tutti e sei producono gli stessi fumetti per parlante.

bash
python potato/flask_server.py start examples/audio/transcript-formats/config.yaml -p 8000

Lo stesso compito è disponibile come progetto scaricabile: Transcript Format Ingestion.

Per i dettagli di implementazione, vedi la documentazione di origine.

Approfondimenti