use super::store::ModelProfile;
pub const MODEL_NAME: &str = "jinaai/jina-embeddings-v2-base-code";
pub const DIM: usize = 768;
pub const MAX_TOKENS: usize = 8192;
pub const MODEL_DIR: &str = env!("NORNIR_MODEL_DIR");
pub const WEIGHTS_SHA: &str = env!("NORNIR_MODEL_WEIGHTS_SHA");
pub const TOKENIZER_SHA: &str = env!("NORNIR_MODEL_TOKENIZER_SHA");
pub fn model_dir() -> std::path::PathBuf {
if let Ok(d) = std::env::var("NORNIR_MODEL_DIR") {
if !d.is_empty() {
return std::path::PathBuf::from(d);
}
}
let opt = std::path::Path::new("/opt/nornir/models");
if opt.join("tokenizer.json").exists() {
return opt.to_path_buf();
}
std::path::PathBuf::from(MODEL_DIR)
}
pub fn profile() -> ModelProfile {
ModelProfile {
model_name: MODEL_NAME.to_string(),
weights_sha: WEIGHTS_SHA.to_string(),
tokenizer_sha: TOKENIZER_SHA.to_string(),
pooling: "mean".to_string(),
normalize: true,
dim: DIM,
dtype: "f32".to_string(),
}
}
pub fn pool_and_normalize(hidden: &[f32], n_tokens: usize) -> Vec<f32> {
debug_assert_eq!(hidden.len(), n_tokens * DIM);
let mut v = vec![0f32; DIM];
for t in 0..n_tokens {
let row = &hidden[t * DIM..(t + 1) * DIM];
for (acc, &x) in v.iter_mut().zip(row) {
*acc += x;
}
}
let inv = 1.0 / n_tokens.max(1) as f32;
for x in &mut v {
*x *= inv;
}
l2_normalize(&mut v);
v
}
pub fn l2_normalize(v: &mut [f32]) {
let norm = v.iter().map(|x| x * x).sum::<f32>().sqrt();
if norm > 0.0 {
for x in v {
*x /= norm;
}
}
}
pub fn prepare_tokens(raw: &[u32]) -> (Vec<i64>, Vec<i64>) {
let n = raw.len().clamp(1, MAX_TOKENS);
let ids: Vec<i64> = raw[..n].iter().map(|&x| x as i64).collect();
let mask = vec![1i64; n];
(ids, mask)
}