import type { Metadata } from 'next'; import Link from 'next/link'; import { CompareButton } from '@/components/compare/compare-button'; import { CompareTrayBar } from '@/components/compare/compare-tray-bar'; import { CONTEXTS, FitForm, QUANTS } from '@/components/hardware/fit-form'; import { Estimated, OpennessBadge } from '@/components/ui/badges'; import { DataTable, EmptyRow, Td, Th } from '@/components/ui/data-table'; import { EntityLink } from '@/components/ui/entity'; import { Container, Note, PageHeader } from '@/components/ui/section'; import { EmptyState, Unavailable } from '@/components/ui/unavailable'; import { api, ApiError } from '@/lib/api'; import { fmtGb, fmtInt, fmtParams, fmtTokens, num } from '@/lib/format'; import { routes } from '@/lib/site'; import type { HardwareFit } from '@/lib/types'; export const revalidate = 600; type SP = Record; function parseInputs(sp: SP): { memory: number | null; quant: string; context: number; fitsOnly: boolean } { const custom = num(sp.memory_custom); const preset = num(sp.memory_gb); const memory = custom !== null && custom > 0 ? custom : preset !== null && preset > 0 ? preset : null; const quant = QUANTS.some((q) => q.value === sp.quant) ? (sp.quant as string) : '4bit'; const ctx = num(sp.context); const context = ctx !== null && ctx > 0 ? Math.round(ctx) : 8192; return { memory, quant, context, fitsOnly: sp.fits === '1' }; } export async function generateMetadata({ searchParams }: { searchParams: Promise }): Promise { const { memory, quant, context } = parseInputs(await searchParams); const base = 'Hardware fit — which models run on my machine? (estimated)'; const title = memory ? `Models estimated to fit ${fmtGb(memory)} at ${quant}, ${fmtTokens(context)} context` : base; return { title, description: 'Estimate which AI models fit a given amount of device memory at 4-bit, 8-bit or fp16 with a chosen context window. Estimates only — bytes per parameter plus a KV-cache allowance, never a measurement.', alternates: { canonical: memory ? routes.hardwareFit({ memory_gb: memory, quant, context }) : '/hardware/fit' }, }; } export default async function HardwareFitPage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const { memory, quant, context, fitsOnly } = parseInputs(sp); let res: HardwareFit | null = null; let error: string | null = null; if (memory) { try { res = await api.hardwareFit({ memory_gb: memory, quant, context, limit: 200 }); } catch (e) { error = e instanceof ApiError ? e.detail ?? e.message : 'API unreachable'; } } const items = res ? (fitsOnly ? res.items.filter((i) => i.fits) : res.items) : []; const fits = num(res?.counts?.fits) ?? res?.items.filter((i) => i.fits).length ?? null; const evaluated = num(res?.counts?.evaluated) ?? res?.items.length ?? null; const self = (patch: { fits?: boolean }) => routes.hardwareFit({ memory_gb: memory ?? undefined, quant, context }) + (patch.fits ? '&fits=1' : ''); const ctxLabel = CONTEXTS.find((c) => Number(c.value) === context)?.label ?? `${fmtTokens(context)} tokens`; return ( Hardware / Fit tool } title="What fits my machine?" lede="Pick a device memory size, a quantization and a context window: the atlas estimates each model's memory need from its parameter count. Every figure here is an estimate, never a measurement." aside={} >
{!memory ? ( Try 32 GB · 4-bit · 8k, 80 GB · 8-bit · 32k or 192 GB · fp16 · 128k. ) : !res ? ( ) : ( <>

All figures are estimates, not measurements. {fmtGb(memory)} · {QUANTS.find((q) => q.value === quant)?.label.split(' (')[0] ?? quant} · {ctxLabel} {fits !== null && evaluated !== null && ( {fmtInt(fits)} of {fmtInt(evaluated)} models with a known parameter count fit )}

    {res.assumptions.map((a) => (
  • {a}
  • ))} {res.assumptions.length === 0 &&
  • Assumptions unavailable from the API.
  • }

{fitsOnly ? ( Show all evaluated models ) : ( Show only fitting models )} Method →

{items.length === 0 ? ( {fitsOnly ? 'Try a larger memory size or a lower-precision quantization.' : 'Models without a sourced parameter count are not estimated.'} ) : ( Model Params Quant Est. memory Headroom Fits Compare {items.length === 0 && } {items.map((r) => { const openness = typeof r.model.attributes?.openness === 'string' ? r.model.attributes.openness : null; return ( {openness && } {r.model.organization && {r.model.organization.name}} {r.note && {r.note}} {fmtParams(r.parameter_count)} {r.quantization} {fmtGb(r.estimated_memory_gb, 1)} {num(r.headroom_gb) === null ? '—' : `${r.headroom_gb >= 0 ? '+' : '−'}${fmtGb(Math.abs(r.headroom_gb), 1)}`} {r.fits ? '✓ fits' : '✗ too large'} ); })} )} Headroom = device memory − 2 GB reserve − estimated need. Sorted by the API (fitting models first). Compare the models you shortlist with the + buttons. Devices with these memory sizes: hardware listing. )}
); }