use siumai::models;
use siumai::prelude::*;
use siumai::traits::ChatCapability;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🔄 Unified Interface - Provider-agnostic AI interactions\n");
demonstrate_provider_abstraction().await;
demonstrate_dynamic_provider_selection().await;
demonstrate_fallback_strategies().await;
demonstrate_capability_detection().await;
demonstrate_provider_independent_functions().await;
println!("\n✅ Unified interface examples completed!");
Ok(())
}
async fn demonstrate_provider_abstraction() {
println!("🎭 Provider Abstraction:\n");
let providers = create_available_providers().await;
if providers.is_empty() {
println!(" ⚠️ No providers available. Set API keys or start Ollama.");
return;
}
let test_message = "Hello! Please introduce yourself in one sentence.";
for (name, client) in providers {
println!(" Testing with {name}:");
let messages = vec![user!(test_message)];
match client.chat(messages).await {
Ok(response) => {
if let Some(text) = response.content_text() {
println!(" Response: {text}");
println!(" ✅ Success");
}
}
Err(e) => {
println!(" ❌ Failed: {e}");
}
}
println!();
}
}
async fn demonstrate_dynamic_provider_selection() {
println!("🎯 Dynamic Provider Selection:\n");
let tasks = vec![
("simple_question", "What is 2+2?"),
("creative_writing", "Write a haiku about programming"),
("analysis", "Analyze the pros and cons of remote work"),
];
for (task_type, prompt) in tasks {
println!(" Task: {task_type} - \"{prompt}\"");
match select_best_provider_for_task(task_type).await {
Ok((provider_name, client)) => {
println!(" Selected provider: {provider_name}");
let messages = vec![user!(prompt)];
match client.chat(messages).await {
Ok(response) => {
if let Some(text) = response.content_text() {
let preview = if text.len() > 100 {
format!("{}...", &text[..100])
} else {
text.to_string()
};
println!(" Response: {preview}");
println!(" ✅ Success");
}
}
Err(e) => {
println!(" ❌ Failed: {e}");
}
}
}
Err(e) => {
println!(" ❌ No suitable provider: {e}");
}
}
println!();
}
}
async fn demonstrate_fallback_strategies() {
println!("🛡️ Fallback Strategies:\n");
let message = "Explain machine learning in simple terms";
match chat_with_fallback(message).await {
Ok((provider_name, response)) => {
println!(" Successfully used provider: {provider_name}");
if let Some(text) = response.content_text() {
let preview = if text.len() > 150 {
format!("{}...", &text[..150])
} else {
text.to_string()
};
println!(" Response: {preview}");
}
println!(" ✅ Fallback strategy successful");
}
Err(e) => {
println!(" ❌ All providers failed: {e}");
}
}
println!();
}
async fn demonstrate_capability_detection() {
println!("🔍 Capability Detection:\n");
let providers = create_available_providers().await;
for (name, client) in providers {
println!(" Provider: {name}");
println!(" Chat: ✅ (all providers support this)");
let supports_streaming = test_streaming_capability(client.as_ref()).await;
println!(
" Streaming: {}",
if supports_streaming { "✅" } else { "❌" }
);
println!(" Vision: 🔍 (would need capability detection)");
println!(" Tools: 🔍 (would need capability detection)");
println!();
}
}
async fn demonstrate_provider_independent_functions() {
println!("🔧 Provider-Independent Functions:\n");
let providers = create_available_providers().await;
if let Some((name, client)) = providers.into_iter().next() {
println!(" Using provider: {name}");
match ask_question(client.as_ref(), "What is the meaning of life?").await {
Ok(answer) => {
println!(" Question: What is the meaning of life?");
println!(" Answer: {answer}");
println!(" ✅ Provider-independent function successful");
}
Err(e) => {
println!(" ❌ Function failed: {e}");
}
}
} else {
println!(" ⚠️ No providers available for testing");
}
}
async fn create_available_providers() -> Vec<(String, Box<dyn ChatCapability + Send + Sync>)> {
let mut providers = Vec::new();
if let Ok(api_key) = std::env::var("OPENAI_API_KEY")
&& let Ok(client) = LlmBuilder::new()
.openai()
.api_key(&api_key)
.model(models::openai::GPT_4O_MINI)
.build()
.await
{
providers.push((
"OpenAI".to_string(),
Box::new(client) as Box<dyn ChatCapability + Send + Sync>,
));
}
if let Ok(api_key) = std::env::var("ANTHROPIC_API_KEY")
&& let Ok(client) = LlmBuilder::new()
.anthropic()
.api_key(&api_key)
.model(models::anthropic::CLAUDE_HAIKU_3_5)
.build()
.await
{
providers.push((
"Anthropic".to_string(),
Box::new(client) as Box<dyn ChatCapability + Send + Sync>,
));
}
if let Ok(client) = LlmBuilder::new()
.ollama()
.base_url("http://localhost:11434")
.model(models::ollama::LLAMA_3_2)
.build()
.await
{
let test_messages = vec![user!("Hi")];
if client.chat(test_messages).await.is_ok() {
providers.push((
"Ollama".to_string(),
Box::new(client) as Box<dyn ChatCapability + Send + Sync>,
));
}
}
providers
}
async fn select_best_provider_for_task(
task_type: &str,
) -> Result<(String, Box<dyn ChatCapability + Send + Sync>), LlmError> {
let mut providers = create_available_providers().await;
if providers.is_empty() {
return Err(LlmError::InternalError(
"No providers available".to_string(),
));
}
match task_type {
"simple_question" => {
for i in 0..providers.len() {
let (name, _) = &providers[i];
if name == "Ollama" || name == "OpenAI" {
let (name, client) = providers.remove(i);
return Ok((name, client));
}
}
if let Some((name, client)) = providers.pop() {
return Ok((name, client));
}
}
"creative_writing" => {
for i in 0..providers.len() {
let (name, _) = &providers[i];
if name == "Anthropic" || name == "OpenAI" {
let (name, client) = providers.remove(i);
return Ok((name, client));
}
}
if let Some((name, client)) = providers.pop() {
return Ok((name, client));
}
}
"analysis" => {
for i in 0..providers.len() {
let (name, _) = &providers[i];
if name == "Anthropic" {
let (name, client) = providers.remove(i);
return Ok((name, client));
}
}
if let Some((name, client)) = providers.pop() {
return Ok((name, client));
}
}
_ => {}
}
providers
.into_iter()
.next()
.ok_or_else(|| LlmError::InternalError("No suitable provider found".to_string()))
}
async fn chat_with_fallback(message: &str) -> Result<(String, ChatResponse), LlmError> {
let providers = create_available_providers().await;
for (name, client) in providers {
let messages = vec![user!(message)];
if let Ok(response) = client.chat(messages).await {
return Ok((name, response));
} else {
}
}
Err(LlmError::InternalError("All providers failed".to_string()))
}
async fn test_streaming_capability(_client: &dyn ChatCapability) -> bool {
true
}
async fn ask_question(client: &dyn ChatCapability, question: &str) -> Result<String, LlmError> {
let messages = vec![user!(question)];
let response = client.chat(messages).await?;
Ok(response.content_text().unwrap_or_default().to_string())
}