Add model-usage table to admin panel
This commit is contained in:
1 parent
6b4dcac7a1
commit
25568680b4
1 file changed
+45
+45
@@ -111,6 +111,16 @@ async def api_overview(request: Request):
|
|||||||
return await portal_get("/admin/overview")
|
return await portal_get("/admin/overview")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/api/model-usage")
|
||||||
|
async def api_model_usage(request: Request):
|
||||||
|
if not is_admin(request):
|
||||||
|
return JSONResponse({"error": "forbidden"}, status_code=403)
|
||||||
|
try:
|
||||||
|
return await portal_get("/admin/model-usage")
|
||||||
|
except HTTPException as e:
|
||||||
|
return JSONResponse({"error": e.detail}, status_code=e.status_code)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/set-balance")
|
@app.post("/api/set-balance")
|
||||||
async def api_set_balance(request: Request):
|
async def api_set_balance(request: Request):
|
||||||
if not is_admin(request):
|
if not is_admin(request):
|
||||||
@@ -257,6 +267,16 @@ PAGE_HTML = """<!DOCTYPE html>
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody id="rows"><tr><td colspan="8" style="color:var(--muted)">Loading…</td></tr></tbody>
|
<tbody id="rows"><tr><td colspan="8" style="color:var(--muted)">Loading…</td></tr></tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<h2 style="margin:28px 0 12px;font-size:17px;font-weight:700;">Model usage</h2>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Model</th><th>Spend</th><th>Tokens</th><th>Requests</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="model-rows"><tr><td colspan="4" style="color:var(--muted)">Loading…</td></tr></tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -271,6 +291,30 @@ function flash(msg, ok) {
|
|||||||
|
|
||||||
function fmt(n) { return '$' + (Number(n) || 0).toFixed(2); }
|
function fmt(n) { return '$' + (Number(n) || 0).toFixed(2); }
|
||||||
|
|
||||||
|
async function loadModels() {
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/model-usage');
|
||||||
|
if (r.status === 403) return;
|
||||||
|
const d = await r.json();
|
||||||
|
if (d.error) { $('model-rows').innerHTML = '<tr><td colspan="4" style="color:var(--muted)">' + esc(d.error) + '</td></tr>'; return; }
|
||||||
|
const models = d.models || [];
|
||||||
|
if (!models.length) {
|
||||||
|
$('model-rows').innerHTML = '<tr><td colspan="4" style="color:var(--muted)">No usage recorded.</td></tr>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$('model-rows').innerHTML = models.map(m =>
|
||||||
|
'<tr>' +
|
||||||
|
'<td>' + esc(m.model) + '</td>' +
|
||||||
|
'<td class="num">' + fmt(m.spend) + '</td>' +
|
||||||
|
'<td class="num">' + (m.tokens || 0).toLocaleString() + '</td>' +
|
||||||
|
'<td class="num">' + (m.requests || 0).toLocaleString() + '</td>' +
|
||||||
|
'</tr>'
|
||||||
|
).join('');
|
||||||
|
} catch (e) {
|
||||||
|
$('model-rows').innerHTML = '<tr><td colspan="4" style="color:var(--muted)">Could not load model usage.</td></tr>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
try {
|
try {
|
||||||
const r = await fetch('/api/overview');
|
const r = await fetch('/api/overview');
|
||||||
@@ -330,6 +374,7 @@ async function addBalance(email) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
load();
|
load();
|
||||||
|
loadModels();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>"""
|
</html>"""
|
||||||
|
|||||||
Reference in new issue
Block a user