use std::env;
use async_trait::async_trait;
use crate::error::Result as SdkResult;
use super::interface::{
GenerateRequest, GenerateResponse, LanguageModel, StreamHandle, StreamRequest,
};
use super::openai_chat::{OpenAiChatConfig, OpenAiChatProvider};
const DEFAULT_BASE_URL: &str = "http://localhost:11434/v1";
const MODEL_PREFIX: &str = "ollama";
#[derive(Clone, Debug)]
pub struct OllamaConfig {
pub api_key: Option<String>,
pub base_url: String,
}
impl OllamaConfig {
pub fn new() -> Self {
Self {
api_key: None,
base_url: DEFAULT_BASE_URL.to_string(),
}
}
pub fn with_api_key(mut self, api_key: impl Into<String>) -> Self {
self.api_key = Some(api_key.into());
self
}
pub fn with_base_url(mut self, base_url: impl Into<String>) -> Self {
self.base_url = base_url.into();
self
}
pub fn from_env() -> SdkResult<Self> {
let mut config = OllamaConfig::new();
if let Ok(base) = env::var("OLLAMA_BASE_URL") {
if !base.trim().is_empty() {
config.base_url = base;
}
}
if let Ok(api_key) = env::var("OLLAMA_API_KEY") {
if !api_key.trim().is_empty() {
config.api_key = Some(api_key);
}
}
Ok(config)
}
}
impl Default for OllamaConfig {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone)]
pub struct OllamaProvider {
inner: OpenAiChatProvider,
}
impl OllamaProvider {
pub fn new(config: OllamaConfig) -> SdkResult<Self> {
let api_key = config.api_key.unwrap_or_else(|| "ollama".to_string());
let inner_config = OpenAiChatConfig::new(api_key)
.with_base_url(config.base_url)
.with_model_prefix(Some(MODEL_PREFIX));
let inner = OpenAiChatProvider::new(inner_config)?;
Ok(Self { inner })
}
pub fn from_env() -> SdkResult<Self> {
let config = OllamaConfig::from_env()?;
Self::new(config)
}
pub async fn generate(&self, request: GenerateRequest) -> SdkResult<GenerateResponse> {
self.inner.generate(request).await
}
pub async fn stream(&self, request: StreamRequest) -> SdkResult<StreamHandle> {
self.inner.stream(request).await
}
}
#[async_trait]
impl LanguageModel for OllamaProvider {
async fn generate(&self, request: GenerateRequest) -> SdkResult<GenerateResponse> {
self.inner.generate(request).await
}
async fn stream(&self, request: StreamRequest) -> SdkResult<StreamHandle> {
self.inner.stream(request).await
}
}