use std::ptr;
use ik_llama_cpp_sys as sys;
use crate::context::LlamaContext;
use crate::token::data::LlamaTokenData;
use crate::token::LlamaToken;
#[derive(Debug, Clone, PartialEq)]
pub struct LlamaTokenDataArray {
pub data: Vec<LlamaTokenData>,
pub selected: Option<usize>,
pub sorted: bool,
}
impl LlamaTokenDataArray {
#[must_use]
pub fn new(data: Vec<LlamaTokenData>, sorted: bool) -> Self {
Self {
data,
selected: None,
sorted,
}
}
pub fn from_iter<T>(data: T, sorted: bool) -> LlamaTokenDataArray
where
T: IntoIterator<Item = LlamaTokenData>,
{
Self::new(data.into_iter().collect(), sorted)
}
#[must_use]
pub fn from_logits(logits: &[f32]) -> Self {
let data = logits
.iter()
.enumerate()
.map(|(i, &logit)| LlamaTokenData::new(LlamaToken(i as sys::llama_token), logit, 0.0))
.collect();
Self::new(data, false)
}
#[must_use]
pub fn selected_token(&self) -> Option<LlamaToken> {
self.data.get(self.selected?).map(LlamaTokenData::id)
}
pub fn apply_repetition_penalties(
&mut self,
ctx: &mut LlamaContext,
last_tokens: &[LlamaToken],
penalty_repeat: f32,
penalty_freq: f32,
penalty_present: f32,
) {
let raw: Vec<sys::llama_token> = last_tokens.iter().map(|t| t.0).collect();
let ctx_ptr = ctx.as_ptr();
unsafe {
self.modify_as_c_llama_token_data_array(|c| {
sys::llama_sample_repetition_penalties(
ctx_ptr,
c,
raw.as_ptr(),
raw.len(),
penalty_repeat,
penalty_freq,
penalty_present,
);
});
}
}
pub(crate) fn as_c(&mut self) -> sys::llama_token_data_array {
sys::llama_token_data_array {
data: self.data.as_mut_ptr().cast::<sys::llama_token_data>(),
size: self.data.len(),
selected: self.selected.and_then(|s| s.try_into().ok()).unwrap_or(-1),
sorted: self.sorted,
}
}
pub(crate) unsafe fn modify_as_c_llama_token_data_array<T>(
&mut self,
modify: impl FnOnce(&mut sys::llama_token_data_array) -> T,
) -> T {
let data = self.data.as_mut_ptr().cast::<sys::llama_token_data>();
let mut c = sys::llama_token_data_array {
data,
size: self.data.len(),
selected: self.selected.and_then(|s| s.try_into().ok()).unwrap_or(-1),
sorted: self.sorted,
};
let result = modify(&mut c);
assert!(
c.size <= self.data.capacity(),
"sampler returned an array larger than the candidate buffer capacity"
);
if !ptr::eq(c.data, data) {
ptr::copy(c.data, data, c.size);
}
self.data.set_len(c.size);
self.sorted = c.sorted;
self.selected = c.selected.try_into().ok().filter(|&s| s < self.data.len());
result
}
}