kpn load: Ollama-mallin vaihto lennossa (0.5b → 32b)

- Hub: uusi POST /api/v1/model endpoint, broadcastaa change_model
- Native node: kuuntelee change_model, kutsuu Ollaman pull + vaihtaa mallin
- Frontend: kpn load näyttää 5 mallia, numero vaihtaa Ollaman mallin
- Selain-WASM pysyy 0.5B:nä (kpn load 1)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 07:05:57 +03:00
parent 54a5af96c7
commit 34ef19472a
4 changed files with 95 additions and 19 deletions

View File

@@ -2371,18 +2371,58 @@ Files: ${Object.keys(generatedFiles).join(', ')}`;
}
if (sub === 'load') {
const btn = document.getElementById('agent-compute-btn');
if (btn?.dataset.state === 'ready') {
termLog(' ✓ Qwen2.5-Coder:0.5B on jo ladattu ja valmis (selain)', '#3fb950');
termLog(' <span style="color:#8b949e">Natiivisolmu (Docker) on nopeampi — ks. kpn models</span>');
const arg = parts[2];
const ollamaModels = [
{ id: '1', name: 'qwen2.5-coder:0.5b', size: '~400 MB', type: 'selain + Ollama' },
{ id: '2', name: 'qwen2.5-coder:1.5b', size: '~1 GB', type: 'Ollama GPU' },
{ id: '3', name: 'qwen2.5-coder:7b', size: '~4.7 GB', type: 'Ollama GPU', default: true },
{ id: '4', name: 'qwen2.5-coder:14b', size: '~9 GB', type: 'Ollama GPU' },
{ id: '5', name: 'qwen2.5-coder:32b', size: '~20 GB', type: 'Ollama GPU' },
];
if (!arg) {
termLog(' Mallit:', '#c9d1d9');
for (const m of ollamaModels) {
const active = m.default ? ' <span style="color:#3fb950">← aktiivinen</span>' : '';
termLog(` <span style="color:#58a6ff">${m.id}</span> ${m.name} <span style="color:#8b949e">${m.size} | ${m.type}</span>${active}`);
}
termLog(' Käyttö: kpn load &lt;numero&gt;', '#8b949e');
return;
}
coderSize = '05b';
localStorage.setItem('kpn-coder-size', coderSize);
termLog(' Ladataan Qwen2.5-Coder:0.5B (~990 MB) selaimeen...', '#d29922');
termLog(' <span style="color:#8b949e">Vinkki: natiivisolmu (Docker) on ~20× nopeampi</span>');
if (btn) btn.click();
else ensureCoderNode();
const selected = ollamaModels.find(m => m.id === arg || m.name === arg);
if (!selected) {
termLog(` Tuntematon malli "${esc(arg)}". Kokeile: kpn load`, '#f85149');
return;
}
// Selain-WASM (vain 0.5b)
if (selected.id === '1') {
const btn = document.getElementById('agent-compute-btn');
if (btn?.dataset.state === 'ready') {
termLog(' ✓ Qwen2.5-Coder:0.5B on jo ladattu (selain)', '#3fb950');
return;
}
coderSize = '05b';
termLog(' Ladataan Qwen2.5-Coder:0.5B selaimeen...', '#d29922');
if (btn) btn.click();
else ensureCoderNode();
return;
}
// Ollama: vaihdetaan malli hubin kautta
termLog(` Vaihdetaan Ollama-malli: ${selected.name} (${selected.size})...`, '#d29922');
fetch('/api/v1/model', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model: selected.name }),
}).then(r => r.json()).then(data => {
if (data.status === 'ok') {
termLog(` <span style="color:#3fb950">✓</span> Malli vaihdettu: ${selected.name}`, '#3fb950');
termLog(' <span style="color:#8b949e">Ollama lataa mallin ensimmäisellä pyynnöllä</span>');
// Päivitetään aktiivinen default
ollamaModels.forEach(m => m.default = false);
selected.default = true;
} else {
termLog(` ✗ Mallin vaihto epäonnistui`, '#f85149');
}
}).catch(e => termLog(`${e.message}`, '#f85149'));
return;
}