feat(diagnostic): Karten-Auslastung auch pro Box aus der Compute-Flotte

Neben "Auslastung" bei jeder Box ein "📊 Karten"-Button: dasselbe Fenster,
nur fuer diese Box (Titel zeigt den Namen).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 14:37:10 +01:00
co-authored by Claude Opus 5.5
parent 294917fe36
commit f7f9275b31
+7 -3
View File
@@ -201,7 +201,7 @@
<div id="card-load-modal" style="display:none;position:fixed;inset:0;z-index:1001;background:rgba(0,0,0,0.8);align-items:center;justify-content:center;" onclick="if(event.target===this)closeCardLoad()">
<div style="background:#0D0D1A;border:1px solid #2A2A3E;border-radius:10px;padding:16px;max-width:1000px;width:94%;max-height:92vh;overflow:auto;display:flex;flex-direction:column;gap:10px;">
<div style="display:flex;align-items:center;justify-content:space-between;">
<h3 style="margin:0;color:#fff;">Auslastung der Grafikkarten <span style="font-size:11px;color:#8888AA;font-weight:normal;">· live, jede Sekunde</span></h3>
<h3 style="margin:0;color:#fff;">Auslastung der Grafikkarten<span id="card-load-scope"></span> <span style="font-size:11px;color:#8888AA;font-weight:normal;">· live, jede Sekunde</span></h3>
<button onclick="closeCardLoad()" style="background:none;border:none;color:#8888AA;font-size:22px;cursor:pointer;">&times;</button>
</div>
<div id="card-load-body" style="display:flex;flex-direction:column;gap:14px;"></div>
@@ -5249,7 +5249,8 @@
// GPUs + Tokens), sonst irgendein online Worker des Node.
const group = byNode[node];
const rep = group.find(w => w.service === 'llm' && w.online) || group.find(w => w.online) || group[0];
const btn = rep ? '<button class="btn secondary" onclick="openNodeStats(\'' + escapeHtml(rep.instanceId) + '\',\'' + escapeHtml(node) + '\')" style="padding:2px 8px;font-size:10px;margin-left:8px;">Auslastung</button>' : '';
const btn = rep ? '<button class="btn secondary" onclick="openNodeStats(\'' + escapeHtml(rep.instanceId) + '\',\'' + escapeHtml(node) + '\')" style="padding:2px 8px;font-size:10px;margin-left:8px;">Auslastung</button>' +
'<button class="btn secondary" onclick="openCardLoad(\'' + escapeHtml(node) + '\')" title="Live-Auslastung pro Grafikkarte dieser Box" style="padding:2px 8px;font-size:10px;margin-left:6px;">📊 Karten</button>' : '';
return '<div style="margin-bottom:10px;">' +
'<div style="font-weight:600;color:#AAB;margin-bottom:2px;">🖥️ ' + escapeHtml(node) + btn + '</div>' +
rows + '</div>';
@@ -5331,13 +5332,16 @@
const _cardLoadStreams = new Map(); // instanceId → {node, gpus, single}
const _cardLoad = new Map(); // node|uuid → {node, index, name, util, ..., hist: []}
let _cardLoadTimer = null;
function openCardLoad() {
/** onlyNode: nur diese Box (Button in der Compute-Flotte); leer = alle */
function openCardLoad(onlyNode) {
document.getElementById('card-load-modal').style.display = 'flex';
document.getElementById('card-load-scope').textContent = onlyNode ? ' · ' + onlyNode : '';
_cardLoad.clear();
_cardLoadStreams.clear();
const byNode = {};
for (const w of workers) {
if (!w.online || !['llm', 'whisper', 'f5tts', 'voxtral'].includes(w.service)) continue;
if (onlyNode && w.node !== onlyNode) continue;
(byNode[w.node] = byNode[w.node] || []).push(w);
}
for (const [node, list] of Object.entries(byNode)) {