Fix: "Modelle finden" bevorzugt faehigste passende Modelle (kein Downgrade) + Rollen-Farben zentral
- discover.rank_runnable: rankt jetzt fit-level > params_b(desc) > downloads -> fuer die 128GB-Box wird das faehigste passende (MoE-)Modell empfohlen statt kleiner Populaer-Modelle. Top-4-Anzeige nutzt dasselbe Ranking. - maintenance.model_upgrades: schlaegt KEIN Downgrade mehr vor (rec.params_b >= installiert*0.95). Behebt: fast 35B-A3B -> 4B wurde faelschlich als Upgrade angeboten. - Frontend: Rollen-Farb-Mapping zentralisiert in ModelBadges (ROLE_TONE/roleTone); Cockpit/RolesCard/ActiveModelsCard nutzen es statt eigener Duplikate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -47,12 +47,18 @@ def _fetch_author_models(author: str) -> list:
|
||||
|
||||
|
||||
def rank_runnable(models: list[dict]) -> list[dict]:
|
||||
"""EINE Quelle der Wahrheit fürs Ranking lauffähiger Modelle:
|
||||
bestes Fit-Level zuerst (perfect < marginal), bei Gleichstand meistgeladen.
|
||||
Zu große Modelle (too_tight) fliegen raus."""
|
||||
"""EINE Quelle der Wahrheit fürs Ranking lauffähiger Modelle für DIESE Hardware:
|
||||
1) nur was komfortabel passt (perfect vor marginal, too_tight fliegt raus),
|
||||
2) das FÄHIGSTE zuerst — mehr Parameter = mehr Können (bei MoE bleibt es dank
|
||||
aktiver-Param-Schätzung schnell),
|
||||
3) bei Gleichstand das meistgeladene.
|
||||
So bevorzugt die 128-GB-Box große (MoE-)Modelle statt kleiner Populär-Modelle —
|
||||
und „Modelle finden" schlägt nie ein Downgrade vor (z.B. 35B-A3B → 4B)."""
|
||||
return sorted(
|
||||
[m for m in models if m["fit"]["level"] != "too_tight"],
|
||||
key=lambda m: (_FIT_ORDER[m["fit"]["level"]], -int(m.get("downloads") or 0)),
|
||||
key=lambda m: (_FIT_ORDER[m["fit"]["level"]],
|
||||
-float(m.get("params_b") or 0.0),
|
||||
-int(m.get("downloads") or 0)),
|
||||
)
|
||||
|
||||
|
||||
@@ -97,9 +103,8 @@ def refresh_discover(ram_gb: float) -> dict:
|
||||
for c in CATEGORIES:
|
||||
items = by_cat[c["role"]]
|
||||
ranked = rank_runnable(items)
|
||||
# Top 4 je Kategorie (für die Anzeige) — gerankt, dann nach Downloads aufgefüllt.
|
||||
items.sort(key=lambda x: (x["fit"]["level"] != "too_tight", x["downloads"]), reverse=True)
|
||||
top = items[:4]
|
||||
# Top 4 je Kategorie = die best-gerankten (fähigstes-was-passt zuerst).
|
||||
top = ranked[:4]
|
||||
if top:
|
||||
cats.append({
|
||||
"role": c["role"], "title": c["title"], "icon": c["icon"],
|
||||
|
||||
@@ -164,6 +164,12 @@ def model_upgrades() -> list[dict]:
|
||||
|
||||
installed = llamaswap.list_models()
|
||||
active_roles = {m["role"] for m in installed if m.get("role")}
|
||||
# Größtes installiertes Modell je Rolle (params_b) — Basis für „kein Downgrade".
|
||||
inst_params: dict[str, float] = {}
|
||||
for m in installed:
|
||||
r, pb = m.get("role"), (m.get("capabilities") or {}).get("params_b")
|
||||
if r and pb:
|
||||
inst_params[r] = max(inst_params.get(r, 0.0), float(pb))
|
||||
|
||||
cmds = " ".join(str(s.get("cmd", "")).lower()
|
||||
for s in (llamaswap.read_config().get("models") or {}).values())
|
||||
@@ -178,6 +184,14 @@ def model_upgrades() -> list[dict]:
|
||||
rec = c.get("recommended")
|
||||
if not rec:
|
||||
continue
|
||||
# KEIN Downgrade: Empfehlung nur, wenn sie mind. so „groß"/fähig ist wie das
|
||||
# installierte Modell der Rolle (verhindert z.B. fast 35B-A3B → 4B).
|
||||
rec_model = next((x for x in c.get("models", []) if x.get("repo") == rec), None)
|
||||
rec_params = float((rec_model or {}).get("params_b") or 0.0)
|
||||
cur = inst_params.get(role, 0.0)
|
||||
if cur and rec_params and rec_params < cur * 0.95:
|
||||
continue
|
||||
|
||||
base = rec.split("/")[-1].lower()
|
||||
stem = base[:-5] if base.endswith("-gguf") else base
|
||||
if base in cmds or (stem and stem in cmds):
|
||||
|
||||
Reference in New Issue
Block a user