diff --git a/routers/maintenance.py b/routers/maintenance.py index 8e4ddee..e0a622e 100644 --- a/routers/maintenance.py +++ b/routers/maintenance.py @@ -72,9 +72,34 @@ def reboot(req: PwdReq): pass return {"ok": True, "note": "Reboot getriggert."} +_engine_cache = {"ts": 0.0, "avail": False} + + +def _engine_update_available(): + """Heuristik: ist die neueste llama.cpp-ROCm-Release neuer als die installierte? (1h gecacht)""" + import time + now = time.time() + if now - _engine_cache["ts"] < 3600: + return _engine_cache["avail"] + avail = False + try: + import os as _os + import httpx + from datetime import datetime + rel = httpx.get("https://api.github.com/repos/lemonade-sdk/llamacpp-rocm/releases/latest", + timeout=6, headers={"User-Agent": "MissionControl"}).json() + pub = datetime.fromisoformat(rel["published_at"].replace("Z", "+00:00")).timestamp() + inst = _os.path.getmtime("/opt/llamacpp") + avail = pub > inst + 86400 # neuer als Installation (1 Tag Puffer) + except Exception: # noqa: BLE001 + avail = False + _engine_cache.update(ts=now, avail=avail) + return avail + + @router.get("/updates") def updates(): - """Ausstehende Updates für die Toolbar: OS-Pakete (apt-Cache) + Modell-Upgrades.""" + """Ausstehende Updates für die Toolbar: OS-Pakete (apt), AI-Engine (llama.cpp), Modell-Upgrades.""" import psutil from routers.cookbook import compute_upgrades os_count = 0 @@ -89,7 +114,7 @@ def updates(): models = len(compute_upgrades(psutil.virtual_memory().total / (1024 ** 3))) except Exception: # noqa: BLE001 models = 0 - return {"os": os_count, "models": models} + return {"os": os_count, "models": models, "engine": 1 if _engine_update_available() else 0} @router.websocket("/logs/{service}") async def stream_logs(websocket: WebSocket, service: str): diff --git a/static/css/components.css b/static/css/components.css index 7584a16..9b32edf 100644 --- a/static/css/components.css +++ b/static/css/components.css @@ -151,6 +151,7 @@ textarea{resize:vertical;min-height:64px;font-family:var(--sans)} .upd-badge{font-size:11.5px;padding:4px 10px;border-radius:999px;cursor:pointer;white-space:nowrap; background:rgba(68,147,224,.14);color:#86b9ff;border:1px solid rgba(68,147,224,.25)} .upd-badge.warn{background:rgba(224,163,46,.14);color:#f0c570;border-color:rgba(224,163,46,.25)} +.upd-badge.ok{background:rgba(63,185,80,.12);color:#7ee29a;border-color:rgba(63,185,80,.22)} .upd-badge:hover{filter:brightness(1.12)} .mono-sm{font-family:var(--mono);font-size:11.5px;color:var(--mut)} diff --git a/static/js/main.js b/static/js/main.js index 232acd1..9602565 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -87,8 +87,9 @@ async function pollUpdates() { const u = await api("/api/updates"); const el = $("#update-badges"); if (!el) return; el.innerHTML = ""; - if (u.os > 0) el.appendChild(badge(`${u.os} OS-Updates`, "warn", "server")); - if (u.models > 0) el.appendChild(badge(`${u.models} Modell-Upgrade${u.models > 1 ? "s" : ""}`, "", "news")); + el.appendChild(badge(u.os > 0 ? `OS: ${u.os} Updates` : "OS: aktuell", u.os > 0 ? "warn" : "ok", "server")); + el.appendChild(badge(u.engine > 0 ? "Engine: Update" : "Engine: aktuell", u.engine > 0 ? "warn" : "ok", "server")); + el.appendChild(badge(u.models > 0 ? `Modelle: ${u.models}` : "Modelle: aktuell", u.models > 0 ? "warn" : "ok", "news")); } catch { /* still */ } } diff --git a/static/js/panels/guides.js b/static/js/panels/guides.js index 62b2d7b..99058f5 100644 --- a/static/js/panels/guides.js +++ b/static/js/panels/guides.js @@ -19,6 +19,17 @@ const TUTORIALS = [
Du musst nur selten eingreifen: wird ein Gespräch sehr lang, fang einen neuen an. Wichtig: „Grafikspeicher leeren" (Tab Server) ist etwas anderes — das wirft das Modell aus dem Speicher, nicht den Gesprächsverlauf.
`], + ["Was passiert, wenn der Kontext volläuft?", ` +Ist das Kontextfenster voll, passiert je nach Tool eins von dreien: das Modell vergisst den + Anfang (älteste Nachrichten fallen raus), das Tool kürzt automatisch, oder du bekommst + einen Fehler wie „context length exceeded".
+So gehst du vor:
+Kommt drauf an, was du willst: