FI/SV/EN kielituki about valmis (testaamatta)
This commit is contained in:
@@ -120,6 +120,7 @@
|
||||
.main-panel.active { display: block; }
|
||||
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
@keyframes blink { 0%,100% { opacity:1; } 50% { opacity:0; } }
|
||||
|
||||
.code-output {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
@@ -1286,36 +1287,87 @@
|
||||
termPanel.scrollTop = termPanel.scrollHeight;
|
||||
}
|
||||
|
||||
async function kpnRun(model, prompt) {
|
||||
// Aktiiviset streaming-rivit task_id:n mukaan
|
||||
const activeStreams = {};
|
||||
|
||||
// Lähettää promptin mallille ja palauttaa vastauksen (tai null virhetilanteessa)
|
||||
async function kpnRun(model, prompt, silent) {
|
||||
termLog(` → <span style="color:#58a6ff">${model}</span> käsittelee...`, '#8b949e');
|
||||
try {
|
||||
const taskId = crypto.randomUUID();
|
||||
// Liitetään yhteinen konteksti + agentin oma system prompt
|
||||
const agent = Object.values(agentPrompts).find(a => a.model === model);
|
||||
const parts = [];
|
||||
if (sharedPrompt) parts.push(sharedPrompt);
|
||||
if (agent && agent.prompt) parts.push(agent.prompt);
|
||||
parts.push(prompt);
|
||||
const fullPrompt = parts.join('\n\n');
|
||||
|
||||
// Luodaan streaming-rivi terminaaliin
|
||||
if (!silent) {
|
||||
const streamDiv = document.createElement('div');
|
||||
streamDiv.className = 'terminal-line';
|
||||
streamDiv.style.color = '#c9d1d9';
|
||||
streamDiv.innerHTML = ' <span class="stream-content"></span><span style="color:#8b949e;animation:blink 1s infinite">▌</span>';
|
||||
termPanel.appendChild(streamDiv);
|
||||
termPanel.scrollTop = termPanel.scrollHeight;
|
||||
activeStreams[taskId] = streamDiv;
|
||||
}
|
||||
|
||||
const res = await fetch('/api/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ model, prompt: fullPrompt, task_id: taskId }),
|
||||
});
|
||||
|
||||
// Poistetaan streaming-rivi
|
||||
if (activeStreams[taskId]) {
|
||||
activeStreams[taskId].remove();
|
||||
delete activeStreams[taskId];
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
termLog(` ✗ Virhe: ${res.status} ${res.statusText}`, '#f85149');
|
||||
return;
|
||||
const errText = await res.text().catch(() => res.statusText);
|
||||
termLog(` ✗ ${errText}`, '#f85149');
|
||||
return null;
|
||||
}
|
||||
const data = await res.json();
|
||||
const response = (data.response || '').trim();
|
||||
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>`);
|
||||
termLog(` ${response.replace(/</g,'<').replace(/\n/g,'\n ')}`, '#c9d1d9');
|
||||
if (!silent) {
|
||||
termLog(` ${response.replace(/</g,'<').replace(/\n/g,'\n ')}`, '#c9d1d9');
|
||||
}
|
||||
return response;
|
||||
} catch (e) {
|
||||
termLog(` ✗ ${e.message}`, '#f85149');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Pipeline: manageri → koodari → testaaja
|
||||
async function kpnPipeline(task) {
|
||||
termLog(`<span style="color:#a371f7;font-weight:bold">━━━ Pipeline käynnistyy ━━━</span>`);
|
||||
|
||||
// Vaihe 1: Manageri analysoi
|
||||
termLog(`\n<span style="color:#d29922;font-weight:bold">[1/3] Manageri</span> — tehtävän analyysi`);
|
||||
const managerPrompt = `Analysoi seuraava ohjelmistokehitystehtävä ja kirjoita koodarille selkeä tekninen ohje mitä koodata. Vastaa lyhyesti.\n\nTehtävä: ${task}`;
|
||||
const plan = await kpnRun(agentPrompts.manager.model, managerPrompt);
|
||||
if (!plan) { termLog(' ✗ Pipeline keskeytyi (manageri)', '#f85149'); return; }
|
||||
|
||||
// Vaihe 2: Koodari toteuttaa
|
||||
termLog(`\n<span style="color:#3fb950;font-weight:bold">[2/3] Koodari</span> — toteutus`);
|
||||
const coderPrompt = `${plan}\n\nKirjoita koodi yllä olevan ohjeen mukaisesti.`;
|
||||
const code = await kpnRun(agentPrompts.coder.model, coderPrompt);
|
||||
if (!code) { termLog(' ✗ Pipeline keskeytyi (koodari)', '#f85149'); return; }
|
||||
|
||||
// Vaihe 3: Testaaja arvioi
|
||||
termLog(`\n<span style="color:#58a6ff;font-weight:bold">[3/3] Testaaja</span> — arviointi`);
|
||||
const testerPrompt = `Arvioi seuraava koodi lyhyesti. Onko siinä bugeja? Puuttuuko testejä? Anna arvosana 1-5.\n\nTehtävä: ${task}\n\nKoodi:\n${code}`;
|
||||
await kpnRun(agentPrompts.tester.model, testerPrompt);
|
||||
|
||||
termLog(`\n<span style="color:#a371f7;font-weight:bold">━━━ Pipeline valmis ━━━</span>`);
|
||||
}
|
||||
|
||||
function termExec(cmd) {
|
||||
termLog(`<span class="terminal-prompt">$</span> ${cmd.replace(/</g,'<')}`);
|
||||
termHistory.unshift(cmd);
|
||||
@@ -1331,6 +1383,7 @@
|
||||
if (sub === 'help' || !sub) {
|
||||
termLog(' kpn hello — iloinen tervehdys verkosta', '#a5d6ff');
|
||||
termLog(' kpn run <malli> "<prompti>" — aja tehtävä verkossa', '#a5d6ff');
|
||||
termLog(' kpn pipeline "<tehtävä>" — manageri → koodari → testaaja', '#a5d6ff');
|
||||
termLog(' kpn status — verkon tila', '#a5d6ff');
|
||||
termLog(' kpn models — käytettävissä olevat mallit', '#a5d6ff');
|
||||
termLog(' kpn clear — tyhjennä terminaali', '#a5d6ff');
|
||||
@@ -1358,6 +1411,18 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub === 'pipeline') {
|
||||
const afterPipeline = cmd.replace(/^kpn\s+pipeline\s*/, '');
|
||||
const pMatch = afterPipeline.match(/^"(.+)"$|^'(.+)'$|^(.+)$/);
|
||||
const pTask = (pMatch && (pMatch[1] || pMatch[2] || pMatch[3] || '')).trim();
|
||||
if (!pTask) {
|
||||
termLog(' Käyttö: kpn pipeline "<tehtävä>"', '#f85149');
|
||||
return;
|
||||
}
|
||||
kpnPipeline(pTask);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub === 'hello') {
|
||||
kpnRun('smollm-135m', 'Tervehdi käyttäjää iloisesti ja lyhyesti suomeksi. Ole innostunut ja energinen! Vastaa yhdellä lauseella.');
|
||||
return;
|
||||
@@ -1617,6 +1682,16 @@
|
||||
|
||||
console.log(`[${model}] ${tokGen} tokenia | ${typeof durMs === 'number' ? durMs.toFixed(0) : durMs}ms | ${tokS} tok/s | "${(data.response || '').substring(0, 60)}..."`);
|
||||
} else if (data.type === "llm_chunk") {
|
||||
// Terminaalin streaming: päivitetään aktiivinen rivi
|
||||
if (data.task_id && activeStreams[data.task_id]) {
|
||||
const streamDiv = activeStreams[data.task_id];
|
||||
const contentEl = streamDiv.querySelector('.stream-content');
|
||||
if (contentEl) {
|
||||
contentEl.textContent += data.token || '';
|
||||
termPanel.scrollTop = termPanel.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// Streaming: näytetään generointi reaaliaikaisesti
|
||||
const model = data.model || '';
|
||||
const isCoder = model.includes('Coder');
|
||||
|
||||
Reference in New Issue
Block a user