diff --git a/src-tauri/src/commands/usage.rs b/src-tauri/src/commands/usage.rs index 6aa4778..3808e97 100644 --- a/src-tauri/src/commands/usage.rs +++ b/src-tauri/src/commands/usage.rs @@ -71,36 +71,61 @@ pub struct ProjectUsage { // Claude pricing constants (per million tokens) // 最新价格表 (2025-01) -// Claude 4.x 系列 +// 注意:Cache Writes 使用 5m (5分钟) 的价格,1h 价格更高 + +// Claude Opus 系列 const OPUS_4_1_INPUT_PRICE: f64 = 15.0; const OPUS_4_1_OUTPUT_PRICE: f64 = 75.0; -const OPUS_4_1_CACHE_WRITE_PRICE: f64 = 18.75; +const OPUS_4_1_CACHE_WRITE_PRICE: f64 = 18.75; // 5m cache writes const OPUS_4_1_CACHE_READ_PRICE: f64 = 1.50; +const OPUS_4_INPUT_PRICE: f64 = 15.0; +const OPUS_4_OUTPUT_PRICE: f64 = 75.0; +const OPUS_4_CACHE_WRITE_PRICE: f64 = 18.75; // 5m cache writes +const OPUS_4_CACHE_READ_PRICE: f64 = 1.50; + +const OPUS_3_INPUT_PRICE: f64 = 15.0; +const OPUS_3_OUTPUT_PRICE: f64 = 75.0; +const OPUS_3_CACHE_WRITE_PRICE: f64 = 18.75; // 5m cache writes +const OPUS_3_CACHE_READ_PRICE: f64 = 1.50; + +// Claude Sonnet 系列 +const SONNET_4_5_INPUT_PRICE: f64 = 3.0; +const SONNET_4_5_OUTPUT_PRICE: f64 = 15.0; +const SONNET_4_5_CACHE_WRITE_PRICE: f64 = 3.75; // 5m cache writes +const SONNET_4_5_CACHE_READ_PRICE: f64 = 0.30; + const SONNET_4_INPUT_PRICE: f64 = 3.0; const SONNET_4_OUTPUT_PRICE: f64 = 15.0; -const SONNET_4_CACHE_WRITE_PRICE: f64 = 3.75; +const SONNET_4_CACHE_WRITE_PRICE: f64 = 3.75; // 5m cache writes const SONNET_4_CACHE_READ_PRICE: f64 = 0.30; -// Claude 3.x 系列 (旧版本,价格可能不同) -// Sonnet 3.7/3.5 -const SONNET_3_INPUT_PRICE: f64 = 3.0; -const SONNET_3_OUTPUT_PRICE: f64 = 15.0; -const SONNET_3_CACHE_WRITE_PRICE: f64 = 3.75; -const SONNET_3_CACHE_READ_PRICE: f64 = 0.30; +const SONNET_3_7_INPUT_PRICE: f64 = 3.0; +const SONNET_3_7_OUTPUT_PRICE: f64 = 15.0; +const SONNET_3_7_CACHE_WRITE_PRICE: f64 = 3.75; // 5m cache writes +const SONNET_3_7_CACHE_READ_PRICE: f64 = 0.30; -// Opus 3 - 假设与 Opus 4.1 相同 -const OPUS_3_INPUT_PRICE: f64 = 15.0; -const OPUS_3_OUTPUT_PRICE: f64 = 75.0; -const OPUS_3_CACHE_WRITE_PRICE: f64 = 18.75; -const OPUS_3_CACHE_READ_PRICE: f64 = 1.50; +const SONNET_3_5_INPUT_PRICE: f64 = 3.0; +const SONNET_3_5_OUTPUT_PRICE: f64 = 15.0; +const SONNET_3_5_CACHE_WRITE_PRICE: f64 = 3.75; // 5m cache writes +const SONNET_3_5_CACHE_READ_PRICE: f64 = 0.30; + +// Claude Haiku 系列 +const HAIKU_4_5_INPUT_PRICE: f64 = 1.0; +const HAIKU_4_5_OUTPUT_PRICE: f64 = 5.0; +const HAIKU_4_5_CACHE_WRITE_PRICE: f64 = 1.25; // 5m cache writes +const HAIKU_4_5_CACHE_READ_PRICE: f64 = 0.10; -// Haiku 3.5 - 最具性价比 const HAIKU_3_5_INPUT_PRICE: f64 = 0.80; const HAIKU_3_5_OUTPUT_PRICE: f64 = 4.0; -const HAIKU_3_5_CACHE_WRITE_PRICE: f64 = 1.0; +const HAIKU_3_5_CACHE_WRITE_PRICE: f64 = 1.0; // 5m cache writes const HAIKU_3_5_CACHE_READ_PRICE: f64 = 0.08; +const HAIKU_3_INPUT_PRICE: f64 = 0.25; +const HAIKU_3_OUTPUT_PRICE: f64 = 1.25; +const HAIKU_3_CACHE_WRITE_PRICE: f64 = 0.30; // 5m cache writes +const HAIKU_3_CACHE_READ_PRICE: f64 = 0.03; + #[derive(Debug, Deserialize)] struct JsonlEntry { timestamp: String, @@ -151,9 +176,8 @@ fn calculate_cost(model: &str, usage: &UsageData) -> f64 { // 独立的模型价格匹配函数,更精确的模型识别 fn match_model_prices(model_lower: &str) -> (f64, f64, f64, f64) { - // Claude Opus 4.1 (最新最强) - if model_lower.contains("opus") && (model_lower.contains("4-1") || model_lower.contains("4.1")) - { + // Claude Opus 系列 + if model_lower.contains("opus") && (model_lower.contains("4-1") || model_lower.contains("4.1")) { ( OPUS_4_1_INPUT_PRICE, OPUS_4_1_OUTPUT_PRICE, @@ -161,41 +185,14 @@ fn match_model_prices(model_lower: &str) -> (f64, f64, f64, f64) { OPUS_4_1_CACHE_READ_PRICE, ) } - // Claude Sonnet 4 - else if model_lower.contains("sonnet") - && (model_lower.contains("-4-") || model_lower.contains("sonnet-4")) - { + else if model_lower.contains("opus") && model_lower.contains("4") && !model_lower.contains("4-1") && !model_lower.contains("4.1") { ( - SONNET_4_INPUT_PRICE, - SONNET_4_OUTPUT_PRICE, - SONNET_4_CACHE_WRITE_PRICE, - SONNET_4_CACHE_READ_PRICE, + OPUS_4_INPUT_PRICE, + OPUS_4_OUTPUT_PRICE, + OPUS_4_CACHE_WRITE_PRICE, + OPUS_4_CACHE_READ_PRICE, ) } - // Claude Haiku 3.5 - else if model_lower.contains("haiku") { - ( - HAIKU_3_5_INPUT_PRICE, - HAIKU_3_5_OUTPUT_PRICE, - HAIKU_3_5_CACHE_WRITE_PRICE, - HAIKU_3_5_CACHE_READ_PRICE, - ) - } - // Claude 3.x Sonnet 系列(3.7, 3.5) - else if model_lower.contains("sonnet") - && (model_lower.contains("3-7") - || model_lower.contains("3.7") - || model_lower.contains("3-5") - || model_lower.contains("3.5")) - { - ( - SONNET_3_INPUT_PRICE, - SONNET_3_OUTPUT_PRICE, - SONNET_3_CACHE_WRITE_PRICE, - SONNET_3_CACHE_READ_PRICE, - ) - } - // Claude 3 Opus (旧版) else if model_lower.contains("opus") && model_lower.contains("3") { ( OPUS_3_INPUT_PRICE, @@ -204,16 +201,74 @@ fn match_model_prices(model_lower: &str) -> (f64, f64, f64, f64) { OPUS_3_CACHE_READ_PRICE, ) } - // 默认 Sonnet(未明确版本号时) - else if model_lower.contains("sonnet") { + // Claude Sonnet 系列 + else if model_lower.contains("sonnet") && (model_lower.contains("4-5") || model_lower.contains("4.5")) { ( - SONNET_3_INPUT_PRICE, - SONNET_3_OUTPUT_PRICE, - SONNET_3_CACHE_WRITE_PRICE, - SONNET_3_CACHE_READ_PRICE, + SONNET_4_5_INPUT_PRICE, + SONNET_4_5_OUTPUT_PRICE, + SONNET_4_5_CACHE_WRITE_PRICE, + SONNET_4_5_CACHE_READ_PRICE, ) } - // 默认 Opus(未明确版本号时,假设是最新版) + else if model_lower.contains("sonnet") && (model_lower.contains("-4-") || model_lower.contains("sonnet-4") || model_lower.contains("4-20")) { + ( + SONNET_4_INPUT_PRICE, + SONNET_4_OUTPUT_PRICE, + SONNET_4_CACHE_WRITE_PRICE, + SONNET_4_CACHE_READ_PRICE, + ) + } + else if model_lower.contains("sonnet") && (model_lower.contains("3-7") || model_lower.contains("3.7")) { + ( + SONNET_3_7_INPUT_PRICE, + SONNET_3_7_OUTPUT_PRICE, + SONNET_3_7_CACHE_WRITE_PRICE, + SONNET_3_7_CACHE_READ_PRICE, + ) + } + else if model_lower.contains("sonnet") && (model_lower.contains("3-5") || model_lower.contains("3.5")) { + ( + SONNET_3_5_INPUT_PRICE, + SONNET_3_5_OUTPUT_PRICE, + SONNET_3_5_CACHE_WRITE_PRICE, + SONNET_3_5_CACHE_READ_PRICE, + ) + } + // Claude Haiku 系列 + else if model_lower.contains("haiku") && (model_lower.contains("4-5") || model_lower.contains("4.5")) { + ( + HAIKU_4_5_INPUT_PRICE, + HAIKU_4_5_OUTPUT_PRICE, + HAIKU_4_5_CACHE_WRITE_PRICE, + HAIKU_4_5_CACHE_READ_PRICE, + ) + } + else if model_lower.contains("haiku") && (model_lower.contains("3-5") || model_lower.contains("3.5")) { + ( + HAIKU_3_5_INPUT_PRICE, + HAIKU_3_5_OUTPUT_PRICE, + HAIKU_3_5_CACHE_WRITE_PRICE, + HAIKU_3_5_CACHE_READ_PRICE, + ) + } + else if model_lower.contains("haiku") && model_lower.contains("3") && !model_lower.contains("3-5") && !model_lower.contains("3.5") { + ( + HAIKU_3_INPUT_PRICE, + HAIKU_3_OUTPUT_PRICE, + HAIKU_3_CACHE_WRITE_PRICE, + HAIKU_3_CACHE_READ_PRICE, + ) + } + // 默认 Sonnet(未明确版本号时,使用 Sonnet 4 作为默认) + else if model_lower.contains("sonnet") { + ( + SONNET_4_INPUT_PRICE, + SONNET_4_OUTPUT_PRICE, + SONNET_4_CACHE_WRITE_PRICE, + SONNET_4_CACHE_READ_PRICE, + ) + } + // 默认 Opus(未明确版本号时,假设是最新版 4.1) else if model_lower.contains("opus") { ( OPUS_4_1_INPUT_PRICE, @@ -222,15 +277,23 @@ fn match_model_prices(model_lower: &str) -> (f64, f64, f64, f64) { OPUS_4_1_CACHE_READ_PRICE, ) } - // 未知模型 - else { - log::warn!("Unknown model for cost calculation: {}", model_lower); - // 默认使用 Sonnet 3 的价格(保守估计) + // 默认 Haiku(未明确版本号时,使用 Haiku 3.5) + else if model_lower.contains("haiku") { ( - SONNET_3_INPUT_PRICE, - SONNET_3_OUTPUT_PRICE, - SONNET_3_CACHE_WRITE_PRICE, - SONNET_3_CACHE_READ_PRICE, + HAIKU_3_5_INPUT_PRICE, + HAIKU_3_5_OUTPUT_PRICE, + HAIKU_3_5_CACHE_WRITE_PRICE, + HAIKU_3_5_CACHE_READ_PRICE, + ) + } + // 未知模型 - 使用 Sonnet 4 作为默认(用户要求的默认价格) + else { + log::warn!("Unknown model for cost calculation: {}, using Sonnet 4 prices as default", model_lower); + ( + SONNET_4_INPUT_PRICE, + SONNET_4_OUTPUT_PRICE, + SONNET_4_CACHE_WRITE_PRICE, + SONNET_4_CACHE_READ_PRICE, ) } }