use crate::embedding::{EMBED_MODEL_ID, EMBED_MODEL_REVISION};
use crate::errors::Error;
pub const BUILTIN_PROFILES: &[ModelProfile] = &[
ModelProfile {
model_id: EMBED_MODEL_ID,
revision: EMBED_MODEL_REVISION,
onnx_path: "onnx/model.onnx",
query_prefix: "",
passage_prefix: "",
},
ModelProfile {
model_id: "intfloat/multilingual-e5-small",
revision: "614241f622f53c4eeff9890bdc4f31cfecc418b3",
onnx_path: "onnx/model.onnx",
query_prefix: "query: ",
passage_prefix: "passage: ",
},
];
#[derive(Debug)]
pub struct ModelProfile {
pub model_id: &'static str,
pub revision: &'static str,
pub onnx_path: &'static str,
pub query_prefix: &'static str,
pub passage_prefix: &'static str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EmbeddingRole {
Passage,
Query,
}
impl EmbeddingRole {
pub fn prefix(self, profile: &ModelProfile) -> &'static str {
match self {
EmbeddingRole::Passage => profile.passage_prefix,
EmbeddingRole::Query => profile.query_prefix,
}
}
}
pub fn available_profile_ids() -> Vec<&'static str> {
BUILTIN_PROFILES.iter().map(|p| p.model_id).collect()
}
pub fn profile_for(model_id: &str) -> Result<&'static ModelProfile, Error> {
BUILTIN_PROFILES
.iter()
.find(|p| p.model_id == model_id)
.ok_or_else(|| {
let available = available_profile_ids().join(", ");
Error::Config(format!(
"Unknown embedding model '{model_id}'. Available built-in models: {available}"
))
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bge_profile_declares_expected_values() {
let p = profile_for("BAAI/bge-small-en-v1.5").expect("bge profile");
assert_eq!(p.model_id, "BAAI/bge-small-en-v1.5");
assert_eq!(p.revision, "5c38ec7c405ec4b44b94cc5a9bb96e735b38267a");
assert_eq!(p.onnx_path, "onnx/model.onnx");
assert_eq!(p.query_prefix, "");
assert_eq!(p.passage_prefix, "");
}
#[test]
fn e5_profile_declares_expected_values() {
let p = profile_for("intfloat/multilingual-e5-small").expect("e5 profile");
assert_eq!(p.model_id, "intfloat/multilingual-e5-small");
assert_eq!(p.revision, "614241f622f53c4eeff9890bdc4f31cfecc418b3");
assert_eq!(p.onnx_path, "onnx/model.onnx");
assert_eq!(p.query_prefix, "query: ");
assert_eq!(p.passage_prefix, "passage: ");
}
#[test]
fn unknown_model_id_is_rejected_listing_available_profiles() {
let err = profile_for("someone/else-model").unwrap_err();
let msg = match err {
Error::Config(msg) => msg,
other => panic!("expected Error::Config, got {other:?}"),
};
assert!(
msg.contains("someone/else-model"),
"error must name the bad id: {msg}"
);
assert!(
msg.contains("BAAI/bge-small-en-v1.5"),
"error must list the bge profile: {msg}"
);
assert!(
msg.contains("intfloat/multilingual-e5-small"),
"error must list the e5 profile: {msg}"
);
}
#[test]
fn no_profile_uses_a_floating_revision() {
for p in BUILTIN_PROFILES {
assert!(
p.revision != "main" && !p.revision.is_empty(),
"profile {} must be pinned to an exact revision, not {}",
p.model_id,
p.revision
);
}
}
#[test]
fn default_profile_is_bge() {
assert_eq!(BUILTIN_PROFILES[0].model_id, "BAAI/bge-small-en-v1.5");
}
#[test]
fn available_profile_ids_lists_all_builtins() {
let ids = available_profile_ids();
assert_eq!(ids.len(), 2);
assert!(ids.contains(&"BAAI/bge-small-en-v1.5"));
assert!(ids.contains(&"intfloat/multilingual-e5-small"));
}
}