Files
llmgw/internal/web/templates/admin_usage.html
T
Ilker ManapandClaude Opus 5.5 11231d8c2b The portal in English and Turkish: a catalogue per language, a switcher at the foot of every page, landing.language, Turkish numbers and dates
Every template and handler message in internal/web goes through a JSON
catalogue under internal/web/locales/<code>/, with English as the fallback.
The language is the person's choice (a cookie set by /_lang/{code}), else
Accept-Language, else landing.language. Tests refuse a key some language
lacks, a translation with other arguments than English, and template text
left in English.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-05 00:12:53 +02:00

88 lines
3.7 KiB
HTML

{{/* The usage tab of the people page. */}}
{{define "usage_body"}}
{{if .Error}}<p class="error">{{.Error}}</p>{{end}}
{{/* One row of controls above the charts, which is where a reader looks for
them. Links rather than a script: the choice is in the URL, so a view worth
coming back to can be bookmarked or pasted to somebody else. */}}
<div class="filters">
<span class="filter-label">{{t "usage.group_by"}}</span>
{{range .Groups}}<a class="chip{{if .Selected}} on{{end}}"
href="/admin/usage?by={{.Key}}&amp;window={{$.Window}}">{{.Label}}</a>{{end}}
<span class="filter-label">{{t "usage.window"}}</span>
{{range .Windows}}<a class="chip{{if .Selected}} on{{end}}"
href="/admin/usage?by={{$.By}}&amp;window={{.Key}}">{{.Label}}</a>{{end}}
</div>
<div class="chart-row">
{{template "tschart" dict "t" .Requests "title" (t "usage.requests")
"note" (t "usage.requests_note")}}
{{template "tschart" dict "t" .Tokens "title" (t "usage.tokens")
"note" (t "usage.tokens_note")}}
</div>
<div class="chart-row">
{{if .Priced}}
{{template "tschart" dict "t" .Spend "title" (t "usage.spend")
"note" (t "usage.spend_note")}}
{{else}}
{{/* Said rather than drawn. A spend chart flat along the bottom reads as a
quiet month, and this is not that. */}}
<div class="chart-wrap">
<h3 class="chart-title">{{t "usage.spend"}}</h3>
<p class="empty">{{th "usage.unpriced"}}</p>
</div>
{{end}}
</div>
{{if .Rows}}
<table class="rows">
<tr><th>{{t "usage.col.group"}}</th><th class="num">{{t "usage.requests"}}</th><th class="num">{{t "usage.tokens"}}</th><th class="num">{{t "usage.spend"}}</th><th class="num">{{t "usage.errors"}}</th>
{{if .HasStats}}<th class="num" title="{{t "usage.col.error_rate_title"}}">{{t "usage.col.error_rate"}}</th>
<th class="num" title="{{t "usage.col.limited_title"}}">{{t "usage.col.limited"}}</th>
<th class="num" title="{{t "usage.col.ttft_title"}}">{{t "usage.col.ttft"}}</th>
<th class="num">{{t "usage.col.latency"}}</th>{{end}}</tr>
{{range .Rows}}
<tr>
<td>{{.Name}}</td>
<td class="num">{{compact .Requests}}</td>
<td class="num">{{compact .Tokens}}</td>
<td class="num">{{.Spend}}</td>
<td class="num">{{if .Errors}}{{count .Errors}}{{else}}—{{end}}</td>
{{if $.HasStats}}{{with .Stats}}
<td class="num{{if ge .ErrorRate 5.0}} q-warn{{end}}">{{if .Requests}}{{t "usage.pct" (pct1 .ErrorRate)}}{{else}}—{{end}}</td>
<td class="num{{if .Limited}} q-warn{{end}}">{{if .Limited}}{{compact .Limited}}{{else}}—{{end}}</td>
<td class="num">{{pctile .TTFT 50}} / {{pctile .TTFT 95}}</td>
<td class="num">{{pctile .Latency 95}}</td>{{end}}{{end}}
</tr>
{{end}}
</table>
{{else}}
<p class="empty">{{t "usage.empty"}}</p>
{{end}}
{{with .GPUHours}}
<h2>{{t "usage.gpu.title"}}</h2>
{{/* What each owner's models held, whether or not anybody asked them
anything: a model kept loaded holds its cards all the same, and that is
the time a GPU quota is about. */}}
<div class="chart-row">
{{template "tschart" dict "t" $.GPUHeld "title" (t "usage.gpu.chart") "note" (t "usage.gpu.chart_note")}}
</div>
<table class="rows">
<tr><th>{{t "usage.col.owner"}}</th><th class="num">{{t "usage.col.gpu_hours"}}</th><th class="num">{{t "usage.col.held_now"}}</th></tr>
{{range .}}<tr><td>{{.Owner}}</td><td class="num">{{num .Hours 1}}</td><td class="num">{{num .Now 0}}</td></tr>{{end}}
</table>
<p class="note">{{t "usage.gpu.note"}}</p>
{{end}}
{{/* The charts fold their tail; the table does not. Both are here because they
answer different questions, and the one that is easy to get wrong is
thinking the four coloured lines are all of it. */}}
<p class="note">{{t "usage.note.charts"}}</p>
<p class="note">{{th "usage.note.person"}}</p>
{{end}}