Skip to content

Commit 38bcb30

Browse files
committed
feat(compare): add indexed per-dollar chart images
1 parent d9b0475 commit 38bcb30

6 files changed

Lines changed: 494 additions & 13 deletions

File tree

packages/app/cypress/e2e/compare-per-dollar-table.cy.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ describe('Compare-per-dollar slug page — slimmed table + cross-link', () => {
5858
it('uses "Performance per Dollar" framing in the page header', () => {
5959
cy.contains('Performance per Dollar').should('be.visible');
6060
});
61+
62+
it('renders an indexable comparison PNG with descriptive alt text', () => {
63+
cy.get('[data-testid="compare-per-dollar-indexed-image"] img')
64+
.should('be.visible')
65+
.and('have.attr', 'src')
66+
.and(
67+
'match',
68+
/\/compare-per-dollar\/deepseek-r1-gb200-vs-h100\/performance-per-dollar\.png$/u,
69+
);
70+
cy.get('[data-testid="compare-per-dollar-indexed-image"] img')
71+
.should('have.attr', 'alt')
72+
.and('contain', 'cost per million tokens at matched interactivity levels');
73+
});
6174
});
6275

6376
describe('Compare slug page — cross-link to per-dollar view', () => {

packages/app/src/app/compare-per-dollar/[slug]/page-client.tsx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ interface ComparePerDollarPageClientProps {
4848
* header so readers can audit the pricing assumptions. */
4949
aCostPerGpuHr: number;
5050
bCostPerGpuHr: number;
51+
/** Crawlable data graphic generated for the canonical default comparison. */
52+
heroImageSrc: string;
5153
}
5254

5355
/** Only show Cost + Concurrency in the interpolated table — the rest of the
@@ -98,6 +100,7 @@ export default function ComparePerDollarPageClient({
98100
bArch,
99101
aCostPerGpuHr,
100102
bCostPerGpuHr,
103+
heroImageSrc,
101104
}: ComparePerDollarPageClientProps) {
102105
useEffect(() => {
103106
track('compare_per_dollar_page_view', { gpu_a: a, gpu_b: b, default_model: defaultModel });
@@ -121,15 +124,15 @@ export default function ComparePerDollarPageClient({
121124
initialYAxisMetric={PER_DOLLAR_DEFAULT_Y_AXIS}
122125
>
123126
<div className="flex flex-col gap-4">
124-
<Card className="flex flex-col gap-3">
127+
<Card className="flex w-full min-w-0 flex-col gap-3">
125128
<header>
126129
<div className="text-xs uppercase tracking-wider text-muted-foreground">
127130
{modelLabel} · Performance per Dollar
128131
</div>
129132
<h1 className="text-2xl lg:text-3xl font-bold tracking-tight mt-1">
130133
{label} Performance per Dollar
131134
</h1>
132-
<p className="mt-2 text-sm text-muted-foreground max-w-3xl">
135+
<p className="mt-2 text-sm text-muted-foreground">
133136
Cost per million tokens of <strong>{aLabel}</strong> ({aVendor} {aArch}) versus{' '}
134137
<strong>{bLabel}</strong> ({bVendor} {bArch}) on <strong>{modelLabel}</strong>.
135138
Owning-hyperscaler TCO normalized by output tokens — performance per dollar across
@@ -143,7 +146,7 @@ export default function ComparePerDollarPageClient({
143146
</p>
144147
{narrative.length > 0 && (
145148
<div
146-
className="mt-3 flex flex-col gap-2 max-w-3xl"
149+
className="mt-3 flex flex-col gap-2"
147150
data-testid="compare-per-dollar-narrative"
148151
>
149152
{narrative.map((para, i) => (
@@ -166,7 +169,7 @@ export default function ComparePerDollarPageClient({
166169
)}
167170
{(aCostPerGpuHr > 0 || bCostPerGpuHr > 0) && (
168171
<p
169-
className="mt-2 text-xs text-muted-foreground max-w-3xl"
172+
className="mt-2 text-xs text-muted-foreground"
170173
data-testid="compare-per-dollar-pricing"
171174
>
172175
GPU pricing (owning hyperscaler): <strong>{aLabel}</strong>{' '}
@@ -195,6 +198,24 @@ export default function ComparePerDollarPageClient({
195198
</Link>
196199
</p>
197200
</header>
201+
<figure
202+
className="mt-2 flex flex-col gap-2"
203+
data-testid="compare-per-dollar-indexed-image"
204+
>
205+
<img
206+
src={heroImageSrc}
207+
alt={`${modelLabel}: ${aLabel} versus ${bLabel} cost per million tokens at matched interactivity levels`}
208+
width={1200}
209+
height={675}
210+
loading="eager"
211+
fetchPriority="high"
212+
className="w-full rounded-lg border border-border/50"
213+
/>
214+
<figcaption className="text-xs text-muted-foreground">
215+
{aLabel} versus {bLabel} cost per million tokens for this comparison's canonical
216+
default workload. Lower cost indicates better performance per dollar.
217+
</figcaption>
218+
</figure>
198219
<CompareTableSection
199220
a={a}
200221
b={b}

packages/app/src/app/compare-per-dollar/[slug]/page.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export default async function ComparePerDollarPage({ params, searchParams }: Pro
120120
);
121121

122122
const url = `${SITE_URL}/compare-per-dollar/${canonical}`;
123+
const imageUrl = `${url}/performance-per-dollar.png`;
123124
const jsonLd = buildJsonLd(
124125
'per-dollar',
125126
parsed.model,
@@ -129,6 +130,7 @@ export default async function ComparePerDollarPage({ params, searchParams }: Pro
129130
summaryA,
130131
summaryB,
131132
ssrRows,
133+
imageUrl,
132134
);
133135
const label = compareModelDisplayLabel(parsed.model, parsed.a, parsed.b);
134136
const aMeta = HW_REGISTRY[parsed.a];
@@ -172,6 +174,7 @@ export default async function ComparePerDollarPage({ params, searchParams }: Pro
172174
bArch={bMeta?.arch ?? ''}
173175
aCostPerGpuHr={aCostPerGpuHr}
174176
bCostPerGpuHr={bCostPerGpuHr}
177+
heroImageSrc={`/compare-per-dollar/${canonical}/performance-per-dollar.png`}
175178
/>
176179
</>
177180
);

0 commit comments

Comments
 (0)