Neuer Endpoint POST /api/jobs/{id}/reprocess: erlaubt einen LLM-Lauf
auch auf done/failed-Jobs, sichert Summary/Protokoll/DOCX/PDF in
results/<id>/runs/<ts>-<modell>/ als Snapshot, leert die DB-Pfade,
startet die Pipeline mit dem aktuell auf dem Mac konfigurierten
Ollama-Modell. Transkript bleibt erhalten.
GET /api/jobs/{id}/runs liefert die Snapshot-Liste,
GET /api/jobs/{id}/runs/{run_id}/{file} den Einzeldownload.
UI: zwei neue Buttons auf done/failed-Jobs — "↻ Mit anderem Modell"
und "Verlauf ▾". Reprocess-Dialog zeigt das aktuell konfigurierte
Mac-Modell an, bevor er startet, damit kein Versehen passiert.
Verlauf-Panel listet pro Lauf Modellname + Zeitstempel + Download-
Links für die Snapshot-Dateien.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Voice-Agent — LXC-Frontend
FastAPI + statisches HTML/JS. Läuft im LXC-Container, stellt die Weboberfläche, verwaltet Jobs (SQLite) und ruft den Mac-Worker per HTTP an. Macht selbst keine AI-Verarbeitung.
Lokal starten (Entwicklung)
cd lxc-frontend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# Für lokalen Test ohne Mac kann der Mac-Worker mit WHISPER_ENGINE=mock laufen
uvicorn app.main:app --reload --port 8000
Öffnen: http://localhost:8000
Auf LXC deployen
deploy/install.sh macht alles: Repo klonen, venv anlegen, systemd-Service und Nginx einrichten. Siehe Haupt-README.md.
API
| Methode | Pfad | Zweck |
|---|---|---|
| GET | / |
Web-UI |
| GET | /health |
LXC-Health |
| GET | /api/mac/health |
Mac-Worker-Erreichbarkeit |
| GET | /api/profiles |
Verfügbare Verarbeitungs-Profile (Cache 60 s) |
| POST | /api/auth/login / logout / setup |
Cookie-Session-Auth |
| GET / PATCH | /api/auth/me |
Eigener User + Standard-Profil |
| GET / POST / DELETE | /api/admin/users[...] |
User-Verwaltung (admin) |
| POST | /api/jobs |
multipart: audio, title, profile → Job anlegen |
| GET | /api/jobs |
Liste aller Jobs (Owner-gefiltert; Admin sieht alle) |
| GET | /api/jobs/{id} |
Job-Detail (inkl. step_started_at, last_heartbeat_at) |
| GET | /api/jobs/{id}/diag |
Diagnose-Bündel: Stage-Sekunden + Mac-Worker-Log |
| POST | /api/jobs/{id}/retry |
Verarbeitung neu anstoßen (Transkript bleibt) |
| GET | /api/jobs/{id}/download/{kind} |
kind ∈ pdf, docx, transcript, summary, protocol |
Benutzer- und Passwort-Verwaltung per CLI
Nach dem Deploy ist /usr/local/bin/voice-agent-admin verfügbar — ein Wrapper auf das Python-Modul app.cli. Funktioniert vom Root-Login aus jedem Verzeichnis.
# Alle User auflisten
sudo voice-agent-admin list
# Passwort eines Users zurücksetzen (z. B. Admin-Passwort vergessen)
sudo voice-agent-admin reset admin 'NeuesPasswort123'
# Neuen User anlegen
sudo voice-agent-admin create maria 'StartPasswort123'
sudo voice-agent-admin create chefin 'Geheim12345' --admin
# User zum Admin machen
sudo voice-agent-admin promote maria
# User löschen (geht nicht für den letzten Admin oder den eigenen Account)
sudo voice-agent-admin delete maria
# Passwort prüfen ohne Browser (für Debug)
sudo voice-agent-admin verify admin 'NeuesPasswort123'
# → "OK — Passwort für 'admin' stimmt." oder "NEIN — ..."
Mindest-Passwortlänge: 8 Zeichen. Der letzte Admin kann nicht gelöscht werden.
Initialer Admin
Beim allerersten Web-Aufruf zeigt die UI das Setup-Formular statt des Logins (weil noch kein User existiert). Username + Passwort eingeben → erster Admin wird angelegt + alle bestehenden Jobs werden ihm zugeordnet.
Falls du den Erst-Admin lieber per CLI anlegen willst (z. B. Skript-gesteuert):
sudo voice-agent-admin create admin 'StartPasswort123' --admin
Danach im Browser direkt einloggen.
Datenfluss
Upload → SQLite-Job → BackgroundTask (idempotent)
→ Mac: /api/transcribe (multipart)
→ Mac: /api/preload (Modell ins RAM ziehen, vor Summarize)
→ Mac: /api/summarize (JSON)
→ Mac: /api/protocol (JSON)
→ Mac: /api/export/docx (JSON) → DOCX
→ Mac: /api/export/pdf (JSON) → PDF
→ Ergebnisse landen in /var/lib/voice-agent/results/{job_id}/
Während laufender Mac-Calls pingt ein Heartbeat alle 3 s last_heartbeat_at.
Bei RemoteProtocolError / ConnectError retried der MacClient einmal automatisch
mit 3 s Backoff. Jeder Mac-Call trägt einen X-Job-Id-Header — der Mac-Worker
sammelt damit pro Job einen Log-Ringbuffer (200 Zeilen, 1 h TTL), den
/api/jobs/{id}/diag für die UI bündelt.