/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { useMemo } from 'react' import { useQuery } from '@tanstack/react-query' import { Gauge, HeartPulse, Timer } from 'lucide-react' import { useTranslation } from 'react-i18next' import { cn } from '@/lib/utils' import { Skeleton } from '@/components/ui/skeleton' import { getPerfMetricsSummary } from '@/features/performance-metrics/api' import { formatLatency, formatThroughput, formatUptimePct, } from '@/features/performance-metrics/lib/format' import type { PerfModelSummary } from '@/features/performance-metrics/types' const PERFORMANCE_WINDOW_HOURS = 24 const TOP_MODEL_LIMIT = 5 type WeightedMetric = 'avg_latency_ms' | 'avg_tps' | 'success_rate' function simpleAverage( rows: PerfModelSummary[], metric: WeightedMetric, isValid: (value: number) => boolean ): number { let total = 0 let count = 0 for (const row of rows) { const value = Number(row[metric]) if (!isValid(value)) continue total += value count++ } return count > 0 ? total / count : NaN } function rateTextClass(rate: number): string { if (!Number.isFinite(rate)) return 'text-muted-foreground' if (rate >= 99.9) return 'text-success' if (rate >= 99) return 'text-warning' return 'text-destructive' } function rateDotClass(rate: number): string { if (!Number.isFinite(rate)) return 'bg-muted-foreground' if (rate >= 99.9) return 'bg-success' if (rate >= 99) return 'bg-warning' return 'bg-destructive' } export function PerformanceHealthPanel() { const { t } = useTranslation() const metricsQuery = useQuery({ queryKey: ['perf-metrics-summary', PERFORMANCE_WINDOW_HOURS], queryFn: () => getPerfMetricsSummary(PERFORMANCE_WINDOW_HOURS), staleTime: 60 * 1000, retry: false, }) const models = useMemo( () => metricsQuery.data?.data.models ?? [], [metricsQuery.data] ) const summary = useMemo(() => { return { avgLatencyMs: Math.round( simpleAverage(models, 'avg_latency_ms', (v) => Number.isFinite(v) && v > 0) ), avgTps: simpleAverage(models, 'avg_tps', (v) => Number.isFinite(v) && v > 0), successRate: simpleAverage(models, 'success_rate', Number.isFinite), } }, [models]) const topModels = useMemo(() => models.slice(0, TOP_MODEL_LIMIT), [models]) const loading = metricsQuery.isLoading const hasData = models.length > 0 return (
{/* KPI metrics */}
{/* Top models */}
{t('Top models by traffic')} {loading ? (
{Array.from({ length: 3 }).map((_, i) => ( ))}
) : !hasData ? ( {t('No performance data available')} ) : (
{topModels.map((model) => (
{model.model_name}
))}
)}
) } function MetricCell(props: { icon: React.ComponentType<{ className?: string }> label: string value: string loading: boolean valueClassName?: string }) { const Icon = props.icon return (
{props.loading ? ( ) : (
{props.value}
)}
) }