32 Commits

Author SHA1 Message Date
root
dbf7bca6c7 feat(jobs): "Mit anderem Modell verarbeiten" + Verlauf pro Job
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>
2026-05-16 07:58:23 +00:00
root
031d52c77a fix(profiles): KeyError bei JSON-Beispielen in Prompt-Templates
Bug: 9 von 17 Profilen (phone-call, brainstorm, one-on-one, postmortem,
schichtuebergabe, pflegedoku, visite, biografie) zeigen in ihren Prompts
JSON-Schema-Beispiele wie {"owner", "task"}. Python's str.format() liest
diese geschweiften Klammern als Platzhalter und wirft KeyError →
HTTP 500 vom Mac-Worker → Job FAILED bei summarize/protocol.

Fix:
- Neuer render(template, **vars) Helper in ollama_client: ersetzt nur
  explizit benannte Platzhalter, lässt alles andere literal stehen.
- summarize/make_protocol nutzen diesen Helper statt .format()
- profiles.validate_all() warnt beim Worker-Start, wenn ein erwarteter
  Platzhalter fehlt — Defekte werden früh sichtbar
- Mac-Worker-Middleware fängt unhandled exceptions und liefert JSON-Body
  mit Type+Message+Traceback-Tail (statt generic "Internal Server Error")
- LXC MacClient liest diesen Error-Body und packt ihn in die HTTPStatusError-
  Message → landet im Job-error-Feld + Diagnose-Panel mit echter Wurzel-Info

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 06:55:55 +00:00
root
bc497a1665 docs+install: vollständiger Installer + aktuelle README
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>
2026-05-14 20:36:35 +00:00
root
f408a555f8 feat: kontinuierliche LXC↔Mac-Diagnose + Auto-Retry
Diagnose-Sichtbarkeit (Plan A):
- Job.step_started_at + last_heartbeat_at, Heartbeat-Task pingt alle 3 s
  während laufender Mac-Calls
- Mac-Worker hält per X-Job-Id Header einen Log-Ringbuffer pro Job
  (200 Zeilen, 1 h TTL); GET /api/jobs/{id}/log liefert ihn aus
- LXC-Endpoint GET /api/jobs/{id}/diag bündelt Job-Status, Stage-Sekunden,
  Heartbeat-Alter und Mac-Worker-Log
- Frontend: Live-Timing im Status-Pill ("läuft seit Xs · letzter Ping vor Ys"),
  klappbares Diagnose-Panel mit Mac-Log für FAILED + langlaufende Jobs

Robustheit (Plan B):
- MacClient: einmaliger Retry mit 3 s Backoff bei RemoteProtocolError /
  ConnectError / ReadError für summarize/protocol/export
- Mac-Worker /api/preload heizt Ollama vor (keep_alive 30 m, num_predict 1);
  Pipeline ruft Preload vor summarize, damit Modell-Reload nicht mitten
  in der Generierung passiert (Hauptursache "Server disconnected")

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 09:12:27 +00:00
root
354e4c57eb feat: PDF-Export zusätzlich zu DOCX
Mac-Worker:
- pdf_export.py mit reportlab (pure Python, kein externes Tool)
- Nutzt dieselbe profile.docx-Konfig wie der DOCX-Renderer →
  strukturell identisch, nur andere Optik
- POST /api/export/pdf
- requirements: reportlab==4.2.5

LXC:
- Job.pdf_path neu (Migration: ALTER TABLE job ADD COLUMN)
- Pipeline-Step nach DOCX: PDF wird ebenfalls erzeugt
  (Progress: 90 DOCX → 95 PDF → 100 done)
