Skip to content

Improve models page pricing summaries and hover cards#474

Merged
DanielButler1 merged 3 commits into
mainfrom
feat/models-pricing-hovercards-20260507
May 7, 2026
Merged

Improve models page pricing summaries and hover cards#474
DanielButler1 merged 3 commits into
mainfrom
feat/models-pricing-hovercards-20260507

Conversation

@DanielButler1

@DanielButler1 DanielButler1 commented May 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR improves pricing presentation on the main /models catalogue so the model cards and pricing hover cards are descriptive for non-trivial pricing structures instead of being misleading or incomplete.

Problem

The list view was reasonably fine for simple text-token pricing, but it broke down for media and tiered models.

Users were seeing several concrete issues:

  • provider-backed pricing rows from the monitor RPC were incomplete for image, audio, and video meters
  • the /models index could silently miss pricing detail rows that were available in the underlying pricing rules
  • image and video hover cards either showed too little detail, showed repetitive labels, or hid important output-side pricing entirely
  • tiered text models such as x-ai/grok-4.3 surfaced duplicate input/output prices with no explanation of the context threshold behind them
  • GPT Image family cards could show compressed summaries that did not line up with what the hover card explained, which made the cards hard to trust

Root Cause

There were two broad causes:

  • the monitor feed and models-page aggregation were only carrying a narrow set of pricing fields, so richer pricing-rule context was lost before the card renderer saw it
  • the card renderer was optimized for simple text pricing and did not have good grouping rules for image, video, or tiered text variants

What changed

Monitor feed and aggregation

  • paged the get_monitor_model_rows RPC fetch so the /models index no longer truncates at 1000 rows
  • supplemented monitor rows with active pricing-rule data from data_api_pricing_rules
  • added support for media meters and richer detail rows in the monitor-model types and aggregation path
  • preserved pricing detail rows through the models-page compact-card projection
  • fixed null/zero coercion issues so missing standard prices do not overwrite supplemented pricing data

Pricing detail labelling

  • added variant extraction for image quality and resolution
  • added variant extraction for video resolution, duration, and audio/no-audio distinctions
  • added context-threshold labels for tiered text models like Grok (Up to 200K context, Over 200K context)
  • normalized image quality labels to title case

Card and hover-card UX

  • enabled pricing hover cards for non-text models instead of leaving them inert
  • merged explicit pricing rows with fallback rows so input/output information is not dropped
  • improved compressed summary chips for media models, including cheapest-tier signalling where appropriate
  • grouped repeated rows under shared headings instead of repeating labels like Video Output over and over
  • simplified dense image output pricing to a single descriptive range in the hover card when the full quality breakdown is too noisy for a list view
  • made hover-card width size to content more naturally instead of forcing a narrow fixed width

Result

The /models cards now behave much more like a lightweight version of the individual model pricing pages:

  • image models show input costs and a meaningful basic output range
  • video models show grouped output pricing with audio/no-audio and resolution distinctions
  • tiered text models explain why multiple prices exist instead of looking broken
  • summary chips and hover-card details line up much better, which makes the catalogue easier to trust when scanning quickly

Validation

  • pnpm --filter @ai-stats/web typecheck

Scope

This PR is intentionally limited to the web models catalogue pricing/feed path:

  • apps/web/src/lib/fetchers/models/table-view/getMonitorModels.ts
  • apps/web/src/app/(dashboard)/models/page.tsx
  • apps/web/src/components/(data)/models/Models/ModelCard.tsx
  • supporting types in the related models fetcher files

Summary by CodeRabbit

  • New Features
    • Improved pricing display on model cards with enhanced organization and structured grouping of pricing information
    • Modality-aware pricing presentation with specialized formatting for different pricing variant types
    • More compact and readable pricing summaries for models with multiple pricing tiers

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Rate limit exceeded

@DanielButler1 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 17 seconds before requesting another review.

To continue reviewing without waiting, purchase usage credits in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3719fd7d-d44e-496a-8018-9bb485be350f

📥 Commits

Reviewing files that changed from the base of the PR and between 5460872 and be7216e.

📒 Files selected for processing (2)
  • apps/web/src/components/(data)/models/Models/ModelCard.tsx
  • apps/web/src/lib/fetchers/models/table-view/getMonitorModels.ts
📝 Walkthrough

Walkthrough

This PR extends the models display system to track and render pricing detail rows as structured { label, value } pairs. Pricing supplements are computed from database rules, passed through the data pipeline, and rendered in the ModelCard with modality-aware grouping for image and video outputs.

Changes

Pricing Detail Rows Data Flow

Layer / File(s) Summary
Type Definitions & Contracts
apps/web/src/lib/fetchers/models/getAllModels.ts, apps/web/src/components/(data)/models/Models/modelsDisplay.types.ts, apps/web/src/lib/fetchers/models/table-view/types.ts
ModelCard, ModelsPageModel, MonitorModelData.provider, and PricingSupplement types are extended with optional pricingDetailRows or pricing_detail_rows fields (Array<{ label: string; value: string }>) to carry structured pricing row data through the system.
Pricing Computation & Fetching
apps/web/src/lib/fetchers/models/table-view/getMonitorModels.ts
New pricing helpers determine rule activity by effective dates, normalize display units, compute display prices from pricing-rule semantics (token/time scaling), and format variant labels (quality, resolution, audio). The fetchPricingSupplements function queries data_api_pricing_rules in chunks, deduplicates and groups detail rows by unit/variant, truncates to 6 entries, and returns a map from modelKey to PricingSupplement. Provider pricing fields are assigned from RPC values when present, otherwise fall back to computed supplements.
UI Pricing Display & Rendering
apps/web/src/components/(data)/models/Models/ModelCard.tsx
New helpers (inferPriceUnitFromModality, summarizePricingValues) infer units from modality keys and condense image-output pricing into range strings. Structured pricing summaries are computed by combining input/output prices with modality awareness and cheapest-tier + suffixing. Detail rows are rebuilt with modality-aware fallback labels/units and merged via a map. The hover tooltip is rewritten to render grouped pricing detail rows with specialized variant-aware rendering for image output groups (using price range summarization) and video output groups (splitting into "With audio"/"No audio" sections).
Dashboard Gateway Signal Aggregation
apps/web/src/app/(dashboard)/models/page.tsx
GatewaySignals type now includes pricingDetailRows. createEmptyGatewaySignals() initializes it to an empty array. aggregateGatewaySignals() iterates over incoming row.provider.pricingDetailRows, de-duplicates by (label, value) pair, and appends new entries. withGatewayMetadata() populates pricing_detail_rows on each compactModel from the aggregated rows, limited to 6 items.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • AI-Stats/AI-Stats#418: Both PRs modify ModelCard.tsx's pricing display and label logic, restructuring summaries and pricing rows for improved rendering.
  • AI-Stats/AI-Stats#307: Both PRs make related changes to the model pricing data flow, adding and populating pricingDetailRows throughout fetchers, types, and UI wiring.

Poem

🐰 A pricing row hops through the pipeline so neat,
From rules to summaries, a modality feat!
Image groups sparkle, videos split with care,
Detail rows grouped and truncated with flair.
The gateway aggregates—deduplicated true,
Compact dashboards now know what to show you! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Improve models page pricing summaries and hover cards' clearly and concisely summarizes the main change: enhancing pricing presentation on the models page through improved summaries and hover card displays.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/models-pricing-hovercards-20260507

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54608722ad

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/web/src/lib/fetchers/models/table-view/getMonitorModels.ts
Comment thread apps/web/src/lib/fetchers/models/table-view/getMonitorModels.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/web/src/components/(data)/models/Models/ModelCard.tsx (1)

994-1078: 💤 Low value

Hardcoded label strings create fragile coupling across files.

