Mac-Worker: - install-launchagent.sh legt jetzt selbst venv + Dependencies an, statt das vorauszusetzen — ein Befehl reicht für komplette Erstinstallation - modernes launchctl bootout/bootstrap/kickstart statt unload/load (alte Variante wirft auf neueren macOS-Versionen "Input/output error 5") - neuer Sub-Befehl "restart" zum Neustarten ohne Reinstall - neues update.sh: git pull + pip install + kickstart + Health in einem Schritt LXC: - install.sh ALLOWED_EXTS-Check verhindert wiederholtes ",webm"-Anhängen - bessere Abschluss-Ausgabe mit echter Host-IP, Update-Anweisung, Diagnose-Hinweis Docs: - Haupt-README: aktueller Funktionsstand (Auth, PDF, Profile, Mobile/PWA, Diagnose, Retry alle als done markiert), Installation auf neuen Stand gebracht - Profile-Tabelle mit allen 17 Profilen - API-Listen vervollständigt (diag, preload, log, pdf, profiles) - Datenfluss-Skizze mit Preload + Heartbeat + X-Job-Id beschrieben Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
288 lines
11 KiB
Markdown
288 lines
11 KiB
Markdown
# Voice-Agent
|
||
|
||
Self-hosted Transkriptions- und Protokollsystem für Sprachaufzeichnungen — vollständig lokal, DSGVO-konform.
|
||
|
||
> Vollständiges Lastenheft: siehe [`need.md`](need.md)
|
||
|
||
## Architektur
|
||
|
||
```
|
||
Benutzer (Browser / Handy-PWA)
|
||
│
|
||
▼ HTTPS (selbst-signiert, Mikrofon-fähig)
|
||
┌──────────────────────────────┐ ┌──────────────────────────────┐
|
||
│ LXC-Container (Linux) │ HTTP │ Mac (Apple Silicon) │
|
||
│ - FastAPI + HTML/JS UI │ ──────► │ - FastAPI Worker │
|
||
│ - SQLite Job-Store + Auth │ │ - lightning-whisper-mlx │
|
||
│ - Profile (YAML, ≥17) │ │ - Ollama (Standard 8B) │
|
||
│ - Result-/Upload-Verz. │ ◄────── │ - python-docx + reportlab │
|
||
│ - Nginx HTTPS-Reverse-Proxy │ │ - Per-Job Log-Ringbuffer │
|
||
└──────────────────────────────┘ └──────────────────────────────┘
|
||
```
|
||
|
||
- **LXC**: keine AI-Verarbeitung — nur Uploads, Job-Tracking, Login, Auslieferung.
|
||
- **Mac**: Stateless API. Erhält Audio/Text, gibt Transkripte / Zusammenfassungen / Protokolle / DOCX / PDF zurück.
|
||
|
||
## Funktionsumfang (aktueller Stand)
|
||
|
||
- [x] Audio-Upload (MP3, WAV, M4A, MP4, OGG, FLAC, WEBM — max. 500 MB)
|
||
- [x] Mobile-First-Layout + PWA mit Mikrofon-Aufnahme (Start / Pause / Stop)
|
||
- [x] Whisper-Transkription auf dem Mac (MLX, Apple Neural Engine)
|
||
- [x] Ollama-Zusammenfassung
|
||
- [x] Strukturiertes Protokoll je Profil
|
||
- [x] **17 Verarbeitungs-Profile** (Sitzung, Diktat, Pflegedoku, IT-Ticket, Sales-Call, …)
|
||
- [x] **DOCX- und PDF-Export**
|
||
- [x] **Benutzer-Verwaltung** (bcrypt, Cookie-Sessions, Per-User-Job-Isolation, Admin-Rolle)
|
||
- [x] **HTTPS via selbst-signiertem Zertifikat** (Mikrofon-Zugriff am Handy)
|
||
- [x] **Idempotente Pipeline + Retry** — bei „Server disconnected" automatischer 1× Retry, Transkript wird beim manuellen Erneut-Versuchen weiterverwendet
|
||
- [x] **Diagnose-Panel pro Job** — Live-Heartbeat während laufender Mac-Calls + Mac-Worker-Log direkt in der UI
|
||
- [ ] Speaker-Diarization (Prio 2 — siehe `mac-worker/README.md`)
|
||
|
||
---
|
||
|
||
## Installation — Schritt für Schritt
|
||
|
||
Voraussetzungen:
|
||
|
||
- **Mac** (Apple Silicon empfohlen, M1/M2/M3/M4) mit min. 16 GB RAM, besser 32 GB.
|
||
- **Proxmox-Host** (oder beliebiger Linux-Host) für den LXC-Container.
|
||
- **Netzwerk**: Mac und LXC im selben LAN, der LXC muss den Mac auf Port 8080 erreichen.
|
||
|
||
### Schritt 1 — LXC-Container provisionieren (Proxmox)
|
||
|
||
Container mit:
|
||
|
||
- Debian 13 (Trixie) oder Ubuntu 24.04
|
||
- 2 vCPU, 2 GB RAM, 20 GB Disk reichen
|
||
- Statische LAN-IP, SSH-Zugang als root
|
||
|
||
### Schritt 2 — App im LXC installieren
|
||
|
||
Im Container als `root` einloggen, dann **eine** der folgenden Optionen wählen:
|
||
|
||
**Option A — Auto-Install per Curl** (Repo wird selbst geklont):
|
||
|
||
```bash
|
||
bash <(curl -sSL https://git.cynfo.net/christian/voice-agent/raw/branch/main/deploy/install.sh)
|
||
```
|
||
|
||
**Option B — Manuell aus geklontem Repo:**
|
||
|
||
```bash
|
||
git clone https://git.cynfo.net/christian/voice-agent.git /var/www/voice-agent
|
||
cd /var/www/voice-agent
|
||
./deploy/install.sh
|
||
```
|
||
|
||
Das Skript installiert idempotent:
|
||
|
||
1. apt-Pakete (`git python3-venv nginx ffmpeg openssl …`)
|
||
2. Deploy-User `deploy`, klont/aktualisiert Repo nach `/var/www/voice-agent`
|
||
3. Python-venv + Dependencies in `lxc-frontend/.venv`
|
||
4. `.env` aus Vorlage anlegen, `SESSION_SECRET` automatisch erzeugen
|
||
5. Verzeichnisse `/var/lib/voice-agent/{uploads,results}` + SQLite-DB
|
||
6. systemd-Service `voice-agent.service` (autostart, restart-on-failure)
|
||
7. Selbst-signiertes TLS-Zertifikat mit SAN (Hostname + IP)
|
||
8. Nginx HTTPS-Reverse-Proxy + HTTP→HTTPS Redirect
|
||
9. CLI-Wrapper `/usr/local/bin/voice-agent-admin`
|
||
|
||
Erneutes Ausführen aktualisiert auf den neuesten `main` (idempotent, kein Datenverlust — die SQLite-DB liegt unter `/var/lib/voice-agent/`, nicht im App-Verzeichnis).
|
||
|
||
### Schritt 3 — Mac-Worker einrichten
|
||
|
||
Auf dem Mac (Details in [`mac-worker/README.md`](mac-worker/README.md)):
|
||
|
||
```bash
|
||
# Repo holen
|
||
git clone https://git.cynfo.net/christian/voice-agent.git ~/voice-agent
|
||
cd ~/voice-agent/mac-worker
|
||
|
||
# Ollama + Modell (einmalig)
|
||
brew install ollama
|
||
launchctl setenv OLLAMA_HOST "0.0.0.0:11434"
|
||
brew services restart ollama
|
||
ollama pull llama3.1:8b
|
||
|
||
# Worker als LaunchAgent installieren — macht venv + Dependencies + Autostart in einem Rutsch
|
||
./deploy/install-launchagent.sh
|
||
```
|
||
|
||
Test vom LXC aus:
|
||
|
||
```bash
|
||
curl http://<MAC-LAN-IP>:8080/health
|
||
# erwartet: {"status":"ok","whisper_engine":"mlx","ollama_reachable":true,...}
|
||
```
|
||
|
||
### Schritt 4 — LXC mit Mac verbinden
|
||
|
||
Im LXC `MAC_API_URL` auf die Mac-LAN-IP setzen:
|
||
|
||
```bash
|
||
sudo nano /var/www/voice-agent/lxc-frontend/.env
|
||
# MAC_API_URL=http://192.168.x.y:8080
|
||
sudo systemctl restart voice-agent
|
||
```
|
||
|
||
### Schritt 5 — Erst-Anmeldung + Benutzen
|
||
|
||
Browser auf `https://<LXC-IP>/` — beim allerersten Aufruf legt die UI den initialen Admin an (Username + Passwort wählen). Bestehende Jobs werden diesem Konto zugeordnet.
|
||
|
||
Audio hochladen oder direkt in der UI aufnehmen → fertig.
|
||
|
||
---
|
||
|
||
## Update / Neudeployment
|
||
|
||
**LXC** — einfach nochmal:
|
||
|
||
```bash
|
||
sudo /var/www/voice-agent/deploy/install.sh
|
||
```
|
||
|
||
**Mac** — ein Befehl macht git-pull + pip-install + Worker-Restart + Health-Check:
|
||
|
||
```bash
|
||
~/voice-agent/mac-worker/deploy/update.sh
|
||
```
|
||
|
||
(Falls `update.sh` aus irgendeinem Grund nicht läuft, ist `./deploy/install-launchagent.sh restart` der manuelle Fallback.)
|
||
|
||
---
|
||
|
||
## Benutzer-Verwaltung / Passwort zurücksetzen
|
||
|
||
Auf dem LXC steht nach dem Deploy `voice-agent-admin` als Befehl bereit:
|
||
|
||
```bash
|
||
# Passwort zurücksetzen (z. B. Admin-Login vergessen)
|
||
sudo voice-agent-admin reset admin 'NeuesPasswort123'
|
||
|
||
# User auflisten / anlegen / löschen
|
||
sudo voice-agent-admin list
|
||
sudo voice-agent-admin create maria 'StartPasswort123'
|
||
sudo voice-agent-admin create chefin 'Geheim12345' --admin
|
||
sudo voice-agent-admin delete maria
|
||
|
||
# Passwort prüfen ohne Browser (Debug)
|
||
sudo voice-agent-admin verify admin 'NeuesPasswort123'
|
||
```
|
||
|
||
Vollständige Befehlsreferenz: [`lxc-frontend/README.md`](lxc-frontend/README.md#benutzer--und-passwort-verwaltung-per-cli).
|
||
|
||
---
|
||
|
||
## Profile
|
||
|
||
Jeder Job läuft mit einem **Verarbeitungs-Profil**, das die Prompts für Summary, Protokoll und das Layout des Exports steuert. Standard ist `meeting`. Das Standard-Profil je User wird im Web-UI im Header gewählt und bleibt gespeichert.
|
||
|
||
Mitgelieferte Profile (alle in `mac-worker/profiles/*.yaml`):
|
||
|
||
| Profil | Zweck |
|
||
|---|---|
|
||
| `meeting` | Klassisches Sitzungsprotokoll |
|
||
| `phone-call` | Telefonat-Notiz mit Beteiligten/Verabredungen |
|
||
| `memo` | Kurze Sprachnotiz / Diktat |
|
||
| `interview` | Interview mit Sprecherspuren |
|
||
| `one-on-one` | 1:1-Gespräch (Mitarbeiter / Kunde) |
|
||
| `brainstorm` | Ideen-Sammlung mit Cluster-Vorschlägen |
|
||
| `service-ticket` | IT-Service-Ticket aus Anruf-Mitschnitt |
|
||
| `incident-report` | Incident-Doku (was, wann, Auswirkung, Status) |
|
||
| `postmortem` | Post-Mortem mit Lessons-Learned |
|
||
| `site-survey` | Vor-Ort-Aufnahme (Leitungsverlauf, Hardware, Zustand) |
|
||
| `sales-call` | Sales-Gespräch mit Pain-Points / Next-Steps |
|
||
| `schichtuebergabe` | Schichtübergabe Pflege |
|
||
| `pflegedoku` | Pflegedokumentations-Eintrag |
|
||
| `sturzbericht` | Sturzbericht (Pflege) |
|
||
| `visite` | Arzt-Visite |
|
||
| `angehoerigengespraech` | Angehörigen-Gespräch (Pflege) |
|
||
| `biografie` | Biografie-Eintrag (Pflege) |
|
||
|
||
Eigene Profile: einfach eine weitere YAML-Datei in `mac-worker/profiles/` ablegen (Beispiel siehe `meeting.yaml`) und Mac-Worker neu starten.
|
||
|
||
---
|
||
|
||
## Diagnose / Troubleshooting
|
||
|
||
Wenn ein Job hängt oder fehlschlägt:
|
||
|
||
- **In der UI**: bei FAILED-Jobs und langlaufenden Stages erscheint **„Diagnose ▾"**. Aufklappen zeigt:
|
||
- aktuelle Stage und wie lange sie schon läuft
|
||
- letzter Heartbeat (alle 3 s während Mac-Calls)
|
||
- die letzten 200 Mac-Worker-Log-Zeilen für genau diesen Job
|
||
- **Auf dem LXC**:
|
||
- `systemctl status voice-agent` / `journalctl -u voice-agent -f`
|
||
- `curl -sk https://localhost/api/mac/health`
|
||
- **Auf dem Mac**:
|
||
- `~/voice-agent/mac-worker/deploy/install-launchagent.sh status`
|
||
- `tail -f ~/Library/Logs/voice-agent-worker.{out,err}.log`
|
||
|
||
Wenn der Mac mitten in `summarize` die Verbindung abreissen lässt, retried der LXC einmal automatisch (3 s Backoff) — ein vorgelagerter Preload-Aufruf hat zudem das Ollama-Modell schon ins RAM geladen, damit es nicht in der eigentlichen Generierung neu lädt.
|
||
|
||
---
|
||
|
||
## Modelle
|
||
|
||
### Transkription (Mac, Whisper)
|
||
|
||
| `WHISPER_ENGINE` | `WHISPER_MODEL` | Wann nutzen |
|
||
|---|---|---|
|
||
| `mlx` | `large-v3` (Default) | Maximale Qualität, langsamer (~0.3× Realzeit auf M2) |
|
||
| `mlx` | `distil-large-v3` | ~5× schneller, minimal schlechtere Qualität |
|
||
| `mlx` | `medium` | Schneller, deutlich schlechter bei Fachbegriffen |
|
||
| `faster` | `large-v3` | Intel-Mac / Linux / CUDA |
|
||
| `mock` | – | Tests ohne Modell-Download |
|
||
|
||
Standard ist `mlx` + `large-v3`. Für lange Sitzungen lohnt sich `distil-large-v3`. Alternativen (whisper.cpp + CoreML, WhisperX mit Diarization, Voxtral) sind in [`mac-worker/README.md`](mac-worker/README.md#alternative-transkriptions-engines) dokumentiert.
|
||
|
||
### Zusammenfassung (Ollama)
|
||
|
||
Standard: `llama3.1:8b` — solide Basisqualität bei deutschen Texten, ~8 GB Speicher.
|
||
|
||
Empfohlene Alternativen je nach Hardware (alle via `ollama pull <name>` und `OLLAMA_MODEL=<name>` in `.env`):
|
||
|
||
| Modell | Größe | RAM-Bedarf | Stärken |
|
||
|---|---|---|---|
|
||
| `llama3.1:8b` (Default) | 8 B | ~8 GB | Schnell, brauchbares Deutsch |
|
||
| `qwen2.5:14b` | 14 B | ~10 GB | Sehr zuverlässige JSON-Ausgabe, exzellentes Deutsch |
|
||
| `mistral-small:24b` | 24 B | ~16 GB | Europäisch trainiert, beste Kompromiss-Wahl |
|
||
| `gemma3:12b` | 12 B | ~10 GB | Stark multilingual, gute Strukturierung |
|
||
| `gpt-oss:20b` | 20 B | ~14 GB | Sehr gute strukturierte Ausgabe (OpenAI Open-Weight) |
|
||
| `llama3.3:70b` | 70 B | ~48 GB | Top-Qualität, nur auf Macs mit 64 GB+ |
|
||
|
||
Für deutsche Protokolle mit viel JSON-Struktur ist **`qwen2.5:14b`** oder **`mistral-small:24b`** der beste Sweet-Spot auf einem Mac mit 32 GB.
|
||
|
||
Detaillierte Bewertung siehe [`mac-worker/README.md`](mac-worker/README.md#ollama-modell-wählen).
|
||
|
||
---
|
||
|
||
## Verzeichnisstruktur
|
||
|
||
```
|
||
voice-agent/
|
||
├── lxc-frontend/ # FastAPI Web-App (läuft im LXC)
|
||
│ ├── app/
|
||
│ ├── requirements.txt
|
||
│ └── .env.example
|
||
├── mac-worker/ # FastAPI AI-Worker (läuft auf dem Mac)
|
||
│ ├── app/
|
||
│ ├── profiles/ # YAML-Profile (Prompts + Layout)
|
||
│ ├── deploy/ # install-launchagent.sh, update.sh, plist-Template
|
||
│ ├── requirements.txt
|
||
│ └── .env.example
|
||
├── deploy/ # systemd / nginx / install.sh (LXC)
|
||
├── config/ # Toolkit-Konfiguration (project.env)
|
||
├── .claude/ # KI-Agenten Skills
|
||
├── need.md # Lastenheft
|
||
└── README.md
|
||
```
|
||
|
||
## Sicherheit
|
||
|
||
- Vollständig lokaler Betrieb. Keine Cloud-Calls.
|
||
- HTTPS mit selbst-signiertem Cert (für Mikrofon-Zugriff am Handy zwingend nötig).
|
||
- Web-UI ist Cookie-Session-basiert (bcrypt cost 12, signiert mit `SESSION_SECRET`).
|
||
- Mac-Worker hat **keine** Auth — Betrieb nur im internen Netz.
|
||
- Uploads / Ergebnisse unter `/var/lib/voice-agent/` — bei Bedarf Backup einplanen.
|
||
- `.env`-Dateien (LXC + Mac) sind chmod 600, enthalten Session-Secret + ggf. Tokens.
|