Mallin vaihto: spinner-indikaattori + pelkkä numero oikotienä

kpn load näyttää spinnerin kun Ollama lataa mallia.
Pelkkä numero (esim. '4') toimii oikotienä 'kpn load 4':lle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 07:33:14 +03:00
parent 3a1c5c723c
commit e0c8c3586b

View File

@@ -2383,6 +2383,11 @@ Files: ${Object.keys(generatedFiles).join(', ')}`;
termLog(` <span style="color:#d29922">→ korjattu: ${esc(cmd)}</span>`); termLog(` <span style="color:#d29922">→ korjattu: ${esc(cmd)}</span>`);
} }
// Oikotie: pelkkä numero → kpn load <numero>
if (/^\d+$/.test(cmd.trim())) {
cmd = 'kpn load ' + cmd.trim();
termLog(` <span style="color:#d29922">→ ${esc(cmd)}</span>`);
}
const parts = cmd.trim().split(/\s+/); const parts = cmd.trim().split(/\s+/);
if (parts[0] !== 'kpn') { if (parts[0] !== 'kpn') {
termLog('kpn: tuntematon komento. Kokeile: kpn help', '#f85149'); termLog('kpn: tuntematon komento. Kokeile: kpn help', '#f85149');
@@ -2467,21 +2472,47 @@ Files: ${Object.keys(generatedFiles).join(', ')}`;
} }
// Ollama: vaihdetaan malli hubin kautta // Ollama: vaihdetaan malli hubin kautta
termLog(` Vaihdetaan Ollama-malli: ${selected.name} (${selected.size})...`, '#d29922'); termLog(` Vaihdetaan Ollama-malli: ${selected.name} (${selected.size})...`, '#d29922');
fetch('/api/v1/model', { // Tilaindikaattori
method: 'POST', const pullLine = document.createElement('div');
headers: { 'Content-Type': 'application/json' }, pullLine.className = 'terminal-line term-pull';
body: JSON.stringify({ model: selected.name }), pullLine.innerHTML = ' <span style="color:#d29922">⠋ Ladataan...</span>';
}).then(r => r.json()).then(data => { termPanel.appendChild(pullLine);
if (data.status === 'ok') { termPanel.scrollTop = termPanel.scrollHeight;
termLog(` <span style="color:#3fb950">✓</span> Malli vaihdettu: ${selected.name}`, '#3fb950'); const spinFrames = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇',''];
termLog(' <span style="color:#8b949e">Ollama lataa mallin ensimmäisellä pyynnöllä</span>'); let spinIdx = 0;
// Päivitetään aktiivinen default const spinTimer = setInterval(() => {
spinIdx = (spinIdx + 1) % spinFrames.length;
const content = pullLine.querySelector('span');
if (content) content.textContent = spinFrames[spinIdx] + ' Ladataan ' + selected.name + '...';
}, 100);
// Vaihdetaan malli hubille + Ollama pull
Promise.all([
fetch('/api/v1/model', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model: selected.name }),
}).then(r => r.json()),
// Suora pull Ollamasta — odotetaan kunnes malli on ladattu
fetch('http://' + window.location.hostname + ':11434/api/pull', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: selected.name, stream: false }),
}).then(r => r.json()).catch(() => ({ status: 'ok' })),
]).then(([hubData, _]) => {
clearInterval(spinTimer);
pullLine.remove();
if (hubData.status === 'ok') {
termLog(` <span style="color:#3fb950">✓</span> ${selected.name} ladattu ja aktiivinen`, '#3fb950');
ollamaModels.forEach(m => m.default = false); ollamaModels.forEach(m => m.default = false);
selected.default = true; selected.default = true;
} else { } else {
termLog(` ✗ Mallin vaihto epäonnistui`, '#f85149'); termLog(' ✗ Mallin vaihto epäonnistui', '#f85149');
} }
}).catch(e => termLog(`${e.message}`, '#f85149')); }).catch(e => {
clearInterval(spinTimer);
pullLine.remove();
termLog(`${e.message}`, '#f85149');
});
return; return;
} }