From cb7022a298cc69dd8c9424fbe25073921a6285f9 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Mon, 14 Sep 2026 01:02:21 +0200 Subject: [PATCH] =?UTF-8?q?Dokumentation=20aktualisiert,=20CHANGELOG=20erg?= =?UTF-8?q?=C3=A4nzt,=20Version=200.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- BEDIENUNGSANLEITUNG.md | 16 ++++++++++++++-- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ CLAUDE.md | 6 +++--- README.md | 5 ++++- docs/API.md | 2 +- docs/ENTWICKLER.md | 23 +++++++++++++++++++---- stt_core.py | 2 +- 7 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 CHANGELOG.md diff --git a/BEDIENUNGSANLEITUNG.md b/BEDIENUNGSANLEITUNG.md index f5ede0c..67ade7f 100644 --- a/BEDIENUNGSANLEITUNG.md +++ b/BEDIENUNGSANLEITUNG.md @@ -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
Whisper-Modell auf GPU] SVC --> TXT[Text] + CLI -. "optional: llm-correct" .-> LLM[Ollama
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`). diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f4bf12c --- /dev/null +++ b/CHANGELOG.md @@ -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`. diff --git a/CLAUDE.md b/CLAUDE.md index c231686..4e99098 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 diff --git a/README.md b/README.md index e9cc44c..6733e61 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/API.md b/docs/API.md index 1c4f80e..6edfbfd 100644 --- a/docs/API.md +++ b/docs/API.md @@ -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" } ``` diff --git a/docs/ENTWICKLER.md b/docs/ENTWICKLER.md index 590e77a..ee7a09b 100644 --- a/docs/ENTWICKLER.md +++ b/docs/ENTWICKLER.md @@ -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). diff --git a/stt_core.py b/stt_core.py index 2d9b60f..228bcfd 100644 --- a/stt_core.py +++ b/stt_core.py @@ -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