v4 Schritt 2: Cookbook 2.0 — Use-Case-Setups (Stacks)
- recipes.py: 6 kuratierte Use-Case-Stacks (Coding, Vision, Chat, LongDoc, Agents, Fast). - cookbook.py: /recipes (Stack-Fit pro Modell + Gesamturteil) + /install-recipe (download + register aller Modelle mit optimalem, gedeckeltem Kontext). - cookbook.js: Use-Case-Karten als Haupteinstieg + Setup-Modal + 'Komplettes Setup installieren'; Roh-Suche in 'Profi-Modus' (collapsible). - models.py /register: exists()-Check entfernt (fixt frischen Download-Install). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,11 +8,19 @@ from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
import psutil
|
||||
|
||||
from ruamel.yaml.scalarstring import LiteralScalarString
|
||||
|
||||
from auth import auth
|
||||
from hw_math import evaluate_fit, max_ctx_for
|
||||
from config import MODELS_DIR, CMD_TEMPLATE, DEFAULT_TTL
|
||||
from llamaswap import read_config, write_config
|
||||
from jobengine import start_job, JOBS
|
||||
from recipes import RECIPES
|
||||
|
||||
router = APIRouter(prefix="/api/cookbook", dependencies=[Depends(auth)])
|
||||
|
||||
_FIT_ORDER = {"perfect": 0, "marginal": 1, "too_tight": 2}
|
||||
|
||||
class AnalyzeRequest(BaseModel):
|
||||
repo_id: str
|
||||
ctx: int = 8192
|
||||
@@ -22,6 +30,9 @@ class EvaluateRequest(BaseModel):
|
||||
quant: str
|
||||
ctx: int
|
||||
|
||||
class InstallRecipeReq(BaseModel):
|
||||
recipe_id: str
|
||||
|
||||
def extract_params_b(repo_id: str) -> float:
|
||||
"""Extrahiert die Parametergröße (in Milliarden) aus dem Repo-Namen."""
|
||||
# z.B. Qwen2.5-Coder-32B -> 32
|
||||
@@ -100,3 +111,47 @@ def evaluate_single(req: EvaluateRequest):
|
||||
fit["optimal_ctx"] = max_ctx_for(req.params_b, req.quant, ram_gb)
|
||||
return fit
|
||||
|
||||
|
||||
@router.get("/recipes")
|
||||
def recipes():
|
||||
"""Use-Case-Setups mit Hardware-Fit pro Modell + Stack-Gesamturteil. Da llama-swap nur EIN
|
||||
Modell gleichzeitig lädt, ist das Stack-Urteil der schlechteste (= größte) Einzel-Fit."""
|
||||
ram_gb = psutil.virtual_memory().total / (1024 ** 3)
|
||||
out = []
|
||||
for r in RECIPES:
|
||||
models, worst = [], "perfect"
|
||||
for m in r["models"]:
|
||||
fit = evaluate_fit(m["params_b"], m["quant"], 8192, ram_gb)
|
||||
models.append({**m, "fit": fit, "optimal_ctx": max_ctx_for(m["params_b"], m["quant"], ram_gb)})
|
||||
if _FIT_ORDER[fit["level"]] > _FIT_ORDER[worst]:
|
||||
worst = fit["level"]
|
||||
out.append({**r, "models": models, "fit_level": worst})
|
||||
return {"recipes": out, "sys_ram_gb": round(ram_gb, 1)}
|
||||
|
||||
|
||||
@router.post("/install-recipe")
|
||||
def install_recipe(req: InstallRecipeReq):
|
||||
"""Komplettes Setup installieren: jedes Modell als Download-Job starten UND sofort mit
|
||||
optimalem (gedeckeltem) Kontext in die config.yaml eintragen. llama-swap (-watch-config)
|
||||
übernimmt es, sobald die Datei da ist."""
|
||||
recipe = next((r for r in RECIPES if r["id"] == req.recipe_id), None)
|
||||
if not recipe:
|
||||
raise HTTPException(404, "Setup nicht gefunden.")
|
||||
ram_gb = psutil.virtual_memory().total / (1024 ** 3)
|
||||
cfg = read_config()
|
||||
job_ids = []
|
||||
for m in recipe["models"]:
|
||||
target = MODELS_DIR / m["repo"].split("/")[-1]
|
||||
target.mkdir(parents=True, exist_ok=True)
|
||||
args = ["hf", "download", m["repo"], m["file"], "--local-dir", str(target)]
|
||||
jid = start_job(args, f"download {m['name']}", env={"HF_XET_HIGH_PERFORMANCE": "1"})
|
||||
JOBS[jid]["result_path"] = str(target / m["file"])
|
||||
job_ids.append(jid)
|
||||
# Eintrag jetzt schon schreiben — optimaler Kontext, aber gedeckelt fuer schnellen Erststart.
|
||||
ctx = min(max_ctx_for(m["params_b"], m["quant"], ram_gb), 32768)
|
||||
path = str(target / m["file"])
|
||||
cmd = CMD_TEMPLATE.replace("{model}", path).replace("{ctx}", str(ctx))
|
||||
cfg["models"][m["role"]] = {"cmd": LiteralScalarString(cmd + "\n"), "ttl": DEFAULT_TTL}
|
||||
write_config(cfg)
|
||||
return {"job_ids": job_ids, "count": len(recipe["models"])}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user