const VISION_PATTERNS: &[&str] = &[
"claude-3",
"claude-4",
"gpt-4o",
"gpt-4-turbo",
"gpt-4-vision",
"gemini-pro-vision",
"gemini-1.5",
"gemini-2",
"llava",
"cogvlm",
"internvl",
"qwen-vl",
"qwen2-vl",
"pixtral",
];
pub fn is_vision_model(model: &str) -> bool {
let lower = model.to_lowercase();
VISION_PATTERNS.iter().any(|p| lower.contains(p))
}
pub fn suggest_vision_model(models: &[String]) -> Option<&str> {
let priorities: &[&str] = &[
"claude-3",
"claude-4",
"gpt-4o",
"gpt-4-turbo",
"gpt-4-vision",
"gemini",
"llava",
"pixtral",
];
for priority in priorities {
if let Some(model) = models.iter().find(|m| m.to_lowercase().contains(priority)) {
return Some(model);
}
}
models.iter().find_map(|m| {
if is_vision_model(m) {
Some(m.as_str())
} else {
None
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detects_claude_vision() {
assert!(is_vision_model("claude-3-5-sonnet-20241022"));
assert!(is_vision_model("claude-3-opus"));
assert!(is_vision_model("claude-4-sonnet"));
}
#[test]
fn detects_gpt4_vision() {
assert!(is_vision_model("gpt-4o"));
assert!(is_vision_model("gpt-4-turbo"));
assert!(is_vision_model("gpt-4-vision-preview"));
}
#[test]
fn detects_other_vision_models() {
assert!(is_vision_model("gemini-1.5-pro"));
assert!(is_vision_model("llava-v1.6"));
assert!(is_vision_model("pixtral-12b"));
}
#[test]
fn rejects_non_vision_models() {
assert!(!is_vision_model("gpt-3.5-turbo"));
assert!(!is_vision_model("llama-3.1-70b"));
assert!(!is_vision_model("mistral-7b"));
}
#[test]
fn suggests_claude_first() {
let models = vec![
"gpt-4o".to_string(),
"claude-3-5-sonnet-20241022".to_string(),
];
assert_eq!(
suggest_vision_model(&models),
Some("claude-3-5-sonnet-20241022")
);
}
#[test]
fn returns_none_when_no_vision_models() {
let models = vec!["gpt-3.5-turbo".to_string(), "llama-3.1-70b".to_string()];
assert_eq!(suggest_vision_model(&models), None);
}
}