diff --git a/src/components/usage/ModelStatsCard.tsx b/src/components/usage/ModelStatsCard.tsx index 57285e7..40b5cb0 100644 --- a/src/components/usage/ModelStatsCard.tsx +++ b/src/components/usage/ModelStatsCard.tsx @@ -19,9 +19,13 @@ export interface ModelStatsCardProps { hasPrices: boolean; } -type SortKey = 'model' | 'requests' | 'tokens' | 'cost'; +type SortKey = 'model' | 'requests' | 'tokens' | 'cost' | 'successRate'; type SortDir = 'asc' | 'desc'; +interface ModelStatWithRate extends ModelStat { + successRate: number; +} + export function ModelStatsCard({ modelStats, loading, hasPrices }: ModelStatsCardProps) { const { t } = useTranslation(); const [sortKey, setSortKey] = useState('requests'); @@ -36,8 +40,11 @@ export function ModelStatsCard({ modelStats, loading, hasPrices }: ModelStatsCar } }; - const sorted = useMemo(() => { - const list = [...modelStats]; + const sorted = useMemo((): ModelStatWithRate[] => { + const list: ModelStatWithRate[] = modelStats.map((s) => ({ + ...s, + successRate: s.requests > 0 ? (s.successCount / s.requests) * 100 : 100, + })); const dir = sortDir === 'asc' ? 1 : -1; list.sort((a, b) => { if (sortKey === 'model') return dir * a.model.localeCompare(b.model); @@ -67,6 +74,9 @@ export function ModelStatsCard({ modelStats, loading, hasPrices }: ModelStatsCar handleSort('tokens')}> {t('usage_stats.tokens_count')}{arrow('tokens')} + handleSort('successRate')}> + {t('usage_stats.success_rate')}{arrow('successRate')} + {hasPrices && ( handleSort('cost')}> {t('usage_stats.total_cost')}{arrow('cost')} @@ -88,6 +98,19 @@ export function ModelStatsCard({ modelStats, loading, hasPrices }: ModelStatsCar {formatTokensInMillions(stat.tokens)} + + = 95 + ? styles.statSuccess + : stat.successRate >= 80 + ? styles.statNeutral + : styles.statFailure + } + > + {stat.successRate.toFixed(1)}% + + {hasPrices && {stat.cost > 0 ? formatUsd(stat.cost) : '--'}} ))}