Feat: Discover zukunftssicher (Recency-Score) + Agent-Hirn (Hermes) im Modell-Manager
- discover.rank_runnable: Score aus Fit + Recency (lastModified, Halbwertszeit ~9 Mon) + Capability (params, log) + Popularity (downloads, log) -> neuere Generationen bevorzugt. - Agent-Hirn: neuer GET /api/agent/brain (aktuelles hermes-Modell + bestes NousResearch- Hermes-Update, versions-aware via Hermes-X.Y-Parsing). Cockpit zeigt "Agent-Hirn (Hermes)"-Karte mit aktuellem Brain + Aktualisieren-Button, wenn NousResearch eine neuere Generation hat (z.B. Hermes-4-14B -> Hermes-4.3-36B). Update installiert mit Rolle hermes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -6,14 +6,78 @@ Hermes' eigener Config verdrahtet (siehe docs/HERMES_SETUP.md).
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
import httpx
|
||||
import psutil
|
||||
|
||||
from config import ANYTHINGLLM_URL, HERMES_API_URL, HERMES_HOME, PC_EXECUTOR_URL
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _hermes_version(name: str) -> float | None:
|
||||
"""Versionszahl aus 'Hermes-4.3', 'Hermes-4', 'Nous-Hermes-2' → 4.3/4.0/2.0."""
|
||||
low = (name or "").lower()
|
||||
if "hermes" not in low:
|
||||
return None
|
||||
m = re.search(r"hermes[-_ ]?(\d+(?:\.\d+)?)", low)
|
||||
return float(m.group(1)) if m else None
|
||||
|
||||
|
||||
def hermes_brain_info() -> dict:
|
||||
"""Aktuelles Agent-Hirn (hermes-Rolle) + bestes verfügbares NousResearch-Hermes-Modell,
|
||||
das auf diese Hardware passt. Für den Modell-Manager: Brain sichtbar + updatebar,
|
||||
sobald NousResearch eine neuere Hermes-Generation veröffentlicht."""
|
||||
from services import discover, llamaswap
|
||||
from services.fit import evaluate_fit, extract_params_b
|
||||
|
||||
models = llamaswap.list_models()
|
||||
cur = next((m for m in models if m.get("role") == "hermes"), None)
|
||||
cur_ver = _hermes_version(cur["name"]) if cur else None
|
||||
cur_params = (cur.get("capabilities") or {}).get("params_b") if cur else None
|
||||
current = None
|
||||
if cur:
|
||||
current = {"name": cur["name"], "filename": cur.get("filename"),
|
||||
"params_b": cur_params, "quant": cur.get("quant"),
|
||||
"size_bytes": cur.get("size_bytes"), "version": cur_ver,
|
||||
"gguf_path": cur.get("gguf_path"), "incomplete": cur.get("incomplete")}
|
||||
|
||||
ram = psutil.virtual_memory().total / (1024 ** 3)
|
||||
best = None
|
||||
try:
|
||||
cands = []
|
||||
for r in discover._fetch_author_models("NousResearch"):
|
||||
rid = r.get("id", "")
|
||||
if "hermes" not in rid.lower():
|
||||
continue
|
||||
pb = extract_params_b(rid)
|
||||
fit = evaluate_fit(pb, "Q4_K_M", 8192, ram, name=rid)
|
||||
if fit["level"] == "too_tight":
|
||||
continue
|
||||
cands.append({"repo": rid, "name": rid.split("/")[-1],
|
||||
"version": _hermes_version(rid) or 0.0, "params_b": pb,
|
||||
"downloads": int(r.get("downloads") or 0), "fit": fit})
|
||||
# neueste Hermes-Version zuerst, dann größer/fähiger, dann beliebter
|
||||
cands.sort(key=lambda c: (c["version"], c["params_b"], c["downloads"]), reverse=True)
|
||||
best = cands[0] if cands else None
|
||||
except Exception:
|
||||
log.debug("hermes_brain_info: HF-Abfrage fehlgeschlagen", exc_info=True)
|
||||
|
||||
update = False
|
||||
if best is not None:
|
||||
if cur_ver is None:
|
||||
update = True
|
||||
elif best["version"] > cur_ver:
|
||||
update = True
|
||||
elif best["version"] == cur_ver and best["params_b"] > (cur_params or 0) * 1.05:
|
||||
update = True
|
||||
# gleiche Datei schon installiert? dann kein Update
|
||||
if current and best["repo"].split("/")[-1].lower() in (current["name"] or "").lower():
|
||||
update = False
|
||||
return {"current": current, "recommended": best, "update_available": update}
|
||||
|
||||
|
||||
def _reach(url: str, path: str = "") -> bool:
|
||||
try:
|
||||
with httpx.Client(timeout=3.0) as c:
|
||||
|
||||
Reference in New Issue
Block a user