From 762b394c8a139c257ac123270bbced8d34f474d1 Mon Sep 17 00:00:00 2001 From: Barely Removable Date: Sat, 22 Aug 2026 13:10:08 -0700 Subject: [PATCH] Make Sonnet's expiring intro pricing date-aware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The table hardcoded $2/$10 with a comment noting it lapses 2026-08-31. From Sept 1 that would have under-reported every grade by a third — both the per-grade figure in the UI and the cost recorded against each result. --- vision.py | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/vision.py b/vision.py index 1d1e8b8..3571b70 100644 --- a/vision.py +++ b/vision.py @@ -16,6 +16,7 @@ Works on any trading card: Pokemon, sports, Magic, whatever PSA grades. import base64 import json import os +import time import cardimage @@ -48,8 +49,11 @@ MODELS = { "effort": True, "adaptive_thinking": True, "fallbacks": False, - # Introductory pricing runs through 2026-08-31, then 3.00 / 15.00. + # Introductory pricing, which EXPIRES — see `priced_from` below. + # Hardcoding the intro rate alone would have quietly under-reported + # every grade by a third from 2026-09-01 onward. "in_per_mtok": 2.00, "out_per_mtok": 10.00, + "priced_from": [("2026-09-01", 3.00, 15.00)], "approx_image_tokens": 4800, }, "claude-opus-5": { @@ -824,13 +828,31 @@ def grade_card(images, api_key=None, model=None, effort=None, zoom_details=True) } +def current_rates(caps, on_date=None): + """(input, output) $/Mtok for a model, honouring any scheduled change. + + A model on introductory pricing carries the dated rates that supersede + it in `priced_from`; the latest one whose date has passed wins. Without + this the table silently keeps quoting a rate that no longer exists once + the promotion ends, and every cost shown in the app is wrong by + whatever the increase was. + """ + rate_in, rate_out = caps["in_per_mtok"], caps["out_per_mtok"] + today = on_date or time.strftime("%Y-%m-%d") + for starts, new_in, new_out in sorted(caps.get("priced_from") or []): + if today >= starts: + rate_in, rate_out = new_in, new_out + return rate_in, rate_out + + def estimate_cost(usage): """Actual USD cost of one grading call, from the reported token counts.""" if not usage: return None caps = MODELS.get(usage.get("model") or "", MODELS[DEFAULT_MODEL]) - return ((usage.get("input_tokens") or 0) * caps["in_per_mtok"] / 1_000_000 - + (usage.get("output_tokens") or 0) * caps["out_per_mtok"] / 1_000_000) + rate_in, rate_out = current_rates(caps) + return ((usage.get("input_tokens") or 0) * rate_in / 1_000_000 + + (usage.get("output_tokens") or 0) * rate_out / 1_000_000) def price_guide(): @@ -840,10 +862,11 @@ def price_guide(): # 1 supplied photo + ~12 generated close-ups, JSON verdict out. est_in = caps["approx_image_tokens"] * 5 + 600 est_out = 700 + rate_in, rate_out = current_rates(caps) guide[model_id] = { "label": caps["label"], "supports_effort": caps["effort"], - "per_grade": round(est_in * caps["in_per_mtok"] / 1_000_000 - + est_out * caps["out_per_mtok"] / 1_000_000, 4), + "per_grade": round(est_in * rate_in / 1_000_000 + + est_out * rate_out / 1_000_000, 4), } return guide