mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): EndpointUsageTable to shadcn
- antd Table/Progress \u2192 shadcn Table/Progress. Success rate and success/fail counts use categorical emerald/amber/destructive palette (already in overrides from prior commits). - Progress bar simplified to a single success-percentage bar since Radix Progress doesn't support multi-stop strokeColor gradients. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
parent
fa9d5ae6d9
commit
d5df40b9c4
1 changed files with 103 additions and 98 deletions
|
|
@ -1,6 +1,14 @@
|
|||
import React from "react";
|
||||
import { Table, Progress } from "antd";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { formatNumberWithCommas } from "@/utils/dataUtils";
|
||||
import { MetricWithMetadata } from "../../../types";
|
||||
|
||||
|
|
@ -19,104 +27,101 @@ interface EndpointRow {
|
|||
successRate: number;
|
||||
}
|
||||
|
||||
const EndpointUsageTable: React.FC<EndpointUsageTableProps> = ({ endpointData }) => {
|
||||
const calculateSuccessRate = (successful: number, total: number): number => {
|
||||
if (total === 0) return 0;
|
||||
return (successful / total) * 100;
|
||||
};
|
||||
const calculateSuccessRate = (successful: number, total: number): number => {
|
||||
if (total === 0) return 0;
|
||||
return (successful / total) * 100;
|
||||
};
|
||||
|
||||
const dataSource: EndpointRow[] = Object.entries(endpointData).map(([endpoint, data]) => ({
|
||||
key: endpoint,
|
||||
endpoint,
|
||||
successful_requests: data.metrics.successful_requests,
|
||||
failed_requests: data.metrics.failed_requests,
|
||||
api_requests: data.metrics.api_requests,
|
||||
total_tokens: data.metrics.total_tokens,
|
||||
spend: data.metrics.spend,
|
||||
successRate: calculateSuccessRate(data.metrics.successful_requests, data.metrics.api_requests),
|
||||
}));
|
||||
const EndpointUsageTable: React.FC<EndpointUsageTableProps> = ({
|
||||
endpointData,
|
||||
}) => {
|
||||
const rows: EndpointRow[] = Object.entries(endpointData).map(
|
||||
([endpoint, data]) => ({
|
||||
key: endpoint,
|
||||
endpoint,
|
||||
successful_requests: data.metrics.successful_requests,
|
||||
failed_requests: data.metrics.failed_requests,
|
||||
api_requests: data.metrics.api_requests,
|
||||
total_tokens: data.metrics.total_tokens,
|
||||
spend: data.metrics.spend,
|
||||
successRate: calculateSuccessRate(
|
||||
data.metrics.successful_requests,
|
||||
data.metrics.api_requests,
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
const columns: ColumnsType<EndpointRow> = [
|
||||
{
|
||||
title: "Endpoint",
|
||||
dataIndex: "endpoint",
|
||||
key: "endpoint",
|
||||
render: (text: string) => <span className="font-medium">{text}</span>,
|
||||
},
|
||||
{
|
||||
title: "Successful / Failed",
|
||||
key: "requests",
|
||||
render: (_: any, record: EndpointRow) => {
|
||||
const successPercentage =
|
||||
record.api_requests > 0 ? (record.successful_requests / record.api_requests) * 100 : 0;
|
||||
const failurePercentage = record.api_requests > 0 ? (record.failed_requests / record.api_requests) * 100 : 0;
|
||||
const totalPercentage = successPercentage + failurePercentage;
|
||||
|
||||
const strokeColorConfig: Record<string, string> = {
|
||||
"0%": "#22c55e",
|
||||
};
|
||||
if (successPercentage > 0 && successPercentage < 100) {
|
||||
strokeColorConfig[`${successPercentage}%`] = "#22c55e";
|
||||
strokeColorConfig[`${successPercentage + 0.01}%`] = "#ef4444";
|
||||
}
|
||||
strokeColorConfig["100%"] = failurePercentage > 0 ? "#ef4444" : "#22c55e";
|
||||
|
||||
return (
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="flex-1 relative">
|
||||
<Progress percent={totalPercentage} size="small" strokeColor={strokeColorConfig} showInfo={false} />
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 text-sm min-w-[100px]">
|
||||
<span className="text-green-600 font-medium">{record.successful_requests.toLocaleString()}</span>
|
||||
<span className="text-gray-400">/</span>
|
||||
<span className="text-red-600 font-medium">{record.failed_requests.toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Total Request",
|
||||
dataIndex: "api_requests",
|
||||
key: "api_requests",
|
||||
render: (value: number) => value.toLocaleString(),
|
||||
},
|
||||
{
|
||||
title: "Success Rate",
|
||||
dataIndex: "successRate",
|
||||
key: "successRate",
|
||||
render: (value: number) => {
|
||||
const successRateStr = value.toFixed(2);
|
||||
return (
|
||||
<span
|
||||
className={
|
||||
value >= 95
|
||||
? "text-green-600 font-medium"
|
||||
: value >= 80
|
||||
? "text-yellow-600 font-medium"
|
||||
: "text-red-600 font-medium"
|
||||
}
|
||||
>
|
||||
{successRateStr}%
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Total Tokens",
|
||||
dataIndex: "total_tokens",
|
||||
key: "total_tokens",
|
||||
render: (value: number) => value.toLocaleString(),
|
||||
},
|
||||
{
|
||||
title: "Spend",
|
||||
dataIndex: "spend",
|
||||
key: "spend",
|
||||
render: (value: number) => `$${formatNumberWithCommas(value, 2)}`,
|
||||
},
|
||||
];
|
||||
|
||||
return <Table columns={columns} dataSource={dataSource} pagination={false} />;
|
||||
return (
|
||||
<div className="border border-border rounded-md overflow-hidden">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Endpoint</TableHead>
|
||||
<TableHead>Successful / Failed</TableHead>
|
||||
<TableHead>Total Request</TableHead>
|
||||
<TableHead>Success Rate</TableHead>
|
||||
<TableHead>Total Tokens</TableHead>
|
||||
<TableHead>Spend</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{rows.map((record) => {
|
||||
const successPercentage =
|
||||
record.api_requests > 0
|
||||
? (record.successful_requests / record.api_requests) * 100
|
||||
: 0;
|
||||
const successRateStr = record.successRate.toFixed(2);
|
||||
return (
|
||||
<TableRow key={record.key}>
|
||||
<TableCell className="font-medium">
|
||||
{record.endpoint}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="flex-1 relative">
|
||||
<Progress value={successPercentage} className="h-2" />
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 text-sm min-w-[100px]">
|
||||
<span className="text-emerald-600 dark:text-emerald-400 font-medium">
|
||||
{record.successful_requests.toLocaleString()}
|
||||
</span>
|
||||
<span className="text-muted-foreground">/</span>
|
||||
<span className="text-destructive font-medium">
|
||||
{record.failed_requests.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{record.api_requests.toLocaleString()}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<span
|
||||
className={cn(
|
||||
"font-medium",
|
||||
record.successRate >= 95
|
||||
? "text-emerald-600 dark:text-emerald-400"
|
||||
: record.successRate >= 80
|
||||
? "text-amber-600 dark:text-amber-400"
|
||||
: "text-destructive",
|
||||
)}
|
||||
>
|
||||
{successRateStr}%
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{record.total_tokens.toLocaleString()}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
${formatNumberWithCommas(record.spend, 2)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EndpointUsageTable;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue