import React from 'react'; import { Card, Grid, Text, Title, Accordion, AccordionHeader, AccordionBody } from '@tremor/react'; import { AreaChart, BarChart } from '@tremor/react'; import { SpendMetrics, DailyData, ModelActivityData, MetricWithMetadata, KeyMetricWithMetadata } from './usage/types'; import { Collapse } from 'antd'; interface ActivityMetricsProps { modelMetrics: Record; } const ModelSection = ({ modelName, metrics }: { modelName: string; metrics: ModelActivityData }) => { return (
{/* Summary Cards */} Total Requests {metrics.total_requests.toLocaleString()} Total Successful Requests {metrics.total_successful_requests.toLocaleString()} Total Tokens {metrics.total_tokens.toLocaleString()} {Math.round(metrics.total_tokens / metrics.total_successful_requests)} avg per successful request Total Spend ${metrics.total_spend.toFixed(2)} ${(metrics.total_spend / metrics.total_successful_requests).toFixed(3)} per successful request {/* Charts */} Total Tokens number.toLocaleString()} /> Requests per day number.toLocaleString()} /> Spend per day `$${value.toFixed(2)}`} /> Success vs Failed Requests number.toLocaleString()} stack /> Prompt Caching Metrics
Cache Read: {metrics.total_cache_read_input_tokens?.toLocaleString() || 0} tokens Cache Creation: {metrics.total_cache_creation_input_tokens?.toLocaleString() || 0} tokens
number.toLocaleString()} />
); }; export const ActivityMetrics: React.FC = ({ modelMetrics }) => { const modelNames = Object.keys(modelMetrics).sort((a, b) => { if (a === '') return 1; if (b === '') return -1; return modelMetrics[b].total_spend - modelMetrics[a].total_spend; }); // Calculate total metrics across all models const totalMetrics = { total_requests: 0, total_successful_requests: 0, total_tokens: 0, total_spend: 0, total_cache_read_input_tokens: 0, total_cache_creation_input_tokens: 0, daily_data: {} as Record }; // Aggregate data Object.values(modelMetrics).forEach(model => { totalMetrics.total_requests += model.total_requests; totalMetrics.total_successful_requests += model.total_successful_requests; totalMetrics.total_tokens += model.total_tokens; totalMetrics.total_spend += model.total_spend; totalMetrics.total_cache_read_input_tokens += model.total_cache_read_input_tokens || 0; totalMetrics.total_cache_creation_input_tokens += model.total_cache_creation_input_tokens || 0; // Aggregate daily data model.daily_data.forEach(day => { if (!totalMetrics.daily_data[day.date]) { totalMetrics.daily_data[day.date] = { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0, api_requests: 0, spend: 0, successful_requests: 0, failed_requests: 0, cache_read_input_tokens: 0, cache_creation_input_tokens: 0 }; } totalMetrics.daily_data[day.date].prompt_tokens += day.metrics.prompt_tokens; totalMetrics.daily_data[day.date].completion_tokens += day.metrics.completion_tokens; totalMetrics.daily_data[day.date].total_tokens += day.metrics.total_tokens; totalMetrics.daily_data[day.date].api_requests += day.metrics.api_requests; totalMetrics.daily_data[day.date].spend += day.metrics.spend; totalMetrics.daily_data[day.date].successful_requests += day.metrics.successful_requests; totalMetrics.daily_data[day.date].failed_requests += day.metrics.failed_requests; totalMetrics.daily_data[day.date].cache_read_input_tokens += day.metrics.cache_read_input_tokens || 0; totalMetrics.daily_data[day.date].cache_creation_input_tokens += day.metrics.cache_creation_input_tokens || 0; }); }); // Convert daily_data object to array and sort by date const sortedDailyData = Object.entries(totalMetrics.daily_data) .map(([date, metrics]) => ({ date, metrics })) .sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); return (
{/* Global Summary */}
Overall Usage Total Requests {totalMetrics.total_requests.toLocaleString()} Total Successful Requests {totalMetrics.total_successful_requests.toLocaleString()} Total Tokens {totalMetrics.total_tokens.toLocaleString()} Total Spend ${totalMetrics.total_spend.toFixed(2)} Total Tokens Over Time number.toLocaleString()} /> Total Requests Over Time number.toLocaleString()} stack />
{/* Individual Model Sections */} {modelNames.map((modelName) => ( {modelMetrics[modelName].label || 'Unknown Item'}
${modelMetrics[modelName].total_spend.toFixed(2)} {modelMetrics[modelName].total_requests.toLocaleString()} requests
} > ))} ); }; // Helper function to format key label const formatKeyLabel = (modelData: KeyMetricWithMetadata, model: string): string => { const keyAlias = modelData.metadata.key_alias || `key-hash-${model}`; const teamId = modelData.metadata.team_id; return teamId ? `${keyAlias} (team_id: ${teamId})` : keyAlias; }; // Process data function export const processActivityData = (dailyActivity: { results: DailyData[] }, key: "models" | "api_keys"): Record => { const modelMetrics: Record = {}; dailyActivity.results.forEach((day) => { Object.entries(day.breakdown[key] || {}).forEach(([model, modelData]) => { if (!modelMetrics[model]) { modelMetrics[model] = { label: key === 'api_keys' ? formatKeyLabel(modelData as KeyMetricWithMetadata, model) : model, total_requests: 0, total_successful_requests: 0, total_failed_requests: 0, total_tokens: 0, prompt_tokens: 0, completion_tokens: 0, total_spend: 0, total_cache_read_input_tokens: 0, total_cache_creation_input_tokens: 0, daily_data: [] }; } // Update totals modelMetrics[model].total_requests += modelData.metrics.api_requests; modelMetrics[model].prompt_tokens += modelData.metrics.prompt_tokens; modelMetrics[model].completion_tokens += modelData.metrics.completion_tokens; modelMetrics[model].total_tokens += modelData.metrics.total_tokens; modelMetrics[model].total_spend += modelData.metrics.spend; modelMetrics[model].total_successful_requests += modelData.metrics.successful_requests; modelMetrics[model].total_failed_requests += modelData.metrics.failed_requests; modelMetrics[model].total_cache_read_input_tokens += modelData.metrics.cache_read_input_tokens || 0; modelMetrics[model].total_cache_creation_input_tokens += modelData.metrics.cache_creation_input_tokens || 0; // Add daily data modelMetrics[model].daily_data.push({ date: day.date, metrics: { prompt_tokens: modelData.metrics.prompt_tokens, completion_tokens: modelData.metrics.completion_tokens, total_tokens: modelData.metrics.total_tokens, api_requests: modelData.metrics.api_requests, spend: modelData.metrics.spend, successful_requests: modelData.metrics.successful_requests, failed_requests: modelData.metrics.failed_requests, cache_read_input_tokens: modelData.metrics.cache_read_input_tokens || 0, cache_creation_input_tokens: modelData.metrics.cache_creation_input_tokens || 0 } }); }); }); // Sort daily data Object.values(modelMetrics).forEach(metrics => { metrics.daily_data.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); }); return modelMetrics; };