2026-06-18 16:55:05 +02:00
# Voice Assistant Gateway — Handbuch
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
> **Zielgruppen:** 👤 Endnutzer · 🔧 Admin/Betreiber · 💻 Entwickler
>
> Technische Tiefe: [Architektur-Dokument](Docs/voice-assistant-architecture.md) ·
> Remote-Deployment: [deploy/README.md](deploy/README.md) ·
> Kurzübersicht: [README.md](README.md)
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
2026-06-18 17:23:25 +02:00
### Lesehilfe: `$URL` und `| jq`
In allen Shell-Beispielen dieses Handbuchs steht `$URL` als Platzhalter für die
Gateway-Adresse. Einmal setzen, dann überall einsetzbar:
2026-06-18 16:55:05 +02:00
```bash
export URL=http://localhost:8003
```
2026-06-18 17:23:25 +02:00
*(Port aus deiner `.env` — Standard ist `8080` , in dieser Installation `8003` .)*
Danach kann man z. B. schreiben:
```bash
curl -s $URL/health
# entspricht: curl -s http://localhost:8003/health
```
Befehle, die JSON zurückgeben, enden auf `| jq` — das formatiert die Ausgabe lesbar.
Installieren: `sudo apt install jq` . Ohne `jq` einfach weglassen; der Befehl
funktioniert trotzdem, die Ausgabe ist dann unformatiert.
2026-06-18 16:55:05 +02:00
---
## Inhaltsverzeichnis
**Grundlagen**
1. [Was ist dieses System? ](#1-was-ist-dieses-system )
2. [Installation und Einrichtung ](#2-installation-und-einrichtung )
3. [Betriebsprofile wählen ](#3-betriebsprofile-wählen )
2026-06-19 12:58:54 +02:00
4. [Starten und Stoppen ](#4-starten-und-stoppen ) — [4.0 Schnellbefehle ](#40-schnellbefehle-überblick ) · [4.5 llama.cpp ](#45-llamacpp-server-für-profil-hybridlocal-dev ) · [4.6 Ollama ](#46-ollama-alternative-zu-llamacpp-kein-docker-nötig ) · [4.7 Wechseln ](#47-zwischen-llamacpp-und-ollama-wechseln ) · [4.8 Stoppen ](#48-alles-stoppen ) · [4.9 Neustart ](#49-komplett-neustart )
2026-06-18 16:55:05 +02:00
**Bedienung**
5. [Das System benutzen ](#5-das-system-benutzen )
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
2026-06-18 16:55:05 +02:00
**Konfiguration**
6. [Einstellungen und Konfiguration ](#6-einstellungen-und-konfiguration )
**Administration**
2026-06-19 01:15:28 +02:00
7. [Nutzerverwaltung und Authentifizierung ](#7-nutzerverwaltung-und-authentifizierung ) · [7.5 Admin-Web-Panel ](#75-admin-web-panel )
2026-06-18 16:55:05 +02:00
8. [Gedächtnis und Erinnerungen ](#8-gedächtnis-und-erinnerungen )
9. [Resilienz, Fallbacks und Metriken ](#9-resilienz-fallbacks-und-metriken )
10. [Notfall-Erkennung und Eskalation ](#10-notfall-erkennung-und-eskalation )
11. [Remote-Zugang und Deployment ](#11-remote-zugang-und-deployment )
**Qualitätssicherung**
12. [Tests und Reaktionszeiten ](#12-tests-und-reaktionszeiten )
**Problemlösung**
13. [Fehlerbehebung ](#13-fehlerbehebung )
**Referenz**
- [Anhang A — Alle Umgebungsvariablen ](#anhang-a--alle-umgebungsvariablen )
- [Anhang B — API-Endpunkte ](#anhang-b--api-endpunkte )
- [Anhang C — Provider-Übersicht ](#anhang-c--provider-übersicht )
- [Anhang D — Sachregister ](#anhang-d--sachregister )
2026-06-17 01:48:56 +02:00
---
2026-06-18 16:55:05 +02:00
## 1. Was ist dieses System?
### 1.1 Überblick
Der **Voice Assistant Gateway ** ist ein modulares Sprachassistenten-System. Er nimmt
gesprochene oder getippte Eingaben entgegen, lässt sie von einer KI beantworten und
liest die Antwort vor. Die drei KI-Stufen — **Spracherkennung (STT) ** , **Sprachmodell (LLM) **
und **Sprachsynthese (TTS) ** — sind einzeln austauschbar: lokal oder in der Cloud,
je nach Bedarf.
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
Das System läuft als HTTP-/WebSocket-Server (FastAPI). Darauf greift man zu per:
- **Browser** (Web-Interface, mobiltauglich)
- **Kommandozeile** (Sprech-Loop, Chat-Client)
- **eigene Apps** (REST-API, WebSocket)
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
### 1.2 Leseanleitung nach Zielgruppe
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
| Du bist … | Lies zuerst … | Dann … |
|-----------|--------------|--------|
| 👤 **Endnutzer ** (nutzt den Assistenten) | § 5 Bedienung | § 8 Gedächtnis |
| 🔧 **Admin/Betreiber ** (installiert, verwaltet) | § 2– 4 Installation + Profile | § 7, 9, 10, 11 |
| 💻 **Entwickler ** (erweitert den Code) | § 2 Installation | [Architektur-Dokument ](Docs/voice-assistant-architecture.md ) |
### 1.3 Architektur auf einen Blick
```
Eingabe (Sprache/Text)
↓
[ STT-Provider ] Sprache → Text (Whisper lokal oder Cloud)
↓
[ Input Cleaner ] Füllwörter, Whitespace bereinigen
↓
[ LLM-Provider ] Text → Antwort-Text (lokal oder Cloud)
↓
[ Spoken-Response-Adapter ] Markdown raus, vorlesbar machen
↓
[ TTS-Normalizer ] Aussprache (Ordinalzahlen, Einheiten, Abkürzungen)
↓
[ TTS-Provider ] Text → Audio (piper lokal / Cloud)
↓
Ausgabe (Audio-Stream)
```
Jeder Provider ist über die Registry austauschbar — ohne Code-Änderung.
Technische Details: [Architektur-Dokument § 3– 6 ](Docs/voice-assistant-architecture.md ).
---
## 2. Installation und Einrichtung
> 🔧 Admin / 💻 Entwickler
### 2.1 Voraussetzungen
| Bedarf | Details |
|--------|---------|
| **Python 3.11+ ** | `python3 --version` |
| **jq ** | `sudo apt install jq` — für lesbare JSON-Ausgabe |
| **Audio-Tools ** | `sudo apt install alsa-utils ffmpeg` — für CLI-Sprech-Loop |
| **OpenRouter-Key ** | für Profile `cloud` und `hybrid` (→ [openrouter.ai ](https://openrouter.ai )) |
| **Docker + NVIDIA-GPU ** | nur für lokalen llama.cpp-Server (Profil `local-dev` / `hybrid` ) |
| **piper + Stimmmodell ** | nur für lokales TTS (→ § 6.5.2) |
Für lokales STT und TTS zusätzlich:
```bash
pip install -e .[local] # installiert faster-whisper + piper-tts
```
### 2.2 Installation
2026-06-17 01:48:56 +02:00
```bash
cd voice-assistant-scaffold
python3 -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -e .[test]
cp config/voice-assistant.example.toml config/voice-assistant.toml
```
2026-06-18 16:55:05 +02:00
Fehlt `.env` , legt `make run` sie automatisch aus `.env.example` an.
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
### 2.3 API-Key hinterlegen (für Cloud/Hybrid)
Der Key gehört **ausschließlich in die Umgebung ** — nie in `.env` oder eine Config-Datei
(Leakage-Risiko):
2026-06-17 01:48:56 +02:00
```bash
echo 'export OPENROUTER_API_KEY=sk-or-v1-DEIN_KEY' >> ~/.bashrc
chmod 600 ~/.bashrc
source ~/.bashrc
2026-06-18 16:55:05 +02:00
echo ${OPENROUTER_API_KEY:0:8} # nur Anfang anzeigen zur Kontrolle
2026-06-17 01:48:56 +02:00
```
2026-06-18 16:55:05 +02:00
Bei Leak: im OpenRouter-Dashboard löschen (= sofort widerrufen) und neu erstellen.
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
### 2.4 Konfigurationsdatei
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
Die Datei `config/voice-assistant.toml` enthält Profile und Modellnamen (kein Secret).
Die Vorlage `config/voice-assistant.example.toml` zeigt alle möglichen Einträge.
Präzedenz (höhere Ebene gewinnt): → § 6.1.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
---
2026-06-18 16:55:05 +02:00
## 3. Betriebsprofile wählen
> 🔧 Admin
Das Gateway kennt **drei Betriebsprofile ** . Sie legen fest, welche der drei KI-Stufen
lokal oder in der Cloud laufen. Einzelne Stufen lassen sich danach noch weiter
übersteuern (→ § 6.2).
### 3.1 Profil `cloud` — alles über OpenRouter *(Empfehlung für den Einstieg)*
Alle drei Stufen laufen remote bei OpenRouter. Nichts lokal zu starten außer dem Gateway.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
| Stufe | Läuft | Standard-Modell |
|-------|-------|-----------------|
| STT | OpenRouter | `openai/whisper-large-v3` |
| LLM | OpenRouter | `openai/gpt-4.1-mini` |
| TTS | OpenRouter | `openai/gpt-4o-mini-tts` |
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
**Was muss laufen?** Nur das Gateway (`make run` ).
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
**Hardware:** Beliebiger Rechner mit Internetzugang. Keine GPU.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
**Software:** Nur die Basisinstallation (`pip install -e .[test]` ).
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
**API-Key:** `OPENROUTER_API_KEY` erforderlich.
2026-06-18 16:55:05 +02:00
**Kosten:** ca. 1– 2 ¢ pro Sprech-Runde. STT und TTS sind die Kostentreiber; LLM ist
nahezu kostenlos. Grob ~20– 40 ¢ pro 10-Minuten-Gespräch.
Genaue Werte: OpenRouter-Dashboard → Activity/Usage.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
**Antwortgeschwindigkeit:** ~4 s Round-Trip (STT ~1,2 s + LLM ~0,7 s + TTS ~1,9 s).
Mit Streaming (`audio_stream=true` ) kommt die erste Silbe früher — subjektiv schneller.
→ Messung: § 12.2.
**Bewährte Modell-Kombination** (inkl. Plattdeutsch, Stand 2026-06-17):
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
```bash
2026-06-18 16:55:05 +02:00
# in .env:
VA_PROFILE=cloud
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
OPENROUTER_STT_MODEL=openai/whisper-large-v3
OPENROUTER_LLM_MODEL=google/gemini-3.1-flash-lite
OPENROUTER_TTS_MODEL=google/gemini-3.1-flash-tts-preview
OPENROUTER_TTS_VOICE=Zephyr
```
2026-06-18 16:55:05 +02:00
**Einrichten:**
```bash
VA_PROFILE=cloud make run
```
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
---
2026-06-18 16:55:05 +02:00
### 3.2 Profil `hybrid` — STT/TTS Cloud, LLM lokal
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
STT und TTS laufen remote (OpenRouter), die KI (LLM) läuft lokal. Datenschutzvorteil:
Sprachverständnis verlässt den Rechner nicht. Der finanzielle Vorteil ist gering
(nur ~10– 15 % günstiger als `cloud` ), weil TTS der eigentliche Kostentreiber ist
und remote bleibt.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
| Stufe | Läuft | Provider |
|-------|-------|----------|
| STT | OpenRouter | `openrouter` |
| LLM | eigener Rechner | `local-openai-compatible` |
| TTS | OpenRouter | `openrouter` |
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
**Was muss laufen?** Gateway + lokaler LLM-Server (llama.cpp oder Ollama).
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
**Hardware:** NVIDIA-GPU empfohlen (llama.cpp mit >7B-Modellen braucht VRAM). Mit
Ollama + kleinen Modellen (7B) auch ohne GPU möglich, aber langsamer.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
**API-Key:** `OPENROUTER_API_KEY` erforderlich (für STT + TTS).
2026-06-18 16:55:05 +02:00
**Kosten:** ~0,5– 1,5 ¢/Runde. Nur TTS bleibt remote; STT war ohnehin günstig.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
**Antwortgeschwindigkeit:** STT/TTS wie `cloud` . LLM-Latenz vom lokalen Modell
abhängig — Qwen3-35B auf RTX 3090 mit `LOCAL_LLM_DISABLE_REASONING=true` : ~0,7 s.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
**Einrichten (llama.cpp):**
```bash
2026-06-18 16:55:05 +02:00
make llm-up # Docker-Container starten (GPU 1, Port 8001)
make llm-status # warten bis "HTTP OK" erscheint
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
VA_PROFILE=hybrid make run
```
**Einrichten (Ollama):**
```bash
# in .env:
LOCAL_LLM_BASE_URL=http://127.0.0.1:11434/v1
LOCAL_LLM_API_KEY=ollama
2026-06-18 16:55:05 +02:00
LOCAL_LLM_MODEL=qwen3:30b-a3b # exakter Name aus 'ollama list'
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
VA_PROFILE=hybrid make run
```
2026-06-18 16:55:05 +02:00
> ⚠️ Das Gateway startet auch ohne laufenden LLM-Server fehlerfrei hoch. Der Fehler
> „All connection attempts failed" erscheint erst beim ersten Request. Deshalb: immer
> erst auf den LLM-Server warten, dann Gateway starten.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
---
2026-06-18 16:55:05 +02:00
### 3.3 Profil `local-dev` — alles lokal
Alle drei Stufen laufen auf dem eigenen Rechner. Kein Internet nötig, keine API-Kosten.
Maximaler Datenschutz.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
| Stufe | Läuft | Provider |
|-------|-------|----------|
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
| STT | eigener Rechner | `faster-whisper` |
2026-06-18 16:55:05 +02:00
| LLM | eigener Rechner | `local-openai-compatible` |
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
| TTS | eigener Rechner | `piper` |
2026-06-18 16:55:05 +02:00
**Was muss laufen?** Gateway + lokaler LLM-Server. STT (faster-whisper) und TTS (piper)
laufen direkt im Gateway-Prozess — kein eigener Dienst nötig.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
**Hardware:**
2026-06-18 16:55:05 +02:00
- NVIDIA-GPU für llama.cpp (35B-Modell: ~20 GB VRAM)
- Mit Ollama + 7B-Modell auch ohne GPU möglich (langsam)
- Kein Internetzugang nötig
**API-Key:** keiner.
**Kosten:** keine API-Kosten. Nur Stromkosten (GPU).
**Antwortgeschwindigkeit:** STT (`faster-whisper base` auf CPU) ~1– 3 s; LLM wie
`hybrid` ; TTS (`piper` , in-process) ~0,3– 0,5 s/Satz. Erste Antwort nach Start ist
schnell, weil Modelle beim Serverstart vorgeladen werden (Warm-up).
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
**Sprachqualität:** piper klingt synthetischer als Cloud-TTS. Whisper `base` ist
bei Dialekten schwächer als `large-v3` . Für bessere Qualität:
`FASTER_WHISPER_MODEL=large-v3` + `FASTER_WHISPER_DEVICE=cuda` .
**Einrichten (llama.cpp):**
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
```bash
2026-06-18 16:55:05 +02:00
pip install -e .[local] # faster-whisper + piper-tts installieren
# Piper-Stimmmodell bereitstellen (einmalig, → § 6.5.2)
make llm-up # warten bis make llm-status "HTTP OK" zeigt
VA_PROFILE=local-dev make run
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
```
2026-06-18 16:55:05 +02:00
**Einrichten (Ollama als LLM-Backend):**
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
Ollama bietet eine OpenAI-kompatible API und verwaltet seinen Server selbst — kein
Docker, kein Start-Skript nötig.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
```bash
# Voraussetzung: ollama installiert und Modell geladen
ollama pull qwen3:30b-a3b
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
# in .env:
LOCAL_LLM_BASE_URL=http://127.0.0.1:11434/v1
LOCAL_LLM_API_KEY=ollama
LOCAL_LLM_MODEL=qwen3:30b-a3b
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
VA_PROFILE=local-dev make run
```
2026-06-18 16:55:05 +02:00
Hinweis: `LOCAL_LLM_DISABLE_REASONING=true` (Standard) schickt
`chat_template_kwargs: {enable_thinking: false}` — Ollama ignoriert dieses Feld.
Reasoning muss über den Modell-Tag abgeschaltet werden (`qwen3:30b-a3b` statt
`qwen3:30b-a3b:thinking` ) oder bleibt an.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
---
2026-06-18 16:55:05 +02:00
### 3.4 Vergleich auf einen Blick
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
| | `cloud` | `hybrid` | `local-dev` |
|---|---------|----------|-------------|
| **STT ** | remote | remote | lokal |
| **LLM ** | remote | **lokal ** | **lokal ** |
| **TTS ** | remote | remote | **lokal ** |
| **API-Key nötig ** | ja | ja | nein |
| **GPU nötig ** | nein | empfohlen | empfohlen |
| **Internetverbindung ** | ja | ja | nein |
2026-06-18 16:55:05 +02:00
| **API-Kosten/Runde ** | ~1– 2 ¢ | ~0,5– 1,5 ¢ | ~0 (nur Strom) |
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
| **Round-Trip ** | ~4 s | ~3– 5 s | ~3– 6 s |
2026-06-18 16:55:05 +02:00
| **TTS-Qualität ** | hoch | hoch | mittel (piper) |
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
| **Datenschutz ** | gering | hoch | maximal |
| **Empfohlen für ** | Einstieg, Senioren | Datenschutz + gutes TTS | Offline, kein API-Key |
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
### 3.5 Profil wechseln
2026-06-17 01:48:56 +02:00
```bash
2026-06-18 16:55:05 +02:00
# dauerhaft in .env:
VA_PROFILE=cloud
# einmalig für einen Start:
VA_PROFILE=hybrid make run
# aktive Konfiguration prüfen:
curl -s $URL/api/config | jq '{profile, default_route}'
```
> **Falle:** Sind `DEFAULT_STT_PROVIDER`, `DEFAULT_LLM_PROVIDER` oder
> `DEFAULT_TTS_PROVIDER` in `.env` gesetzt, überschreiben sie das Profil.
> Diese Zeilen auskommentieren, wenn profilbasiert umgeschaltet werden soll.
---
## 4. Starten und Stoppen
> 🔧 Admin
2026-06-19 12:58:54 +02:00
### 4.0 Schnellbefehle (Überblick)
Die wichtigsten Kommandos auf einen Blick — Details in den Abschnitten darunter.
**Starten:**
| Situation | Kommando |
|-----------|----------|
| Profil `cloud` — nur Gateway | `make run` |
| Profil `hybrid` / `local-dev` — llama.cpp + Gateway | `make start` |
| Profil `hybrid` / `local-dev` — Ollama + Gateway | `sudo systemctl start ollama && make run` |
2026-06-20 15:56:42 +02:00
| LLM-Backend → Ollama wechseln | `make llm-ollama` (→ § 4.7) |
| LLM-Backend → llama.cpp wechseln | `make llm-llamacpp` (→ § 4.7) |
2026-06-19 12:58:54 +02:00
| systemd-Dienst starten | `systemctl --user start voice-assistant` |
**Stoppen:**
| Situation | Kommando |
|-----------|----------|
| Gateway im Vordergrund | **Strg + C ** |
| Gateway im Hintergrund / systemd | `make stop` |
| Alles (Gateway + llama.cpp) | `make stop` |
| llama.cpp allein | `make llm-down` |
| Ollama allein | `sudo systemctl stop ollama` |
**Neu starten (alles):**
```bash
make restart # make stop + make start (llama.cpp + Gateway)
# Nur Gateway neu starten (llama.cpp läuft weiter):
systemctl --user restart voice-assistant # systemd
# oder: Strg+C und make run # Vordergrund
```
---
2026-06-18 16:55:05 +02:00
### 4.1 Vordergrund (Entwicklung/Test)
```bash
source .venv/bin/activate
make run # Gateway startet auf dem in .env gesetzten PORT
2026-06-17 01:48:56 +02:00
```
2026-06-18 16:55:05 +02:00
Beenden mit **Strg + C ** . Schnelltest:
2026-06-17 01:48:56 +02:00
```bash
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
curl -s $URL/health | jq
curl -s $URL/api/config | jq
2026-06-17 01:48:56 +02:00
```
2026-06-18 16:55:05 +02:00
### 4.2 Hintergrund
2026-06-17 01:48:56 +02:00
```bash
2026-06-18 16:55:05 +02:00
nohup make run > server.log 2>&1 & # starten, Logs nach server.log
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
pkill -f "uvicorn app.main:app" # stoppen
2026-06-18 16:55:05 +02:00
tail -f server.log # Logs beobachten
2026-06-17 01:48:56 +02:00
```
2026-06-18 16:55:05 +02:00
Mehr Log-Details: `LOG_LEVEL=debug` in `.env` setzen.
### 4.3 Als systemd-Dienst (Dauer-Betrieb, ohne root)
```bash
cp deploy/voice-assistant.user.service ~/.config/systemd/user/voice-assistant.service
loginctl enable-linger "$USER" # überlebt Logout und Reboot
systemctl --user daemon-reload
systemctl --user enable --now voice-assistant
systemctl --user status voice-assistant
journalctl --user -u voice-assistant -f # Logs live verfolgen
```
Konfiguration: `deploy/voice-assistant.env.example` → anpassen, dann als
`/etc/voice-assistant/voice-assistant.env` ablegen (Pfad in der Unit).
### 4.4 Docker
```bash
export OPENROUTER_API_KEY=...
docker compose up --build
```
Port ändern: `PORT=8005 make run` (einmalig) oder `PORT=8005` in `.env` (dauerhaft).
### 4.5 llama.cpp-Server (für Profil `hybrid`/`local-dev`)
2026-06-19 11:59:04 +02:00
**Voraussetzungen:** Docker mit NVIDIA-Container-Toolkit, GPU mit ausreichend VRAM
(Qwen3-35B-Q4: ~22 GB; Qwen3-8B-Q4: ~5 GB).
2026-06-18 16:55:05 +02:00
```bash
2026-06-19 11:59:04 +02:00
# Starten (Default: GPU 1, Port 8001, Modell qwen3-35B-Uncensored):
make llm-up
# Status prüfen (warten bis „Modell bereit" und HTTP 200 erscheinen):
make llm-status
# Logs live beobachten:
docker logs -f va_llm
# Stoppen:
make llm-down
```
**Mit anderen Parametern** — ENV-Variable vor dem Befehl setzen:
```bash
# Andere GPU:
GPU_DEVICE=0 make llm-up
# Anderen Port:
HOST_PORT=8101 make llm-up
# Anderes Modell auf anderer GPU:
GPU_DEVICE=2 HOST_PORT=8102 MODEL_REL_PATH="models/qwen3/anderes-modell.gguf" make llm-up
# Direkt (ohne make — identisch, aber zeigt alle Parameter):
bash scripts/llm-server/start-llm-server.sh
GPU_DEVICE=0 bash scripts/llm-server/start-llm-server.sh
GPU_DEVICE=2 HOST_PORT=8102 MODEL_REL_PATH="models/qwen3/anderes-modell.gguf" \
bash scripts/llm-server/start-llm-server.sh
2026-06-18 16:55:05 +02:00
```
2026-06-19 11:59:04 +02:00
Alle überschreibbaren ENV-Variablen:
2026-06-18 16:55:05 +02:00
| Variable | Default | Bedeutung |
|----------|---------|-----------|
2026-06-19 11:59:04 +02:00
| `GPU_DEVICE` | `1` | GPU-Index (0-basiert, `nvidia-smi` zeigt verfügbare GPUs) |
| `HOST_PORT` | `8001` | Host-Port des LLM-Servers |
2026-06-18 16:55:05 +02:00
| `MODEL_REL_PATH` | `models/qwen3/Qwen3.6-35B-A3B-Uncensored-...Q4_K_M.gguf` | Modellpfad relativ zu `HF_HOME` |
2026-06-19 11:59:04 +02:00
| `HF_HOME` | `~/nvme2n1p7_home/huggingface` | Modell-Basisverzeichnis (als Volume eingebunden) |
| `MODEL_ALIAS` | `va_llm` | Modellname in der OpenAI-API (→ `LOCAL_LLM_MODEL` in `.env` ) |
2026-06-18 16:55:05 +02:00
| `CONTAINER_NAME` | `va_llm` | Docker-Containername |
2026-06-19 11:59:04 +02:00
| `IMAGE` | `ghcr.io/ggml-org/llama.cpp:server-cuda` | Docker-Image |
> ⚠️ Wird `HOST_PORT` oder `MODEL_ALIAS` geändert, müssen `LOCAL_LLM_BASE_URL`
> und `LOCAL_LLM_MODEL` in `.env` entsprechend angepasst werden.
Das Skript wartet bis zu 300 Sekunden auf einen HTTP-200-Response und bricht mit
Fehler ab, wenn das Modell nicht startet — kein stilles Fehlschlagen.
2026-06-18 16:55:05 +02:00
2026-06-19 11:59:04 +02:00
---
### 4.6 Ollama (Alternative zu llama.cpp, kein Docker nötig)
Ollama verwaltet seinen Serverprozess selbst und braucht kein Docker. Es eignet sich
besonders für schnellen Einstieg, CPU-Betrieb und kleinere Modelle.
**Installation** (falls noch nicht installiert):
2026-06-18 16:55:05 +02:00
```bash
2026-06-19 11:59:04 +02:00
curl -fsSL https://ollama.com/install.sh | sh
2026-06-18 16:55:05 +02:00
```
2026-06-19 11:59:04 +02:00
**Dienst starten:**
```bash
# empfohlen — systemd verwaltet den Prozess:
sudo systemctl start ollama
sudo systemctl enable ollama # automatisch bei Boot starten
sudo systemctl status ollama # Status prüfen
# alternativ — manuell im Vordergrund (Strg+C stoppt):
ollama serve
# mit anderem Port (Default: 11434):
OLLAMA_HOST=0.0.0.0:11435 ollama serve
```
**Modell herunterladen** (einmalig):
```bash
ollama pull qwen3:30b-a3b # ~20 GB, Thinking deaktiviert (empfohlen für Voice)
ollama pull qwen3:8b # ~5 GB, CPU-tauglich, weniger Qualität
ollama pull qwen3:14b # ~9 GB, guter Kompromiss
```
**Status prüfen:**
```bash
ollama list # installierte Modelle mit Größe und Änderungsdatum
ollama ps # gerade aktive Modelle mit VRAM-Verbrauch
```
**Modell entfernen** (Speicher freigeben):
```bash
ollama rm qwen3:8b
```
**Gateway für Ollama konfigurieren** (in `.env` ):
```bash
LOCAL_LLM_BASE_URL=http://127.0.0.1:11434/v1
LOCAL_LLM_API_KEY=ollama
LOCAL_LLM_MODEL=qwen3:30b-a3b # exakter Name aus 'ollama list'
```
**Gateway starten:**
```bash
VA_PROFILE=hybrid make run # STT/TTS cloud, LLM via Ollama
VA_PROFILE=local-dev make run # alles lokal (STT/TTS in-process, LLM via Ollama)
```
> **Hinweis Reasoning:** `LOCAL_LLM_DISABLE_REASONING=true` (Gateway-Standard) schickt
> `enable_thinking: false` an den Server — Ollama ignoriert dieses Feld. Um Reasoning
> zu deaktivieren, den Modell-Tag ohne Thinking-Suffix wählen (`qwen3:30b-a3b` statt
> `qwen3:30b-a3b:thinking`).
2026-06-17 01:48:56 +02:00
---
2026-06-19 12:12:29 +02:00
### 4.7 Zwischen llama.cpp und Ollama wechseln
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
Beide nutzen denselben Gateway-Provider `local-openai-compatible` (OpenAI-kompatible
2026-06-20 15:56:42 +02:00
API). `DEFAULT_LLM_PROVIDER` bleibt beim Wechsel unverändert.
#### Schnellster Weg: Make-Targets (empfohlen)
```bash
make llm-ollama # -> Ollama (Default-Modell gemma3:latest)
make llm-llamacpp # -> llama.cpp (Alias va_llm)
# Anderes Ollama-Modell:
OLLAMA_MODEL=qwen2.5:latest make llm-ollama
```
Das Target erledigt automatisch alle Schritte: es gibt den GPU-Speicher des anderen
Backends frei (llama.cpp-Container stoppen bzw. geladene Ollama-Modelle entladen — der
Ollama-*Dienst* bleibt für andere Nutzungen laufen), startet das gewünschte Backend,
passt die `LOCAL_LLM_*` -Zeilen in `.env` an und startet das Gateway neu (als Dienst)
bzw. weist auf den manuellen Neustart hin. Skript: `scripts/llm-server/switch-llm.sh` .
> **Warum der Gateway-Neustart nötig ist:** Das `Makefile` exportiert die `.env`-Werte
> als echte Umgebungsvariablen an `uvicorn` — und Env-Variablen haben **Vorrang vor der
> `.env`-Datei**. Eine reine `.env`-Änderung wirkt daher erst, wenn das Gateway neu
> gestartet wird (uvicorn `--reload` reagiert nur auf Code-, nicht auf `.env`-Änderungen).
> Starte es **in einer frischen Shell** neu (`make run`) bzw. als Dienst:
> `systemctl --user restart voice-assistant.service`.
#### Manuell (was die Targets im Hintergrund tun)
2026-06-19 12:12:29 +02:00
**Merkhilfe:**
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
- llama.cpp = Docker-Container `va_llm` → `make llm-up` / `make llm-down` (Port 8001)
- Ollama = systemd-Dienst → `sudo systemctl start/stop ollama` (Port 11434)
2026-06-20 15:56:42 +02:00
GPU freigeben ohne Dienst-Stopp: `ollama stop <modell>`
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
#### Von llama.cpp → Ollama wechseln
```bash
# 1) llama.cpp stoppen (GPU freigeben)
make llm-down # alternativ: docker rm -f va_llm
# 2) Ollama starten und Modell sicherstellen
sudo systemctl start ollama
ollama list # exakten Modellnamen ablesen (z. B. gemma4:12b)
ollama pull gemma4:12b # nur falls noch nicht vorhanden
# 3) .env umstellen:
# LOCAL_LLM_BASE_URL=http://127.0.0.1:11434/v1
# LOCAL_LLM_API_KEY=ollama
# LOCAL_LLM_MODEL=gemma4:12b # exakter Name aus 'ollama list'
# 4) Gateway neu starten
VA_PROFILE=hybrid make run # oder: systemctl --user restart voice-assistant.service
```
2026-06-19 12:12:29 +02:00
#### Von Ollama → llama.cpp wechseln
```bash
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
# 1) Ollama stoppen (GPU freigeben)
2026-06-19 12:12:29 +02:00
sudo systemctl stop ollama
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
pkill -f "ollama serve" 2>/dev/null || true # falls manuell im Vordergrund gestartet
2026-06-19 12:12:29 +02:00
# 2) llama.cpp starten und warten
make llm-up
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
make llm-status # warten bis „Modell bereit" + HTTP OK
2026-06-19 12:12:29 +02:00
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
# 3) .env umstellen:
# LOCAL_LLM_BASE_URL=http://127.0.0.1:8001/v1
# LOCAL_LLM_API_KEY=dummy
# LOCAL_LLM_MODEL=va_llm
2026-06-19 12:12:29 +02:00
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
# 4) Gateway neu starten
VA_PROFILE=hybrid make run # oder: systemctl --user restart voice-assistant.service
```
2026-06-19 12:12:29 +02:00
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
**Prüfen** (egal welche Richtung):
2026-06-19 12:12:29 +02:00
```bash
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
curl http://127.0.0.1:11434/v1/models # Ollama (bzw. :8001 für llama.cpp)
# danach im Admin → Status den LLM-Provider/das Modell kontrollieren oder kurz testen
2026-06-19 12:12:29 +02:00
```
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
> **Reasoning/Latenz:** Das Gateway sendet `enable_thinking:false`; **Ollama ignoriert**
> das. Modelle mit eingebautem „Thinking" (z. B. `gemma4:12b`) liefern die Antwort sauber
> im `content`, denken aber intern mit → höhere Latenz. Für reinen Smalltalk ggf. ein
> kleineres/nicht-reasonendes Modell wählen.
2026-06-19 12:12:29 +02:00
---
2026-06-19 12:58:54 +02:00
### 4.8 Alles stoppen
```bash
make stop
```
Ein Befehl stoppt alle Voice-Assistant-Komponenten:
- Gateway (ob im Vordergrund gestartet, im Hintergrund oder als systemd-Dienst)
- llama.cpp-Docker-Container (`va_llm` )
Ollama ist ein systemd-Dienst und muss separat gestoppt werden:
```bash
sudo systemctl stop ollama
```
**Einzelne Komponenten stoppen:**
```bash
# Nur Gateway (Vordergrund):
Strg + C
# Nur Gateway (Hintergrund):
pkill -f "uvicorn app.main:app"
# Nur Gateway (systemd):
systemctl --user stop voice-assistant
# Nur llama.cpp:
make llm-down
# oder direkt:
docker rm -f va_llm
# Nur Ollama:
sudo systemctl stop ollama
```
### 4.9 Komplett-Neustart
```bash
make restart
```
Entspricht `make stop` gefolgt von `make start` (llama.cpp + Gateway). Sinnvoll nach
Konfigurationsänderungen, die einen Neustart erfordern (z. B. neue `.env` -Werte).
**Nur Gateway neu starten** (llama.cpp läuft weiter — schneller):
```bash
systemctl --user restart voice-assistant # systemd-Betrieb
# oder: Strg+C → make run # Vordergrund-Betrieb
```
> ⚠️ `make restart` startet llama.cpp neu (Modell lädt ~5 Min.). Wenn nur der Gateway-
> Code oder die Konfiguration geändert wurde, ist `systemctl --user restart voice-assistant`
> deutlich schneller.
---
2026-06-20 18:25:45 +02:00
### 4.10 Dauerbetrieb als Dienst + GPU automatisch frei
Damit der Gateway beim Booten automatisch startet und nicht im Vordergrund hängt,
läuft er als **systemd-User-Dienst ** (Unit: `deploy/voice-assistant.user.service` ).
```bash
cp deploy/voice-assistant.user.service ~/.config/systemd/user/voice-assistant.service
loginctl enable-linger "$USER" # sudo -> Dienst läuft auch ohne Login / nach Reboot
systemctl --user daemon-reload
systemctl --user enable --now voice-assistant
```
**Wichtig — der Gateway blockiert die GPU NICHT.** Der Gateway-Prozess läuft auf der
CPU. Die GPU 1 wird allein vom **LLM-Backend ** belegt:
- **llama.cpp** (Docker-Container) ist * immer resident * → belegt die GPU dauerhaft, solange er läuft. Daher **nicht ** automatisch mitstarten; nur bei Bedarf (`make llm-llamacpp` ).
- **Ollama** lädt das Modell erst beim ersten Request in die GPU und gibt sie nach
Leerlauf wieder frei — **wenn ** `OLLAMA_KEEP_ALIVE` ein Timeout ist (Default `-1` = nie).
→ Für „GPU im Leerlauf frei" das Drop-in `deploy/ollama-keepalive.conf` installieren
(setzt `OLLAMA_KEEP_ALIVE=5m` ):
```bash
sudo mkdir -p /etc/systemd/system/ollama.service.d
sudo cp deploy/ollama-keepalive.conf /etc/systemd/system/ollama.service.d/keepalive.conf
sudo systemctl daemon-reload && sudo systemctl restart ollama
```
So ist GPU 1 standardmäßig frei: Der Gateway läuft (Boot), Ollama hält die GPU nur
während aktiver Nutzung. Du musst nichts mehr manuell stoppen.
> **Hinweis:** Erst im Dienst-Betrieb funktioniert der **Log-Tab** des Admin-Panels
> (er streamt das Journal der Unit). Im Vordergrund-Betrieb (`make run`) landen die
> Logs nur im Terminal.
---
2026-06-18 16:55:05 +02:00
## 5. Das System benutzen
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
> 👤 Endnutzer
### 5.1 Web-Interface im Browser *(einfachster Einstieg)*
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
Das Gateway liefert unter `/` eine fertige Web-Oberfläche aus — kein zusätzliches
2026-06-18 16:55:05 +02:00
Programm nötig.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
#### 5.1.1 URL aufrufen
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
```
http://localhost:8003/ ← am Server selbst (Mikrofon funktioniert)
http://<server-lan-ip>:8003/ ← aus dem LAN (nur Text-Chat; Mikrofon braucht HTTPS)
2026-06-18 16:55:05 +02:00
https://va.beispiel.de/ ← remote über Reverse-Proxy (alles, inkl. Mikrofon)
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
```
2026-06-18 16:55:05 +02:00
> Mikrofon im Browser geht nur über `localhost` oder HTTPS. Für Sprachaufnahme von
> einem anderen Gerät im Heimnetz: HTTPS-Zugang einrichten (→ § 11.2).
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
#### 5.1.2 Oberfläche auf einen Blick
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
```
2026-06-18 16:55:05 +02:00
┌─────────────────────────────────────────────────────────┐
2026-06-20 22:26:20 +02:00
│ 👄 Voice Assistant ............... [🇩🇪 ▾] [ ⋮ ] │
├─────────────────────────────────────────────────────────┤ ┌─ Menü (⋮) ──────────────┐
2026-06-21 01:28:21 +02:00
│ Angemeldet als <user> ....................... Abmelden │ │ VORLESEN │
├─────────────────────────────────────────────────────────┤ │ ▣ 📱 Im Gerät │
│ Nachrichtenverlauf │ │ ▢ ⚡ Schnell │
│ (eigene Nachrichten: blaue Blase rechts) │ │ ▢ ✨ Hohe Qualität │
│ (Assistent: graue Blase links) │ │ ▢ ☁ Cloud │
2026-06-20 22:26:20 +02:00
│ │ │ ────────────────────── │
├─────────────────────────────┬───────────────────────────┤ │ ✎ Neues Gespräch │
│ Texteingabe … [Senden] │ [🎤] │ │ 🌙 Tag-/Nachtmodus │
2026-06-21 01:28:21 +02:00
└─────────────────────────────┴───────────────────────────┘ │ ⚙ Admin-Bereich │
Statuszeile: „denkt …" / „verarbeite Sprache …" / leer └──────────────────────────┘
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
```
2026-06-20 22:26:20 +02:00
**Kopfzeile (immer schlank):**
| Element | Funktion |
|---------|----------|
| * * 👄 / Titel** | Marke; Mund-Symbol als Wiedererkennung |
| **Sprache ▾ ** | Antwortsprache (→ § 6.6): `🔄 Flex` = folgt der gesprochenen Sprache · feste Sprache (🇩🇪/🇬🇧/…) = Antwort + Stimme in dieser Sprache |
| * * ⋮ Menü** | Öffnet die Einstellungen (unten) |
2026-06-21 01:28:21 +02:00
**Identitätsleiste (direkt unter der Kopfzeile):** links „Angemeldet als …" (SSO-Identität;
„Gast" ohne SSO), rechts **Abmelden ** (Link zum SSO-Logout).
2026-06-20 22:26:20 +02:00
**Im ⋮-Menü:**
| Element | Funktion |
|---------|----------|
2026-06-21 01:10:51 +02:00
| **Vorlesen ** | Wie wird die Antwort vorgelesen? `📱 Im Gerät` = das Handy liest selbst vor (kein Server-Audio → spart Daten; fällt auf Server zurück, wenn der Browser keine Stimmen hat) · `⚡ Schnell` = piper (lokal) · `✨ Hohe Qualität` = chatterbox (natürliche Stimme) · `☁ Cloud` = OpenRouter (Internet nötig). „Im Gerät" erscheint nur, wo der Browser es unterstützt. |
2026-06-20 22:26:20 +02:00
| * * ✎ Neues Gespräch** | Frische Sitzung (Verlauf zurücksetzen) |
| * * 🌙 Tag-/Nachtmodus** | Heller/dunkler Modus; folgt sonst dem Betriebssystem |
2026-06-21 01:28:21 +02:00
| * * ⚙ Admin-Bereich** | Öffnet das Admin-Panel — nur für Admin-Nutzer sichtbar (→ § 7.5) |
2026-06-20 22:26:20 +02:00
**Unten:**
2026-06-18 16:55:05 +02:00
| Element | Funktion |
|---------|----------|
2026-06-20 22:26:20 +02:00
| * * 🎤 Mikrofon** | **grün: ** tippen → Aufnahme · **rot: ** tippen → stoppt & sendet · **amber ⏹: ** tippen → KI unterbrechen (Barge-in). STT läuft serverseitig (Whisper). |
2026-06-18 16:55:05 +02:00
| **Texteingabe + Senden ** | Text tippen, dann Enter oder „Senden" |
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
#### 5.1.3 Typischer Ablauf — Textchat
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
1. Seite aufrufen → Eingabefeld ist aktiv.
2. Text tippen (z. B. „Wie wird das Wetter morgen?") → **Enter ** oder **Senden ** .
3. Eigene Nachricht erscheint als blaue Blase; Assistent antwortet grau und liest vor.
4. Nächste Frage — der Verlauf bleibt (solange die Seite offen ist).
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
#### 5.1.4 Typischer Ablauf — Sprachaufnahme
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 16:55:05 +02:00
1. * * 🎤** tippen → Button wird rot, Statuszeile: „Aufnahme …".
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2. Sprechen.
2026-06-18 16:55:05 +02:00
3. * * 🎤** erneut tippen → Statuszeile: „verarbeite Sprache …" → „denkt …".
4. Transkription erscheint blau, Antwort grau — und wird vorgelesen.
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
2026-06-18 18:44:53 +02:00
**Antwort unterbrechen (Barge-in):** Während der Button amber / ⏹ zeigt (KI spricht),
einfach erneut tippen → Wiedergabe stoppt sofort, Generierung auf dem Server bricht ab.
Der Button kehrt zu grün zurück, sobald die Verbindung sauber geschlossen ist.
2026-06-18 16:55:05 +02:00
#### 5.1.5 Fehlermeldungen im Chat
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
| Meldung | Ursache | Abhilfe |
|---------|---------|---------|
2026-06-18 16:55:05 +02:00
| „Verbindungsfehler" | WebSocket-Verbindung gescheitert | Seite neu laden; Gateway läuft? (`make run` ) |
| „Fehler: All connection attempts failed" | LLM-/STT-/TTS-Dienst nicht erreichbar | Dienst starten (z. B. `make llm-up` ) |
| „Mikrofon-Zugriff fehlgeschlagen" | Browser hat Mikrofon verweigert | Browser-Einstellungen → Mikrofon erlauben; oder HTTPS nutzen |
| „Aufnahme nicht unterstützt" | Browser zu alt (iOS < 14.3) | Browser/iOS aktualisieren |
docs: Betriebsprofile, Ollama, Web-UI und Startup-Hinweise dokumentieren
- README: Ollama als LLM-Backend (Alternative zu llama.cpp) mit .env-Snippet
- README: Warnung dass Gateway ohne LLM-Server startet, Fehler erst beim ersten Request
- BEDIENUNGSANLEITUNG: Abschnitt 4 zu vollstaendiger Profilbeschreibung ausgebaut
(cloud / hybrid / local-dev je mit Hardware, Software, Kosten, Latenz, Qualitaet,
Einrichtungsbefehlen und Vergleichstabelle)
- BEDIENUNGSANLEITUNG: neues Kapitel A0 Web-Interface (Oberflaeche, Ablaeufe,
Fehlertabelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:30:46 +02:00
---
2026-06-18 16:55:05 +02:00
### 5.2 Sprech-Loop (Kommandozeile) *(empfohlen für Desktop)*
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
Nimmt vom Mikrofon auf, schickt die Aufnahme ans Gateway, spielt die Antwort ab —
fortlaufend, mit Gedächtnis:
2026-06-17 01:48:56 +02:00
```bash
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
source .venv/bin/activate
python scripts/voice_loop.py --session mein-gespraech
2026-06-17 01:48:56 +02:00
```
2026-06-18 16:55:05 +02:00
**Ablauf je Runde:**
1. * * [Enter]** → sprechen
2. * * [Enter]** → Aufnahme stoppt, Assistent antwortet hörbar
2026-06-19 00:39:00 +02:00
3. * * [Enter]** während der KI antwortet (Text streamt * oder * Audio spielt) → **Barge-in: ** Antwort sofort unterbrechen
2026-06-18 18:44:53 +02:00
4. * * [Enter]** → nächste Runde beginnen
5. **Strg + C ** → beenden
2026-06-18 16:55:05 +02:00
**Nützliche Optionen:**
| Option | Wirkung |
|--------|---------|
| `--stream-text` | Antworttext live anzeigen, während die KI generiert |
| `--no-stream-audio` | satzweises Vorlesen abschalten (erst komplett, dann abspielen) |
| `--recorder arecord --device plughw:6,0` | bestimmtes Mikrofon erzwingen |
| `--stt-provider faster-whisper` | STT-Provider für diese Sitzung |
| `--llm-provider local-openai-compatible` | LLM-Provider für diese Sitzung |
| `--tts-provider openrouter` | TTS-Provider für diese Sitzung |
| `--voice Zephyr` | TTS-Stimme für diese Sitzung |
| `--token "$TOKEN"` | Bearer-Token (wenn `AUTH_ENABLED=true` ) |
| `--file frage.wav` | WAV-Datei statt Mikrofon senden (Test) |
**Mikrofon-Auswahl:** Ohne `--device` folgt der Loop dem **System-Standard-Mikrofon **
(umstellbar unter * Ubuntu → Einstellungen → Ton * , → § 6.7). `--recorder auto` (Standard)
wählt selbsttätig ein Aufnahmewerkzeug, das wirklich Audio liefert
(`ffmpeg` → `parecord` → `arecord` → `pw-record` ).
**Audio-Ausgabe:** Der Loop spielt über das **System-Standard-Ausgabegerät ** . Ist die
Bluetooth-Box dort als Standard gesetzt, kommt die Antwort automatisch über sie.
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
---
2026-06-17 10:37:49 +02:00
2026-06-18 16:55:05 +02:00
### 5.3 Chat-Client (Kommandozeile, nur Text)
2026-06-17 04:16:35 +02:00
```bash
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
python chat_client.py "Erzähl mir bitte einen guten Morgen-Spruch"
2026-06-17 04:16:35 +02:00
```
2026-06-18 16:55:05 +02:00
Schickt Text ans Gateway und spielt die gesprochene Antwort ab (Port aus `.env` , hier 8003).
2026-06-17 04:16:35 +02:00
2026-06-18 16:55:05 +02:00
---
### 5.4 Pipeline manuell verstehen (Einzelschritte)
Gut für Tests und um die Stufen separat zu messen:
2026-06-17 01:48:56 +02:00
```bash
2026-06-18 16:55:05 +02:00
# 1) Aufnehmen (Strg+C zum Stoppen):
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
arecord -f S16_LE -r 16000 -c 1 frage.wav
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
# 2) Transkribieren (Audio → Text):
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
curl -s -X POST $URL/api/transcribe \
2026-06-18 16:55:05 +02:00
-F "file=@frage .wav" -F "language=de" | jq
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
# 3) Antwort erzeugen (Text → Audio) und abspielen:
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
curl -s -X POST "$URL/api/chat?session_id=loop" \
2026-06-17 01:48:56 +02:00
-H 'Content-Type: application/json' \
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
-d '{"text":"Guten Tag, wie heißt du?"}' --output antwort.pcm
ffplay -loglevel quiet -nodisp -autoexit -f s16le -ar 24000 -ac 1 antwort.pcm
2026-06-18 16:55:05 +02:00
# alternativ: aplay -f S16_LE -r 24000 -c 1 antwort.pcm
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
# Nur Sprachausgabe (Text → Audio):
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
curl -s -X POST $URL/api/speak \
2026-06-17 01:48:56 +02:00
-H 'Content-Type: application/json' \
2026-06-18 16:55:05 +02:00
-d '{"text":"Guten Morgen!"}' --output gruss.pcm
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
# Chat als Text-Trace (ohne Audio), lesbar:
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
curl -s -X POST "$URL/api/chat?debug=true" \
-H 'Content-Type: application/json' \
2026-06-18 16:55:05 +02:00
-d '{"text":"Wie wird das Wetter?"}' | jq
```
2026-06-17 01:48:56 +02:00
---
2026-06-18 16:55:05 +02:00
## 6. Einstellungen und Konfiguration
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
> 🔧 Admin / 👤 Endnutzer (je nach Abschnitt)
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
### 6.1 Konfigurationsebenen und Priorität
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
Niedrigere Ebene wird von höherer überschrieben:
```
eingebaute Defaults
↓ überschrieben von
config/voice-assistant.toml (inkl. aktivem Profil)
↓
ENV / .env
↓
Nutzer-Präferenzen (PUT /api/me/prefs)
↓
Session-Route (POST /api/sessions/{id}/route)
↓
Request-Body (Felder im POST /api/chat etc.)
```
Dies bedeutet: Was im Request-Body steht, gilt nur für diesen einen Aufruf.
Was in `.env` steht, gilt global — aber nur wenn die darüber liegenden Ebenen nicht übersteuern.
2026-06-17 01:48:56 +02:00
```bash
2026-06-18 16:55:05 +02:00
# Aktiv aufgelöste Konfiguration ansehen:
curl -s $URL/api/config | jq
```
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
### 6.2 KI-Provider wechseln (STT / LLM / TTS)
Verfügbare Provider (→ vollständige Liste: Anhang C):
| Kategorie | Provider-Name | Beschreibung |
|-----------|--------------|--------------|
| STT | `openrouter` | Cloud (Whisper via OpenRouter) |
| STT | `faster-whisper` | Lokal (braucht `pip install -e .[local]` ) |
| LLM | `openrouter` | Cloud (GPT-4.1-mini, Gemini, …) |
| LLM | `local-openai-compatible` | Lokal (llama.cpp oder Ollama) |
| TTS | `openrouter` | Cloud (GPT-4o-mini-TTS, Gemini-TTS, …) |
| TTS | `piper` | Lokal, schnell (braucht `pip install -e .[local]` + Stimmmodell) |
| TTS | `chatterbox` | Lokal, hohe Qualität + Voice-Cloning (eigener HTTP-Dienst) |
**Global (dauerhaft in `.env` ):**
```bash
# Profil wählen — empfohlen statt einzelne Provider zu setzen:
VA_PROFILE=hybrid
# Alternativ: einzelne Provider direkt setzen (überschreibt das Profil!):
DEFAULT_STT_PROVIDER=faster-whisper
DEFAULT_LLM_PROVIDER=local-openai-compatible
DEFAULT_TTS_PROVIDER=piper
```
**Pro Nutzer** (dauerhaft für diesen User, bis er es ändert):
```bash
curl -s -X PUT $URL/api/me/prefs \
-H "Authorization: Bearer $TOKEN" \
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
-H 'Content-Type: application/json' \
2026-06-18 16:55:05 +02:00
-d '{"llm_provider":"openrouter","tts_provider":"piper"}' | jq
```
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
**Pro Session** (gilt für alle Aufrufe mit dieser `session_id` ):
```bash
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
curl -s -X POST $URL/api/sessions/oma-anna/route \
-H 'Content-Type: application/json' \
2026-06-18 16:55:05 +02:00
-d '{"tts_provider":"openrouter","language":"de"}' | jq
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
```
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
**Pro Aufruf** (gilt nur für diesen einen Request):
```bash
curl -s -X POST "$URL/api/chat?debug=true" \
-H 'Content-Type: application/json' \
-d '{"text":"Test","llm_provider":"openrouter","tts_provider":"piper"}' | jq '.route'
```
2026-06-17 02:14:25 +02:00
2026-06-18 16:55:05 +02:00
Im Sprech-Loop per Flag:
2026-06-17 11:28:20 +02:00
```bash
2026-06-18 16:55:05 +02:00
python scripts/voice_loop.py \
2026-06-17 11:28:20 +02:00
--stt-provider faster-whisper \
--llm-provider local-openai-compatible \
--tts-provider openrouter
```
2026-06-18 16:55:05 +02:00
---
### 6.3 STT-Einstellungen (Spracherkennung)
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `OPENROUTER_STT_MODEL` | `openai/whisper-large-v3` | Cloud-Modell |
| `FASTER_WHISPER_MODEL` | `base` | Lokales Modell: `tiny\|base\|small\|medium\|large-v3` |
| `FASTER_WHISPER_DEVICE` | `auto` | Gerät: `auto\|cpu\|cuda` |
| `FASTER_WHISPER_COMPUTE_TYPE` | `default` | Precision: `default\|int8\|float16\|int8_float16` |
Für bessere Qualität bei Dialekt (braucht viel VRAM):
```bash
FASTER_WHISPER_MODEL=large-v3
FASTER_WHISPER_DEVICE=cuda
FASTER_WHISPER_COMPUTE_TYPE=float16
2026-06-17 22:11:20 +02:00
```
2026-06-20 22:26:20 +02:00
> **Hinweis:** Die Spracherkennung läuft auf **allen** Geräten serverseitig (Whisper) —
> einheitlich und zuverlässig. (Ein früher erprobtes Geräte-STT über die Web Speech API
> wurde wieder entfernt: Auf Android-Chrome lief es nur über die Google-Cloud, und die
> Erkennungsqualität war Whisper unterlegen. Das **Vorlesen** im Gerät (§ 6.5.0) bleibt.)
2026-06-20 20:08:10 +02:00
2026-06-18 16:55:05 +02:00
---
### 6.4 LLM-Einstellungen (Sprachmodell, lokal)
Diese Settings gelten nur für den Provider `local-openai-compatible` .
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `LOCAL_LLM_BASE_URL` | `http://127.0.0.1:8001/v1` | URL des lokalen LLM-Servers |
| `LOCAL_LLM_API_KEY` | `dummy` | Beliebiger Wert (bei Ollama: `ollama` ) |
| `LOCAL_LLM_MODEL` | `va_llm` | Modellname / Alias |
| `LOCAL_LLM_DISABLE_REASONING` | `true` | Qwen3-Denkphase abschalten (~9× schneller) |
| `LOCAL_LLM_SYSTEM_PROMPT` | Sprach-Prompt | Kurze, vorlesbare Antworten |
| `LOCAL_LLM_MAX_TOKENS` | `0` (Server-Limit) | Optionaler Deckel, z. B. `256` |
| `LOCAL_LLM_TEMPERATURE` | `0.3` | Sampling-Temperatur |
2026-06-20 18:46:33 +02:00
| `LOCAL_LLM_TOP_P` | `0.9` | Nucleus-Sampling (0.0– 1.0) |
> Temperatur, Top-p und Max-Tokens sind **Live-Parameter**: im Admin-Panel →
> Einstellungen änderbar und **ohne Neustart** sofort wirksam (pro Anfrage gesendet).
> Das **Kontextfenster** ist dagegen ein Startup-Wert (Ollama: `OLLAMA_CONTEXT_LENGTH`,
> llama.cpp: `-c`) und erfordert einen Backend-Neustart.
2026-06-18 16:55:05 +02:00
Messung (Qwen3-35B, `va_llm` ): Reasoning an → **5,5 s / 1433 Zeichen ** ;
Reasoning aus + Sprach-Prompt → **0,7 s / ~190 Zeichen ** .
System-Prompt leeren (für „freie" Gespräche ohne inhaltliche Einschränkung):
```bash
LOCAL_LLM_SYSTEM_PROMPT=
```
---
### 6.5 TTS-Einstellungen (Sprachsynthese)
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
Die Vorlese-Quelle wählt der Nutzer im Kopfzeilen-Menü **Qualität ** (→ § 5.1.2). Es gibt
vier Optionen: das **Gerät ** selbst (§ 6.5.0) oder einen der drei Server-Provider
**piper** (§ 6.5.2), **chatterbox ** (§ 6.5.3) bzw. **OpenRouter ** (§ 6.5.1).
#### 6.5.0 Geräte-TTS (Web Speech API) — „📱 Gerät"
Wählt der Nutzer * * „📱 Gerät"**, liest das Endgerät die Antwort **selbst ** vor (iPhone:
Safari/Siri-Stimmen, Android: System-TTS). Der Server erzeugt und überträgt dann **kein
Audio** — er schickt nur den Text. Das spart Mobilfunk-Daten und TTS-Rechenzeit/Kosten.
- **Vorteile:** keine Audio-Bytes, geringere Latenz, funktioniert auch ohne laufenden
TTS-Dienst.
- **Grenzen:** Stimme/Qualität hängen vom Gerät ab; deine eigenen Stimmen (Klon,
FLEURS-Referenzen) und der Aussprache-Normalizer/das Wörterbuch (§ 6.5.4) greifen **nicht ** .
- **Verhalten:** Auf Mobilgeräten ist „Gerät" voreingestellt (solange nichts gewählt wurde).
Die Wahl ist **geräte-lokal ** gespeichert (kein Server-Pref), da On-Device-Stimmen pro
Gerät verschieden sind. Browser ohne Web Speech API blenden die Option aus.
- **Technik:** Das Frontend sendet `text_only:true` ; die Antwortsprache je Bubble steuert
`SpeechSynthesisUtterance.lang` . iOS erlaubt Sprachausgabe erst nach einer Nutzergeste —
das Frontend schaltet sie beim ersten Tippen/Senden frei.
2026-06-18 16:55:05 +02:00
#### 6.5.1 Cloud-TTS (OpenRouter) — Stimmen wählen
Das Gateway reicht den Stimmennamen unverändert an OpenRouter weiter. Welche
Namen gültig sind, bestimmt das gewählte TTS-Modell:
**Gemini-TTS** (`google/gemini-3.1-flash-tts-preview` , empfohlen):
Verfügbare Stimmen (live verifiziert 2026-06-17): `Zephyr` , `Puck` , `Charon` , `Kore` ,
`Fenrir` , `Leda` , `Orus` , `Aoede` , `Callirrhoe` , `Enceladus` , `Iapetus` , `Umbriel` ,
`Algieba` , `Despina` , `Erinome` , `Algenib` , `Achernar` , `Schedar` , `Gacrux` , `Sulafat` .
**OpenAI-TTS** (`openai/gpt-4o-mini-tts` , TOML-Default):
Stimmen: `alloy` , `ash` , `ballad` , `coral` , `echo` , `fable` , `nova` , `onyx` , `sage` ,
`shimmer` , `verse` .
> Preview-Modelle liefern gelegentlich leer (HTTP 200, kein Audio) — das Gateway
> wiederholt den Aufruf automatisch bis zu 3 Mal. Eine einzelne
> „empty audio content"-Meldung war meist ein Aussetzer; einfach erneut versuchen.
Stimme dauerhaft setzen (in `.env` , dann Server neu starten):
```bash
OPENROUTER_TTS_MODEL=google/gemini-3.1-flash-tts-preview
OPENROUTER_TTS_VOICE=Zephyr
```
Stimme pro Aufruf:
```bash
curl -s -X POST $URL/api/speak \
-H 'Content-Type: application/json' \
-d '{"text":"Probe","voice":"Kore","tts_provider":"openrouter"}' --output probe.pcm
```
Im Sprech-Loop:
```bash
python scripts/voice_loop.py --tts-provider openrouter --voice Puck
```
#### 6.5.2 Lokales TTS (piper) — Stimmen und Modelle
piper läuft in-process — das Stimmmodell wird **einmal ** beim Server-Start geladen
und gecacht. Kein Subprozess pro Satz, kein Kaltstart beim ersten Turn.
Stimmmodell-Dateien (`<name>.onnx` + `<name>.onnx.json` ) liegen im `PIPER_VOICES_DIR`
(Default: `~/.local/share/piper/voices` ). Neue Stimmen von HuggingFace:
`rhasspy/piper-voices` → die zwei Dateien in das Verzeichnis kopieren, dann
`PIPER_VOICE` setzen und Server neu starten.
2026-06-19 13:41:03 +02:00
Aktuell installierte Stimmen (Stand 2026-06-19):
| `PIPER_VOICE` | Sprache | Qualität | Phoneme | Hinweis |
|---|---|---|---|---|
| `de_DE-thorsten-high` | Deutsch | **high ** | 154 | **Default ** , männlich |
| `en_US-ryan-high` | Englisch (US) | **high ** | 130 | männlich |
| `en_US-lessac-high` | Englisch (US) | **high ** | 154 | weiblich |
| `en_GB-cori-high` | Englisch (GB) | **high ** | 157 | weiblich, britischer Akzent |
| `es_ES-sharvard-medium` | Spanisch | medium* | 154 | männlich |
| `fr_FR-siwis-medium` | Französisch | medium* | 154 | weiblich, korrekte Nasalvokale |
| `it_IT-paola-medium` | Italienisch | medium* | 154 | weiblich |
| `nl_NL-mls-medium` | Niederländisch | medium* | 159 | mehrere Sprecher |
| `ru_RU-irina-medium` | Russisch | medium* | 151 | weiblich |
| `zh_CN-huayan-medium` | Chinesisch (Mandarin) | medium* | 152 | weiblich |
\* Für diese Sprachen existiert keine `high` -Variante in piper — `medium` ist das Maximum.
2026-06-18 16:55:05 +02:00
Stimme wechseln (in `.env` ):
```bash
PIPER_VOICE=de_DE-kerstin-low
```
Liefert ein Modell nicht 24000 Hz (z. B. `de_DE-thorsten-high` = 22050 Hz), resampelt
das Gateway automatisch per `ffmpeg` .
Im Sprech-Loop:
```bash
python scripts/voice_loop.py --tts-provider piper --voice de_DE-kerstin-low
```
#### 6.5.3 Chatterbox TTS (Voice-Cloning, hohe Qualität)
Chatterbox ist ein eigener HTTP-Dienst auf der GPU (Resemble AI, Port 9999). Er ist
deutlich langsamer als piper (~Echtzeit), aber deutlich natürlicher. Unterstützt
**Voice-Cloning** über eine Referenz-WAV. Setup: [deploy/README.md § 6 ](deploy/README.md ).
Aktivieren pro Request/Session:
```bash
curl -s -X POST $URL/api/chat \
2026-06-17 02:14:25 +02:00
-H 'Content-Type: application/json' \
2026-06-18 16:55:05 +02:00
-d '{"text":"Hallo!","tts_provider":"chatterbox"}' --output antwort.pcm
```
Konfiguration in `.env` :
```bash
CHATTERBOX_BASE_URL=http://127.0.0.1:9999
CHATTERBOX_VOICE=/pfad/zu/referenz_stimme.wav # leer = Standardstimme
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
CHATTERBOX_LANG=de # Fallback-Sprache (Gesprächssprache gewinnt)
2026-06-18 16:55:05 +02:00
CHATTERBOX_SPEED=1.0
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
CHATTERBOX_VOICES_DIR=config/voices # native Referenz-Stimmen je Sprache
2026-06-17 02:14:25 +02:00
```
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
**Mehrsprachig + native Stimme je Sprache.** Chatterbox ist mehrsprachig (de, en, fr,
es, it, nl, ru, zh u. a.) und klont **cross-lingual ** : Die Antwortsprache (→ § 6.6)
wird automatisch an den Dienst übergeben, und die passende Referenz-Stimme wird aus
`CHATTERBOX_VOICES_DIR` nach Konvention `<lang>.wav` gewählt (z. B. `fr.wav` , `zh.wav` ).
So spricht jede Sprache mit einer muttersprachlichen Stimme statt deutsch-akzentuiert.
- Reihenfolge der Stimm-Auswahl: explizit angefragte `voice` (WAV-Pfad) → `config/voices/<lang>.wav` → `CHATTERBOX_VOICE` (persönlicher Klon) → Standardstimme des Dienstes.
- Deutsch nutzt bewusst keine Datei in `config/voices/` , sondern `CHATTERBOX_VOICE` .
- Die mitgelieferten Referenz-Clips stammen aus dem FLEURS-Datensatz (CC-BY 4.0) —
Quelle/Lizenz/Austausch siehe `config/voices/README.md` .
2026-06-18 16:55:05 +02:00
#### 6.5.4 Aussprache verbessern (TTS-Normalizer)
Vor dem TTS läuft ein Normalizer, der Ausspracheprobleme des Phonemizers behebt:
- **Ordinalzahlen:** „1. Mai" → „erster Mai", „1. 2. 3." → „erstens, zweitens, drittens"
- **Einheiten nach Zahl:** „10 kg" → „zehn Kilogramm", „km/h" → „Kilometer pro Stunde"
- **Abkürzungen:** „Dr." → „Doktor", „z. B." → „zum Beispiel"
docs: § 6.5.4 Aussprache-Lexika vollständig dokumentiert (alle 8 Sprachen)
- YAML-Dateistruktur für alle Sprachen erklärt (de/en/fr/es/it/nl/ru/zh)
- Drei Sektionen (abbreviations/units/terms) mit Matching-Regeln
- Anleitung "Eigennamen in Fremdsprachen" — Textersetzungs-Prinzip statt IPA
mit Klangäquivalent-Tabelle (ʃ, y/ü, x, ts in je 6 Sprachen)
- Sonderfall RU/ZH: Kyrillisch/Hanzi notwendig, Lateinschrift unzuverlässig
- Drei Wege dokumentiert: Web-UI (de/en), REST-API (alle Sprachen, sofort),
direkte YAML-Bearbeitung (alle Sprachen, Neustart nötig)
- Test-Befehle: Admin-Test-Button, curl, Normalizer-Skript
- § 7.5 Wörterbuch-Tab: Hinweis auf de/en-Beschränkung + Verweis auf § 6.5.4
- API-Referenz: lang-Parameter auf alle Sprachcodes erweitert
- Stichwortverzeichnis: zwei neue Einträge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:34:08 +02:00
- **YAML-Lexikon:** eigene Begriffe — für jede Sprache eine eigene Datei
2026-06-18 16:55:05 +02:00
Stärke: `TTS_NORMALIZE_LEVEL=auto|full|light|off`
— `auto` = piper bekommt `full` , Cloud-TTS bekommt `light` (Cloud kann Zahlen selbst).
2026-06-17 02:14:25 +02:00
docs: § 6.5.4 Aussprache-Lexika vollständig dokumentiert (alle 8 Sprachen)
- YAML-Dateistruktur für alle Sprachen erklärt (de/en/fr/es/it/nl/ru/zh)
- Drei Sektionen (abbreviations/units/terms) mit Matching-Regeln
- Anleitung "Eigennamen in Fremdsprachen" — Textersetzungs-Prinzip statt IPA
mit Klangäquivalent-Tabelle (ʃ, y/ü, x, ts in je 6 Sprachen)
- Sonderfall RU/ZH: Kyrillisch/Hanzi notwendig, Lateinschrift unzuverlässig
- Drei Wege dokumentiert: Web-UI (de/en), REST-API (alle Sprachen, sofort),
direkte YAML-Bearbeitung (alle Sprachen, Neustart nötig)
- Test-Befehle: Admin-Test-Button, curl, Normalizer-Skript
- § 7.5 Wörterbuch-Tab: Hinweis auf de/en-Beschränkung + Verweis auf § 6.5.4
- API-Referenz: lang-Parameter auf alle Sprachcodes erweitert
- Stichwortverzeichnis: zwei neue Einträge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:34:08 +02:00
##### Eigene Aussprache hinzufügen (Deutsch / Englisch)
2026-06-19 01:15:28 +02:00
**Web-UI (empfohlen):** Admin-Panel → Tab „🔤 Wörterbuch" (→ § 7.5). Kein Neustart nötig.
**Kommandozeile:**
2026-06-18 16:55:05 +02:00
```bash
python scripts/add_pronunciation.py "strömt:ströhmt" # Wort:Aussprache
python scripts/add_pronunciation.py Mond Mohnd --verify # mit Phonem-Check
python scripts/add_pronunciation.py kWh "Kilowattstunden" --section units
```
2026-06-19 01:15:28 +02:00
Danach Server neu starten (damit der Cache geleert wird).
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
docs: § 6.5.4 Aussprache-Lexika vollständig dokumentiert (alle 8 Sprachen)
- YAML-Dateistruktur für alle Sprachen erklärt (de/en/fr/es/it/nl/ru/zh)
- Drei Sektionen (abbreviations/units/terms) mit Matching-Regeln
- Anleitung "Eigennamen in Fremdsprachen" — Textersetzungs-Prinzip statt IPA
mit Klangäquivalent-Tabelle (ʃ, y/ü, x, ts in je 6 Sprachen)
- Sonderfall RU/ZH: Kyrillisch/Hanzi notwendig, Lateinschrift unzuverlässig
- Drei Wege dokumentiert: Web-UI (de/en), REST-API (alle Sprachen, sofort),
direkte YAML-Bearbeitung (alle Sprachen, Neustart nötig)
- Test-Befehle: Admin-Test-Button, curl, Normalizer-Skript
- § 7.5 Wörterbuch-Tab: Hinweis auf de/en-Beschränkung + Verweis auf § 6.5.4
- API-Referenz: lang-Parameter auf alle Sprachcodes erweitert
- Stichwortverzeichnis: zwei neue Einträge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:34:08 +02:00
##### Aussprache für alle Sprachen — YAML-Lexika
Für jede aktive Sprache gibt es eine separate YAML-Datei im Verzeichnis `config/` :
```
config/
pronunciation.de.yaml # Deutsch
pronunciation.en.yaml # Englisch
pronunciation.fr.yaml # Französisch
pronunciation.es.yaml # Spanisch
pronunciation.it.yaml # Italienisch
pronunciation.nl.yaml # Niederländisch
pronunciation.ru.yaml # Russisch
pronunciation.zh.yaml # Chinesisch
```
Fehlende Dateien werden stillschweigend übersprungen (keine Pflicht für jede Sprache).
Jede Datei hat drei Sektionen:
```yaml
# config/pronunciation.de.yaml (Beispiel)
abbreviations: # Abkürzungen — ganze Token, wortgrenzen-sicher
"ggf.": "gegebenenfalls"
"inkl.": "inklusive"
units: # Einheiten — nur DIREKT nach einer Zahl ersetzt
"kWh": "Kilowattstunden"
terms: # Eigennamen / Begriffe — Groß-/Kleinschreibung egal
"Linux": "Linuks"
"Mond": "Mohnd"
```
| Sektion | Trifft | Beispiel |
|---------|--------|---------|
| `abbreviations` | ganze Wörter / Token mit Wortgrenze | `"z.B."` → `"zum Beispiel"` |
| `units` | nur nach einer Zahl (`\d\s*Einheit` ) | `"kg"` → `"Kilogramm"` (nur nach Zahl!) |
| `terms` | beliebiger Teiltext, Groß/Klein egal | `"Linux"` → `"Linuks"` |
**Längerer Eintrag gewinnt** — `"z. B."` wird vor `"B."` geprüft. Reihenfolge im YAML spielt keine Rolle.
##### Eigennamen in Fremdsprachen korrekt aussprechen
Das Lexikon arbeitet mit **Textersetzung ** — kein IPA nötig. Der eingetragene Text
wird von espeak-ng (in Piper) nach den Phonemregeln der **Zielsprache ** gelesen.
Das Ziel ist also: den Namen so schreiben, wie ihn ein Muttersprachler der Zielsprache
schreiben würde, damit er richtig klingt.
**Grundprinzip:**
```
Original: "Schlüter"
DE: kein Eintrag nötig (nativ)
FR: "Chluteur" → ch=/ʃ/ u=/y/ (= ü!) eur=/œʁ/ → /ʃlytœʁ/ ≈ /ʃlyː tɐ/
EN: "Schlueter" → espeak-en liest "ue" als /uː / → /ˈ ʃluː tər/ ✓
NL: "Schluuter" → nl "uu"=/yː / (= ü) sch=/sx/
RU: "Шлютер" → Kyrillisch für exakte Phoneme (Latein wird schlecht gelesen)
ZH: "施吕特" → 施=Shī=/ʃɨ/ 吕=lǚ=/ly/ (≈ lü!) 特=tè=/tɛ/
```
**Praktische Anleitung für einen neuen Eigennamen:**
1. Überlege, welche Laute der Name enthält.
2. Finde in der Zielsprache Buchstaben/Buchstabenkombinationen, die diese Laute erzeugen.
3. Trage den Ersatztext in `terms:` der passenden Sprachdatei ein.
4. Teste (→ unten).
**Häufige Klangäquivalente je Sprache:**
| Laut | DE | EN | FR | NL | RU | ZH |
|------|----|----|----|----|----|----|
| /ʃ/ | sch | sh | ch | sch (≈) | Ш | sh → 施/书 |
| /y/ (= ü) | ü | — | u | uu | Ю/Ю | ü → 吕/绿 |
| /x/ (= ch) | ch | kh | — | g/ch | Х | h → 哈 |
| /ts/ | z | ts | ts | ts | Ц | ts → 茨 |
**Sonderfall Russisch und Chinesisch:** espeak-ng liest lateinische Buchstaben
in russischem / chinesischem Modus schlecht. Immer Kyrillisch (RU) bzw. Hanzi (ZH) verwenden:
```yaml
# config/pronunciation.ru.yaml
terms:
"Schlüter": "Шлютер" # Ш=/ʃ/ лю=/lʲu/ тер=/tʲɛr/
"Dieter": "Дитер"
# config/pronunciation.zh.yaml
terms:
"Schlüter": "施吕特" # 施=Shī=/ʃɨ/ 吕=lǚ=/ly/ 特=tè=/tɛ/
"Dieter": "迪特"
```
##### Einträge hinzufügen — alle Wege im Überblick
**Weg 1 — Admin-Web-UI** (de/en, sofort wirksam):
Admin-Panel → Tab „🔤 Wörterbuch" → Sprache und Sektion wählen → Eintrag hinzufügen.
Der Cache wird automatisch geleert.
**Weg 2 — REST-API** (alle Sprachen, sofort wirksam):
```bash
# Französischen Eintrag hinzufügen (kein Neustart nötig):
curl -X POST http://localhost:8080/api/admin/pronunciation/fr \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{"section":"terms","key":"Schlüter","value":"Chluteur"}'
# Eintrag löschen:
curl -X DELETE http://localhost:8080/api/admin/pronunciation/fr/terms/Schlüter \
-H "Authorization: Bearer <admin-token>"
# Alle Einträge einer Sprache anzeigen:
curl http://localhost:8080/api/admin/pronunciation/ru \
-H "Authorization: Bearer <admin-token>"
```
**Weg 3 — YAML-Datei direkt editieren** (alle Sprachen):
```bash
nano config/pronunciation.fr.yaml # oder vim, gedit …
```
Danach **Server neu starten ** , damit der In-Memory-Cache geleert wird:
```bash
make restart # oder: systemctl --user restart voice-assistant
```
##### Aussprache testen
Nach dem Hinzufügen eines Eintrags kannst du den Effekt sofort prüfen:
**Admin-Panel → Tab „⚙ Einstellungen" → Feld „Piper-Stimme" → Test-Button:**
Spricht den Testsatz mit der aktuell eingestellten Stimme und Sprache.
**Oder via curl:**
```bash
curl -s -X POST http://localhost:8080/api/speak \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"text":"Hallo, ich bin Dieter Schlüter.","tts_provider":"piper","language":"fr"}' \
--output /tmp/test.wav && aplay /tmp/test.wav
```
**Oder mit dem Normalizer-Skript allein** (kein Server nötig):
```bash
source .venv/bin/activate
python3 -c "
import asyncio
from app.pipeline.tts_normalizer import TTSNormalizer
t = TTSNormalizer()
result = asyncio.run(t.run('Schlüter kommt.', language='fr', level='full'))
print(result) # → 'Chluteur kommt.'
"
```
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
---
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
### 6.6 Sprache wechseln (Fix / Flex)
Die Antwortsprache wird in der Web-Oberfläche über **ein einziges Dropdown ** („Sprache")
gesteuert. Es kennt zwei Arten von Werten:
| Auswahl | Bedeutung | Whisper (STT) | LLM-Antwort + Stimme |
|---------|-----------|---------------|----------------------|
| * * 🔄 Flex** | keine feste Sprache — folgt automatisch der gesprochenen | erkennt die Sprache, **übersetzt nicht ** | in der **erkannten ** Sprache (blaue Blase zeigt das Original) |
| * * 🇩🇪 / 🇬🇧 / … (feste Sprache)** | „Fix": System bleibt bei dieser Sprache | bekommt die feste Sprache → **übersetzt ** die Eingabe | immer in der **festen ** Sprache, egal worin gefragt wurde |
**Beispiele** (Eingabe auf Französisch gesprochen):
- **Flex** → blaue Blase: französischer Originaltext · Antwort + Stimme: Französisch.
- **🇩🇪 DE** → blaue Blase: deutsche Übersetzung · Antwort + Stimme: Deutsch.
Die vorlesende Piper-Stimme folgt immer der Antwortsprache automatisch (z. B. `thorsten`
für Deutsch, `siwis` für Französisch — Zuordnung → `LANG_TO_PIPER_VOICE` ). Bei Text-Chat
im Flex-Modus (keine Audio-Erkennung möglich) bekommt das LLM **keine ** Sprachvorgabe und
antwortet von selbst in der Sprache der Eingabe; als Fallback gilt `DEFAULT_LANGUAGE` .
> **Hinweis:** Es gibt kein separates „Fix/Flex"-Menü mehr — eine konkrete Sprache zu
> wählen *ist* der Fix-Modus, „🔄 Flex" der flexible. Intern bleiben zwei Felder
> erhalten: `language` (ISO-Code) und `language_mode` (`fix` | `flex`).
**Konfiguration außerhalb der Web-UI:**
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
2026-06-18 16:55:05 +02:00
```bash
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
DEFAULT_LANGUAGE=de # global in .env (Fallback-/Standardsprache)
DEFAULT_LANGUAGE_MODE=fix # global: fix | flex (Admin: Tab „⚙ Einstellungen")
2026-06-18 16:55:05 +02:00
```
2026-06-17 02:14:25 +02:00
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
Pro Nutzer (dauerhaft):
2026-06-17 02:14:25 +02:00
```bash
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
# Feste Sprache (Fix):
curl -X PUT $URL/api/me/prefs -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"language":"en","language_mode":"fix"}'
# Flex (Sprache folgt automatisch):
curl -X PUT $URL/api/me/prefs -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"language_mode":"flex"}'
2026-06-17 02:14:25 +02:00
```
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
Pro Aufruf: `{"text":"…","language":"en","language_mode":"fix"}` im Body.
2026-06-18 16:55:05 +02:00
---
### 6.7 Audio-Geräte (Mikrofon, Lautsprecher, Bluetooth)
> Hinweis: Die Geräte-Endpunkte im Gateway (`input_endpoint`/`output_endpoint`) sind
> vorbereitet (Routing-Ebene, `GET /api/devices`), aber die Hardware-Treiber sind noch
> Platzhalter — kein echtes I/O durch das Gateway. Geräteauswahl erfolgt heute auf
> **Betriebssystem-Ebene**.
**Empfohlen: Ubuntu-Systemeinstellungen (grafisch)**
1. * Einstellungen → Ton * öffnen.
2. **Ausgabe: ** gewünschtes Gerät wählen (z. B. Bluetooth-Box).
3. **Eingabe: ** Mikrofon wählen (z. B. reSpeaker). Pegelbalken zeigt Schall.
Bluetooth-Box koppeln (einmalig): *Einstellungen → Bluetooth → Box in Kopplungsmodus →
Verbinden*. Danach erscheint sie unter Ton → Ausgabe.
**Per Kommandozeile:**
2026-06-17 02:14:25 +02:00
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
```bash
2026-06-18 16:55:05 +02:00
arecord -l # Karten-/Gerätennummern (hw:X,Y)
pactl list short sources # Mikrofone
pactl list short sinks # Ausgaben (inkl. Bluetooth)
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
2026-06-18 16:55:05 +02:00
# Standard-Gerät setzen:
pactl set-default-source <SOURCE_NAME>
pactl set-default-sink <SINK_NAME>
```
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
2026-06-18 16:55:05 +02:00
Der Sprech-Loop folgt mit `--recorder auto` automatisch dem System-Standard.
Bestimmtes Mikrofon erzwingen:
```bash
python scripts/voice_loop.py --recorder arecord --device plughw:6,0
```
(`arecord -l` zeigt Kartennummer; auf diesem Rechner: M2-Mic = Karte 5, reSpeaker = Karte 6)
---
### 6.8 Streaming-Verhalten
| Variable | Default | Wirkung |
|----------|---------|---------|
| `AUDIO_STREAM_DEFAULT` | `true` | Satzweises Audio-Streaming als Standard |
Mit `audio_stream=true` (Standard bei WebSocket) beginnt die Ausgabe nach dem ersten
Satz — spürbar kürzere wahrgenommene Latenz. Abschalten:
```bash
# global:
AUDIO_STREAM_DEFAULT=false
# pro Aufruf im Sprech-Loop:
python scripts/voice_loop.py --no-stream-audio
```
2026-06-18 18:44:53 +02:00
**Barge-in** (laufende Antwort unterbrechen):
- **Web-Interface:** Mic-Button ⏹ (amber) während der KI-Antwort tippen → Wiedergabe stoppt sofort, Server bricht Generierung ab.
2026-06-19 00:39:00 +02:00
- **Terminal:** `[Enter]` drücken, sobald die KI antwortet — egal ob Text noch streamt oder Audio bereits läuft → dasselbe Ergebnis.
2026-06-18 18:44:53 +02:00
- **API/eigene Clients:** WebSocket-Event `{"type":"interrupt"}` senden → Server stoppt Streaming und meldet `{"type":"interrupted"}` .
2026-06-18 16:55:05 +02:00
**VAD** (automatische Sprechpausen-Erkennung): Im Start-Frame von `/ws/voice`
`{"type":"start","vad":true,"format":"pcm","sample_rate":16000}` → kein manuelles Ende nötig.
Optional: `vad_silence_ms` , `vad_threshold` .
---
## 7. Nutzerverwaltung und Authentifizierung
> 🔧 Admin
### 7.1 Auth aktivieren/deaktivieren
```bash
AUTH_ENABLED=true # Standard: geschützte Endpunkte brauchen Bearer-Token
AUTH_ENABLED=false # Lokal/Entwicklung: anonymer Standardnutzer, kein Token nötig
```
Geschützte Endpunkte: `chat` , `speak` , `transcribe` , `sessions` , `me` .
2026-06-18 17:55:05 +02:00
### 7.2 SSO-Nutzer (va.linix.de) — automatische Registrierung
Nutzer, die über den YunoHost-SSO kommen (`https://va.linix.de/` ), werden **beim ersten
Besuch automatisch registriert** — kein manuelles Anlegen nötig.
Der genaue Ablauf:
1. YunoHost-SSO authentifiziert den Nutzer (nur eingeloggte YunoHost-Nutzer durch)
2. Der Benutzername aus dem JWT-Cookie (`yunohost.portal` ) wird ans Gateway weitergegeben
3. Gateway ruft intern `get_or_create_user_by_external_id(username)` auf:
- Erster Besuch → neuer Datenbankdatensatz (UUID-ID, `external_id = YunoHost-Username` )
- Folgender Besuch → selber Datensatz
4. Jeder Nutzer hat ab sofort **eigene ** Sessions, Erinnerungen und Präferenzen
**Kein Bearer-Token** — SSO-Nutzer authentifizieren sich ausschließlich über den YunoHost-Cookie.
**Persönlichkeit und Kontextwissen der KI:**
Das Sprachmodell kennt den Nutzer über zwei Kanäle:
- `display_name` wird bei jeder Anfrage als `"Du sprichst mit <Name>."` ins System-Prompt injiziert
- Erinnerungen (automatisch extrahiert + manuell angelegt) folgen darunter
#### Anzeigenamen setzen (nach erstem SSO-Login)
Nach dem ersten Besuch steht im Datensatz als `display_name` der YunoHost-Username
(z. B. `"dschlueter"` ). Die KI würde den Nutzer mit diesem Systemnamen ansprechen.
Ein Admin setzt einen echten Namen:
```bash
# user_id aus der Nutzerliste holen:
curl -s $URL/api/admin/users -H "X-Admin-Key: $ADMIN_API_KEY" | jq '.[].user_id'
USER_ID=a3f8c1d2e4b7... # user_id des betroffenen Nutzers
curl -s -X PUT $URL/api/admin/users/$USER_ID \
-H "X-Admin-Key: $ADMIN_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"display_name":"Oma Anna"}' | jq
```
Antwort:
```json
{ "user_id": "a3f8c1d2e4b7...", "display_name": "Oma Anna" }
```
Ab dem nächsten Gespräch sagt die KI „Guten Tag, Anna" statt „Guten Tag, dschlueter".
#### Initiale Erinnerungen vorbelegen
Ohne vorher gespeicherte Erinnerungen beginnt die KI jedes Gespräch mit Neuem.
Ein Admin kann Kontext vorab anlegen, damit die KI von Anfang an personalisiert reagiert:
```bash
curl -s -X POST $URL/api/admin/users/$USER_ID/memories \
-H "X-Admin-Key: $ADMIN_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"content":"Anna ist 78 Jahre alt, wohnt allein in Hamburg und mag klassische Musik."}' | jq
```
Antwort:
```json
{ "id": 1, "content": "Anna ist 78 Jahre alt...", "created_at": "2026-06-18T10:00:00+00:00" }
```
Mehrere Erinnerungen sind möglich — einfach den Aufruf wiederholen. Beim nächsten Gespräch
bekommt das LLM als System-Nachricht:
```
Du sprichst mit Oma Anna.
Was du über den Nutzer weisst:
- Anna ist 78 Jahre alt, wohnt allein in Hamburg und mag klassische Musik.
```
#### Empfohlener Workflow für neue SSO-Nutzer
```
1. Nutzer loggt sich einmal bei https://va.linix.de/ ein
→ Datensatz wird automatisch angelegt
2. Admin: GET /api/admin/users → user_id notieren
3. Admin: PUT /api/admin/users/{id}
→ {"display_name": "Oma Anna"}
4. Optional: POST /api/admin/users/{id}/memories
→ 1-3 Sätze über die Person
5. Ab dem nächsten Gespräch ist die KI sofort personalisiert.
```
> **Hinweis:** Nutzer, die per `POST /api/admin/users` mit Bearer-Token angelegt werden,
> und SSO-Nutzer sind **getrennte Identitäten**. Es gibt keine Verknüpfung. Für
> va.linix.de-Nutzer daher **nicht** manuell vorab anlegen — das würde zu zwei getrennten
> Datensätzen führen.
---
### 7.3 Nutzer anlegen, anzeigen und löschen (Bearer-Token-Nutzer)
> Für Nutzer **ohne** SSO-Zugang (z. B. lokale Nutzung, API-Clients, curl/CLI).
2026-06-18 17:23:25 +02:00
**Voraussetzung:** `ADMIN_API_KEY` muss beim Gateway-Start als Umgebungsvariable gesetzt sein.
Einmal setzen (gilt für alle folgenden Befehle im Terminal):
2026-06-18 16:55:05 +02:00
```bash
2026-06-18 17:23:25 +02:00
export ADMIN_API_KEY=mein-langes-geheimnis
```
#### Nutzer anlegen
2026-06-18 16:55:05 +02:00
2026-06-18 17:23:25 +02:00
```bash
2026-06-18 16:55:05 +02:00
curl -s -X POST $URL/api/admin/users \
-H "X-Admin-Key: $ADMIN_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"display_name":"Oma Anna"}' | jq
2026-06-18 17:23:25 +02:00
```
2026-06-18 16:55:05 +02:00
2026-06-18 17:23:25 +02:00
Beispiel-Antwort:
```json
{
"user_id": "a3f8c1d2e4b7...",
"display_name": "Oma Anna",
"token": "va-tok-AbCdEfGh12345..."
}
```
> ⚠️ Das Token erscheint **nur einmal** — sofort sicher aufbewahren (z. B. in einem
2026-06-18 17:36:41 +02:00
> Passwort-Manager oder `~/.bashrc`). Es wird nur als SHA256-Hash in der Datenbank
> gespeichert — der Klartext ist danach **nicht mehr abrufbar**.
>
> Token verloren? → Neues Token ausstellen (s. u.) oder Nutzer löschen und neu anlegen.
2026-06-18 17:23:25 +02:00
Das Token dem Nutzer mitteilen. Er gibt es bei jedem Aufruf im `Authorization` -Header an:
```bash
2026-06-18 17:36:41 +02:00
TOKEN=va-tok-AbCdEfGh12345... # einmal setzen, z.B. in ~/.bashrc:
# export TOKEN=va-tok-AbCdEfGh12345...
2026-06-18 16:55:05 +02:00
curl -s $URL/api/me -H "Authorization: Bearer $TOKEN" | jq
2026-06-18 17:23:25 +02:00
# → {"user_id":"a3f8c1d2e4b7…","display_name":"Oma Anna","prefs":{}}
```
2026-06-18 17:36:41 +02:00
#### Token neu ausstellen (bei Verlust oder Rotation)
Falls das Token verloren gegangen ist oder aus Sicherheitsgründen gewechselt werden soll:
```bash
curl -s -X POST $URL/api/admin/users/$USER_ID/token \
-H "X-Admin-Key: $ADMIN_API_KEY" | jq
```
Beispiel-Antwort:
```json
{
"user_id": "a3f8c1d2e4b7...",
"display_name": "Oma Anna",
"token": "va-tok-NeuErKlArTeXt..."
}
```
Der **alte Token wird sofort ungültig ** . Der neue Token erscheint ebenfalls nur einmal —
alle bisherigen Daten (Erinnerungen, Gesprächsverlauf) bleiben erhalten.
> **Woher kommt `$ADMIN_API_KEY`?** Dieser Key ist in der Datei `.env` auf dem Server
> hinterlegt. Nachschauen mit:
> ```bash
> grep ADMIN_API_KEY .env
> # ADMIN_API_KEY=mein-geheimes-admin-passwort
> ```
> Du hast ihn beim Setup selbst gewählt. Er ist **kein** auto-generierter Hash —
> du kannst ihn jederzeit in `.env` lesen und bei Bedarf ändern (Gateway neu starten).
2026-06-18 17:23:25 +02:00
#### Alle Nutzer anzeigen
2026-06-18 16:55:05 +02:00
2026-06-18 17:23:25 +02:00
```bash
2026-06-18 16:55:05 +02:00
curl -s $URL/api/admin/users -H "X-Admin-Key: $ADMIN_API_KEY" | jq
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
```
2026-06-17 04:26:55 +02:00
2026-06-18 17:23:25 +02:00
Beispiel-Antwort:
```json
[
{
"user_id": "a3f8c1d2e4b7...",
"display_name": "Oma Anna",
"external_id": null,
"created_at": "2026-06-18T10:00:00+00:00"
},
{
"user_id": "b9e2f5a1c6d3...",
"display_name": "Herr Müller",
"external_id": null,
"created_at": "2026-06-18T11:30:00+00:00"
}
]
```
#### Nutzer löschen
Löscht den Nutzer **und alle seine Daten ** (Sessions, Gesprächsverlauf, Erinnerungen,
Nutzungsstatistik) unwiderruflich.
```bash
USER_ID=a3f8c1d2e4b7... # user_id aus der Liste oben
curl -s -X DELETE $URL/api/admin/users/$USER_ID \
-H "X-Admin-Key: $ADMIN_API_KEY" | jq
```
Beispiel-Antwort bei Erfolg:
```json
{ "deleted": "a3f8c1d2e4b7..." }
```
Nutzer nicht gefunden → HTTP 404:
```json
{ "detail": "Nutzer 'xyz' nicht gefunden." }
```
#### Dauerhafte Nutzerpräferenzen setzen
2026-06-18 16:55:05 +02:00
```bash
curl -s -X PUT $URL/api/me/prefs \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"tts_provider":"piper","language":"de","daily_request_limit":100}' | jq
```
Fremde Sessions → HTTP 403.
2026-06-18 17:55:05 +02:00
### 7.4 SSO / YunoHost-Integration (Remote-Betrieb)
2026-06-18 16:55:05 +02:00
Der Gateway akzeptiert Identitäten von einem Reverse-Proxy per Cookie oder Header —
ausschließlich von vertrauenswürdigen Proxy-IPs (`TRUSTED_PROXY_IPS` ):
```bash
# YunoHost-Cookie (empfohlen):
TRUSTED_AUTH_COOKIE=yunohost.portal
TRUSTED_AUTH_COOKIE_CLAIM=user
TRUSTED_PROXY_IPS=192.168.179.10
ADMIN_USERS=atoor,dieterschlueter,dschlueter
SSO_LOGOUT_URL=https://linix.de/yunohost/sso/?action=logout
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
SSO_LOGIN_URL=https://linix.de/yunohost/sso/ # unauth. Seitenaufrufe -> hierhin umleiten
2026-06-18 16:55:05 +02:00
# Optional: Signaturprüfung des JWT-Cookies
TRUSTED_AUTH_JWT_SECRET=<hs256-secret aus /etc/yunohost/.ssowat_cookie_secret>
# Alternativ: Header-basiert (andere SSO-Systeme):
TRUSTED_AUTH_HEADER=X-Remote-User
```
Vollständige Anleitung: [deploy/README.md ](deploy/README.md ).
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
**Zugriffsschutz der Web-UI (mehrstufig):**
1. **YunoHost SSOwat (primär): ** Die App-Berechtigung darf die Gruppe „visitors" nicht
enthalten → unauthentifizierte Besucher werden zum Portal umgeleitet, bevor sie das
Gateway erreichen: `yunohost user permission update <APP>.main --remove visitors --add all_users` .
2. **Gateway, API/WS: ** Anfragen über den Proxy ohne gültiges `yunohost.portal` -Cookie
bekommen 401 (auch bei `AUTH_ENABLED=false` — das betrifft nur den LAN-Direktzugriff).
3. **Gateway, statische Seite: ** Unauthentifizierte Seitenaufrufe werden auf `SSO_LOGIN_URL`
umgeleitet (bzw. 401, falls nicht gesetzt) — Defense-in-Depth, falls SSOwat umgangen wird.
4. **Port: ** Das Gateway sollte nicht offen im Netz lauschen (`HOST=127.0.0.1` bzw. Firewall
auf die Proxy-IP), damit der SSO-Weg nicht per Direktzugriff umgangen werden kann.
2026-06-19 01:15:28 +02:00
### 7.5 Admin-Web-Panel
> 🔧 Admin — erreichbar über den **⚙️-Button** im Web-Interface (nur für Admin-Nutzer sichtbar)
2026-06-20 23:11:57 +02:00
Das Admin-Panel öffnet sich als Vollbild-Overlay über dem Chat und gliedert sich in
**fünf Bereiche**. Bereiche mit mehreren Ansichten zeigen darunter eine Sub-Navigation:
2026-06-19 01:15:28 +02:00
2026-06-20 23:11:57 +02:00
| Bereich | Inhalt |
|---------|--------|
| * * 📊 Übersicht** | Start-Dashboard: Kennzahlen (Nutzer, Anfragen gesamt, Notfälle) + LLM-Backend/GPU; Direktsprünge |
| * * 👥 Nutzer** | Sub-Tabs * Verwalten * (anlegen/umbenennen/Token/löschen, Erinnerungen) und * Gespräche * (Transkripte) |
| * * 🚨 Notfälle** | protokollierte Notfall-Ereignisse |
| * * 🖥 System** | Sub-Tabs * Status * (inkl. LLM-Steuerung), * Metriken * , * Log * |
| * * ⚙ Konfiguration** | Sub-Tabs * Einstellungen * (Laufzeit-Config) und * Wörterbuch * (Aussprache) |
#### Übersicht
Beim Öffnen sichtbar: Kacheln mit Nutzerzahl, Anfragen gesamt, Notfall-Anzahl und
aktivem LLM-Backend/Modell, dazu die GPU-Auslastung und Schnell-Sprünge in die Bereiche.
#### Nutzer › Verwalten
2026-06-19 01:15:28 +02:00
Nutzer anlegen (Name eingeben → „Anlegen" → Token erscheint **einmalig ** — sofort kopieren!),
umbenennen, Token zurücksetzen und löschen. Erinnerungen je Nutzer auf- und zuklappen,
neue Erinnerungen hinzufügen oder vorhandene löschen.
2026-06-20 23:11:57 +02:00
#### Nutzer › Gespräche
2026-06-19 01:15:28 +02:00
Nutzerliste links → Session auswählen → Gesprächs-Transkript als Chat-Bubbles ansehen.
#### Notfälle
Tabellarische Übersicht aller protokollierten Notfall-Ereignisse (Zeitpunkt, Nutzer,
Kategorie, Textausschnitt).
2026-06-20 23:11:57 +02:00
#### System › Status
2026-06-19 01:15:28 +02:00
Zeigt aktives Profil, Provider-Konfiguration, Laufzeit-Metriken und verfügbare Provider.
2026-06-20 18:39:59 +02:00
Zusätzlich eine **LLM-Backend-Karte ** : aktives Backend (Ollama/llama.cpp), Modell, ob
die Backends laufen, geladene Ollama-Modelle und die **GPU-Auslastung ** je Karte als
Balken. Darunter eine **Steuerung ** : Backend wählen (+ Ollama-Modell), * * „Backend
wechseln"** und * * „Gateway neu starten"**.
> Sicherheit: Backend ist auf `ollama|llamacpp` beschränkt, Modellnamen werden gegen
> `ollama list` und ein striktes Format geprüft (kein Shell-Zugriff, kein sudo). Der
> Wechsel läuft losgelöst; die Seite pollt, bis das Gateway wieder antwortet.
> **Wirkt vollständig nur, wenn das Gateway als systemd-Dienst läuft** (→ § 4.10) —
> im Vordergrund-Betrieb werden `.env`/Backend umgestellt, der Gateway muss aber manuell
> neu gestartet werden.
Am Ende: * * ⬇ voice-assistant.db herunterladen** — lädt die SQLite-Datenbank als Backup.
2026-06-19 01:15:28 +02:00
2026-06-20 23:11:57 +02:00
#### System › Metriken
2026-06-19 01:15:28 +02:00
Nutzungsstatistik je Nutzer (Anfragen, Einheiten, letzte Aktivität) als Tabelle
und CSS-Balkendiagramm.
2026-06-20 23:11:57 +02:00
#### Konfiguration › Wörterbuch
2026-06-19 01:15:28 +02:00
Aussprache-Lexikon direkt im Browser bearbeiten — kein Kommandozeilen-Skript nötig:
2026-06-20 23:11:57 +02:00
1. Sprache wählen (alle 8 Sprachen: de, en, fr, es, it, nl, ru, zh).
2026-06-19 01:15:28 +02:00
2. Sektion wählen: **Abkürzungen ** , **Einheiten ** , **Begriffe / Aussprache ** .
2026-06-20 23:11:57 +02:00
3. Eintrag bearbeiten: Zeile anklicken → lädt in die Felder unten (Button wird zu „Speichern").
4. Eintrag löschen: Maus drüber → * * ✕**.
5. Neuer Eintrag: Schlüssel + Ersetzung → * * + Hinzufügen**.
Die Liste wird nach jedem Speichern alphabetisch sortiert; Änderungen greifen sofort
(Server-Cache wird automatisch geleert). Vollständige Anleitung → § 6.5.4.
docs: § 6.5.4 Aussprache-Lexika vollständig dokumentiert (alle 8 Sprachen)
- YAML-Dateistruktur für alle Sprachen erklärt (de/en/fr/es/it/nl/ru/zh)
- Drei Sektionen (abbreviations/units/terms) mit Matching-Regeln
- Anleitung "Eigennamen in Fremdsprachen" — Textersetzungs-Prinzip statt IPA
mit Klangäquivalent-Tabelle (ʃ, y/ü, x, ts in je 6 Sprachen)
- Sonderfall RU/ZH: Kyrillisch/Hanzi notwendig, Lateinschrift unzuverlässig
- Drei Wege dokumentiert: Web-UI (de/en), REST-API (alle Sprachen, sofort),
direkte YAML-Bearbeitung (alle Sprachen, Neustart nötig)
- Test-Befehle: Admin-Test-Button, curl, Normalizer-Skript
- § 7.5 Wörterbuch-Tab: Hinweis auf de/en-Beschränkung + Verweis auf § 6.5.4
- API-Referenz: lang-Parameter auf alle Sprachcodes erweitert
- Stichwortverzeichnis: zwei neue Einträge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:34:08 +02:00
2026-06-20 23:11:57 +02:00
#### System › Log
2026-06-19 01:15:28 +02:00
Zeigt den systemd-Journal-Log des `voice-assistant.service` live im Browser:
1. * * ▶ Verbinden** → letzte 100 Zeilen + laufende Ausgabe erscheinen im Terminal-Fenster.
2. * * ■ Trennen** → Stream stoppen.
3. **Leeren ** → Anzeige leeren (Log auf dem Server bleibt erhalten).
Der Log hilft, Fehler zu diagnostizieren ohne SSH-Zugang.
2026-06-20 18:50:55 +02:00
**Audit:** Schreibende Admin-Aktionen werden mit Auslöser protokolliert und erscheinen
hier live, z. B.:
```
ADMIN action=config_set user=dschlueter key='local_llm_top_p' value='0.7'
ADMIN action=llm_backend_switch user=dschlueter backend='ollama' model='gemma3:latest'
ADMIN action=gateway_restart user=admin-key
```
Protokolliert werden u. a. `config_set` / `config_reset` (Laufzeit-Einstellungen),
`llm_backend_switch` (+ `_rejected` bei Allowlist-Verstoß) und `gateway_restart` .
`user` ist der SSO-Name bzw. `admin-key` bei Zugriff per `ADMIN_API_KEY` .
> Sichtbar im Log-Tab nur im **Dienst-Betrieb** (Journal). Im Vordergrund-Betrieb
> (`make run`) erscheinen die Audit-Zeilen im Terminal.
2026-06-18 16:55:05 +02:00
---
## 8. Gedächtnis und Erinnerungen
> 👤 Endnutzer / 🔧 Admin
2026-06-18 17:29:04 +02:00
**Woher kommt `$TOKEN` ?** Das Token erscheint einmalig beim Anlegen eines Nutzers
2026-06-18 17:55:05 +02:00
(→ § 7.3). Im Terminal einmal setzen:
2026-06-18 17:29:04 +02:00
```bash
TOKEN=va-tok-AbCdEfGh12345...
```
Bei `AUTH_ENABLED=false` (lokale Entwicklung) ist kein Token nötig —
`-H "Authorization: Bearer $TOKEN"` dann einfach weglassen.
2026-06-18 16:55:05 +02:00
### 8.1 Sitzungsgedächtnis (Kurzzeit)
Mit `?session_id=name` merkt sich der Assistent den Gesprächsverlauf der aktuellen
Sitzung. Die letzten `HISTORY_MAX_MESSAGES` (Standard: 10) Nachrichten fließen als
Kontext ins LLM. Ohne `session_id` ist jeder Aufruf zustandslos.
```bash
curl -s -X POST "$URL/api/chat?session_id=oma-anna" \
-H 'Content-Type: application/json' -d '{"text":"Ich heiße Anna."}' --output /dev/null
curl -s -X POST "$URL/api/chat?session_id=oma-anna&debug=true" \
-H 'Content-Type: application/json' -d '{"text":"Wie heiße ich?"}' | jq '.trace'
```
### 8.2 Langzeit-Erinnerungen (manuell)
Dauerhafte Fakten und Vorlieben, die bei jedem Chat als Kontext ans LLM gehen —
unabhängig von der Session.
```bash
# Erinnerung hinzufügen:
curl -s -X POST $URL/api/me/memories \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"content":"Mag morgens Kamillentee."}' | jq
# Alle Erinnerungen anzeigen:
curl -s $URL/api/me/memories -H "Authorization: Bearer $TOKEN" | jq
# Erinnerung löschen:
curl -s -X DELETE $URL/api/me/memories/<id> -H "Authorization: Bearer $TOKEN"
```
In der Datenbank direkt ansehen/löschen (nötig z. B. wenn eine falsch extrahierte
Erinnerung stört):
```bash
python3 -c "
import sqlite3; conn = sqlite3.connect('data/voice-assistant.db')
for r in conn.execute('SELECT id, content FROM memories'): print(r)
"
# Löschen:
python3 -c "
import sqlite3; conn = sqlite3.connect('data/voice-assistant.db')
conn.execute('DELETE FROM memories WHERE content LIKE \"%Stichwort%\"'); conn.commit()
"
```
### 8.3 Automatische Erinnerungsextraktion
Nach je N Turns (Standard: 3) destilliert ein LLM dauerhaft wirkende Fakten und
Vorlieben aus dem Gespräch und legt sie als Erinnerungen ab. Der Prozess läuft als
**Hintergrund-Task** — kein Einfluss auf die Antwortlatenz.
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `MEMORY_EXTRACTION_ENABLED` | `true` | Extraktion ein/aus |
| `MEMORY_EXTRACTION_EVERY_N_TURNS` | `3` | Wie oft extrahiert wird |
| `MEMORY_EXTRACTION_MAX` | `50` | Maximale Anzahl gespeicherter Erinnerungen |
| `MEMORY_EXTRACTION_PROVIDER` | (leer = Default-LLM) | Welcher Provider extrahiert |
Besonders nützlich mit lokalem LLM (kostenloser Zusatzaufruf). Bei Cloud-LLM entstehen
geringe Zusatzkosten pro Extraktion.
---
## 9. Resilienz, Fallbacks und Metriken
> 🔧 Admin
### 9.1 Fallback-Ketten
Fällt der primäre Provider aus (Timeout, HTTP-Fehler), übernimmt transparent der nächste:
```bash
# in .env (kommasepariert, mehrere möglich):
STT_FALLBACK=faster-whisper
LLM_FALLBACK=local-openai-compatible
TTS_FALLBACK=piper
```
Erfolgreiche Fallbacks und Fehler werden in den Metriken gezählt.
### 9.2 Metriken und Monitoring
2026-06-17 04:26:55 +02:00
```bash
2026-06-18 16:55:05 +02:00
curl -s $URL/api/metrics | jq # JSON (alle Zähler + Latenzen)
curl -s "$URL/api/metrics?format=prometheus" # Prometheus-Text
# Nur Pipeline-Latenzen:
curl -s $URL/api/metrics | jq '
.timers | to_entries
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
| map(select(.key|test("stage_duration")))
2026-06-18 16:55:05 +02:00
| map({stufe:.key, avg_s:.value.avg})'
2026-06-17 04:26:55 +02:00
```
2026-06-18 16:55:05 +02:00
In-Memory pro Prozess — kein externer Dienst nötig. Bei Neustart auf null.
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
**Gemessene Richtwerte** (Profil `cloud` , gegen OpenRouter, Stand 2026-06-17):
| Stufe | Modell | ~Zeit |
|-------|--------|-------|
| STT | `whisper-large-v3` | ~1,2 s |
| LLM | `gemini-3.1-flash-lite` | ~0,7 s |
| TTS | `gemini-3.1-flash-tts` | ~1,9 s |
2026-06-18 16:55:05 +02:00
| **Sprach-Round-Trip ** | — | * * ~4 s** |
2026-06-17 04:26:55 +02:00
2026-06-18 16:55:05 +02:00
### 9.3 Tageskontingent (Kostenbremse)
2026-06-17 04:26:55 +02:00
2026-06-18 16:55:05 +02:00
```bash
DAILY_REQUEST_LIMIT=200 # Anfragen/Nutzer/Tag; 0 = unbegrenzt
```
2026-06-17 05:06:58 +02:00
2026-06-18 16:55:05 +02:00
Überschreitung → HTTP 429 (auch als `error` -Event im WebSocket). Notfall-Eingaben
werden **nie ** blockiert, auch bei Limit.
2026-06-17 04:51:49 +02:00
2026-06-18 16:55:05 +02:00
Pro Nutzer übersteuern: `daily_request_limit` in `PUT /api/me/prefs` .
2026-06-17 02:14:25 +02:00
2026-06-18 16:55:05 +02:00
---
2026-06-17 16:10:00 +02:00
2026-06-18 16:55:05 +02:00
## 10. Notfall-Erkennung und Eskalation
2026-06-17 16:10:00 +02:00
2026-06-18 16:55:05 +02:00
> 🔧 Admin
Das System erkennt Notlagen-Signale (medizinisch, Sturz, Hilferuf) in der Nutzereingabe.
Die Erkennung ist **zweistufig ** :
1. **Stichwort-Heuristik ** — im Hot-Path, sofort, ohne Latenz.
2. **LLM-Klassifikation ** — läuft als Hintergrund-Task, **nur ** wenn Stufe 1 nichts fand.
Erkennt verpasste Formulierungen (metaphorische Suizidalität, Schlaganfall-Symptome
ohne Schlüsselwort) mit Konfidenz-Schwelle.
Bei Treffer: Protokolleintrag + Metrik + optionaler Webhook + Signal im Response
(`X-Emergency` -Header, `emergency` -Feld, WebSocket-`emergency` -Event).
2026-06-17 16:10:00 +02:00
```bash
2026-06-18 16:55:05 +02:00
EMERGENCY_WEBHOOK_URL=https://example.org/alert # optional
EMERGENCY_LLM_ENABLED=true # Stufe 2 (Standard: an)
EMERGENCY_LLM_MIN_CONFIDENCE=0.6 # Schwelle gegen Fehlalarme
EMERGENCY_LLM_PROVIDER= # leer = Default-LLM
2026-06-17 16:10:00 +02:00
```
2026-06-18 16:55:05 +02:00
> ⚠️ **Wichtig:** Die Erkennung ist **keine verlässliche Lebensrettung** und kein Ersatz
> für einen echten Notruf. Sie kann Notlagen verpassen oder Fehlalarme auslösen.
> Erkannte Texte sind hochsensibel (DSGVO Art. 9: Einwilligung, Aufbewahrung, Zugriff).
2026-06-17 16:10:00 +02:00
2026-06-18 16:55:05 +02:00
---
## 11. Remote-Zugang und Deployment
2026-06-17 16:10:00 +02:00
2026-06-18 16:55:05 +02:00
> 🔧 Admin
2026-06-17 16:10:00 +02:00
2026-06-18 16:55:05 +02:00
### 11.1 Zugriff aus dem lokalen Netz (LAN)
2026-06-17 18:08:58 +02:00
2026-06-18 16:55:05 +02:00
Der Gateway lauscht standardmäßig auf `0.0.0.0` (alle Interfaces). Firewall öffnen:
2026-06-17 18:08:58 +02:00
2026-06-18 16:55:05 +02:00
```bash
sudo ufw allow from 192.168.179.0/24 to any port 8003 proto tcp comment 'voice-assistant LAN'
```
2026-06-17 18:08:58 +02:00
2026-06-18 16:55:05 +02:00
Browser: `http://<server-lan-ip>:8003/` — **Text-Chat ** funktioniert. **Mikrofon-Button **
nicht: Browser geben das Mikrofon nur über HTTPS oder `localhost` frei.
2026-06-17 18:08:58 +02:00
2026-06-18 16:55:05 +02:00
> ⚠️ Bei `AUTH_ENABLED=false` kann jeder im LAN den Dienst anonym nutzen. Für Produktiv-
> betrieb: Auth aktivieren oder SSO-Weg nutzen.
2026-06-17 18:08:58 +02:00
2026-06-18 16:55:05 +02:00
### 11.2 Remote + HTTPS + SSO (YunoHost)
2026-06-17 02:14:25 +02:00
2026-06-18 16:55:05 +02:00
Für Handy/Browser von unterwegs über HTTPS mit YunoHost-SSO:
2026-06-17 05:19:07 +02:00
2026-06-18 16:55:05 +02:00
```
https://va.linix.de → nginx@YunoHost (TLS + SSO) → LAN → http://GPU-Box:8003
```
2026-06-17 05:19:07 +02:00
2026-06-18 16:55:05 +02:00
Vollständige Anleitung mit nginx-Konfiguration, Firewall, systemd und Chatterbox:
**[deploy/README.md ](deploy/README.md )**
2026-06-17 05:19:07 +02:00
2026-06-18 16:55:05 +02:00
Kern-Einstellungen auf der GPU-Box (`/etc/voice-assistant/voice-assistant.env` ):
2026-06-17 05:19:07 +02:00
```bash
2026-06-18 16:55:05 +02:00
HOST=<LAN-IP der GPU-Box> # nicht 0.0.0.0
PORT=8003
AUTH_ENABLED=true
TRUSTED_AUTH_COOKIE=yunohost.portal
TRUSTED_AUTH_COOKIE_CLAIM=user
TRUSTED_PROXY_IPS=<LAN-IP des YunoHost-Servers>
ADMIN_USERS=atoor,dieterschlueter,dschlueter
SSO_LOGOUT_URL=https://linix.de/yunohost/sso/?action=logout
2026-06-17 05:19:07 +02:00
```
2026-06-18 16:55:05 +02:00
WebSocket-Upgrade im nginx nicht vergessen — sonst kein Mikrofon und kein Streaming.
### 11.3 Docker
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
```bash
2026-06-18 16:55:05 +02:00
export OPENROUTER_API_KEY=...
docker compose up --build
2026-06-17 05:29:30 +02:00
```
2026-06-18 16:55:05 +02:00
### 11.4 systemd-Dienst
→ § 4.3 (Dauer-Betrieb ohne root)
2026-06-17 05:29:30 +02:00
2026-06-18 16:55:05 +02:00
---
## 12. Tests und Reaktionszeiten
> 💻 Entwickler / 🔧 Admin
2026-06-17 05:29:30 +02:00
2026-06-18 16:55:05 +02:00
### 12.1 Automatisierte Tests
2026-06-17 05:29:30 +02:00
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
```bash
2026-06-18 16:55:05 +02:00
make test # offline (mit Platzhaltern) — schnell, kostenlos
# oder: pytest -q
```
2026-06-17 05:29:30 +02:00
2026-06-18 16:55:05 +02:00
Abgedeckt: Config-Profile + Präzedenz, Route-Auflösung, Device Router,
Auth/Mandanten, Gedächtnis, Streaming, Resilienz, Quota, Notfall.
### 12.2 Reaktionszeiten messen
```bash
# TTS (Text → Audio):
curl -s -o gruss.pcm -w "TTS: %{time_total}s, %{size_download} Bytes\n" \
-X POST $URL/api/speak -H 'Content-Type: application/json' \
-d '{"text":"Guten Tag, wie kann ich Ihnen helfen?"}'
# STT (Audio → Text):
curl -s -o /dev/null -w "STT: %{time_total}s\n" \
-X POST $URL/api/transcribe -F "file=@frage .wav" -F "language=de"
# LLM (Text → Text, TTS auf Stub isoliert):
curl -s -o /dev/null -w "LLM: %{time_total}s\n" \
-X POST "$URL/api/chat?debug=true" -H 'Content-Type: application/json' \
-d '{"text":"Sag einen kurzen Gruß.","tts_provider":"piper"}'
# Durchschnitt der Pipeline-Stufen serverseitig:
curl -s $URL/api/metrics | jq '
.timers | to_entries
| map(select(.key|test("stage_duration")))
| map({stufe:.key, avg_s:.value.avg})'
```
### 12.3 Live-Smoke-Test (echter Netz-Aufruf)
```bash
make smoke # oder: python scripts/smoke_e2e.py
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
```
2026-06-17 05:19:07 +02:00
2026-06-18 16:55:05 +02:00
Prüft LLM, TTS und STT live gegen OpenRouter (geringe Kosten). Braucht `OPENROUTER_API_KEY` .
Meldet pro Modul `[OK]` / `[FAIL]` , inkl. TTS→STT-Round-Trip.
---
## 13. Fehlerbehebung
> alle Zielgruppen
2026-06-17 01:48:56 +02:00
| Symptom | Ursache | Lösung |
2026-06-18 16:55:05 +02:00
|---------|---------|--------|
2026-06-19 00:39:00 +02:00
| `OPENROUTER_API_KEY is empty` | Key fehlt im Service-Environment | `OPENROUTER_API_KEY=sk-or-…` in `.env` eintragen — systemd sourct kein `.bashrc` |
2026-06-18 16:55:05 +02:00
| HTTP **401 ** „Bearer/Invalid token" | Auth an, Token fehlt/falsch | Token im Header; oder `AUTH_ENABLED=false` für Dev |
docs: Bedienungsanleitung (Sprech-Loop, Einstellungen, Praxis-Tests) + voice_loop.py
- NEU scripts/voice_loop.py: Mikrofon -> /ws/voice -> Wiedergabe im Loop, mit
Gedaechtnis (--session), Geraete-/Provider-Optionen, --file fuer Test ohne Mikrofon
- BEDIENUNGSANLEITUNG.md neu strukturiert:
Teil A (sprechen->hoeren->sprechen: voice_loop + manueller Loop + chat_client),
Teil B (Einstellungen: KI/Provider auf allen Ebenen real; Sound-Quelle/-Ausgabe
ehrlich auf OS-Ebene, Gateway-Endpunkte als vorbereitete Routing-Ebene),
Teil C (Praxis-Tests + gemessene Reaktionszeiten: STT ~1,2s / LLM ~0,7s / TTS ~1,9s
/ Round-Trip ~4s; Konstellations-Empfehlung)
- Alle JSON-Befehle mit '| jq'; Audio-Befehle in Datei + Player
- README: kurzer Verweis auf den Sprech-Loop
- live verifiziert (make smoke, Timings, voice_loop --file); 64 Tests gruen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:31:35 +02:00
| HTTP **401 ** bei `/api/admin/users` | falscher/fehlender Admin-Key | `X-Admin-Key` = `ADMIN_API_KEY` |
2026-06-18 16:55:05 +02:00
| HTTP **403 ** bei `?session_id=…` | Session gehört anderem Nutzer | eigene `session_id` wählen |
| HTTP **429 ** | Tageskontingent erreicht | `DAILY_REQUEST_LIMIT` erhöhen; oder nächster Tag |
| HTTP **422 ** „Unbekannter Provider" | Tippfehler im Provider-Namen | gültige Namen: `curl -s $URL/api/config \| jq '.available'` |
| HTTP **502 ** bei STT/TTS | Cloud-Fehler oder falsches Modell | `make smoke` ; Modellnamen in `.env` prüfen |
| `VA_PROFILE` wirkt nicht | `DEFAULT_*_PROVIDER` in `.env` überschreibt das Profil | diese Zeilen auskommentieren |
| `Address already in use` | Port belegt | anderen `PORT` setzen; `ss -tlnp \| grep 8003` |
| „All connection attempts failed" (im Web-Chat) | LLM-/STT-/TTS-Dienst nicht erreichbar | Dienst starten; bei `local-dev` : `make llm-up` und warten bis HTTP OK |
| Kein Mikrofon im Browser | Kein HTTPS / kein `localhost` | HTTPS-Zugang einrichten (§ 11.2) oder lokal auf `localhost` zugreifen |
| `pw_context_connect() failed` | PipeWire-Pfad gestört | `--recorder auto` überspringt gestörte Tools; notfalls `--recorder arecord --device plughw:6,0` |
| Keine Aufnahme/Wiedergabe | Tool/Gerät fehlt | `arecord -L` ; Pakete `alsa-utils` , `ffmpeg` , `pipewire` prüfen |
| Profil greift nicht | `config/voice-assistant.toml` fehlt | aus `*.example.toml` kopieren (→ § 2.2) |
| Erste Antwort sehr langsam | lokale Modelle noch nicht vorgeladen | Warm-up passiert im Hintergrund; 1– 2 Minuten warten |
Logs: Terminal von `make run` . Mehr Details: `LOG_LEVEL=debug` in `.env` .
---
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
---
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
# Anhang A — Alle Umgebungsvariablen
> Vollständige Referenz. Alle Werte gehören in `.env` oder die Systemumgebung.
> Secrets (API-Keys, JWT-Secret) **nur** in die Umgebung, nie in `config/*.toml`.
## A.1 Betrieb und Server
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `APP_ENV` | `dev` | Umgebungskennung (z. B. `prod` ) |
| `HOST` | `0.0.0.0` | Bind-Adresse (für LAN-only: LAN-IP setzen) |
| `PORT` | `8080` | Gateway-Port |
| `LOG_LEVEL` | `info` | `debug\|info\|warning\|error` |
| `VA_PROFILE` | (leer) | Aktives Profil: `local-dev\|hybrid\|cloud` |
| `VA_CONFIG_FILE` | `config/voice-assistant.toml` | Pfad zur TOML-Konfiguration |
| `DB_PATH` | `data/voice-assistant.db` | SQLite-Datenbankpfad |
## A.2 API-Keys und Authentifizierung
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `OPENROUTER_API_KEY` | (leer) | OpenRouter-API-Key — **nur als Umgebungsvariable ** |
| `ADMIN_API_KEY` | (leer) | Admin-Key für `/api/admin/*` — **nur als Umgebungsvariable ** |
| `AUTH_ENABLED` | `true` | Bearer-Token-Auth ein/aus |
| `TRUSTED_AUTH_HEADER` | (leer) | Header mit SSO-Usernamen (z. B. `X-Remote-User` ) |
| `TRUSTED_AUTH_COOKIE` | (leer) | Cookie-Name (z. B. `yunohost.portal` ) |
| `TRUSTED_AUTH_COOKIE_CLAIM` | `user` | JWT-Claim im Cookie |
| `TRUSTED_AUTH_JWT_SECRET` | (leer) | HS256-Secret für Cookie-Signaturprüfung |
| `TRUSTED_PROXY_IPS` | (leer) | Kommaseparierte IPs der vertrauenswürdigen Proxys |
| `ADMIN_USERS` | (leer) | Kommaseparierte SSO-Usernamen mit Admin-Rechten |
| `SSO_LOGOUT_URL` | (leer) | Logout-Link fürs Frontend |
## A.3 Profil und Provider-Auswahl
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `DEFAULT_LANGUAGE` | `de` | Standardsprache |
| `DEFAULT_STT_PROVIDER` | (Profil) | Überschreibt Profil; leer lassen für profilbasiert |
| `DEFAULT_LLM_PROVIDER` | (Profil) | Überschreibt Profil |
| `DEFAULT_TTS_PROVIDER` | (Profil) | Überschreibt Profil |
| `DEFAULT_INPUT_ENDPOINT` | `local-default` | Standard-Audio-Eingang |
| `DEFAULT_OUTPUT_ENDPOINT` | `local-default` | Standard-Audio-Ausgang |
| `STT_FALLBACK` | (leer) | Kommaseparierte Fallback-Provider für STT |
| `LLM_FALLBACK` | (leer) | Fallback-Provider für LLM |
| `TTS_FALLBACK` | (leer) | Fallback-Provider für TTS |
## A.4 Cloud-STT/LLM/TTS (OpenRouter)
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `OPENROUTER_STT_MODEL` | `openai/whisper-large-v3` | STT-Modell |
| `OPENROUTER_LLM_MODEL` | `openai/gpt-4.1-mini` | LLM-Modell |
| `OPENROUTER_TTS_MODEL` | `openai/gpt-4o-mini-tts` | TTS-Modell |
| `OPENROUTER_TTS_VOICE` | `alloy` | TTS-Stimme |
## A.5 Lokales LLM (llama.cpp / Ollama)
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `LOCAL_LLM_BASE_URL` | `http://127.0.0.1:8001/v1` | API-URL des LLM-Servers |
| `LOCAL_LLM_API_KEY` | `dummy` | Beliebiger Wert (Ollama: `ollama` ) |
| `LOCAL_LLM_MODEL` | `va_llm` | Modellname / Alias |
| `LOCAL_LLM_DISABLE_REASONING` | `true` | Qwen3-Denkphase abschalten |
| `LOCAL_LLM_SYSTEM_PROMPT` | Sprach-Prompt | System-Prompt für gesprochene Antworten |
| `LOCAL_LLM_MAX_TOKENS` | `0` | Maximale Antwort-Tokens (0 = Server-Limit) |
| `LOCAL_LLM_TEMPERATURE` | `0.3` | Sampling-Temperatur |
## A.6 Lokales STT (faster-whisper)
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `FASTER_WHISPER_MODEL` | `base` | Modell: `tiny\|base\|small\|medium\|large-v3` |
| `FASTER_WHISPER_DEVICE` | `auto` | `auto\|cpu\|cuda` |
| `FASTER_WHISPER_COMPUTE_TYPE` | `default` | `default\|int8\|float16\|int8_float16` |
## A.7 Lokales TTS (piper)
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `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` ) |
| `TTS_SAMPLE_RATE` | `24000` | Ziel-Sample-Rate (Gateway resampelt bei Bedarf) |
| `TTS_NORMALIZE_LEVEL` | `auto` | `auto\|full\|light\|off` |
## A.8 Chatterbox TTS
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `CHATTERBOX_BASE_URL` | `http://127.0.0.1:9999` | URL des Chatterbox-Dienstes |
| `CHATTERBOX_VOICE` | (leer) | Pfad zu Referenz-WAV (Voice-Cloning) |
| `CHATTERBOX_LANG` | `de` | Synthesesprache |
| `CHATTERBOX_SPEED` | `1.0` | Sprechgeschwindigkeit |
| `CHATTERBOX_TIMEOUT` | `180` | Timeout in Sekunden |
## A.9 Gedächtnis und Erinnerungen
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `HISTORY_MAX_MESSAGES` | `10` | Gesprächsverlauf pro Session (Turns) |
| `MEMORY_EXTRACTION_ENABLED` | `true` | Automatische Erinnerungsextraktion |
| `MEMORY_EXTRACTION_EVERY_N_TURNS` | `3` | Extraktion alle N Turns |
| `MEMORY_EXTRACTION_MAX` | `50` | Maximale Anzahl gespeicherter Erinnerungen |
| `MEMORY_EXTRACTION_PROVIDER` | (leer = Default-LLM) | Provider für Extraktion |
## A.10 Streaming und Audio
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `AUDIO_STREAM_DEFAULT` | `true` | Satzweises Audio-Streaming als Standard |
## A.11 Betrieb, Kontingent und Notfall
| Variable | Default | Bedeutung |
|----------|---------|-----------|
| `DAILY_REQUEST_LIMIT` | `0` | Anfragen/Nutzer/Tag (0 = unbegrenzt) |
| `EMERGENCY_WEBHOOK_URL` | (leer) | Webhook-URL für Notfall-Eskalation |
| `EMERGENCY_LLM_ENABLED` | `true` | LLM-Klassifikation (Stufe 2) ein/aus |
| `EMERGENCY_LLM_PROVIDER` | (leer = Default-LLM) | Provider für Klassifikation |
| `EMERGENCY_LLM_MIN_CONFIDENCE` | `0.6` | Konfidenz-Schwelle gegen Fehlalarme |
2026-06-17 01:48:56 +02:00
2026-06-18 16:55:05 +02:00
---
# Anhang B — API-Endpunkte
> Vollständige Referenz aller HTTP- und WebSocket-Endpunkte.
## B.1 System
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/health` | Liveness-Check → `{"status":"ok"}` |
| `GET` | `/api/config` | Aktives Profil + aufgelöste Route (ohne Secrets) |
| `GET` | `/api/devices` | Verfügbare Audio-Endpunkte + Capabilities |
| `GET` | `/api/metrics` | Metriken (JSON oder `?format=prometheus` ) |
## B.2 Konversation
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `POST` | `/api/chat` | Text rein → Audio raus (PCM). `?debug=true` → JSON-Trace. `?session_id=…` → Gedächtnis |
| `POST` | `/api/speak` | Text rein → TTS-Audio raus (PCM) |
| `POST` | `/api/transcribe` | Audio-Upload (multipart) → Transkript-JSON |
Wichtige Body-Felder für `/api/chat` und `/api/speak` :
| Feld | Typ | Bedeutung |
|------|-----|-----------|
| `text` | string | Eingabe-Text (Pflicht) |
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
| `language` | string | Sprache, z. B. `de` , `en` (im Fix-Modus maßgeblich) |
| `language_mode` | string | `fix` (feste Sprache, Eingabe wird übersetzt) oder `flex` (folgt der erkannten Sprache) — → § 6.6 |
2026-06-18 16:55:05 +02:00
| `stt_provider` | string | Provider für diese Anfrage |
| `llm_provider` | string | Provider für diese Anfrage |
| `tts_provider` | string | Provider für diese Anfrage |
| `voice` | string | TTS-Stimme für diese Anfrage |
| `stream` | bool | LLM-Token-Streaming (nur WebSocket) |
| `audio_stream` | bool | Satzweises Audio-Streaming (nur WebSocket) |
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
| `text_only` | bool | Kein Server-Audio erzeugen/senden (nur Text) — fürs Geräte-TTS (→ § 6.5.0) |
2026-06-18 16:55:05 +02:00
## B.3 Sessions und Routing
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `POST` | `/api/sessions/{id}/route` | Provider/Sprache/Geräte für Session festlegen |
Body-Felder: `input_endpoint` , `output_endpoint` , `stt_provider` , `llm_provider` ,
`tts_provider` , `language` .
## B.4 Nutzer und Präferenzen
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| `GET` | `/api/me` | Aktueller Nutzer + Präferenzen |
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
| `PUT` | `/api/me/prefs` | Dauerhafte Routing-Präferenzen setzen (Merge; Felder u. a. `language` , `language_mode` , `tts_provider` — → § 6.6) |
2026-06-18 16:55:05 +02:00
| `GET` | `/api/me/memories` | Alle Langzeit-Erinnerungen |
| `POST` | `/api/me/memories` | Erinnerung hinzufügen |
| `DELETE` | `/api/me/memories/{id}` | Erinnerung löschen |
## B.5 Administration
| Methode | Pfad | Auth | Beschreibung |
|---------|------|------|--------------|
2026-06-19 01:15:28 +02:00
| `POST` | `/api/admin/users` | Admin | Nutzer anlegen → Token einmalig |
| `GET` | `/api/admin/users` | Admin | Alle Nutzer auflisten |
| `PUT` | `/api/admin/users/{user_id}` | Admin | Anzeigenamen aktualisieren (`{"display_name":"…"}` ) |
| `DELETE` | `/api/admin/users/{user_id}` | Admin | Nutzer + alle Daten löschen |
| `POST` | `/api/admin/users/{user_id}/token` | Admin | Neues Token ausstellen (alter Token sofort ungültig) |
| `POST` | `/api/admin/users/{user_id}/memories` | Admin | Erinnerung für Nutzer vorbelegen (`{"content":"…"}` ) |
| `GET` | `/api/admin/users/{user_id}/memories` | Admin | Alle Erinnerungen eines Nutzers |
| `DELETE` | `/api/admin/users/{user_id}/memories/{id}` | Admin | Eine Erinnerung löschen |
| `GET` | `/api/admin/users/{user_id}/sessions` | Admin | Sessions eines Nutzers (neueste zuerst) |
| `GET` | `/api/admin/sessions/{session_id}/messages` | Admin | Nachrichten einer Session (`?limit=200` ) |
| `GET` | `/api/admin/emergency-events` | Admin | Notfall-Ereignisse (`?limit=50` ) |
| `GET` | `/api/admin/users/{user_id}/usage` | Admin | Nutzungsstatistik eines Nutzers |
| `GET` | `/api/admin/usage` | Admin | Aggregierte Nutzungsstatistik aller Nutzer |
| `GET` | `/api/admin/db-export` | Admin | SQLite-Datenbank als Datei-Download (Backup) |
docs: § 6.5.4 Aussprache-Lexika vollständig dokumentiert (alle 8 Sprachen)
- YAML-Dateistruktur für alle Sprachen erklärt (de/en/fr/es/it/nl/ru/zh)
- Drei Sektionen (abbreviations/units/terms) mit Matching-Regeln
- Anleitung "Eigennamen in Fremdsprachen" — Textersetzungs-Prinzip statt IPA
mit Klangäquivalent-Tabelle (ʃ, y/ü, x, ts in je 6 Sprachen)
- Sonderfall RU/ZH: Kyrillisch/Hanzi notwendig, Lateinschrift unzuverlässig
- Drei Wege dokumentiert: Web-UI (de/en), REST-API (alle Sprachen, sofort),
direkte YAML-Bearbeitung (alle Sprachen, Neustart nötig)
- Test-Befehle: Admin-Test-Button, curl, Normalizer-Skript
- § 7.5 Wörterbuch-Tab: Hinweis auf de/en-Beschränkung + Verweis auf § 6.5.4
- API-Referenz: lang-Parameter auf alle Sprachcodes erweitert
- Stichwortverzeichnis: zwei neue Einträge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:34:08 +02:00
| `GET` | `/api/admin/pronunciation/{lang}` | Admin | Aussprache-Lexikon lesen (`lang` : `de` , `en` , `fr` , `es` , `it` , `nl` , `ru` , `zh` , …) |
| `POST` | `/api/admin/pronunciation/{lang}` | Admin | Eintrag hinzufügen/überschreiben (`{"section":"terms","key":"Schlüter","value":"Chluteur"}` ) |
2026-06-19 01:15:28 +02:00
| `DELETE` | `/api/admin/pronunciation/{lang}/{section}/{key}` | Admin | Eintrag löschen |
| `WS` | `/api/admin/log` | Admin | Live-Log via WebSocket (journalctl stream) |
**Auth:** `X-Admin-Key` -Header oder SSO-Admin-Cookie (→ § 7.4).
2026-06-18 16:55:05 +02:00
## B.6 WebSocket
| Pfad | Beschreibung |
|------|--------------|
| `/ws/chat` | Echtzeit-Chat. Client sendet JSON mit `text` ; Server streamt `ack` → `token` * → `semantic` → Audio (binär) → `done` . Auth: `?token=…` , Gedächtnis: `?session_id=…` |
| `/ws/voice` | Echtzeit-Sprache. Client sendet Start-JSON (`{"type":"start","format":"webm"}` ), dann Audio-Bytes, dann `{"type":"end"}` . Server antwortet mit `transcript` → dann wie `/ws/chat` |
**WebSocket-Events (Server → Client):**
| Event-Typ | Inhalt | Wann |
|-----------|--------|------|
| `ack` | `{}` | Verbindung aufgebaut |
| `transcript` | `{"text":"…"}` | STT-Ergebnis (bei `/ws/voice` ) |
| `token` | `{"text":"…"}` | LLM-Token (bei `stream:true` ) |
| `semantic` | `{"text":"…"}` | Vollständige Antwort |
| `audio` | `{"seq":N}` + binärer Frame | Satz-Audio (bei `audio_stream:true` ) |
| `done` | `{"sample_rate":24000}` | Antwort fertig |
| `error` | `{"detail":"…"}` | Fehler |
| `emergency` | `{"category":"…","source":"keyword\|llm"}` | Notfall erkannt |
| `interrupted` | `{}` | Barge-in bestätigt |
**Barge-in:** `{"type":"interrupt"}` senden → laufende Antwort bricht ab.
**VAD:** Im Start-Frame `{"type":"start","vad":true,"format":"pcm","sample_rate":16000}` → Server erkennt Sprechpausen selbst.
---
# Anhang C — Provider-Übersicht
| Provider-Name | Kategorie | Typ | Abhängigkeit | Bemerkung |
|---------------|-----------|-----|-------------|-----------|
| `openrouter` | STT | Cloud | `OPENROUTER_API_KEY` | Whisper-large-v3, andere |
| `faster-whisper` | STT | Lokal | `pip install -e .[local]` | In-Process, GPU-fähig |
| `openrouter` | LLM | Cloud | `OPENROUTER_API_KEY` | GPT-4.1-mini, Gemini, … |
| `local-openai-compatible` | LLM | Lokal | llama.cpp oder Ollama | OpenAI-kompatibler Server |
| `openrouter` | TTS | Cloud | `OPENROUTER_API_KEY` | GPT-4o-mini-TTS, Gemini-TTS |
| `piper` | TTS | Lokal | `pip install -e .[local]` + Stimmmodell | In-Process, schnell |
| `chatterbox` | TTS | Lokal | Eigener HTTP-Dienst (Port 9999) | Langsam, hohe Qualität, Voice-Cloning |
Neuen Provider hinzufügen: Eintrag in `STT_REGISTRY` /`LLM_REGISTRY` /`TTS_REGISTRY`
in `app/dependencies.py` + Implementierung in `app/providers/` . → [Architektur-Dokument § 3.3 ](Docs/voice-assistant-architecture.md ).
---
# Anhang D — Sachregister
| Begriff | Abschnitt |
|---------|-----------|
2026-06-19 01:15:28 +02:00
| Admin-Web-Panel | § 7.5 |
2026-06-18 16:55:05 +02:00
| API-Key (OpenRouter) | § 2.3, Anhang A.2 |
2026-06-18 17:55:05 +02:00
| Authentifizierung / Bearer-Token | § 7.1, § 7.3, Anhang B.4 |
2026-06-18 16:55:05 +02:00
| Audio-Geräte / Mikrofon / Lautsprecher | § 6.7 |
| Aussprache verbessern | § 6.5.4 |
docs: § 6.5.4 Aussprache-Lexika vollständig dokumentiert (alle 8 Sprachen)
- YAML-Dateistruktur für alle Sprachen erklärt (de/en/fr/es/it/nl/ru/zh)
- Drei Sektionen (abbreviations/units/terms) mit Matching-Regeln
- Anleitung "Eigennamen in Fremdsprachen" — Textersetzungs-Prinzip statt IPA
mit Klangäquivalent-Tabelle (ʃ, y/ü, x, ts in je 6 Sprachen)
- Sonderfall RU/ZH: Kyrillisch/Hanzi notwendig, Lateinschrift unzuverlässig
- Drei Wege dokumentiert: Web-UI (de/en), REST-API (alle Sprachen, sofort),
direkte YAML-Bearbeitung (alle Sprachen, Neustart nötig)
- Test-Befehle: Admin-Test-Button, curl, Normalizer-Skript
- § 7.5 Wörterbuch-Tab: Hinweis auf de/en-Beschränkung + Verweis auf § 6.5.4
- API-Referenz: lang-Parameter auf alle Sprachcodes erweitert
- Stichwortverzeichnis: zwei neue Einträge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:34:08 +02:00
| Aussprache — Eigennamen in Fremdsprachen | § 6.5.4 |
| Aussprache — YAML-Lexika (alle Sprachen) | § 6.5.4 |
2026-06-18 16:55:05 +02:00
| Automatische Erinnerungen | § 8.3 |
| Barge-in (Unterbrechung) | § 6.8, Anhang B.6 |
| Bluetooth | § 6.7 |
| Chatterbox TTS | § 6.5.3, Anhang C |
| Cloud-Profil | § 3.1 |
| Deployment (systemd, Docker) | § 4.3, § 4.4, § 11 |
| Erinnerungen (Langzeit) | § 8.2, § 8.3 |
| Fallback-Ketten | § 9.1, Anhang A.3 |
| faster-whisper | § 6.3, Anhang C |
| Fehlerbehebung | § 13 |
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
| Fix / Flex (Sprachmodus) | § 6.6 |
2026-06-18 16:55:05 +02:00
| Gedächtnis (Sitzung) | § 8.1 |
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
| Geräte-TTS (Web Speech API) | § 6.5.0 |
2026-06-18 16:55:05 +02:00
| Hybrid-Profil | § 3.2 |
| Installation | § 2 |
| Konfigurationsebenen / Priorität | § 6.1 |
| Kontingent (Kosten-Bremse) | § 9.3 |
| llama.cpp | § 4.5, § 3.2, § 3.3 |
| local-dev-Profil | § 3.3 |
2026-06-19 11:59:04 +02:00
| Ollama starten | § 4.6 |
2026-06-19 12:12:29 +02:00
| Ollama ↔ llama.cpp wechseln | § 4.7 |
2026-06-19 12:58:54 +02:00
| Stoppen (alle Varianten) | § 4.8 |
| Neustart | § 4.9 |
2026-06-18 16:55:05 +02:00
| Metriken / Monitoring | § 9.2, Anhang B.1 |
| Mikrofon → Audio-Geräte | § 6.7 |
| Notfall-Erkennung | § 10 |
2026-06-19 11:59:04 +02:00
| Ollama | § 3.2, § 3.3, * * § 4.6** |
2026-06-18 16:55:05 +02:00
| piper (TTS) | § 6.5.2, Anhang C |
| Pipeline (Architektur) | § 1.3 |
| Profile (cloud/hybrid/local-dev) | § 3 |
| Provider wechseln | § 6.2 |
| Remote-Zugang / HTTPS / SSO | § 11 |
| Sachregister | Anhang D |
| Sitzungsgedächtnis | § 8.1 |
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
| Sprache wechseln (Fix/Flex) | § 6.6 |
2026-06-18 16:55:05 +02:00
| Sprech-Loop | § 5.2 |
| Stimmen (TTS) | § 6.5.1, § 6.5.2 |
feat: Geräte-TTS, native Stimmen, Favicon, Auth-Gate, UI-Fixes
Web-UI / TTS:
- Geräte-TTS ("📱 Gerät"): Antwort wird on-device vorgelesen (Web Speech
API), Server sendet nur Text (text_only) -> spart Bandbreite/Kosten.
Mobil-Default, geräte-lokale Speicherung, iOS-Autoplay-Freischaltung.
- Vorlese-Symbol (🔊) je Bubble: Hybrid-Replay (Assistent-PCM gecacht,
Eingabe via /api/speak); SVG-Icon mit kontrastreicher Farbe.
- Kombiniertes Sprachmenü (Flex + feste Sprachen) statt separatem Modus-Menü.
- "Neues Gespräch"-Button (frische Session gegen Sprach-Trägheit).
- Dark-Mode: lesbare <option>-Popups (Kontrast-Fix).
- Favicon (SVG + PNG-Fallbacks) aus mund.png.
TTS-Backend:
- Sprache wird an alle TTS-Provider durchgereicht; Piper-Stimme folgt der
Sprache; Chatterbox mehrsprachig + cross-lingual.
- Native Referenz-Stimmen je Sprache (config/voices/<lang>.wav, FLEURS CC-BY),
loudness-normalisiert.
LLM-Sprache:
- Antwort folgt zuverlässig der gewählten Sprache (verstärkte Anweisung +
Erinnerung an der letzten Nutzer-Nachricht gegen History-Trägheit).
Admin / Auth:
- Wörterbuch: alle 8 Sprachen, Zeilen editierbar, alphabetische Sortierung.
- Web-UI hinter Auth-Gate (Redirect auf SSO_LOGIN_URL / 401); Favicons offen.
- Log-Tab: Hinweis, wenn der systemd-Dienst nicht aktiv ist.
- Einstellungen: Hinweis "pro Nutzer überschreibbar" bei Sprache/Modus/Qualität.
Doku (BEDIENUNGSANLEITUNG.md): Geräte-TTS §6.5.0, Fix/Flex §6.6, native
Stimmen §6.5.3, llama.cpp<->Ollama-Wechsel §4.7, Auth/SSO §7.4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 13:12:04 +02:00
| Stimme folgt Sprache (Flex) | § 6.6 |
2026-06-18 16:55:05 +02:00
| STT-Einstellungen | § 6.3 |
| Streaming (Audio/Token/VAD) | § 6.8, Anhang B.6 |
| Tests | § 12 |
| TTS-Einstellungen | § 6.5 |
| Umgebungsvariablen (alle) | Anhang A |
| VAD (Sprechpausen-Erkennung) | § 6.8, Anhang B.6 |
| Voice-Cloning (Chatterbox) | § 6.5.3 |
| Web-Interface | § 5.1 |
| WebSocket | Anhang B.6 |
2026-06-18 17:55:05 +02:00
| YunoHost / SSO | § 7.2, § 7.4, § 11.2 |