LLMProviders / src /App.tsx
CrispStrobe
fix: unify grouping logic using canonical IDs and getGroupKey helper
644a44f
import { useState, useMemo, useCallback, useEffect } from 'react'
import providersData from '../data/providers.json'
import benchmarksData from '../data/benchmarks.json'
import { ManagementPanel } from './components/ManagementPanel'
interface Model {
name: string
category?: string
type: string
size_b?: number
input_price_per_1m?: number
output_price_per_1m?: number
price_per_image?: number
price_per_minute?: number
audio_price_per_1m?: number
price_per_1m_tokens_30d?: number
currency: string
capabilities?: string[]
display_name?: string;
hf_id?: string;
canonical_id?: string;
ollama_id?: string;
hf_private?: boolean;
size_source?: 'hf-total' | 'hf-config-estimate' | 'hf-card' | 'ollama' | 'manual' | 'benchmark' | 'openrouter';
provider?: Provider;
complianceStatus?: string;
}
interface Provider {
name: string
url: string
headquarters: string
region: string
gdpr_compliant: boolean
eu_endpoints: boolean
models: Model[]
}
type SortConfig = {
key: string;
direction: 'asc' | 'desc';
} | null;
interface BenchmarkEntry {
slug?: string; // LLMStats slug
hf_id?: string; // HF leaderboard fullname
name: string;
// LLMStats benchmarks
mmlu?: number;
mmlu_pro?: number;
gpqa?: number;
human_eval?: number;
math?: number;
gsm8k?: number;
mmmu?: number;
hellaswag?: number;
ifeval?: number;
arc?: number;
drop?: number;
mbpp?: number;
mgsm?: number;
bbh?: number;
// HF-specific
hf_math_lvl5?: number;
hf_musr?: number;
hf_avg?: number;
params_b?: number;
// LiveBench (livebench.ai β€” contamination-free, monthly updated)
lb_name?: string;
lb_global?: number;
lb_reasoning?: number;
lb_coding?: number;
lb_math?: number;
lb_language?: number;
lb_if?: number;
lb_data_analysis?: number;
// Chatbot Arena (lmarena.ai β€” real human preference votes)
arena_name?: string;
arena_elo?: number; // raw ELO score ~800-1500 (higher = better)
arena_rank?: number;
arena_votes?: number;
// Aider code editing benchmark (aider.chat)
aider_pass_rate?: number; // 0-1, first-pass success on 133 coding tasks
// Artificial Analysis (artificialanalysis.ai)
aa_id?: string;
aa_name?: string;
aa_slug?: string;
aa_intelligence?: number; // 0-100 intelligence index
aa_coding?: number; // 0-100 coding index
aa_math?: number; // 0-100 math index
aa_mmlu_pro?: number;
aa_gpqa?: number;
aa_livecodebench?: number;
aa_hle?: number;
aa_scicode?: number;
aa_math_500?: number;
aa_aime?: number;
aa_tokens_per_s?: number;
aa_latency_s?: number;
// MTEB (Massive Text Embedding Benchmark)
mteb_avg?: number;
mteb_retrieval?: number;
// OCR Benchmark
ocr_avg?: number;
}
const normalizeName = (s?: string) =>
(s || '').toLowerCase().replace(/[-_.]/g, ' ').replace(/[^a-z0-9 ]/g, '').replace(/\s+/g, ' ').trim();
const EXCHANGE_RATE_EUR_TO_USD = 1.05
const CAP_ICON: Record<string, string> = {
// Input Modalities
vision: 'πŸ‘', // Image Input
video: '🎬', // Video Input
audio: '🎀', // Audio Input (ASR)
files: 'πŸ“„', // File/PDF Input
// Output Modalities
'image-out': '🎨', // Image Generation
'video-out': 'πŸŽ₯', // Video Generation
'audio-out': 'πŸ”Š', // Audio Generation (TTS)
// Functional Capabilities
tools: 'πŸ”§',
reasoning: 'πŸ’‘',
embedding: '🧩',
'eu-endpoint': 'πŸ‡ͺπŸ‡Ί',
}
function App() {
const [searchTerm, setSearchTerm] = useState('')
const [selectedType, setSelectedType] = useState('all')
const [selectedRegion, setSelectedRegion] = useState('all')
const [sortConfig, setSortConfig] = useState<SortConfig>({ key: 'price', direction: 'asc' });
const [groupByModel, setGroupByModel] = useState(false);
const [showBenchmarks, setShowBenchmarks] = useState(false);
const [showManagement, setShowManagement] = useState(false);
const [dataVersion, setDataVersion] = useState(0);
// Live data β€” initialized from bundled JSON, refreshed from /api/* when available
const [liveProviders, setLiveProviders] = useState<Provider[]>((providersData as any).providers);
const [liveBenchmarks, setLiveBenchmarks] = useState<BenchmarkEntry[]>(benchmarksData as BenchmarkEntry[]);
const getGroupKey = useCallback((m: Model) => {
return (m.hf_id || m.canonical_id || m.name || '').toLowerCase();
}, []);
useEffect(() => {
fetch('/api/data')
.then(r => r.ok ? r.json() : null)
.then(d => { if (d?.providers) setLiveProviders(d.providers); })
.catch(() => {});
fetch('/api/benchmarks')
.then(r => r.ok ? r.json() : null)
.then(d => { if (Array.isArray(d)) setLiveBenchmarks(d); })
.catch(() => {});
}, [dataVersion]);
const fmtNum = (v?: number, decimals = 0) => (v !== undefined && Number.isFinite(v)) ? v.toFixed(decimals) : '–';
const fmtPct = (v?: number) => (v !== undefined && Number.isFinite(v)) ? `${(v * 100).toFixed(0)}%` : '–';
// Build benchmark lookup maps
const { nameMap, hfIdMap } = useMemo(() => {
const nameMap = new Map<string, BenchmarkEntry>();
const hfIdMap = new Map<string, BenchmarkEntry>();
for (const b of liveBenchmarks) {
nameMap.set(normalizeName(b.name), b);
if (b.slug) {
const slugModel = b.slug.split('/').pop() || '';
if (slugModel) nameMap.set(normalizeName(slugModel), b);
}
if (b.hf_id) {
hfIdMap.set(normalizeName(b.hf_id), b);
const modelPart = b.hf_id.split('/').pop() || '';
const normModel = normalizeName(modelPart);
nameMap.set(normModel, b);
const words = normModel.split(' ');
if (words.length > 1) nameMap.set(words.slice(1).join(' '), b);
}
if (b.lb_name) nameMap.set(normalizeName(b.lb_name), b);
if (b.arena_name) nameMap.set(normalizeName(b.arena_name), b);
if (b.aa_name) nameMap.set(normalizeName(b.aa_name), b);
if (b.aa_slug) nameMap.set(normalizeName(b.aa_slug), b);
}
return { nameMap, hfIdMap };
}, [liveBenchmarks]);
const findBenchmark = useCallback((modelName: string): BenchmarkEntry | undefined => {
// Strip @region (e.g. @us-east-1) and :effort (e.g. :high) suffixes before normalizing
const cleanName = modelName.replace(/@[^/]+$/, '').replace(/:[^/]+$/, '');
const norm = normalizeName(cleanName);
// Direct HF ID match (for providers that use "org/model-id" format)
let modelPart = '';
if (cleanName.includes('/')) {
if (hfIdMap.has(norm)) return hfIdMap.get(norm)!;
// Try model part only (after "/")
modelPart = normalizeName(cleanName.split('/').pop() || '');
if (nameMap.has(modelPart)) return nameMap.get(modelPart)!;
// Strip first word from model part β€” handles "Meta-Llama-..." vs "Llama-..."
const modelWords = modelPart.split(' ');
if (modelWords.length > 1) {
const stripped = modelWords.slice(1).join(' ');
if (nameMap.has(stripped)) return nameMap.get(stripped)!;
}
}
if (nameMap.has(norm)) return nameMap.get(norm);
// Longest startsWith match β€” handles date-suffixed variants like "claude-3-5-sonnet-20241022"
let best: BenchmarkEntry | undefined;
let bestLen = 0;
for (const [key, val] of nameMap) {
if (norm.startsWith(key)) {
const rest = norm.slice(key.length);
if ((rest === '' || /^ \d/.test(rest)) && key.length > bestLen) {
best = val;
bestLen = key.length;
}
}
}
if (best) return best;
// Reverse prefix: benchmark key starts with provider name β€” handles cases where the
// benchmark stores a base name longer than the provider's model ID.
// Check both norm and modelPart (for versionless names like "anthropic/claude-haiku-4-5").
// Pick the highest lb_global among all matches (best variant of the model).
let bestReverse: BenchmarkEntry | undefined;
let bestReverseScore = -1;
for (const [key, val] of nameMap) {
const score = val.lb_global ?? 0;
if (
(key.startsWith(norm + ' ') || (modelPart && key.startsWith(modelPart + ' '))) &&
score > bestReverseScore
) {
bestReverse = val;
bestReverseScore = score;
}
}
return bestReverse;
}, [nameMap, hfIdMap]);
const handleDataUpdated = useCallback(() => {
// Increment version to signal that a page reload would show fresh data
setDataVersion((v) => v + 1);
}, []);
const getComplianceStatus = (provider: Provider, model?: Model) => {
const hq = provider.headquarters.toLowerCase();
const isEU = provider.region === 'EU' || hq === 'germany' || hq === 'france' || hq === 'netherlands';
const isUS = hq === 'usa' || provider.region === 'US';
const isEEA = provider.region === 'EEA Equivalent' || hq === 'switzerland';
// Model-level override for OpenRouter or similar aggregators
const hasEuEndpoint = model?.capabilities?.includes('eu-endpoint') || provider.eu_endpoints;
if (isEU) return 'EU';
if (isEEA) return 'EEA';
if (isUS && hasEuEndpoint) return 'US/EU';
if (isUS) return 'US';
return 'Other';
};
const allModels = useMemo(() => {
const rawModels: any[] = []
liveProviders.forEach((provider: Provider) => {
provider.models.forEach((model) => {
const status = getComplianceStatus(provider, model);
let cleanName = model.name;
// Strip provider/ prefix for all models
if (cleanName.includes('/')) {
cleanName = cleanName.split('/').pop() || cleanName;
}
rawModels.push({
...model,
name: cleanName,
provider,
complianceStatus: status
})
})
})
// De-duplicate: filter out models with same name, provider, and price
const seen = new Set<string>();
const uniqueModels = rawModels.filter(m => {
const key = `${m.provider?.name}|${m.name}|${m.input_price_per_1m}|${m.output_price_per_1m}`;
if (seen.has(key)) return false;
seen.add(key);
return true;
});
return uniqueModels;
}, [liveProviders])
const filteredModels = useMemo(() => {
return allModels.filter((model) => {
const providerName = model.provider?.name || '';
const matchesSearch = model.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
providerName.toLowerCase().includes(searchTerm.toLowerCase())
const caps = model.capabilities || [];
const matchesType = selectedType === 'all' ||
model.type === selectedType ||
(selectedType === 'audio' && (caps.includes('audio') || caps.includes('audio-out'))) ||
(selectedType === 'vision' && (caps.includes('vision') || caps.includes('video'))) ||
(selectedType === 'chat' && model.type === 'chat');
const status = model.complianceStatus || 'Other';
let matchesRegion = selectedRegion === 'all' || status === selectedRegion;
// US filter includes US/EU
if (selectedRegion === 'US' && status === 'US/EU') matchesRegion = true;
return matchesSearch && matchesType && matchesRegion
})
}, [searchTerm, selectedType, selectedRegion, allModels])
const getNormalizedPriceUSD = (model: Model) => {
const price = model.input_price_per_1m || model.price_per_image || model.price_per_minute || 0
return model.currency === 'EUR' ? price * EXCHANGE_RATE_EUR_TO_USD : price
}
const sortedModels = useMemo(() => {
return [...filteredModels].sort((a, b) => {
if (!sortConfig) return 0;
let aValue: any;
let bValue: any;
switch (sortConfig.key) {
case 'provider':
aValue = a.provider.name;
bValue = b.provider.name;
break;
case 'model':
aValue = a.name;
bValue = b.name;
break;
case 'size':
aValue = a.size_b || 0;
bValue = b.size_b || 0;
break;
case 'price':
aValue = getNormalizedPriceUSD(a);
bValue = getNormalizedPriceUSD(b);
break;
case 'output_price':
aValue = a.output_price_per_1m ?? 0;
bValue = b.output_price_per_1m ?? 0;
break;
case 'compliance':
aValue = a.complianceStatus;
bValue = b.complianceStatus;
break;
case 'mmlu':
case 'gpqa':
case 'human_eval':
case 'math':
case 'gsm8k':
case 'mmmu':
case 'ifeval':
case 'bbh':
case 'hf_math_lvl5':
case 'hf_musr':
case 'hf_avg':
case 'lb_global':
case 'lb_reasoning':
case 'lb_coding':
case 'lb_math':
case 'lb_language':
case 'lb_if':
case 'lb_data_analysis':
case 'arena_elo':
case 'aider_pass_rate':
case 'aa_intelligence':
case 'aa_tokens_per_s':
case 'mteb_avg':
case 'mteb_retrieval': {
try {
const bA = findBenchmark(a.name);
const bB = findBenchmark(b.name);
aValue = bA?.[sortConfig.key as keyof BenchmarkEntry] as number ?? -1;
bValue = bB?.[sortConfig.key as keyof BenchmarkEntry] as number ?? -1;
} catch (e) {
aValue = -1;
bValue = -1;
}
break;
}
default:
return 0;
}
if (aValue < bValue) return sortConfig.direction === 'asc' ? -1 : 1;
if (aValue > bValue) return sortConfig.direction === 'asc' ? 1 : -1;
return 0;
});
}, [filteredModels, sortConfig])
const displayModels = useMemo(() => {
if (!groupByModel) return sortedModels;
const groups: Record<string, typeof sortedModels> = {};
const groupOrder: string[] = [];
sortedModels.forEach(m => {
const key = getGroupKey(m);
if (!groups[key]) {
groups[key] = [];
groupOrder.push(key);
}
groups[key].push(m);
});
const result: typeof sortedModels = [];
groupOrder.forEach(key => {
result.push(...groups[key]);
});
return result;
}, [sortedModels, groupByModel, getGroupKey]);
const requestSort = (key: string) => {
let direction: 'asc' | 'desc' = 'asc';
if (sortConfig && sortConfig.key === key && sortConfig.direction === 'asc') {
direction = 'desc';
}
setSortConfig({ key, direction });
};
const formatPrice = (price: number | undefined, currency: string) => {
if (price === undefined) return '-'
if (price === 0) return 'Free'
const symbol = currency === 'USD' ? '$' : '€'
return `${symbol}${price.toFixed(4)}`
}
const getSortIcon = (key: string) => {
if (sortConfig?.key !== key) return '↕️';
return sortConfig.direction === 'asc' ? 'πŸ”Ό' : 'πŸ”½';
}
return (
<div className="container">
<header>
<div className="header-row">
<div>
<h1>AI Provider Comparison</h1>
<p>Analyze costs, data sovereignty, and model efficiency.</p>
</div>
<div className="header-actions">
{dataVersion > 0 && (
<span className="data-stale-hint" title="Data refreshed from server">
↻ data updated
</span>
)}
<a
className="btn-github"
href="https://github.com/CrispStrobe/LLMProviders"
target="_blank"
rel="noopener noreferrer"
title="View source on GitHub"
>
GitHub
</a>
<button className="btn-manage" onClick={() => setShowManagement(true)}>
βš™ Manage Data
</button>
</div>
</div>
</header>
{showManagement && (
<ManagementPanel
onClose={() => setShowManagement(false)}
onDataUpdated={handleDataUpdated}
/>
)}
<div className="controls">
<input
type="text"
placeholder="Search models or providers..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="search-input"
/>
<select value={selectedType} onChange={(e) => setSelectedType(e.target.value)} className="type-select">
<option value="all">All Types</option>
<option value="chat">Chat (LLM)</option>
<option value="vision">Vision</option>
<option value="embedding">Embedding</option>
<option value="image">Image</option>
<option value="audio">Audio</option>
</select>
<select value={selectedRegion} onChange={(e) => setSelectedRegion(e.target.value)} className="type-select">
<option value="all">All Jurisdictions</option>
<option value="EU">EU (Sovereign)</option>
<option value="EEA">EEA (Swiss/EEA)</option>
<option value="US/EU">US/EU (EU Endpoint)</option>
<option value="US">US (Cloud Act)</option>
<option value="Other">Other</option>
</select>
<label className="checkbox-label">
<input
type="checkbox"
checked={groupByModel}
onChange={(e) => setGroupByModel(e.target.checked)}
/>
Group by Model
</label>
<label className="checkbox-label">
<input
type="checkbox"
checked={showBenchmarks}
onChange={(e) => setShowBenchmarks(e.target.checked)}
/>
Show Benchmarks
</label>
</div>
<div className="table-container">
<table>
<thead>
<tr>
<th onClick={() => requestSort('provider')} className="sortable">Provider {getSortIcon('provider')}</th>
<th onClick={() => requestSort('compliance')} className="sortable">Jurisdiction {getSortIcon('compliance')}</th>
<th onClick={() => requestSort('model')} className="sortable">Model {getSortIcon('model')}</th>
<th>Caps</th>
<th onClick={() => requestSort('size')} className="sortable">Size (B) {getSortIcon('size')}</th>
<th onClick={() => requestSort('price')} className="sortable">Input Price (USD) {getSortIcon('price')}</th>
<th onClick={() => requestSort('output_price')} className="sortable">Output Price {getSortIcon('output_price')}</th>
{showBenchmarks && <>
<th onClick={() => requestSort('arena_elo')} className="sortable" title="Chatbot Arena ELO (human preference votes)">Arena ELO {getSortIcon('arena_elo')}</th>
<th onClick={() => requestSort('aider_pass_rate')} className="sortable" title="Aider code editing benchmark (pass rate, 133 tasks)">Aider {getSortIcon('aider_pass_rate')}</th>
<th onClick={() => requestSort('aa_intelligence')} className="sortable" title="Artificial Analysis Intelligence Index (0-100)">AA Intel {getSortIcon('aa_intelligence')}</th>
<th onClick={() => requestSort('aa_tokens_per_s')} className="sortable" title="Artificial Analysis Median Speed (Tokens per Second)">AA Speed {getSortIcon('aa_tokens_per_s')}</th>
<th onClick={() => requestSort('mteb_avg')} className="sortable" title="MTEB (Massive Text Embedding Benchmark) Average">MTEB {getSortIcon('mteb_avg')}</th>
<th onClick={() => requestSort('mteb_retrieval')} className="sortable" title="MTEB Retrieval Average">MTEB-Ret {getSortIcon('mteb_retrieval')}</th>
<th onClick={() => requestSort('lb_global')} className="sortable" title="LiveBench overall average (contamination-free)">LB {getSortIcon('lb_global')}</th>
<th onClick={() => requestSort('lb_math')} className="sortable" title="LiveBench Mathematics">LB-Math {getSortIcon('lb_math')}</th>
<th onClick={() => requestSort('lb_coding')} className="sortable" title="LiveBench Coding + Agentic Coding">LB-Code {getSortIcon('lb_coding')}</th>
<th onClick={() => requestSort('lb_reasoning')} className="sortable" title="LiveBench Reasoning">LB-Reas {getSortIcon('lb_reasoning')}</th>
<th onClick={() => requestSort('gpqa')} className="sortable" title="Graduate-level reasoning (GPQA)">GPQA {getSortIcon('gpqa')}</th>
<th onClick={() => requestSort('mmlu_pro')} className="sortable" title="MMLU-Pro knowledge">MMLU-PRO {getSortIcon('mmlu_pro')}</th>
<th onClick={() => requestSort('ifeval')} className="sortable" title="Instruction following (IFEval)">IFEval {getSortIcon('ifeval')}</th>
<th onClick={() => requestSort('bbh')} className="sortable" title="Big-Bench Hard reasoning">BBH {getSortIcon('bbh')}</th>
<th onClick={() => requestSort('hf_math_lvl5')} className="sortable" title="MATH Level 5 (HF leaderboard)">MATH L5 {getSortIcon('hf_math_lvl5')}</th>
<th onClick={() => requestSort('hf_musr')} className="sortable" title="Multi-step Soft Reasoning (HF leaderboard)">MUSR {getSortIcon('hf_musr')}</th>
<th onClick={() => requestSort('mmlu')} className="sortable" title="Classic MMLU (LLMStats)">MMLU {getSortIcon('mmlu')}</th>
<th onClick={() => requestSort('human_eval')} className="sortable" title="HumanEval coding (LLMStats)">HumanEval {getSortIcon('human_eval')}</th>
</>}
</tr>
</thead>
<tbody>
{displayModels.map((model, idx) => {
const prev = displayModels[idx - 1];
const isGroupStart = groupByModel && (
idx === 0 || getGroupKey(prev) !== getGroupKey(model)
);
const bm = findBenchmark(model.name);
return (
<tr key={`${model.provider.name}-${model.name}-${idx}`} className={isGroupStart ? 'group-divider' : ''}>
<td className="provider-cell">{model.provider.name}</td>
<td>
<span className={`status-badge ${model.complianceStatus.replace(/\s+|[\(\)\/]/g, '-').toLowerCase()}`}>
{model.complianceStatus}
</span>
</td>
<td className="model-name">
<div className="model-name-wrapper">
{model.display_name ?? model.name}
<div className="model-info-container">
<span className="info-icon">β“˜</span>
<div className="model-tooltip">
<div className="tooltip-row"><strong>Type:</strong> {model.type}</div>
{model.size_b && <div className="tooltip-row"><strong>Size:</strong> {model.size_b}B</div>}
{model.hf_id && (
<div className="tooltip-row">
<strong>HF:</strong>
<a href={`https://huggingface.co/${model.hf_id}`} target="_blank" rel="noopener noreferrer" className="hf-link">
{model.hf_id} β†—
</a>
</div>
)}
{!model.hf_id && model.hf_private && (
<div className="tooltip-row"><strong>HF:</strong> Proprietary API</div>
)}
{model.ollama_id && (
<div className="tooltip-row">
<strong>Ollama:</strong>
<a href={`https://ollama.com/library/${model.ollama_id}`} target="_blank" rel="noopener noreferrer" className="hf-link">
{model.ollama_id} β†—
</a>
</div>
)}
{model.capabilities && model.capabilities.length > 0 && (
<div className="tooltip-row"><strong>Caps:</strong> {model.capabilities.join(', ')}</div>
)}
{bm?.ocr_avg !== undefined && (
<div className="tooltip-row"><strong>OCR:</strong> {bm.ocr_avg.toFixed(1)} (olmOCR-bench)</div>
)}
</div>
</div>
</div>
</td>
<td className="caps-cell">
{model.type === 'embedding' && (
<span className="cap-badge cap-embedding" title="embedding">{CAP_ICON.embedding}</span>
)}
{(model.capabilities || []).map((cap: string) => (
<span key={cap} className={`cap-badge cap-${cap}`} title={cap}>{CAP_ICON[cap] ?? cap}</span>
))}
</td>
<td className="size-cell">{model.size_b ? `${model.size_b}B` : '-'}</td>
<td>
<div className="price-stack">
{model.price_per_image !== undefined && !model.input_price_per_1m
? `$${model.price_per_image}/MP`
: model.price_per_minute !== undefined
? `${formatPrice(model.price_per_minute, model.currency)}/min`
: formatPrice(model.input_price_per_1m, model.currency)}
{model.audio_price_per_1m !== undefined && (
<div className="price-subtext" title="Audio token price">
{CAP_ICON.audio} {formatPrice(model.audio_price_per_1m, model.currency)}/M
</div>
)}
</div>
</td>
<td>
{model.price_per_image !== undefined && !model.output_price_per_1m
? '–'
: model.price_per_minute !== undefined
? '–'
: formatPrice(model.output_price_per_1m, model.currency)}
</td>
{showBenchmarks && (
<>
<td className="benchmark-cell">{fmtNum(bm?.arena_elo)}</td>
<td className="benchmark-cell">{fmtPct(bm?.aider_pass_rate)}</td>
<td className="benchmark-cell">{fmtNum(bm?.aa_intelligence)}</td>
<td className="benchmark-cell">{fmtNum(bm?.aa_tokens_per_s)}</td>
<td className="benchmark-cell">{fmtNum(bm?.mteb_avg, 1)}</td>
<td className="benchmark-cell">{fmtNum(bm?.mteb_retrieval, 1)}</td>
<td className="benchmark-cell">{fmtPct(bm?.lb_global)}</td>
<td className="benchmark-cell">{fmtPct(bm?.lb_math)}</td>
<td className="benchmark-cell">{fmtPct(bm?.lb_coding)}</td>
<td className="benchmark-cell">{fmtPct(bm?.lb_reasoning)}</td>
<td className="benchmark-cell">{fmtPct(bm?.gpqa)}</td>
<td className="benchmark-cell">{fmtPct(bm?.mmlu_pro)}</td>
<td className="benchmark-cell">{fmtPct(bm?.ifeval)}</td>
<td className="benchmark-cell">{fmtPct(bm?.bbh)}</td>
<td className="benchmark-cell">{fmtPct(bm?.hf_math_lvl5)}</td>
<td className="benchmark-cell">{fmtPct(bm?.hf_musr)}</td>
<td className="benchmark-cell">{fmtPct(bm?.mmlu)}</td>
<td className="benchmark-cell">{fmtPct(bm?.human_eval)}</td>
</>
)}
</tr>
)
})}
</tbody>
</table>
</div>
<footer>
<p>* All prices normalized to USD for comparison using 1 EUR = {EXCHANGE_RATE_EUR_TO_USD} USD.</p>
<p>Benchmark data from LLMStats, HF Leaderboard, LiveBench, Chatbot Arena, Aider, MTEB, and <a href="https://artificialanalysis.ai/" target="_blank" rel="noopener noreferrer">Artificial Analysis</a>.</p>
<p>Sorted by input price by default.</p>
</footer>
</div>
)
}
export default App