use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use ts_rs::TS;
use crate::error::AiMuxError;
use crate::shared::{SharedHeaders, SharedProviderMetadata, SharedProviderOptions, Warning};
use crate::{AbortSignal, retry, timeout};
pub type Embedding = Vec<f32>;
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct EmbeddingCallOptions {
pub values: Vec<String>,
#[serde(skip)]
#[ts(skip)]
pub abort_signal: Option<AbortSignal>,
pub max_retries: Option<u32>,
pub timeout: Option<crate::options::TimeoutConfiguration>,
pub provider_options: Option<SharedProviderOptions>,
pub headers: Option<SharedHeaders>,
}
impl EmbeddingCallOptions {
pub fn new(value: impl Into<String>) -> Self {
Self {
values: vec![value.into()],
abort_signal: None,
max_retries: None,
timeout: None,
provider_options: None,
headers: None,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct EmbeddingUsage {
pub tokens: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct EmbeddingResult {
pub embeddings: Vec<Embedding>,
pub usage: Option<EmbeddingUsage>,
pub provider_metadata: Option<SharedProviderMetadata>,
pub response: Option<EmbeddingResponse>,
pub warnings: Vec<Warning>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
#[ts(export)]
pub struct EmbeddingResponse {
pub headers: Option<SharedHeaders>,
pub body: Option<serde_json::Value>,
}
#[async_trait]
pub trait EmbeddingModel: Send + Sync {
fn specification_version(&self) -> &'static str {
"v4"
}
fn provider(&self) -> &str;
fn model_id(&self) -> &str;
fn retry_config(&self) -> crate::retry::RetryConfig {
crate::retry::RetryConfig::default()
}
fn max_embeddings_per_call(&self) -> Option<u32>;
fn supports_parallel_calls(&self) -> bool;
async fn do_embed(&self, options: &EmbeddingCallOptions)
-> Result<EmbeddingResult, AiMuxError>;
}
pub async fn embed(
model: &dyn EmbeddingModel,
options: EmbeddingCallOptions,
) -> Result<EmbeddingResult, AiMuxError> {
let timeout = timeout::OperationTimeout::new(options.timeout.unwrap_or_default())?;
let abort_signal = options.abort_signal.clone();
let retries = retry::prepare_retries(
options.max_retries,
model.retry_config(),
abort_signal.clone(),
);
timeout::run(
retries.retry(|| model.do_embed(&options)),
abort_signal.as_ref(),
timeout,
)
.await
}