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

58 lines
2.4 KiB
Python

from pathlib import Path
import httpx
from .config import settings
class MacClient:
def __init__(self, base_url: str | None = None, timeout: int | None = None):
self.base_url = (base_url or settings.mac_api_url).rstrip("/")
self.timeout = timeout or settings.mac_api_timeout
async def health(self) -> dict:
async with httpx.AsyncClient(timeout=10) as c:
r = await c.get(f"{self.base_url}/health")
r.raise_for_status()
return r.json()
async def list_profiles(self) -> list[dict]:
async with httpx.AsyncClient(timeout=10) as c:
r = await c.get(f"{self.base_url}/api/profiles")
r.raise_for_status()
return r.json().get("profiles", [])
async def transcribe(self, audio_path: Path, language: str = "de") -> dict:
async with httpx.AsyncClient(timeout=self.timeout) as c:
with audio_path.open("rb") as f:
files = {"audio": (audio_path.name, f, "application/octet-stream")}
data = {"language": language}
r = await c.post(f"{self.base_url}/api/transcribe", files=files, data=data)
r.raise_for_status()
return r.json()
async def summarize(self, transcript: str, title: str = "", profile: str | None = None) -> dict:
async with httpx.AsyncClient(timeout=self.timeout) as c:
r = await c.post(
f"{self.base_url}/api/summarize",
json={"transcript": transcript, "title": title, "profile": profile},
)
r.raise_for_status()
return r.json()
async def protocol(self, transcript: str, summary: dict, title: str = "", profile: str | None = None) -> dict:
async with httpx.AsyncClient(timeout=self.timeout) as c:
r = await c.post(
f"{self.base_url}/api/protocol",
json={"transcript": transcript, "summary": summary, "title": title, "profile": profile},
)
r.raise_for_status()
return r.json()
async def export_docx(self, data: dict, profile: str | None = None) -> bytes:
async with httpx.AsyncClient(timeout=self.timeout) as c:
r = await c.post(
f"{self.base_url}/api/export/docx",
json={"data": data, "profile": profile},
)
r.raise_for_status()
return r.content