eka toimiva
This commit is contained in:
@@ -129,6 +129,40 @@
|
||||
.btn:hover { background-color: #2ea043; }
|
||||
.hidden { display: none; }
|
||||
|
||||
.compat-banner {
|
||||
border-radius: 6px;
|
||||
padding: 14px 18px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
display: none;
|
||||
}
|
||||
.compat-banner.gpu {
|
||||
background: #23392020;
|
||||
border: 1px solid #3fb95040;
|
||||
color: var(--success-color);
|
||||
}
|
||||
.compat-banner.cpu {
|
||||
background: #d2992215;
|
||||
border: 1px solid #d2992240;
|
||||
color: #d29922;
|
||||
}
|
||||
.compat-banner code {
|
||||
background: #0d1117;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
color: var(--text-color);
|
||||
}
|
||||
.compat-banner summary {
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.compat-banner details[open] summary {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.chat-box {
|
||||
background-color: var(--panel-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
@@ -191,12 +225,30 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
.toggle-tokens:hover { color: var(--text-color); border-color: #8b949e; }
|
||||
|
||||
.metric-card {
|
||||
background: var(--panel-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.metric-val {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: var(--accent-color);
|
||||
}
|
||||
.metric-label {
|
||||
font-size: 11px;
|
||||
color: #8b949e;
|
||||
margin-top: 2px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Kipinä <span>Agent Dashboard</span></h1>
|
||||
<p class="sub">Hajautettu WebGPU Laskentaverkko</p>
|
||||
<p class="sub">Hajautettu WebGPU Laskentaverkko · <span id="hub-version" style="color:#58a6ff">-</span></p>
|
||||
|
||||
<!-- Global Cluster Statistics (UI) -->
|
||||
<div class="dashboard-panel">
|
||||
@@ -215,16 +267,51 @@
|
||||
</div>
|
||||
|
||||
<div id="device-info" class="device-info"></div>
|
||||
<div id="compat-banner" class="compat-banner"></div>
|
||||
|
||||
<div id="initial-state">
|
||||
<button id="start-btn" class="btn">Liity laskentaverkkoon</button>
|
||||
</div>
|
||||
|
||||
<div id="active-state" class="hidden">
|
||||
<div class="slider-container">
|
||||
<label for="gpu-load">Oman Laitteen Kuormitusrajoitin: <strong id="load-display" style="color:var(--accent-color);">50%</strong></label>
|
||||
<input type="range" id="gpu-load" min="0" max="75" value="50">
|
||||
<p style="font-size: 11px; color:#8b949e;">Hallitsee "Duty Cyclea" – kuinka pitkään Wasm-ydin pakotetaan nukkumaan Tensorimatriisien laskennan välissä.</p>
|
||||
<!-- 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">
|
||||
<span style="font-weight:600;font-size:15px">Resurssien hallinta</span>
|
||||
<span id="node-status" style="font-size:12px;color:var(--success-color)">Aktiivinen</span>
|
||||
</div>
|
||||
|
||||
<!-- Kuormitussäädin -->
|
||||
<div style="margin-bottom:14px">
|
||||
<div style="display:flex;justify-content:space-between;font-size:13px;margin-bottom:4px">
|
||||
<span>Laskentatehon rajoitin</span>
|
||||
<strong id="load-display" style="color:var(--accent-color)">50%</strong>
|
||||
</div>
|
||||
<input type="range" id="gpu-load" min="0" max="100" value="50" style="width:100%;accent-color:var(--accent-color)">
|
||||
<div style="display:flex;justify-content:space-between;font-size:11px;color:#8b949e;margin-top:2px">
|
||||
<span>Pysäytetty</span><span>Säästö</span><span>Tasapaino</span><span>Suorituskyky</span><span>Maksimi</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reaaliaikaiset metriikat -->
|
||||
<div id="metrics-grid" style="display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-top:12px">
|
||||
<div class="metric-card">
|
||||
<div class="metric-val" id="m-tasks">0</div>
|
||||
<div class="metric-label">Tehtäviä</div>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<div class="metric-val" id="m-avg-time">-</div>
|
||||
<div class="metric-label">Ka. aika</div>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<div class="metric-val" id="m-tokens">0</div>
|
||||
<div class="metric-label">Tokeneita</div>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<div class="metric-val" id="m-uptime">0s</div>
|
||||
<div class="metric-label">Käynnissä</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="chat-box" class="chat-box hidden">
|
||||
@@ -251,6 +338,29 @@
|
||||
|
||||
let currentChatMsg = null;
|
||||
|
||||
// Reaaliaikaiset metriikat
|
||||
const metrics = {
|
||||
tasks: 0,
|
||||
totalTokens: 0,
|
||||
totalTimeMs: 0,
|
||||
startTime: null,
|
||||
};
|
||||
|
||||
function updateMetrics() {
|
||||
document.getElementById('m-tasks').textContent = metrics.tasks;
|
||||
document.getElementById('m-tokens').textContent = metrics.totalTokens.toLocaleString('fi-FI');
|
||||
document.getElementById('m-avg-time').textContent = metrics.tasks > 0
|
||||
? (metrics.totalTimeMs / metrics.tasks).toFixed(1) + 'ms'
|
||||
: '-';
|
||||
if (metrics.startTime) {
|
||||
const sec = Math.floor((Date.now() - metrics.startTime) / 1000);
|
||||
if (sec < 60) document.getElementById('m-uptime').textContent = sec + 's';
|
||||
else if (sec < 3600) document.getElementById('m-uptime').textContent = Math.floor(sec/60) + 'min';
|
||||
else document.getElementById('m-uptime').textContent = Math.floor(sec/3600) + 'h ' + (Math.floor(sec/60)%60) + 'min';
|
||||
}
|
||||
}
|
||||
setInterval(updateMetrics, 1000);
|
||||
|
||||
// Ylikirjoitetaan console.log uppoamaan lokilaatikkoon
|
||||
const originalLog = console.log;
|
||||
console.log = function(...args) {
|
||||
@@ -272,9 +382,22 @@
|
||||
|
||||
// UI Slider Listener -> Lähettää arvon suoraan WebAssemblyn ytimeen!
|
||||
loadSlider.addEventListener('input', (e) => {
|
||||
loadDisplay.textContent = e.target.value + '%';
|
||||
const val = parseInt(e.target.value);
|
||||
loadDisplay.textContent = val + '%';
|
||||
if (window.wasm_active) {
|
||||
set_gpu_load(parseInt(e.target.value));
|
||||
set_gpu_load(val);
|
||||
}
|
||||
// Tilapäivitys
|
||||
const statusEl = document.getElementById('node-status');
|
||||
if (val === 0) {
|
||||
statusEl.textContent = 'Pysäytetty';
|
||||
statusEl.style.color = '#f85149';
|
||||
} else if (val <= 25) {
|
||||
statusEl.textContent = 'Säästötila';
|
||||
statusEl.style.color = '#d29922';
|
||||
} else {
|
||||
statusEl.textContent = 'Aktiivinen';
|
||||
statusEl.style.color = 'var(--success-color)';
|
||||
}
|
||||
});
|
||||
|
||||
@@ -289,6 +412,9 @@
|
||||
if (data.tasks !== undefined) {
|
||||
statTasks.textContent = data.tasks;
|
||||
}
|
||||
if (data.version) {
|
||||
document.getElementById('hub-version').textContent = 'v' + data.version;
|
||||
}
|
||||
} else if (data.type === "node_joined") {
|
||||
chatBox.classList.remove('hidden');
|
||||
const msgDiv = document.createElement('div');
|
||||
@@ -321,6 +447,12 @@
|
||||
const nodeId = data.node_id || "?";
|
||||
const ms = data.duration_ms || 0;
|
||||
|
||||
// Päivitetään metriikat
|
||||
metrics.tasks++;
|
||||
metrics.totalTokens += (en.token_count || 0) + (fi.token_count || 0);
|
||||
metrics.totalTimeMs += ms;
|
||||
updateMetrics();
|
||||
|
||||
const enCpt = parseFloat((en.chars_per_token || 0).toFixed(2));
|
||||
const fiCpt = parseFloat((fi.chars_per_token || 0).toFixed(2));
|
||||
|
||||
@@ -432,6 +564,52 @@
|
||||
`Varaus: <span>${deviceInfo.allocated_gb} GB</span>`
|
||||
].filter(Boolean).join(' · ');
|
||||
|
||||
// Yhteensopivuusbanneri
|
||||
const banner = document.getElementById('compat-banner');
|
||||
banner.style.display = 'block';
|
||||
|
||||
if (hasWebGPU) {
|
||||
banner.className = 'compat-banner gpu';
|
||||
banner.innerHTML = `GPU-kiihdytys aktiivinen — ${gpuStr}`;
|
||||
} else {
|
||||
// Tunnistetaan selain ohjeen personointia varten
|
||||
const ua = navigator.userAgent;
|
||||
const isFirefox = ua.includes('Firefox');
|
||||
const isChrome = ua.includes('Chrome') && !ua.includes('Edg');
|
||||
const isBrave = ua.includes('Brave') || (navigator.brave && navigator.brave.isBrave);
|
||||
const isSafari = ua.includes('Safari') && !ua.includes('Chrome');
|
||||
const isLinux = ua.includes('Linux');
|
||||
|
||||
let browserTip = '';
|
||||
if (isFirefox) {
|
||||
browserTip = `
|
||||
<p><strong>Firefox</strong> ei tue WebGPU:ta oletuksena.</p>
|
||||
<p>Ota käyttöön: <code>about:config</code> → <code>dom.webgpu.enabled</code> = <code>true</code> → käynnistä uudelleen.</p>
|
||||
<p>Tai vaihda Chromeen/Braveen — niissä WebGPU toimii oletuksena.</p>`;
|
||||
} else if ((isChrome || isBrave) && isLinux) {
|
||||
const browser = isBrave ? 'brave-browser' : 'google-chrome';
|
||||
browserTip = `
|
||||
<p><strong>${isBrave ? 'Brave' : 'Chrome'} + Linux</strong>: GPU-ajuri ei ehkä tarjoa WebGPU:ta Wayland-ympäristössä.</p>
|
||||
<p>Kokeile käynnistää selain komentoriviltä:</p>
|
||||
<code>${browser} --enable-unsafe-webgpu --enable-features=Vulkan --ignore-gpu-blocklist --use-angle=vulkan --ozone-platform=x11</code>`;
|
||||
} else if (isSafari) {
|
||||
browserTip = `
|
||||
<p><strong>Safari</strong>: WebGPU on tuettu versiosta 26 alkaen (macOS Tahoe).</p>
|
||||
<p>Vanhemmissa versioissa: Develop → Feature Flags → WebGPU.</p>`;
|
||||
} else {
|
||||
browserTip = `
|
||||
<p>Selaimesi ei tue WebGPU:ta. Kokeile <strong>Chrome 113+</strong> tai <strong>Brave</strong>.</p>`;
|
||||
}
|
||||
|
||||
banner.className = 'compat-banner cpu';
|
||||
banner.innerHTML = `
|
||||
<details>
|
||||
<summary>CPU-laskenta (WebGPU ei käytettävissä) — klikkaa ohjeita</summary>
|
||||
${browserTip}
|
||||
<p style="margin-top:8px;color:#8b949e;font-size:12px">Laskenta toimii silti CPU:lla, mutta GPU-kiihdytys olisi nopeampi.</p>
|
||||
</details>`;
|
||||
}
|
||||
|
||||
document.getElementById('initial-state').classList.add('hidden');
|
||||
document.getElementById('active-state').classList.remove('hidden');
|
||||
btn.style.display = 'none';
|
||||
@@ -440,6 +618,7 @@
|
||||
console.log("Ladataan Burn Wasm -binääriä...");
|
||||
await init();
|
||||
window.wasm_active = true;
|
||||
metrics.startTime = Date.now();
|
||||
|
||||
// Varmistetaan, että Wasm saa nykyisen sliderin arvon heti kärkeen
|
||||
set_gpu_load(parseInt(loadSlider.value));
|
||||
|
||||
Reference in New Issue
Block a user