From 133ff38fa498824edbfb202b6bf7e9ab9ed72f4b Mon Sep 17 00:00:00 2001 From: Jaakko Vanhala Date: Sat, 4 Apr 2026 21:22:46 +0300 Subject: [PATCH] tilakoneen fiksailuja --- network-poc/static/index.html | 203 ++++++++++++++++++++-------------- 1 file changed, 120 insertions(+), 83 deletions(-) diff --git a/network-poc/static/index.html b/network-poc/static/index.html index 9417715..e37d710 100644 --- a/network-poc/static/index.html +++ b/network-poc/static/index.html @@ -1417,6 +1417,9 @@ document.querySelector(`.main-tab[onclick*="${tab}"]`).classList.add('active'); window.location.hash = tab; + // Siivotaan streaming-kortit näkymistä tab-vaihdon yhteydessä + document.querySelectorAll('.streaming-card').forEach(el => el.remove()); + // Päivitetään admin-sessio vastaamaan nykyistä välilehteä if (window._uiSocket && window._uiSocket.readyState === 1) { const viewTask = tab === 'codelab' ? 'codelab-viewer' : 'viewer'; @@ -2034,64 +2037,95 @@ if (chatBox.children.length > 5) chatBox.removeChild(chatBox.firstChild); chatBox.scrollTop = chatBox.scrollHeight; } else if (data.type === "llm_done") { - const term = document.getElementById('agent-terminal'); - if (term) { - const model = data.model || 'llm'; + // Reititetäänkö agents-näkymään vai codelab-näkymään? + const isAgentsTask = data.task_id && activeStreams[data.task_id]; + const isCoder = (data.model || '').includes('Coder'); + + if (isAgentsTask) { + // Agents-pipeline: päivitetään terminaali + const term = document.getElementById('agent-terminal'); + if (term) { + const model = data.model || 'llm'; + const tokGen = data.tokens_generated || 0; + const durMs = typeof data.duration_ms === 'number' ? data.duration_ms.toFixed(0) : data.duration_ms || '?'; + const tokS = data.tokens_per_sec || '?'; + const div = document.createElement('div'); + div.className = 'terminal-line'; + div.style.color = '#a5d6ff'; + div.innerHTML = ` ✓ ${model} ${tokGen} tok | ${durMs}ms | ${tokS} tok/s`; + term.appendChild(div); + while (term.children.length > 50) term.removeChild(term.firstChild); + term.scrollTop = term.scrollHeight; + + document.querySelectorAll('.avatar-card').forEach(c => c.classList.remove('active')); + document.getElementById('avatar-kpn').classList.add('active'); + } + } else if (isCoder) { + // Codelab: erillinen addCodeResult-handler käsittelee (rivi 2364) + // Poistetaan vain streaming-kortti codelabista + if (codeResults) codeResults.querySelector('.streaming-card')?.remove(); + } else { + // Muu malli (network-näkymä): näytetään chatBoxissa + chatBox.querySelector('.streaming-card')?.remove(); + chatBox.classList.remove('hidden'); + const nodeId = data.node_id || "?"; + const model = data.model || "LLM"; const tokGen = data.tokens_generated || 0; - const durMs = typeof data.duration_ms === 'number' ? data.duration_ms.toFixed(0) : data.duration_ms || '?'; - const tokS = data.tokens_per_sec || '?'; - const div = document.createElement('div'); - div.className = 'terminal-line'; - div.style.color = '#a5d6ff'; - div.innerHTML = ` ✓ ${model} ${tokGen} tok | ${durMs}ms | ${tokS} tok/s`; - term.appendChild(div); - while (term.children.length > 50) term.removeChild(term.firstChild); - term.scrollTop = term.scrollHeight; - - document.querySelectorAll('.avatar-card').forEach(c => c.classList.remove('active')); - document.getElementById('avatar-kpn').classList.add('active'); + const durMs = data.duration_ms || 0; + const tokS = data.tokens_per_sec || 0; + const loadMs = data.load_time_ms || 0; + + const msgDiv = document.createElement('div'); + msgDiv.className = 'chat-msg'; + msgDiv.style.borderLeftColor = '#a371f7'; + msgDiv.innerHTML = ` +
+ Solmu #${nodeId} — ${model} + ${typeof durMs === 'number' ? durMs.toFixed(0) : durMs}ms | ${tokS} tok/s +
+
+ Prompt: "${data.prompt || ''}" +
+
+ ${(data.response || 'tyhjä vastaus').replace(//g, '>')} +
+
+ ${tokGen} tokenia generoitu | malli ladattu: ${typeof loadMs === 'number' ? loadMs.toFixed(0) : loadMs}ms +
`; + chatBox.appendChild(msgDiv); + if (chatBox.children.length > 5) chatBox.removeChild(chatBox.firstChild); + chatBox.scrollTop = chatBox.scrollHeight; } - // Poistetaan streaming-kortti - chatBox.querySelector('.streaming-card')?.remove(); - chatBox.classList.remove('hidden'); - const nodeId = data.node_id || "?"; - const model = data.model || "LLM"; - const tokGen = data.tokens_generated || 0; - const durMs = data.duration_ms || 0; - const tokS = data.tokens_per_sec || 0; - const loadMs = data.load_time_ms || 0; - - const msgDiv = document.createElement('div'); - msgDiv.className = 'chat-msg'; - msgDiv.style.borderLeftColor = '#a371f7'; - msgDiv.innerHTML = ` -
- Solmu #${nodeId} — ${model} - ${typeof durMs === 'number' ? durMs.toFixed(0) : durMs}ms | ${tokS} tok/s -
-
- Prompt: "${data.prompt || ''}" -
-
- ${(data.response || 'tyhjä vastaus').replace(//g, '>')} -
-
- ${tokGen} tokenia generoitu | malli ladattu: ${typeof loadMs === 'number' ? loadMs.toFixed(0) : loadMs}ms -
`; - chatBox.appendChild(msgDiv); - if (chatBox.children.length > 5) chatBox.removeChild(chatBox.firstChild); - chatBox.scrollTop = chatBox.scrollHeight; - metrics.tasks++; - metrics.totalTokens += tokGen; - metrics.totalTimeMs += durMs; + metrics.totalTokens += (data.tokens_generated || 0); + metrics.totalTimeMs += (data.duration_ms || 0); flashComputing(); updateMetrics(); - console.log(`[${model}] ${tokGen} tokenia | ${typeof durMs === 'number' ? durMs.toFixed(0) : durMs}ms | ${tokS} tok/s | "${(data.response || '').substring(0, 60)}..."`); + console.log(`[${data.model || 'LLM'}] ${data.tokens_generated || 0} tokenia | ${typeof data.duration_ms === 'number' ? data.duration_ms.toFixed(0) : data.duration_ms || '?'}ms | ${data.tokens_per_sec || '?'} tok/s | "${(data.response || '').substring(0, 60)}..."`); + } else if (data.type === "llm_error") { + // Virheenkäsittely: siivotaan streaming-tila + const errMsg = data.error || 'Tuntematon virhe'; + if (data.task_id && activeStreams[data.task_id]) { + // Agents-pipeline: näytetään virhe terminaalissa + activeStreams[data.task_id].remove(); + delete activeStreams[data.task_id]; + } + chatBox.querySelector('.streaming-card')?.remove(); + if (codeResults) codeResults.querySelector('.streaming-card')?.remove(); + const term = document.getElementById('agent-terminal'); + if (term) { + const div = document.createElement('div'); + div.className = 'terminal-line'; + div.style.color = '#f85149'; + div.innerHTML = ` ✗ LLM-virhe: ${errMsg}`; + term.appendChild(div); + term.scrollTop = term.scrollHeight; + } + console.warn('[LLM Error]', errMsg); } else if (data.type === "llm_chunk") { - // Terminaalin streaming: päivitetään aktiivinen rivi + // Agents-terminaalin streaming: päivitetään aktiivinen rivi task_id:n perusteella if (data.task_id && activeStreams[data.task_id]) { const streamDiv = activeStreams[data.task_id]; const contentEl = streamDiv.querySelector('.stream-content'); @@ -2099,41 +2133,42 @@ contentEl.textContent += data.token || ''; termPanel.scrollTop = termPanel.scrollHeight; } - } + // Agents-pipeline omistaa tämän chunkin, ei näytetä muualla + } else { + // Ei agents-task → näytetään streaming-kortti oikeassa näkymässä + const model = data.model || ''; + const isCoder = model.includes('Coder'); + const targetBox = isCoder ? codeResults : chatBox; - // Streaming: näytetään generointi reaaliaikaisesti - const model = data.model || ''; - const isCoder = model.includes('Coder'); - const targetBox = isCoder ? codeResults : chatBox; - - if (targetBox) { - let streamEl = targetBox.querySelector('.streaming-card'); - if (!streamEl) { - streamEl = document.createElement('div'); - streamEl.className = isCoder ? 'code-task-card streaming-card' : 'chat-msg streaming-card'; - streamEl.style.borderLeftColor = '#a371f7'; - streamEl.innerHTML = ` -
- ${model} - 0 tok -
-
Prompt: "${data.prompt || ''}"
-
-
- Generating... -
`; - if (isCoder) { - targetBox.insertBefore(streamEl, targetBox.firstChild); - } else { - targetBox.appendChild(streamEl); + if (targetBox) { + let streamEl = targetBox.querySelector('.streaming-card'); + if (!streamEl) { + streamEl = document.createElement('div'); + streamEl.className = isCoder ? 'code-task-card streaming-card' : 'chat-msg streaming-card'; + streamEl.style.borderLeftColor = '#a371f7'; + streamEl.innerHTML = ` +
+ ${model} + 0 tok +
+
Prompt: "${data.prompt || ''}"
+
+
+ Generating... +
`; + if (isCoder) { + targetBox.insertBefore(streamEl, targetBox.firstChild); + } else { + targetBox.appendChild(streamEl); + } } + const textEl = streamEl.querySelector('.stream-text'); + const counterEl = streamEl.querySelector('.stream-counter'); + if (textEl) textEl.textContent += data.token || ''; + const tokCount = (textEl.textContent || '').split('').length; + if (counterEl) counterEl.textContent = tokCount + ' tok'; + targetBox.scrollTop = targetBox.scrollHeight; } - const textEl = streamEl.querySelector('.stream-text'); - const counterEl = streamEl.querySelector('.stream-counter'); - if (textEl) textEl.textContent += data.token || ''; - const tokCount = (textEl.textContent || '').split('').length; - if (counterEl) counterEl.textContent = tokCount + ' tok'; - targetBox.scrollTop = targetBox.scrollHeight; } } else if (data.type === "llm_prompt") { if (data.task_id) { @@ -2360,11 +2395,13 @@ if (codeResults.children.length > 10) codeResults.removeChild(codeResults.lastChild); } - // Kuuntele coder-tuloksia UI WebSocketista + // Kuuntele coder-tuloksia UI WebSocketista (vain ei-agents-tehtävät) uiSocket.addEventListener('message', (event) => { try { const data = JSON.parse(event.data); if (data.type === 'llm_done' && (data.model || '').includes('Coder')) { + // Ohita agents-pipelinen tehtävät — ne käsitellään kpnRun:issa + if (data.task_id && activeStreams[data.task_id]) return; addCodeResult(data); } } catch(e) {}