Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 37 additions & 40 deletions packages/app/cypress/e2e/inference-chart.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ describe('Inference Chart', () => {
.and('not.contain.text', 'Workload:')
.and('not.contain.text', 'Precision:')
.and('not.contain.text', 'Metric:');
cy.get('[data-testid="deprecated-watermark"]').should('not.exist');
});

it('plots OpenRouter-priced token revenue for official and unofficial runs', () => {
Expand Down Expand Up @@ -390,8 +389,8 @@ describe('Inference Chart', () => {
});
});

describe('Deprecated model background watermark', () => {
it('marks every deprecated model and clears the mark for an active model', () => {
describe('Deprecated model source attribution', () => {
it('marks every deprecated model in the source, without a background watermark', () => {
cy.viewport(1280, 900);
for (const [display, dbKey, deprecated] of [
['MiniMax-M3', 'minimaxm3', true],
Expand All @@ -411,19 +410,14 @@ describe('Deprecated model background watermark', () => {
onBeforeLoad: unlockAgenticGate,
});
cy.get('#chart-0 svg[data-testid="d3-chart-svg"]').should('be.visible');
if (deprecated) {
cy.get('#chart-0 .deprecated-watermark')
.should('have.length', 2)
.each(($mark) => {
cy.wrap($mark).should('have.text', 'Deprecated').and('have.attr', 'opacity', '0.3');
});
} else {
cy.get('#chart-0 .deprecated-watermark').should('not.exist');
}
cy.get('#chart-0 [data-testid="result-context"]')
.should('contain.text', 'Source: SemiAnalysis InferenceX™')
.and(deprecated ? 'contain.text' : 'not.contain.text', '(deprecated)');
cy.get('.deprecated-watermark').should('not.exist');
}
});

it('keeps a large plot watermark in PNG exports, overlays, and the Chinese mobile chart', () => {
it('keeps the suffix in PNG exports, overlays, and the Chinese mobile chart', () => {
const model = 'minimaxm3';
const officialRows = b300Rows(null).map((row) => ({ ...row, model }));
const overlayRows = b300Rows(OVERLAY_RUN_URL).map((row) => ({ ...row, model }));
Expand Down Expand Up @@ -454,58 +448,61 @@ describe('Deprecated model background watermark', () => {
cy.visit('/inference/minimax-m3?i_seq=agentic-traces', {
onBeforeLoad: unlockAgenticGate,
});
cy.get('#chart-0 [data-testid="result-context"]')
.should('contain.text', 'Source: SemiAnalysis InferenceX™')
.and('not.contain.text', 'Historical benchmark — submissions closed');
cy.get('#chart-0 svg [data-testid="deprecated-watermark"]').should('be.visible');
cy.get('#chart-0 [data-testid="result-context"]').should(
'contain.text',
'Source: SemiAnalysis InferenceX™ (deprecated)',
);
let exportedPng = '';
let exportedLabels: string[] = [];
let exportedCaption = '';
cy.window().then((win) => {
win.HTMLAnchorElement.prototype.click = function () {
if (this.download.endsWith('.png')) {
exportedPng = this.href;
exportedLabels = [
...win.document.querySelectorAll('#chart-0-export .deprecated-watermark'),
].map((mark) => mark.textContent ?? '');
exportedCaption =
win.document.querySelector('#chart-0-export [data-testid="result-context"]')
?.textContent ?? '';
expect(win.document.querySelector('#chart-0-export .deprecated-watermark')).to.equal(
null,
);
}
};
});
cy.get('[data-testid="chart-figure"] [data-testid="export-button"]').first().click();
cy.get('[data-testid="export-png-button"]').click();
cy.window()
.should(() => expect(exportedPng).to.match(/^data:image\/png;base64,/u))
.then(() => {
expect(exportedLabels).to.deep.equal(['Deprecated', 'Deprecated']);
cy.writeFile(
'cypress/downloads/deprecated-model-watermark.png',
exportedPng.split(',')[1],
'base64',
);
});
cy.window().should(() => {
expect(exportedPng).to.match(/^data:image\/png;base64,/u);
expect(exportedCaption).to.contain('Source: SemiAnalysis InferenceX™ (deprecated)');
});

cy.visit(`/inference/minimax-m3?i_seq=agentic-traces&unofficialrun=${OVERLAY_RUN_ID}`, {
onBeforeLoad: unlockAgenticGate,
});
cy.wait('@historicalM3Overlay');
cy.get('#chart-0 .unofficial-overlay-pt').should('have.length.greaterThan', 0);
cy.get('#chart-0 .deprecated-watermark').should('contain.text', 'Deprecated');
cy.get('#chart-0 [data-testid="result-context"]').should(
'contain.text',
'Source: SemiAnalysis InferenceX™ + UNOFFICIAL overlays (deprecated)',
);
cy.get('#chart-0 .unofficial-watermark-image').should('exist');
cy.get('.deprecated-watermark').should('not.exist');
cy.get('[aria-label="Dismiss historical-m3-overlay"]').click();
cy.get('#chart-0 .unofficial-overlay-pt').should('not.exist');
cy.get('#chart-0 svg [data-testid="deprecated-watermark"]').should('be.visible');
cy.get('#chart-0 [data-testid="result-context"]').should(
'contain.text',
'Source: SemiAnalysis InferenceX™ (deprecated)',
);

cy.viewport(375, 900);
cy.visit(`/zh/inference/minimax-m3?i_seq=agentic-traces&unofficialrun=${OVERLAY_RUN_ID}`, {
onBeforeLoad: unlockAgenticGate,
});
cy.wait('@historicalM3Overlay');
cy.get('#chart-0 svg [data-testid="deprecated-watermark"]')
.should('be.visible')
.and('have.length', 2)
.each(($mark) => cy.wrap($mark).should('have.text', '已弃用'));
cy.document().then((doc) => {
expect(doc.documentElement.scrollWidth).to.be.at.most(doc.documentElement.clientWidth);
});
cy.get('#chart-0 [data-testid="result-context"]').should(
'contain.text',
'来源: SemiAnalysis InferenceX™ + 非官方 overlays (已弃用)',
);
cy.get('.deprecated-watermark').should('not.exist');
expectNoPageOverflow();
});
});

Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/components/inference/ui/ChartDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import {
getModelLabel,
getPrecisionLabel,
getSequenceLabel,
isModelDeprecated,
sequenceKind,
} from '@/lib/catalog/data-mappings';
import { useComparisonChangelogs } from '@/hooks/api/use-comparison-changelogs';
Expand Down Expand Up @@ -1085,6 +1086,7 @@ export default function ChartDisplay({ embedded = false }: { embedded?: boolean
</div>
<ResultContext
locale={locale}
deprecated={isModelDeprecated(selectedModel)}
precision={
embedded
? selectedPrecisions
Expand Down
7 changes: 1 addition & 6 deletions packages/app/src/components/inference/ui/GPUGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ import {
getInferenceRunLabel,
getOverlayLineLabel,
} from '@/lib/benchmarks/inference-labels';
import {
getChartWatermark,
getDeprecatedChartWatermark,
Sequence,
} from '@/lib/catalog/data-mappings';
import { getChartWatermark, Sequence } from '@/lib/catalog/data-mappings';
import { useLocale } from '@/lib/i18n/use-locale';
import { formatNumber, getDisplayLabel, updateRepoUrl } from '@/lib/shared/utils';
import { perfRulerAxisMetricKey, usePerfRulerAxisReset } from '@/hooks/usePerfRulerAxisReset';
Expand Down Expand Up @@ -1314,7 +1310,6 @@ const GPUGraph = React.memo(
data={officialPoints}
margin={CHART_MARGIN}
watermark={getChartWatermark()}
backgroundWatermark={getDeprecatedChartWatermark(modelLabel, locale)}
testId="gpu-graph"
grabCursor={true}
caption={caption}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import { lttbDownsample } from '@/lib/d3-chart/downsample';
import { CHART_FONT_SANS, CHART_TYPE, px } from '@/lib/d3-chart/typography';
import { overlayRunColor, overlayRunIndex } from '@/lib/charts/overlay-run-style';
import { useLocale } from '@/lib/i18n/use-locale';
import { getDeprecatedChartWatermark } from '@/lib/catalog/data-mappings';
import { getDisplayLabel } from '@/lib/shared/utils';

import {
Expand Down Expand Up @@ -629,8 +628,7 @@ export default function PowerTimeline({
const locale = useLocale();
const t = STRINGS[locale];
const { hardwareConfig, hwTypesWithData } = useInferenceData();
const { activeHwTypes, selectedPrecisions, quickFilters, activeDates, selectedModel } =
useInferenceFilters();
const { activeHwTypes, selectedPrecisions, quickFilters, activeDates } = useInferenceFilters();
const { isLegendExpanded, highContrast } = useInferenceDisplay();
const { setBestPerSku, toggleHwType, setIsLegendExpanded, toggleActiveDate } =
useInferenceActions();
Expand Down Expand Up @@ -1425,7 +1423,6 @@ export default function PowerTimeline({
height={CHART_HEIGHT}
margin={MARGIN}
watermark={overlayData && overlayPoints.length > 0 ? 'unofficial' : 'logo'}
backgroundWatermark={getDeprecatedChartWatermark(selectedModel, locale)}
testId="power-timeline-chart-svg"
grabCursor
instructions={t.instructions}
Expand Down
2 changes: 0 additions & 2 deletions packages/app/src/components/inference/ui/ScatterGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ import {
} from '@/lib/catalog/constants';
import {
getChartWatermark,
getDeprecatedChartWatermark,
getPrecisionLabel,
getSequenceLabel,
type Precision,
Expand Down Expand Up @@ -3724,7 +3723,6 @@ const ScatterGraph = React.memo(
metricIdentity={metricIdentity}
margin={CHART_MARGIN}
watermark={getChartWatermark(isUnofficialRun)}
backgroundWatermark={getDeprecatedChartWatermark(modelLabel, locale)}
testId="scatter-graph"
grabCursor={true}
caption={caption}
Expand Down
31 changes: 31 additions & 0 deletions packages/app/src/components/ui/result-context.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,37 @@ function renderContext(locale: 'en' | 'zh') {
}

describe('ResultContext', () => {
it.each([
['en', 'SemiAnalysis InferenceX™', 'Source: SemiAnalysis InferenceX™ (deprecated)'],
['zh', 'SemiAnalysis InferenceX™', '来源: SemiAnalysis InferenceX™ (已弃用)'],
[
'en',
'SemiAnalysis InferenceX™ + UNOFFICIAL overlays',
'Source: SemiAnalysis InferenceX™ + UNOFFICIAL overlays (deprecated)',
],
[
'zh',
'SemiAnalysis InferenceX™ + 非官方 overlays',
'来源: SemiAnalysis InferenceX™ + 非官方 overlays (已弃用)',
],
] as const)('appends the deprecated status to the %s source %s', (locale, source, expected) => {
const container = document.createElement('div');
const root = createRoot(container);
act(() => root.render(<ResultContext locale={locale} source={source} deprecated />));
expect(container.textContent).toBe(expected);
act(() => root.render(<ResultContext locale={locale} source={source} deprecated={false} />));
expect(container.textContent).toBe(`${locale === 'zh' ? '来源' : 'Source'}: ${source}`);
act(() => root.unmount());
});

it('does not render an orphan deprecated label without a source', () => {
const container = document.createElement('div');
const root = createRoot(container);
act(() => root.render(<ResultContext locale="en" deprecated />));
expect(container.textContent).toBe('');
act(() => root.unmount());
});

it('renders all effective result inputs in English', () => {
const context = renderContext('en');
expect(context.querySelector('[data-testid="result-context"]')?.textContent).toContain(
Expand Down
7 changes: 6 additions & 1 deletion packages/app/src/components/ui/result-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface ResultContextProps {
dates?: readonly string[];
dateRange?: { start: string; end: string };
source?: string;
deprecated?: boolean;
costBasis?: string;
costBasisTestId?: string;
}
Expand Down Expand Up @@ -83,6 +84,7 @@ export function ResultContext({
dates,
dateRange,
source,
deprecated = false,
costBasis,
costBasisTestId,
}: ResultContextProps) {
Expand Down Expand Up @@ -204,7 +206,10 @@ export function ResultContext({
{source && (
<div>
<dt className="inline font-medium text-foreground">{labels.source}:</dt>{' '}
<dd className="inline">{source}</dd>
<dd className="inline">
{source}
{deprecated && (locale === 'zh' ? ' (已弃用)' : ' (deprecated)')}
</dd>
</div>
)}
{costBasis && (
Expand Down
22 changes: 0 additions & 22 deletions packages/app/src/lib/catalog/data-mappings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
getModelAndSequence,
getModelAndSequenceFromArtifact,
getModelLabel,
getDeprecatedChartWatermark,
getOpenRouterModelId,
MODEL_OPTIONS,
SEQUENCE_OPTIONS,
Expand Down Expand Up @@ -168,27 +167,6 @@ describe('getModelAndSequenceFromArtifact', () => {
});

describe('isModelDeprecated', () => {
it.each([
Model.MiniMax_M3,
Model.MiniMax_M2_5,
Model.Kimi_K2_5,
Model.GLM_5,
Model.GptOss,
Model.Llama3_3_70B,
])('adds a localized Deprecated watermark to %s', (model) => {
expect(getDeprecatedChartWatermark(model, 'en')).toBe('Deprecated');
expect(getDeprecatedChartWatermark(model, 'zh')).toBe('已弃用');
});

it.each([
Model.MiniMax_M3_1_Flash,
Model.DeepSeek_R1,
Model.Qwen3_8_27B,
Model.Llama3_1_70B,
undefined,
])('does not mark the non-deprecated model %s', (model) => {
expect(getDeprecatedChartWatermark(model, 'en')).toBeUndefined();
});
it('returns true for deprecated model Llama3_3_70B', () => {
expect(isModelDeprecated(Model.Llama3_3_70B)).toBe(true);
});
Expand Down
8 changes: 0 additions & 8 deletions packages/app/src/lib/catalog/data-mappings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,6 @@ export function getChartWatermark(isUnofficialRun = false): 'logo' | 'unofficial
return isUnofficialRun ? 'unofficial' : 'logo';
}

export function getDeprecatedChartWatermark(
model: string | undefined,
locale: 'en' | 'zh',
): string | undefined {
if (!model || !isModelDeprecated(model as Model)) return undefined;
return locale === 'zh' ? '已弃用' : 'Deprecated';
}

export const MODEL_PREFIX_MAPPING: Record<string, Model> = Object.fromEntries(
(Object.entries(MODEL_CONFIG) as [Model, (typeof MODEL_CONFIG)[Model]][])
.filter(([, c]) => c.prefix)
Expand Down
2 changes: 0 additions & 2 deletions packages/app/src/lib/d3-chart/D3Chart/D3Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ function D3ChartInner<T>(
height = 600,
margin,
watermark,
backgroundWatermark,
testId,
grabCursor = true,
instructions,
Expand Down Expand Up @@ -108,7 +107,6 @@ function D3ChartInner<T>(
height,
margin,
watermark,
backgroundWatermark,
testId,
grabCursor,
instructions,
Expand Down
1 change: 0 additions & 1 deletion packages/app/src/lib/d3-chart/D3Chart/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ export interface D3ChartProps<T = any> {
height?: number;
margin?: ChartMargin;
watermark?: 'logo' | 'unofficial' | 'none';
backgroundWatermark?: string;
testId?: string;
grabCursor?: boolean;
instructions?: string;
Expand Down
3 changes: 0 additions & 3 deletions packages/app/src/lib/d3-chart/D3Chart/useD3ChartRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,6 @@ export function useD3ChartRenderer<T>(props: D3ChartProps<T>, deps: RendererDeps
data,
margin = { top: 24, right: 10, bottom: 40, left: 60 },
watermark = 'logo',
backgroundWatermark,
clipContent = true,
dataIdentity,
metricIdentity,
Expand Down Expand Up @@ -318,7 +317,6 @@ export function useD3ChartRenderer<T>(props: D3ChartProps<T>, deps: RendererDeps
containerHeight: dimensions.height,
margin,
watermark: getDomainAwareChartWatermark(watermark, window.location.hostname),
backgroundWatermark,
xLabel: xAxisConfig?.label,
yLabel: yAxisConfig?.label,
clipContent,
Expand All @@ -333,7 +331,6 @@ export function useD3ChartRenderer<T>(props: D3ChartProps<T>, deps: RendererDeps
margin.bottom,
margin.left,
watermark,
backgroundWatermark,
xAxisConfig?.label,
yAxisConfig?.label,
clipContent,
Expand Down
Loading
Loading