Skip to content
Announcements5 min read

Potato 2.7.1: Das Transkript gibt es schon

Potato 2.7.1 liest 21 Transkript- und Untertitelformate direkt, lädt sie aus Begleitdateien neben den Medien und bringt einen Konverter mit, der aus einem Ordner voller ASR-Ausgaben eine annotationsfertige Datendatei macht.

Potato Team

Fast niemand kommt mit rohem Audio und sonst nichts zu einem Annotationswerkzeug. Man kommt mit einem Transkript. Jemand hat Whisper über einen Ordner voller Interviews laufen lassen. Jemand hat die Untertitel von hundert Konferenzvorträgen heruntergeladen. Jemand hat ein Korpus von TextGrids aus einem Feldforschungsprojekt geerbt, das 2019 endete.

Und dann verlangt das Werkzeug ein Konvertierungsskript.

In Potato 2.7.1 geht es darum, diesen Schritt zu streichen. Es liest 21 Transkript- und Untertitelformate direkt, lädt sie aus Dateien, die neben den Medien liegen, statt zu verlangen, dass alles in eine Datendatei kopiert wird, und bringt einen Konverter für den Fall mit, dass am Ende doch eine einzige Datendatei stehen soll.

Potato 2.7.1: 21 Transkriptformate hinein, ein Turn-Modell herausPotato 2.7.1

21 Formate hinein, ein Modell heraus

Vorher waren es 6. Die vollständige Liste steht auf der Seite Transkriptformate, grob aber: neun Arten von ASR-Ausgaben (Whisper JSON, WhisperX und anderes diarisiertes JSON, whisper.cpp, Whisper TSV, AWS Transcribe, Deepgram, AssemblyAI, Rev.ai, SPoRC), sechs Untertitelformate (SubRip, WebVTT, SubStation Alpha, TTML und DFXP, YouTube json3, YouTube srv1/srv2/srv3), drei aus der Welt des Forced Alignment (NIST CTM, Praat TextGrid, ELAN EAF) und drei generische Formen für Daten, die ganz woanders herkommen.

Über die Alignment-Formate freuen wir uns am meisten. Den Export nach EAF und TextGrid gab es schon, Ebenen-Annotationen laufen damit jetzt einen vollen Kreis: ein bestehendes Alignment einlesen, in Potato korrigieren und zurück an ELAN oder Praat schicken.

Die Erkennung geht über die Form der Daten und nicht über die Dateiendung. Eine WebVTT-Datei namens captions.txt wird also weiterhin als WebVTT gelesen, und dasselbe Transkript funktioniert eingebettet ebenso wie von der Festplatte gelesen, ohne Änderung an der Konfiguration.

Wortweise Zeiten und Konfidenz je Segment bleiben erhalten, sofern die Quelle sie liefert. Formate, die von Haus aus wortweise sind, etwa CTM, Deepgram und AssemblyAI, werden bei Sprecherwechsel und über eine Pausenschwelle zu Turns gruppiert.

Ein Transkript als farbige Sprecherblasen mit einem Abspielknopf je Turn und einer eingebetteten BeschriftungsfrageWelches Format auch hineinging, das kommt heraus

Begleitdateien

Das ASR-Werkzeug hat die Dateien ohnehin schon sinnvoll abgelegt: Medien hier, Transkript daneben. Es gab keinen guten Grund, das erst zu einem Datenklumpen platt zu drücken, also lässt sich jetzt einfach darauf zeigen:

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

Pfade werden relativ zu task_dir aufgelöst und durchlaufen dieselbe Prüfung gegen Verzeichniswechsel wie jeder andere konfigurierte Pfad. Enthalten die Daten tatsächlich einzeilige eingebettete Transkripte, die zufällig wie Dateinamen aussehen, schaltet transcript_is_path: false die Heuristik ab.

Der praktische Gewinn: Die Transkripte bleiben Dateien. Man kann sie diffen, neu erzeugen und weitergeben, statt eine Kopie in einem JSON-Array zu versteinern.

Ein Konverter für den anderen Fall

Manchmal will man doch eine einzige Datendatei. potato transcripts durchsucht einen Ordner, ordnet jedes Transkript über den Basisnamen seinen Medien zu, leitet die Element-IDs aus den Dateinamen ab und schreibt das Ergebnis:

bash
potato transcripts ./whisper_out --media-dir ./audio -o data/interviews.json

