import type { ComponentType } from 'react' import Link from 'next/link' import { getProviderColor } from '@/app/(landing)/models/components/constants' import type { CatalogModel } from '@/app/(landing)/models/utils' import { formatPrice, formatTokenCount, MODEL_CATALOG_PROVIDERS, } from '@/app/(landing)/models/utils' /** Flagship providers featured in the landing-page comparison, in display order. */ const FEATURED_COMPARISON_PROVIDER_IDS = ['anthropic', 'openai', 'google'] /** Max latest models pulled from each featured provider. */ const MAX_MODELS_PER_PROVIDER = 4 const PROVIDER_ICON_MAP: Record> = (() => { const map: Record> = {} for (const provider of MODEL_CATALOG_PROVIDERS) { if (provider.icon) { map[provider.id] = provider.icon } } return map })() function selectComparisonModels(models: CatalogModel[]): CatalogModel[] { const seen = new Set() const result: CatalogModel[] = [] for (const providerId of FEATURED_COMPARISON_PROVIDER_IDS) { const providerModels = models .filter((model) => model.providerId === providerId && !model.deprecated) .sort((a, b) => (b.releaseDate ?? '').localeCompare(a.releaseDate ?? '')) let takenForProvider = 0 for (const model of providerModels) { if (takenForProvider >= MAX_MODELS_PER_PROVIDER) break const nameKey = model.displayName.toLowerCase() if (seen.has(nameKey)) continue seen.add(nameKey) result.push(model) takenForProvider += 1 } } return result } interface ModelLabelProps { model: CatalogModel } function ModelLabel({ model }: ModelLabelProps) { const Icon = PROVIDER_ICON_MAP[model.providerId] return (
{Icon && } {model.displayName}
) } interface ChartProps { models: CatalogModel[] } function StackedCostChart({ models }: ChartProps) { const entries = models .reduce>( (acc, model) => { const total = model.pricing.input + model.pricing.output if (total > 0) { acc.push({ model, input: model.pricing.input, output: model.pricing.output, total }) } return acc }, [] ) .sort((a, b) => a.total - b.total) const maxTotal = entries.length > 0 ? Math.max(...entries.map((e) => e.total)) : 0 const data = { entries, maxTotal } if (data.entries.length === 0) return null return (

Cost

Per 1M tokens
{data.entries.map(({ model, input, output, total }) => { const totalPct = data.maxTotal > 0 ? (total / data.maxTotal) * 100 : 0 const inputPct = total > 0 ? (input / total) * 100 : 0 const color = getProviderColor(model.providerId) return (
{formatPrice(input)} input / {formatPrice(output)} output
) })}
) } function ContextWindowChart({ models }: ChartProps) { const entries = models .map((model) => ({ model, value: model.contextWindow, })) .filter((e): e is { model: CatalogModel; value: number } => e.value !== null && e.value > 0) .sort((a, b) => a.value - b.value) const maxValue = entries.length > 0 ? Math.max(...entries.map((e) => e.value)) : 0 const data = { entries, maxValue } if (data.entries.length === 0) return null return (

Context window

Max tokens
{data.entries.map(({ model, value }) => { const pct = data.maxValue > 0 ? (value / data.maxValue) * 100 : 0 const color = getProviderColor(model.providerId) return (
{formatTokenCount(value)}
) })}
) } interface ModelComparisonChartsProps { models: CatalogModel[] } export function ModelComparisonCharts({ models }: ModelComparisonChartsProps) { const comparisonModels = selectComparisonModels(models) return (

Compare models

Side-by-side comparison of top models across key metrics.

) }