use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct ModelMetadata {
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub model_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider_id: Option<Uuid>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct TokenUsage {
pub input_tokens: u32,
pub output_tokens: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_read_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_creation_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub actual_cost_usd: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub estimated_cost_usd: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub effective_cost_usd: Option<f64>,
}
impl TokenUsage {
pub fn new(input_tokens: u32, output_tokens: u32) -> Self {
Self {
input_tokens,
output_tokens,
cache_read_tokens: None,
cache_creation_tokens: None,
actual_cost_usd: None,
estimated_cost_usd: None,
effective_cost_usd: None,
}
}
pub fn with_cache(
input_tokens: u32,
output_tokens: u32,
cache_read_tokens: Option<u32>,
cache_creation_tokens: Option<u32>,
) -> Self {
Self {
input_tokens,
output_tokens,
cache_read_tokens,
cache_creation_tokens,
actual_cost_usd: None,
estimated_cost_usd: None,
effective_cost_usd: None,
}
}
pub fn with_cost(
mut self,
actual_cost_usd: Option<f64>,
estimated_cost_usd: Option<f64>,
) -> Self {
self.actual_cost_usd = actual_cost_usd;
self.estimated_cost_usd = estimated_cost_usd;
self
}
pub fn with_effective_cost(mut self, effective_cost_usd: Option<f64>) -> Self {
self.effective_cost_usd = effective_cost_usd;
self
}
pub fn effective_cost_usd(&self) -> Option<f64> {
self.effective_cost_usd
.or(self.actual_cost_usd.or(self.estimated_cost_usd))
}
pub fn total_tokens(&self) -> u32 {
self.input_tokens.saturating_add(self.output_tokens)
}
pub fn add(&mut self, other: &TokenUsage) {
let current_cost = self.effective_cost_usd();
self.input_tokens = self.input_tokens.saturating_add(other.input_tokens);
self.output_tokens = self.output_tokens.saturating_add(other.output_tokens);
if let Some(cache) = other.cache_read_tokens {
let total = self.cache_read_tokens.get_or_insert(0);
*total = total.saturating_add(cache);
}
if let Some(cache) = other.cache_creation_tokens {
let total = self.cache_creation_tokens.get_or_insert(0);
*total = total.saturating_add(cache);
}
if let Some(cost) = other.actual_cost_usd {
*self.actual_cost_usd.get_or_insert(0.0) += cost;
}
if let Some(cost) = other.estimated_cost_usd {
*self.estimated_cost_usd.get_or_insert(0.0) += cost;
}
if let Some(cost) = other.effective_cost_usd() {
*self
.effective_cost_usd
.get_or_insert(current_cost.unwrap_or(0.0)) += cost;
}
}
}