# 04 Diktat (Whisper im Browser)
Überall, wo längerer Text entsteht - Projektbeschreibung, Interaktionsnotiz,
nächster Schritt, interne Notizen - sitzt ein Mikrofon-Button. Die Erkennung
läuft **vollständig im Browser des Benutzers**.
Das Backend ist daran nicht beteiligt und sieht keine Audiodaten: kein API-Key,
keine Kosten pro Minute, kein Datenabfluss. Aufnahmen werden nirgends gespeichert.
## Weg der Aufnahme
```mermaid
flowchart LR
MIC(("Mikrofon")) --> MR["MediaRecorder"]
MR --> AC["AudioContext
16 kHz Mono PCM"]
AC --> W["Web Worker"]
W --> ONNX["Whisper als ONNX
WebGPU, sonst WASM"]
ONNX --> T["Text"]
T --> F["Formularfeld"]
HF["Hugging-Face-CDN"] -.->|"einmalig 759 MB"| CACHE[("Cache-Speicher
der Seite")]
CACHE --> ONNX
```
Die Erkennung liegt im Web Worker (`src/lib/whisper.worker.ts`), damit die
Oberfläche währenddessen nicht einfriert. Die ONNX-Laufzeit wird mit
ausgeliefert (Vite bundelt die `.wasm`), nur die Modelldateien kommen beim ersten
Laden vom CDN und bleiben danach im Cache-Speicher der Seite.
## Lebenszyklus des Modells
```mermaid
stateDiagram-v2
[*] --> idle : Anmeldung
idle --> loading : "Sprachmodell laden" oder
automatisch, wenn schon im Cache
loading --> ready : im Worker initialisiert
loading --> error : Abbruch, Haenger, kein Speicher
error --> loading : erneut versuchen
ready --> idle : "Sprachmodell löschen"
ready --> ready : Diktat benutzen
note right of loading
Phase download: Dateien holen
Phase init: Modell im Worker aufbauen
end note
```
Beim Anmelden wird das Modell automatisch bereitgestellt, **wenn** es schon in
diesem Browser liegt. Ein Download von 759 MB startet nie von allein, und der
Automatismus greift bewusst nur einmal pro Seitenaufruf: wer das Modell löscht,
bekommt es nicht sofort wieder heruntergeladen.
## Wo es sitzt
Reiter **Whisper** in den Einstellungen - für **jede Rolle** sichtbar, denn jeder
richtet sein Diktat auf seinem eigenen Gerät ein. Genau deshalb sind die
Einstellungen überhaupt für alle Rollen zugänglich; welche Reiter erscheinen,
entscheidet die Rolle:
```mermaid
flowchart LR
E["Einstellungen"] --> A["Mein Konto
(alle)"]
E --> W["Whisper
(alle)"]
E --> N["Nutzerverwaltung
(admin)"]
E --> S["Scanner
(admin)"]
```
Ist das Modell noch nicht geladen, wird der Mikrofon-Button zu *Diktat
einrichten* und springt per `goTo('Einstellungen', { tab: 'whisper' })` direkt
dorthin - ein offener Dialog wird vorher geschlossen (`onBeforeNavigate`).
## Warum keine Auswahl
Modell, Genauigkeit, Rechenweg und Sprache stehen als Konstanten in
`src/lib/whisper.tsx`: `large-v3-turbo`, `q4`, Grafikkarte wenn vorhanden,
Deutsch. Jede andere Kombination war in den Messungen entweder schlechter oder
kaputt - bei `small` in fp16 auf WebGPU reagiert der ganze Browser-Tab nicht mehr,
und **kein Timeout in der Seite kann das abfangen**, weil das Skript selbst nicht
mehr läuft.
Eine Auswahl hätte also nur Gelegenheit geboten, etwas falsch zu machen. Die
Messwerte stehen im [README](../README.md#warum-small-und-q4---die-messungen).
Als Netz bleibt eine Frist pro Erkennung (15x Aufnahmedauer, mindestens 45 s,
höchstens 5 min) und eine Hänger-Erkennung beim Laden.