use crate::traits::{CerebroError, Embedder, Result};
use async_trait::async_trait;
use serde_json::json;
pub struct AnthropicVoyageEmbedder {
api_key: String,
model: String,
client: reqwest::Client,
}
impl AnthropicVoyageEmbedder {
pub fn new(api_key: impl Into<String>, model: &str) -> Self {
Self {
api_key: api_key.into(),
model: model.to_string(),
client: reqwest::Client::new(),
}
}
}
#[async_trait]
impl Embedder for AnthropicVoyageEmbedder {
async fn embed(&self, texts: &[&str]) -> Result<Vec<Vec<f32>>> {
let url = "https://api.voyageai.com/v1/embeddings";
let payload = json!({ "input": texts, "model": self.model });
let resp = self
.client
.post(url)
.bearer_auth(&self.api_key)
.json(&payload)
.send()
.await
.map_err(|e| CerebroError::EmbeddingError(e.to_string()))?;
if !resp.status().is_success() {
let err_text = resp.text().await.unwrap_or_default();
return Err(CerebroError::EmbeddingError(format!(
"Voyage AI API Error: {}",
err_text
)));
}
let data: serde_json::Value = resp
.json()
.await
.map_err(|e| CerebroError::EmbeddingError(e.to_string()))?;
let mut results = Vec::new();
if let Some(data_array) = data["data"].as_array() {
for item in data_array {
if let Some(embedding) = item["embedding"].as_array() {
let vec_f32: Vec<f32> = embedding
.iter()
.filter_map(|v| v.as_f64().map(|f| f as f32))
.collect();
results.push(vec_f32);
}
}
}
Ok(results)
}
}