use async_trait::async_trait;
use crate::error::Result;
#[async_trait]
pub trait Embedder: Send + Sync + std::fmt::Debug + 'static {
async fn embed(&self, texts: &[String]) -> Result<Vec<Vec<f32>>>;
}
pub fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 {
if a.is_empty() || a.len() != b.len() {
return 0.0;
}
let (mut dot, mut na, mut nb) = (0.0f32, 0.0f32, 0.0f32);
for (x, y) in a.iter().zip(b) {
dot += x * y;
na += x * x;
nb += y * y;
}
if na == 0.0 || nb == 0.0 {
return 0.0;
}
dot / (na.sqrt() * nb.sqrt())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cosine_basics() {
let close = |a: f32, b: f32| (a - b).abs() < 1e-6;
assert!(close(cosine_similarity(&[1.0, 0.0], &[1.0, 0.0]), 1.0));
assert!(close(cosine_similarity(&[1.0, 0.0], &[0.0, 1.0]), 0.0));
assert!(close(cosine_similarity(&[1.0, 0.0], &[-1.0, 0.0]), -1.0));
assert!(close(cosine_similarity(&[], &[]), 0.0));
assert!(close(cosine_similarity(&[1.0], &[1.0, 2.0]), 0.0));
assert!(close(cosine_similarity(&[0.0, 0.0], &[1.0, 2.0]), 0.0));
}
}