Lokale Sprecher-Diarisierung: Wie wir einen zu 100 % privaten Meeting-Mitschreiber gebaut haben
OpenWhispr ist der Open-Source-Meeting-Assistent, bei dem dein Audio dein Gerät niemals verlässt. Jeder Stimmfingerabdruck, jede Sprecherbezeichnung, jedes Embedding – verarbeitet und gespeichert auf deinem eigenen Rechner.
OpenWhispr
Ingenieurwesen
Inhaltsverzeichnis
Lokale Sprecher-Diarisierung ist der Vorgang, in einer Meeting-Aufnahme zu kennzeichnen, wer wann gesprochen hat – vollständig auf dem Gerät des Nutzers ausgeführt, ohne dass Audio, Embeddings oder Transkripte an irgendeinen externen Server übertragen werden. Meeting-Transkripte haben ein „Wer-sagte-was“-Problem. Zoom liefert dir eine Textwand. Die meisten KI-Mitschreiber – Otter, Fireflies, Read, Granola – lösen das, indem sie dein Meeting-Audio auf ihre Server hochladen, dort ein Sprechermodell laufen lassen und dir gekennzeichnete Segmente zurückschicken. Deine Stimme und die deiner Kolleginnen und Kollegen landen als Vektoren in der Datenbank von jemand anderem. Das wollten wir nicht – und unsere Nutzer auch nicht. OpenWhispr ist der Open-Source-Meeting-Mitschreiber, der auf der entgegengesetzten Annahme aufbaut: Audio verlässt dein Gerät nie, Stimmfingerabdrücke liegen in einer lokalen SQLite-Datei auf deiner Festplatte, und nichts aus einem Meeting wird hochgeladen, es sei denn, du entscheidest dich ausdrücklich dafür. Dieser Artikel ist die technische Aufschlüsselung der Diarisierungsseite dieses Versprechens – was sie ist, welche Modelle wir gewählt haben, wie sie zusammenspielen und genau wo jedes Datenbyte in jedem Schritt liegt.
Zuletzt aktualisiert: 15. April 2026. Die Implementierungsdetails beziehen sich auf die Funktion zur Sprecher-Diarisierung, die am 14. April 2026 in die OpenWhispr-Desktop-App eingeflossen ist. Jede technische Aussage unten ist durch Primärquellen belegt oder direkt im Open-Source-Repository einsehbar.
Faktencheck-Momentaufnahme (zwei Quellen)
- Sprecher-Diarisierung beantwortet „wer wann gesprochen hat“. Sie wird anhand von Community-Benchmarks wie NIST Rich Transcription und der Referenz-Pipeline von pyannote.audio bewertet. NIST-RT-Bewertung · pyannote.audio-Paper (Bredin et al., 2020)
- Wir verwenden pyannote-segmentation-3.0 und CAM++ aus dem 3D-Speaker-Projekt. Beide sind Open Source, beide sind ONNX-portabel, und beide werden direkt aus den sherpa-onnx-Modell-Releases heruntergeladen. Modellkarte pyannote-segmentation-3.0 · CAM++ / 3D-Speaker-Paper (Wang et al., 2023)
- Die gesamte Inferenz läuft über sherpa-onnx, eine native ONNX-Binärdatei – keine Python-Laufzeit, kein PyTorch, keine GPU erforderlich. Wir pinnen die Binärdatei und ihre Abhängigkeiten zur Build-Zeit auf feste Versionen. sherpa-onnx auf GitHub · sherpa-onnx-Releases
- Stimmfingerabdrücke sind 512-dimensionale float32-Vektoren, die als lokale SQLite-BLOBs gespeichert werden, rund 2 KB pro Sprecher. Sie verlassen das Gerät nie. SQLite-Datentyp-Doku · ONNX Runtime
- Während der Diarisierung werden kein Audio, keine Embeddings und keine Transkripte vom Gerät übertragen. Die einzige Netzwerkaktivität der gesamten Funktion ist ein einmaliger Modell-Download beim ersten Start, den du im Open-Source-Repo selbst überprüfen kannst. OpenWhispr-Datenschutzrichtlinie · OpenWhispr auf GitHub
Was Sprecher-Diarisierung tatsächlich ist
Sprecher-Diarisierung ist der Vorgang, in einer Aufnahme zu kennzeichnen, wer wann gesprochen hat – nicht, was gesagt wurde. Transkription beantwortet das Was; Diarisierung beantwortet das Wer. Beide ergänzen einander: Ein guter Meeting-Mitschreiber braucht beides, und sie zum Zusammenspiel zu bringen, ist schwieriger als jedes für sich allein.
Diarisierung ist aus einer Handvoll hartnäckiger Gründe wirklich schwierig. Zwei Stimmen können sich im selben Gespräch überlagern. Hintergrundgeräusche sickern hinein. Kurze Äußerungen („ja“, „okay“) tragen kaum Sprecherinformationen. Neue Sprecher tauchen mitten im Meeting auf. Und anders als die Transkription muss die Diarisierung globale Entscheidungen treffen – sie kann Segment sieben nicht kennzeichnen, ohne es mit Segment zwei zu vergleichen. Wegen dieses globalen Kontexts erledigen die meisten kommerziellen Lösungen die Diarisierung serverseitig auf der gesamten Aufnahme und schicken dann das gekennzeichnete Transkript zurück.
Transkription allein reicht nicht. Ein Meeting mit zehn Personen und fünfundvierzig Minuten Durcheinandergerede, dargestellt als eine einzige undifferenzierte Textwand, ist unlesbar. Meeting-Notizen – das eigentliche Ergebnis, das die Leute wollen – erfordern eine Sprecherzuordnung, denn Aufgaben, Entscheidungen und Zusagen hängen alle an Personen. „Alice liefert die Migration bis Freitag“ ist eine Notiz. „Liefert die Migration bis Freitag“ ist Rauschen.
Diarisierung ist nicht dasselbe wie Sprechererkennung
Diarisierung sagt: „Diese drei Abschnitte sind Sprecher A; diese zwei sind Sprecher B.“ Sie weiß nicht, wer Sprecher A ist. Die Sprechererkennung gibt Sprecher A einen Namen, indem sie einen Stimmfingerabdruck mit einem gespeicherten Profil abgleicht. OpenWhispr macht beides – die Diarisierung läuft bei jedem Meeting, die Erkennung greift, sobald du jemanden namentlich gekennzeichnet hast. Beides bleibt lokal.
Die vierstufige lokale Pipeline
Die Pipeline zur Sprecher-Diarisierung von OpenWhispr hat vier Stufen: Sprachaktivitätserkennung, Segmentierung, Sprecher-Embedding und Clustering – gefolgt von einem Merge-Schritt, der die Sprechersegmente mit dem Transkript abgleicht. Jede Stufe ist ein eigenes ONNX-Modell oder eine native Binärdatei. Keine Python-Laufzeit, kein PyTorch, kein CUDA. Der gesamte Speicherbedarf der Modelle auf der Festplatte beträgt etwa 45 MB.
Die lokale Diarisierungspipeline
Warum es lokal bleibt:
Jede Stufe läuft auf deinem Gerät über eine einzige sherpa-onnx-Binärdatei – kein Python, keine Cloud.
~45MB von ONNX Modellen wurden einmal heruntergeladen und dann bei ~/.cache/openwhispr/diarization-models/. zwischengespeichert
Einbettungen sind 512-dim float32 Vektoren, die als SQLite BLOBs auf deiner lokalen Festplatte gespeichert sind.
Die Audioaufnahme erfolgt von Anfang an in zwei Streams. Das Mikrofon ist definitionsgemäß „du“, also verschwenden wir nie Rechenleistung darauf, deine eigene Stimme zu diarisieren – jedes Mikrofonsegment wird über die Quelle als du gekennzeichnet, nicht über einen Stimmabgleich. Das System-Audio (alle anderen im Gespräch) ist das Einzige, das tatsächlich nach Sprechern aufgeteilt werden muss, was die Arbeit sofort halbiert.
Sobald das Audio aufgenommen ist, laufen die vier Stufen nacheinander. Die VAD verwirft Stille, damit die teure Embedding-Stufe nie Rechenzyklen auf leere Frames verschwendet. Die Segmentierung zerschneidet zusammenhängende Sprache in Abschnitte mit nur einem Sprecher. Das Embedding-Modell verwandelt jeden Abschnitt in einen 512-dimensionalen Stimmfingerabdruck. Agglomeratives Clustering gruppiert ähnlich aussehende Fingerabdrücke und erzeugt eine endgültige Menge von Sprecher-IDs. Ein letzter Durchgang führt diese IDs anhand zeitlicher Überlappung wieder ins Transkript zurück, sodass jedes Wort am Ende einem Sprecher zugeordnet ist.
Das Ganze läuft innerhalb eines einzigen aus der App gestarteten Kindprozesses – kein Server, kein lauschender Port, keine IPC zu irgendetwas außerhalb von Electron. Das kannst du bestätigen, indem du src/helpers/diarization.js im Open-Source-Repo liest.
Stufe 1: Sprachaktivitätserkennung (Silero)
Die Sprachaktivitätserkennung (VAD) ist der günstige Filter, der Sprache von Stille trennt, bevor die teuren Stufen laufen. Ein Sprecher-Embedding-Modell auf Stille laufen zu lassen, ist verschwendete CPU-Leistung und erzeugt unbrauchbare Vektoren. Die VAD sorgt dafür, dass der Rest der Pipeline schnell bleibt.
Wir verwenden Silero VAD: ein 2 MB großes ONNX-Modell, MIT-lizenziert, faktisch der Open-Source-Industriestandard. Silero liefert pro Frame eine Wahrscheinlichkeit dafür, dass das aktuelle 32-Millisekunden-Fenster Sprache enthält. Auf einer modernen CPU sind die Kosten vernachlässigbar – etwa 0,1 Millisekunden pro 32-Millisekunden-Abschnitt, also rund ein Drittel Prozent eines Kerns.
Die Live-Pipeline lässt Silero während eines Gesprächs kontinuierlich auf dem System-Audio laufen. Die Schwellenwerte, mit denen wir tatsächlich ausliefern, sind auf echtes Meeting-Audio abgestimmt, nicht auf einen sauberen Benchmark:
- Fenstergröße: 512 Samples (32 ms bei 16 kHz)
- Sprach-Schwellenwert: 0,15 – bewusst aggressiv, damit leise oder weit entfernte Sprecher nicht übersehen werden
- Stille-Schwellenwert: 0,08
- Segment endet nach: 16 aufeinanderfolgenden stillen Fenstern (~512 ms)
- Mindestsegment für Embedding: 0,8 Sekunden
- Takt der Live-Erkennung: jede Sekunde, sobald ≥ 1,6 Sekunden Sprache angefallen sind
Ehrlicher Kompromiss
Ein aggressiver Sprach-Schwellenwert von 0,15 erfasst leise Sprecher an entfernten Mikrofonen, löst aber gelegentlich auch fälschlich bei lauten Tastenanschlägen oder Raumgeräuschen aus. Der Filter mit dem 0,8-Sekunden-Mindestsegment verwirft die meisten dieser Fehlauslösungen, bevor sie die Embedding-Stufe erreichen, sodass die nachgelagerte Genauigkeit geschützt bleibt.
Stufe 2: Segmentierung (pyannote 3.0)
Die Segmentierung nimmt zusammenhängende Sprache und zerschneidet sie in Abschnitte, die jeweils nur einen Sprecher enthalten, wobei sie sowohl Sprecherwechsel als auch Überlappungsbereiche erkennt. Es ist die Stufe, die entscheidet, wo die Sprechergrenzen liegen. Alles danach geht davon aus, dass diese Grenzen korrekt sind.
Wir verwenden pyannote-segmentation-3.0, die aktuelle Version des Modells vom pyannote.audio-Team, ONNX-exportiert vom sherpa-onnx -Projekt. Pyannote ist die De-facto-Referenz aus der Forschung: Die pyannote.audio-Pipeline erreicht auf Standard-Benchmarks wie AMI und CALLHOME Diarisierungsfehlerraten im Bereich von 12–15 % – dieselben Zahlen, die kommerzielle Cloud-Anbieter gern zitieren.
Warum gerade der ONNX-Port? Weil es ein Ausschlusskriterium ist, PyTorch in einer Electron-App auszuliefern – allein die Laufzeit ist rund 1,5 GB groß und braucht für Schnelligkeit faktisch eine GPU. Der ONNX-Export ist eine einzige 6,6 MB große Datei, die über ONNX Runtimeauf der CPU läuft. Dasselbe Modell, ein winziger Bruchteil des Gewichts.
Wir rufen es über die Offline-Diarisierungs-Binärdatei von sherpa-onnx mit einer Handvoll Flags auf. Die Einstellungen für die Mindestdauer stammen aus den im pyannote-Paper empfohlenen Standardwerten: Kurze Sprachausbrüche werden mit angrenzender Stille zusammengeführt, und kurze Stillephasen unterbrechen kein zusammenhängendes Sprechersegment. Die Ausgabe ist eine Liste von Start-/End-Zeitpaaren, versehen mit vorläufigen Sprecher-IDs ( speaker_0, speaker_1 usw.).
Stufe 3: Sprecher-Embeddings (CAM++)
Ein Sprecher-Embedding ist eine Zahlenliste mit fester Länge, die eine Stimme so repräsentiert, wie ein Hash eine Datei repräsentiert. Zwei Aufnahmen derselben Stimme erzeugen Embeddings, die im Vektorraum nahe beieinander liegen; unterschiedliche Stimmen erzeugen Embeddings, die weit auseinanderliegen. „Nahe“ wird über die Kosinus-Ähnlichkeit gemessen – eine einzige Zahl zwischen -1 und 1. Das ist das mathematische Herzstück von allem anderen in der Pipeline.
Unser Embedding-Modell ist CAM++ aus dem 3D-Speaker-Projekt der DAMO Academy von Alibaba, trainiert auf dem VoxCeleb -Sprecherverifizierungs-Benchmark. Die konkrete Datei, die wir ausliefern, ist 3dspeaker_speech_campplus_sv_en_voxceleb_16k.onnx, ein rund 28 MB großer ONNX-Export, der pro Segment einen 512-dimensionalen float32-Vektor erzeugt. Das Paper ist arXiv:2303.00332 (Wang et al., 2023).
Wir haben CAM++ gegenüber der naheliegenden Alternative, ECAPA-TDNN, aus drei konkreten Gründen gewählt: rund halb so viele Parameter, eine niedrigere Equal-Error-Rate auf VoxCeleb1-O und schnellere CPU-Inferenz. Das MSDD-Modell von NVIDIA NeMo hat keinen offiziellen ONNX-Export und stützt sich stark auf PyTorch. Picovoice Falcon hat eine kommerzielle Lizenz pro Platz. Apples CoreML-Speech-Framework ist nur für macOS verfügbar. CAM++ war die einzige Option, die unsere Anforderungen erfüllte – plattformübergreifend, ONNX, offene Lizenz, CPU-schnell.
Um CAM++ zu speisen, liefern wir unseren eigenen Log-Mel-Filterbank-Feature-Extraktor in src/helpers/speakerEmbeddings.js: 80 Mel-Bänder, 25-Millisekunden-Fenster, 10-Millisekunden-Schritte, Standardparameter für diese Modellklasse. Die Features fließen über onnxruntime-nodeins ONNX-Modell, ausgeführt im Electron-Hauptprozess. Auf der anderen Seite kommt ein 512-Einträge-Float32Array heraus, das wir als 2.048-Byte-BLOB in SQLite schreiben.
Der Abgleichsschritt selbst ist das Einfachste, was möglich ist: Kosinus-Ähnlichkeit zwischen zwei Vektoren. Hier ist der wörtliche Code, der entscheidet, ob zwei Meeting-Segmente derselbe Sprecher sind:
// src/helpers/speakerEmbeddings.js
cosineSimilarity(a, b) {
let dot = 0, normA = 0, normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
const denom = Math.sqrt(normA) * Math.sqrt(normB);
return denom === 0 ? 0 : dot / denom;
}Warum 512 Dimensionen?
512 ist auf dem VoxCeleb-Leaderboard zur Sprecherverifizierung aktuell der ideale Mittelweg zwischen Genauigkeit und Speicherkosten. Bei 256 Dimensionen beginnt die Unterscheidungskraft bei ähnlichen, aber unterschiedlichen Stimmen zu schwinden; 1024 Dimensionen kosten mehr Speicher und Rechenleistung bei abnehmendem Nutzen. 512 float32-Werte × 2 KB × tausend Meetings mit zehn Sprechern ergeben 20 MB auf der Festplatte. Das passt bequem in eine lokale SQLite-Datei.
Stufe 4: Clustering – das Problem „wie viele Sprecher?“
Nachdem du jedes Segment eingebettet hast, hast du N Vektoren. Das Clustering gruppiert sie in K Sprecher – aber das Schwierige ist, dass du K im Voraus meist nicht kennst. Ein Vertriebsgespräch hat vielleicht 2 Sprecher. Ein All-Hands vielleicht 8. Clustering mit festem K scheitert an beiden Enden.
Wir verwenden agglomeratives Clustering mit einem Kosinus-Ähnlichkeits-Schwellenwert von 0,5: Beginne mit jedem Segment als eigenem Cluster, führe die beiden Cluster mit der höchsten Ähnlichkeit zusammen, wiederhole das, bis kein verbleibendes Paar den Schwellenwert mehr übersteigt. Der Schwellenwert – nicht eine Zielanzahl – entscheidet, wo Schluss ist. Das skaliert ganz natürlich von zwei bis zehn Sprechern, ganz ohne Konfiguration.
Der eigentliche Aufruf liegt in src/helpers/diarization.js. Es ist ein Spawn der sherpa-onnx-Binärdatei mit einer Handvoll CLI-Flags:
// src/helpers/diarization.js
const args = [
`--segmentation.pyannote-model=${segPath}`,
`--embedding.model=${embPath}`,
`--clustering.num-clusters=${numSpeakers}`, // -1 = auto
`--clustering.cluster-threshold=${threshold}`, // 0.5 default
"--min-duration-on=0.2",
"--min-duration-off=0.5",
wavPath,
];Die Ausgabe ist reiner Text: eine Zeile pro Segment, formatiert als start_sec -- end_sec speaker_NN. Wir parsen das in ein Array von Objekten und gehen dann das Transkript durch, wobei wir jedes Transkriptsegment dem Diarisierungssegment mit der maximalen zeitlichen Überlappung zuordnen. Vom Mikrofon stammende Segmente werden immer als you gekennzeichnet – die Quelle schlägt die Stimme, jedes Mal.
Der Schwellenwert von 0,5 ist keine Schätzung. Wir haben ihn anhand unseres eigenen Eval-Harness (scripts/meeting-diarization-eval.js) auf echten Meeting-Aufnahmen abgestimmt. Höhere Schwellenwerte clustern zu wenig – ein Sprecher wird in zwei aufgeteilt. Niedrigere Schwellenwerte clustern zu stark – zwei ähnliche Stimmen werden zusammengeführt. 0,5 ist der ideale Wert, auf den wir uns festgelegt haben.
Live-Diarisierung: Bezeichnungen, während du sprichst
Reine Batch-Diarisierung ist genau, aber während eines Gesprächs unsichtbar. Reine Live-Verarbeitung ist sofort verfügbar, aber verrauscht. OpenWhispr macht beides: Live-Bezeichnungen erscheinen während des Meetings, und ein vollständiger Batch-Durchgang verfeinert sie danach.
Der Live-Pfad liegt in src/helpers/liveSpeakerIdentifier.js. Er greift den System-Audio-Stream bei 16 kHz ab, speist jeden 32-Millisekunden-Frame in Silero VAD und sammelt Sprach-Frames, bis ein Segment entweder schließt (nach ~512 ms Stille) oder den Live-Erkennungstakt erreicht (jede Sekunde, sobald ≥ 1,6 Sekunden angefallen sind). Beim Auslösen extrahiert er ein CAM++-Embedding, vergleicht es mit der In-Memory-Map der Embeddings des aktiven Gesprächs und der gespeicherten Sprecherprofile und löst ein IPC-Event aus – meeting-speaker-identified – mit der besten Übereinstimmung. Die React-Seite greift das auf und aktualisiert die Transkript-Sprechblase an Ort und Stelle.
Sobald ein Mensch in der Benutzeroberfläche manuell einen Sprechernamen festgelegt hat, ist diese Zuordnung gesperrt. Der nachträgliche Batch-Durchgang darf sie nicht überschreiben, selbst wenn seine eigene Analyse anderer Meinung ist. Dieses Sperrverhalten liegt in src/utils/transcriptSpeakerState.ts, und es ist wichtig: Die schlimmstmögliche Nutzererfahrung ist, einen automatischen Durchgang die Korrektur einer Person stillschweigend überschreiben zu lassen.
Wenn die Aufnahme stoppt, lassen wir die vollständige Offline-Diarisierung auf der kompletten WAV-Datei laufen. Der Batch hat den vollen Kontext – er sieht das ganze Meeting, nicht nur die letzten 1,6 Sekunden – und erzeugt eine sauberere endgültige Kennzeichnung. Das Batch-Ergebnis wird mit den Live-Bezeichnungen abgeglichen, respektiert jede Nutzersperre und ersetzt vorläufige Vermutungen durch die genauere Gruppierung.
Warum hybrid besser ist als jedes für sich
Reine Live-Verarbeitung ist schnell, aber bei kurzen Segmenten verrauscht. Reine Batch-Verarbeitung ist genau, aber stumm, bis das Meeting endet. Hybrid gibt dir beides – sofortiges Feedback während des Gesprächs und ein endgültiges Transkript, das die Analyse mit vollem Kontext widerspiegelt. Der Preis ist ein zusätzlicher Abgleichsschritt, der einmal im Hintergrund läuft und faktisch kostenlos ist.
Stimmprofile: Sprecher über Meetings hinweg wiedererkennen
Sobald du einen Sprecher in einem Meeting als „Alice“ kennzeichnest, kennzeichnet OpenWhispr sie in jedem künftigen Meeting automatisch – ohne dass du etwas tust und ohne dass ihr Stimmfingerabdruck je dein Gerät verlässt.
Der Mechanismus ist unkompliziert: Das Centroid-Embedding jedes Sprechers wird in deiner lokalen SQLite-Datenbank gespeichert. Wenn in einem künftigen Gespräch neue Embeddings auftauchen, vergleichen wir sie per Kosinus-Ähnlichkeit mit jedem gespeicherten Profil. Eine Übereinstimmung über dem Schwellenwert weist den Namen automatisch zu. Nichts davon berührt einen Server. Die drei Tabellen, die das antreiben, sind reines SQLite:
-- src/helpers/database.js
CREATE TABLE speaker_profiles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
display_name TEXT NOT NULL,
email TEXT,
embedding BLOB NOT NULL, -- 512 float32s (~2KB)
sample_count INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE speaker_mappings (
note_id INTEGER NOT NULL,
speaker_id TEXT NOT NULL,
profile_id INTEGER,
display_name TEXT NOT NULL,
PRIMARY KEY (note_id, speaker_id),
FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE,
FOREIGN KEY (profile_id) REFERENCES speaker_profiles(id) ON DELETE SET NULL
);
CREATE TABLE note_speaker_embeddings (
note_id INTEGER NOT NULL,
speaker_id TEXT NOT NULL,
embedding BLOB NOT NULL,
PRIMARY KEY (note_id, speaker_id),
FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE
);Der Abgleich erfolgt dreistufig, um Konfidenz gegen Falschtreffer abzuwägen:
- Kosinus ≥ 0,70: automatisch bestätigen. Die Bezeichnung erscheint sofort, ohne Nachfrage.
- 0,55 ≤ Kosinus < 0,70: vorschlagen. Die Benutzeroberfläche zeigt „Ist das Alice?“ mit Bestätigen-/Verwerfen-Schaltflächen und wartet auf deine Eingabe.
- Kosinus < 0,55: anonym bleiben. Das Segment bleibt Sprecher N, bis du sie manuell benennst.
Wenn du eine Übereinstimmung bestätigst, wird das gespeicherte Centroid über einen laufenden Mittelwert aktualisiert, statt es roh zu überschreiben. Die Formel ist einfach: new_avg = (stored_avg × sample_count + new_embedding) / (sample_count + 1). Das fängt Stimmdrift ab – ein kalter Morgen, ein anderes Mikrofon, ein schlechtes Kabel – ohne künftige Übereinstimmungen zu beeinträchtigen. Je mehr Stimmproben von Alice das System gesehen hat, desto stabiler wird ihr Profil.
Neue Profile lösen außerdem rückwirkende Neukennzeichnung aus. Wenn du einen Sprecher zum ersten Mal benennst, durchläuft eine Hintergrundaufgabe die gespeicherten Embeddings jedes vergangenen Meetings, findet Übereinstimmungen und aktualisiert zuvor unbenannte Sprecher in historischen Transkripten. Vom Nutzer gesperrte Zuordnungen werden nie angerührt. Das Ergebnis: Alice einmal zu benennen, kennzeichnet sie rückwirkend in jedem früheren Gespräch, an dem sie teilgenommen hat.
Wenn Google Calendar verbunden ist und das Meeting Teilnehmer hat, füllt sich die Sprecherauswahl-Oberfläche vorab mit deren Namen und E-Mail-Adressen. Ein Klick ordnet Sprecher 2 → alice@example.com zu und behält das für immer bei – Teilnehmer und Stimmprofile bleiben verknüpft, sodass die richtigen Namen sogar geräteübergreifend auftauchen.
Wo deine Daten tatsächlich liegen
Audio verlässt dein Gerät nie. Das ist kein Marketingspruch – es ist eine mechanische Eigenschaft des Codes, und weil OpenWhispr Open Source ist, kannst du es selbst überprüfen. Hier ist genau, was mit jedem Datenstück in jedem Schritt passiert.
| Was | Wo es liegt | Verlässt es dein Gerät? |
|---|---|---|
| Rohes Meeting-Audio | Temp-Verzeichnis des Betriebssystems, nach der Diarisierung gelöscht | Nein – niemals |
| ONNX-Modelle zur Diarisierung | ~/.cache/openwhispr/diarization-models/ | Einmal beim ersten Start heruntergeladen, dann nie wieder |
| Sprecher-Embeddings (Stimmfingerabdrücke) | Lokaler SQLite-BLOB | Nein – niemals |
| Sprecher-zu-Name-Zuordnungen | Lokale SQLite-Tabelle | Nein – niemals |
| Transkripttext | Lokales SQLite (optionale Cloud-Synchronisierung, wenn du sie aktivierst) | Nur wenn du dich dafür entscheidest |
Das rohe PCM-Audio aus einem Meeting wird in eine Datei im Temp-Verzeichnis deines Betriebssystems geschrieben, an die lokal gestartete sherpa-onnx-Binärdatei übergeben und in einem finally-Block gelöscht, sobald die Diarisierung abgeschlossen ist. Es gibt in der Diarisierungs-Pipeline von OpenWhispr keinen Codepfad, der einen Netzwerk-Socket öffnet, um Audio hochzuladen. Weil der Code Open Source ist, kannst du src/helpers/diarization.js, src/helpers/liveSpeakerIdentifier.js, und src/helpers/speakerEmbeddings.js nach fetch, axios, oder http durchsuchen und das selbst bestätigen.
Die IPC zwischen Electrons Haupt- und Renderer-Prozess nutzt das eingebaute contextBridge – eine Pipe auf Kernel-Ebene innerhalb eines einzigen Prozesses, kein Netzwerk-Socket. Sprecher-Embeddings und Stimmprofile werden als SQLite-BLOBs in derselben Datenbankdatei wie deine Notizen gespeichert, mit denselben Dateiberechtigungen auf Betriebssystemebene.
Eine Ausnahme, ganz transparent
Die einzige Netzwerkaktivität dieser Funktion ist der einmalige Modell-Download beim ersten Start – drei ONNX-Dateien, die vom CDN der sherpa-onnx-GitHub-Releases geholt werden. Wir dokumentieren das ausdrücklich, denn „ein Netzwerkaufruf beim Einrichten, danach keiner“ ist eine ganz andere Datenschutzgeschichte als „dauerhafte Cloud-Inferenz“, und als Open-Source-Meeting-Assistent sagen wir es dir lieber, als dass du es selbst entdeckst.
Ehrliche Grenzen
Lokale Diarisierung ist gut, nicht perfekt. Hier sind die Fälle, in denen sie wirklich Mühe hat, und was wir gegen jeden tun.
- Sich überlagernde Sprecher. Zwei Menschen, die gleichzeitig reden, sind für eine Zuordnung mit nur einer Bezeichnung von Natur aus verlustbehaftet. Pyannote 3.0 erkennt den Überlappungsbereich, aber eine einzelne speaker_id pro Segment reicht nicht aus, um „beide reden“ darzustellen. Wir markieren solche Segmente als vorläufig und lassen dich sie in der Benutzeroberfläche korrigieren.
- Kaltstart-Genauigkeit. Das erste Meeting mit einem neuen Kollegen nutzt nur die generischen, auf VoxCeleb trainierten Features. Sobald du ihn einmal kennzeichnest und das Profil ein paar Proben hat, sind die folgenden Meetings merklich genauer.
- Kurze Äußerungen. „Ja“, „okay“, ein kurzes Lachen – alles unter ~0,8 Sekunden kann kein verlässliches Embedding erzeugen. Wir verwerfen solche Segmente in der Embedding-Stufe und greifen auf eine Label-Übertragung aus dem umgebenden Kontext zurück.
- Fernfeld- oder Audio mit niedrigem SNR. Jemand auf einer Freisprechanlage in einem lauten Raum verschlechtert sich kontrolliert, aber sichtbar. Automatische Aussteuerung und VAD-Abstimmung helfen, aber keine noch so ausgefeilte Modellierung überwindet schlechte Physik vollständig.
- Inferenz nur auf der CPU. Eine GPU wäre schneller, aber wir setzen bewusst keine voraus. In der Praxis ist der Durchsatz auf einer modernen CPU völlig ausreichend: ~100 Millisekunden pro Embedding und etwa 30 Sekunden Batch-Diarisierung für ein 45-minütiges Meeting auf einem M1-Mac.
Wir veröffentlichen unseren Eval-Harness ( (scripts/meeting-diarization-eval.js) ) im Open-Source-Repo, damit du all das selbst messen kannst, auf deinen eigenen Aufnahmen – nicht auf unseren handverlesenen Demo-Clips. Das fühlt sich ehrlicher an als eine glänzende Zahl in einem Marketing-Foliensatz.
Warum wir uns für Sherpa-ONNX entschieden haben
Wir brauchten eine Diarisierungs-Laufzeit, die plattformübergreifend, Python-frei, CPU-schnell und Open Source war. Sherpa-ONNX war die einzige Option, die alle vier Punkte traf.
Unsere Anforderungen waren konkret. Sie musste auf macOS (sowohl Intel als auch Apple Silicon), Windows x64 und Linux x64 ohne separate Codepfade laufen. Sie durfte PyTorch nicht bündeln – allein die Laufzeit ist etwa 1,5 GB groß und braucht im Grunde eine GPU, um bei interaktiven Latenzen nutzbar zu sein. Sie durfte kein CUDA voraussetzen. Und die Lizenz musste freizügig genug sein, um in einer kommerziellen, aber quelloffenen Desktop-App ausgeliefert zu werden.
Hier ist, was wir tatsächlich evaluiert haben:
- pyannote.audio (Python): ausgeschlossen. PyTorch in einer Electron-App zu bündeln, ist ein Ausschlusskriterium.
- NVIDIA NeMo MSDD: PyTorch-abhängig, kein offizieller ONNX-Export, GPU-zentriert.
- Picovoice Falcon: kommerzielle Lizenz pro aktivem Nutzer plus Cloud-Aktivierung beim ersten Start.
- Apple CoreML + Speech-Framework: nur für macOS, keine plattformübergreifende Parität.
- sherpa-onnx: Apache 2.0, native ONNX-Binärdatei, ~35 MB an Modellen, Spawn-und-stdout-lesen-Schnittstelle, aktiv von k2-fsa gepflegt. Dieselbe Toolchain treibt produktive ASR in anderen ausgelieferten Produkten an.
Ein ehrlicher Vorbehalt: Die Offline-Sprecher-Diarisierungs-Binärdatei von sherpa-onnx ist relativ neu. Wir pinnen auf v1.12.23 als feste Version und lassen vor jedem Versionssprung unseren vollständigen Eval-Harness gegen jedes Update laufen. Das ist der richtige Kompromiss für etwas so Tragendes.
Häufig gestellte Fragen
- Gibt es einen privaten Meeting-Mitschreiber, der mein Audio nicht in die Cloud hochlädt?
- Ja. OpenWhispr ist ein kostenloser, quelloffener Meeting-Mitschreiber, bei dem dein Audio dein Gerät niemals verlässt. Die Transkription läuft lokal mit OpenAI Whisper oder NVIDIA Parakeet, die Sprecher-Diarisierung läuft lokal mit pyannote-Segmentierung und CAM++-Embeddings, und Stimmfingerabdrücke werden in einer lokalen SQLite-Datei auf deinem eigenen Rechner gespeichert – nicht auf unseren Servern.
- Können Otter, Fireflies oder Granola meine Meetings sehen?
- Ja. Cloud-basierte KI-Mitschreiber laden dein Meeting-Audio auf ihre Server hoch, um es zu transkribieren und zu diarisieren. Sprecherbezeichnungen, Transkripte und Stimm-Embeddings werden in ihrer Infrastruktur berechnet und in ihren Datenbanken gespeichert. Wenn du eine Alternative brauchst, die jedes Audio-Byte auf deinem Gerät behält, brauchst du ein Local-First-Tool wie OpenWhispr.
- Was ist Sprecher-Diarisierung?
- Sprecher-Diarisierung ist der Vorgang, in einer Aufnahme zu kennzeichnen, wer wann gesprochen hat – im Unterschied zur Transkription, die beantwortet, was gesagt wurde. Ein diarisiertes Transkript zeigt jede Äußerung mit einer Sprecherbezeichnung versehen – Alice, Bob, Sprecher 3 – statt einer einzigen undifferenzierten Textwand.
- Funktioniert lokale Sprecher-Diarisierung wirklich, oder ist sie ein Rückschritt gegenüber der Cloud?
- Sie funktioniert. Die Pipeline von OpenWhispr – pyannote-segmentation-3.0 plus CAM++-Embeddings aus dem 3D-Speaker-Projekt, ausgeführt über sherpa-onnx – erreicht auf Standard-Benchmarks Diarisierungsfehlerraten in derselben Größenordnung wie kommerzielle Cloud-APIs. Die wichtigsten ehrlichen Kompromisse sind der Umgang mit sich überlagernden Sprechern und die Kaltstart-Genauigkeit bei Stimmen, die das System noch nie gehört hat.
- Wie viel Speicherplatz benötigen die lokalen Diarisierungsmodelle?
- Insgesamt etwa 45 MB: pyannote-Segmentierung (6,6 MB) plus das CAM++-Sprecher-Embedding-Modell (28 MB) plus Silero VAD (2 MB). Alle drei werden einmal beim ersten Start heruntergeladen und unter ~/.cache/openwhispr/diarization-models/ zwischengespeichert. Danach bleiben sie auf der Festplatte und werden nie erneut heruntergeladen.
- Brauche ich eine GPU, um die lokale Diarisierung von OpenWhispr auszuführen?
- Nein. Alles läuft auf der CPU über ONNX Runtime. Moderne Apple-Silicon- und aktuelle x86-CPUs bewältigen es problemlos – in der Praxis etwa 30 Sekunden Batch-Diarisierung für ein 45-minütiges Meeting auf einem M1-Mac, wobei Live-Sprecherbezeichnungen während des Gesprächs selbst innerhalb von ein, zwei Sekunden erscheinen.
- Ist OpenWhispr tatsächlich Open Source?
- Ja. Der Diarisierungscode, die Transkriptions-Pipeline und der Rest der Desktop-App sind auf GitHub Open Source. Die Datenschutzaussagen in diesem Artikel sind direkt überprüfbar: Durchsuche die Diarisierungs-Helfer nach fetch, axios oder http, und du wirst keinerlei Netzwerkaufrufe im Diarisierungspfad finden.
- Was passiert, wenn zwei Personen in einem Gespräch durcheinanderreden?
- Pyannote 3.0 erkennt und annotiert Überlappungsbereiche ausdrücklich, aber die Zuordnung mit nur einer Bezeichnung während einer Überlappung ist von Natur aus verlustbehaftet. Wir markieren solche Segmente im Transkript als vorläufig und lassen dich sie korrigieren, indem du auf die Sprecherbezeichnung klickst. Deine manuellen Korrekturen sind gesperrt und werden von späteren automatischen Durchgängen nie überschrieben.
Probiere den privaten Meeting-Mitschreiber aus
OpenWhispr ist ein kostenloser, quelloffener Meeting-Assistent, bei dem dein Audio dein Gerät niemals verlässt. Lokale Diarisierung, lokale Transkription, lokale Stimmprofile. Funktioniert auf macOS, Windows und Linux.
Kein Konto erforderlich · Funktioniert offline · Für immer Open Source