use std::collections::HashMap;
use crate::llm::TokenUsage;
pub trait ModelPricing {
fn input_price_per_mtok(&self) -> f64;
fn output_price_per_mtok(&self) -> f64;
fn cost_for_usage(&self, usage: &TokenUsage) -> f64 {
#[expect(
clippy::cast_precision_loss,
reason = "token counts are precise but float is acceptable for pricing"
)]
let input_cost = usage.input_tokens as f64 * self.input_price_per_mtok() / 1_000_000.0;
#[expect(
clippy::cast_precision_loss,
reason = "token counts are precise but float is acceptable for pricing"
)]
let output_cost = usage.output_tokens as f64 * self.output_price_per_mtok() / 1_000_000.0;
input_cost + output_cost
}
}
#[derive(Clone, Debug)]
pub struct PricingTable {
prices: HashMap<String, (f64, f64)>,
}
impl PricingTable {
#[must_use]
pub fn new() -> Self {
let mut prices = HashMap::new();
prices.insert("claude-3-opus-20240229".to_string(), (15.0, 75.0));
prices.insert("claude-3-sonnet-20240229".to_string(), (3.0, 15.0));
prices.insert("claude-3-haiku-20240307".to_string(), (0.25, 1.25));
prices.insert("claude-3-5-sonnet-20241022".to_string(), (3.0, 15.0));
prices.insert("claude-3-5-sonnet-20240620".to_string(), (3.0, 15.0));
prices.insert("gpt-4o-2024-11-20".to_string(), (2.5, 10.0));
prices.insert("gpt-4o-2024-08-06".to_string(), (2.5, 10.0));
prices.insert("gpt-4o-mini-2024-07-18".to_string(), (0.15, 0.60));
prices.insert("gpt-4-turbo-2024-04-09".to_string(), (10.0, 30.0));
prices.insert("gpt-4-0125-preview".to_string(), (10.0, 30.0));
prices.insert("gpt-4-1106-preview".to_string(), (10.0, 30.0));
prices.insert("gpt-35-turbo-0125".to_string(), (0.5, 1.5));
prices.insert("gpt-35-turbo-1106".to_string(), (0.5, 1.5));
prices.insert("gpt-35-turbo-16k-0613".to_string(), (0.3, 0.6));
prices.insert("gemini-2.0-flash-exp".to_string(), (0.075, 0.30));
prices.insert("gemini-1.5-pro-002".to_string(), (1.25, 5.0));
prices.insert("gemini-1.5-flash-002".to_string(), (0.075, 0.30));
prices.insert("gemini-1.5-flash-8b-001".to_string(), (0.0375, 0.15));
Self { prices }
}
#[must_use]
pub fn get(&self, model: &str) -> Option<(f64, f64)> {
self.prices.get(model).copied()
}
pub fn insert(&mut self, model: impl Into<String>, input_price: f64, output_price: f64) {
self.prices
.insert(model.into(), (input_price, output_price));
}
#[must_use]
pub fn contains(&self, model: &str) -> bool {
self.prices.contains_key(model)
}
}
impl Default for PricingTable {
fn default() -> Self {
Self::new()
}
}