feat(cookbook): Elite-Lineup + MoE-Badge/Faehigkeit + Best-of-4
- Elite-Lineup-Rezept (5 Rollen: coder/manager/reviewer/vision/scout), MoE-orientiert -> wird automatisch 'Beste Wahl' (meiste Modelle, passt). - MoE-Erkennung clientseitig aus Repo-Name (8xNB / -A3B / mixtral/moe); Chip 'MoE - ~XB aktiv' in Discover-/Such-Karten + Rezept-Detail. - Faehigkeits-Chip (Bilder/Coden/Logik/Agenten/Allrounder) je Modell. - Discover hebt je Kategorie das beste lauffaehige Modell hervor (recommended pro Kategorie: bester Fit, dann Downloads). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,38 @@ import { $, esc, icon, toast, infoDot, confirmModal } from "../core/ui.js";
|
||||
|
||||
const CTX_HELP = "Kontext = das Kurzzeitgedächtnis des Modells. Größer = merkt sich mehr, braucht aber mehr Speicher und wird etwas langsamer.";
|
||||
const GGUF_HELP = "GGUF ist das lokal lauffähige Dateiformat. Unsere Engine lädt nur GGUF — Repos ohne GGUF-Datei kann sie nicht nutzen.";
|
||||
const MOE_HELP = "MoE (Mixture of Experts): viele Parameter fürs Wissen, aber pro Wort ist nur ein kleiner Teil aktiv → fast große-Modell-Qualität bei hohem Tempo. Ideal für deine APU.";
|
||||
|
||||
// Was kann das Modell? (Fähigkeit aus dem Namen / der Backend-Rolle ableiten.)
|
||||
const ROLE_LABEL = { vision: "Bilder", coder: "Coden", reasoning: "Logik", agent: "Agenten & Tools",
|
||||
scout: "Allrounder", reviewer: "Review", manager: "Manager" };
|
||||
const CAP_KW = [
|
||||
{ label: "Bilder", kw: ["-vl-", "-vl", "vision", "llava", "multimodal", "-mm-", "pixtral"] },
|
||||
{ label: "Coden", kw: ["coder", "-code-", "code-", "codestral", "starcoder"] },
|
||||
{ label: "Logik", kw: ["-r1", "deepseek-r1", "reasoning", "qwq", "magistral", "-think", "thinking", "-o1"] },
|
||||
{ label: "Agenten & Tools", kw: ["hermes", "-tool", "command-r", "watt", "-fc-", "function"] },
|
||||
];
|
||||
function capLabel(name) {
|
||||
const l = (name || "").toLowerCase();
|
||||
for (const c of CAP_KW) if (c.kw.some(k => l.includes(k))) return c.label;
|
||||
return "Allrounder";
|
||||
}
|
||||
// MoE-Erkennung über strukturelle Marker im Namen (zuverlässig, keine Falschaussagen):
|
||||
// 8x7B-Stil, „…-A3B" (aktive Parameter), oder explizit „mixtral"/„moe".
|
||||
function isMoe(s = "") {
|
||||
const l = s.toLowerCase();
|
||||
return /\d+x\d+(\.\d+)?b/.test(l) || /(?<![a-z])a\d+(\.\d+)?b\b/.test(l) || l.includes("mixtral") || /\bmoe\b/.test(l);
|
||||
}
|
||||
function moeActive(s = "") {
|
||||
const m = s.toLowerCase().match(/(?<![a-z])a(\d+(?:\.\d+)?)b\b/);
|
||||
return m ? m[1] : null;
|
||||
}
|
||||
function moeChip(name) {
|
||||
if (!isMoe(name)) return "";
|
||||
const a = moeActive(name);
|
||||
return `<span class="chip" title="${esc(MOE_HELP)}">MoE${a ? ` · ~${a}B aktiv` : ""}</span>`;
|
||||
}
|
||||
function capChip(label) { return label ? `<span class="chip">${esc(label)}</span>` : ""; }
|
||||
|
||||
const FILTERS = [
|
||||
{ id: "", label: "Alle" }, { id: "coder", label: "Coder" }, { id: "scout", label: "Scout" },
|
||||
@@ -182,23 +214,28 @@ function renderDiscover(d) {
|
||||
<div style="margin-bottom:8px">
|
||||
<div class="flex items-center gap-2" style="margin:6px 0 8px"><span class="text-accent">${icon(c.icon)}</span>
|
||||
<h4 style="margin:0;font-size:13.5px;font-weight:600">${esc(c.title)}</h4></div>
|
||||
<div class="grid grid-3">${c.models.map(discCard).join("")}</div>
|
||||
<div class="grid grid-3">${c.models.map(m => discCard(m, c.recommended)).join("")}</div>
|
||||
</div>`).join("");
|
||||
}
|
||||
|
||||
function discCard(m) {
|
||||
function discCard(m, recommended) {
|
||||
const reqs = (m.requirements || []).map(r =>
|
||||
`<div class="li-sub" style="color:var(--warn);margin-top:3px">⚠ ${esc(r)}</div>`).join("");
|
||||
const best = recommended && m.repo === recommended;
|
||||
const tag = best ? `<div class="cb-best-tag">★ Beste Wahl für dein System</div>` : "";
|
||||
const chips = `<div class="flex gap-2" style="flex-wrap:wrap;margin-top:7px">${capChip(ROLE_LABEL[m.role] || capLabel(m.repo))}${moeChip(m.repo)}</div>`;
|
||||
const action = m.installed
|
||||
? `<span class="fit-badge ok" title="bereits eingerichtet als ${esc(m.installed)}">✓ installiert</span>`
|
||||
: `<button class="primary" data-inst="${esc(m.repo)}" data-role="${esc(m.role)}" data-pb="${m.params_b}"
|
||||
style="padding:6px 12px;font-size:12.5px">Installieren</button>`;
|
||||
return `<div class="card" style="display:flex;flex-direction:column">
|
||||
return `<div class="card${best ? " res-best" : ""}" style="display:flex;flex-direction:column;position:relative">
|
||||
${tag}
|
||||
<div class="flex justify-between" style="align-items:flex-start;gap:8px">
|
||||
<div style="min-width:0"><h3 style="margin:0;font-size:14px;font-weight:500;word-break:break-word">${esc(m.name)}</h3>
|
||||
<div class="text-xs text-mut" style="margin-top:3px">${esc(m.author)} · ${m.params_b}B</div></div>
|
||||
<span class="fit-badge ${fitCls(m.fit.level)}">${esc(m.fit.text)}</span>
|
||||
</div>
|
||||
${chips}
|
||||
<div class="mono-sm text-mut" style="margin-top:8px;font-size:11.5px">${metricLine(m.fit)} · ⬇ ${(m.downloads || 0).toLocaleString()}</div>
|
||||
${reqs}
|
||||
<div style="flex:1;min-height:8px"></div>
|
||||
@@ -308,7 +345,7 @@ function openRecipe(id) {
|
||||
<div class="li" style="align-items:flex-start">
|
||||
<div class="li-main">
|
||||
<div class="flex items-center gap-2" style="flex-wrap:wrap">
|
||||
<span class="li-id">${esc(m.name)}</span><span class="tag text">${esc(m.role)}</span></div>
|
||||
<span class="li-id">${esc(m.name)}</span><span class="tag text">${esc(m.role)}</span>${moeChip(m.repo)}</div>
|
||||
<div class="li-sub">${esc(m.why)}</div>
|
||||
<div class="li-sub mono-sm">~${m.fit.req_gb.toFixed(1)} GB · ~${Math.round(m.fit.tps)} Tok/s · optimal ~${Math.round(m.optimal_ctx / 1024)}k Kontext</div>
|
||||
</div>
|
||||
@@ -398,6 +435,7 @@ function renderResults(results) {
|
||||
<div class="text-xs text-mut" style="margin-top:3px">${esc(m.author || "")}</div></div>
|
||||
<span class="fit-badge warn" id="cb-b-${i}">prüfe…</span>
|
||||
</div>
|
||||
<div class="flex gap-2" style="flex-wrap:wrap;margin-top:7px">${capChip(capLabel(m.id))}${moeChip(m.id)}</div>
|
||||
<div style="flex:1;margin-top:12px"></div>
|
||||
<div class="flex justify-between items-center text-xs text-mut" style="border-top:1px solid var(--line);padding-top:11px">
|
||||
<span class="mono-sm" id="cb-m-${i}">Hardware-Fit…</span>
|
||||
|
||||
Reference in New Issue
Block a user