use std::sync::{Arc, Mutex};
use anyhow::{Context, Result};
use async_trait::async_trait;
use fastembed::{EmbeddingModel, InitOptions, TextEmbedding};
use super::EmbeddingService;
pub struct FastEmbedding {
model: Arc<Mutex<TextEmbedding>>,
}
impl FastEmbedding {
pub fn new() -> Result<Self> {
let model = TextEmbedding::try_new(
InitOptions::new(EmbeddingModel::AllMiniLML6V2).with_show_download_progress(true),
)
.map_err(|e| anyhow::anyhow!("loading fastembed model: {e}"))?;
Ok(Self { model: Arc::new(Mutex::new(model)) })
}
}
#[async_trait]
impl EmbeddingService for FastEmbedding {
async fn embed(&self, text: &str) -> Result<Vec<f32>> {
let model = self.model.clone();
let text = text.to_string();
tokio::task::spawn_blocking(move || {
let mut model = model.lock().unwrap();
let mut out = model
.embed(vec![text], None)
.map_err(|e| anyhow::anyhow!("fastembed inference: {e}"))?;
out.pop().context("fastembed returned no embedding")
})
.await
.context("fastembed task panicked")?
}
}