Viestien säätöä

This commit is contained in:
Jaakko Vanhala
2026-04-05 08:09:35 +03:00
parent 1845ddf8c2
commit 12fd3c4eae
2 changed files with 41 additions and 19 deletions

View File

@@ -1107,7 +1107,19 @@
<script type="module">
import init, { start_agent_node, set_gpu_load, set_auto_tasks } from './pkg/node.js';
// Päävälilehtien vaihto
// HTML-escape kaikelle käyttäjä-/backendidatalle joka menee innerHTML:ään
function esc(str) {
if (!str) return '';
return String(str).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
// Poistaa system-promptin näkyvästä prompt-tekstistä (agents-pipeline lisää sen alkuun)
function stripSystemPrompt(prompt) {
if (!prompt) return '';
// Poistetaan kaikki ennen viimeistä kappaletta (system + agent promptit erotettu \n\n:llä)
const parts = prompt.split('\n\n');
return parts[parts.length - 1] || prompt;
}
// Agenttien system promptit
const agentPrompts = {
client: { name: 'Asiakas — Projektin vaatimukset', model: 'user-input', default: 'Kirjoita tähän asiakkaan toiveet ja projektin vaatimukset. Orkestraattori (Manageri) purkaa ja delegoi nämä työt asiantuntijoille.' },
@@ -1736,7 +1748,7 @@
const tokGen = data.tokens_generated || 0;
termLog(` <span style="color:#3fb950">✓</span> <span style="color:#58a6ff">${data.model || model}</span> <span style="color:#8b949e">(${tokGen} tok)</span>`);
if (!silent) {
termLog(` ${response.replace(/</g,'&lt;').replace(/\n/g,'\n ')}`, '#c9d1d9');
termLog(` ${esc(response).replace(/\n/g,'\n ')}`, '#c9d1d9');
}
return response;
} catch (e) {
@@ -1775,7 +1787,7 @@
}
function termExec(cmd) {
termLog(`<span class="terminal-prompt">$</span> ${cmd.replace(/</g,'&lt;')}`);
termLog(`<span class="terminal-prompt">$</span> ${esc(cmd)}`);
termHistory.unshift(cmd);
termHistIdx = -1;
@@ -1919,7 +1931,7 @@
const cpt = parseFloat((r.chars_per_token || 0).toFixed(2));
const cptColor = cpt >= 4 ? "#3fb950" : cpt >= 3 ? "#d29922" : "#f85149";
const renderTokens = (tokens) => (tokens || []).map(t =>
`<span class="tok tok-en">${t.replace(/</g,'&lt;')}</span>`
`<span class="tok tok-en">${esc(t)}</span>`
).join('');
const tokHtml = renderTokens(r.tokens);
const detailId = 'stok-' + Date.now();
@@ -1934,7 +1946,7 @@
<span style="color:#8b949e;font-size:13px">${typeof ms === 'number' ? ms.toFixed(2) : ms}ms</span>
</div>
</div>
<div style="font-size:14px;color:#79b8ff;margin-bottom:6px">"${r.text || ''}"</div>
<div style="font-size:14px;color:#79b8ff;margin-bottom:6px">"${esc(r.text)}"</div>
<div style="font-size:14px;display:flex;gap:16px">
<span style="color:#8b949e">${r.char_count || 0} merkkiä</span>
<span style="color:#8b949e">${r.word_count || 0} sanaa</span>
@@ -1957,8 +1969,8 @@
msgDiv.className = 'chat-msg';
msgDiv.innerHTML = `<span class="chat-prompt">Tokenisoidaan...</span>
<div style="font-size:12px;color:#8b949e">
<div><strong style="color:#58a6ff">EN</strong> "${data.en}"</div>
<div><strong style="color:#d29922">FI</strong> "${data.fi}"</div>
<div><strong style="color:#58a6ff">EN</strong> "${esc(data.en)}"</div>
<div><strong style="color:#d29922">FI</strong> "${esc(data.fi)}"</div>
</div>`;
chatBox.appendChild(msgDiv);
if (chatBox.children.length > 5) chatBox.removeChild(chatBox.firstChild);
@@ -1997,7 +2009,7 @@
// Tokenilistat renderöitäväksi
const renderTokens = (tokens, cls) => (tokens || []).map(t =>
`<span class="tok ${cls}">${t.replace(/</g,'&lt;')}</span>`
`<span class="tok ${cls}">${esc(t)}</span>`
).join('');
const enTokHtml = renderTokens(en.tokens, 'tok-en');
const fiTokHtml = renderTokens(fi.tokens, 'tok-fi');
@@ -2013,13 +2025,13 @@
</div>
<div style="font-size:14px;display:grid;grid-template-columns:32px 1fr auto auto auto;gap:6px 10px;align-items:baseline">
<strong style="color:#58a6ff">EN</strong>
<span style="color:#79b8ff">"${en.text || ''}"</span>
<span style="color:#79b8ff">"${esc(en.text)}"</span>
<span style="color:#8b949e">${en.char_count} m</span>
<span style="color:var(--accent-color);font-weight:600">${en.token_count} tok</span>
<span style="color:${cptColor(enCpt)};font-weight:600">${enCpt} m/t</span>
<strong style="color:#d29922">FI</strong>
<span style="color:#e3b341">"${fi.text || ''}"</span>
<span style="color:#e3b341">"${esc(fi.text)}"</span>
<span style="color:#8b949e">${fi.char_count} m</span>
<span style="color:var(--accent-color);font-weight:600">${fi.token_count} tok</span>
<span style="color:${cptColor(fiCpt)};font-weight:600">${fiCpt} m/t</span>
@@ -2084,10 +2096,10 @@
<span style="color:#8b949e;font-size:12px">${typeof durMs === 'number' ? durMs.toFixed(0) : durMs}ms | ${tokS} tok/s</span>
</div>
<div style="font-size:13px;color:#8b949e;margin-bottom:6px">
Prompt: <span style="color:#d29922">"${data.prompt || ''}"</span>
Prompt: <span style="color:#d29922">"${esc(stripSystemPrompt(data.prompt))}"</span>
</div>
<div style="font-size:14px;color:var(--text-color);line-height:1.5;${(model.includes('Coder') || (data.response||'').includes('def ')) ? 'font-family:Courier New,monospace;background:#010409;padding:10px;border-radius:4px;white-space:pre-wrap;font-size:12px' : ''}">
${(data.response || '<em>tyhjä vastaus</em>').replace(/</g, '&lt;').replace(/>/g, '&gt;')}
${data.response ? esc(data.response) : '<em>tyhjä vastaus</em>'}
</div>
<div style="margin-top:8px;font-size:12px;color:#8b949e">
${tokGen} tokenia generoitu | malli ladattu: ${typeof loadMs === 'number' ? loadMs.toFixed(0) : loadMs}ms
@@ -2151,7 +2163,7 @@
<span style="color:#a371f7;font-weight:600">${model}</span>
<span class="stream-counter" style="color:var(--accent-color);font-size:12px">0 tok</span>
</div>
<div style="font-size:13px;color:#8b949e;margin-bottom:4px">Prompt: "${data.prompt || ''}"</div>
<div style="font-size:13px;color:#8b949e;margin-bottom:4px">Prompt: "${esc(stripSystemPrompt(data.prompt))}"</div>
<div class="stream-text" style="font-size:14px;color:var(--text-color);line-height:1.5;${isCoder ? 'font-family:Courier New,monospace;background:#010409;padding:8px;border-radius:4px;white-space:pre-wrap;font-size:12px;color:#3fb950' : ''}"></div>
<div style="margin-top:6px;font-size:11px;color:#d29922">
<span class="spinner" style="display:inline-block;animation:spin 1s linear infinite">&#9696;</span> Generating...
@@ -2175,7 +2187,7 @@
const term = document.getElementById('agent-terminal');
if (term) {
const model = data.model || 'llm';
const promptShort = (data.prompt || '').substring(0, 50).replace(/</g,'&lt;');
const promptShort = esc(stripSystemPrompt(data.prompt)).substring(0, 50);
const div = document.createElement('div');
div.className = 'terminal-line';
div.innerHTML = `<span class="terminal-prompt">$</span> kpn run ${model} <span style="color:#8b949e">"${promptShort}"</span>`;
@@ -2365,7 +2377,7 @@
const tokGen = data.tokens_generated || 0;
const durMs = data.duration_ms || 0;
const tokS = data.tokens_per_sec || 0;
const response = (data.response || '').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const response = esc(data.response);
codeMetrics.tasks++;
codeMetrics.tokens += tokGen;
@@ -2386,7 +2398,7 @@
const card = document.createElement('div');
card.className = 'code-task-card';
card.innerHTML = `
<div class="prompt">${data.prompt || ''}</div>
<div class="prompt">${esc(stripSystemPrompt(data.prompt))}</div>
<div class="code-output">${highlightPython(response)}</div>
<div class="meta">
${model} · ${tokGen} tokenia · ${typeof durMs === 'number' ? durMs.toFixed(0) : durMs}ms · ${tokS} tok/s
@@ -2440,7 +2452,14 @@
if (msg.includes('[Coder]') && msg.includes('model') && msg.includes('löytyi')) { setStep('step-model', 'done', 'cache'); }
if (msg.includes('[Coder]') && msg.includes('model') && msg.includes('tallennettu')) { setStep('step-model', 'done', '100%'); }
if (msg.includes('[Coder]') && msg.includes('Rakennetaan')) { setStep('step-build', 'active'); }
if (msg.includes('[Coder]') && msg.includes('Malli ladattu')) { setStep('step-build', 'done'); setStep('step-ready', 'done'); }
if (msg.includes('[Coder]') && msg.includes('Malli ladattu')) {
// Malli on valmis — merkataan kaikki vaiheet valmiiksi (myös cache-hitillä)
setStep('step-wasm', 'done');
setStep('step-tokenizer', 'done');
setStep('step-model', 'done', 'cache');
setStep('step-build', 'done');
setStep('step-ready', 'done');
}
if (msg.includes('[Coder]') && msg.includes('Syöte:')) {
// Pipeline piiloon kun generointi alkaa
setTimeout(() => { document.getElementById('code-pipeline').style.display = 'none'; }, 1000);