my_voice_assistant/BEDIENUNGSANLEITUNG.md
2026-06-16 02:21:26 +02:00

513 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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

# Bedienungsanleitung — Voice Assistant
## Inhaltsverzeichnis
1. [Voraussetzungen](#1-voraussetzungen)
2. [Installation der Abhängigkeiten](#2-installation-der-abhängigkeiten)
3. [Schnellstart](#3-schnellstart)
4. [Die fünf Zustände](#4-die-fünf-zustände)
5. [Steuer-Wörter](#5-steuer-wörter)
6. [Alle Kommandozeilenoptionen](#6-alle-kommandozeilenoptionen)
7. [Mikrofon wählen](#7-mikrofon-wählen)
8. [Audio-Ausgang wählen](#8-audio-ausgang-wählen)
9. [LLM-Backend konfigurieren](#9-llm-backend-konfigurieren)
10. [Sprache und Stimme](#10-sprache-und-stimme)
11. [Standalone-Werkzeuge](#11-standalone-werkzeuge)
12. [Tipps und Fehlerbehebung](#12-tipps-und-fehlerbehebung)
---
## 1. Voraussetzungen
### Hardware
| Komponente | Empfehlung |
|---|---|
| Mikrofon | ReSpeaker XVF3800 (Hardware-AEC, 4 Mikrofone, 48 kHz) |
| GPU | NVIDIA RTX (CUDA) für Whisper-Transkription |
| Audio-System | PipeWire mit `paplay` |
Jedes USB-Mikrofon funktioniert. Das ReSpeaker XVF3800 ist empfohlen, weil es
Hardware-seitig Echo cancellation (AEC) und Beamforming bietet — das verhindert,
dass die TTS-Ausgabe als Spracheingabe erkannt wird.
### Software
- Python 3.12+
- PipeWire als Audio-Server (`pactl`, `paplay` müssen verfügbar sein)
- CUDA-Treiber für NVIDIA-GPU
---
## 2. Installation der Abhängigkeiten
```bash
pip install faster-whisper openwakeword piper-tts sounddevice scipy langdetect openai
```
Das Whisper-Modell (`large-v3`) wird beim ersten Start automatisch heruntergeladen (~3 GB).
Piper-Stimmen werden bei Bedarf automatisch heruntergeladen (~60120 MB pro Sprache).
---
## 3. Schnellstart
```bash
# Standard: ReSpeaker-Mikrofon, llama.cpp auf localhost:8001, Deutsch
python3 assistant.py
# Ohne Wake-Word — sofort aufnahmebereit (gut zum Testen)
python3 assistant.py --no-wakeword
# Mit Ollama
python3 assistant.py --backend ollama --model llama3.2
# Mit OpenAI
export OPENAI_API_KEY=sk-...
python3 assistant.py --backend openai --model gpt-4o-mini
```
Beim ersten Start werden Modelle geladen (ca. 1030 Sekunden). Danach erscheint:
```
Warte auf "Hey Jarvis" …
[LAUSCH] Warte auf "Hey Jarvis" …
```
---
## 4. Die fünf Zustände
Der Assistent durchläuft folgende Zustände. Der aktuelle Zustand wird in der
Statuszeile links in eckigen Klammern angezeigt: `[ZUSTAND] Info`
```
"Hey Jarvis"
LAUSCH ─────────────► AUFNAHME
▲ │
│ Timeout/Stopp Stille ≥5s
│ oder "over"
│ │
│ Stopp ▼
DIALOG ◄──────────── VORLESE ◄── GENERATOR
│ Vorlesen fertig Transkription
│ + LLM-Antwort
└── Sprache erkannt ──► AUFNAHME
```
### LAUSCH
Wartet auf das Wake-Word **„Hey Jarvis"**. Kein Quittungston, kein Feedback bis
das Wake-Word erkannt wird. Ein kurzer Piepton signalisiert den Übergang zu AUFNAHME.
### AUFNAHME
Nimmt die Sprache auf. Die Statuszeile zeigt die bisherige Aufnahmedauer und die
aktuelle Stille-Dauer:
```
[AUFNAHME] 3.2s (Stille 1.1s)
```
Die Aufnahme endet wenn:
- Stille ≥ `--silence-sec` (Standard: 5 Sekunden)
- Das Stop-Wort gesagt wird (Standard: „over")
- „Stopp" gesagt wird → direkt zurück zu LAUSCH (ohne Antwort)
- Maximaldauer von 60 Sekunden erreicht ist
### GENERATOR
Der Assistent sagt den Quittungssatz (Standard: „Moment, ich antworte gleich."),
während er die Transkription und den LLM-Aufruf durchführt. Auch hier ist „Stopp"
aktiv und bricht den Vorgang ab.
### VORLESE
Die Antwort wird vorgelesen. Alle **Steuer-Wörter** sind aktiv (→ Abschnitt 5).
Mehrere Sätze werden parallel synthetisiert und nahtlos abgespielt.
### DIALOG
Nach dem Vorlesen öffnet sich ein Zeitfenster (Standard: 5 Sekunden). Wird in
dieser Zeit gesprochen, geht der Assistent direkt in AUFNAHME — **ohne Wake-Word**.
So sind Rückfragen flüssig möglich. Nach Ablauf des Zeitfensters oder bei „Stopp"
kehrt der Assistent zu LAUSCH zurück.
---
## 5. Steuer-Wörter
Das Wort **„bitte"** wird vor dem Abgleich immer ignoriert (z. B. „Stopp bitte" = „Stopp").
### Während VORLESE
| Gesprochener Befehl | Wirkung |
|---|---|
| **„Stopp"** | Wiedergabe sofort abbrechen → DIALOG |
| **„Pause"** | Wiedergabe anhalten (bleibt pausiert) |
| **„Weiter"** | Nach Pause: aktuellen Satz von vorne abspielen |
| **„Noch einmal"** | Letzten Satz wiederholen |
| **„Absatz noch einmal"** | Zum Anfang des letzten Absatzes springen |
| **„Alles von vorn"** | Gesamte Antwort von Anfang an wiederholen |
### In allen anderen aktiven Zuständen
| Zustand | Befehl | Wirkung |
|---|---|---|
| AUFNAHME | **„Stopp"** | Aufnahme abbrechen → LAUSCH |
| GENERATOR | **„Stopp"** | Verarbeitung abbrechen → LAUSCH |
| DIALOG | **„Stopp"** | Dialogfenster schließen → LAUSCH |
---
## 6. Alle Kommandozeilenoptionen
```
python3 assistant.py [OPTIONEN]
```
### Eingabe
| Option | Standard | Beschreibung |
|---|---|---|
| `--mic NAME` | `respeaker` | Mikrofon: `respeaker` \| `motu` \| `camera` \| `default` \| `bluetooth` \| `<Index>` \| `<Substring>` |
| `--list-mics` | — | Alle verfügbaren Mikrofone anzeigen und beenden |
| `--silence-sec N` | `5.0` | Stille-Dauer in Sekunden bis die Aufnahme endet |
| `--stop-word WORT` | `over` | Codewort zum manuellen Beenden der Aufnahme |
| `--no-wakeword` | — | Wake-Word deaktivieren, sofort in AUFNAHME starten |
| `--wakeword-threshold N` | `0.5` | Empfindlichkeit Wake-Word-Erkennung (0.01.0) |
### LLM-Backend
| Option | Standard | Beschreibung |
|---|---|---|
| `--backend NAME` | `llama` | Backend: `llama` \| `ollama` \| `openai` |
| `--model NAME` | auto | Modellname (bei llama.cpp: automatisch vom Server) |
| `--api-url URL` | — | Überschreibt die Backend-URL (beliebiger OpenAI-kompatibler Endpunkt) |
| `--api-key KEY` | — | API-Key (überschreibt `OPENAI_API_KEY` / Backend-Default) |
| `--system TEXT` | (eingebaut) | System-Prompt für den Assistenten |
| `--history N` | `10` | Maximale Anzahl gespeicherter Gesprächsrunden |
### Spracherkennung (Whisper)
| Option | Standard | Beschreibung |
|---|---|---|
| `--whisper-model NAME` | `large-v3` | Whisper-Modell |
| `--gpu N` | `1` | CUDA-Index für Whisper (in `CUDA_VISIBLE_DEVICES`) |
| `--lang CODE` | `de` | Sprache der Benutzereingabe (`de`, `en`, `fr`, …) |
### Sprachausgabe (TTS)
| Option | Standard | Beschreibung |
|---|---|---|
| `--voice NAME` | `de_DE-thorsten-high` | Standard-Piper-Stimme (Fallback) |
| `--en-variant` | `us` | Englische Variante: `us` (Ryan) \| `gb` (Alan) |
| `--out NAME` | `default` | Ausgabe-Sink: `default` \| `respeaker` \| `hdmi` \| `motu` \| `bluetooth` \| `<Sink-Name>` |
| `--ack-text TEXT` | `Moment, ich antworte gleich.` | Quittungssatz im GENERATOR-Zustand |
| `--dialog-timeout N` | `5.0` | DIALOG-Fenster in Sekunden |
### Typische Kombinationen
```bash
# Entwicklung / Debugging (kein Wake-Word, kurze Stille)
python3 assistant.py --no-wakeword --silence-sec 2.0
# MOTU M2 als Mikrofon und Ausgang
python3 assistant.py --mic motu --out motu
# Englisch mit britischer Stimme
python3 assistant.py --lang en --voice en_GB-alan-medium --en-variant gb
# Empfindlicheres Wake-Word
python3 assistant.py --wakeword-threshold 0.3
# Längeres Dialogfenster
python3 assistant.py --dialog-timeout 10.0
```
---
## 7. Mikrofon wählen
```bash
# Alle verfügbaren Mikrofone anzeigen
python3 assistant.py --list-mics
# oder
python3 mic.py
```
**Vordefinierte Kurznamen:**
| Kurzname | Gerät |
|---|---|
| `respeaker` | ReSpeaker XVF3800 (Standard) |
| `motu` | MOTU M2 Mikrofon-Eingang |
| `camera` | USB-Kamera-Mikrofon (VF0680) |
| `default` | System-Standard-Eingabe (PipeWire) |
| `bluetooth` | Erstes verbundenes Bluetooth-Gerät |
Alternativ kann ein **numerischer Index** (`--mic 3`) oder ein **Substring** des
Gerätenamens (`--mic "USB Audio"`) angegeben werden.
---
## 8. Audio-Ausgang wählen
```bash
# Alle verfügbaren Ausgänge anzeigen
python3 speak.py --list
```
**Vordefinierte Kurznamen:**
| Kurzname | Gerät |
|---|---|
| `default` | PipeWire-Standard-Sink |
| `respeaker` | ReSpeaker XVF3800 3,5-mm-Klinke |
| `hdmi` | HDA NVidia HDMI |
| `motu` | MOTU M2 Ausgang |
| `bluetooth` | Erstes verbundenes Bluetooth-Gerät |
Vollständige Sink-Namen aus `pactl list sinks short` können direkt verwendet werden.
---
## 9. LLM-Backend konfigurieren
Der Assistent spricht mit jedem LLM, das die **OpenAI Chat-Completions API**
implementiert. Mit `--api-url` und `--api-key` kann der Endpunkt frei
überschrieben werden — das `--backend`-Flag wählt nur den Verbindungs-Default.
### llama.cpp (Standard)
```bash
# llama.cpp muss auf Port 8001 laufen
python3 assistant.py --backend llama
```
Der Modellname wird automatisch vom Server abgefragt.
Anderen Port oder Host angeben:
```bash
python3 assistant.py --backend llama --api-url http://192.168.1.10:8001/v1
```
### Ollama (lokal)
```bash
# Ollama muss laufen: ollama serve
python3 assistant.py --backend ollama --model llama3.2
python3 assistant.py --backend ollama --model mistral
```
### Ollama (remote / anderer Rechner)
```bash
python3 assistant.py --backend ollama \
--api-url http://mein-server:11434/v1 \
--model llama3.2
```
### OpenAI
```bash
export OPENAI_API_KEY=sk-...
python3 assistant.py --backend openai --model gpt-4o-mini
python3 assistant.py --backend openai --model gpt-4o
```
### OpenRouter (viele Modelle über eine API)
[OpenRouter](https://openrouter.ai) bietet Zugang zu hunderten Modellen
(Mistral, Llama, Gemma, Claude, GPT-4 u. v. m.) über eine einheitliche API.
```bash
export OPENROUTER_API_KEY=sk-or-...
python3 assistant.py \
--backend openai \
--api-url https://openrouter.ai/api/v1 \
--model mistralai/mistral-7b-instruct
```
Andere beliebte OpenRouter-Modelle:
- `meta-llama/llama-3.1-8b-instruct:free` (kostenlos)
- `google/gemma-3-27b-it`
- `anthropic/claude-3.5-haiku`
Den API-Key unter `https://openrouter.ai/keys` erstellen.
### Groq (sehr schnelle Inferenz)
```bash
export GROQ_API_KEY=gsk_...
python3 assistant.py \
--backend openai \
--api-url https://api.groq.com/openai/v1 \
--model llama-3.1-70b-versatile
```
### LM Studio
```bash
# LM Studio muss mit aktiviertem lokalen Server laufen (Port 1234)
python3 assistant.py --backend llama --api-url http://localhost:1234/v1
```
### Together AI
```bash
export TOGETHER_API_KEY=...
python3 assistant.py \
--backend openai \
--api-url https://api.together.xyz/v1 \
--model meta-llama/Llama-3-8b-chat-hf
```
### Allgemeines Prinzip
Jeder Provider, der `/v1/chat/completions` mit `stream=true` unterstützt,
funktioniert mit:
```bash
python3 assistant.py \
--backend openai \
--api-url https://<provider>/v1 \
--model <modellname> \
--api-key <api-key>
```
---
## 10. Sprache und Stimme
### Automatische Spracherkennung
Der Assistent erkennt automatisch die Sprache der LLM-Antwort und wählt die
passende Piper-Stimme. Fehlende Stimmen werden beim ersten Bedarf automatisch
heruntergeladen.
| Sprache | Stimme |
|---|---|
| Deutsch | `de_DE-thorsten-high` |
| Englisch (US) | `en_US-ryan-high` |
| Englisch (GB) | `en_GB-alan-medium` |
| Französisch | `fr_FR-upmc-medium` |
| Spanisch | `es_ES-davefx-medium` |
| Italienisch | `it_IT-paola-medium` |
| Niederländisch | `nl_NL-mls-medium` |
| Portugiesisch | `pt_BR-faber-medium` |
| Russisch | `ru_RU-ruslan-medium` |
| Polnisch | `pl_PL-bass-high` |
| Ukrainisch | `uk_UA-lada-x_low` |
| Tschechisch | `cs_CZ-jirka-medium` |
### Englische Variante wählen
Da automatische Erkennung nicht zwischen en-US und en-GB unterscheiden kann,
wird die Variante beim Start festgelegt:
```bash
python3 assistant.py --en-variant us # Standard: amerikanisches Englisch
python3 assistant.py --en-variant gb # britisches Englisch
```
### Eigene Standardstimme
Die `--voice`-Option setzt die Fallback-Stimme (wenn Spracherkennung fehlschlägt
oder die erkannte Sprache nicht in der Tabelle ist):
```bash
python3 assistant.py --voice de_DE-kerstin-low
```
---
## 11. Standalone-Werkzeuge
### speak.py — Sprachausgabe testen
```bash
# Text vorlesen
python3 speak.py --text "Hallo, ich bin dein Assistent."
# Mit bestimmter Stimme und Ausgang
python3 speak.py --text "Hello World" --voice en_US-ryan-high --out respeaker
# Text aus stdin
echo "Test" | python3 speak.py
# Alle Ausgänge anzeigen
python3 speak.py --list
# Alle verfügbaren Piper-Stimmen (Deutsch)
python3 speak.py --list-voices --voice-lang de
# Alle Stimmen aller Sprachen
python3 speak.py --list-voices --voice-lang ""
```
### transcribe.py — Transkription testen
```bash
# Live-Transkription mit ReSpeaker
python3 transcribe.py
# Mit anderem Mikrofon
python3 transcribe.py --mic motu
# Alle Mikrofone anzeigen
python3 transcribe.py --list-mics
```
### mic.py — Mikrofone anzeigen
```bash
python3 mic.py
```
---
## 12. Tipps und Fehlerbehebung
### Wake-Word wird nicht erkannt
- Lautstärke des Mikrofons erhöhen: `pactl set-source-volume <Gerät> 150%`
- Schwellenwert senken: `--wakeword-threshold 0.3`
- Zum Testen `--no-wakeword` verwenden
### Transkription ist ungenau
- Lautstärke erhöhen
- Hintergrundgeräusche reduzieren
- ReSpeaker XVF3800 verwenden (Hardware-AEC unterdrückt Lautsprecher-Echo)
- `--lang` korrekt setzen (z. B. `--lang de` für Deutsch)
### „Stopp" wird nicht erkannt
- Deutlich und mit normaler Lautstärke sprechen
- Latenz: ca. 0,51 Sekunde bis zur Reaktion (Whisper muss verarbeiten)
- In AUFNAHME: `--stop-word` ist ein anderes Wort; „Stopp" wird separat erkannt
### TTS-Stimme klingt falsch für die Sprache
- Stimme wurde mit falscher Sprache verwendet (z. B. Download fehlgeschlagen)
- Fehlermeldung erscheint im Terminal; nochmals versuchen (automatischer Retry 3×)
- Netzwerkverbindung prüfen (Stimmen werden von HuggingFace geladen)
### Piper-Stimme fehlt / Download schlägt fehl
```bash
# Verfügbare Stimmen anzeigen
python3 speak.py --list-voices --voice-lang de
# Stimme manuell laden (wird dann gecacht)
python3 speak.py --text "Test" --voice ru_RU-ruslan-medium
```
### audio: input overflow
Diese Meldung wird bewusst unterdrückt. Sie tritt auf wenn Whisper die
Verarbeitung verzögert und der PortAudio-Puffer überläuft. Das ist normal
und beeinflusst die Qualität nicht wesentlich.
### llama.cpp antwortet nicht
```bash
# Prüfen ob der Server läuft
curl http://localhost:8001/v1/models
# Modell und Port in llama.cpp-Konfiguration prüfen
```