Audit fixes: mis-framed crops, GPT cost 2.2x low, camera button losing photos
1. detail_crops had no equivalent of the margin guard the measurements got. When box detection fails (card still in a case), every crop is cut relative to the wrong rectangle -- verified the 'TOP-LEFT CORNER' close-up of the cased Ohtani is actually the CASE's corner bracket. The measurements refuse and explain; the crops kept being produced and captioned authoritatively, and the prompt tells the model to judge corners/edges/surface *from* them. Now surfaces a framing caveat telling the model to locate the real card edge inside each crop and say cannot_assess rather than grade the holder. 2. gpt-5.6-sol's approx_image_tokens was a pre-launch guess (1500) that advertised ~2.2x under true cost across all 9 real calls. Recalibrated to 3560 against median real usage, and added a per-model output estimate since GPT writes ~1.2k tokens of verdict vs Sonnet's ~0.9k. Both models now advertise within ~3% of observed cost. 3. 'Take photo' didn't reset after a completed grade, unlike 'Choose from library'. The result view has no photo strip, so new photos piled up invisibly behind the old verdict, silently, to the 6-photo cap. Also fixed the cap itself being a silent no-op with no explanation.
This commit is contained in:
parent
deabe74593
commit
6c612c1f4a
3 changed files with 79 additions and 12 deletions
36
vision.py
36
vision.py
|
|
@ -85,12 +85,14 @@ MODELS = {
|
|||
"adaptive_thinking": False,
|
||||
"fallbacks": False,
|
||||
"in_per_mtok": 2.00, "out_per_mtok": 10.00,
|
||||
# A rough estimate, unlike the Anthropic figures (which were true'd
|
||||
# up against real usage — see the README's grading-cost note). Only
|
||||
# affects the ADVERTISED per-grade estimate in Settings; the actual
|
||||
# billed cost always comes from the real usage this API call
|
||||
# reports, never from this number.
|
||||
"approx_image_tokens": 1500,
|
||||
# Calibrated against 8 real single/two-photo grades once this model
|
||||
# had actually been used (median 18.4k in / 1.2k out). The initial
|
||||
# 1500 was a guess made before any real call existed and advertised
|
||||
# roughly 2.2x under the true cost — a guess is fine to start from,
|
||||
# but it has to be trued up once real usage exists, exactly as the
|
||||
# Anthropic figures were.
|
||||
"approx_image_tokens": 3560,
|
||||
"approx_output_tokens": 1180,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -853,6 +855,9 @@ def grade_card(images, api_key=None, model=None, effort=None, zoom_details=True)
|
|||
measured = cardimage.edge_wear_profile(images[0][0]) if can_measure else None
|
||||
centering = cardimage.centering_profile(images[0][0]) if can_measure else None
|
||||
aspect = cardimage.aspect_profile(images[0][0]) if can_measure else None
|
||||
# Same detection failure that makes the measurements refuse also
|
||||
# mis-frames every crop — see cardimage.framing_warning.
|
||||
framing = cardimage.framing_warning(images[0][0]) if (crops or can_measure) else None
|
||||
|
||||
prompt_parts = []
|
||||
if centering and centering.get("reliable") is False:
|
||||
|
|
@ -986,6 +991,20 @@ def grade_card(images, api_key=None, model=None, effort=None, zoom_details=True)
|
|||
"when you say which corner or edge a problem is on. They add no "
|
||||
"information the full photo lacked, only easier viewing, so do not "
|
||||
"read resampling softness as card wear.")
|
||||
if framing:
|
||||
prompt_parts.append(
|
||||
"IMPORTANT CAVEAT ON THOSE CROPS: {} Because the crop "
|
||||
"rectangle is derived from that same detection, each close-up "
|
||||
"is cut relative to the wrong boundary — a corner close-up may "
|
||||
"well be showing the CORNER OF A CASE, SLEEVE OR HOLDER with "
|
||||
"the card's own corner sitting somewhere inside the frame, or "
|
||||
"out of it. Do not assume the crop's own edge is the card's "
|
||||
"edge. Find the actual card edge inside each close-up first "
|
||||
"and judge only that; if a given close-up doesn't clearly "
|
||||
"contain the card's real corner or edge, say cannot_assess "
|
||||
"for that category rather than grading the holder. Damage, "
|
||||
"scuffing or whitening on a case is not damage to the "
|
||||
"card.".format(framing))
|
||||
prompt_parts.append("Estimate the PSA grade this trading card would likely receive.")
|
||||
|
||||
parsed, usage = _call_vision(
|
||||
|
|
@ -1084,8 +1103,11 @@ def price_guide():
|
|||
guide = {}
|
||||
for model_id, caps in MODELS.items():
|
||||
# 1 supplied photo + ~12 generated close-ups, JSON verdict out.
|
||||
# Per-model output estimate where one is known: GPT-5.6 Sol
|
||||
# reliably writes ~1.2k tokens of verdict against Sonnet's ~0.9k,
|
||||
# enough to matter at these prices.
|
||||
est_in = caps["approx_image_tokens"] * 5 + 600
|
||||
est_out = 700
|
||||
est_out = caps.get("approx_output_tokens", 700)
|
||||
rate_in, rate_out = current_rates(caps)
|
||||
guide[model_id] = {
|
||||
"label": caps["label"],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue