claudex_cli/commands/
models.rs1use anyhow::Result;
2
3use crate::cli::ResolvedFilter;
4use crate::ui;
5use claudex::index::IndexStore;
6use claudex::providers::enabled_default;
7use claudex::types::ModelPricing;
8
9pub fn run(project: Option<&str>, json: bool, filter: &ResolvedFilter) -> Result<()> {
10 let providers = enabled_default()?;
11 let mut idx = IndexStore::open()?;
12 idx.ensure_fresh(&providers)?;
13
14 let rows = idx.query_model_usage(project, filter)?;
15
16 if json {
17 let output: Vec<_> = rows
18 .iter()
19 .map(|r| {
20 serde_json::json!({
21 "model": r.model,
22 "model_family": ModelPricing::name(Some(&r.model)),
23 "session_count": r.session_count,
24 "input_tokens": r.input_tokens,
25 "output_tokens": r.output_tokens,
26 "cache_creation_tokens": r.cache_creation_tokens,
27 "cache_read_tokens": r.cache_read_tokens,
28 "avg_cost_per_session_usd": r.avg_cost_per_session_usd,
29 "avg_tokens_per_session": r.avg_tokens_per_session,
30 "service_tiers": r.service_tiers,
31 "inference_geos": r.inference_geos,
32 "avg_speed": r.avg_speed,
33 "total_iterations": r.total_iterations,
34 "cost_usd": r.cost_usd,
35 })
36 })
37 .collect();
38 println!("{}", serde_json::to_string_pretty(&output)?);
39 return Ok(());
40 }
41
42 if rows.is_empty() {
43 println!("No model usage data found.");
44 return Ok(());
45 }
46
47 let mut table = ui::table();
48 table.set_header(ui::header([
49 "Model",
50 "Sessions",
51 "Input",
52 "Output",
53 "Cache Write",
54 "Cache Read",
55 "Avg/Session",
56 "Avg Tokens",
57 "Cost (USD)",
58 ]));
59 ui::right_align(&mut table, &[1, 2, 3, 4, 5, 6, 7, 8]);
60 let mut total_sessions = 0i64;
61 let mut total_input = 0i64;
62 let mut total_output = 0i64;
63 let mut total_cache_creation = 0i64;
64 let mut total_cache_read = 0i64;
65 let mut total_cost = 0.0f64;
66 for r in &rows {
67 let family = ModelPricing::name(Some(&r.model));
68 let display = if r.model.is_empty() {
69 family.to_string()
70 } else {
71 format!("{} ({})", family, r.model.trim_start_matches("claude-"))
72 };
73 table.add_row([
74 ui::cell_model(&display),
75 ui::cell_count(r.session_count as u64),
76 ui::cell_count(r.input_tokens as u64),
77 ui::cell_count(r.output_tokens as u64),
78 ui::cell_count(r.cache_creation_tokens as u64),
79 ui::cell_count(r.cache_read_tokens as u64),
80 ui::cell_cost(r.avg_cost_per_session_usd),
81 ui::cell_count(r.avg_tokens_per_session.round() as u64),
82 ui::cell_cost(r.cost_usd),
83 ]);
84 total_sessions += r.session_count;
85 total_input += r.input_tokens;
86 total_output += r.output_tokens;
87 total_cache_creation += r.cache_creation_tokens;
88 total_cache_read += r.cache_read_tokens;
89 total_cost += r.cost_usd;
90 }
91 table.add_row(ui::total_row([
92 "TOTAL".to_string(),
93 ui::fmt_count(total_sessions as u64),
94 ui::fmt_count(total_input as u64),
95 ui::fmt_count(total_output as u64),
96 ui::fmt_count(total_cache_creation as u64),
97 ui::fmt_count(total_cache_read as u64),
98 String::new(),
99 String::new(),
100 ui::fmt_cost(total_cost),
101 ]));
102 println!("{table}");
103 Ok(())
104}