Dashboard: 'Popular in the co-op' model leaderboard (ranked bars, aggregate requests)

This commit is contained in:
inference-bot committed 2026-10-01 15:38:11 -06:00
1 parent 112e9ca1fc
commit d09bc8a9c6
1 file changed
+52
+52
View File
@@ -122,6 +122,12 @@ async def api_usage(request: Request):
data = await broker_get(identity, "/broker/usage")
keys = await broker_get(identity, "/broker/keys")
data["keys"] = keys.get("keys", [])
# Co-op-wide model popularity (aggregate, anonymized) for the leaderboard.
try:
board = await broker_get(identity, "/broker/model-leaderboard")
data["coop_models"] = board.get("models", [])
except HTTPException:
data["coop_models"] = [] # best-effort; never block the main view
return data
except HTTPException as e:
return JSONResponse({"error": e.detail}, status_code=e.status_code)
@@ -318,6 +324,24 @@ PAGE_HTML = """<!DOCTYPE html>
.model-name { font-weight: 600; font-size: 13px; }
.model-sub { color: var(--muted); font-size: 12px; }
.model-spend { font-size: 13px; font-weight: 600; color: var(--ink); text-align: right; }
/* Leaderboard */
.board-row {
display: flex; align-items: flex-start; gap: 14px;
padding: 12px 0; border-top: 1px solid #f0ede6;
}
.board-rank {
width: 26px; height: 26px; border-radius: 50%;
background: #eaf3ea; color: #2f5c30; font-weight: 700; font-size: 13px;
display: flex; align-items: center; justify-content: center; flex-shrink: 0;
margin-top: 2px;
}
.board-row:first-child .board-rank { background: var(--green-deep); color: #fff; }
.board-main { flex: 1; min-width: 0; }
.board-name { font-weight: 600; font-size: 13px; margin-bottom: 5px; }
.board-bar { height: 6px; background: #eef0ea; border-radius: 4px; overflow: hidden; }
.board-fill { height: 100%; background: var(--green-mid); border-radius: 4px; }
.board-sub { color: var(--muted); font-size: 11px; margin-top: 4px; }
.keys { margin-top: 8px; }
.key-row {
display: flex; align-items: center; justify-content: space-between; gap: 12px;
@@ -461,6 +485,12 @@ PAGE_HTML = """<!DOCTYPE html>
<div class="models" id="models"></div>
</div>
<div class="card">
<h2>Popular in the co-op</h2>
<p class="hint">Which models members are using most, across the whole co-op. A starting point when choosing one.</p>
<div class="board" id="coop-board"></div>
</div>
<div class="card">
<h2>API keys</h2>
<p class="hint">Keys let you use the co-op's AI from your own tools. They draw from the same balance as chat.</p>
@@ -538,6 +568,7 @@ async function load() {
$('calls').textContent = calls.toLocaleString();
renderModels(d.models || []);
renderBoard(d.coop_models || []);
renderKeys(d.keys || []);
} catch (e) {
flash('Could not load usage: ' + e.message, false);
@@ -557,6 +588,27 @@ function renderModels(models) {
}).join('');
}
function renderBoard(models) {
const el = $('coop-board');
if (!models.length) {
el.innerHTML = '<div class="empty">Not enough usage data yet — check back soon.</div>';
return;
}
// Rank bar widths are relative to the top model's request count.
const top = Math.max(...models.map(m => m.requests || 0), 1);
el.innerHTML = models.map((m, i) => {
const pct = Math.round(((m.requests || 0) / top) * 100);
return '<div class="board-row">' +
'<div class="board-rank">' + (i + 1) + '</div>' +
'<div class="board-main">' +
'<div class="board-name">' + escapeHtml(m.model) + '</div>' +
'<div class="board-bar"><div class="board-fill" style="width:' + pct + '%"></div></div>' +
'<div class="board-sub">' + (m.requests || 0).toLocaleString() + ' requests by members</div>' +
'</div>' +
'</div>';
}).join('');
}
function renderKeys(keys) {
const el = $('keys');
if (!keys.length) {