toka toimiva vedos
This commit is contained in:
@@ -226,6 +226,54 @@
|
||||
}
|
||||
.toggle-tokens:hover { color: var(--text-color); border-color: #8b949e; }
|
||||
|
||||
.task-option {
|
||||
background: var(--panel-bg);
|
||||
border: 2px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
padding: 14px;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s;
|
||||
position: relative;
|
||||
}
|
||||
.task-option:hover { border-color: #8b949e; }
|
||||
.task-option.selected { border-color: var(--accent-color); background: #58a6ff10; }
|
||||
.task-title { font-weight: 600; font-size: 15px; color: var(--text-color); margin-bottom: 4px; }
|
||||
.task-desc { font-size: 12px; color: #8b949e; line-height: 1.4; margin-bottom: 8px; }
|
||||
.task-size { font-size: 11px; color: #6e7681; }
|
||||
.task-badge {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.task-ready { background: #23392050; color: var(--success-color); border: 1px solid #23392080; }
|
||||
.task-soon { background: #d2992215; color: #d29922; border: 1px solid #d2992240; }
|
||||
|
||||
.download-bar {
|
||||
background: #0d1117;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
padding: 12px 16px;
|
||||
margin-bottom: 16px;
|
||||
display: none;
|
||||
}
|
||||
.download-bar .bar-track {
|
||||
background: #21262d;
|
||||
border-radius: 4px;
|
||||
height: 8px;
|
||||
margin-top: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.download-bar .bar-fill {
|
||||
background: var(--accent-color);
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.metric-card {
|
||||
background: var(--panel-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
@@ -270,10 +318,53 @@
|
||||
<div id="compat-banner" class="compat-banner"></div>
|
||||
|
||||
<div id="initial-state">
|
||||
<!-- Tehtävävalitsin -->
|
||||
<div style="background:#0d1117;border:1px solid var(--border-color);border-radius:6px;padding:16px;margin-bottom:16px;text-align:left">
|
||||
<div style="font-weight:600;font-size:15px;margin-bottom:12px">Valitse tehtävä</div>
|
||||
<div id="task-selector" style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
|
||||
<label class="task-option selected" data-task="tokenize">
|
||||
<input type="radio" name="task" value="tokenize" checked style="display:none">
|
||||
<div class="task-title">Tokenisointivertailu</div>
|
||||
<div class="task-desc">EN/FI-kieliparien tokenisointitehokkuuden vertailu Qwen2.5-tokenizeria käyttäen</div>
|
||||
<div class="task-size">Lataus: ~7 MB (tokenizer)</div>
|
||||
<span class="task-badge task-ready">Valmis</span>
|
||||
</label>
|
||||
<label class="task-option" data-task="smollm-135m">
|
||||
<input type="radio" name="task" value="smollm-135m" style="display:none">
|
||||
<div class="task-title">SmolLM 135M</div>
|
||||
<div class="task-desc">Kevyt kielimalli tekstigeneraatioon — sopii kaikille laitteille (CPU)</div>
|
||||
<div class="task-size">Lataus: ~269 MB (safetensors) + 2 MB (tokenizer)</div>
|
||||
<span class="task-badge task-ready">Valmis</span>
|
||||
</label>
|
||||
<label class="task-option" data-task="qwen-05b">
|
||||
<input type="radio" name="task" value="qwen-05b" style="display:none">
|
||||
<div class="task-title">Qwen2.5 0.5B</div>
|
||||
<div class="task-desc">Tehokkaampi kielimalli — vaatii WebGPU:n ja vähintään 1 GB muistia</div>
|
||||
<div class="task-size">Lataus: ~430 MB (Q4)</div>
|
||||
<span class="task-badge task-soon">Tulossa</span>
|
||||
</label>
|
||||
<label class="task-option" data-task="phi3-mini">
|
||||
<input type="radio" name="task" value="phi3-mini" style="display:none">
|
||||
<div class="task-title">Phi-3 Mini 3.8B</div>
|
||||
<div class="task-desc">Iso kielimalli — vaatii tehokkaan GPU:n ja vähintään 4 GB VRAM</div>
|
||||
<div class="task-size">Lataus: ~2.3 GB (Q4)</div>
|
||||
<span class="task-badge task-soon">Tulossa</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="start-btn" class="btn">Liity laskentaverkkoon</button>
|
||||
</div>
|
||||
|
||||
<div id="active-state" class="hidden">
|
||||
<div id="download-bar" class="download-bar">
|
||||
<div style="display:flex;justify-content:space-between;font-size:13px">
|
||||
<span id="dl-label">Ladataan mallia...</span>
|
||||
<span id="dl-pct" style="color:var(--accent-color);font-weight:600">0%</span>
|
||||
</div>
|
||||
<div class="bar-track"><div id="dl-fill" class="bar-fill" style="width:0%"></div></div>
|
||||
<div id="dl-detail" style="font-size:11px;color:#8b949e;margin-top:4px">0 / 0 MB</div>
|
||||
</div>
|
||||
<!-- Resurssipaneeli -->
|
||||
<div style="background:#0d1117;border:1px solid var(--border-color);border-radius:6px;padding:16px;margin-bottom:16px">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px">
|
||||
@@ -335,7 +426,17 @@
|
||||
const statVram = document.getElementById('stat-vram');
|
||||
const statTasks = document.getElementById('stat-tasks');
|
||||
const chatBox = document.getElementById('chat-box');
|
||||
|
||||
|
||||
// Tehtävävalitsin
|
||||
let selectedTask = 'tokenize';
|
||||
document.querySelectorAll('.task-option').forEach(opt => {
|
||||
opt.addEventListener('click', () => {
|
||||
document.querySelectorAll('.task-option').forEach(o => o.classList.remove('selected'));
|
||||
opt.classList.add('selected');
|
||||
selectedTask = opt.dataset.task;
|
||||
});
|
||||
});
|
||||
|
||||
let currentChatMsg = null;
|
||||
|
||||
// Reaaliaikaiset metriikat
|
||||
@@ -424,6 +525,17 @@
|
||||
chatBox.appendChild(msgDiv);
|
||||
if (chatBox.children.length > 5) chatBox.removeChild(chatBox.firstChild);
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
} else if (data.type === "download_progress") {
|
||||
const dlBar = document.getElementById('download-bar');
|
||||
if (data.pct < 100) {
|
||||
dlBar.style.display = 'block';
|
||||
document.getElementById('dl-label').textContent = `Ladataan: ${data.file}`;
|
||||
document.getElementById('dl-pct').textContent = data.pct + '%';
|
||||
document.getElementById('dl-fill').style.width = data.pct + '%';
|
||||
document.getElementById('dl-detail').textContent = `${data.loaded_mb} / ${data.total_mb} MB`;
|
||||
} else {
|
||||
dlBar.style.display = 'none';
|
||||
}
|
||||
} else if (data.type === "pair_task") {
|
||||
chatBox.classList.remove('hidden');
|
||||
if (chatBox.children.length === 1 && chatBox.children[0].textContent.includes('Odotetaan')) {
|
||||
@@ -453,6 +565,9 @@
|
||||
metrics.totalTimeMs += ms;
|
||||
updateMetrics();
|
||||
|
||||
// Lokiboksiin yhteenveto
|
||||
console.log(`EN: ${en.token_count} tokenia (${(en.chars_per_token||0).toFixed(2)} m/t) vs FI: ${fi.token_count} tokenia (${(fi.chars_per_token||0).toFixed(2)} m/t) | ylikustannus: ${overhead}% | ${typeof ms === 'number' ? ms.toFixed(2) : ms}ms`);
|
||||
|
||||
const enCpt = parseFloat((en.chars_per_token || 0).toFixed(2));
|
||||
const fiCpt = parseFloat((fi.chars_per_token || 0).toFixed(2));
|
||||
|
||||
@@ -480,7 +595,7 @@
|
||||
<span style="color:var(--accent-color);font-weight:600;font-size:15px">Solmu #${nodeId}</span>
|
||||
<div style="display:flex;gap:8px;align-items:center">
|
||||
<button class="toggle-tokens" onclick="document.getElementById('${detailId}').classList.toggle('visible')">Tokenit</button>
|
||||
<span style="color:#8b949e;font-size:13px">${ms}ms</span>
|
||||
<span style="color:#8b949e;font-size:13px">${typeof ms === 'number' ? ms.toFixed(2) : ms}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="font-size:14px;display:grid;grid-template-columns:32px 1fr auto auto auto;gap:6px 10px;align-items:baseline">
|
||||
@@ -508,6 +623,46 @@
|
||||
if (!msgDiv.parentNode) chatBox.appendChild(msgDiv);
|
||||
if (chatBox.children.length > 8) chatBox.removeChild(chatBox.firstChild);
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
} else if (data.type === "llm_done") {
|
||||
// SmolLM / LLM-inferenssin tulos
|
||||
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 = `
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">
|
||||
<span style="color:#a371f7;font-weight:600;font-size:15px">Solmu #${nodeId} — ${model}</span>
|
||||
<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>
|
||||
</div>
|
||||
<div style="font-size:14px;color:var(--text-color);line-height:1.5">
|
||||
${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
|
||||
</div>`;
|
||||
chatBox.appendChild(msgDiv);
|
||||
if (chatBox.children.length > 8) chatBox.removeChild(chatBox.firstChild);
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
|
||||
metrics.tasks++;
|
||||
metrics.totalTokens += tokGen;
|
||||
metrics.totalTimeMs += durMs;
|
||||
updateMetrics();
|
||||
|
||||
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") {
|
||||
// Streaming-token LLM:ltä — näytetään lokissa
|
||||
// (chat-ikkunan streaming tulisi toteuttaa samalla logiikalla kuin pair_task/pair_done)
|
||||
}
|
||||
} catch(e) {}
|
||||
};
|
||||
@@ -520,7 +675,8 @@
|
||||
cpu_cores: navigator.hardwareConcurrency || 0,
|
||||
device_memory_gb: navigator.deviceMemory || 0,
|
||||
platform: navigator.platform || "",
|
||||
gpu: null
|
||||
gpu: null,
|
||||
selected_task: selectedTask
|
||||
};
|
||||
|
||||
if (navigator.gpu) {
|
||||
@@ -625,7 +781,9 @@
|
||||
|
||||
// WebAssembly yhdistää oikeaksi Agent Nodeksi
|
||||
const wsUrl = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/ws`;
|
||||
await start_agent_node(wsUrl, hasWebGPU, JSON.stringify(deviceInfo));
|
||||
const taskIds = {'tokenize': 0, 'smollm-135m': 1, 'qwen-05b': 2, 'phi3-mini': 3};
|
||||
const taskId = taskIds[selectedTask] || 0;
|
||||
await start_agent_node(wsUrl, hasWebGPU, JSON.stringify(deviceInfo), taskId);
|
||||
} catch(e) {
|
||||
console.log("Virhe GPU-käynnistyksessä: " + e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user