"""Direct vendor API arithmetic, checked 2026-09-23. No network or inference.
Token buckets must be disjoint. USD/1M; excludes taxes/tools/regional premiums.
Opus write rates here use five-minute caching; OpenAI uses its own cache rules.
"""
from decimal import Decimal as D
import json
RATES={
 'gpt-6-sol':('2','.20','2.50','10'),
 'gpt-6-luna':('.10','.01','.125','.50'),
 'gpt-6-astra':('10','1','12.50','50'),
 'claude-opus-5-5':('4','.20','5','20'),
 'claude-opus-5':('5','.50','6.25','25')}
def cost(model,ordinary,read,write,output,mode='standard'):
 counts=(ordinary,read,write,output)
 if any(not isinstance(n,int) or isinstance(n,bool) or n<0 for n in counts):raise ValueError('Use nonnegative integer counts in disjoint buckets')
 if mode not in ('standard','batch','flex','fast'):raise ValueError('Unknown processing mode')
 if model.startswith('claude') and mode!='standard':raise ValueError('This calculator covers Claude Standard only; check separate mode/cache rules')
 rates=list(map(D,RATES[model]))
 if model.startswith('gpt-6') and ordinary+read+write>272000:
  rates=[r*D('2' if i<3 else '1.5') for i,r in enumerate(rates)]
 factor={'standard':D(1),'batch':D('.5'),'flex':D('.5'),'fast':D(2)}[mode]
 return sum(D(n)*rate for n,rate in zip(counts,rates))*factor/D(1000000)
def examples():
 return {'sol_cache_example':str(cost('gpt-6-sol',20000,60000,20000,5000)),
 'opus55_cache_example':str(cost('claude-opus-5-5',20000,60000,20000,5000)),
 'opus5_cache_example':str(cost('claude-opus-5',20000,60000,20000,5000)),
 'sol_long_example':str(cost('gpt-6-sol',300000,0,0,5000)),
 'luna_1000_standard':str(1000*cost('gpt-6-luna',2000,0,0,300)),
 'luna_1000_batch':str(1000*cost('gpt-6-luna',2000,0,0,300,'batch')),
 'luna_1100_standard':str(1100*cost('gpt-6-luna',2000,0,0,300)),
 'luna_1100_batch':str(1100*cost('gpt-6-luna',2000,0,0,300,'batch')),
 'luna_uncached_20k_5k':str(cost('gpt-6-luna',20000,0,0,5000)),
 'sol_uncached_20k_5k':str(cost('gpt-6-sol',20000,0,0,5000)),
 'astra_uncached_20k_5k':str(cost('gpt-6-astra',20000,0,0,5000)),
 'opus55_uncached_20k_5k':str(cost('claude-opus-5-5',20000,0,0,5000))}
if __name__=='__main__':print(json.dumps(examples(),indent=2))
