- 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>
3.5 KiB
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 mitcpu_model,_run_lockserialisiert Inferenz,condition_on_previous_text=False, Halluzinationsfilteris_hallucination), Audio-Hilfen (decode_audio_bytesvia PyAV für jedes Format,pcm16_to_floatmit Kanalwahl,StreamResamplervia soxr),UtteranceSegmenter(Streaming-Endpointing über 512-Sample-Fenster; Wahrscheinlichkeitsfunktion injizierbar, StandardSileroProb).stt_service.py—create_app(engine, settings, vad_config, prob_fn_factory)als Fabrik (Tests injizierenFakeEngine/EnergyProbaustests/conftest.py).TranscriptionWorker= ThreadPoolExecutor(1) + Zählerpending→Overloaded/503. Preload läuft als erster Worker-Job, ohne den Start zu blockieren._StreamSession= WebSocket-Protokoll (Empfangsschleife legt Äußerungen in eine Queue,_consumetranskribiert 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 perPOST /transcribe, Mikrofon per/ws/stream;--localnutzt den Kern direkt. stdout nur Transkripte, stderr Status. Default-Mikrofon über das ALSA-Gerätpulse(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.