Skip to main content

semtree_embed/
embedder.rs

1use async_trait::async_trait;
2
3use crate::{EmbedError, Embedding};
4
5#[async_trait]
6pub trait Embedder: Send + Sync {
7    async fn embed(&self, texts: &[&str]) -> Result<Vec<Embedding>, EmbedError>;
8
9    async fn embed_one(&self, text: &str) -> Result<Embedding, EmbedError> {
10        self.embed(&[text]).await.map(|mut v| v.remove(0))
11    }
12
13    /// Largest number of texts a single [`embed`](Embedder::embed) call should
14    /// receive. Callers indexing many chunks split their work into groups of at
15    /// most this size, bounding peak memory (local models) and request size
16    /// (remote APIs). The default suits the on-device models; raise or lower it
17    /// to match a backend's limits.
18    fn max_batch_size(&self) -> usize {
19        256
20    }
21
22    /// Number of dimensions every vector this embedder produces has.
23    ///
24    /// A store built for one dimension cannot hold vectors of another, so an
25    /// index persists this and refuses to mix them.
26    fn dimension(&self) -> usize;
27
28    /// Stable identifier for the model behind this embedder, e.g.
29    /// `"fastembed:AllMiniLML6V2"` or `"openai:text-embedding-3-small"`.
30    ///
31    /// It must stay the same across runs and versions for the *same* model, and
32    /// differ whenever the produced vectors would be incompatible. It is the
33    /// discriminating half of [`fingerprint`](Embedder::fingerprint).
34    fn model_id(&self) -> &str;
35
36    /// Fingerprint an index stores to detect that it was built with a different
37    /// embedder. Re-indexing is required whenever this changes.
38    fn fingerprint(&self) -> String {
39        format!("{}/{}d", self.model_id(), self.dimension())
40    }
41}