11import type { Metadata } from 'next' ;
22
3- import { HW_REGISTRY , SITE_NAME , SITE_URL } from '@semianalysisai/inferencex-constants' ;
3+ import { SITE_NAME , SITE_URL } from '@semianalysisai/inferencex-constants' ;
44
5- import { ComparePairCardLink } from '@/components/compare/compare-pair-card-link ' ;
5+ import { CompareMatrixLegend , ComparePairMatrix } from '@/components/compare/compare-pair-matrix ' ;
66import { JsonLd } from '@/components/json-ld' ;
77import { Card } from '@/components/ui/card' ;
88import { getComparablePairsByModelSlug } from '@/lib/compare-availability' ;
9- import { type ComparePair , COMPARE_MODEL_SLUGS , type CompareModelSlug } from '@/lib/compare-slug' ;
9+ import { COMPARE_MODEL_SLUGS } from '@/lib/compare-slug' ;
1010import { bucketComparePairsByVendor , formatModelList } from '@/lib/compare-ssr' ;
1111
1212export const dynamic = 'force-dynamic' ;
@@ -31,42 +31,6 @@ export const metadata: Metadata = {
3131 } ,
3232} ;
3333
34- interface VendorGroup {
35- heading : string ;
36- description : string ;
37- pairs : { a : string ; b : string ; slug : string ; label : string } [ ] ;
38- }
39-
40- function groupPairsByVendorForModel (
41- model : CompareModelSlug ,
42- comparablePairs : ComparePair [ ] ,
43- ) : VendorGroup [ ] {
44- const { cross, nvidia, amd } = bucketComparePairsByVendor ( model . slug , comparablePairs ) ;
45- const groups : VendorGroup [ ] = [ ] ;
46- if ( cross . length > 0 ) {
47- groups . push ( {
48- heading : 'NVIDIA vs AMD' ,
49- description : 'Cross-vendor cost-per-token comparisons across architecture generations.' ,
50- pairs : cross ,
51- } ) ;
52- }
53- if ( nvidia . length > 0 ) {
54- groups . push ( {
55- heading : 'NVIDIA vs NVIDIA' ,
56- description : 'Hopper and Blackwell generation cost-per-token comparisons.' ,
57- pairs : nvidia ,
58- } ) ;
59- }
60- if ( amd . length > 0 ) {
61- groups . push ( {
62- heading : 'AMD vs AMD' ,
63- description : 'CDNA 3 and CDNA 4 generation cost-per-token comparisons.' ,
64- pairs : amd ,
65- } ) ;
66- }
67- return groups ;
68- }
69-
7034const jsonLd = {
7135 '@context' : 'https://schema.org' ,
7236 '@type' : 'CollectionPage' ,
@@ -78,9 +42,9 @@ const jsonLd = {
7842export default async function ComparePerDollarIndexPage ( ) {
7943 // Server-side filter (Neon availability): only show (model, pair) combos
8044 // where both GPUs have benchmark data for that model. Matches the /compare
81- // index's behavior — no empty-state cards in navigation. The page-level
82- // handler at /compare-per-dollar/[slug] still renders the empty-state for
83- // direct URL hits.
45+ // index's behavior — no empty cells in navigation. The page-level handler at
46+ // /compare-per-dollar/[slug] still renders the empty-state for direct URL
47+ // hits.
8448 const comparablePairsByModel = await getComparablePairsByModelSlug ( ) ;
8549 const totalUrls = [ ...comparablePairsByModel . values ( ) ] . reduce ( ( s , p ) => s + p . length , 0 ) ;
8650 const modelsWithPairs = COMPARE_MODEL_SLUGS . filter (
@@ -101,12 +65,16 @@ export default async function ComparePerDollarIndexPage() {
10165 each page renders the cost-per-token chart and an interpolated dollars-per-million
10266 comparison table so you can pick the cheaper SKU at any target interactivity level.
10367 </ p >
68+ < div className = "mt-5" >
69+ < CompareMatrixLegend />
70+ </ div >
10471 </ Card >
10572 </ section >
10673
10774 { modelsWithPairs . map ( ( model ) => {
10875 const pairs = comparablePairsByModel . get ( model . slug ) ?? [ ] ;
109- const groups = groupPairsByVendorForModel ( model , pairs ) ;
76+ const buckets = bucketComparePairsByVendor ( model . slug , pairs ) ;
77+ const entries = [ ...buckets . nvidia , ...buckets . amd , ...buckets . cross ] ;
11078 return (
11179 < section key = { model . slug } id = { model . slug } >
11280 < Card className = "flex flex-col gap-4" >
@@ -117,30 +85,7 @@ export default async function ComparePerDollarIndexPage() {
11785 benchmark data on { model . label } .
11886 </ p >
11987 </ div >
120- { groups . map ( ( group ) => (
121- < div key = { `${ model . slug } __${ group . heading } ` } className = "flex flex-col gap-3" >
122- < div >
123- < h3 className = "text-base font-semibold" > { group . heading } </ h3 >
124- < p className = "text-xs text-muted-foreground mt-1" > { group . description } </ p >
125- </ div >
126- < div className = "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3" >
127- { group . pairs . map ( ( { slug, label, a, b } ) => {
128- const aMeta = HW_REGISTRY [ a ] ;
129- const bMeta = HW_REGISTRY [ b ] ;
130- const archLine = `${ aMeta ?. arch ?? '—' } · ${ bMeta ?. arch ?? '—' } ` ;
131- return (
132- < ComparePairCardLink
133- key = { slug }
134- href = { `/compare-per-dollar/${ slug } ` }
135- slug = { slug }
136- label = { label }
137- archLine = { archLine }
138- />
139- ) ;
140- } ) }
141- </ div >
142- </ div >
143- ) ) }
88+ < ComparePairMatrix pairs = { entries } hrefPrefix = "/compare-per-dollar" />
14489 </ Card >
14590 </ section >
14691 ) ;
0 commit comments