feat(admin): Backend-Wechsel + Gateway-Neustart aus dem Admin-Panel — Plan-Schritt 3
- admin_llm: switch_backend() mit strikter Allowlist (backend ∈ {ollama,llamacpp},
Modell gegen 'ollama list' + Format-Regex), detached (Self-Restart-sicher),
niemals shell=True. restart_gateway_detached() für systemd-User-Dienst.
- switch-llm.sh: flock-Lock gegen parallele Backend-Wechsel (Exit 75).
- Endpunkte POST /api/admin/llm/backend (422 bei ungültig) und
POST /api/admin/gateway/restart (require_admin).
- Status-Tab: Steuerung (Backend-Dropdown + Modell, Wechseln/Neustart) mit
Poll bis das Gateway wieder antwortet; Hinweis auf systemd-Voraussetzung.
- Tests: Auth + Allowlist (Shell-Metazeichen/unbekanntes Modell -> 422). 165 grün.
- Doku §7.5.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
97ae0a5d34
commit
5b6f0f8ef2
7 changed files with 219 additions and 6 deletions
|
|
@ -6,7 +6,12 @@ from fastapi import APIRouter, Depends, HTTPException, Request, WebSocket, WebSo
|
|||
from fastapi.responses import FileResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.admin_llm import llm_status
|
||||
from app.admin_llm import (
|
||||
LlmControlError,
|
||||
llm_status,
|
||||
restart_gateway_detached,
|
||||
switch_backend,
|
||||
)
|
||||
from app.auth import is_admin_user, require_admin, require_admin_or_user
|
||||
from app.config import settings
|
||||
from app.dependencies import get_store
|
||||
|
|
@ -196,6 +201,27 @@ async def get_llm_status():
|
|||
return await llm_status()
|
||||
|
||||
|
||||
class BackendSwitch(BaseModel):
|
||||
backend: str
|
||||
model: str | None = None
|
||||
|
||||
|
||||
@router.post("/admin/llm/backend", dependencies=[Depends(require_admin)])
|
||||
async def post_llm_backend(payload: BackendSwitch):
|
||||
"""Wechselt das LLM-Backend (Allowlist-validiert, detached). Greift voll erst,
|
||||
wenn das Gateway als systemd-Dienst läuft; sonst muss es manuell neu starten."""
|
||||
try:
|
||||
return await switch_backend(payload.backend, payload.model)
|
||||
except LlmControlError as exc:
|
||||
raise HTTPException(status_code=422, detail=str(exc))
|
||||
|
||||
|
||||
@router.post("/admin/gateway/restart", dependencies=[Depends(require_admin)])
|
||||
async def post_gateway_restart():
|
||||
"""Startet das Gateway (systemd-User-Dienst) neu — losgelöst, Self-Restart-sicher."""
|
||||
return restart_gateway_detached()
|
||||
|
||||
|
||||
# ── Aussprache-Lexikon CRUD ─────────────────────────────────────────────────
|
||||
|
||||
def _read_pronunciation(lang: str) -> dict:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue