feat(inference): add token revenue and profit per GW-year y-axes / 新增每吉瓦年 token 收入与利润 Y 轴指标 - #973
feat(inference): add token revenue and profit per GW-year y-axes / 新增每吉瓦年 token 收入与利润 Y 轴指标#973functionstackx wants to merge 3 commits into
Conversation
Add four y-axis metrics that reuse the normalized/OpenRouter token sale pricing path behind Token Revenue per GPU Hour: - tokenRevenuePerMwYear: $/GPU/hr revenue x (1000 / all-in kW per GPU) x 8760 - tokenProfitPerMwYearH/N/R: ($/GPU/hr revenue - costh|costn|costr) x the same GPU-hours per MW-year; negative when sale prices sit below TCO Generalize the price-source axis labels, the Historical Trends interpolation, and applyTokenRevenuePricing over TOKEN_SALE_PRICING_METRIC_KEYS so every sale-priced metric shares one pricing path. Let the linear y-domain in ScatterGraph, GPUGraph, and TrendChart extend below zero only when the data does, so negative profit stays visible. Add bilingual axis explanations, docs, and unit tests. 中文:新增四个 Y 轴指标,复用每 GPU 小时 token 收入所用的标准化/OpenRouter token 售价路径: tokenRevenuePerMwYear 为 $/GPU/hr 收入 ×(1000 ÷ 每 GPU 全电源配置 kW)× 8760; tokenProfitPerMwYearH/N/R 为($/GPU/hr 收入 − costh|costn|costr)× 相同的每兆瓦年 GPU 小时数, 售价低于 TCO 时为负值。将价格来源轴标签、历史趋势插值以及 applyTokenRevenuePricing 统一泛化到 TOKEN_SALE_PRICING_METRIC_KEYS,使所有按售价计算的指标共用同一条定价路径。 ScatterGraph、GPUGraph 与 TrendChart 的线性 Y 轴仅在数据为负时才向下延伸,以保留负利润的可见性。 补充中英双语指标说明、文档与单元测试。
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| return { | ||
| type: (useLog ? 'log' : 'linear') as 'log' | 'linear', | ||
| domain: [yMin, ext[1] * 1.05] as [number, number], | ||
| domain: [yMin, yMax] as [number, number], |
There was a problem hiding this comment.
Log scale drops negative profits
Medium Severity
Linear y-domains now extend below zero for profit, but a log y-scale still substitutes 0.1 when the extent is non-positive and does not keep signed values. With log scale left on, negative profit points become invalid log inputs and disappear, or the domain inverts when every point is a loss.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit a1ccaa4. Configure here.
Rename tokenRevenuePerMwYear and tokenProfitPerMwYearH/N/R to their GW-year equivalents and scale GPU-hours by 1,000,000 kW per GW instead of 1,000 kW per MW. Update labels, bilingual explanations, docs, and tests. Add a billions tier to formatLargeNumber so $/GW/yr ticks render as "36.9B" rather than "36900.0M". 中文:将 tokenRevenuePerMwYear 与 tokenProfitPerMwYearH/N/R 重命名为对应的每吉瓦年指标, GPU 小时数按每 GW 1,000,000 kW(而非每 MW 1,000 kW)换算。同步更新标签、中英双语说明、 文档与测试。为 formatLargeNumber 新增十亿(B)档位,使 $/GW/yr 刻度显示为 "36.9B" 而非 "36900.0M"。
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit efb6fc2. Configure here.
| // zero for every other metric so throughput charts still start at 0. | ||
| yMin = ext[0] < 0 ? ext[0] - range * 0.05 : Math.max(0, ext[0] - range * 0.05); | ||
| } | ||
| const yMax = ext[1] >= 0 ? ext[1] * 1.05 : ext[1] + range * 0.05; |
There was a problem hiding this comment.
Collapsed domain for uniform negative profit
Medium Severity
All-negative max padding uses yRange * 0.05, so a single point or identical profits collapse to a [v, v] y-domain. Positive points still get max * 1.05 even when the range is zero, so a lone negative profit point gets a degenerate axis while a lone positive one does not.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit efb6fc2. Configure here.


