use std::collections::HashMap;
use std::sync::Arc;
use crate::audio::{AudioInput, PendingSpeechToTextRequest, PendingTextToSpeechRequest};
use crate::embeddings::PendingEmbeddingsRequest;
use crate::error::Error;
use crate::images::PendingImagesRequest;
use crate::moderation::PendingModerationRequest;
use crate::provider::Provider;
use crate::schema::ObjectSchema;
use crate::structured::PendingStructuredRequest;
use crate::text::PendingTextRequest;
#[derive(Default, Clone)]
pub struct Registry {
providers: HashMap<String, Arc<dyn Provider>>,
}
impl Registry {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, name: impl Into<String>, provider: impl Provider + 'static) {
self.providers.insert(name.into(), Arc::new(provider));
}
pub fn register_arc(&mut self, name: impl Into<String>, provider: Arc<dyn Provider>) {
self.providers.insert(name.into(), provider);
}
pub fn provider(&self, name: &str) -> Result<Arc<dyn Provider>, Error> {
self.providers
.get(name)
.cloned()
.ok_or_else(|| Error::UnknownProvider(name.to_string()))
}
pub fn text(
&self,
provider_name: &str,
model: impl Into<String>,
) -> Result<PendingTextRequest, Error> {
let provider = self.provider(provider_name)?;
Ok(PendingTextRequest::new(provider, model))
}
pub fn structured(
&self,
provider_name: &str,
model: impl Into<String>,
schema: ObjectSchema,
) -> Result<PendingStructuredRequest, Error> {
let provider = self.provider(provider_name)?;
Ok(PendingStructuredRequest::new(provider, model, schema))
}
pub fn moderation(
&self,
provider_name: &str,
model: impl Into<String>,
) -> Result<PendingModerationRequest, Error> {
let provider = self.provider(provider_name)?;
Ok(PendingModerationRequest::new(provider, model))
}
pub fn embeddings(
&self,
provider_name: &str,
model: impl Into<String>,
) -> Result<PendingEmbeddingsRequest, Error> {
let provider = self.provider(provider_name)?;
Ok(PendingEmbeddingsRequest::new(provider, model))
}
pub fn images(
&self,
provider_name: &str,
model: impl Into<String>,
prompt: impl Into<String>,
) -> Result<PendingImagesRequest, Error> {
let provider = self.provider(provider_name)?;
Ok(PendingImagesRequest::new(provider, model, prompt))
}
pub fn text_to_speech(
&self,
provider_name: &str,
model: impl Into<String>,
input: impl Into<String>,
) -> Result<PendingTextToSpeechRequest, Error> {
let provider = self.provider(provider_name)?;
Ok(PendingTextToSpeechRequest::new(provider, model, input))
}
pub fn speech_to_text(
&self,
provider_name: &str,
model: impl Into<String>,
audio: AudioInput,
) -> Result<PendingSpeechToTextRequest, Error> {
let provider = self.provider(provider_name)?;
Ok(PendingSpeechToTextRequest::new(provider, model, audio))
}
#[cfg(feature = "http")]
pub fn from_env() -> Self {
let mut registry = Self::new();
#[cfg(feature = "openai")]
if let Ok(api_key) = std::env::var("OPENAI_API_KEY") {
registry.register(
"openai",
crate::providers::openai::OpenAiProvider::new(api_key),
);
}
#[cfg(feature = "anthropic")]
if let Ok(api_key) = std::env::var("ANTHROPIC_API_KEY") {
registry.register(
"anthropic",
crate::providers::anthropic::AnthropicProvider::new(api_key),
);
}
#[cfg(feature = "groq")]
if let Ok(api_key) = std::env::var("GROQ_API_KEY") {
registry.register(
"groq",
crate::providers::openai_compatible::GroqProvider::new(api_key),
);
}
#[cfg(feature = "deepseek")]
if let Ok(api_key) = std::env::var("DEEPSEEK_API_KEY") {
registry.register(
"deepseek",
crate::providers::openai_compatible::DeepSeekProvider::new(api_key),
);
}
#[cfg(feature = "mistral")]
if let Ok(api_key) = std::env::var("MISTRAL_API_KEY") {
registry.register(
"mistral",
crate::providers::openai_compatible::MistralProvider::new(api_key),
);
}
#[cfg(feature = "xai")]
if let Ok(api_key) = std::env::var("XAI_API_KEY") {
registry.register(
"xai",
crate::providers::openai_compatible::XaiProvider::new(api_key),
);
}
#[cfg(feature = "openrouter")]
if let Ok(api_key) = std::env::var("OPENROUTER_API_KEY") {
registry.register(
"openrouter",
crate::providers::openai_compatible::OpenRouterProvider::new(api_key),
);
}
#[cfg(feature = "perplexity")]
if let Ok(api_key) = std::env::var("PERPLEXITY_API_KEY") {
registry.register(
"perplexity",
crate::providers::openai_compatible::PerplexityProvider::new(api_key),
);
}
#[cfg(feature = "zai")]
if let Ok(api_key) = std::env::var("ZAI_API_KEY") {
registry.register(
"zai",
crate::providers::openai_compatible::ZaiProvider::new(api_key),
);
}
#[cfg(feature = "voyageai")]
if let Ok(api_key) = std::env::var("VOYAGEAI_API_KEY") {
registry.register(
"voyageai",
crate::providers::voyageai::VoyageAiProvider::new(api_key),
);
}
#[cfg(feature = "ollama")]
{
let provider = match std::env::var("OLLAMA_BASE_URL") {
Ok(base_url) => crate::providers::ollama::OllamaProvider::with_base_url(base_url),
Err(_) => crate::providers::ollama::OllamaProvider::new(),
};
registry.register("ollama", provider);
}
#[cfg(feature = "elevenlabs")]
if let Ok(api_key) = std::env::var("ELEVENLABS_API_KEY") {
registry.register(
"elevenlabs",
crate::providers::elevenlabs::ElevenLabsProvider::new(api_key),
);
}
#[cfg(feature = "gemini")]
if let Ok(api_key) = std::env::var("GEMINI_API_KEY") {
registry.register(
"gemini",
crate::providers::gemini::GeminiProvider::new(api_key),
);
}
registry
}
}