v5 Phase 3: News-Quellen aufgeraeumt + Upgrade-Vorschlaege

- news.py: Git-Release-Feeds raus (b9745-Rauschen), Qualitaetsquellen rein
  (HuggingFace, r/LocalLLaMA, Simon Willison, Latent Space, Ahead of AI, The Batch).
- cookbook.py: /upgrades (matcht installierte alte Modelle gegen UPGRADES-Map) +
  /install-model (einzelnes Modell tauschen, GGUF dynamisch, optimaler ctx).
- news.js: 'Fuer dich: Upgrades'-Sektion oben (Modell X ersetzt dein Y, weil ... [Installieren]).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-21 14:18:37 +02:00
parent 970e04af30
commit b75335dafd
3 changed files with 111 additions and 8 deletions
+59 -1
View File
@@ -15,7 +15,7 @@ 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
from recipes import RECIPES, UPGRADES
router = APIRouter(prefix="/api/cookbook", dependencies=[Depends(auth)])
@@ -34,6 +34,13 @@ class InstallRecipeReq(BaseModel):
recipe_id: str
hf_token: str | None = None
class InstallModelReq(BaseModel):
repo: str
role: str
params_b: float
quant: str = "Q4_K_M"
hf_token: str | None = None
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
@@ -177,3 +184,54 @@ def _pick_gguf(repo: str, quant: str = "Q4_K_M") -> str | None:
nosplit = [g for g in ggufs if "-of-" not in g]
return (pref or nosplit or ggufs)[0]
@router.get("/upgrades")
def upgrades():
"""Schlägt für installierte 'alte' Modelle ein aktuelleres vor (UPGRADES-Map)."""
ram_gb = psutil.virtual_memory().total / (1024 ** 3)
installed = (read_config().get("models") or {})
out, seen = [], set()
for up in UPGRADES:
new_base = up["repo"].split("/")[-1].lower()
if any(new_base in str(s.get("cmd", "")).lower() for s in installed.values()):
continue # neueres Modell schon installiert
old = None
for alias, spec in installed.items():
hay = (alias + " " + str(spec.get("cmd", ""))).lower()
if any(k in hay for k in up["match"]):
old = alias
break
if not old or up["repo"] in seen:
continue
seen.add(up["repo"])
out.append({
"name": up["name"], "repo": up["repo"], "params_b": up["params_b"], "quant": up["quant"],
"why": up["why"], "old": old, "role": old,
"fit": evaluate_fit(up["params_b"], up["quant"], 8192, ram_gb),
"optimal_ctx": max_ctx_for(up["params_b"], up["quant"], ram_gb),
})
return {"upgrades": out}
@router.post("/install-model")
def install_model(req: InstallModelReq):
"""Ein einzelnes Modell installieren (Download + Einpflegen unter 'role', optimaler ctx)."""
file = _pick_gguf(req.repo, req.quant)
if not file:
raise HTTPException(404, "Keine GGUF-Datei im Repo gefunden.")
ram_gb = psutil.virtual_memory().total / (1024 ** 3)
env = {"HF_XET_HIGH_PERFORMANCE": "1"}
if req.hf_token:
env["HF_TOKEN"] = req.hf_token
target = MODELS_DIR / req.repo.split("/")[-1]
target.mkdir(parents=True, exist_ok=True)
jid = start_job(["hf", "download", req.repo, file, "--local-dir", str(target)],
f"download {req.repo.split('/')[-1]}", env=env)
JOBS[jid]["result_path"] = str(target / file)
cfg = read_config()
ctx = min(max_ctx_for(req.params_b, req.quant, ram_gb), 32768)
cmd = CMD_TEMPLATE.replace("{model}", str(target / file)).replace("{ctx}", str(ctx))
cfg["models"][req.role] = {"cmd": LiteralScalarString(cmd + "\n"), "ttl": DEFAULT_TTL}
write_config(cfg)
return {"job_id": jid}
+3 -2
View File
@@ -18,10 +18,11 @@ router = APIRouter(prefix="/api", dependencies=[Depends(auth)])
FEEDS = [
("HuggingFace", "https://huggingface.co/blog/feed.xml"),
("llama.cpp", "https://github.com/ggml-org/llama.cpp/releases.atom"),
("Ollama", "https://github.com/ollama/ollama/releases.atom"),
("r/LocalLLaMA", "https://www.reddit.com/r/LocalLLaMA/.rss"),
("Simon Willison", "https://simonwillison.net/atom/everything/"),
("Latent Space", "https://www.latent.space/feed"),
("Ahead of AI", "https://magazine.sebastianraschka.com/feed"),
("The Batch", "https://www.deeplearning.ai/the-batch/rss.xml"),
]
_UA = {"User-Agent": "Mozilla/5.0 (MissionControl NewsBot)"}
_TTL = 1800 # 30 min