use crate::pooling::{pool, PoolingError, PoolingType};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum EncodeError {
#[error("an encoder needs at least one token; got an empty sequence")]
EmptySequence,
#[error(
"sequence of {got} tokens exceeds the {max} learned position embeddings this \
checkpoint carries ({arch}.context_length). A learned position table cannot be \
extrapolated the way RoPE can, so this is a hard limit, not a quality cliff — \
truncate the input or use a longer-context embedding model"
)]
TooLong {
got: usize,
max: usize,
arch: String,
},
#[error("token id {id} is outside this checkpoint's {vocab_size}-entry vocabulary")]
TokenOutOfRange { id: u32, vocab_size: usize },
#[error(transparent)]
Pooling(#[from] PoolingError),
}
pub trait TextEncoder {
fn n_embd(&self) -> usize;
fn n_ctx_train(&self) -> usize;
fn pooling_type(&self) -> PoolingType;
fn wrap_special(&self, pieces: &[u32]) -> Vec<u32> {
pieces.to_vec()
}
fn wrap_special_pair(&self, _a: &[u32], _b: &[u32]) -> Option<Vec<u32>> {
None
}
fn encode_tokens(&self, tokens: &[u32]) -> Result<Vec<f32>, EncodeError>;
fn embed_tokens(&self, tokens: &[u32]) -> Result<Vec<f32>, EncodeError> {
let hidden = self.encode_tokens(tokens)?;
Ok(pool(&hidden, self.n_embd(), self.pooling_type())?)
}
}