Dokumentation aktualisiert, CHANGELOG ergänzt, Version 0.2.0
- CHANGELOG.md neu (0.1.0, 0.2.0) - Bedienungsanleitung: LLM-Korrektur in Überblick, Voraussetzungen, Installation, Deinstallation - Entwicklerdoku: Output-Klasse, STT_LLM_*-Konfiguration, Nebenläufigkeitsregel für Ausgaben, Erweitern (LLM/Prompt), Grenzen und nächste Schritte - README, CLAUDE.md: Verweise und Befehle ergänzt - stt_core.__version__ = 0.2.0 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
6ebea4b745
commit
cb7022a298
7 changed files with 76 additions and 12 deletions
|
|
@ -29,12 +29,14 @@ SpeechToText wandelt **gesprochene Sprache in Text** um — vollständig **lokal
|
|||
ohne Cloud. Grundlage ist das Spracherkennungsmodell *Whisper* in der schnellen Umsetzung
|
||||
*faster-whisper*.
|
||||
|
||||
Es besteht aus zwei Teilen:
|
||||
Es besteht aus zwei Teilen und einem optionalen Zusatz:
|
||||
|
||||
- **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.
|
||||
- **Optional der LLM-Korrektur** (`stt_llm.py`): lässt den erkannten Text auf Wunsch von einem lokalen
|
||||
Sprachmodell (Ollama) auf Erkennungsfehler prüfen — nur in der Kommandozeile mit `--llm-correct`.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
|
|
@ -44,6 +46,7 @@ flowchart LR
|
|||
ESP[ESP32 / Skripte / Apps] -- HTTP / WebSocket :9998 --> SVC
|
||||
CLI -- HTTP / WebSocket :9998 --> SVC[STT-Dienst<br/>Whisper-Modell auf GPU]
|
||||
SVC --> TXT[Text]
|
||||
CLI -. "optional: llm-correct" .-> LLM[Ollama<br/>gemma4:12b] -.-> TXT
|
||||
```
|
||||
|
||||
**Wie schnell?** Auf einer RTX 3090 mit dem Modell `large-v3-turbo`: ein Satz von 6 Sekunden ist in
|
||||
|
|
@ -65,6 +68,7 @@ nach Sprache). Ein Stoppwort ist nicht nötig.
|
|||
| 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 |
|
||||
| Nur für LLM-Korrektur | Ollama + Modell `gemma4:12b` (7,6 GB Festplatte) | ~10 GB freier Grafikspeicher |
|
||||
|
||||
Systemprogramme: `ffmpeg` ist hilfreich (Formatumwandlung), `pactl` (PipeWire/PulseAudio) für die
|
||||
Mikrofonwahl, `espeak-ng` nur für die automatischen Tests.
|
||||
|
|
@ -92,6 +96,13 @@ mit. Ohne vorhandene Installation lädt `pip` alles herunter.
|
|||
# … 49 passed
|
||||
```
|
||||
|
||||
**Optional für die LLM-Korrektur** (`--llm-correct`): [Ollama](https://ollama.com) installieren und das
|
||||
Modell holen:
|
||||
|
||||
```bash
|
||||
ollama pull gemma4:12b
|
||||
```
|
||||
|
||||
> Beim **ersten Start des Dienstes** wird das Whisper-Modell aus dem Internet geladen
|
||||
> (`large-v3-turbo` ≈ 1,6 GB). Danach arbeitet alles offline.
|
||||
|
||||
|
|
@ -502,4 +513,5 @@ 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.
|
||||
wenn sicher ist, dass sie nicht mehr gebraucht werden. Dasselbe gilt für das LLM der optionalen Korrektur
|
||||
(`ollama rm gemma4:12b`).
|
||||
|
|
|
|||
34
CHANGELOG.md
Normal file
34
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Änderungsprotokoll
|
||||
|
||||
Alle nennenswerten Änderungen an SpeechToText. Versionsnummer: `stt_core.__version__`
|
||||
(erscheint in `/health`, in der FastAPI-Doku und im Wyoming-`info`).
|
||||
|
||||
## 0.2.0 — 2026-09-14
|
||||
|
||||
### Neu
|
||||
- **CLI `--until-enter`:** Aufnahme mit beliebig langen Pausen; Enter beendet, der gesamte Text wird als
|
||||
ein Ergebnis ausgegeben. Funktioniert mit dem Dienst und mit `--local`.
|
||||
- **Optionale LLM-Nachkorrektur** (`stt_llm.py`, CLI `--llm-correct`, `--llm-model`, `--llm-url`):
|
||||
korrigiert offensichtliche Erkennungsfehler mit einem lokalen LLM (Standard `gemma4:12b` über Ollama,
|
||||
OpenAI-kompatible Server möglich). Strenger Prompt, Ähnlichkeitsprüfung und Fehler-Fallback auf den
|
||||
Rohtext; `--json` liefert `raw_text` und Korrekturdetails. Standardmäßig aus.
|
||||
- Umgebungsvariablen `STT_LLM_*` für die LLM-Korrektur.
|
||||
- Umfassende Dokumentation: `BEDIENUNGSANLEITUNG.md`, `docs/API.md`, `docs/ENTWICKLER.md`, dieses Änderungsprotokoll.
|
||||
|
||||
### Geändert
|
||||
- Ungültige Kombinationen von CLI-Optionen enden mit Exit-Code 1 (Fehler) statt 2.
|
||||
- Die alten Einzelskripte `stt.py` und `stt_respeaker.py` liegen jetzt in `legacy/`.
|
||||
|
||||
## 0.1.0 — 2026-09-13
|
||||
|
||||
Erste Version als Dienst — Neuentwurf des alten Einzelskripts `stt.py`.
|
||||
|
||||
- `stt_core.py`: Whisper-Engine (faster-whisper) mit einmaligem Laden, GPU→CPU-Fallback,
|
||||
Dekodierung beliebiger Audioformate, Halluzinationsfilter, Äußerungserkennung per Silero-VAD.
|
||||
- `stt_service.py`: FastAPI-Dienst mit `/health`, `/v1/audio/transcriptions` (OpenAI-kompatibel),
|
||||
`/transcribe` (Rohdaten) und `WS /ws/stream` (Live-Streaming); Inferenz in einem Worker-Thread,
|
||||
begrenzte Warteschlange (HTTP 503).
|
||||
- `stt_wyoming.py`: Wyoming-Protokoll für Home Assistant (TCP 10300).
|
||||
- `stt_cli.py`: Dateien und Mikrofon über den Dienst oder lokal; Standardmikrofon über PipeWire,
|
||||
ReSpeaker XVF3800 automatisch mit ASR-Kanal.
|
||||
- Tests (Unit und Integration), systemd-User-Unit `deploy/stt-service.service`.
|
||||
|
|
@ -17,17 +17,17 @@ Git-Remote auf kitux.de (Forgejo) geplant, noch nicht eingerichtet.
|
|||
`README.md` (Überblick) · `BEDIENUNGSANLEITUNG.md` (Anwender, vollständige Tabelle der `STT_*`-Variablen) ·
|
||||
`docs/API.md` (HTTP/WebSocket/Wyoming-Protokoll) · `docs/ENTWICKLER.md` (Architektur, Nebenläufigkeitsregeln,
|
||||
Tests, Erweitern). Bei Änderungen an Schnittstellen, Optionen oder Umgebungsvariablen die betroffenen Dokumente
|
||||
mitpflegen.
|
||||
mitpflegen; bei neuer Version `stt_core.__version__` erhöhen und `CHANGELOG.md` ergänzen.
|
||||
|
||||
## Befehle
|
||||
|
||||
```bash
|
||||
.venv/bin/python -m pytest # Unit-Tests, ohne Modell/LLM (~9 s)
|
||||
.venv/bin/python -m pytest -m integration # echtes Whisper small/CPU + Silero, espeak-ng-Sprache (~20 s)
|
||||
.venv/bin/python -m pytest -m integration # echtes Whisper small/CPU + Silero (~20 s), LLM über Ollama (bis ~75 s)
|
||||
.venv/bin/python -m pytest tests/test_service.py::test_ws_stream_with_vad_emits_transcripts_per_utterance
|
||||
|
||||
CUDA_VISIBLE_DEVICES=GPU-83ba6d1f-ebbe-f8c8-1433-153e0ebc3866 .venv/bin/python stt_service.py # Port 9998, Wyoming 10300
|
||||
.venv/bin/python stt_cli.py datei.wav | --once | --local --model small datei.wav
|
||||
.venv/bin/python stt_cli.py datei.wav | --once | --until-enter [--llm-correct] | --local --model small datei.wav
|
||||
```
|
||||
|
||||
`.venv` ist mit `--system-site-packages` auf miniforge-Base angelegt (faster-whisper, fastapi, onnxruntime kommen
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ Gedacht als Baustein für Sprachassistenten und Smarthome: **Home Assistant** (W
|
|||
|---|---|---|
|
||||
| **[BEDIENUNGSANLEITUNG.md](BEDIENUNGSANLEITUNG.md)** | Anwender | Installation, Starten, CLI, Mikrofon, Home Assistant, Einstellungen, Fehlerbehebung |
|
||||
| **[docs/API.md](docs/API.md)** | Client-Entwickler | HTTP, WebSocket-Protokoll, Wyoming, Fehlercodes, Beispiele (Python, curl, ESP32) |
|
||||
| **[docs/ENTWICKLER.md](docs/ENTWICKLER.md)** | Programmierer am Projekt | Architektur, Module, Nebenläufigkeit, Tests, Erweitern, Designentscheidungen |
|
||||
| **[docs/ENTWICKLER.md](docs/ENTWICKLER.md)** | Programmierer am Projekt | Architektur, Module, Nebenläufigkeit, LLM-Korrektur, Tests, Erweitern, Designentscheidungen |
|
||||
| **[CHANGELOG.md](CHANGELOG.md)** | alle | Änderungen je Version (aktuell 0.2.0) |
|
||||
|
||||
## Schnellstart
|
||||
|
||||
|
|
@ -38,6 +39,7 @@ curl http://127.0.0.1:9998/health # "status":"ok" = bereit
|
|||
.venv/bin/python stt_cli.py aufnahme.wav # Datei → Text
|
||||
.venv/bin/python stt_cli.py -v # Mikrofon → Text (Strg+C beendet)
|
||||
.venv/bin/python stt_cli.py --until-enter # Pausen erlaubt, Enter beendet → ein Text
|
||||
.venv/bin/python stt_cli.py --until-enter --llm-correct # zusätzlich per lokalem LLM korrigieren (Ollama)
|
||||
```
|
||||
|
||||
Beim ersten Start wird das Modell geladen (`large-v3-turbo` ≈ 1,6 GB). Schnittstellen zum Ausprobieren
|
||||
|
|
@ -86,6 +88,7 @@ curl -F file=@aufnahme.mp3 http://127.0.0.1:9998/v1/audio/transcriptions
|
|||
(bei natürlicher Sprache selten).
|
||||
- Keine Zwischenergebnisse während des Sprechens — Text kommt pro Äußerung.
|
||||
- Keine Authentifizierung und kein TLS.
|
||||
- LLM-Korrektur nur in der CLI; kostet ~1 s pro Text, das erste Laden des LLM rund eine Minute.
|
||||
|
||||
## Lizenz und Autor
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ curl http://127.0.0.1:9998/health
|
|||
"load_seconds": 2.34,
|
||||
"wyoming_port": 10300,
|
||||
"error": null,
|
||||
"version": "0.1.0"
|
||||
"version": "0.2.0"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ Für Programmierer, die den Code verstehen, ändern oder erweitern wollen. Anwen
|
|||
| **Zuverlässig** | GPU→CPU-Fallback beim Laden; Halluzinationsfilter; robustes Dekodieren beliebiger Formate; Fehler einzelner Anfragen beenden keine Verbindung |
|
||||
| **Vielseitig anbindbar** | eine Engine, mehrere Schnittstellen: OpenAI-HTTP, Roh-HTTP, WebSocket, Wyoming, CLI |
|
||||
| **Testbar** | reine Logik ohne I/O im Kern; App-Fabrik mit injizierbarer Engine und VAD |
|
||||
| **Zusätze getrennt halten** | LLM-Korrektur nur optional in der CLI; Kern, Dienst und Wyoming bleiben davon unberührt |
|
||||
| **Gegenstück zu chatterbox-tts-cli** | gleiche Bauart: Kernmodul + FastAPI-Dienst + CLI + systemd-User-Unit |
|
||||
|
||||
Das Projekt ersetzt das alte Einzelskript `legacy/stt.py`. Dessen Schwächen — Stoppwort-Erkennung in
|
||||
|
|
@ -345,6 +346,7 @@ Port `0` ist in Tests erlaubt (freien Port über `server._server.sockets[0]` erm
|
|||
| Funktion | Aufgabe |
|
||||
|---|---|
|
||||
| `main` | Argumente, Modus-Auswahl, Fehler → Exit-Code, Hinweis bei nicht erreichbarem Dienst |
|
||||
| `Output` | einzige Ausgabestelle: `put()` gibt direkt aus oder reicht an die LLM-Korrektur (eigener Thread, Reihenfolge bleibt); `warmup()` lädt das LLM vorab; `close()` wartet auf ausstehende Korrekturen |
|
||||
| `service_file` | `POST /transcribe` mit Datei als Body (Streaming-Upload über `requests`) |
|
||||
| `service_mic` | Mikrofon → `/ws/stream` (synchroner `websockets`-Client, Empfänger-Thread) |
|
||||
| `local_files` / `local_mic` | wie oben, aber `SttEngine` + `UtteranceSegmenter` im Prozess; Inferenz im `ThreadPoolExecutor(1)` |
|
||||
|
|
@ -364,8 +366,6 @@ ReSpeaker-Erkennung (→ Kanal 1).
|
|||
**Ausgabevertrag:** stdout nur Ergebnisse (Text oder JSON-Zeile), stderr alles andere.
|
||||
Exit-Codes `0/1/2/130` (siehe Bedienungsanleitung).
|
||||
|
||||
---
|
||||
|
||||
### LLM-Nachkorrektur (`stt_llm.py`)
|
||||
|
||||
Optionaler Zusatz, bewusst **außerhalb** von Kern und Dienst: Smarthome-, ESP32- und Wyoming-Pfade bleiben
|
||||
|
|
@ -414,6 +414,8 @@ Prompt mit Tags und Beispielen):
|
|||
|
||||
Das erste Laden eines Modells dauert 35–75 s; `Output.warmup()` stößt es im Mikrofon-Modus sofort an.
|
||||
|
||||
---
|
||||
|
||||
## 8. Nebenläufigkeit — die wichtigsten Regeln
|
||||
|
||||
1. **Nie** `engine.transcribe` (oder anderes Blockierendes) direkt in einer `async`-Funktion aufrufen —
|
||||
|
|
@ -423,7 +425,9 @@ Das erste Laden eines Modells dauert 35–75 s; `Output.warmup()` stößt es im
|
|||
4. `SttEngine` ist thread-sicher (`_load_lock`, `_run_lock`), aber der Dienst verlässt sich zusätzlich
|
||||
auf den Ein-Thread-Worker für die Warteschlangenlogik.
|
||||
5. `UtteranceSegmenter` und `StreamResampler` sind **nicht** thread-sicher — eine Instanz pro Stream.
|
||||
6. Silero-VAD läuft im Event-Loop (gemessen ≈ 0,4 ms Rechenzeit pro 100 ms Audio). Bei sehr vielen gleichzeitigen
|
||||
6. In der CLI nur über `Output.put` ausgeben — nie `print` aus Empfänger- oder Callback-Threads, sonst
|
||||
geraten LLM-korrigierte und direkte Ausgaben durcheinander.
|
||||
7. Silero-VAD läuft im Event-Loop (gemessen ≈ 0,4 ms Rechenzeit pro 100 ms Audio). Bei sehr vielen gleichzeitigen
|
||||
Streams wäre das der erste Kandidat für einen eigenen Thread.
|
||||
|
||||
---
|
||||
|
|
@ -439,6 +443,7 @@ Stellen:
|
|||
| `stt_core.EngineConfig.from_env` | `STT_MODEL`, `STT_DEVICE`, `STT_COMPUTE_TYPE`, `STT_DEVICE_INDEX`, `STT_CPU_MODEL`, `STT_CPU_THREADS`, `STT_LANGUAGE`, `STT_BEAM_SIZE`, `STT_INITIAL_PROMPT`, `STT_DOWNLOAD_ROOT` |
|
||||
| `stt_core.VadConfig.from_env` | `STT_VAD_THRESHOLD`, `STT_VAD_MIN_SPEECH_MS`, `STT_VAD_SILENCE_MS`, `STT_VAD_PRE_ROLL_MS`, `STT_VAD_MAX_UTTERANCE_S` |
|
||||
| `stt_service.ServiceSettings.from_env` | `STT_MAX_QUEUE`, `STT_MAX_UPLOAD_MB`, `STT_PRELOAD`, `STT_WYOMING_HOST`, `STT_WYOMING_PORT` |
|
||||
| `stt_llm.LlmConfig.from_env` | `STT_LLM_URL`, `STT_LLM_MODEL`, `STT_LLM_API`, `STT_LLM_TIMEOUT`, `STT_LLM_KEEP_ALIVE`, `STT_LLM_NUM_CTX`, `STT_LLM_MIN_SIMILARITY` |
|
||||
|
||||
Außerdem direkt: `STT_LOG_LEVEL`, `STT_HOST`, `STT_PORT` (`stt_service.py`), `STT_URL` (`stt_cli.py`).
|
||||
Hilfsfunktion `stt_core._env(name, default, cast)`: leere Werte gelten als „nicht gesetzt“,
|
||||
|
|
@ -546,10 +551,17 @@ Parametrisierung in `test_hallucinations_are_detected` **und** ein Gegenbeispiel
|
|||
**Andere Engine** (z. B. anderes STT-Backend) — Unterklasse von `SttEngine`, die `load` und `transcribe`
|
||||
überschreibt und ein `Transcript` liefert (`FakeEngine` zeigt das minimale Muster).
|
||||
|
||||
**Anderes LLM oder Prompt anpassen** — Modell/Server nur per `STT_LLM_MODEL`/`STT_LLM_URL` wechseln. Vor
|
||||
einem neuen Standardmodell den Vergleich wiederholen (Fälle wie in §7 „LLM-Nachkorrektur“: echte
|
||||
Whisper-Fehler, korrekte Sätze inkl. Befehle mit Verneinung/Zahlen, eine „Anweisung“ im Diktat). Prompt-
|
||||
Änderungen in `SYSTEM_PROMPT`/`FEW_SHOT`, danach `pytest -m integration tests/test_llm.py`. Neue
|
||||
Ablehnungsregeln gehören in `_accept` und brauchen einen Test mit `ScriptedCorrector`.
|
||||
|
||||
**Neuer Client** — gegen [docs/API.md](API.md) programmieren; `stt_cli.py` ist die Referenzimplementierung
|
||||
für Datei-Upload und WebSocket-Streaming.
|
||||
|
||||
**Version erhöhen** — `stt_core.__version__` (wird von `/health`, FastAPI und Wyoming übernommen).
|
||||
**Version erhöhen** — `stt_core.__version__` (wird von `/health`, FastAPI und Wyoming übernommen),
|
||||
Beispiel in `docs/API.md` (`/health`) anpassen und Eintrag in `CHANGELOG.md` ergänzen.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -582,6 +594,8 @@ für Datei-Upload und WebSocket-Streaming.
|
|||
- Keine Authentifizierung, kein TLS.
|
||||
- Ein Modell pro Dienstinstanz; Modellwechsel = Neustart.
|
||||
- Wyoming protokolliert Transkripttexte auf `INFO`.
|
||||
- LLM-Korrektur: ~1 s pro Text, erstes Laden 35–75 s, ~10 GB Grafikspeicher; stark verstümmelte Sätze
|
||||
werden oft nicht sinnvoll repariert. Nur in der CLI verfügbar.
|
||||
- Die Mikrofonpfade der CLI sind mit synthetischer Sprache und Pegelmessung getestet, der WebSocket-Pfad
|
||||
mit echter Sprache in Echtzeit-Simulation — nicht automatisiert mit echtem Mikrofon.
|
||||
|
||||
|
|
@ -590,6 +604,7 @@ für Datei-Upload und WebSocket-Streaming.
|
|||
- Optionales Bearer-Token (`STT_API_TOKEN`) für HTTP/WebSocket.
|
||||
- Metriken (`/metrics` im Prometheus-Format: Latenzen, Queue, Fehler).
|
||||
- Zwischenergebnisse (partielle Transkripte) während langer Äußerungen.
|
||||
- LLM-Korrektur optional auch im Dienst anbieten (z. B. `/transcribe?correct=true`), weiterhin standardmäßig aus.
|
||||
- MCP-Adapter analog zu chatterbox-tts-cli (`mcp_adapter.py`).
|
||||
- Remote-Repository auf kitux.de (Forgejo).
|
||||
- Anbindung als STT-Provider im Voice-Assistant v3 (OpenAI-kompatibel bereits möglich).
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import numpy as np
|
|||
|
||||
log = logging.getLogger("stt")
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__version__ = "0.2.0"
|
||||
|
||||
SAMPLE_RATE = 16000 # Whisper arbeitet intern mit 16 kHz mono float32
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue