pub mod completion;
pub mod error;
pub mod types;
use crate::core::types::{GenerateOptions, GenerateResult, Prompt, ProviderSettings, StreamPart};
use crate::openai::OpenAIModel;
use async_trait::async_trait;
use futures::stream::BoxStream;
use reqwest::Client;
pub struct DeepSeekModel {
pub inner: OpenAIModel,
}
impl DeepSeekModel {
#[must_use]
pub fn new(api_key: String) -> Self {
Self {
inner: OpenAIModel {
api_key,
base_url: "https://api.deepseek.com".to_string(),
client: Client::new(),
},
}
}
#[must_use]
pub fn completion(&self) -> completion::DeepSeekCompletionModel {
completion::DeepSeekCompletionModel::new(
self.inner.api_key.clone(),
self.inner.base_url.clone(),
)
}
}
#[async_trait]
impl crate::core::LanguageModel for DeepSeekModel {
#[tracing::instrument(skip(self, prompt), fields(model = options.model_id))]
async fn generate(
&self,
prompt: Prompt,
options: GenerateOptions,
) -> crate::core::Result<GenerateResult> {
self.inner.generate(prompt, options).await
}
async fn generate_stream(
&self,
prompt: Prompt,
options: GenerateOptions,
) -> crate::core::Result<BoxStream<'static, StreamPart>> {
self.inner.generate_stream(prompt, options).await
}
}
pub struct DeepSeekProvider {
settings: ProviderSettings,
}
impl DeepSeekProvider {
#[must_use]
pub fn chat(&self, _model_id: &str) -> DeepSeekModel {
let api_key = self
.settings
.api_key
.clone()
.or_else(|| std::env::var("DEEPSEEK_API_KEY").ok())
.unwrap_or_default();
let base_url = self
.settings
.base_url
.clone()
.unwrap_or_else(|| "https://api.deepseek.com".to_string());
DeepSeekModel {
inner: OpenAIModel {
api_key,
base_url,
client: Client::new(),
},
}
}
#[must_use]
pub fn language_model(&self, model_id: &str) -> DeepSeekModel {
self.chat(model_id)
}
pub async fn get_balance(&self) -> crate::core::Result<types::DeepSeekBalanceResponse> {
let api_key = self
.settings
.api_key
.clone()
.or_else(|| std::env::var("DEEPSEEK_API_KEY").ok())
.unwrap_or_default();
let base_url = self
.settings
.base_url
.clone()
.unwrap_or_else(|| "https://api.deepseek.com".to_string());
let url = format!("{}/user/balance", base_url);
let client = Client::new();
let response = client
.get(&url)
.header("Authorization", format!("Bearer {}", api_key))
.send()
.await?;
if !response.status().is_success() {
let error_text = response.text().await.unwrap_or_default();
return Err(crate::core::ProviderError::Network(error_text));
}
let balance: types::DeepSeekBalanceResponse = response
.json()
.await
.map_err(|e| crate::core::ProviderError::InvalidResponse(e.to_string()))?;
Ok(balance)
}
#[must_use]
pub fn completion(&self, _model_id: &str) -> completion::DeepSeekCompletionModel {
let api_key = self
.settings
.api_key
.clone()
.or_else(|| std::env::var("DEEPSEEK_API_KEY").ok())
.unwrap_or_default();
let base_url = self
.settings
.base_url
.clone()
.unwrap_or_else(|| "https://api.deepseek.com".to_string());
completion::DeepSeekCompletionModel::new(api_key, base_url)
}
pub async fn list_models(&self) -> crate::core::Result<types::DeepSeekModelsResponse> {
let api_key = self
.settings
.api_key
.clone()
.or_else(|| std::env::var("DEEPSEEK_API_KEY").ok())
.unwrap_or_default();
let base_url = self
.settings
.base_url
.clone()
.unwrap_or_else(|| "https://api.deepseek.com".to_string());
let url = format!("{}/models", base_url);
let client = Client::new();
let response = client
.get(&url)
.header("Authorization", format!("Bearer {}", api_key))
.send()
.await?;
if !response.status().is_success() {
let error_text = response.text().await.unwrap_or_default();
return Err(crate::core::ProviderError::Network(error_text));
}
let models: types::DeepSeekModelsResponse = response
.json()
.await
.map_err(|e| crate::core::ProviderError::InvalidResponse(e.to_string()))?;
Ok(models)
}
}
#[must_use]
pub fn create_deepseek(settings: ProviderSettings) -> DeepSeekProvider {
DeepSeekProvider { settings }
}
impl crate::core::registry::Provider for DeepSeekProvider {
fn language_model(&self, model_id: &str) -> Option<Box<dyn crate::core::LanguageModel>> {
Some(Box::new(self.chat(model_id)))
}
fn completion_model(&self, model_id: &str) -> Option<Box<dyn crate::core::CompletionModel>> {
Some(Box::new(self.completion(model_id)))
}
}