feat(platform/admin): enhance cost dashboard with token breakdown and per-request averages

Add deeper cost visibility to the admin platform cost dashboard:
- Show prompt vs completion tokens separately in provider table
- Add summary cards for avg cost/request, avg input/output tokens, total token split
- Add avg cost per request column to the per-user table
- Compute aggregate token totals and per-request averages in backend
This commit is contained in:
majdyz
2026-04-12 23:51:04 +00:00
parent b319c26cab
commit 2084e6e06e
5 changed files with 92 additions and 6 deletions

View File

@@ -167,6 +167,11 @@ class PlatformCostDashboard(BaseModel):
total_cost_microdollars: int
total_requests: int
total_users: int
total_input_tokens: int = 0
total_output_tokens: int = 0
avg_input_tokens_per_request: float = 0.0
avg_output_tokens_per_request: float = 0.0
avg_cost_microdollars_per_request: float = 0.0
def _si(row: dict, field: str) -> int:
@@ -293,7 +298,11 @@ async def get_platform_cost_dashboard(
PrismaLog.prisma().group_by(
by=["provider"],
where=where,
sum={"costMicrodollars": True},
sum={
"costMicrodollars": True,
"inputTokens": True,
"outputTokens": True,
},
count=True,
),
)
@@ -322,6 +331,8 @@ async def get_platform_cost_dashboard(
# Grand totals — sum across all provider groups (no LIMIT applied above).
total_cost = sum(_si(r, "costMicrodollars") for r in total_agg_groups)
total_requests = sum(_ca(r) for r in total_agg_groups)
total_input_tokens = sum(_si(r, "inputTokens") for r in total_agg_groups)
total_output_tokens = sum(_si(r, "outputTokens") for r in total_agg_groups)
return PlatformCostDashboard(
by_provider=[
@@ -354,6 +365,17 @@ async def get_platform_cost_dashboard(
total_cost_microdollars=total_cost,
total_requests=total_requests,
total_users=total_users,
total_input_tokens=total_input_tokens,
total_output_tokens=total_output_tokens,
avg_input_tokens_per_request=(
total_input_tokens / total_requests if total_requests > 0 else 0.0
),
avg_output_tokens_per_request=(
total_output_tokens / total_requests if total_requests > 0 else 0.0
),
avg_cost_microdollars_per_request=(
total_cost / total_requests if total_requests > 0 else 0.0
),
)

View File

@@ -2,7 +2,7 @@
import { Alert, AlertDescription } from "@/components/molecules/Alert/Alert";
import { Skeleton } from "@/components/atoms/Skeleton/Skeleton";
import { formatMicrodollars } from "../helpers";
import { formatMicrodollars, formatTokens } from "../helpers";
import { SummaryCard } from "./SummaryCard";
import { ProviderTable } from "./ProviderTable";
import { UserTable } from "./UserTable";
@@ -215,7 +215,7 @@ export function PlatformCostContent({ searchParams }: Props) {
) : (
<>
{dashboard && (
<div className="grid grid-cols-2 gap-4 md:grid-cols-4">
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4">
<SummaryCard
label="Known Cost"
value={formatMicrodollars(dashboard.total_cost_microdollars)}
@@ -234,6 +234,36 @@ export function PlatformCostContent({ searchParams }: Props) {
label="Active Users"
value={dashboard.total_users.toLocaleString()}
/>
<SummaryCard
label="Avg Cost / Request"
value={
dashboard.avg_cost_microdollars_per_request
? formatMicrodollars(
dashboard.avg_cost_microdollars_per_request,
)
: "$0.00"
}
subtitle="Known cost divided by total requests"
/>
<SummaryCard
label="Avg Input Tokens"
value={Math.round(
dashboard.avg_input_tokens_per_request ?? 0,
).toLocaleString()}
subtitle="Prompt tokens per request (context size)"
/>
<SummaryCard
label="Avg Output Tokens"
value={Math.round(
dashboard.avg_output_tokens_per_request ?? 0,
).toLocaleString()}
subtitle="Completion tokens per request (response length)"
/>
<SummaryCard
label="Total Tokens"
value={`${formatTokens(dashboard.total_input_tokens ?? 0)} in / ${formatTokens(dashboard.total_output_tokens ?? 0)} out`}
subtitle="Prompt vs completion token split"
/>
</div>
)}

View File

@@ -3,6 +3,7 @@ import {
defaultRateFor,
estimateCostForRow,
formatMicrodollars,
formatTokens,
rateKey,
rateUnitLabel,
trackingValue,
@@ -33,6 +34,12 @@ function ProviderTable({ data, rateOverrides, onRateOverride }: Props) {
<th scope="col" className="px-4 py-3 text-right">
Usage
</th>
<th scope="col" className="px-4 py-3 text-right">
Input Tokens
</th>
<th scope="col" className="px-4 py-3 text-right">
Output Tokens
</th>
<th scope="col" className="px-4 py-3 text-right">
Requests
</th>
@@ -74,6 +81,16 @@ function ProviderTable({ data, rateOverrides, onRateOverride }: Props) {
<TrackingBadge trackingType={row.tracking_type} />
</td>
<td className="px-4 py-3 text-right">{trackingValue(row)}</td>
<td className="px-4 py-3 text-right">
{row.total_input_tokens > 0
? formatTokens(row.total_input_tokens)
: "-"}
</td>
<td className="px-4 py-3 text-right">
{row.total_output_tokens > 0
? formatTokens(row.total_output_tokens)
: "-"}
</td>
<td className="px-4 py-3 text-right">
{row.request_count.toLocaleString()}
</td>
@@ -124,7 +141,7 @@ function ProviderTable({ data, rateOverrides, onRateOverride }: Props) {
{data.length === 0 && (
<tr>
<td
colSpan={8}
colSpan={10}
className="px-4 py-8 text-center text-muted-foreground"
>
No cost data yet

View File

@@ -26,6 +26,9 @@ function UserTable({ data }: Props) {
<th scope="col" className="px-4 py-3 text-right">
Output Tokens
</th>
<th scope="col" className="px-4 py-3 text-right">
Avg Cost / Req
</th>
</tr>
</thead>
<tbody>
@@ -54,12 +57,21 @@ function UserTable({ data }: Props) {
<td className="px-4 py-3 text-right">
{formatTokens(row.total_output_tokens)}
</td>
<td className="px-4 py-3 text-right">
{row.request_count > 0 && row.total_cost_microdollars > 0
? formatMicrodollars(
Math.round(
row.total_cost_microdollars / row.request_count,
),
)
: "-"}
</td>
</tr>
))}
{data.length === 0 && (
<tr>
<td
colSpan={5}
colSpan={6}
className="px-4 py-8 text-center text-muted-foreground"
>
No cost data yet

View File

@@ -12141,7 +12141,12 @@
"title": "Total Cost Microdollars"
},
"total_requests": { "type": "integer", "title": "Total Requests" },
"total_users": { "type": "integer", "title": "Total Users" }
"total_users": { "type": "integer", "title": "Total Users" },
"total_input_tokens": { "type": "integer", "title": "Total Input Tokens", "default": 0 },
"total_output_tokens": { "type": "integer", "title": "Total Output Tokens", "default": 0 },
"avg_input_tokens_per_request": { "type": "number", "title": "Avg Input Tokens Per Request", "default": 0.0 },
"avg_output_tokens_per_request": { "type": "number", "title": "Avg Output Tokens Per Request", "default": 0.0 },
"avg_cost_microdollars_per_request": { "type": "number", "title": "Avg Cost Microdollars Per Request", "default": 0.0 }
},
"type": "object",
"required": [