'use client' import { useState, useMemo, useCallback } from 'react' import type { ModelData } from '@/lib/types' import { fmtPct, fmtNum, lucColor, ragColor, fairnessColor, creatorColor, CREATOR_COLORS } from '@/lib/utils' import { LabLogo } from '@/components/LabLogo' type SortKey = 'rank' | 'luc' | 'rag' | 'fairness' interface Props { models: ModelData[] maxFairness: number } function ScoreCell({ value, color, max = 1, format, invert = false, }: { value: number | null color: string max?: number format: (v: number | null) => string invert?: boolean }) { const barWidth = value === null ? 0 : invert ? Math.max(0, 1 - value / max) : value / max return ( {value === null ? ( ) : ( <>
{format(value)}
)} ) } function ExpandedRow({ model, maxFairness }: { model: ModelData; maxFairness: number }) { const lucMetrics = [ { label: 'General', val: model.luc.general, color: lucColor(model.luc.general) }, { label: 'Physics misuse', val: model.luc.physics, color: lucColor(model.luc.physics) }, { label: 'Career scams', val: model.luc.career, color: lucColor(model.luc.career) }, { label: 'Job discrimination', val: model.luc.jd, color: lucColor(model.luc.jd) }, ] const ragMetrics = [ { label: 'Long In-Context Abstractive', val: model.rag.lcAbs, color: ragColor(model.rag.lcAbs) }, { label: 'Long In-Context Factual', val: model.rag.lcFact, color: ragColor(model.rag.lcFact) }, { label: 'HyDE RAG Abstractive', val: model.rag.hyAbs, color: ragColor(model.rag.hyAbs) }, { label: 'HyDE RAG Factual', val: model.rag.hyFact, color: ragColor(model.rag.hyFact) }, ] const fairMetrics = [ { label: 'Style disparity', val: model.fairness.style, invert: true }, { label: 'Content disparity', val: model.fairness.con, invert: true }, ] return (
{/* LUC */}
Localised Undesired Content
{lucMetrics.map(m => (
{m.label}
{fmtPct(m.val)}
))}
{/* RAG */}
RAG Robustness
{ragMetrics.map(m => (
{m.label}
{fmtPct(m.val)}
))}
{/* Fairness */}
Fairness Disparity
{fairMetrics.map(m => { const fc = fairnessColor(m.val) const pct = m.val !== null ? Math.min(100, (m.val / maxFairness) * 100) : 0 return (
{m.label}
{fmtNum(m.val, 4)}
) })}
) } export default function LeaderboardTable({ models, maxFairness }: Props) { const [sortKey, setSortKey] = useState('luc') const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc') const [query, setQuery] = useState('') const [expandedRank, setExpandedRank] = useState(null) const [activeCreator, setActiveCreator] = useState(null) const creators = useMemo(() => [...new Set(models.map(m => m.creator))].sort(), [models]) const handleSort = useCallback((key: SortKey) => { if (sortKey === key) { setSortDir(d => (d === 'asc' ? 'desc' : 'asc')) } else { setSortKey(key) setSortDir(key === 'fairness' ? 'asc' : 'desc') } }, [sortKey]) const sortedFiltered = useMemo(() => { let list = models.filter(m => !m.archived) if (activeCreator) list = list.filter(m => m.creator === activeCreator) if (query.trim()) { const q = query.toLowerCase() list = list.filter( m => m.model.toLowerCase().includes(q) || m.creator.toLowerCase().includes(q), ) } list.sort((a, b) => { let va: number | null, vb: number | null if (sortKey === 'rank') { va = a.rank; vb = b.rank } else if (sortKey === 'luc') { va = a.luc.avg; vb = b.luc.avg } else if (sortKey === 'rag') { va = a.rag.avg; vb = b.rag.avg } else { va = a.fairness.avg; vb = b.fairness.avg } if (va === null && vb === null) return 0 if (va === null) return 1 if (vb === null) return -1 return sortDir === 'asc' ? va - vb : vb - va }) return list }, [models, activeCreator, query, sortKey, sortDir]) function SortArrow({ k }: { k: SortKey }) { if (sortKey !== k) return return {sortDir === 'asc' ? '↑' : '↓'} } return (
{/* Controls */}
setQuery(e.target.value)} />
{creators.map(c => ( ))}
{/* Table */}
{sortedFiltered.map((model, i) => { const isExpanded = expandedRank === model.rank const cc = creatorColor(model.creator) return [ fmtPct(v)} /> fmtPct(v)} /> fmtNum(v, 4)} invert /> , isExpanded && ( ), ] })}
handleSort('rank')} className={sortKey === 'rank' ? 'sort-active' : ''} style={{ width: 48 }}> # Creator Model handleSort('luc')} className={sortKey === 'luc' ? 'sort-active' : ''}> Refusal Rate handleSort('rag')} className={sortKey === 'rag' ? 'sort-active' : ''}> RAG Score handleSort('fairness')} className={sortKey === 'fairness' ? 'sort-active' : ''}> Fairness ↓
{i + 1}
{sortedFiltered.length} models · ↓ lower fairness score = more equitable
) }