more chat UI

This commit is contained in:
Dobromir Popov
2026-07-08 20:51:42 +03:00
parent 42d6fe2b15
commit aa7f4eb13b
3 changed files with 20 additions and 9 deletions

View File

@@ -277,6 +277,7 @@ const esc = s => String(s).replace(/[&<>"]/g,
const usdt = v => (Math.round(v * 1e6) / 1e6).toFixed(6); 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 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 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; }; const short = (s, n=14) => { s = String(s); return s.length > n ? s.slice(0, 6) + "…" + s.slice(-5) : s; };
function modelAliasKey(value) { function modelAliasKey(value) {
@@ -1114,12 +1115,8 @@ function findRoutingForModel(model, routing) {
return null; return null;
} }
function chatModelHealthLabel(coverage) { function chatModelHealthHp(servedCopies) {
if (coverage === null || coverage === undefined) return "unknown"; return hp(servedCopies);
const pct = Math.round(Number(coverage));
if (pct >= 100) return "healthy";
if (pct > 0) return `${pct}% cov`;
return "no coverage";
} }
function chatModelTypicalTps(model, routing) { function chatModelTypicalTps(model, routing) {
@@ -1136,7 +1133,7 @@ function chatModelOptionLabel(model, routing) {
const base = model.name && model.name !== model.id const base = model.name && model.name !== model.id
? `${model.name} (${model.id})` ? `${model.name} (${model.id})`
: model.id; : model.id;
const health = chatModelHealthLabel(model.coverage); const health = chatModelHealthHp(model.servedCopies);
const speed = chatModelTypicalTps(model, routing); const speed = chatModelTypicalTps(model, routing);
const speedText = speed === null ? "?" : `${tps(speed)} tok/s`; const speedText = speed === null ? "?" : `${tps(speed)} tok/s`;
const suffix = model.recommended ? " · recommended" : ""; const suffix = model.recommended ? " · recommended" : "";
@@ -1644,6 +1641,7 @@ async function refresh() {
recommended: Boolean(model.recommended), recommended: Boolean(model.recommended),
aliases: model.aliases || [], aliases: model.aliases || [],
coverage: model.shard_coverage_percentage, coverage: model.shard_coverage_percentage,
servedCopies: model.served_model_copies,
})).filter(model => model.id); })).filter(model => model.id);
renderHive(raft); renderHive(raft);
renderNodes(map); renderNodes(map);

View File

@@ -2729,6 +2729,11 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
required_start, required_start,
required_end, required_end,
) )
served_copies = _served_model_copies(
model_nodes,
required_start,
required_end,
)
aliases = [name] aliases = [name]
hf_repo = preset.get("hf_repo") hf_repo = preset.get("hf_repo")
if hf_repo and hf_repo not in aliases: if hf_repo and hf_repo not in aliases:
@@ -2748,6 +2753,7 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
"recommended": bool(preset.get("recommended", False)), "recommended": bool(preset.get("recommended", False)),
"deployment": _deployment_summary(alive, preset), "deployment": _deployment_summary(alive, preset),
"shard_coverage_percentage": coverage, "shard_coverage_percentage": coverage,
"served_model_copies": served_copies,
}) })
seen_ids.add(name) seen_ids.add(name)
if hf_repo: 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]] aliases = [model_id, *[name for name in short_names if name != model_id]]
required_start = 0 required_start = 0
required_end = max(node.num_layers for node in model_nodes) - 1 required_end = max(node.num_layers for node in model_nodes) - 1
coverage = _coverage_percentage(
model_nodes,
required_start,
required_end,
)
data.append({ data.append({
"id": model_id, "id": model_id,
"object": "model", "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, "hf_repo": model_id if any(node.hf_repo == model_id for node in model_nodes) else None,
"aliases": aliases, "aliases": aliases,
"metadata": _model_metadata_from_nodes(model_nodes), "metadata": _model_metadata_from_nodes(model_nodes),
"shard_coverage_percentage": _coverage_percentage( "shard_coverage_percentage": coverage,
"served_model_copies": _served_model_copies(
model_nodes, model_nodes,
required_start, required_start,
required_end, required_end,

View File

@@ -62,11 +62,12 @@ def test_dashboard_chat_model_selector_shows_health_and_speed():
finally: finally:
tracker.stop() tracker.stop()
assert "chatModelHealthLabel" in html assert "chatModelHealthHp" in html
assert "chatModelTypicalTps" in html assert "chatModelTypicalTps" in html
assert "chatModelOptionLabel" in html assert "chatModelOptionLabel" in html
assert "findRoutingForModel" in html assert "findRoutingForModel" in html
assert "tok/s" 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(): def test_dashboard_chat_sessions_use_delegated_handlers():