The specialized rendering branches at lines 994 (group.baseLabel === "Image Output") and 1011 (group.baseLabel === "Video Output") rely on exact string matches against labels produced in getMonitorModels.ts (lines 184 and 190). If those label strings are ever renamed or localized in the server-side fetcher, the specialized rendering silently falls through to the generic renderer with no type or test signal.

Consider attaching a kind: "image_output" | "video_output" discriminator to each pricing row when it is built in getMonitorModels.ts, or export the label strings from a shared constants module that both files import.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/`(data)/models/Models/ModelCard.tsx around lines 994
- 1078, The rendering logic in ModelCard.tsx branches on fragile baseLabel
string checks (group.baseLabel === "Image Output" / "Video Output"); update the
data shape in getMonitorModels.ts to include a stable discriminator (e.g., add
kind: "image_output" | "video_output" on each pricing row) or export canonical
label constants from a shared module and use those constants here; then replace
the string comparisons in ModelCard.tsx (the checks around group.baseLabel and
the audio grouping logic using getVideoAudioGroup) to check the new kind
property or imported constants so rendering no longer depends on literal label
text.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/components/`(data)/models/Models/ModelCard.tsx:
- Around line 636-654: The input fallback row uses formatFromPrice (producing
"$X per Y") while the output and other rows use the "$X / Y" style; update the
fallbackPricingRows creation so the "input" row uses the same formatter as the
"output" row (replace formatFromPrice with formatPriceWithUnit for the
model.lowest_input_price value, preserving any relevant options like allowZero
behavior) so both input and output rows render with a consistent "$X / Y"
format; keep the existing .filter(Boolean) logic unchanged.

In `@apps/web/src/lib/fetchers/models/table-view/getMonitorModels.ts`:
- Around line 219-226: The decimal cutoff logic in formatPriceAmount is
inconsistent with the client-side formatter used in ModelCard.tsx (formatPrice),
causing differing precision for the same price; update formatPriceAmount to use
the same threshold values as formatPrice in ModelCard.tsx (adjust the 3-decimal
cutoff from <0.1 to <0.01 and ensure the surrounding branches match the same
boundaries), then run the UI where formatDetailValue and ModelCard use these
formatters to verify identical output.

---

Nitpick comments:
In `@apps/web/src/components/`(data)/models/Models/ModelCard.tsx:
- Around line 994-1078: The rendering logic in ModelCard.tsx branches on fragile
baseLabel string checks (group.baseLabel === "Image Output" / "Video Output");
update the data shape in getMonitorModels.ts to include a stable discriminator
(e.g., add kind: "image_output" | "video_output" on each pricing row) or export
canonical label constants from a shared module and use those constants here;
then replace the string comparisons in ModelCard.tsx (the checks around
group.baseLabel and the audio grouping logic using getVideoAudioGroup) to check
the new kind property or imported constants so rendering no longer depends on
literal label text.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4d3d0cfc-f27a-4112-a345-8e2bb0eae46c

📥 Commits

Reviewing files that changed from the base of the PR and between dfe44e5 and 5460872.

📒 Files selected for processing (6)
  • apps/web/src/app/(dashboard)/models/page.tsx
  • apps/web/src/components/(data)/models/Models/ModelCard.tsx
  • apps/web/src/components/(data)/models/Models/modelsDisplay.types.ts
  • apps/web/src/lib/fetchers/models/getAllModels.ts
  • apps/web/src/lib/fetchers/models/table-view/getMonitorModels.ts
  • apps/web/src/lib/fetchers/models/table-view/types.ts

Comment thread apps/web/src/components/(data)/models/Models/ModelCard.tsx
Comment thread apps/web/src/lib/fetchers/models/table-view/getMonitorModels.ts
@DanielButler1 DanielButler1 merged commit 5829b78 into main May 7, 2026
32 checks passed
@DanielButler1 DanielButler1 deleted the feat/models-pricing-hovercards-20260507 branch May 7, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant