2026-06-17 01:48:56 +02:00
|
|
|
# Port bei Bedarf anpassen
|
|
|
|
|
APP_ENV=dev
|
|
|
|
|
HOST=0.0.0.0
|
|
|
|
|
PORT=8080
|
|
|
|
|
LOG_LEVEL=info
|
|
|
|
|
|
|
|
|
|
# Secret nur ueber die Umgebung setzen (nicht hier eintragen), z. B. export in ~/.bashrc
|
|
|
|
|
OPENROUTER_API_KEY=
|
|
|
|
|
|
2026-06-17 18:07:36 +02:00
|
|
|
# Satzweises Vorlesen (Audio-Streaming) als Default fuer WebSocket-Turns.
|
|
|
|
|
# false = Antwort erst komplett synthetisieren, dann abspielen.
|
|
|
|
|
AUDIO_STREAM_DEFAULT=true
|
|
|
|
|
|
feat(tts): Aussprache-Normalisierung vor Piper (Ordinalia/Einheiten/Abk./Lexikon)
In-Process-Layer ausgebaut statt neuer Lib/CLI. Leitprinzip: nicht duplizieren,
was espeak-ng schon kann (Kardinal-/Dezimalzahlen bleiben unangetastet) -- nur die
belegten Luecken fuellen.
- german_numbers.py: deutsche Ordinalzahlen 1.-31. (attributiv/adverbial)
- tts_normalizer.py: Ordinalia (Datum '1. Mai'->'erster Mai', Folgen '1. 2. 3.'->
'erstens, zweitens, ...'), Einheiten nach Zahl (kg/km/km-h/...), Abkuerzungen
(Dr./z.B./usw.), optionales YAML-Lexikon (config/pronunciation.<lang>.yaml).
Provider-abhaengige Stufen auto|full|light|off (TTS_NORMALIZE_LEVEL): piper=full,
Cloud=light (laesst Zahlen/Abk. fuer das Cloud-Modell in Ruhe).
- spoken_response_adapter.py: nummerierte Listen -> Ordinalwoerter statt Loeschen.
- sentence_chunker.py: trennt nicht mehr nach Ziffer+Punkt, Einzelbuchstabe+Punkt
('z. B.', Initialen) oder bekannten Abkuerzungen -> behebt das Streaming-Symptom
('1.' wurde als eigener 'Satz' zu 'eins').
- orchestrator/dependencies: normalize_level durchgereicht (auto: piper->full).
- Tests: tests/test_tts_normalizer.py + Chunker-Faelle (85 gruen).
- Doku: BEDIENUNGSANLEITUNG (Aussprache verbessern), .env.example.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 23:01:41 +02:00
|
|
|
# Text-Normalisierung vor dem TTS (Aussprache): auto|full|light|off.
|
|
|
|
|
# auto = piper bekommt 'full' (Ordinalia/Einheiten/Abk./Lexikon), Cloud-TTS 'light'
|
|
|
|
|
# (nur Glaettung; Cloud spricht Zahlen/Abkuerzungen selbst gut). Lexikon:
|
|
|
|
|
# config/pronunciation.de.yaml (erweitert die eingebauten Defaults).
|
|
|
|
|
TTS_NORMALIZE_LEVEL=auto
|
|
|
|
|
|
2026-06-17 02:14:25 +02:00
|
|
|
# --- Authentifizierung -----------------------------------------------------
|
|
|
|
|
# AUTH_ENABLED=true (Standard) schuetzt chat/speak/transcribe/sessions per Bearer-Token.
|
|
|
|
|
# Fuer lokale Entwicklung/Tests auf false setzen (dann gilt ein anonymer Nutzer).
|
|
|
|
|
AUTH_ENABLED=true
|
|
|
|
|
# Schluessel fuer die Nutzerverwaltung (POST /api/admin/users). Nur ueber die Umgebung.
|
|
|
|
|
ADMIN_API_KEY=
|
|
|
|
|
|
2026-06-18 08:44:33 +02:00
|
|
|
# Forward-Auth via Reverse-Proxy/SSO (z. B. YunoHost). Nur fuer Remote-Betrieb -
|
|
|
|
|
# siehe deploy/README.md. Lokal leer lassen. Identitaet per Header ODER Cookie:
|
|
|
|
|
# TRUSTED_AUTH_HEADER=X-Remote-User # falls der Proxy einen Header setzt
|
|
|
|
|
# TRUSTED_AUTH_COOKIE=yunohost.portal # YunoHost: Username im JWT-Cookie
|
|
|
|
|
# TRUSTED_AUTH_COOKIE_CLAIM=user
|
|
|
|
|
# TRUSTED_AUTH_JWT_SECRET= # optional: HS256-Signatur pruefen
|
feat(web): Remote-Web-UI mit Mikrofon + Forward-Auth (YunoHost-SSO)
- Minimale Web-UI (app/web/, vanilla, same-origin -> kein CORS): Text-Prompt +
Mikrofon-Button (Aufnahme im Browser -> /ws/voice -> Antwort wird vorgelesen),
Token-Streaming, PCM-Wiedergabe, Identitaet/Logout/Admin im Menue
- Forward-/Trusted-Header-Auth (app/auth.py): Identitaet aus SSO-Header, nur von
TRUSTED_PROXY_IPS akzeptiert; sonst Token/Anonymous-Fallback. Auto-Provisioning
via store.get_or_create_user_by_external_id (+ external_id-Spalte/Migration)
- /api/me um is_admin + sso_logout_url erweitert; GET /api/admin/users (Liste) und
GET /api/admin/request-headers (SSO-Header-Discovery), Admin-gated
- StaticFiles-Mount; Config: TRUSTED_AUTH_HEADER/_PROXY_IPS, ADMIN_USERS, SSO_LOGOUT_URL
- WS-Auth liest Identitaet aus dem Handshake-Header
- Deploy: nginx-Vorlage (WS-Upgrade!) + deploy/README.md (HTTPS/SSO/Firewall/Discovery)
- Tests: Forward-Auth (Provisioning, Admin-Flag, Proxy-IP-Trust, 401/403, Static)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 04:37:16 +02:00
|
|
|
# TRUSTED_PROXY_IPS=192.168.0.10
|
|
|
|
|
# ADMIN_USERS=atoor,dieterschlueter,dschlueter
|
|
|
|
|
# SSO_LOGOUT_URL=https://linix.de/yunohost/sso/?action=logout
|
|
|
|
|
|
2026-06-17 01:48:56 +02:00
|
|
|
# --- Zentrale Konfiguration / Profile -------------------------------------
|
|
|
|
|
# Aktives Profil aus config/voice-assistant.toml waehlen: local-dev | hybrid | cloud
|
|
|
|
|
# (leer lassen = nur Defaults/ENV). Eigener Pfad via VA_CONFIG_FILE.
|
|
|
|
|
VA_PROFILE=
|
|
|
|
|
# VA_CONFIG_FILE=config/voice-assistant.toml
|
|
|
|
|
|
|
|
|
|
# Hinweis zur Praezedenz: ENV gewinnt ueber die TOML-Datei. Die DEFAULT_*_PROVIDER-
|
|
|
|
|
# Zeilen unten ueberschreiben daher ein gesetztes VA_PROFILE. Wer profilbasiert
|
|
|
|
|
# umschalten will, sollte sie auskommentiert lassen.
|
|
|
|
|
OPENROUTER_STT_MODEL=openai/whisper-large-v3
|
2026-06-17 23:36:13 +02:00
|
|
|
# Stimme haengt vom Modell ab (Gemini: Zephyr/Puck/Kore/...; OpenAI: alloy/echo/nova/...).
|
|
|
|
|
# Stimmenliste + Umstellen pro Aufruf: siehe BEDIENUNGSANLEITUNG ("Stimme des Cloud-TTS").
|
2026-06-17 01:48:56 +02:00
|
|
|
OPENROUTER_TTS_MODEL=openai/gpt-4o-mini-tts
|
|
|
|
|
OPENROUTER_TTS_VOICE=alloy
|
|
|
|
|
OPENROUTER_LLM_MODEL=openai/gpt-4.1-mini
|
|
|
|
|
DEFAULT_LANGUAGE=de
|
|
|
|
|
DEFAULT_INPUT_ENDPOINT=local-default
|
|
|
|
|
DEFAULT_OUTPUT_ENDPOINT=local-default
|
|
|
|
|
# DEFAULT_STT_PROVIDER=openrouter
|
|
|
|
|
# DEFAULT_LLM_PROVIDER=local-openai-compatible
|
|
|
|
|
# DEFAULT_TTS_PROVIDER=openrouter
|
2026-06-18 02:57:57 +02:00
|
|
|
# Lokaler llama.cpp-Server (zentrale, unzensierte KI). Start: scripts/llm-server/start-llm-server.sh
|
|
|
|
|
# LOCAL_LLM_MODEL muss dem --alias des Servers entsprechen (Default: va_llm).
|
|
|
|
|
LOCAL_LLM_BASE_URL=http://127.0.0.1:8001/v1
|
2026-06-17 01:48:56 +02:00
|
|
|
LOCAL_LLM_API_KEY=dummy
|
2026-06-18 02:57:57 +02:00
|
|
|
LOCAL_LLM_MODEL=va_llm
|
|
|
|
|
# Tempo-Hebel fuer den Sprach-Loop: Reasoning aus + knappe, vorlesbare Antworten.
|
|
|
|
|
# LOCAL_LLM_DISABLE_REASONING=true # Qwen3-Denkphase abschalten (deutlich schneller)
|
|
|
|
|
# LOCAL_LLM_MAX_TOKENS=0 # 0 = serverseitiges Limit (-n); z. B. 256 kappt lange Antworten
|
|
|
|
|
# LOCAL_LLM_TEMPERATURE=0.3
|
|
|
|
|
# LOCAL_LLM_SYSTEM_PROMPT=Du bist ein gesprochener Sprachassistent. Antworte kurz ...
|
2026-06-17 05:19:07 +02:00
|
|
|
|
2026-06-17 11:28:20 +02:00
|
|
|
# --- Lokales STT (faster-whisper; nur mit pip install -e .[local] ) ---------
|
|
|
|
|
FASTER_WHISPER_MODEL=base # tiny|base|small|medium|large-v3
|
|
|
|
|
FASTER_WHISPER_DEVICE=auto # auto|cpu|cuda
|
|
|
|
|
FASTER_WHISPER_COMPUTE_TYPE=default # default|int8|float16|int8_float16
|
|
|
|
|
|
2026-06-17 22:11:20 +02:00
|
|
|
# --- Lokales TTS (piper; Binary + Stimmmodell noetig) ------------------------
|
|
|
|
|
# Aktivieren z. B. mit DEFAULT_TTS_PROVIDER=piper (oder --tts-provider piper).
|
|
|
|
|
# Stimmen liegen als <name>.onnx (+ .onnx.json) im Voices-Verzeichnis.
|
2026-06-17 23:31:58 +02:00
|
|
|
# Installierte Stimmen anzeigen: ls ~/.local/share/piper/voices/*.onnx
|
|
|
|
|
# Weitere laden: von huggingface 'rhasspy/piper-voices' nach PIPER_VOICES_DIR kopieren.
|
2026-06-17 22:11:20 +02:00
|
|
|
PIPER_BIN=piper # Pfad/Name des piper-Binaries
|
|
|
|
|
PIPER_VOICES_DIR=~/.local/share/piper/voices # Verzeichnis der .onnx-Stimmen
|
|
|
|
|
PIPER_VOICE=de_DE-thorsten-high # Stimmmodell (ohne .onnx) oder voller Pfad
|
|
|
|
|
TTS_SAMPLE_RATE=24000 # Ziel-Sample-Rate (ffmpeg resampelt bei Bedarf)
|
|
|
|
|
|
2026-06-17 05:19:07 +02:00
|
|
|
# --- Resilienz: Fallback-Ketten (kommaseparierte Provider-Namen) ------------
|
|
|
|
|
# Faellt der primaere Provider aus, uebernimmt der naechste.
|
|
|
|
|
# STT_FALLBACK=faster-whisper
|
|
|
|
|
# LLM_FALLBACK=local-openai-compatible
|
|
|
|
|
# TTS_FALLBACK=piper
|
2026-06-17 05:29:30 +02:00
|
|
|
|
feat(memory): automatische Erinnerungs-Extraktion aus Gespraechen
- app/core/memory_extractor.py: LLM destilliert nach je N Turns dauerhafte
Fakten/Vorlieben aus dem Verlauf, dedupliziert gegen vorhandene Erinnerungen
und legt sie ab - best-effort, nicht-blockierend (Hintergrund-Task), eigener
Extraktions-Prompt (JSON, Reasoning aus), Cap-Begrenzung
- Trigger in /api/chat und /ws/voice nach dem Persistieren des Turns
- Konfig: MEMORY_EXTRACTION_ENABLED/_EVERY_N_TURNS/_MAX/_PROVIDER
- Tests: Extraktion, Dedup, kaputtes JSON, Cap, leeres Gespraech, Scheduling
- Doku: README + Architektur-Roadmap (Punkt 3 erledigt)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 03:15:08 +02:00
|
|
|
# --- Automatische Erinnerungs-Extraktion -----------------------------------
|
|
|
|
|
# Das LLM destilliert nach je N Turns dauerhafte Fakten/Vorlieben aus dem Gespraech
|
|
|
|
|
# und legt sie als Nutzer-Erinnerungen ab (best-effort, nicht-blockierend).
|
|
|
|
|
# MEMORY_EXTRACTION_ENABLED=true
|
|
|
|
|
# MEMORY_EXTRACTION_EVERY_N_TURNS=3 # wie oft extrahiert wird
|
|
|
|
|
# MEMORY_EXTRACTION_MAX=50 # Obergrenze gespeicherter Erinnerungen
|
|
|
|
|
# MEMORY_EXTRACTION_PROVIDER= # leer = Default-LLM; sonst Registry-Name
|
|
|
|
|
|
2026-06-17 05:29:30 +02:00
|
|
|
# --- Betrieb: Kontingent & Notfall -----------------------------------------
|
|
|
|
|
DAILY_REQUEST_LIMIT=0 # Anfragen pro Nutzer/Tag (0 = unbegrenzt)
|
|
|
|
|
# EMERGENCY_WEBHOOK_URL=https://example.org/alert # optionale Eskalation
|
2026-06-18 03:24:25 +02:00
|
|
|
# LLM-Notfall-Klassifikation (Stufe 2): faengt im Hintergrund Notlagen, die die
|
|
|
|
|
# Stichwort-Heuristik verpasst -> keine zusaetzliche Antwortlatenz.
|
|
|
|
|
# EMERGENCY_LLM_ENABLED=true
|
|
|
|
|
# EMERGENCY_LLM_PROVIDER= # leer = Default-LLM; sonst Registry-Name
|
|
|
|
|
# EMERGENCY_LLM_MIN_CONFIDENCE=0.6 # Schwelle gegen Fehlalarme
|