Skip to main content

fathomdb_embedder_api/
lib.rs

1pub type Vector = Vec<f32>;
2
3#[derive(Clone, Debug, Eq, PartialEq)]
4pub struct EmbedderIdentity {
5    pub name: String,
6    pub revision: String,
7    pub dimension: u32,
8}
9
10impl EmbedderIdentity {
11    #[must_use]
12    pub fn new(name: impl Into<String>, revision: impl Into<String>, dimension: u32) -> Self {
13        Self { name: name.into(), revision: revision.into(), dimension }
14    }
15}
16
17#[derive(Clone, Debug, Eq, PartialEq)]
18pub enum EmbedderError {
19    Failed { message: String },
20    Timeout,
21}
22
23pub trait Embedder: Send + Sync {
24    fn identity(&self) -> EmbedderIdentity;
25
26    fn embed(&self, input: &str) -> Result<Vector, EmbedderError>;
27
28    /// Embed many inputs in one call. The default implementation loops [`embed`],
29    /// so every backend works unchanged; backends with a true batched forward
30    /// (e.g. the candle GPU path) override this to amortize per-call overhead and
31    /// saturate the device (minutes -> seconds on a full-corpus embed).
32    ///
33    /// Contract: `embed_batch` MUST be numerically equivalent (within float
34    /// tolerance) to calling [`embed`] on each input, so a caller can switch to
35    /// batching WITHOUT changing the vectors written to an index. Locked by a
36    /// parity test in the default-embedder crate.
37    ///
38    /// [`embed`]: Embedder::embed
39    fn embed_batch(&self, inputs: &[&str]) -> Result<Vec<Vector>, EmbedderError> {
40        inputs.iter().map(|input| self.embed(input)).collect()
41    }
42}