feat(model): wählbares LLM-Modell pro User & pro Job
Mac-Worker: - /api/summarize, /api/protocol, /api/preload akzeptieren optionales model-Feld → überschreibt den .env-Default pro Call, kein Restart nötig - /api/models listet die lokal verfügbaren Ollama-Modelle + Default LXC: - User.default_model + Job.model (Migration für SQLite) - /api/auth/me liefert default_model, PATCH speichert ihn sofort - /api/mac/models proxiet die Liste an die UI - Pipeline reicht job.model an Mac-Worker durch; leer = Worker-Default - create_job & reprocess akzeptieren model-Override - Snapshot-Meta nutzt job.model (genauer als /health-Snapshot) UI: - Header-Dropdown "Modell:" neben "Profil:" — sofort-speichert User-Default - Jeder Job zeigt sein Modell als Tag (lila); leer bedeutet Worker-Default - Reprocess öffnet einen Modal-Picker (statt simplem confirm), Auswahl aller verfügbaren Modelle inkl. "Worker-Default" Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -86,6 +86,13 @@ class MacClient:
|
||||
r.raise_for_status()
|
||||
return r.json().get("profiles", [])
|
||||
|
||||
async def list_models(self) -> dict:
|
||||
"""Liefert {models: [...], default: <worker .env default>}."""
|
||||
async with httpx.AsyncClient(timeout=10) as c:
|
||||
r = await c.get(f"{self.base_url}/api/models")
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
async def fetch_log(self, job_id: int, last: int = 200) -> list[str]:
|
||||
"""Holt die letzten Mac-Worker-Logzeilen für einen Job (für die Diagnose-Anzeige)."""
|
||||
try:
|
||||
@@ -97,11 +104,12 @@ class MacClient:
|
||||
log.warning("fetch_log job=%s failed: %s", job_id, e)
|
||||
return []
|
||||
|
||||
async def preload(self, profile: str | None = None, job_id: int | None = None) -> dict:
|
||||
async def preload(self, profile: str | None = None, model: str | None = None,
|
||||
job_id: int | None = None) -> dict:
|
||||
"""Vor-Heizen: Ollama soll das Modell laden, bevor der echte Call läuft."""
|
||||
return await self._post_json_retry(
|
||||
f"{self.base_url}/api/preload",
|
||||
{"profile": profile},
|
||||
{"profile": profile, "model": model},
|
||||
job_id,
|
||||
)
|
||||
|
||||
@@ -122,18 +130,19 @@ class MacClient:
|
||||
return r.json()
|
||||
|
||||
async def summarize(self, transcript: str, title: str = "", profile: str | None = None,
|
||||
job_id: int | None = None) -> dict:
|
||||
model: str | None = None, job_id: int | None = None) -> dict:
|
||||
return await self._post_json_retry(
|
||||
f"{self.base_url}/api/summarize",
|
||||
{"transcript": transcript, "title": title, "profile": profile},
|
||||
{"transcript": transcript, "title": title, "profile": profile, "model": model},
|
||||
job_id,
|
||||
)
|
||||
|
||||
async def protocol(self, transcript: str, summary: dict, title: str = "", profile: str | None = None,
|
||||
job_id: int | None = None) -> dict:
|
||||
model: str | None = None, job_id: int | None = None) -> dict:
|
||||
return await self._post_json_retry(
|
||||
f"{self.base_url}/api/protocol",
|
||||
{"transcript": transcript, "summary": summary, "title": title, "profile": profile},
|
||||
{"transcript": transcript, "summary": summary, "title": title, "profile": profile,
|
||||
"model": model},
|
||||
job_id,
|
||||
)
|
||||
|
||||
|
||||
@@ -55,6 +55,16 @@ def run_migrations() -> None:
|
||||
log.info("Migration: füge job.last_heartbeat_at hinzu")
|
||||
conn.execute(text("ALTER TABLE job ADD COLUMN last_heartbeat_at DATETIME"))
|
||||
|
||||
# 6) Modell-Auswahl: user.default_model + job.model
|
||||
user_cols = _existing_columns(conn, "user")
|
||||
if user_cols and "default_model" not in user_cols:
|
||||
log.info("Migration: füge user.default_model hinzu (leer = Worker-Default)")
|
||||
conn.execute(text("ALTER TABLE user ADD COLUMN default_model VARCHAR DEFAULT ''"))
|
||||
cols = _existing_columns(conn, "job")
|
||||
if "model" not in cols:
|
||||
log.info("Migration: füge job.model hinzu (leer = Worker-Default)")
|
||||
conn.execute(text("ALTER TABLE job ADD COLUMN model VARCHAR DEFAULT ''"))
|
||||
|
||||
|
||||
def assign_orphan_jobs_to(user_id: int) -> int:
|
||||
"""Weist alle Jobs ohne owner_id dem angegebenen User zu. Gibt Anzahl zurück."""
|
||||
|
||||
Reference in New Issue
Block a user