Bei INNOQ entstehen laufend neue Podcast-Folgen. Die Transkription verursacht ziemlich viel Aufwand. Sowas sollte doch in der neuen KI-Welt automatisierbar sein!
Manuelle Versuche ergaben, dass Googles Gemini-Modelle die Aufgabe am besten lösen. Whisper von OpenAI konnte zum Beispiel nicht mithalten.
Die Gemini-Modelle eignen sich durch ihr riesiges Kontextfenster und ihre Audio-Fähigkeiten bestens für die Transkription von Gesprächen. In diesem Blogpost erzähle ich, wie ich nach einigen Hindernissen zu einer Lösung kam.
Naiver Ansatz und erster Dämpfer
Was ist schon dabei? Audio-Datei im Google AI Studio hochladen, Prompt schreiben und ab damit!
Es stellt sich raus, dass es nicht genügend Output Tokens dafür gibt. Eine Stunde Podcast produziert ungefähr 20000 bis 30000 Tokens im Transkript. Die (non-reasoning) Gemini-Modelle können maximal 8192 Tokens ausgeben. Wir freuen uns über das großzügige 1-Mio-Token-Kontextfenster, aber wenn wir viel Text produzieren müssen, sind die Ouput Tokens das Hindernis.
Ohne Programmieren geht es nicht
Mit Handarbeit kommen wir nicht weiter. Also muss was programmiert werden. Hier bauen sich schon die nächsten Hürden auf.
- Die API begrenzt die Größe der Audio-Datei in einem Request auf 20MB. Das MP3 eines einstündigen Podcast hat ca. 70MB.
- Man kann größere Dateien vorher hochladen. Diese bleiben nur 48h am Leben. Ich soll also den Lifecycle dieser Dateien managen. Nein danke, zu zerbrechlich das Ganze mit zu viel state management. Ich brauche ein Tool, das jederzeit dort weitermachen kann wo es aufgehört hat (Restartfähigkeit). KI-basierte Tools können Launen haben und man muss dann in der Lage sein, Teile der Ergebnisse zu verwerfen und schnell neu erzeugen zu lassen, ohne immer ganz von vorne anfangen zu müssen.
Chunking muss sein - und macht neue Probleme
Also muss die Audiodatei zerhackt, und die Stücke einzeln transkribiert werden mit je einem API call. Beim Zerteilen (Chunking) muss man aufpassen, dass an einer Sprechpause getrennt wird, nicht mitten in einem Satz. Den Algorithmus in Python habe ich ChatGPT schreiben lassen, weil ich davon keine Ahnung hatte. Mit der pydub Library funktionierte es auf Anhieb und ich lernte was dazu. Damit es nicht zu einfach wird, musste ich die Lautstärke mit Audiokompression angleichen (wieder mit pydub), weil sonst die Pausenerkennung bei leisen Aufnahmen versagt.
Wer seid ihr?
Jetzt wurde es schwierig mit der Personenerkennung. Wenn die Vorstellungsrunde am Anfang fehlt, wie soll das Modell wissen wer spricht? Die Idee: Ein Intro rausschneiden, ungefähr 2–3 Minuten lang, wo alle zu Wort kommen, und das Intro vor jeden Chunk kleben.
Die Personenerkennung funktioniert mit diesem Trick gut, aber jeder Chunk enthält nun das Intro, das ich danach aus dem Transkript wieder entfernen muss. Das ist komplizierter als erwartet, da man nicht einfach nach einem Text suchen kann, auch nicht mit Ähnlichkeitssuche. Das Modell fasst immer wieder mal Abschnitte der gleichen Person zusammen und es wird außerdem eine wacklige Angelegenheit, wenn der letzte Textblock im Intro ausgerechnet ein „Ähm” ist. Ich spreche aus Erfahrung…
Lösung: Einen prägnanten, einfachen Trennsatz einsprechen, der so sicher nie vorkommt und immer eindeutig transkribiert wird. Das Audio des Trennsatzes wird zwischen Intro und Chunk eingefügt mit einigen Sekunden Pause dazwischen. Diese Methode ist sehr zuverlässig.
Transkript-Format
Ich wählte ein JSON-Format, um flexibel in der Weiterverarbeitung zu sein.
[
{
"speaker": "Hermann",
"text": "Herzlich willkommen zum INNOQ Podcast. Ich bin Hermann Schmidt und begrüße unseren Gast Jemand",
"timestamp": "00:00"
},
{
"speaker": "Jemand",
"text": "Hallo, ich bin Jemand und freue mich, hier sein zu dürfen.",
"timestamp": "00:05"
}
...
]
Modelle sind launisch
Das erste Modell war Gemini 2.0 Flash experimental. Die Texte waren sehr exakt, aber die Zeitstempel völlig unbrauchbar. Außerdem wurde das Modell öfter faul, wenn es auf die 4000 Output Tokens zuging. Dann wurden Personen nicht mehr getrennt und am Ende eines Chunks fand ich dicke Textblöcke. Außerdem hatte es keine Lust mehr, die definierte JSON-Struktur ordentlich abzuschließen.
Überraschung: Man kann die maximale Menge an Output-Tokens gar nicht nutzen!
Mit der Pro-Version dauerte alles viel zu lange und das Ergebnis war nicht besser.
Nach einem Update von Google konnte zu meinem Erstaunen Gemini-2.0-flash-lite-preview-02–05 die Zeitstempel sekundengenau ausgeben und leistete sich keine Fehler im Text. Die Faulheit hatte es aber geerbt.
Modelle können nicht alles
Um bei schwierigen Eigennamen die richtige Schreibweise zu bekommen, legte ich eine Glossar-Datei an, die in jedes Prompt eingefügt wird. Dann gibt es kein „Jason” statt „JSON” oder „Chat GPT” statt „ChatGPT” mehr. Das funktioniert sehr gut.
Die Personenerkennung kommt an ihre Grenzen, wenn die Qualität der Aufnahme mäßig ist oder wenn gleichzeitig gesprochen wird. Auch tut sich das Modell leichter, wenn die Tonlage der Personen unterschiedlich ist.
Sonstige Implementierungsdetails
Alle Zwischenergebnisse werden in Dateien zwischengespeichert. Ein Restart ist immer möglich, ohne mühsam von vorne anfangen zu müssen.
Ein Postprocessing-Schritt liest Prompts aus Dateien und wendet diese auf das rohe Transkript an. So lässt sich vollautomatisch Übersetzen, Sätze von „ähm” befreien, Schwurbeltext vereinfachen, Zusammenfassungen unterschiedlicher Länge und Art erstellen, etc. Die Möglichkeiten sind endlos. Durch das Caching kosten Experimente mit Postprocessing wenig Zeit.
Ablaufübersicht
Zusammenfassung
Die Voraussetzung für ein gutes Transkript ist gute Audioqualität!
Die Präzision des Transkripts ist erstaunlich hoch. Es wird wirklich jedes Wort und jede Lautäußerung erkannt. Nachbearbeitung ist nur notwendig, wenn neue Eigennamen vorkommen, die das Modell nicht erkennt oder nicht richtig schreiben kann. Diese werden in die Glossar-Datei eingetragen, und nächstes Mal wird es besser.
Durch sekundengenaue Zeitstempel kann man stichprobenartig prüfen, ob bei verdächtigen Passagen die Personen richtig zugeordnet sind. Wir denken, dass es zu verschmerzen ist, dass mal jemand verwechselt wird, wenn der Inhalt völlig korrekt ist.
Die Aufbereitung des Audiomaterials hat die meiste Zeit gekostet. An zweiter Stelle stand die Zeit für das Verständnis der Eigenarten des Modells.
Es hat sich gelohnt, ein eigenes Tool dafür zu bauen, weil Spezialwünsche so viel zielgenauer erfüllt werden können.