whisper-stt-cli/CLAUDE.md
dschlueter 6ebea4b745 CLI: --until-enter und optionale LLM-Korrektur (--llm-correct)
- --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>
2026-09-14 00:48:02 +02:00

64 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
> Sprache: Code-Kommentare, Doku und Commits auf Deutsch.
## Projektziel
Lokale, schnelle, zuverlässige Spracherkennung, nicht blockierend. Baustein für Smarthome
(Home Assistant via Wyoming, ESP32/Arduino als Audio-Clients) und **STT-Pendant zu `chatterbox-tts-cli`**
(`~/chatterbox-tts-cli`: CLI-Kern + FastAPI-Service + MCP-Adapter + systemd-User-Service, Port 9999).
Bewährtes STT-Vorbild: `~/my_voice_assistant_v3` (`app/providers/stt/faster_whisper.py`, `app/api/ws.py`).
Git-Remote auf kitux.de (Forgejo) geplant, noch nicht eingerichtet.
## Dokumentation
`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.
## 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 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` ist mit `--system-site-packages` auf miniforge-Base angelegt (faster-whisper, fastapi, onnxruntime kommen
von dort); nur `wyoming` ist in der venv installiert. Tests immer mit `.venv/bin/python`, sonst fehlt `wyoming`.
## Architektur
- `stt_core.py` — reine Logik, kein print/sys.exit. `SttEngine` (Modell einmal laden, Lade-Versuche cuda→cpu mit
`cpu_model`, `_run_lock` serialisiert Inferenz, `condition_on_previous_text=False`, Halluzinationsfilter
`is_hallucination`), Audio-Hilfen (`decode_audio_bytes` via PyAV für jedes Format, `pcm16_to_float` mit
Kanalwahl, `StreamResampler` via soxr), `UtteranceSegmenter` (Streaming-Endpointing über 512-Sample-Fenster;
Wahrscheinlichkeitsfunktion injizierbar, Standard `SileroProb`).
- `stt_service.py` — `create_app(engine, settings, vad_config, prob_fn_factory)` als Fabrik (Tests injizieren
`FakeEngine`/`EnergyProb` aus `tests/conftest.py`). `TranscriptionWorker` = ThreadPoolExecutor(1) + Zähler
`pending` → `Overloaded`/503. Preload läuft als erster Worker-Job, ohne den Start zu blockieren.
`_StreamSession` = WebSocket-Protokoll (Empfangsschleife legt Äußerungen in eine Queue, `_consume` transkribiert
der Reihe nach; `send_lock`, weil zwei Tasks senden).
- `stt_wyoming.py` — Wyoming-Handler im selben Prozess/Worker; nimmt HA-Audio komplett an (externe VAD),
`transcript_names/terms` → Whisper-`hotwords`; Verbindung wird nach dem Transkript geschlossen (HA-Konvention).
- `stt_cli.py` — Client: Dateien per `POST /transcribe`, Mikrofon per `/ws/stream`; `--local` nutzt den Kern direkt.
stdout nur Transkripte, stderr Status. Default-Mikrofon über das ALSA-Gerät `pulse` (PortAudios Default ist hier
die falsche Onboard-Karte); ReSpeaker XVF3800 → automatisch Kanal 1 (ASR-Ausgang).
- `stt_llm.py` — optionale LLM-Nachkorrektur, nur über `Output` in `stt_cli.py` (`--llm-correct`); Kern und Dienst kennen
sie nicht. Ollama nativ (`num_ctx`/`keep_alive`/`think:false` pro Anfrage, weil Ollama global 131k Kontext hat) oder
OpenAI-kompatibel; `_accept` verwirft Antworten mit Ähnlichkeit < 0,75 oder ±30 % Länge → Rohtext.
- `legacy/stt.py`, `legacy/stt_respeaker.py` — **historische** Einzelskripte, nicht weiterentwickeln.
Sprache: `language=None` → Config-Default, `"auto"` → Erkennung, `"de-DE"` → `"de"` (`SttEngine.resolve_language`).
## Umgebung
GPUs: T600 + 2× RTX 3090. `nvidia-smi` zählt in PCI-Reihenfolge, CUDA „fastest first“ → GPU immer per
`CUDA_VISIBLE_DEVICES=GPU-<uuid>` pinnen. GPU 1 belegt llama.cpp/ollama fast komplett; der Dienst läuft auf GPU 2
(`large-v3-turbo` ≈ 2,4 GB) neben chatterbox-tts und open-notebook-stt (:8902). HF-Modelle unter `$HF_HOME`.