package classify // Pricing for receipt classification. Token counts come straight from each API // response (exact, free); per-token prices are not available from any Anthropic // API, so they live here as constants keyed by exact model id. A model id is // priced once and never re-priced — Anthropic ships price changes as new ids — so // this table only needs a new row when we adopt a new model (i.e. when we'd be // changing CLASSIFY_MODEL anyway). An unknown id yields ok=false, and callers show // the token counts without a (wrong) dollar figure rather than guessing. // Usage is the token accounting from one Messages API response. type Usage struct { InputTokens int OutputTokens int CacheReadTokens int CacheCreationTokens int } // rate holds a model's price in cents per one million tokens. type rate struct { inPerM float64 // cents per 1M input tokens outPerM float64 // cents per 1M output tokens } // modelRates is the hand-maintained price table (cents per 1M tokens). // $1/1M == 100 cents/1M. var modelRates = map[string]rate{ "claude-haiku-4-5-20251001": {inPerM: 100, outPerM: 500}, "claude-haiku-4-5": {inPerM: 100, outPerM: 500}, "claude-sonnet-4-6": {inPerM: 300, outPerM: 1500}, "claude-opus-4-8": {inPerM: 500, outPerM: 2500}, "claude-opus-4-7": {inPerM: 500, outPerM: 2500}, } // CostCents returns the cost of a classification call in cents, and whether the // model's price is known. Cache tokens are billed at the input rate (a slight // over-estimate — cache reads actually bill at ~0.1× input — which is fine for a // "what did this scan cost" readout). Returns ok=false for an unpriced model. func CostCents(model string, u Usage) (float64, bool) { r, ok := modelRates[model] if !ok { return 0, false } inTokens := float64(u.InputTokens + u.CacheReadTokens + u.CacheCreationTokens) cents := inTokens*r.inPerM/1_000_000 + float64(u.OutputTokens)*r.outPerM/1_000_000 return cents, true }