Feat: "Auto"-Button beim Kontext setzen - setzt den setup-bewussten Optimalwert

Beim manuellen ctx-Eintrag (Modellkarte »Ctx«) gab es nur ein leeres Eingabefeld.
Jetzt:
- Backend: GET /api/models/{id}/ctx/auto liefert den setup-bewussten Optimal-ctx fuer
  ein bestehendes Modell (Rolle/Params/Quant + aktuelles Setup) inkl. Budget-Herleitung.
  budget.py: params_of_model() + setup_aware_ctx_for_model() (DRY mit footprint_gb).
- Dialog (CustomDialog/useDialog): optionaler Auto-Button im Prompt, der den Wert eintraegt.
- Cockpit: »Ctx« holt den Optimalwert, zeigt ihn + Budget (GTT/reserviert/frei) in der
  Meldung und bietet »Auto (Nk)« zum direkten Uebernehmen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-27 14:32:14 +02:00
parent 6d529e3f79
commit 1e011714dd
7 changed files with 153 additions and 91 deletions
+13
View File
@@ -162,6 +162,19 @@ class CtxReq(BaseModel):
ctx: int
@router.get("/models/{model_id}/ctx/auto")
def auto_ctx(model_id: str) -> dict:
"""Setup-bewusster Optimal-ctx für ein bestehendes Modell (Rolle/Params/Quant +
aktuelles Setup). Basis für den 'Auto'-Button an der Modellkarte."""
m = next((x for x in llamaswap.list_models() if x["name"] == model_id), None)
if not m:
raise HTTPException(404, "Modell nicht gefunden")
saw = budget.setup_aware_ctx_for_model(m)
return {"model_id": model_id, "current_ctx": m.get("ctx"),
"params_b": round(budget.params_of_model(m), 1), "quant": m.get("quant"),
"role": m.get("role"), **saw}
@router.post("/models/{model_id}/ctx")
def set_model_ctx(model_id: str, body: CtxReq) -> dict:
if not llamaswap.set_ctx(model_id, body.ctx):
+23 -6
View File
@@ -40,17 +40,26 @@ def gtt_budget_gb() -> float:
return round(psutil.virtual_memory().total / (1024 ** 3) - 6.0, 1)
def footprint_gb(model: dict) -> float:
"""Loaded-Footprint eines Modells = Gewichte + kalibrierter KV-Anteil. Params robust
aus dem MAXIMUM von Namens-Schätzung und Dateigröße (deckt 'Coder-Next' ohne Größe im
Namen sowie Split-GGUFs ab, deren size_bytes nur den ersten Teil zählt)."""
def params_of_model(model: dict) -> float:
"""Robuste Params (Mrd.) eines INSTALLIERTEN Modells: MAXIMUM aus Caps-Schätzung und
Dateigröße. Deckt 'Coder-Next' ohne Größe im Namen (→ aus Datei) und Split-GGUFs
(size_bytes = nur erster Teil → ignoriert) ab."""
caps = model.get("capabilities") or {}
quant = model.get("quant") or "Q4_K_M"
bpp = QUANT_BYTES_PER_PARAM.get(quant.upper(), 0.55)
size_gb = (model.get("size_bytes") or 0) / (1024 ** 3)
pb_size = (size_gb / bpp) if size_gb > 1.0 else 0.0
return max(float(caps.get("params_b") or 0), pb_size, 7.0)
def footprint_gb(model: dict) -> float:
"""Loaded-Footprint eines Modells = Gewichte + kalibrierter KV-Anteil (bei seinem
aktuellen ctx)."""
quant = model.get("quant") or "Q4_K_M"
ctx = int(model.get("ctx") or 32768)
bpp = QUANT_BYTES_PER_PARAM.get(quant.upper(), 0.55)
size_gb = (model.get("size_bytes") or 0) / (1024 ** 3)
pb_size = (size_gb / bpp) if size_gb > 1.0 else 0.0 # Split-Teil → ignoriert
pb = max(float(caps.get("params_b") or 0), pb_size, 7.0)
pb = params_of_model(model)
weights = max(pb * bpp, size_gb)
kv = estimate_memory_gb(pb, quant, ctx) - pb * bpp
return weights + max(kv, 0.0)
@@ -122,3 +131,11 @@ def setup_aware_ctx(params_b: float, quant: str, role: str | None = None) -> dic
"budget_gb": round(budget, 1),
"mode": r["mode"],
}
def setup_aware_ctx_for_model(model: dict) -> dict:
"""Setup-bewusster Optimal-ctx für ein INSTALLIERTES Modell (aus seiner Rolle,
Params & Quant). Für den 'Auto'-Button an der Modellkarte."""
return setup_aware_ctx(params_of_model(model),
model.get("quant") or "Q4_K_M",
role=model.get("role"))