| |
| use std::collections::HashMap; |
| use once_cell::sync::Lazy; |
|
|
| static CLAUDE_TO_GEMINI: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| { |
| let mut m = HashMap::new(); |
|
|
| |
| m.insert("claude-opus-4-5-thinking", "claude-opus-4-5-thinking"); |
| m.insert("claude-sonnet-4-5", "claude-sonnet-4-5"); |
| m.insert("claude-sonnet-4-5-thinking", "claude-sonnet-4-5-thinking"); |
|
|
| |
| m.insert("claude-sonnet-4-5-20250929", "claude-sonnet-4-5-thinking"); |
| m.insert("claude-3-5-sonnet-20241022", "claude-sonnet-4-5"); |
| m.insert("claude-3-5-sonnet-20240620", "claude-sonnet-4-5"); |
| m.insert("claude-opus-4", "claude-opus-4-5-thinking"); |
| m.insert("claude-opus-4-5-20251101", "claude-opus-4-5-thinking"); |
| m.insert("claude-haiku-4", "claude-sonnet-4-5"); |
| m.insert("claude-3-haiku-20240307", "claude-sonnet-4-5"); |
| m.insert("claude-haiku-4-5-20251001", "claude-sonnet-4-5"); |
| |
| m.insert("gpt-4", "gemini-2.5-pro"); |
| m.insert("gpt-4-turbo", "gemini-2.5-pro"); |
| m.insert("gpt-4-turbo-preview", "gemini-2.5-pro"); |
| m.insert("gpt-4-0125-preview", "gemini-2.5-pro"); |
| m.insert("gpt-4-1106-preview", "gemini-2.5-pro"); |
| m.insert("gpt-4-0613", "gemini-2.5-pro"); |
|
|
| m.insert("gpt-4o", "gemini-2.5-pro"); |
| m.insert("gpt-4o-2024-05-13", "gemini-2.5-pro"); |
| m.insert("gpt-4o-2024-08-06", "gemini-2.5-pro"); |
|
|
| m.insert("gpt-4o-mini", "gemini-2.5-flash"); |
| m.insert("gpt-4o-mini-2024-07-18", "gemini-2.5-flash"); |
|
|
| m.insert("gpt-3.5-turbo", "gemini-2.5-flash"); |
| m.insert("gpt-3.5-turbo-16k", "gemini-2.5-flash"); |
| m.insert("gpt-3.5-turbo-0125", "gemini-2.5-flash"); |
| m.insert("gpt-3.5-turbo-1106", "gemini-2.5-flash"); |
| m.insert("gpt-3.5-turbo-0613", "gemini-2.5-flash"); |
|
|
| |
| m.insert("gemini-2.5-flash-lite", "gemini-2.5-flash-lite"); |
| m.insert("gemini-2.5-flash-thinking", "gemini-2.5-flash-thinking"); |
| m.insert("gemini-3-pro-low", "gemini-3-pro-low"); |
| m.insert("gemini-3-pro-high", "gemini-3-pro-high"); |
| m.insert("gemini-3-pro-preview", "gemini-3-pro-preview"); |
| m.insert("gemini-2.5-flash", "gemini-2.5-flash"); |
| m.insert("gemini-3-flash", "gemini-3-flash"); |
| m.insert("gemini-3-pro-image", "gemini-3-pro-image"); |
|
|
| m |
| }); |
|
|
| pub fn map_claude_model_to_gemini(input: &str) -> String { |
| |
| if let Some(mapped) = CLAUDE_TO_GEMINI.get(input) { |
| return mapped.to_string(); |
| } |
|
|
| |
| if input.starts_with("gemini-") || input.contains("thinking") { |
| return input.to_string(); |
| } |
|
|
| |
| "claude-sonnet-4-5".to_string() |
| } |
|
|
| |
| |
| pub fn resolve_model_route( |
| original_model: &str, |
| custom_mapping: &std::collections::HashMap<String, String>, |
| openai_mapping: &std::collections::HashMap<String, String>, |
| anthropic_mapping: &std::collections::HashMap<String, String>, |
| ) -> String { |
| |
| if let Some(target) = custom_mapping.get(original_model) { |
| crate::modules::logger::log_info(&format!("[Router] 使用自定义精确映射: {} -> {}", original_model, target)); |
| return target.clone(); |
| } |
|
|
| let lower_model = original_model.to_lowercase(); |
|
|
| |
| |
| if (lower_model.starts_with("gpt-4") && !lower_model.contains("o") && !lower_model.contains("mini") && !lower_model.contains("turbo")) || |
| lower_model.starts_with("o1-") || lower_model.starts_with("o3-") || lower_model == "gpt-4" { |
| if let Some(target) = openai_mapping.get("gpt-4-series") { |
| crate::modules::logger::log_info(&format!("[Router] 使用 GPT-4 系列映射: {} -> {}", original_model, target)); |
| return target.clone(); |
| } |
| } |
| |
| |
| if lower_model.contains("4o") || lower_model.starts_with("gpt-3.5") || (lower_model.contains("mini") && !lower_model.contains("gemini")) || lower_model.contains("turbo") { |
| if let Some(target) = openai_mapping.get("gpt-4o-series") { |
| crate::modules::logger::log_info(&format!("[Router] 使用 GPT-4o/3.5 系列映射: {} -> {}", original_model, target)); |
| return target.clone(); |
| } |
| } |
|
|
| |
| if lower_model.starts_with("gpt-5") { |
| |
| if let Some(target) = openai_mapping.get("gpt-5-series") { |
| crate::modules::logger::log_info(&format!("[Router] 使用 GPT-5 系列映射: {} -> {}", original_model, target)); |
| return target.clone(); |
| } |
| if let Some(target) = openai_mapping.get("gpt-4-series") { |
| crate::modules::logger::log_info(&format!("[Router] 使用 GPT-4 系列映射 (GPT-5 fallback): {} -> {}", original_model, target)); |
| return target.clone(); |
| } |
| } |
|
|
| |
| if lower_model.starts_with("claude-") { |
| let family_key = if lower_model.contains("4-5") || lower_model.contains("4.5") { |
| "claude-4.5-series" |
| } else if lower_model.contains("3-5") || lower_model.contains("3.5") { |
| "claude-3.5-series" |
| } else { |
| "claude-default" |
| }; |
|
|
| if let Some(target) = anthropic_mapping.get(family_key) { |
| crate::modules::logger::log_warn(&format!("[Router] 使用 Anthropic 系列映射: {} -> {}", original_model, target)); |
| return target.clone(); |
| } |
| |
| |
| if let Some(target) = anthropic_mapping.get(original_model) { |
| return target.clone(); |
| } |
| } |
|
|
| |
| map_claude_model_to_gemini(original_model) |
| } |
|
|
| #[cfg(test)] |
| mod tests { |
| use super::*; |
|
|
| #[test] |
| fn test_model_mapping() { |
| assert_eq!( |
| map_claude_model_to_gemini("claude-3-5-sonnet-20241022"), |
| "claude-sonnet-4-5" |
| ); |
| assert_eq!( |
| map_claude_model_to_gemini("claude-opus-4"), |
| "claude-opus-4-5-thinking" |
| ); |
| |
| assert_eq!( |
| map_claude_model_to_gemini("gemini-2.5-flash-mini-test"), |
| "gemini-2.5-flash-mini-test" |
| ); |
| assert_eq!( |
| map_claude_model_to_gemini("unknown-model"), |
| "claude-sonnet-4-5" |
| ); |
| } |
| } |
|
|