- /api/jobs/{id}/download/pdf
- /api/jobs/{id}/retry löscht PDF mit, damit es neu erzeugt wird
- Frontend: zusätzlicher Download-Button "PDF" (vorne im Array)
- Tabelle: Download-Spalte 320px, 3-spaltiges Grid (5 Buttons → 3+2)
- Cards (Mobile) bleiben 2-spaltig (5 Buttons → 3 Zeilen)
2026-05-14 04:48:47 +00:00
root
7d4961933e docs: voice-agent-admin CLI dokumentiert (Passwort-Reset, User-Verwaltung) 2026-05-14 04:39:13 +00:00
root
3d39d3e829 fix(ollama): Streaming statt Single-Request — beendet ReadTimeout bei langen Antworten
Vorher: stream=False → der gesamte Generierungs-Lauf musste innerhalb des
Read-Timeout (default 600 s) abgeschlossen sein. Bei langen Transkripten
oder größeren Modellen reicht das nicht und der Mac-Worker wirft
httpx.ReadTimeout.

Jetzt: stream=True + httpx.Timeout(read=...) pro Chunk. Solange Ollama
kontinuierlich Tokens liefert, läuft kein Timeout. Zusätzlich keep_alive
30m, damit das Modell zwischen Calls im RAM bleibt (kein erneuter
Load-Overhead).

Logs jetzt mit Chunk-Anzahl + Gesamtlänge — leichter zu debuggen.
2026-05-14 04:15:23 +00:00
root
220b7ccbc3 feat: Retry-Funktion + idempotente Pipeline (Transkript bleibt erhalten)
Backend:
- POST /api/jobs/{id}/retry — löscht summary/protocol/docx, queued den Job
  neu und startet Pipeline. Transkript bleibt erhalten (teurer Schritt).
- Pipeline überspringt Steps, deren Output-Datei schon existiert →
  retry rennt direkt in summarize ohne erneute Transkription.

Frontend:
- Kleiner gelber '↻ Erneut versuchen'-Button in jeder Job-Zeile/-Karte
  wenn Status != done
- Confirm-Dialog erklärt was passiert
- Event-Delegation, funktioniert für Tabelle (Desktop) und Cards (Mobile)
2026-05-14 04:11:13 +00:00
root
24ac3ac058 ui: echte Mobile-First-Variante — Recording-Hero, Job-Cards, Admin-Klappe
Mobile-Layout ab <700px komplett umgebaut, nicht mehr nur Desktop-Verkleinerung:

- Header: nur Logo + User + Profil-Mini-Dropdown + Logout
- Upload-Card: großer roter Aufnahme-Button als Hero-Element
  - Profil und Titel darunter, kompakt
  - Datei-Upload in <details>-Klappe (auf Desktop offen, Mobile zu)
- Jobs: Card-Liste statt Tabelle (Tabelle nur Desktop, Cards nur Mobile)
- Admin: H2 als Toggle, Body kollabiert (auf Desktop immer offen)
- Inputs auf Mobile mit font-size:16px → kein iOS-Zoom-on-Focus
- Recording-Pane: Timer 64px, Buttons full-width
- safe-area-inset für iPhone-Notch + Bottom-Bar

Ohne JS-Mode-Switch — alles via CSS Media Query +
.desktop-only / .mobile-only Helfer-Klassen. JS rendert beide
Job-Repräsentationen, CSS schaltet die richtige sichtbar.
2026-05-14 04:00:33 +00:00
root
e75bc05421 fix(deploy): ALLOWED_EXTS idempotent pflegen — ergänzt 'webm' falls fehlt 2026-05-14 03:48:08 +00:00
root
11ab8b57bf feat: PWA + Mikrofon-Aufnahme + HTTPS via selbst-signiertem Cert
Frontend-Aufnahme (MediaRecorder):
- Aufnahme-Button im Upload-Form, große Touch-Targets
- Start / Pause / Fortsetzen / Stop mit Live-Timer
- Format-Auto-Detect (Opus/WebM, Safari nimmt M4A)
- Wake Lock damit iOS nicht ins Sleep geht
- Aufnahme-Datei landet als File-Objekt im Upload-Flow
- Beim Submit: aufgenommene Datei bevorzugt vor File-Input

PWA:
- manifest.webmanifest, icon.svg + PNG-Icons (192/512)
- apple-mobile-web-app-capable + theme-color
- "Zum Home-Bildschirm" hinzufügen verwandelt Seite in App

Mobile-Layout:
- Single-Column ab 700px, größere Buttons
- Header stapelt sich vertikal
- Tabelle scrollt horizontal statt zu zerquetschen
- Safe-Area-Insets für iPhone-Notch

