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:
@@ -1,22 +1,66 @@
|
||||
// news.js — News-Board (v4): kuratierte Neuigkeiten rund um lokale LLMs.
|
||||
// news.js — News-Board (v5): kuratierte News + „Für dich: Upgrades" (Modell-Tausch-Vorschläge).
|
||||
|
||||
import { api } from "../core/api.js";
|
||||
import { $, esc, ago } from "../core/ui.js";
|
||||
import { api, getHfToken } from "../core/api.js";
|
||||
import { $, esc, ago, toast } from "../core/ui.js";
|
||||
|
||||
let UPS = [];
|
||||
const fitCls = l => l === "perfect" ? "ok" : l === "marginal" ? "warn" : "bad";
|
||||
|
||||
function mount() {
|
||||
$(".view[data-view='news']").innerHTML = `
|
||||
<div class="pagehead">
|
||||
<div><h1>News</h1>
|
||||
<div class="sub">Neuigkeiten rund um lokale LLMs — automatisch aus kuratierten Quellen (HuggingFace, llama.cpp, Ollama, r/LocalLLaMA …).</div></div>
|
||||
<div class="sub">Neuigkeiten rund um lokale LLMs — aus kuratierten Quellen (HuggingFace, r/LocalLLaMA, Latent Space, Ahead of AI …).</div></div>
|
||||
<button class="ghost" id="news-refresh">Aktualisieren</button>
|
||||
</div>
|
||||
<div id="upgrades"></div>
|
||||
<div class="card"><div id="news-list">
|
||||
<div class="empty" style="text-align:center;padding:40px">Lade News…</div>
|
||||
</div></div>`;
|
||||
$("#news-refresh").addEventListener("click", load);
|
||||
$("#news-refresh").addEventListener("click", () => { load(); loadUpgrades(); });
|
||||
load();
|
||||
loadUpgrades();
|
||||
}
|
||||
|
||||
// ---- Upgrade-Vorschläge ----
|
||||
function upRow(u, i) {
|
||||
return `<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" style="font-family:var(--sans);font-weight:500">${esc(u.name)}</span>
|
||||
<span class="fit-badge ${fitCls(u.fit.level)}">${esc(u.fit.text)}</span></div>
|
||||
<div class="li-sub">Ersetzt dein „${esc(u.old)}". ${esc(u.why)}</div>
|
||||
</div>
|
||||
<button class="primary" data-up="${i}">Installieren</button>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
async function loadUpgrades() {
|
||||
const el = $("#upgrades"); if (!el) return;
|
||||
try {
|
||||
const d = await api("/api/cookbook/upgrades");
|
||||
UPS = d.upgrades || [];
|
||||
if (!UPS.length) { el.innerHTML = ""; return; }
|
||||
el.innerHTML = `<div class="card" style="margin-bottom:16px">
|
||||
<div class="card-h"><h3>Für dich: Upgrades</h3><span class="meta">${UPS.length}</span></div>
|
||||
<div class="card-sub">Neuere Modelle, die ein installiertes ersetzen können — Begründung inklusive.</div>
|
||||
${UPS.map(upRow).join("")}</div>`;
|
||||
el.querySelectorAll("[data-up]").forEach(b => b.addEventListener("click", () => installUpgrade(+b.getAttribute("data-up"), b)));
|
||||
} catch { el.innerHTML = ""; }
|
||||
}
|
||||
|
||||
async function installUpgrade(i, btn) {
|
||||
const u = UPS[i]; if (!u) return;
|
||||
btn.disabled = true; btn.textContent = "Starte…";
|
||||
try {
|
||||
await api("/api/cookbook/install-model", { method: "POST", body: JSON.stringify({
|
||||
repo: u.repo, role: u.role, params_b: u.params_b, quant: u.quant, hf_token: getHfToken() }) });
|
||||
toast(`„${u.name}" wird installiert — ersetzt „${u.old}". Siehe Aktivität.`);
|
||||
document.querySelector(".nav-item[data-view='activity']")?.click();
|
||||
} catch (e) { toast("Fehler: " + e.message, true); btn.disabled = false; btn.textContent = "Installieren"; }
|
||||
}
|
||||
|
||||
// ---- News ----
|
||||
function card(n) {
|
||||
const date = n.ts ? ago(n.ts) : "";
|
||||
const rel = n.relevant ? ' · <span class="text-accent">für deine Hardware</span>' : "";
|
||||
|
||||
Reference in New Issue
Block a user