--dry-run schreibt nichts und meldet, was gefunden wurde. Das ist auch das Erste, was man ausführt, wenn ein Transkript als ein einziger undifferenzierter Block erscheint:

text
Scanned 3 file(s):
  interview_01.json      Whisper JSON      42 turns    891.4s  undiarized
  interview_02.json      WhisperX JSON     51 turns   1120.8s  2 speaker(s): SPEAKER_00, SPEAKER_01
  interview_03.json      Whisper JSON      38 turns    754.2s  undiarized

3 item(s), 131 turn(s).

Eine Datei, die als plain text gemeldet wird, ist fast immer ein Whisper-.txt, das sich unter die .json-Ausgaben gemischt hat. Das .txt enthält überhaupt keine Zeiten, und ohne einen erneuten Modelllauf sind sie nicht zurückzuholen. Diese eine Tatsache erklärt die meisten Meldungen der Sorte „warum sieht mein Transkript falsch aus", die uns erreichen.

--emit-config gibt zusätzlich zur Datendatei eine passende config.yaml aus.

Ein Vokabular über vier Schemata

audio_dialogue, speech_transcript, voice_interaction und tiered_annotation haben Transkriptdaten früher jeweils auf eigene Weise geparst und unterschiedliche Teilmengen der Formate akzeptiert, aus Gründen, die niemand benennen konnte. Sie teilen sich jetzt einen Normalisierer, was also eines akzeptiert, akzeptieren alle vier.

Bestehende Konfigurationen sind nicht betroffen. Jedes Schema behält sein altes Parsing als Rückfallebene, und jede Transkriptform, die vorher funktionierte, funktioniert weiterhin Byte für Byte.

tiered_annotation bekommt außerdem eine optionale Vorbefüllung aus dem Transkript. transcript_field auf das Transkript zeigen lassen, und eine Ebene kommt vorbefüllt an, sodass Annotatoren ein bestehendes Alignment korrigieren, statt die Sprache von Grund auf neu zu segmentieren:

yaml
  - annotation_type: tiered_annotation
    name: tiers
    source_field: audio_url
    media_type: audio
    tiers:
      - name: utterance
        labels:
          - name: speech
            color: "#7c3aed"

Vorbefüllte Intervalle werden erst gespeichert, wenn ein Annotator sie tatsächlich bearbeitet, ein unangetasteter Vorschlag wird also nie fälschlich als menschliche Arbeit verbucht.

Was Potato weiterhin nicht tut

Es transkribiert nicht, und es diarisiert nicht. Die ASR läuft vorgelagert. Potato liest, was die Pipeline produziert hat.

Das kommt auf, weil Potato sehr wohl ein lokales Whisper-Modell ausführt, nämlich für den Think-Aloud-Modus, der Annotatoren beim Sprechen während der Arbeit aufnimmt. Das ist eine Aufnahmefunktion, die auf die Annotatoren zielt und nicht auf das Korpus. Andere Sache, gleiches Wort.

Wortweise Konfidenz wird gelesen und im Datenmodell behalten, sofern die Quelle sie liefert, aber es gibt noch keine Oberfläche, um sie anzusehen.

Und für manche Formate gibt es gar keinen Parser: SAMI, MicroDVD, SubViewer, Transcriber .trs, EXMARaLDA, CHAT/CHILDES, RTTM für sich allein sowie die nativen Ausgaben von Montreal Forced Aligner und Gentle. Die gehören vorher konvertiert. Wir veröffentlichen diese Liste, weil eine Liste unterstützter Formate, aus der nichts ausgeschlossen ist, wenig wert ist.

Dokumentation

  • Transkriptformate — jedes Format mit seiner Erkennungsregel, das normalisierte Turn-Modell, die Regeln für Begleitdateien, die Konfigurationsschlüssel und eine Fehlersuche nach echten Symptomen
  • Whisper-Transkripte annotieren — welche Ausgabedatei man behalten sollte, und warum die Diarisierung eine eigene Entscheidung ist
  • YouTube-Untertitel annotierenyt-dlp, und was automatische Untertitel hergeben und was nicht
  • Transcript Format Ingestion — ein lauffähiges Design mit sechs Formaten nebeneinander

Aktualisieren

bash
pip install --upgrade potato-annotation==2.7.1

An der Konfiguration muss nichts geändert werden. Jede Transkriptform, die Potato vorher akzeptiert hat, akzeptiert es weiterhin.