use std::path::Path;
use std::path::PathBuf;
use candle_core::DType;
use crate::embed::fit;
use crate::error::CanddingError;
use crate::error::Result;
use crate::loader::ModelFiles;
use crate::models::MultiVectorConventions;
use crate::models::MultiVectorHead;
use crate::registry::multi_vector::MultiVectorDescriptor;
use crate::tokenizer::PadToken;
use crate::tokenizer::TextTokenizer;
pub(super) fn conventions_from_descriptor(
descriptor: &MultiVectorDescriptor,
) -> MultiVectorConventions {
MultiVectorConventions {
keeps_cls_row: descriptor.keeps_cls_row,
projection_in: descriptor.projection_in,
projection_out: descriptor.projection_out,
projection_bias: descriptor.projection_bias,
normalize: descriptor.normalize,
attends_to_mask_tokens: descriptor.attends_to_mask_tokens,
position_scheme: descriptor.position_scheme,
}
}
pub(super) fn weight_files(
descriptor: &MultiVectorDescriptor,
files: &ModelFiles,
dtype: DType,
) -> Vec<(PathBuf, DType)> {
let mut weights = fit::at(&files.weights, dtype);
if descriptor.head == MultiVectorHead::M3Colbert
&& let Some(head) = &files.colbert_linear
{
weights.push((head.clone(), dtype));
}
weights
}
pub(super) fn require_fixed_query_length(
model: &str,
descriptor: &MultiVectorDescriptor,
) -> Result<()> {
if descriptor.head == MultiVectorHead::StanfordColbert && descriptor.query_length.is_none() {
return Err(CanddingError::MissingQueryLength {
model: model.to_string(),
});
}
Ok(())
}
pub(super) fn register_marker(tokenizer: &mut TextTokenizer, marker: Option<&str>) -> Result<()> {
if let Some(marker) = marker {
tokenizer.register_special_tokens(&[marker.trim()])?;
}
Ok(())
}
pub(super) fn build_query_tokenizer(
tokenizer_path: &Path,
max_length: usize,
pad: PadToken,
descriptor: &MultiVectorDescriptor,
max_position_embeddings: usize,
tokenizer_config: Option<&Path>,
) -> Result<TextTokenizer> {
let mut tokenizer = match descriptor.query_length {
Some(query_length) => {
let mask_token = crate::tokenizer::read_mask_token(tokenizer_config)?;
TextTokenizer::from_file_fixed_length(
tokenizer_path,
query_length.min(max_position_embeddings),
PadToken::Named(mask_token),
)?
}
None => TextTokenizer::from_file(tokenizer_path, max_length, pad)?,
};
register_marker(&mut tokenizer, descriptor.query_marker.as_deref())?;
Ok(tokenizer)
}