whisper-stt-cli/CLAUDE.md
dschlueter a986cbe42a STT-Dienst: Kern, HTTP/WebSocket/Wyoming-Service, CLI, Tests, systemd-Unit
- stt_core.py: Whisper-Engine (einmal laden, CPU-Fallback), Audio-Dekodierung
  jedes Formats, Halluzinationsfilter, Äußerungserkennung per Silero-VAD
- stt_service.py: /health, /v1/audio/transcriptions (OpenAI), /transcribe (Rohdaten),
  WS /ws/stream; Inferenz im Worker-Thread, begrenzte Warteschlange (503)
- stt_wyoming.py: Home-Assistant-Anbindung (TCP 10300)
- stt_cli.py: Datei/Mikrofon über den Dienst oder lokal
- Tests (Unit + Integration), README, requirements.txt, deploy/stt-service.service

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 21:34:03 +02:00

3.5 KiB
Raw Blame History

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.

Befehle

.venv/bin/python -m pytest                          # Unit-Tests, ohne Modell (~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.py, 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.