HTTPS (Pflicht für Mikrofon-Zugriff):
- install.sh erzeugt selbst-signiertes Cert (4096 Bit, 825 Tage, mit
  SAN aus Hostname + LAN-IP)
- Nginx: HTTP → HTTPS Redirect, Cert unter /ssl/voice-agent.crt
  ungesichert abrufbar (für bequemen iOS-Profil-Import)

Backend:
- ALLOWED_EXTS um 'webm' erweitert
2026-05-14 03:43:51 +00:00
root
05cf2ac349 feat(profiles): 16 Profile für Büro, IT-Systemhaus und Altenpflege
Büro:
- phone-call, memo, interview, one-on-one, brainstorm

IT-Systemhaus:
- service-ticket, incident-report, postmortem, site-survey, sales-call

Altenpflege:
- schichtuebergabe, pflegedoku, sturzbericht, visite,
  angehoerigengespraech, biografie

Alle Profile mit summary_prompt + protocol_prompt + docx-Layout.
Pflegeprofile mit explizitem "nichts erfinden"-Hinweis im Prompt.
2026-05-14 03:34:17 +00:00
root
482b344787 ui: Standard-Profil kompakt in die User-Bar oben statt eigener Karte
- Mini-Select neben dem User-Namen, speichert sofort bei change
- "Meine Einstellungen"-Karte entfernt
- Selector erscheint nur, wenn ≥2 Profile verfügbar (sonst nichts zu wählen)
2026-05-14 03:23:36 +00:00
root
3a9881d36f feat: Profile-System für unterschiedliche Use-Cases (Sitzungsprotokoll, später Arzt-Diktat etc.)
Mac-Worker:
- profiles/meeting.yaml — extrahiert die bisherigen Prompts + DOCX-Layout
- core/profiles.py — YAML-Loader mit Cache und Fallback
- ollama_client.summarize/make_protocol nehmen profile_name
- docx_export: generischer Renderer aus profile.docx (meta + sections mit
  Typ text/list/tasks/transcript)
- /api/profiles listet verfügbare Profile
- pyyaml als Dependency

LXC:
- Job.profile + User.default_profile (Migration: ALTER TABLE)
- /api/profiles proxy mit 60s-Cache und Fallback
- Upload-Form akzeptiert profile (Server-Default: user.default_profile)
- Pipeline gibt Profile bei summarize/protocol/docx an Mac weiter
- PATCH /api/auth/me — User kann Standard-Profil ändern

Frontend:
- Profile-Dropdown im Upload (nur sichtbar wenn ≥2 Profile)
- Settings-Karte "Mein Standard-Profil" (nur wenn ≥2 Profile)
- Job-Zeile zeigt grünes Profile-Tag (nur wenn relevant)

Neue Profile = neue YAML-Datei in mac-worker/profiles/ — kein Code-Deploy
nötig, der Mac-Worker liest sie beim Start ein.
2026-05-14 03:11:30 +00:00
root
98cf9eb47e fix(ui): .hidden mit !important — Overlay verschwand nach Login nicht (display:flex auf .overlay überschrieb display:none) 2026-05-14 02:54:22 +00:00
root
42443e1f23 fix(cli): chdir nach lxc-frontend, damit pydantic-settings die .env findet
Beim Aufruf aus /root oder anderen Verzeichnissen scheiterte der CLI mit
PermissionError, weil pydantic-settings .env relativ zum Arbeitsverzeichnis
liest und z. B. /root/.env stat-en wollte (für deploy nicht lesbar).
2026-05-14 02:52:13 +00:00
root
a681ca871b fix(cli): sys.path-Fix für direktes Skript-Aufrufen + Wrapper voice-agent-admin
- cli.py fügt lxc-frontend/ zu sys.path hinzu, sodass
  `python /pfad/zu/cli.py <cmd>` aus jedem Verzeichnis funktioniert
  (vorher nur via `python -m app.cli` aus dem App-Verzeichnis)
