'use client' import { trpc } from '@/lib/trpc/client' import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' import { Skeleton } from '@/components/ui/skeleton' import { Badge } from '@/components/ui/badge' import { Coins, Zap, TrendingUp, Activity, Brain, Filter, Users, Award, } from 'lucide-react' import { cn } from '@/lib/utils' const ACTION_ICONS: Record = { ASSIGNMENT: Users, FILTERING: Filter, AWARD_ELIGIBILITY: Award, MENTOR_MATCHING: Brain, } const ACTION_LABELS: Record = { ASSIGNMENT: 'Jury Assignment', FILTERING: 'Project Filtering', AWARD_ELIGIBILITY: 'Award Eligibility', MENTOR_MATCHING: 'Mentor Matching', } function StatCard({ label, value, subValue, icon: Icon, trend, }: { label: string value: string subValue?: string icon: typeof Zap trend?: 'up' | 'down' | 'neutral' }) { return (

{label}

{value}

{trend && trend !== 'neutral' && ( )}
{subValue && (

{subValue}

)}
) } function UsageBar({ label, value, maxValue, color, }: { label: string value: number maxValue: number color: string }) { const percentage = maxValue > 0 ? (value / maxValue) * 100 : 0 return (
{label} {value.toLocaleString()}
) } export function AIUsageCard() { const { data: monthCost, isLoading: monthLoading, } = trpc.settings.getAICurrentMonthCost.useQuery(undefined, { staleTime: 60 * 1000, // 1 minute }) const { data: stats, isLoading: statsLoading, } = trpc.settings.getAIUsageStats.useQuery({}, { staleTime: 60 * 1000, }) const { data: history, isLoading: historyLoading, } = trpc.settings.getAIUsageHistory.useQuery({ days: 30 }, { staleTime: 60 * 1000, }) const isLoading = monthLoading || statsLoading if (isLoading) { return ( AI Usage & Costs Loading usage data...
) } const hasUsage = monthCost && monthCost.requestCount > 0 const maxTokensByAction = stats?.byAction ? Math.max(...Object.values(stats.byAction).map((a) => a.tokens)) : 0 return ( AI Usage & Costs Token usage and estimated costs for AI features {/* Current month summary */}
{stats && ( )}
{/* Usage by action */} {hasUsage && stats?.byAction && Object.keys(stats.byAction).length > 0 && (

Usage by Feature

{Object.entries(stats.byAction) .sort(([, a], [, b]) => b.tokens - a.tokens) .map(([action, data]) => { const Icon = ACTION_ICONS[action] || Zap return (
{(data as { costFormatted?: string }).costFormatted}
) })}
)} {/* Usage by model */} {hasUsage && stats?.byModel && Object.keys(stats.byModel).length > 0 && (

Usage by Model

{Object.entries(stats.byModel) .sort(([, a], [, b]) => b.cost - a.cost) .map(([model, data]) => ( {model} {(data as { costFormatted?: string }).costFormatted} ))}
)} {/* Usage history mini chart */} {hasUsage && history && history.length > 0 && (

Last 30 Days

{(() => { const maxCost = Math.max(...history.map((d) => d.cost), 0.001) return history.slice(-30).map((day, i) => { const height = (day.cost / maxCost) * 100 return (
) }) })()}
{history[0]?.date} {history[history.length - 1]?.date}
)} {/* No usage message */} {!hasUsage && (

No AI usage yet

AI usage will be tracked when you use filtering, assignments, or other AI-powered features.

)} ) }