"use client" import { useAudienceMode } from "@/components/audience-mode-provider" import { Fragment, useMemo, useState } from "react" import Link from "next/link" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible" import { Progress } from "@/components/ui/progress" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { getModelFamilyRouteId } from "@/lib/model-family" import { cn } from "@/lib/utils" import { AlertTriangle, BarChart3, BookOpen, ChevronDown, ChevronUp, Database, ExternalLink, FileText, Globe, Medal, Scale, Shield, Tag, } from "lucide-react" import type { BenchmarkCard } from "@/lib/benchmark-schema" import type { BenchmarkEvalSummary, ModelResultForBenchmark } from "@/lib/eval-processing" interface EvalDetailProps { summary: BenchmarkEvalSummary } interface LeaderboardRow { key: string rank: number modelResult: ModelResultForBenchmark normalizedScore: number } const PARAM_RANGE_VALUES = [1, 2, 3, 4, 6, 8, 10, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 500] as const const PARAM_RANGE_MARKERS = [ { label: "< 1B", step: 0 }, { label: "6B", step: PARAM_RANGE_VALUES.indexOf(6) }, { label: "12B", step: PARAM_RANGE_VALUES.indexOf(12) }, { label: "32B", step: PARAM_RANGE_VALUES.indexOf(32) }, { label: "128B", step: PARAM_RANGE_VALUES.indexOf(128) }, { label: "> 500B", step: PARAM_RANGE_VALUES.length - 1 }, ] as const function formatParamBoundLabel(step: number, bound: "min" | "max") { const maxStepIndex = PARAM_RANGE_VALUES.length - 1 if (bound === "min" && step <= 0) { return "< 1B" } if (bound === "max" && step >= maxStepIndex) { return "> 500B" } const value = PARAM_RANGE_VALUES[step] return value != null ? `${value}B` : "Not reported" } function parseParamsBillionsFromText(value: string | null | undefined) { if (!value) { return null } const normalized = value.trim().toLowerCase() if (!normalized) { return null } const compact = normalized.replace(/,/g, "") const tokenMatch = compact.match(/(\d+(?:\.\d+)?)\s*(trillion|tn|t|billion|bn|b|million|mn|m|thousand|k)\b/) if (tokenMatch) { const amount = Number.parseFloat(tokenMatch[1]) if (!Number.isFinite(amount)) { return null } const unit = tokenMatch[2] if (unit === "trillion" || unit === "tn" || unit === "t") { return amount * 1000 } if (unit === "billion" || unit === "bn" || unit === "b") { return amount } if (unit === "million" || unit === "mn" || unit === "m") { return amount / 1000 } if (unit === "thousand" || unit === "k") { return amount / 1_000_000 } } const numeric = Number.parseFloat(compact) return Number.isFinite(numeric) ? numeric : null } function parseParamsBillionsFromModelName(modelName: string | null | undefined) { if (!modelName) { return null } const sizeTokens = Array.from(modelName.matchAll(/\b(\d+(?:\.\d+)?)\s*([tmbk])\b/gi)) if (sizeTokens.length === 0) { return null } const lastToken = sizeTokens[sizeTokens.length - 1] const numericValue = Number.parseFloat(lastToken[1]) if (!Number.isFinite(numericValue)) { return null } const unit = lastToken[2].toLowerCase() if (unit === "t") { return numericValue * 1000 } if (unit === "b") { return numericValue } if (unit === "m") { return numericValue / 1000 } if (unit === "k") { return numericValue / 1_000_000 } return null } function getParamsBillions(modelResult: ModelResultForBenchmark) { const additionalDetails = modelResult.model_info.additional_details const rawParamsBillions = additionalDetails?.params_billions ?? additionalDetails?.parameter_count ?? additionalDetails?.num_parameters ?? additionalDetails?.params if (typeof rawParamsBillions === "number") { return rawParamsBillions } if (typeof rawParamsBillions === "string") { const parsed = parseParamsBillionsFromText(rawParamsBillions) if (Number.isFinite(parsed)) { return parsed } } if (typeof modelResult.model_info.parameter_count === "string") { const parsed = parseParamsBillionsFromText(modelResult.model_info.parameter_count) if (Number.isFinite(parsed)) { return parsed } } return parseParamsBillionsFromModelName(modelResult.model_info.name) } function formatMetadataValue(value: unknown): string { if (value == null) { return "N/A" } if (typeof value === "string") { return value } if (typeof value === "number") { return Number.isFinite(value) ? value.toLocaleString() : String(value) } if (typeof value === "boolean") { return value ? "true" : "false" } if (Array.isArray(value)) { return value.map((item) => formatMetadataValue(item)).join(", ") } try { return JSON.stringify(value) } catch { return String(value) } } function formatDate(ts: string) { const numeric = Number(ts) const parsedDate = !Number.isNaN(numeric) && !ts.includes("-") ? new Date(numeric * 1000) : new Date(ts) try { return parsedDate.toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", }) } catch { return ts } } function formatRawScore(score: number, unit?: string) { const suffix = unit ? ` ${unit}` : "" return `${score.toFixed(2)}${suffix}` } function getRankBadgeClass(rank: number) { if (rank === 1) { return "border-amber-300 bg-amber-100 text-amber-800" } if (rank === 2) { return "border-slate-300 bg-slate-100 text-slate-700" } if (rank === 3) { return "border-orange-300 bg-orange-100 text-orange-800" } return "border-border bg-background text-foreground" } export function EvalDetail({ summary }: EvalDetailProps) { const { mode } = useAudienceMode() const isResearchView = mode === "research" const [expandedRows, setExpandedRows] = useState>({}) const [leaderboardPage, setLeaderboardPage] = useState(1) const [minParamStep, setMinParamStep] = useState(0) const [maxParamStep, setMaxParamStep] = useState(PARAM_RANGE_VALUES.length - 1) const maxScore = summary.metric_config.max_score ?? 1 const minScore = summary.metric_config.min_score ?? 0 const range = maxScore - minScore const normalizeScore = (raw: number) => (range > 0 ? (raw - minScore) / range : raw) const formatPercent = (normalized: number) => `${(normalized * 100).toFixed(1)}%` const maxParamStepIndex = PARAM_RANGE_VALUES.length - 1 const minHandlePercent = (minParamStep / maxParamStepIndex) * 100 const maxHandlePercent = (maxParamStep / maxParamStepIndex) * 100 const numericMinParams = useMemo(() => { if (minParamStep <= 0) { return null } return PARAM_RANGE_VALUES[minParamStep] ?? null }, [minParamStep]) const numericMaxParams = useMemo(() => { if (maxParamStep >= PARAM_RANGE_VALUES.length - 1) { return null } return PARAM_RANGE_VALUES[maxParamStep] ?? null }, [maxParamStep]) const sortedResults = useMemo( () => [...summary.model_results].sort((a, b) => summary.metric_config.lower_is_better ? a.score - b.score : b.score - a.score ), [summary.model_results, summary.metric_config.lower_is_better] ) const hasParameterData = useMemo( () => sortedResults.some((result) => getParamsBillions(result) != null), [sortedResults] ) const filteredResults = useMemo(() => { return sortedResults.filter((modelResult) => { const paramsBillions = getParamsBillions(modelResult) if (numericMinParams != null && (paramsBillions == null || paramsBillions < numericMinParams)) { return false } if (numericMaxParams != null && (paramsBillions == null || paramsBillions > numericMaxParams)) { return false } return true }) }, [numericMaxParams, numericMinParams, sortedResults]) const leaderboardRows = useMemo(() => { let currentRank = 0 let previousScore: number | null = null return filteredResults.map((modelResult, index) => { if (previousScore === null || Math.abs(modelResult.score - previousScore) > 1e-9) { currentRank = index + 1 previousScore = modelResult.score } return { key: `${modelResult.model_info.id}-${index}`, rank: currentRank, modelResult, normalizedScore: normalizeScore(modelResult.score), } }) }, [filteredResults]) const LEADERBOARD_PAGE_SIZE = 50 const pagedLeaderboardRows = useMemo( () => leaderboardRows.slice(0, leaderboardPage * LEADERBOARD_PAGE_SIZE), [leaderboardRows, leaderboardPage] ) const avgNorm = formatPercent(summary.avg_score_norm) const scoreDirectionLabel = summary.metric_config.lower_is_better ? "Lower scores rank higher" : "Higher scores rank higher" const leaderboardTitle = isResearchView ? "Leaderboard" : "Reporting Comparison" const leaderboardDescription = isResearchView ? summary.is_aggregated ? "Models ranked by average normalized score across the contributing composite benchmarks." : "Models ranked by normalized score for this benchmark." : summary.is_aggregated ? "Averaged model results across the contributing composite benchmarks, with drill-down to each component score." : "Model results with stronger emphasis on reporting context and evaluator provenance." const toggleRow = (key: string) => setExpandedRows((current) => ({ ...current, [key]: !current[key], })) return (
{summary.is_aggregated ? "Merged Benchmark" : "Single Benchmark"} {summary.is_aggregated ? ( {summary.aggregate_sources?.length ?? 0} composite benchmarks ) : ( Composite: {summary.composite_benchmark_name} )} {summary.metric_config.score_type} {summary.metric_config.lower_is_better ? "Lower is better" : "Higher is better"} {(summary.factsheet?.input_modality ?? "text")}/{(summary.factsheet?.output_modality ?? "text")}
{summary.evaluation_name}

{summary.metric_config.evaluation_description}

{!isResearchView && (

{`${summary.factsheet?.purpose ?? "This benchmark provides a public-facing capability signal."} Scores should be read alongside reporting context and evaluator independence.`}

)}
Models
{summary.models_count}
{isResearchView ? "Avg norm" : "Reporting orgs"}
{isResearchView ? avgNorm : summary.evaluator_names.length}
{isResearchView ? "Top model" : "Score rule"}
{isResearchView && summary.best_model ? summary.best_model.name : scoreDirectionLabel}
{isResearchView && summary.best_model && (
{formatPercent(normalizeScore(summary.best_model.score))}
)}
{isResearchView ? "Bottom model" : "Purpose"}
{isResearchView && summary.worst_model ? summary.worst_model.name : summary.factsheet?.purpose ?? "General evaluation reporting"}
{isResearchView && summary.worst_model && (
{formatPercent(normalizeScore(summary.worst_model.score))}
)}
{isResearchView ? "Metric specification" : "Reading context"}
Composite benchmark
{summary.is_aggregated ? summary.aggregate_sources?.map((source) => source.composite_benchmark_name).join(", ") || "Multiple composite benchmarks" : summary.composite_benchmark_name}
{isResearchView ? "Single benchmark ID" : "What this covers"}
{isResearchView ? summary.evaluation_id : summary.is_aggregated ? summary.metric_config.evaluation_description : summary.metric_config.evaluation_description}
{isResearchView ? "Score scale" : "How to read scores"}
{isResearchView ? `${summary.metric_config.min_score ?? 0} - ${summary.metric_config.max_score ?? 1}` : scoreDirectionLabel}
Modalities
{(summary.factsheet?.input_modality ?? "text")}/{(summary.factsheet?.output_modality ?? "text")}
{summary.factsheet?.design ? "Documentation" : isResearchView ? "Reporting orgs" : "Evidence sources"}
{summary.factsheet?.design ? ( {summary.factsheet.design.replace(/^https?:\/\//, "")} ) : ( `${summary.evaluator_names.length} reporting org${summary.evaluator_names.length === 1 ? "" : "s"}` )}
{/* Policy: benchmark context BEFORE the leaderboard (context first, numbers second) */} {!isResearchView && summary.benchmark_card && ( )}
{leaderboardTitle}
{leaderboardDescription}
{leaderboardRows.length === summary.models_count ? `${summary.models_count} models` : `${leaderboardRows.length} of ${summary.models_count} models`} {scoreDirectionLabel} {hasParameterData && (numericMinParams != null || numericMaxParams != null) && ( Params {formatParamBoundLabel(minParamStep, "min")} to {formatParamBoundLabel(maxParamStep, "max")} )} {isResearchView && ( Scale {summary.metric_config.min_score ?? 0} - {summary.metric_config.max_score ?? 1} )}
{hasParameterData && (
Parameter range
Narrow the leaderboard to comparable model sizes.
{PARAM_RANGE_MARKERS.map((marker) => ( {marker.label} ))}
{PARAM_RANGE_VALUES.map((_, stepIndex) => (
{ const nextMin = Number(event.target.value) setMinParamStep(Math.min(nextMin, maxParamStep)) }} className="param-range-input" aria-label="Minimum parameter filter" /> { const nextMax = Number(event.target.value) setMaxParamStep(Math.max(nextMax, minParamStep)) }} className="param-range-input" aria-label="Maximum parameter filter" />
{formatParamBoundLabel(minParamStep, "min")} to {formatParamBoundLabel(maxParamStep, "max")}
)} Rank Model {isResearchView ? "Developer" : "Provider"} Score {isResearchView ? ( Performance ) : ( Source type )} {isResearchView ? "Evaluator" : "Reporting Org"} Updated Details {pagedLeaderboardRows.map(({ key, rank, modelResult, normalizedScore }) => { const isExpanded = expandedRows[key] ?? false const subtasks = modelResult.score_details.details ? Object.entries(modelResult.score_details.details).filter(([, value]) => typeof value === "number") : [] const hasExpandableDetails = (modelResult.aggregate_components && modelResult.aggregate_components.length > 1) || subtasks.length > 1 const datasetName = Array.isArray(modelResult.source_data) ? undefined : modelResult.source_data.dataset_name const samples = Array.isArray(modelResult.source_data) ? undefined : modelResult.source_data.samples_number return (
{rank}
{modelResult.model_info.name}
{modelResult.model_info.parameter_count && ( {modelResult.model_info.parameter_count} )} {modelResult.model_info.architecture && ( {modelResult.model_info.architecture} )} {modelResult.model_info.developer ?? "Unknown developer"} {modelResult.aggregate_components && modelResult.aggregate_components.length > 1 && ( Avg of {modelResult.aggregate_components.length} )}
{modelResult.model_info.developer ?? "Unknown developer"}
{formatPercent(normalizedScore)}
Raw {formatRawScore(modelResult.score, summary.metric_config.unit)}
{isResearchView ? (
{formatPercent(normalizedScore)}
) : (
{modelResult.aggregate_components && modelResult.aggregate_components.length > 1 ? `average of ${modelResult.aggregate_components.length} composite scores` : modelResult.source_metadata.evaluator_relationship.replace(/_/g, " ")}
)} {modelResult.aggregate_components && modelResult.aggregate_components.length > 1 ? (
{Array.from(new Set(modelResult.aggregate_components.map((component) => component.source_organization_name))).join(", ")}
{modelResult.aggregate_components .map((component) => component.composite_benchmark_name) .join(", ")}
) : (
{modelResult.source_metadata.source_organization_name}
{modelResult.source_metadata.evaluator_relationship.replace(/_/g, " ")}
)}
{formatDate(modelResult.evaluation_timestamp)}
{hasExpandableDetails && ( )}
{isExpanded && (
{isResearchView && } {modelResult.source_metadata.source_url && ( View source } /> )} {modelResult.score_details.confidence_interval && ( )}
{modelResult.aggregate_components && modelResult.aggregate_components.length > 1 && (
Composite Score Breakdown
{modelResult.aggregate_components.map((component, i) => ( ))}
Benchmark Source Raw Score
{component.composite_benchmark_name} {component.source_organization_name} {formatRawScore(component.score)} {formatPercent(component.normalized_score)}
)} {subtasks.length > 1 && (
Subtask Breakdown
{subtasks.map(([subtaskName, value]) => { const numericValue = value as number const normalizedSubtaskScore = range > 0 ? (numericValue - minScore) / range : numericValue return ( ) })}
Subtask Raw Score
{subtaskName.replace(/_/g, " ")} {formatRawScore(numericValue, summary.metric_config.unit)} {formatPercent(normalizedSubtaskScore)}
)} {modelResult.result.generation_config && (
Generation Config
Evaluation-time generation parameters.
{modelResult.result.generation_config.generation_args && Object.entries(modelResult.result.generation_config.generation_args).map(([key, value]) => (
{key.replace(/_/g, " ")}
{formatMetadataValue(value)}
))} {modelResult.result.generation_config.additional_details && (
Additional Details
{formatMetadataValue(modelResult.result.generation_config.additional_details)}
)} {modelResult.result.generation_config.prompt_template && (
Prompt Template
{formatMetadataValue(modelResult.result.generation_config.prompt_template)}
)}
)}
)} ) })} {leaderboardRows.length === 0 && ( No leaderboard entries match the selected parameter range. )} {/* Load more */} {pagedLeaderboardRows.length < leaderboardRows.length && (
)} {/* Research: benchmark card details AFTER the leaderboard, collapsed by default */} {isResearchView && summary.benchmark_card && ( )} ) } function ResearchBenchmarkCardCollapsible({ card }: { card: BenchmarkCard }) { const [open, setOpen] = useState(false) return ( ) } function DetailPanel({ title, subtitle, children, }: { title: string subtitle: string children: React.ReactNode }) { return (
{title}
{subtitle}
{children}
) } function MetaRow({ label, value, }: { label: string value: React.ReactNode }) { return (
{label} {value}
) } function toStringArray(value: string[] | string | undefined): string[] { if (!value) return [] if (Array.isArray(value)) return value.filter(Boolean) if (value === "Not specified") return [] return [value] } function BenchmarkCardPanel({ card, isResearchView, defaultRisksOpen = false, }: { card: BenchmarkCard isResearchView: boolean defaultRisksOpen?: boolean }) { const [risksOpen, setRisksOpen] = useState(defaultRisksOpen) const details = card.benchmark_details const purpose = card.purpose_and_intended_users const methodology = card.methodology const data = card.data const ethical = card.ethical_and_legal_considerations const risks = card.possible_risks ?? [] const flaggedFields = Object.entries(card.flagged_fields ?? {}) const missingFields = card.missing_fields ?? [] const domains = details.domains ?? [] const languages = details.languages ?? [] const resources = (details.resources ?? []).filter(Boolean) const tasks = toStringArray(purpose.tasks) const audience = toStringArray(purpose.audience) const license = ethical.data_licensing ?? "" const shortLicense = license && license !== "Not specified" ? license : null return (
Benchmark Card {shortLicense && ( {shortLicense} )} {(flaggedFields.length > 0 || missingFields.length > 0) && ( {flaggedFields.length} flagged · {missingFields.length} missing )}
Structured metadata about this benchmark — what it measures, how it was built, and known limitations. {card.card_info?.llm && ( Card generated by {card.card_info.llm}. )}
{/* Overview + domains */}

{details.overview}

{domains.map((d) => ( {d} ))} {languages.map((l) => ( {l} ))}
{/* Goal */}
Goal

{purpose.goal}

{/* Metric interpretation */}
Score interpretation

{methodology.interpretation}

{/* Limitations */}
Limitations

{purpose.limitations}

{/* Research-only: methodology + dataset details */} {isResearchView && (
Dataset
Size
{data.size}
Format
{data.format}
Source
{data.source}
Methodology
{methodology.metrics.length > 0 && (
Metrics
{methodology.metrics.join(", ")}
)} {tasks.length > 0 && (
Tasks
{tasks.join(", ")}
)} {audience.length > 0 && (
Audience
{audience.join("; ")}
)}
)} {/* Risks (collapsible) */} {risks.length > 0 && (
{risks.map((risk, i) => (
{risk.description?.[0] && (

{risk.description[0]}

)}
))}
)} {/* Compliance / ethical notes (policy view emphasis) */} {!isResearchView && (
Ethical & legal
{shortLicense && (
License
{license}
)} {ethical.compliance_with_regulations && ethical.compliance_with_regulations !== "Not specified" && (
Compliance
{ethical.compliance_with_regulations}
)} {ethical.privacy_and_anonymity && ethical.privacy_and_anonymity !== "Not specified" && (
Privacy
{ethical.privacy_and_anonymity}
)}
)} {/* Flagged / missing fields warning */} {(flaggedFields.length > 0 || missingFields.length > 0) && isResearchView && (
Card quality notes
{flaggedFields.length > 0 && (
    {flaggedFields.map(([field, note]) => (
  • {field}: {note}
  • ))}
)} {missingFields.length > 0 && (

Missing: {missingFields.join(", ")}

)}
)} {/* External resources */} {resources.length > 0 && ( )}
) }