- install.sh legt /usr/local/bin/voice-agent-admin als Wrapper an,
  damit man einfach `sudo voice-agent-admin list` aufrufen kann
2026-05-14 02:47:28 +00:00
root
44528ef655 feat(auth): CLI-Tool für Notfall-User-Verwaltung + besseres Login-Logging
- app/cli.py: list / create / reset / promote / delete / verify
  Aufruf: .venv/bin/python -m app.cli <befehl>
- Login-Endpoint loggt jetzt getrennt "User nicht gefunden" vs. "Passwort
  falsch" inkl. Hash-Länge — erlaubt Diagnose ohne Code-Änderung
2026-05-14 02:44:21 +00:00
root
a1167df4f1 feat: User-Verwaltung mit Login, Sessions und Owner-Filter
Backend:
- User-Modell (sqlmodel) mit bcrypt-Passwort-Hash und is_admin-Flag
- Job.owner_id (FK auf user.id), per Migration nachgerüstet (SQLite ALTER)
- Starlette SessionMiddleware mit signiertem Cookie (SESSION_SECRET)
- /api/auth: login / logout / me / needs-setup / setup (Initial-Admin)
- /api/admin: User-CRUD + Passwort-Reset (Admin-only); letzter Admin /
  eigener Account vor Löschung geschützt
- /api/jobs: Owner-Filter (Admin sieht alle inkl. owner_username),
  404 statt 403 bei fremden Jobs (kein Existenz-Leak)

Frontend:
- Auth-Overlay mit Login bzw. Erst-Setup-Modus (auto-Detection)
- Header zeigt User + Logout, Admin-Badge bei Admin-Konten
- Admin-Karte: User anlegen, Passwort zurücksetzen, Löschen (mit Confirm)
- 401 → Login-Overlay (auch bei XHR-Upload)

Deploy:
- install.sh generiert SESSION_SECRET einmalig per python-secrets
- .env wird auf chmod 600 gesetzt
- Erstaufruf zeigt automatisch das Setup-Formular; bestehende Jobs werden
  dem ersten Admin zugeordnet
2026-05-14 02:38:52 +00:00
root
d4b0d21ed1 fix(frontend): no-cache Header für Static-Files und Index
Browser haben nach Deploys die alten app.js / style.css aus dem Cache
weiterbenutzt. Mit Cache-Control: no-cache, must-revalidate wird bei
jeder Anfrage revalidiert (304 wenn unverändert, 200 wenn neu).
2026-05-14 02:24:58 +00:00
root
b57f44cc73 ui: Job-Tabelle aufräumen — feste Spaltenbreiten, Download-Buttons, Fehler unter Status
- table-layout: fixed mit definierten Spaltenbreiten (Status 110px, Downloads 280px)
- Status-Pill bleibt kompakt (white-space: nowrap, nur Status-Name)
- Fehlertext jetzt als eigene Zeile unter dem Pill, max. 3 Zeilen, mit Tooltip
- Downloads als 2x2-Grid aus Pill-Buttons (DOCX / Protokoll / Summary / Transkript)
- Disabled-Buttons grau und ohne href
- HTML-Escape für Titel/Filename/Fehler
2026-05-14 02:20:21 +00:00
root
955075e3fd feat(mac-worker): LaunchAgent für Dauerbetrieb auf dem Mac
- com.voiceagent.worker.plist.template — User-LaunchAgent mit RunAtLoad,
  KeepAlive(Crashed=true), ProcessType=Interactive für MLX/Metal-Zugriff
- install-launchagent.sh — generiert plist mit Pfaden, lädt via launchctl,
  prüft Health-Endpoint; unterstützt install/uninstall/status
- READMEs: Abschnitt "Worker als Dienst" mit Verwaltungs-Befehlen
2026-05-13 22:30:50 +00:00
root
0bbb7bbacd docs: detaillierte Installations-Anleitung + Modell-Übersicht
- README: 5-Schritt-Installation (LXC + Mac), Update-Pfad, neue Sektion
  "Modelle" mit Whisper- und Ollama-Optionen
