fix(llm): Kontext-Auswahl zeigt wieder Maximum + GB — auch fuer Modelle auf der Platte
Seit "erst waehlen, dann Laden" zeigte die Kontext-Liste fuer ein noch nicht geladenes Modell nur feste Stufen — ohne Maximum und ohne Speicherbedarf. Jetzt: - llm-adapter: disk.models[].profiles — pro heruntergeladener Quantisierung Maximum (context_length) und GB je Stufe aus dem Kopf der GGUF (gleiche Rechnung wie fuer die geladene Karte, Annahme: alles auf der Karte). Gesplittete Modelle ausgenommen. - Diagnostic (Karte + Katalog-Spalte): Stufen bis zum Maximum, "(Maximum)" markiert, GB je Stufe, "⚠ passt nicht" bzw. bei MoE "⚠ nur mit Aufteilen". Nicht heruntergeladen: feste Stufen + Hinweis im Tooltip. Katalog rechnet mit der gewaehlten Ziel-Karte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -771,6 +771,13 @@ def _ctx_profile(key: str) -> dict:
|
||||
weights, mmproj = _model_files(key)
|
||||
if not weights:
|
||||
return {}
|
||||
return _profile_of_files(weights, mmproj, lambda: _model_cpu_moe(key))
|
||||
|
||||
|
||||
def _profile_of_files(weights: str, mmproj, cpu_moe_of=lambda: 0) -> dict:
|
||||
"""Wie _ctx_profile, aber fuer beliebige Dateien — auch heruntergeladene
|
||||
Modelle, die (noch) auf keiner Karte liegen. cpu_moe_of: Aufteilung der
|
||||
Experten (0 = Schaetzung "alles auf der Karte")."""
|
||||
meta = _gguf_meta(weights)
|
||||
arch = meta.get("general.architecture")
|
||||
if not arch:
|
||||
@@ -784,7 +791,7 @@ def _ctx_profile(key: str) -> dict:
|
||||
ctx_max = int(g("context_length", 0) or 0)
|
||||
exp_by_layer = meta.get("_expert_bytes_by_layer") or {}
|
||||
moe = bool(exp_by_layer) or int(g("expert_count", 0) or 0) > 0
|
||||
cpu_moe = _model_cpu_moe(key) if moe else 0
|
||||
cpu_moe = cpu_moe_of() if moe else 0
|
||||
if cpu_moe:
|
||||
layers = sorted(exp_by_layer) if cpu_moe < 0 else sorted(exp_by_layer)[:cpu_moe]
|
||||
ram_mb = sum(exp_by_layer[l] for l in layers) / 1048576
|
||||
@@ -1364,6 +1371,25 @@ async def _prefetch(ws, key: str, repo: str, files: list, card: str, cancel: thr
|
||||
return err
|
||||
|
||||
|
||||
def _disk_profiles(repo_dir: str) -> list:
|
||||
"""Kontext-Profil (Maximum + GB je Stufe, Annahme: alles auf der Karte) je
|
||||
heruntergeladener Quantisierung — damit die Diagnostic auch fuer Modelle,
|
||||
die auf keiner Karte liegen, zeigen kann, was sie koennen und kosten."""
|
||||
import glob
|
||||
files = [p for p in glob.glob(os.path.join(repo_dir, "snapshots", "*", "**", "*.gguf"), recursive=True)
|
||||
if os.path.isfile(p)]
|
||||
mmproj = next((p for p in files if "mmproj" in os.path.basename(p).lower()), None)
|
||||
out = []
|
||||
for w in files:
|
||||
if not _is_main_gguf(w) or _SPLIT_RE.search(w):
|
||||
continue # gesplittete Modelle: Groesse waere nur die des ersten Teils
|
||||
prof = _profile_of_files(w, mmproj)
|
||||
if prof:
|
||||
out.append({"quant": _quant_of(w), **{k: prof[k] for k in ("ctxMax", "options", "moe") if k in prof},
|
||||
**({"expertsMB": prof["expertsMB"]} if "expertsMB" in prof else {})})
|
||||
return out
|
||||
|
||||
|
||||
def _disk_info() -> dict:
|
||||
"""Freier Platz + fertig heruntergeladene Modelle (je Repo) fuer die Diagnostic."""
|
||||
out = {"freeBytes": 0, "models": []}
|
||||
@@ -1381,7 +1407,8 @@ def _disk_info() -> dict:
|
||||
except OSError:
|
||||
pass
|
||||
if size:
|
||||
out["models"].append({"repo": name[len("models--"):].replace("--", "/", 1), "bytes": size})
|
||||
out["models"].append({"repo": name[len("models--"):].replace("--", "/", 1), "bytes": size,
|
||||
"profiles": _disk_profiles(os.path.join(MODELS_DIR, name))})
|
||||
except OSError as e:
|
||||
logger.info("Plattenbelegung nicht lesbar: %s", e)
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user