From e0c8c3586b069e7de1dafabb3120f5aef7c5f323 Mon Sep 17 00:00:00 2001 From: jaakko Date: Tue, 7 Apr 2026 07:33:14 +0300 Subject: [PATCH] =?UTF-8?q?Mallin=20vaihto:=20spinner-indikaattori=20+=20p?= =?UTF-8?q?elkk=C3=A4=20numero=20oikotien=C3=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- network-poc/static/index.html | 53 +++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/network-poc/static/index.html b/network-poc/static/index.html index 0ba6aee..6e476d7 100644 --- a/network-poc/static/index.html +++ b/network-poc/static/index.html @@ -2383,6 +2383,11 @@ Files: ${Object.keys(generatedFiles).join(', ')}`; termLog(` → korjattu: ${esc(cmd)}`); } + // Oikotie: pelkkä numero → kpn load + if (/^\d+$/.test(cmd.trim())) { + cmd = 'kpn load ' + cmd.trim(); + termLog(` → ${esc(cmd)}`); + } const parts = cmd.trim().split(/\s+/); if (parts[0] !== 'kpn') { termLog('kpn: tuntematon komento. Kokeile: kpn help', '#f85149'); @@ -2467,21 +2472,47 @@ Files: ${Object.keys(generatedFiles).join(', ')}`; } // 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(` Malli vaihdettu: ${selected.name}`, '#3fb950'); - termLog(' Ollama lataa mallin ensimmäisellä pyynnöllä'); - // Päivitetään aktiivinen default + // Tilaindikaattori + const pullLine = document.createElement('div'); + pullLine.className = 'terminal-line term-pull'; + pullLine.innerHTML = ' ⠋ Ladataan...'; + termPanel.appendChild(pullLine); + termPanel.scrollTop = termPanel.scrollHeight; + const spinFrames = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏']; + let spinIdx = 0; + 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(` ${selected.name} ladattu ja aktiivinen`, '#3fb950'); ollamaModels.forEach(m => m.default = false); selected.default = true; } 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; }