// models.js — "Modelle"-Ansicht: Download + Einpflegen, Schnelltest-Chat, Modell-Tabelle. import { api } from "../core/api.js"; import { $, badge, esc, toast } from "../core/ui.js"; import { track } from "./jobs.js"; function refreshSoon() { document.dispatchEvent(new Event("mc:refresh")); } function mount() { $("#m-download").innerHTML = `

Modell holen

`; $("#m-chat").innerHTML = `

Schnelltest

`; $("#m-table").innerHTML = `

Modelle & Ports

ModellStatusPortAktion
`; $("#dl-btn").addEventListener("click", pull); $("#rg-btn").addEventListener("click", register); $("#chat-btn").addEventListener("click", sendChat); } function onStatus(s) { const models = s?.models || []; const tb = $("#models"); if (!tb) return; tb.innerHTML = ""; $("#models-empty").style.display = models.length ? "none" : "block"; $("#m-count").textContent = models.length ? models.length + " konfiguriert" : ""; const sel = $("#chat-model"); const cur = sel.value; sel.innerHTML = ""; for (const m of models) { const tr = document.createElement("tr"); tr.innerHTML = `${esc(m.name)}${badge(m.state)} ${m.port ?? "auto"} `; tb.appendChild(tr); sel.insertAdjacentHTML("beforeend", ``); } if (cur) sel.value = cur; tb.querySelectorAll("[data-unload]").forEach(b => b.addEventListener("click", () => unloadOne(b.getAttribute("data-unload"))) ); } async function pull() { const repo = $("#dl-repo").value.trim(), file = $("#dl-file").value.trim(); if (!repo || !file) return toast("Repo und Datei angeben.", true); try { const r = await api("/api/download", { method: "POST", body: JSON.stringify({ repo, file }) }); toast("Download gestartet."); const stem = file.split("/").pop().replace(/\.gguf$/i, ""); $("#rg-alias").value = stem; $("#rg-path").value = r.expected_path; $("#register-box").style.display = "block"; track(r.job_id); } catch (e) { toast(e.message, true); } } async function register() { const alias = $("#rg-alias").value.trim(); const model_path = $("#rg-path").value; const ctx = parseInt($("#rg-ctx").value) || 8192; if (!alias) return toast("Alias angeben.", true); try { await api("/api/register", { method: "POST", body: JSON.stringify({ alias, model_path, ctx }) }); toast("Eingepflegt — llama-swap lädt neu."); refreshSoon(); } catch (e) { toast(e.message, true); } } async function unloadOne(m) { try { await api("/api/unload?model=" + encodeURIComponent(m), { method: "POST" }); toast("Entladen: " + m); setTimeout(refreshSoon, 600); } catch (e) { toast(e.message, true); } } async function sendChat() { const model = $("#chat-model").value, message = $("#chat-msg").value.trim(); if (!model) return toast("Kein Modell vorhanden.", true); if (!message) return; const btn = $("#chat-btn"); btn.disabled = true; btn.textContent = "…"; const box = $("#chat-reply"); box.style.display = "block"; box.textContent = "(wecke Modell, kann beim Swap kurz dauern…)"; try { const r = await api("/api/chat", { method: "POST", body: JSON.stringify({ model, message }) }); box.textContent = r.reply; } catch (e) { box.textContent = "Fehler: " + e.message; } btn.disabled = false; btn.textContent = "Senden"; refreshSoon(); } export default { id: "models", mount, onStatus };