Summary
Adds four y-axis metrics that reuse the normalized/OpenRouter token sale pricing path already behind Token Revenue per GPU Hour:
tokenRevenuePerGwYear$/GPU/hr revenue × (1,000,000 ÷ all-in kW per GPU) × 8760tokenProfitPerGwYearH($/GPU/hr revenue − costh) × GPU-hours per GW-yeartokenProfitPerGwYearN($/GPU/hr revenue − costn) × GPU-hours per GW-yeartokenProfitPerGwYearR($/GPU/hr revenue − costr) × GPU-hours per GW-yearpowerandcosth/costn/costrcome fromHW_REGISTRY, same astpPerMwand the tokens-per-dollar axes. Profit can be negative when the sale price does not cover TCO at that operating point.Changes
token-revenue.ts:TOKEN_SALE_PRICING_METRIC_KEYS,gpuHoursPerGwYear,tokenRevenuePerGwYear,tokenProfitPerGwYear,tokenSalePricingMetricFromRevenuePerGpuHour,tokenSalePricingLabels.usesTokenSalePricingandapplyTokenRevenuePricingnow cover all five sale-priced keys, so the OpenRouter price-source selector, subtitle, and URL state (i_revenue) work for the new axes without further wiring.metric-registry.ts: four registry entries; the "Token Revenue per GPU Hour" control group becomes "Token Revenue" (GPU-hour + GW-year) and a "Token Profit per All in Utility GW per Year" group holds the three tiers.chart-utils.ts: normalized placeholders inbuildDerivedChartFields(zero when hardware lacks power or tier cost).chart-rendering.ts:formatLargeNumbergains a billions tier so $/GW/yr ticks read36.9Binstead of36900.0M.useChartData.ts: axis label/title price-source suffix is now generic viatokenSalePricingLabels; existing "Token Revenue per GPU Hour at OpenRouter Pricing ($/GPU/hr)" strings are reproduced byte-for-byte (asserted in tests).useInterpolatedTrendData.ts: Historical Trends interpolates priced $/GPU/hr revenue once and maps it through the new helper.tokenRevenuePerGwYearjoinsPROPORTIONAL_TO_THROUGHPUT; profit is affine so it is deliberately excluded.ScatterGraph/GPUGraph/TrendChart: linear y-domain extends below zero only when data does (other metrics keep the zero floor); max padding handles all-negative extents.axis-metric-explanations.ts: bilingual descriptions and formulas.docs/data-transforms.md: documents the new fields.Testing
bun run typecheck,bun run lint,bun run fmt, pre-commit typography check: clean.bun run test:unit: 4321 passed. New tests cover B200/H200/H100 GPU-hours math, per-tier profit, negative profit,applyTokenRevenuePricingclearing and repricing all five keys, label generation,createChartDataPointplaceholders, Historical Trends interpolation for the new axes, and the billions formatter tier.benchmark-transform.test.ts,Object.groupBy) is a Node 20 sandbox limitation and reproduces onmaster.中文说明
新增四个 Y 轴指标,复用「每 GPU 小时 token 收入」已有的标准化/OpenRouter token 售价路径:
tokenRevenuePerGwYear:$/GPU/hr 收入 ×(1,000,000 ÷ 每 GPU 全电源配置 kW)× 8760,即 1 GW 全电源配置功率一年的 token 毛收入。tokenProfitPerGwYearH/N/R:($/GPU/hr 收入 − costh|costn|costr)× 每吉瓦年 GPU 小时数,分别对应超大规模自有、Neocloud Giant 自有与 3 年租赁的 TCO。售价低于 TCO 时为负值。power与costh/costn/costr均取自HW_REGISTRY,与tpPerMw及 tokens-per-dollar 指标一致。主要改动:
usesTokenSalePricing与applyTokenRevenuePricing统一泛化到TOKEN_SALE_PRICING_METRIC_KEYS,OpenRouter 价格来源选择器、副标题与 URL 状态自动覆盖新指标;轴标签与标题的价格来源后缀改为通用逻辑,原有字符串保持不变;历史趋势插值先计算带价格的 $/GPU/hr 收入,再映射到各指标;ScatterGraph、GPUGraph、TrendChart的线性 Y 轴仅在数据为负时向下延伸;formatLargeNumber新增十亿(B)档位;补充中英双语指标说明、文档与单元测试。测试:
bun run typecheck、bun run lint、bun run fmt均通过;bun run test:unit4321 个用例通过,唯一失败项(Object.groupBy)为 Node 20 环境限制,在master上同样复现。Note
Medium Risk
Touches derived chart math, sale-price pricing, and Y-axis scaling across scatter/GPU/trend charts; changes are well-tested but affect business-facing dollar metrics and trend interpolation.
Overview
Adds four inference Y-axis metrics that scale cache-aware token sale pricing from $/GPU/hr to $/GW/yr using all-in kW per GPU from
HW_REGISTRY: grosstokenRevenuePerGwYearand nettokenProfitPerGwYearH/N/R(hyperscaler, Neocloud Giant, and 3-year rental TCO). Profit can be negative when sale price does not cover the tier hourly cost.Token sale pricing is generalized via
TOKEN_SALE_PRICING_METRIC_KEYSand helpers (gpuHoursPerGwYear,tokenSalePricingMetricFromRevenuePerGpuHour,tokenSalePricingLabels).applyTokenRevenuePricingandusesTokenSalePricingnow cover all five sale-priced axes so OpenRouter/normalized source selection, subtitles, and URL state apply without extra wiring. Axis labels name the active price source for every sale-priced metric, not only GPU-hour revenue.Charts and trends:
buildDerivedChartFieldsemits normalized GW-year placeholders; Historical Trends interpolates priced $/GPU/hr once and maps through the shared helper (profit axes are affine, not proportional throughput). ScatterGraph, GPUGraph, and TrendChart allow linear Y domains below zero when data warrants it.formatLargeNumberadds a B tier for billion-scale ticks.Metric registry control groups, bilingual axis explanations, docs (
data-transforms.md), and unit tests are updated accordingly.Reviewed by Cursor Bugbot for commit efb6fc2. Bugbot is set up for automated code reviews on this repo. Configure here.