Vapora/crates/vapora-llm-router/examples/03-cost-tracking.rs

202 lines
6.4 KiB
Rust
Raw Normal View History

2026-01-12 03:34:01 +00:00
//! # Cost Tracking Example
//!
//! Demonstrates how to track costs across providers and generate reports.
//!
//! ## What This Example Shows
//! - Recording token usage per provider
//! - Calculating costs with provider pricing
//! - Generating cost breakdowns by provider and task type
//! - ROI analysis for optimization
//!
//! ## Run
//! ```bash
//! cargo run --example 03-cost-tracking -p vapora-llm-router
//! ```
fn main() {
println!("=== Cost Tracking Example ===\n");
// Step 1: Define provider pricing
#[derive(Debug, Clone)]
struct ProviderPricing {
name: String,
input_cost_per_1m_tokens: u32, // cents
output_cost_per_1m_tokens: u32, // cents
}
let providers = vec![
ProviderPricing {
name: "claude".to_string(),
input_cost_per_1m_tokens: 300, // $3 per 1M
output_cost_per_1m_tokens: 1500, // $15 per 1M
},
ProviderPricing {
name: "gpt-4".to_string(),
input_cost_per_1m_tokens: 1000, // $10 per 1M
output_cost_per_1m_tokens: 3000, // $30 per 1M
},
ProviderPricing {
name: "gemini".to_string(),
input_cost_per_1m_tokens: 500, // $5 per 1M
output_cost_per_1m_tokens: 1500, // $15 per 1M
},
];
println!("Provider Pricing (per 1M tokens):\n");
for p in &providers {
println!(
" {}: input=${:.2}, output=${:.2}",
p.name,
p.input_cost_per_1m_tokens as f64 / 100.0,
p.output_cost_per_1m_tokens as f64 / 100.0
);
}
// Step 2: Record token usage
println!("\n=== Token Usage by Task ===\n");
#[derive(Debug, Clone)]
struct TaskExecution {
task_id: String,
provider: String,
task_type: String,
input_tokens: u64,
output_tokens: u64,
}
let executions = vec![
TaskExecution {
task_id: "task-001".to_string(),
provider: "claude".to_string(),
task_type: "coding".to_string(),
input_tokens: 1500,
output_tokens: 800,
},
TaskExecution {
task_id: "task-002".to_string(),
provider: "claude".to_string(),
task_type: "coding".to_string(),
input_tokens: 2000,
output_tokens: 1200,
},
TaskExecution {
task_id: "task-003".to_string(),
provider: "gpt-4".to_string(),
task_type: "analysis".to_string(),
input_tokens: 3000,
output_tokens: 1500,
},
TaskExecution {
task_id: "task-004".to_string(),
provider: "gemini".to_string(),
task_type: "documentation".to_string(),
input_tokens: 2500,
output_tokens: 2000,
},
];
let mut total_cost_cents = 0;
for exec in &executions {
let provider = providers.iter().find(|p| p.name == exec.provider).unwrap();
let input_cost = (exec.input_tokens * provider.input_cost_per_1m_tokens as u64) / 1_000_000;
let output_cost =
(exec.output_tokens * provider.output_cost_per_1m_tokens as u64) / 1_000_000;
let task_cost = input_cost + output_cost;
total_cost_cents += task_cost;
println!(
"{}: {} tokens",
exec.task_id,
exec.input_tokens + exec.output_tokens
);
println!(
" Provider: {}, Task type: {}",
exec.provider, exec.task_type
);
println!(
" Cost: ${:.4} (input: ${:.4}, output: ${:.4})\n",
task_cost as f64 / 10000.0,
input_cost as f64 / 10000.0,
output_cost as f64 / 10000.0
);
}
// Step 3: Cost breakdown by provider
println!("=== Cost Breakdown by Provider ===\n");
let mut provider_costs: std::collections::HashMap<String, u64> =
std::collections::HashMap::new();
let mut provider_tokens: std::collections::HashMap<String, u64> =
std::collections::HashMap::new();
for exec in &executions {
let provider = providers.iter().find(|p| p.name == exec.provider).unwrap();
let input_cost = (exec.input_tokens * provider.input_cost_per_1m_tokens as u64) / 1_000_000;
let output_cost =
(exec.output_tokens * provider.output_cost_per_1m_tokens as u64) / 1_000_000;
let task_cost = input_cost + output_cost;
*provider_costs.entry(exec.provider.clone()).or_insert(0) += task_cost;
*provider_tokens.entry(exec.provider.clone()).or_insert(0) +=
exec.input_tokens + exec.output_tokens;
}
for (provider, cost) in provider_costs.iter() {
let tokens = provider_tokens.get(provider).unwrap_or(&0);
let cost_per_1m = if *tokens > 0 {
(*cost * 1_000_000) / tokens
} else {
0
};
println!(
" {}: ${:.4} ({} tokens, ${:.2}/1M tokens)",
provider,
*cost as f64 / 10000.0,
tokens,
cost_per_1m as f64 / 100.0
);
}
// Step 4: Cost breakdown by task type
println!("\n=== Cost Breakdown by Task Type ===\n");
let mut task_type_costs: std::collections::HashMap<String, u64> =
std::collections::HashMap::new();
for exec in &executions {
let provider = providers.iter().find(|p| p.name == exec.provider).unwrap();
let input_cost = (exec.input_tokens * provider.input_cost_per_1m_tokens as u64) / 1_000_000;
let output_cost =
(exec.output_tokens * provider.output_cost_per_1m_tokens as u64) / 1_000_000;
let task_cost = input_cost + output_cost;
*task_type_costs.entry(exec.task_type.clone()).or_insert(0) += task_cost;
}
for (task_type, cost) in task_type_costs.iter() {
let percentage = (*cost as f64 / total_cost_cents as f64) * 100.0;
println!(
" {}: ${:.4} ({:.1}%)",
task_type,
*cost as f64 / 10000.0,
percentage
);
}
// Step 5: Summary
println!("\n=== Cost Summary ===");
println!("Total cost: ${:.4}", total_cost_cents as f64 / 10000.0);
println!(
"Average cost per task: ${:.4}",
(total_cost_cents as f64 / executions.len() as f64) / 10000.0
);
println!(
"Total tokens used: {}",
executions
.iter()
.map(|e| e.input_tokens + e.output_tokens)
.sum::<u64>()
);
}