- --until-enter: Aufnahme mit beliebig langen Pausen, Enter beendet, Ausgabe als ein Text - stt_llm.py: Nachkorrektur per lokalem LLM (Standard gemma4:12b über Ollama nativ mit kleinem Kontext; OpenAI-kompatible Server möglich), strenger Prompt mit Beispielen, Ähnlichkeitsprüfung und Fehler-Fallback auf den Rohtext - Output-Klasse in der CLI: Korrektur in eigenem Thread, Reihenfolge bleibt erhalten - Tests für die LLM-Korrektur (13 Unit, 1 Integration) - Doku: Bedienungsanleitung, README, Entwicklerdoku (inkl. Modellvergleich), CLAUDE.md Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
505 lines
23 KiB
Markdown
505 lines
23 KiB
Markdown
# Bedienungsanleitung SpeechToText
|
||
|
||
Diese Anleitung richtet sich an **Anwender**: Installieren, Starten, Benutzen, Einrichten mit Home
|
||
Assistant, Probleme lösen. Für Programmierer: [docs/API.md](docs/API.md) (Schnittstellen) und
|
||
[docs/ENTWICKLER.md](docs/ENTWICKLER.md) (Aufbau des Codes).
|
||
|
||
## Inhalt
|
||
|
||
1. [Was macht das Programm?](#1-was-macht-das-programm)
|
||
2. [Voraussetzungen](#2-voraussetzungen)
|
||
3. [Installation](#3-installation)
|
||
4. [Dienst starten und prüfen](#4-dienst-starten-und-prüfen)
|
||
5. [Benutzung mit der Kommandozeile (CLI)](#5-benutzung-mit-der-kommandozeile-cli)
|
||
6. [Das richtige Mikrofon](#6-das-richtige-mikrofon)
|
||
7. [Home Assistant anbinden](#7-home-assistant-anbinden)
|
||
8. [Andere Geräte im Netzwerk](#8-andere-geräte-im-netzwerk)
|
||
9. [Einstellungen](#9-einstellungen)
|
||
10. [Welches Whisper-Modell?](#10-welches-whisper-modell)
|
||
11. [Tipps für gute Erkennung](#11-tipps-für-gute-erkennung)
|
||
12. [Fehlerbehebung](#12-fehlerbehebung)
|
||
13. [Datenschutz](#13-datenschutz)
|
||
14. [Deinstallation](#14-deinstallation)
|
||
|
||
---
|
||
|
||
## 1. Was macht das Programm?
|
||
|
||
SpeechToText wandelt **gesprochene Sprache in Text** um — vollständig **lokal** auf dem eigenen Rechner,
|
||
ohne Cloud. Grundlage ist das Spracherkennungsmodell *Whisper* in der schnellen Umsetzung
|
||
*faster-whisper*.
|
||
|
||
Es besteht aus zwei Teilen:
|
||
|
||
- **Dem Dienst** (`stt_service.py`): läuft im Hintergrund, hält das Sprachmodell im Speicher und nimmt
|
||
Aufträge entgegen — von Home Assistant, von Mikrocontrollern, von Skripten oder von der CLI.
|
||
- **Der Kommandozeile** (`stt_cli.py`): schickt Audiodateien oder das Mikrofon an den Dienst und gibt den
|
||
erkannten Text aus.
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
MIC[Mikrofon] --> CLI[stt_cli.py]
|
||
FILE[Audiodatei] --> CLI
|
||
HA[Home Assistant] -- Wyoming :10300 --> SVC
|
||
ESP[ESP32 / Skripte / Apps] -- HTTP / WebSocket :9998 --> SVC
|
||
CLI -- HTTP / WebSocket :9998 --> SVC[STT-Dienst<br/>Whisper-Modell auf GPU]
|
||
SVC --> TXT[Text]
|
||
```
|
||
|
||
**Wie schnell?** Auf einer RTX 3090 mit dem Modell `large-v3-turbo`: ein Satz von 6 Sekunden ist in
|
||
0,2 Sekunden erkannt, 35 Sekunden Sprache in 0,7 Sekunden. Beim freien Sprechen erscheint der Text etwa
|
||
eine Sekunde, nachdem man aufgehört hat zu sprechen.
|
||
|
||
**Wie merkt das Programm, dass ich fertig bin?** Es erkennt eine **Sprechpause** (Standard: 0,7 s Stille
|
||
nach Sprache). Ein Stoppwort ist nicht nötig.
|
||
|
||
---
|
||
|
||
## 2. Voraussetzungen
|
||
|
||
| | Minimum | Empfohlen |
|
||
|---|---|---|
|
||
| Betriebssystem | Linux (getestet: Ubuntu mit PipeWire) | |
|
||
| Python | 3.11 | 3.12 (getestet) |
|
||
| Grafikkarte | keine (läuft auch auf CPU, dann langsamer) | NVIDIA mit ≥ 4 GB freiem Speicher, CUDA 12 |
|
||
| Arbeitsspeicher | 4 GB frei | 8 GB frei |
|
||
| Festplatte | 0,5 GB (Modell `small`) | 2 GB (Modell `large-v3-turbo`) |
|
||
| Mikrofon | beliebig (nur für Live-Betrieb) | ReSpeaker XVF3800 oder gutes USB-Mikrofon |
|
||
|
||
Systemprogramme: `ffmpeg` ist hilfreich (Formatumwandlung), `pactl` (PipeWire/PulseAudio) für die
|
||
Mikrofonwahl, `espeak-ng` nur für die automatischen Tests.
|
||
|
||
---
|
||
|
||
## 3. Installation
|
||
|
||
```bash
|
||
cd ~/Python_Programs
|
||
git clone <repository-url> SpeechToText # bzw. vorhandenen Ordner nutzen
|
||
cd SpeechToText
|
||
|
||
python3 -m venv --system-site-packages .venv
|
||
.venv/bin/pip install -r requirements.txt
|
||
```
|
||
|
||
`--system-site-packages` nutzt bereits installierte Pakete (z. B. faster-whisper, CUDA-Bibliotheken)
|
||
mit. Ohne vorhandene Installation lädt `pip` alles herunter.
|
||
|
||
**Installation prüfen** (dauert ca. 10 Sekunden, braucht kein Modell):
|
||
|
||
```bash
|
||
.venv/bin/python -m pytest
|
||
# … 49 passed
|
||
```
|
||
|
||
> Beim **ersten Start des Dienstes** wird das Whisper-Modell aus dem Internet geladen
|
||
> (`large-v3-turbo` ≈ 1,6 GB). Danach arbeitet alles offline.
|
||
|
||
---
|
||
|
||
## 4. Dienst starten und prüfen
|
||
|
||
### Manuell starten
|
||
|
||
```bash
|
||
cd ~/Python_Programs/SpeechToText
|
||
.venv/bin/python stt_service.py
|
||
```
|
||
|
||
Auf Rechnern mit **mehreren Grafikkarten** die gewünschte Karte fest angeben. Die Kennung (UUID) zeigt
|
||
`nvidia-smi -L`:
|
||
|
||
```bash
|
||
CUDA_VISIBLE_DEVICES=GPU-83ba6d1f-ebbe-f8c8-1433-153e0ebc3866 .venv/bin/python stt_service.py
|
||
```
|
||
|
||
> Warum UUID statt Nummer? `nvidia-smi` und CUDA nummerieren die Karten unterschiedlich. Mit der UUID
|
||
> landet der Dienst sicher auf der richtigen Karte.
|
||
|
||
Im Terminal erscheint u. a.:
|
||
|
||
```
|
||
INFO stt.service: Wyoming-Server auf tcp://0.0.0.0:10300
|
||
INFO stt: Lade Whisper-Modell large-v3-turbo (cuda, float16)
|
||
INFO stt: Modell bereit nach 2.3s
|
||
```
|
||
|
||
Das Fenster offen lassen. **Beenden** mit `Strg+C`.
|
||
|
||
### Prüfen
|
||
|
||
In einem zweiten Terminal:
|
||
|
||
```bash
|
||
curl http://127.0.0.1:9998/health
|
||
```
|
||
|
||
`"status":"ok"` = bereit. `"status":"loading"` = Modell lädt noch (kurz warten).
|
||
`"device":"cuda"` = läuft auf der Grafikkarte, `"cpu"` = auf dem Prozessor.
|
||
|
||
Im Browser zeigt **http://127.0.0.1:9998/docs** alle Schnittstellen zum Ausprobieren.
|
||
|
||
### Optional: automatisch starten (systemd)
|
||
|
||
Soll der Dienst dauerhaft laufen (nötig z. B. für Home Assistant nach einem Neustart):
|
||
|
||
```bash
|
||
cp deploy/stt-service.service ~/.config/systemd/user/
|
||
# ggf. CUDA_VISIBLE_DEVICES und Einstellungen in der Datei anpassen
|
||
systemctl --user daemon-reload
|
||
systemctl --user enable --now stt-service
|
||
```
|
||
|
||
| Aufgabe | Befehl |
|
||
|---|---|
|
||
| Status | `systemctl --user status stt-service` |
|
||
| Neustart (nach Änderungen) | `systemctl --user restart stt-service` |
|
||
| Anhalten | `systemctl --user stop stt-service` |
|
||
| Autostart abschalten | `systemctl --user disable --now stt-service` |
|
||
| Live-Log | `journalctl --user -u stt-service -f` |
|
||
|
||
Vorher einen manuell gestarteten Dienst beenden — beide wollen Port 9998.
|
||
|
||
---
|
||
|
||
## 5. Benutzung mit der Kommandozeile (CLI)
|
||
|
||
Die CLI gibt **nur den erkannten Text** aus (Standardausgabe). Statusmeldungen stehen getrennt davon
|
||
(Fehlerausgabe). Deshalb lässt sie sich direkt in Skripten verwenden.
|
||
|
||
Alle Beispiele im Projektordner: `cd ~/Python_Programs/SpeechToText`
|
||
|
||
### Audiodateien
|
||
|
||
```bash
|
||
.venv/bin/python stt_cli.py aufnahme.wav
|
||
.venv/bin/python stt_cli.py interview.mp3 notiz.ogg # mehrere Dateien, eine Zeile je Datei
|
||
.venv/bin/python stt_cli.py aufnahme.wav --json # mit Details
|
||
.venv/bin/python stt_cli.py aufnahme.wav > text.txt # in Datei speichern
|
||
```
|
||
|
||
Unterstützt: WAV, MP3, OGG, FLAC, M4A, WebM und praktisch alle anderen Audioformate.
|
||
|
||
### Mikrofon
|
||
|
||
```bash
|
||
.venv/bin/python stt_cli.py -v
|
||
```
|
||
|
||
Nach **„Bereit — sprich.“** einfach sprechen und kurz Pause machen. Jeder Satz erscheint als eigene
|
||
Zeile. Beenden mit `Strg+C`.
|
||
|
||
### Mit Pausen sprechen, selbst beenden
|
||
|
||
```bash
|
||
.venv/bin/python stt_cli.py --until-enter -v
|
||
```
|
||
|
||
Die Aufnahme läuft, bis **Enter** gedrückt wird — Denk- und Sprechpausen beliebiger Länge beenden sie
|
||
nicht. Mit `-v` erscheinen die erkannten Abschnitte schon während des Sprechens (mit `+` markiert).
|
||
Nach Enter wird der letzte Abschnitt fertig transkribiert und der **gesamte Text als eine Zeile**
|
||
ausgegeben. Mit `--timeout SEK` endet die Aufnahme spätestens nach SEK Sekunden.
|
||
|
||
```
|
||
Mikrofon: pulse → alsa_input.usb-Seeed_Studio_reSpeaker_XVF3800_… (16000 Hz, 2 Kanäle, Kanal 1)
|
||
Bereit — sprich. (Strg+C beendet)
|
||
… Sprache erkannt (2.3s)
|
||
(3.1s Audio, 0.21s Rechenzeit)
|
||
Schalte das Licht im Wohnzimmer ein.
|
||
```
|
||
|
||
### Alle Optionen
|
||
|
||
| Option | Bedeutung |
|
||
|---|---|
|
||
| `DATEI …` | Audiodateien transkribieren; ohne Datei wird das Mikrofon benutzt |
|
||
| `-v`, `--verbose` | Statusdetails anzeigen (Sprachbeginn, Dauer, Rechenzeit) |
|
||
| `--json` | Ergebnis als JSON-Zeile (Text, Sprache, Dauer, Rechenzeit …) |
|
||
| `-l`, `--language` | Sprache: `de`, `en`, `fr` … oder `auto` (automatisch erkennen) |
|
||
| `--prompt "…"` | Eigennamen/Fachbegriffe vorgeben, z. B. `--prompt "Bredelar, Marsberg"` |
|
||
| `--once` | nach dem ersten erkannten Satz beenden |
|
||
| `--until-enter` | Aufnahme mit **beliebig langen Pausen**, bis Enter gedrückt wird; Ergebnis als **ein** Text |
|
||
| `--timeout SEK` | Mikrofon nach SEK Sekunden beenden |
|
||
| `--silence-ms MS` | Pausenlänge, die einen Satz beendet (Standard 700; für Denkpausen 1200–2000) |
|
||
| `-d`, `--device` | Mikrofon wählen: Nummer oder Namensteil, z. B. `-d respeaker` |
|
||
| `--channel N` | Mikrofonkanal wählen (ReSpeaker: automatisch 1) |
|
||
| `--list-devices` | verfügbare Mikrofone anzeigen (`*` = Standard von PortAudio) |
|
||
| `--url URL` | anderer Dienst, z. B. `--url http://192.168.1.10:9998` (auch per `STT_URL`) |
|
||
| `--local` | **ohne Dienst**: Modell direkt laden (Start dauert länger) |
|
||
| `--model NAME` | nur mit `--local`: Whisper-Modell, z. B. `small`, `large-v3-turbo` |
|
||
| `--compute-device` | nur mit `--local`: `auto`, `cuda` oder `cpu` |
|
||
| `--http-timeout SEK` | max. Wartezeit bei Dateien (Standard 300) |
|
||
| `--llm-correct` | Ergebnis zusätzlich von einem lokalen LLM korrigieren lassen, siehe [LLM-Korrektur](#llm-korrektur-optional) |
|
||
| `--llm-model NAME` | LLM für die Korrektur (Standard `gemma4:12b`) |
|
||
| `--llm-url URL` | LLM-Server (Standard Ollama `http://127.0.0.1:11434`; OpenAI-kompatibel mit `…/v1`) |
|
||
|
||
### Rückgabewerte (für Skripte)
|
||
|
||
| Code | Bedeutung |
|
||
|---|---|
|
||
| `0` | Text erkannt |
|
||
| `1` | Fehler (Dienst nicht erreichbar, Datei fehlt …) |
|
||
| `2` | keine Sprache erkannt (nur Stille/Geräusche, Zeitlimit abgelaufen) |
|
||
| `130` | mit `Strg+C` abgebrochen, bevor ein Ergebnis vorlag (z. B. während einer Dateiübertragung) |
|
||
|
||
### Beispiele für Skripte
|
||
|
||
```bash
|
||
# Einen Satz sprechen und in einer Variablen weiterverarbeiten
|
||
text=$(.venv/bin/python stt_cli.py --once --timeout 15)
|
||
[ $? -eq 0 ] && echo "Du hast gesagt: $text"
|
||
|
||
# Alle MP3s eines Ordners in Textdateien umwandeln
|
||
for f in aufnahmen/*.mp3; do
|
||
.venv/bin/python stt_cli.py "$f" > "${f%.mp3}.txt"
|
||
done
|
||
|
||
# Längere Notiz mit Pausen sprechen, Enter beendet, Text in Variable
|
||
notiz=$(.venv/bin/python stt_cli.py --until-enter)
|
||
|
||
# Diktat mit Denkpausen fortlaufend in eine Datei schreiben
|
||
.venv/bin/python stt_cli.py --silence-ms 1500 >> notizen.txt
|
||
```
|
||
|
||
### LLM-Korrektur (optional)
|
||
|
||
Mit `--llm-correct` wird der erkannte Text zusätzlich von einem **lokalen Sprachmodell** (Standard:
|
||
`gemma4:12b` über Ollama) geprüft. Es korrigiert nur offensichtliche Erkennungsfehler — falsch
|
||
verstandene Wörter, Rechtschreibung, Groß-/Kleinschreibung, Satzzeichen — und lässt Bedeutung, Zahlen,
|
||
Namen und Verneinungen unangetastet.
|
||
|
||
```bash
|
||
.venv/bin/python stt_cli.py --until-enter --llm-correct -v
|
||
.venv/bin/python stt_cli.py notiz.mp3 --llm-correct --json
|
||
```
|
||
|
||
```
|
||
LLM: korrigiert (1.21s)
|
||
roh: Heute ist ein schöner Tag. Die Lonne scheint und die Rögel singen im Garten.
|
||
Heute ist ein schöner Tag. Die Sonne scheint und die Vögel singen im Garten.
|
||
```
|
||
|
||
**Sicherungen:** Weicht die Antwort des LLM zu stark vom erkannten Text ab (z. B. weil es etwas erfindet
|
||
oder einer „Anweisung“ im Diktat folgt), wird sie verworfen und der **Rohtext** ausgegeben. Ist das LLM
|
||
nicht erreichbar, erscheint eine Meldung und ebenfalls der Rohtext. Mit `--json` stehen Rohtext
|
||
(`raw_text`) und Details (`llm`: Status, Dauer, Modell) immer mit im Ergebnis.
|
||
|
||
**Wann sinnvoll?** Für Notizen, Diktate und längere Texte. Für kurze Befehle („Licht an“) nicht nötig —
|
||
Whisper erkennt sie meist fehlerfrei, und die Korrektur kostet rund 1 Sekunde pro Text.
|
||
|
||
**Voraussetzungen und Hinweise:**
|
||
|
||
- Ollama läuft und das Modell ist installiert: `ollama pull gemma4:12b`.
|
||
- Das **erste Laden** dauert je nach Rechner rund eine Minute; im Mikrofon-Modus beginnt es schon beim
|
||
Start im Hintergrund. Danach bleibt das Modell 30 Minuten geladen (`STT_LLM_KEEP_ALIVE`).
|
||
- Das Modell belegt dabei ca. 10 GB Grafikspeicher.
|
||
- Anderes Modell oder anderer Server: `--llm-model mistral-nemo` bzw.
|
||
`--llm-url http://127.0.0.1:8011/v1` (llama.cpp, LM Studio …).
|
||
|
||
### Ohne laufenden Dienst
|
||
|
||
```bash
|
||
.venv/bin/python stt_cli.py --local --model large-v3-turbo aufnahme.wav
|
||
.venv/bin/python stt_cli.py --local --model small --compute-device cpu -v # Mikrofon auf CPU
|
||
```
|
||
|
||
Praktisch für gelegentliche Nutzung; jeder Aufruf lädt das Modell aber neu (Sekunden bis Minuten).
|
||
|
||
---
|
||
|
||
## 6. Das richtige Mikrofon
|
||
|
||
**Standard:** Ohne `-d` benutzt die CLI das Mikrofon, das in den **Systemeinstellungen** (Ubuntu:
|
||
Einstellungen → Ton → Eingabe) ausgewählt ist. Die erste Statuszeile zeigt, welches:
|
||
|
||
```
|
||
Mikrofon: pulse → alsa_input.usb-Seeed_Studio_reSpeaker_XVF3800_…
|
||
```
|
||
|
||
**Anderes Mikrofon:**
|
||
|
||
```bash
|
||
.venv/bin/python stt_cli.py --list-devices # Liste mit Nummern
|
||
.venv/bin/python stt_cli.py -d 15 -v # per Nummer
|
||
.venv/bin/python stt_cli.py -d respeaker -v # per Namensteil
|
||
```
|
||
|
||
**ReSpeaker XVF3800:** Das Gerät liefert zwei Kanäle. Der **rechte Kanal (1)** ist speziell für
|
||
Spracherkennung aufbereitet (Echo- und Rauschunterdrückung). Die CLI erkennt den ReSpeaker am Namen und
|
||
wählt Kanal 1 automatisch. Andere Mikrofone: beide Kanäle werden gemischt; mit `--channel 0`/`1` lässt
|
||
sich ein Kanal erzwingen.
|
||
|
||
**Pegel prüfen:** In den Toneinstellungen muss der Eingangspegel beim Sprechen ausschlagen. Wird nie
|
||
„Sprache erkannt“ angezeigt, ist das Mikrofon meist falsch gewählt, stumm oder zu leise.
|
||
|
||
---
|
||
|
||
## 7. Home Assistant anbinden
|
||
|
||
Der Dienst spricht das **Wyoming-Protokoll**, mit dem Home Assistant lokale Spracherkennung einbindet.
|
||
|
||
1. Dienst dauerhaft laufen lassen ([systemd](#optional-automatisch-starten-systemd)), sonst fehlt die
|
||
Spracherkennung nach einem Neustart.
|
||
2. Port 10300 im Netzwerk erreichbar machen (siehe [Abschnitt 8](#8-andere-geräte-im-netzwerk)).
|
||
3. In Home Assistant: **Einstellungen → Geräte & Dienste → Integration hinzufügen → „Wyoming Protocol“**
|
||
4. **Host:** IP-Adresse des STT-Rechners, **Port:** `10300` → Absenden. Es erscheint „speech-to-text“.
|
||
5. **Einstellungen → Sprachassistenten** → Assistent öffnen → **Spracherkennung:** „speech-to-text“,
|
||
Sprache „Deutsch“.
|
||
6. Testen, z. B. über das Mikrofon-Symbol in der Home-Assistant-App oder einen ESPHome-Satelliten
|
||
(z. B. ESP32-S3-Box, M5Stack Atom Echo).
|
||
|
||
Home Assistant bzw. der Satellit erkennt das Satzende selbst und schickt die komplette Aufnahme. Im Log
|
||
des Dienstes erscheint pro Befehl eine Zeile `Wyoming-Transkript (…)`.
|
||
|
||
---
|
||
|
||
## 8. Andere Geräte im Netzwerk
|
||
|
||
Der Dienst ist im ganzen Netzwerk erreichbar unter `http://<IP-des-Rechners>:9998` (HTTP/WebSocket) und
|
||
`<IP>:10300` (Wyoming). Die IP zeigt `hostname -I`.
|
||
|
||
Ist eine Firewall aktiv, die Ports für das Heimnetz freigeben:
|
||
|
||
```bash
|
||
sudo ufw allow from 192.168.1.0/24 to any port 9998 proto tcp comment 'SpeechToText HTTP'
|
||
sudo ufw allow from 192.168.1.0/24 to any port 10300 proto tcp comment 'SpeechToText Wyoming'
|
||
```
|
||
|
||
(`192.168.1.0/24` an das eigene Netz anpassen.)
|
||
|
||
> **Wichtig:** Der Dienst hat **kein Passwort**. Jeder im Netzwerk kann Audio schicken. Die Ports daher
|
||
> **nicht ins Internet** freigeben (keine Portweiterleitung im Router).
|
||
|
||
Wie Mikrocontroller (ESP32), Web-Apps oder eigene Programme den Dienst ansprechen, beschreibt
|
||
[docs/API.md](docs/API.md) mit Beispielen.
|
||
|
||
---
|
||
|
||
## 9. Einstellungen
|
||
|
||
Der Dienst wird über **Umgebungsvariablen** eingestellt:
|
||
|
||
- **manuell:** vor den Startbefehl schreiben, z. B.
|
||
`STT_MODEL=small STT_LANGUAGE=en .venv/bin/python stt_service.py`
|
||
- **systemd:** in `~/.config/systemd/user/stt-service.service` als `Environment="STT_MODEL=small"`,
|
||
danach `systemctl --user daemon-reload && systemctl --user restart stt-service`
|
||
|
||
| Variable | Standard | Bedeutung |
|
||
|---|---|---|
|
||
| `STT_MODEL` | `large-v3-turbo` | Whisper-Modell, siehe [Abschnitt 10](#10-welches-whisper-modell) |
|
||
| `STT_LANGUAGE` | `de` | Standardsprache; `auto` = automatisch erkennen |
|
||
| `STT_DEVICE` | `auto` | `auto` (GPU wenn vorhanden), `cuda` oder `cpu` |
|
||
| `STT_COMPUTE_TYPE` | `auto` | Rechengenauigkeit; `auto` = `float16` auf GPU, `int8` auf CPU |
|
||
| `STT_CPU_MODEL` | `small` | Modell, falls die GPU nicht nutzbar ist und auf CPU ausgewichen wird |
|
||
| `STT_CPU_THREADS` | `0` | CPU-Threads (0 = automatisch) |
|
||
| `STT_BEAM_SIZE` | `5` | Suchbreite; `1` ist schneller, `5` genauer |
|
||
| `STT_INITIAL_PROMPT` | – | Eigennamen/Fachbegriffe für alle Anfragen |
|
||
| `STT_PRELOAD` | `1` | Modell sofort beim Start laden (`0` = erst bei der ersten Anfrage) |
|
||
| `STT_MAX_QUEUE` | `8` | max. gleichzeitig wartende Aufträge, darüber Ablehnung („beschäftigt“) |
|
||
| `STT_MAX_UPLOAD_MB` | `50` | größte erlaubte Audiodatei |
|
||
| `STT_VAD_SILENCE_MS` | `700` | Pause, die beim Live-Streaming einen Satz beendet |
|
||
| `STT_VAD_THRESHOLD` | `0.5` | Empfindlichkeit der Spracherkennung (höher = weniger Fehlauslösung durch Geräusche) |
|
||
| `STT_VAD_MIN_SPEECH_MS` | `200` | Mindestlänge von Sprache (filtert Klicks und Klopfen) |
|
||
| `STT_VAD_PRE_ROLL_MS` | `300` | Audio vor dem erkannten Sprachbeginn mitnehmen |
|
||
| `STT_VAD_MAX_UTTERANCE_S` | `30` | längster Satz; längere Abschnitte werden geteilt |
|
||
| `STT_WYOMING_PORT` | `10300` | Port für Home Assistant; leer = aus |
|
||
| `STT_WYOMING_HOST` | `0.0.0.0` | Netzwerkschnittstelle für Wyoming |
|
||
| `STT_HOST` / `STT_PORT` | `0.0.0.0` / `9998` | Adresse des HTTP-Dienstes (nur bei `python stt_service.py`) |
|
||
| `STT_LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
||
| `STT_DOWNLOAD_ROOT` | – | eigener Ordner für Modelle (sonst Hugging-Face-Cache) |
|
||
| `CUDA_VISIBLE_DEVICES` | – | Grafikkarte festlegen (UUID aus `nvidia-smi -L`) |
|
||
|
||
**LLM-Korrektur** (nur `stt_cli.py --llm-correct`):
|
||
|
||
| Variable | Standard | Bedeutung |
|
||
|---|---|---|
|
||
| `STT_LLM_MODEL` | `gemma4:12b` | Modell für die Korrektur |
|
||
| `STT_LLM_URL` | `http://127.0.0.1:11434` | Ollama; OpenAI-kompatible Server mit `…/v1` |
|
||
| `STT_LLM_API` | `auto` | `auto`, `ollama` oder `openai` |
|
||
| `STT_LLM_KEEP_ALIVE` | `30m` | nur Ollama: wie lange das Modell nach Gebrauch geladen bleibt |
|
||
| `STT_LLM_NUM_CTX` | `4096` | nur Ollama: Kontextgröße (klein halten, sonst läuft das Modell auf der CPU) |
|
||
| `STT_LLM_TIMEOUT` | `120` | max. Wartezeit in Sekunden (inkl. Laden) |
|
||
| `STT_LLM_MIN_SIMILARITY` | `0.75` | Mindestähnlichkeit zum Rohtext, sonst wird die Korrektur verworfen |
|
||
|
||
---
|
||
|
||
## 10. Welches Whisper-Modell?
|
||
|
||
| Modell | Qualität Deutsch | Geschwindigkeit | Grafikspeicher | Einsatz |
|
||
|---|---|---|---|---|
|
||
| `tiny` | mäßig | sehr schnell | < 1 GB | nur Tests |
|
||
| `base` | ausreichend für kurze Befehle | sehr schnell | ~1 GB | schwache Hardware |
|
||
| `small` | gut | schnell, auch auf CPU brauchbar | ~1 GB | **CPU-Betrieb** |
|
||
| `medium` | sehr gut | mittel | ~2–3 GB | |
|
||
| `large-v3` | ausgezeichnet | langsamer | ~4 GB | höchste Genauigkeit bei langen Texten |
|
||
| **`large-v3-turbo`** | ausgezeichnet | **schnell** | **~2,4 GB** | **Standard mit GPU** |
|
||
|
||
Gemessen wurde in diesem Projekt nur `large-v3-turbo` (RTX 3090); `small` auf CPU ist durch die Tests
|
||
erprobt. Die übrigen Angaben sind Richtwerte. Jedes Modell wird beim ersten Gebrauch einmalig heruntergeladen.
|
||
|
||
---
|
||
|
||
## 11. Tipps für gute Erkennung
|
||
|
||
- **Abstand:** 30 cm bis 1 m zum Mikrofon, deutlich, aber normal sprechen.
|
||
- **Pause am Satzende:** Nach dem Satz kurz innehalten — das signalisiert „fertig“.
|
||
- **Denkpausen:** Wird ein Satz mitten drin abgeschnitten, `--silence-ms 1200` (oder mehr) verwenden.
|
||
- **Eigennamen:** Werden Namen falsch geschrieben, mit `--prompt "Name1, Name2"` vorgeben.
|
||
- **Hintergrundgeräusche:** Radio/Fernseher leiser; bei vielen Fehlauslösungen `STT_VAD_THRESHOLD=0.6`.
|
||
- **Sprache fest einstellen:** `-l de` ist schneller und zuverlässiger als `auto`, besonders bei kurzen
|
||
Sätzen.
|
||
|
||
---
|
||
|
||
## 12. Fehlerbehebung
|
||
|
||
| Problem | Ursache | Lösung |
|
||
|---|---|---|
|
||
| `Fehler: … Connection refused` / „Läuft der Dienst?“ | Dienst nicht gestartet | Dienst starten ([Abschnitt 4](#4-dienst-starten-und-prüfen)) oder `--local` nutzen |
|
||
| `/health` zeigt lange `loading` | erster Start: Modell wird heruntergeladen | Internetverbindung prüfen, warten; Fortschritt im Log |
|
||
| `/health` zeigt `"device":"cpu"`, obwohl eine GPU da ist | GPU belegt/zu wenig Speicher/CUDA-Problem | Log lesen (`Laden auf cuda fehlgeschlagen: …`), `nvidia-smi` prüfen, andere Karte per `CUDA_VISIBLE_DEVICES` |
|
||
| `/health` zeigt `error` | Modell nicht ladbar | Meldung im Feld `error`; Modellname und Speicherplatz prüfen |
|
||
| Nie „Sprache erkannt“ | falsches/stummes Mikrofon | [Abschnitt 6](#6-das-richtige-mikrofon); Pegel in den Toneinstellungen prüfen |
|
||
| Sätze werden mittendrin geteilt / Aufnahme endet bei Pausen | Pausen zu lang für die Einstellung | `--silence-ms 1200` oder `--until-enter` (Enter beendet) |
|
||
| Text kommt erst sehr spät | Pausenerkennung sehr lang eingestellt oder CPU-Betrieb | `--silence-ms` verringern; GPU nutzen |
|
||
| Wörter/Namen falsch | Aussprache, unbekannte Namen | `--prompt` mit Namen; größeres Modell; deutlicher sprechen |
|
||
| „Untertitel im Auftrag des ZDF“ o. Ä. | Whisper-Halluzination bei Stille | wird normalerweise gefiltert; tritt es trotzdem auf, bitte Beispiel melden |
|
||
| Wiederholte gleiche Sätze fehlen teilweise | Whisper fasst wörtliche Wiederholungen zusammen | bekannte Grenze; bei natürlicher Sprache selten |
|
||
| `Warteschlange voll` / HTTP 503 | zu viele Aufträge gleichzeitig | kurz warten; `STT_MAX_QUEUE` erhöhen |
|
||
| `Address already in use` beim Start | Port 9998/10300 belegt (zweiter Dienst läuft) | anderen Dienst beenden (`systemctl --user stop stt-service`) |
|
||
| Home Assistant findet den Dienst nicht | Firewall, falsche IP, Dienst aus | `curl http://<IP>:9998/health` vom HA-Rechner; [Abschnitt 8](#8-andere-geräte-im-netzwerk) |
|
||
| `LLM: Fehler, Rohtext behalten — ConnectionError` | Ollama läuft nicht / falsche `--llm-url` | `systemctl status ollama`; `curl http://127.0.0.1:11434/api/version` |
|
||
| `LLM: verworfen, Rohtext behalten` | LLM-Antwort wich zu stark ab | gewollte Sicherung; bei Bedarf anderes Modell probieren |
|
||
| LLM-Korrektur dauert beim ersten Mal ~1 Minute | Modell wird geladen | normal; danach ~1 s pro Text |
|
||
| LLM-Korrektur dauert immer mehrere Sekunden | Modell läuft auf der CPU (zu großer Kontext/kein GPU-Speicher) | `ollama ps` prüfen: `PROCESSOR` sollte `100% GPU` zeigen |
|
||
| `Warnung: … Audioblöcke verworfen` | Netzwerk/Dienst zu langsam für das Mikrofon | Verbindung prüfen; lokal testen |
|
||
|
||
**Log ansehen:** manuell gestartet → im Terminal; als systemd-Dienst →
|
||
`journalctl --user -u stt-service -n 100`. Mehr Details mit `STT_LOG_LEVEL=DEBUG`.
|
||
|
||
---
|
||
|
||
## 13. Datenschutz
|
||
|
||
- Die gesamte Spracherkennung läuft **lokal**. Audio und Text verlassen den Rechner nicht.
|
||
- Internetzugriff nur beim **ersten Herunterladen** eines Modells (Hugging Face).
|
||
- Die optionale LLM-Korrektur nutzt ein **lokales** LLM (Ollama). Nur wer `--llm-url` auf einen fremden
|
||
Server setzt, schickt Text dorthin.
|
||
- Der Dienst **speichert keine Aufnahmen** und keine Texte auf der Festplatte.
|
||
- **Ausnahme Log:** Bei Home-Assistant-Anfragen (Wyoming) wird der erkannte Text im Log protokolliert
|
||
(Stufe `INFO`). Wer das nicht möchte: `STT_LOG_LEVEL=WARNING`.
|
||
- Der Dienst hat keine Zugangskontrolle → nur im eigenen Netz betreiben ([Abschnitt 8](#8-andere-geräte-im-netzwerk)).
|
||
|
||
---
|
||
|
||
## 14. Deinstallation
|
||
|
||
```bash
|
||
systemctl --user disable --now stt-service 2>/dev/null
|
||
rm -f ~/.config/systemd/user/stt-service.service && systemctl --user daemon-reload
|
||
rm -rf ~/Python_Programs/SpeechToText
|
||
```
|
||
|
||
Heruntergeladene Modelle liegen im Hugging-Face-Cache (`$HF_HOME/hub` bzw. `~/.cache/huggingface/hub`,
|
||
Ordner `models--*faster-whisper*`) und werden eventuell auch von anderen Programmen genutzt — nur löschen,
|
||
wenn sicher ist, dass sie nicht mehr gebraucht werden.
|