Das Ziel
Beim Zuhören den Faden verlieren – das kennt jeder. Man scrollt nebenbei, der Blick wandert, und plötzlich weiß man nicht mehr, wo der Sprecher gerade ist. Die Lösung: Der aktive Absatz wird automatisch hervorgehoben, während man zuhört. Der Text folgt der Stimme.
So sieht das im Browser aus, wenn jemand einen OKAYPLAY-Artikel abspielt:
Mulchen: Der stille Held im Market Garden
Mulchen klingt nicht spektakulär. Kein fancy Werkzeug, keine Hightech-Lösung – einfach nur eine Schicht organisches Material auf dem Boden. Und doch war Mulch im FREILANDWERK einer unserer wichtigsten Verbündeten.
Was Mulch wirklich leistet
Eine gute Mulchschicht aus Stroh, Grasschnitt oder gehäckseltem Laub hält die Feuchtigkeit im Boden, unterdrückt Unkraut und füttert die Bodenlebewesen. In heißen Sommern war der Unterschied zwischen gemulchten und offenen Beeten dramatisch.
Die richtige Schichtdicke
Wir haben mit 5 bis 10 Zentimetern gearbeitet …
Der bereits gelesene Absatz ist leicht ausgeblendet. Die aktive Stelle – Überschrift und Absatz – bekommt einen sanften gelben Hintergrund und einen Akzent-Strich links. Der Rest wartet. Kein Raten, kein Suchen. Einfach mitlaufen.
Zwei Systeme, ein Ergebnis
Im letzten Post haben wir beschrieben, wie OKAYPLAY Absatz-Timestamps während der Aufnahme erzeugt – per Web Speech API direkt im Browser des Sprechers. Das funktioniert, hat aber eine Einschränkung: Die Granularität ist absatzweise, und die Qualität hängt vom Browser ab.
Deshalb gibt es eine zweite Schicht: Deepgram Nova-2, ein Speech-to-Text-Modell, das die fertige Audiodatei serverseitig analysiert und präzise Wort-Timestamps zurückliefert. Aus diesen Wort-Timestamps baut OKAYPLAY automatisch Satz-Timestamps – die Basis für das Highlighting im Player.
im Browser
serverseitig
per Overlap
per currentTime
Deepgram: Von Audio zu Wort-Timestamps
Sobald ein Sprecher seine Aufnahme hochlädt, wird die Audiodatei asynchron an die Deepgram-API geschickt. Das Modell: Nova-2, optimiert für deutsche Sprache. Zurück kommen einzelne Wörter mit Start- und Endzeit – auf Hundertstelsekunden genau.
// Deepgram-Antwort (vereinfacht)
{
"transcript": "Mulchen klingt nicht spektakulär...",
"confidence": 0.99,
"words": [
{ "word": "mulchen", "start": 1.20, "end": 1.68 },
{ "word": "klingt", "start": 1.76, "end": 2.14 },
{ "word": "nicht", "start": 2.16, "end": 2.40 },
// ... hunderte weitere Wörter
]
}Jetzt kommt der entscheidende Schritt: Diese Wort-Liste muss den Absätzen des Originalartikels zugeordnet werden. Denn Deepgram kennt den Artikeltext nicht – es liefert nur, was es hört.
Fuzzy Matching: Gesprochenes trifft Geschriebenes
Die Zuordnung läuft in drei Schritten: Pausen erkennen, Chunks bilden, Chunks den Absätzen zuordnen.
Schritt 1: Natürliche Pausen finden
Zwischen Absätzen macht jeder Sprecher eine kurze Pause. Wenn der zeitliche Abstand zwischen zwei Wörtern größer als 0,8 Sekunden ist, wird an dieser Stelle ein neuer Chunk gestartet. So entstehen Audio-Segmente, die typischerweise einem gesprochenen Absatz entsprechen.
// Pause Detection
for ($i = 1; $i < count($words); $i++) {
$gap = $words[$i]['start'] - $words[$i-1]['end'];
if ($gap >= 0.8) {
// Neuer Chunk: Sprecher hat pausiert
$chunks[] = [
'start' => $words[$chunkStart]['start'],
'end' => $words[$i-1]['end'],
];
$chunkStart = $i;
}
}Schritt 2: Wort-Overlap berechnen
Jeder Chunk wird gegen alle Artikelabsätze verglichen. Die Wörter werden normalisiert – Kleinschreibung, Umlaute auflösen, Satzzeichen entfernen – und dann per Set-Intersection abgeglichen. Der Absatz mit dem höchsten Overlap gewinnt. Mindest-Schwelle: 20%.
Das klingt simpel, ist aber erstaunlich robust. Selbst wenn Deepgram einzelne Wörter falsch erkennt (was bei Fachbegriffen oder Eigennamen vorkommt), reichen die restlichen Wörter locker für eine eindeutige Zuordnung.
Schritt 3: Chunks zusammenführen
Mehrere Chunks, die demselben Absatz zugeordnet werden, werden zeitlich zusammengeführt. Das Ergebnis: Pro Absatz ein Zeitfenster mit Start- und Endzeit. Genau die Datenstruktur, die der Player braucht.
// Fertige Timestamps pro Absatz
{
"sentences": [
{ "start": 1.20, "end": 3.70, "text": "Mulchen: Der stille Held..." },
{ "start": 4.88, "end": 17.60, "text": "Mulchen klingt nicht..." },
{ "start": 18.70, "end": 20.20, "text": "Was Mulch wirklich leistet" },
{ "start": 21.34, "end": 42.97, "text": "Eine gute Mulchschicht..." },
{ "start": 44.60, "end": 45.90, "text": "Die richtige Schichtdicke" },
// ...
],
"confidence": 0.991
}Im Player: Text folgt Audio
Wenn jemand auf Play drückt, lädt der OKAYPLAY-Player die Timestamp-Daten per API. Dann passiert Folgendes:
Der Player sucht auf der Webseitenbetreiber-Seite nach Absätzen und Überschriften (p, h1–h4, li) und ordnet sie den Timestamp-Sätzen zu – wieder per Fuzzy Matching, diesmal direkt im Browser. Alle 200 Millisekunden vergleicht ein Intervall die aktuelle Abspielzeit mit den Timestamps und setzt die CSS-Klasse okp-reading auf den passenden Absatz.
// Player-Highlighting (vereinfacht)
function _tsUpdate(currentTime) {
for (var i = 0; i < sentences.length; i++) {
if (currentTime >= sentences[i].start
&& currentTime < sentences[i].end) {
// Alten Absatz ausblenden
old.classList.remove('okp-reading');
// Neuen Absatz hervorheben
paragraphMap[i].classList.add('okp-reading');
paragraphMap[i].scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}
}
}Das Scrollen passiert sanft und nur wenn nötig – wenn der aktive Absatz außerhalb des Viewports liegt. Der Übergang zwischen Absätzen wird per CSS-Transition animiert: Der gelbe Hintergrund blendet in 0,4 Sekunden ein und in 0,6 Sekunden wieder aus. Kein harter Sprung, sondern ein fließender Wechsel.
Ein paar Zahlen
Das sind die Werte für den Mulchen-Artikel von FREILANDWERK – einen typischen Blogpost mit Titel, vier Absätzen und zwei Zwischenüberschriften. Deepgram erkennt 99,1% der Wörter korrekt, das Matching ordnet alle sieben Abschnitte den richtigen Stellen im Text zu. Auch die Überschriften – obwohl sie nur wenige Wörter lang sind – werden sauber erkannt und getimestampt.
Warum nicht einfach Whisper?
OpenAIs Whisper ist eine starke Alternative. OKAYPLAY nutzt Deepgram aus einem pragmatischen Grund: Es läuft auf Shared Hosting. Kein GPU-Server, kein Docker, kein Python-Stack. Deepgram ist eine API – Audio rein, JSON raus, fertig. Das passt zu einem Laravel-Projekt auf klassischem Webhosting.
| Kriterium | Whisper (Self-hosted) | Deepgram Nova-2 |
|---|---|---|
| Infrastruktur | GPU-Server nötig | API-Call |
| Latenz | Je nach Hardware | Unter 5 Sekunden |
| Deutsche Sprache | Gut | Sehr gut |
| Wort-Timestamps | Ja | Ja |
| Shared Hosting | Nicht möglich | Problemlos |
Qualitätssicherung: Text Match Score
Als Nebenprodukt des Matchings entsteht ein Text Match Score: Wie viel Prozent des Artikeltexts hat der Sprecher tatsächlich eingelesen? Der Score vergleicht das Deepgram-Transkript wortweise mit dem Originaltext – inklusive Levenshtein-Alignment für Reihenfolge und Overlap-Berechnung als Fallback.
Das ist gleichzeitig eine Qualitätssicherung: Wenn ein Sprecher nur die Hälfte des Textes liest oder stark abweicht, fällt das auf. Nicht als Blocker, sondern als Signal.
Wo wir hinwollen
Das Highlighting funktioniert. Aber es gibt noch Raum nach oben.
Alle TextSync-Funktionen sind jetzt live: Satz-Highlighting, Klick-to-Seek, Kapitel-Sprungmarken und Leseposition merken. Jede Funktion baut auf den Wort-Timestamps von Deepgram auf. Als Nächstes: Eine kurze Sprecher-Vorschau direkt am Play-Button, damit Zuhörer die Stimme kennenlernen, bevor sie starten Alle drei Funktionen bauen auf den Wort-Timestamps von Deepgram auf. Als Nächstes: Leseposition dauerhaft merken, damit Zuhörer auch nach Tagen genau dort weitermachen können, wo sie aufgehört haben Beide Funktionen bauen auf den Wort-Timestamps von Deepgram auf. Als Nächstes: Kapitel-Sprungmarken, die Überschriften als visuelle Marker direkt auf der Player-Timeline anzeigen – die Wort-Timestamps von Deepgram sind präzise genug, um einzelne Sätze innerhalb eines Absatzes zu isolieren. Klick-to-Seek ist dann nur noch eine Lookup-Tabelle: Absatz-Index zu Audio-Sekunde.
Fazit
Die Kombination aus Browser-seitigem Forced Alignment (während der Aufnahme) und serverseitigem Deepgram-Matching (nach dem Upload) liefert das Beste aus beiden Welten: Echtzeit-Feedback für den Sprecher und präzise Timestamps für den Zuhörer. Die Technik verschwindet im Hintergrund – was bleibt, ist der gelbe Balken, der durch den Text wandert.