use anyhow::Result;
use mimir_core::model::now_unix;
use mimir_core::savings::{self, to_dollars};
use mimir_core::Mimir;
pub fn savings(json: bool, oneline: bool) -> Result<()> {
let mimir = Mimir::open()?;
let price = mimir.config.savings.input_price_per_mtok;
let s = savings::summary(&mimir.conn, now_unix())?;
if oneline {
println!(
"◇ {} tok / {} saved (today {})",
human(s.all.saved()),
usd(s.all.saved(), price),
human(s.day)
);
return Ok(());
}
let by_source = savings::by_source(&mimir.conn, None)?;
if json {
let by: serde_json::Map<String, serde_json::Value> = by_source
.into_iter()
.map(|(src, t)| {
(
src,
serde_json::json!({
"saved": t.saved(),
"events": t.events,
"saved_usd": to_dollars(t.saved(), price),
}),
)
})
.collect();
println!(
"{}",
serde_json::json!({
"saved": { "day": s.day, "week": s.week, "month": s.month, "all": s.all.saved() },
"saved_usd_all": to_dollars(s.all.saved(), price),
"input_price_per_mtok": price,
"events_all": s.all.events,
"tokens_before_all": s.all.before,
"tokens_after_all": s.all.after,
"by_source": by,
})
);
return Ok(());
}
println!("mimir token savings");
for (label, saved) in [("today", s.day), ("week", s.week), ("month", s.month)] {
println!(
" {label:<6} {:>8} tok {}",
human(saved),
usd(saved, price)
);
}
println!(
" {:<6} {:>8} tok {} ({} events)",
"all",
human(s.all.saved()),
usd(s.all.saved(), price),
s.all.events
);
if s.all.before > 0 {
let pct = 100.0 * s.all.saved() as f64 / s.all.before as f64;
println!(" ratio {pct:.0}% of source tokens avoided (input @ ${price}/MTok)");
}
if by_source.is_empty() {
println!(
"\nno savings recorded yet — try `mimir outline <file>` or `mimir run -- cargo build`"
);
} else {
println!("\nby source:");
for (src, t) in &by_source {
println!(
" {src:<12} {:>8} saved {} ({} events)",
human(t.saved()),
usd(t.saved(), price),
t.events
);
}
}
Ok(())
}
fn usd(tokens: i64, price_per_mtok: f64) -> String {
format!("${:.2}", to_dollars(tokens, price_per_mtok))
}
fn human(n: i64) -> String {
if n >= 1_000_000 {
format!("{:.1}M", n as f64 / 1_000_000.0)
} else if n >= 10_000 {
format!("{:.1}k", n as f64 / 1000.0)
} else {
n.to_string()
}
}