diff --git a/packages/tracker/meshnet_tracker/dashboard.html b/packages/tracker/meshnet_tracker/dashboard.html index 12076cc..bf82ea9 100644 --- a/packages/tracker/meshnet_tracker/dashboard.html +++ b/packages/tracker/meshnet_tracker/dashboard.html @@ -277,6 +277,7 @@ const esc = s => String(s).replace(/[&<>"]/g, const usdt = v => (Math.round(v * 1e6) / 1e6).toFixed(6); const tps = v => (v === null || v === undefined) ? "?" : (Math.round(v * 10) / 10).toFixed(1); const copies = v => (v === null || v === undefined) ? "?" : Number(v).toFixed(2); +const hp = v => (v === null || v === undefined) ? "?HP" : `${Number(v).toFixed(1)}HP`; const short = (s, n=14) => { s = String(s); return s.length > n ? s.slice(0, 6) + "…" + s.slice(-5) : s; }; function modelAliasKey(value) { @@ -1114,12 +1115,8 @@ function findRoutingForModel(model, routing) { return null; } -function chatModelHealthLabel(coverage) { - if (coverage === null || coverage === undefined) return "unknown"; - const pct = Math.round(Number(coverage)); - if (pct >= 100) return "healthy"; - if (pct > 0) return `${pct}% cov`; - return "no coverage"; +function chatModelHealthHp(servedCopies) { + return hp(servedCopies); } function chatModelTypicalTps(model, routing) { @@ -1136,7 +1133,7 @@ function chatModelOptionLabel(model, routing) { const base = model.name && model.name !== model.id ? `${model.name} (${model.id})` : model.id; - const health = chatModelHealthLabel(model.coverage); + const health = chatModelHealthHp(model.servedCopies); const speed = chatModelTypicalTps(model, routing); const speedText = speed === null ? "?" : `${tps(speed)} tok/s`; const suffix = model.recommended ? " · recommended" : ""; @@ -1644,6 +1641,7 @@ async function refresh() { recommended: Boolean(model.recommended), aliases: model.aliases || [], coverage: model.shard_coverage_percentage, + servedCopies: model.served_model_copies, })).filter(model => model.id); renderHive(raft); renderNodes(map); diff --git a/packages/tracker/meshnet_tracker/server.py b/packages/tracker/meshnet_tracker/server.py index ce57080..c433da0 100644 --- a/packages/tracker/meshnet_tracker/server.py +++ b/packages/tracker/meshnet_tracker/server.py @@ -2729,6 +2729,11 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler): required_start, required_end, ) + served_copies = _served_model_copies( + model_nodes, + required_start, + required_end, + ) aliases = [name] hf_repo = preset.get("hf_repo") if hf_repo and hf_repo not in aliases: @@ -2748,6 +2753,7 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler): "recommended": bool(preset.get("recommended", False)), "deployment": _deployment_summary(alive, preset), "shard_coverage_percentage": coverage, + "served_model_copies": served_copies, }) seen_ids.add(name) if hf_repo: @@ -2778,6 +2784,11 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler): aliases = [model_id, *[name for name in short_names if name != model_id]] required_start = 0 required_end = max(node.num_layers for node in model_nodes) - 1 + coverage = _coverage_percentage( + model_nodes, + required_start, + required_end, + ) data.append({ "id": model_id, "object": "model", @@ -2787,7 +2798,8 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler): "hf_repo": model_id if any(node.hf_repo == model_id for node in model_nodes) else None, "aliases": aliases, "metadata": _model_metadata_from_nodes(model_nodes), - "shard_coverage_percentage": _coverage_percentage( + "shard_coverage_percentage": coverage, + "served_model_copies": _served_model_copies( model_nodes, required_start, required_end, diff --git a/tests/test_dashboard.py b/tests/test_dashboard.py index affa31d..dd6e650 100644 --- a/tests/test_dashboard.py +++ b/tests/test_dashboard.py @@ -62,11 +62,12 @@ def test_dashboard_chat_model_selector_shows_health_and_speed(): finally: tracker.stop() - assert "chatModelHealthLabel" in html + assert "chatModelHealthHp" in html assert "chatModelTypicalTps" in html assert "chatModelOptionLabel" in html assert "findRoutingForModel" in html assert "tok/s" in html + assert "0.0HP" in html or "toFixed(1)}HP" in html def test_dashboard_chat_sessions_use_delegated_handlers():