mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
Memoize expensive computations in UsagePageView to prevent unnecessary recalculations on every render
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
08bb3808bc
commit
13c0741262
1 changed files with 39 additions and 39 deletions
|
|
@ -176,7 +176,7 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
const totalSpend = userSpendData.metadata?.total_spend || 0;
|
||||
|
||||
// Calculate top models from the breakdown data
|
||||
const getTopModels = (limit: number = 5) => {
|
||||
const topModels = useMemo(() => {
|
||||
const modelSpend: { [key: string]: MetricWithMetadata } = {};
|
||||
userSpendData.results.forEach((day) => {
|
||||
Object.entries(day.breakdown.models || {}).forEach(([model, metrics]) => {
|
||||
|
|
@ -219,10 +219,10 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
tokens: metrics.metrics.total_tokens,
|
||||
}))
|
||||
.sort((a, b) => b.spend - a.spend)
|
||||
.slice(0, limit);
|
||||
};
|
||||
.slice(0, topModelsLimit);
|
||||
}, [userSpendData.results, topModelsLimit]);
|
||||
|
||||
const getTopModelGroups = (limit: number = 5) => {
|
||||
const topModelGroups = useMemo(() => {
|
||||
const modelGroupSpend: { [key: string]: MetricWithMetadata } = {};
|
||||
userSpendData.results.forEach((day) => {
|
||||
Object.entries(day.breakdown.model_groups || {}).forEach(([modelGroup, metrics]) => {
|
||||
|
|
@ -266,16 +266,16 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
tokens: metrics.metrics.total_tokens,
|
||||
}))
|
||||
.sort((a, b) => b.spend - a.spend)
|
||||
.slice(0, limit);
|
||||
};
|
||||
.slice(0, topModelsLimit);
|
||||
}, [userSpendData.results, topModelsLimit]);
|
||||
|
||||
// Calculate provider spend from the breakdown data
|
||||
const getProviderSpend = () => {
|
||||
const providerSpend: { [key: string]: MetricWithMetadata } = {};
|
||||
const providerSpend = useMemo(() => {
|
||||
const providerSpendMap: { [key: string]: MetricWithMetadata } = {};
|
||||
userSpendData.results.forEach((day) => {
|
||||
Object.entries(day.breakdown.providers || {}).forEach(([provider, metrics]) => {
|
||||
if (!providerSpend[provider]) {
|
||||
providerSpend[provider] = {
|
||||
if (!providerSpendMap[provider]) {
|
||||
providerSpendMap[provider] = {
|
||||
metrics: {
|
||||
spend: 0,
|
||||
prompt_tokens: 0,
|
||||
|
|
@ -291,19 +291,19 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
api_key_breakdown: {},
|
||||
};
|
||||
}
|
||||
providerSpend[provider].metrics.spend += metrics.metrics.spend;
|
||||
providerSpend[provider].metrics.prompt_tokens += metrics.metrics.prompt_tokens;
|
||||
providerSpend[provider].metrics.completion_tokens += metrics.metrics.completion_tokens;
|
||||
providerSpend[provider].metrics.total_tokens += metrics.metrics.total_tokens;
|
||||
providerSpend[provider].metrics.api_requests += metrics.metrics.api_requests;
|
||||
providerSpend[provider].metrics.successful_requests += metrics.metrics.successful_requests || 0;
|
||||
providerSpend[provider].metrics.failed_requests += metrics.metrics.failed_requests || 0;
|
||||
providerSpend[provider].metrics.cache_read_input_tokens += metrics.metrics.cache_read_input_tokens || 0;
|
||||
providerSpend[provider].metrics.cache_creation_input_tokens += metrics.metrics.cache_creation_input_tokens || 0;
|
||||
providerSpendMap[provider].metrics.spend += metrics.metrics.spend;
|
||||
providerSpendMap[provider].metrics.prompt_tokens += metrics.metrics.prompt_tokens;
|
||||
providerSpendMap[provider].metrics.completion_tokens += metrics.metrics.completion_tokens;
|
||||
providerSpendMap[provider].metrics.total_tokens += metrics.metrics.total_tokens;
|
||||
providerSpendMap[provider].metrics.api_requests += metrics.metrics.api_requests;
|
||||
providerSpendMap[provider].metrics.successful_requests += metrics.metrics.successful_requests || 0;
|
||||
providerSpendMap[provider].metrics.failed_requests += metrics.metrics.failed_requests || 0;
|
||||
providerSpendMap[provider].metrics.cache_read_input_tokens += metrics.metrics.cache_read_input_tokens || 0;
|
||||
providerSpendMap[provider].metrics.cache_creation_input_tokens += metrics.metrics.cache_creation_input_tokens || 0;
|
||||
});
|
||||
});
|
||||
|
||||
return Object.entries(providerSpend).map(([provider, metrics]) => ({
|
||||
return Object.entries(providerSpendMap).map(([provider, metrics]) => ({
|
||||
provider,
|
||||
spend: metrics.metrics.spend,
|
||||
requests: metrics.metrics.api_requests,
|
||||
|
|
@ -311,10 +311,10 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
failed_requests: metrics.metrics.failed_requests,
|
||||
tokens: metrics.metrics.total_tokens,
|
||||
}));
|
||||
};
|
||||
}, [userSpendData.results]);
|
||||
|
||||
// Calculate top API keys from the breakdown data
|
||||
const getTopKeys = (limit: number = 5) => {
|
||||
const topKeys = useMemo(() => {
|
||||
const keySpend: { [key: string]: KeyMetricWithMetadata } = {};
|
||||
userSpendData.results.forEach((day) => {
|
||||
Object.entries(day.breakdown.api_keys || {}).forEach(([key, metrics]) => {
|
||||
|
|
@ -334,7 +334,7 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
metadata: {
|
||||
key_alias: metrics.metadata.key_alias,
|
||||
team_id: null,
|
||||
tags: metrics.metadata.tags || [], // This gets key-level tags
|
||||
tags: metrics.metadata.tags || [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -350,18 +350,16 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
});
|
||||
});
|
||||
|
||||
console.log("debugTags", { keySpend, userSpendData });
|
||||
|
||||
return Object.entries(keySpend)
|
||||
.map(([api_key, metrics]) => ({
|
||||
api_key,
|
||||
key_alias: metrics.metadata.key_alias || "-", // Using truncated key as alias
|
||||
tags: metrics.metadata.tags || [], // This will show key-level tags
|
||||
key_alias: metrics.metadata.key_alias || "-",
|
||||
tags: metrics.metadata.tags || [],
|
||||
spend: metrics.metrics.spend,
|
||||
}))
|
||||
.sort((a, b) => b.spend - a.spend)
|
||||
.slice(0, limit);
|
||||
};
|
||||
.slice(0, topKeysLimit);
|
||||
}, [userSpendData.results, topKeysLimit]);
|
||||
|
||||
const fetchUserSpendData = useCallback(async () => {
|
||||
if (!accessToken || !dateValue.from || !dateValue.to) return;
|
||||
|
|
@ -440,9 +438,13 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
return () => clearTimeout(timeoutId);
|
||||
}, [fetchUserSpendData]);
|
||||
|
||||
const modelMetrics = processActivityData(userSpendData, "models", teams);
|
||||
const keyMetrics = processActivityData(userSpendData, "api_keys", teams);
|
||||
const mcpServerMetrics = processActivityData(userSpendData, "mcp_servers", teams);
|
||||
const sortedDailyResults = useMemo(
|
||||
() => [...userSpendData.results].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()),
|
||||
[userSpendData.results],
|
||||
);
|
||||
const modelMetrics = useMemo(() => processActivityData(userSpendData, "models", teams), [userSpendData, teams]);
|
||||
const keyMetrics = useMemo(() => processActivityData(userSpendData, "api_keys", teams), [userSpendData, teams]);
|
||||
const mcpServerMetrics = useMemo(() => processActivityData(userSpendData, "mcp_servers", teams), [userSpendData, teams]);
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%" }} className="p-8 relative">
|
||||
|
|
@ -654,9 +656,7 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
<ChartLoader isDateChanging={isDateChanging} />
|
||||
) : (
|
||||
<BarChart
|
||||
data={[...userSpendData.results].sort(
|
||||
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),
|
||||
)}
|
||||
data={sortedDailyResults}
|
||||
index="date"
|
||||
categories={["metrics.spend"]}
|
||||
colors={["cyan"]}
|
||||
|
|
@ -688,7 +688,7 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
<Card className="h-full">
|
||||
<Title>Top Virtual Keys</Title>
|
||||
<TopKeyView
|
||||
topKeys={getTopKeys(topKeysLimit)}
|
||||
topKeys={topKeys}
|
||||
teams={null}
|
||||
topKeysLimit={topKeysLimit}
|
||||
setTopKeysLimit={setTopKeysLimit}
|
||||
|
|
@ -739,8 +739,8 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
{(() => {
|
||||
const modelData =
|
||||
modelViewType === "groups"
|
||||
? getTopModelGroups(topModelsLimit)
|
||||
: getTopModels(topModelsLimit);
|
||||
? topModelGroups
|
||||
: topModels;
|
||||
return (
|
||||
<BarChart
|
||||
className="mt-4"
|
||||
|
|
@ -784,7 +784,7 @@ const UsagePage: React.FC<UsagePageProps> = ({ teams, organizations }) => {
|
|||
<SpendByProvider
|
||||
loading={loading}
|
||||
isDateChanging={isDateChanging}
|
||||
providerSpend={getProviderSpend()}
|
||||
providerSpend={providerSpend}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue