use crate::{DType, Engine, Error, Matrix, Result};
pub const VOCAB_SIZE: usize = 256;
pub const PAD: u8 = 0x00;
pub const BOS: u8 = 0x01;
pub const EOS: u8 = 0x02;
pub const SEP: u8 = 0x03;
pub fn encode(engine: &Engine, bytes: &[u8]) -> Result<Matrix> {
Matrix::from_slice(engine, [bytes.len()], bytes)
}
pub fn encode_batched(engine: &Engine, bytes: &[u8]) -> Result<Matrix> {
Matrix::from_slice(engine, [1, bytes.len()], bytes)
}
pub fn encode_text(engine: &Engine, text: &str) -> Result<Matrix> {
encode(engine, text.as_bytes())
}
pub fn decode(logits: &Matrix) -> Result<Vec<u8>> {
decode_sampled(logits, 0.0, 0, 1.0, 0)
}
pub fn sample(
logits: &Matrix,
temperature: f32,
top_k: i32,
top_p: f32,
seed: u64,
) -> Result<Vec<u8>> {
decode_sampled(logits, temperature, top_k, top_p, seed)
}
pub fn decode_text(logits: &Matrix) -> Result<String> {
String::from_utf8(decode(logits)?)
.map_err(|_| Error::data_loss("byte logits do not decode to valid UTF-8"))
}
fn decode_sampled(
logits: &Matrix,
temperature: f32,
top_k: i32,
top_p: f32,
seed: u64,
) -> Result<Vec<u8>> {
if logits.dtype() != DType::F32
|| !(1..=2).contains(&logits.shape().len())
|| logits.shape().last() != Some(&VOCAB_SIZE)
{
return Err(Error::invalid_argument(
"byte decoding requires rank-one or rank-two FP32 logits with 256 classes",
));
}
let ids = crate::matrix::sample_logits(logits, temperature, top_k, top_p, seed)?;
ids
.read::<i32>()?
.into_iter()
.map(|id| {
u8::try_from(id)
.map_err(|_| Error::internal("256-class byte sampling produced an out-of-range token"))
})
.collect()
}