- mac-worker/README: vollständige Tabellen für MLX-Whisper-Modelle und
  Ollama-Alternativen (qwen2.5, mistral-small, gemma3, gpt-oss, llama3.3),
  Empfehlungen nach Mac-RAM, Hinweise zu WhisperX/whisper.cpp/Voxtral
2026-05-13 19:02:01 +00:00
root
cb60172b51 fix(mac-worker): handle MLX segments as list/tuple in addition to dict
lightning-whisper-mlx returns segments as [start, end, text] lists
(not dicts) in some versions, which broke transcribe(). Normalize all
three observed shapes: str output, list/tuple segments, dict segments.
Also fall back to joining segment texts when top-level text is empty.
2026-05-13 16:00:30 +00:00
root
27f2f91ec6 fix(deploy): install sudo on minimal Debian, use runuser instead of sudo
Minimal-LXC-Templates (debian-13-standard) have no sudo. Script
runs as root anyway, so switch to runuser. Also install sudo so
the systemd service file's 'User=deploy' has the helper available
when needed.
2026-05-13 15:47:27 +00:00
root
5321c8602e feat: voice-agent MVP — LXC web frontend + Mac AI worker
LXC-Frontend (FastAPI + HTML/JS):
- Audio-Upload (MP3/WAV/M4A/MP4/OGG/FLAC, max. 500 MB)
- SQLite Job-Store, BackgroundTask-Pipeline
- Job-Liste mit Live-Status, Downloads (DOCX + JSON)
- Mac-Health-Indicator im UI

Mac-Worker (FastAPI):
- /api/transcribe (lightning-whisper-mlx | faster-whisper | mock)
- /api/summarize + /api/protocol via Ollama (llama3.1:8b)
- /api/export/docx via python-docx

Deploy:
- systemd-Service, Nginx Reverse-Proxy
- deploy/install.sh: idempotentes LXC-Setup

Doku: README.md, lxc-frontend/README.md, mac-worker/README.md
2026-05-13 15:33:53 +00:00
32ab12014f fix: allow all permissions to eliminate confirmation prompts
Bash(*), Read(*), Write(*), Edit(*), Glob(*), Grep(*) - no more prompts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 23:36:04 +01:00
218c0f0deb fix: broad permissions, git-based deploy, correct workflow order
- settings.local.json: wildcard permissions for git, ssh, curl, npm, docker
  to eliminate constant confirmation prompts
- ssh-deploy: git clone/pull as primary deploy method, rsync as fallback
- workflow provision: git-push before ssh-deploy (push to Gitea first,
  then git clone on LXC)
- all workflows: deploy steps now explicitly git-based

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 23:19:27 +01:00
036e5d63f8 feat: auto-detect LXC IP and pass to ssh-deploy
- proxmox-lxc: new section to read LXC IP via API or pct exec
- ssh-deploy: SSH_HOST auto-populated from LXC IP, no manual config needed
- workflow: provision flow explicitly includes IP detection step
- project.env: SSH_HOST marked as optional when using Proxmox LXC

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 22:35:43 +01:00
acceefe99b chore: upgrade to Debian 13 (Trixie), Node.js 22 LTS, PostgreSQL 17
- LXC templates: debian-13-standard (default)
- Docker images: node:22-alpine, postgres:17-alpine
- TypeScript target: ES2022
- Updated template references (Ubuntu 24.04, Alpine 3.20)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 22:01:28 +01:00
c5808dbf55 feat: add Proxmox LXC skill for container provisioning
- New /proxmox-lxc skill: create, configure, and manage LXC containers
  on Proxmox servers via API and SSH
- Includes Node.js/Docker base setup, Nginx reverse proxy templates
- Integrated into /ssh-deploy and /workflow orchestrator
- New workflow: /workflow provision for full LXC + deploy pipeline
- Added PVE config section to project.env.template

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:54:12 +01:00
dbe08b4814 chore: initial setup KI-Agenten Toolkit
10 wiederverwendbare Claude Code Skills für React + Node.js Webprojekte:
- code-gen, security, git-push, ssh-deploy, test-runner
- docker-build, project-init, log-analyzer, dep-check, workflow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:07:32 +01:00