v4 Schritt 1: optimale Kontextfenster automatisch ermitteln

- hw_math: max_ctx_for() (Umkehrung der ctx-Heuristik) + extract_params_b + recommend_ctx.
- cookbook.py: optimal_ctx pro Datei in analyze + evaluate.
- models.py status: params_b + optimal_ctx pro Modell (psutil-RAM).
- models.js Konfig-Modal: Empfehlung + 'Optimal uebernehmen'.
- cookbook.js Modal: 'Empfohlener Kontext ... uebernehmen'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-21 13:13:30 +02:00
parent f3da24a712
commit 654720ed05
5 changed files with 75 additions and 3 deletions
+7 -1
View File
@@ -74,6 +74,7 @@ function mount() {
<div><label>Alias (Rolle)</label><input id="cb-m-alias" placeholder="z.B. coder"></div>
<div><label>Kontext-Größe</label><input id="cb-m-ctx" type="number" value="8192"></div>
</div>
<div class="hint" id="cb-m-ctx-rec" style="margin:-6px 0 14px"></div>
<div id="cb-m-fit" class="tile" style="display:flex;justify-content:space-between;align-items:center;margin:8px 0 18px">
<div><div style="font-size:13px">Ressourcen-Check</div>
@@ -94,6 +95,7 @@ function mount() {
$("#cb-m-download").addEventListener("click", doDownload);
$("#cb-m-files").addEventListener("change", updateLiveFit);
$("#cb-m-ctx").addEventListener("change", reanalyzeCtx);
window.cbSetCtx = v => { $("#cb-m-ctx").value = v; reanalyzeCtx(); };
renderHwChip();
renderCurated();
@@ -207,6 +209,10 @@ function showFit() {
$("#cb-m-fit").style.display = "flex";
$("#cb-m-fit-text").innerHTML = `Bedarf: <b>~${f.fit.req_gb.toFixed(1)} GB</b> · ${currentAnalysis.params_b}B · ${esc(f.quant)} · ~${Math.round(f.fit.tps)} Tok/s`;
$("#cb-m-fit-badge").innerHTML = `<span class="fit-badge ${fitCls(f.fit.level)}">${esc(f.fit.text)}</span>`;
const opt = f.optimal_ctx, recEl = $("#cb-m-ctx-rec");
if (recEl) recEl.innerHTML = opt
? `Empfohlener Kontext für deine Hardware: <b>~${Math.round(opt / 1024)}k</b> — <a href="#" onclick="event.preventDefault();window.cbSetCtx(${opt})">übernehmen</a>`
: "";
const btn = $("#cb-m-download");
if (f.fit.level === "too_tight") { btn.className = "primary warn"; btn.textContent = "Trotzdem holen (zu groß)"; }
else { btn.className = "primary"; btn.textContent = "Herunterladen & Einpflegen"; }
@@ -255,7 +261,7 @@ async function openCurated(i) {
$("#cb-m-alias").value = m.alias; $("#cb-m-ctx").value = m.ctx; $("#cb-m-download").disabled = false;
try {
const fit = await api("/api/cookbook/evaluate", { method: "POST", body: JSON.stringify({ params_b: m.params_b, quant: m.quant, ctx: m.ctx }) });
currentAnalysis = { repo: m.repo, params_b: m.params_b, files: [{ filename: m.file, quant: m.quant, fit }] };
currentAnalysis = { repo: m.repo, params_b: m.params_b, files: [{ filename: m.file, quant: m.quant, fit, optimal_ctx: fit.optimal_ctx }] };
showFit();
} catch {}
}