use super::super::ChatTokenizer;
impl ChatTokenizer {
pub fn image_pad_token_id(&self, declared: u32) -> Option<u32> {
if declared != 0 {
return Some(declared);
}
self.encode("<|image_pad|>")
.ok()
.and_then(|ids| if ids.len() == 1 { Some(ids[0]) } else { None })
}
pub fn video_pad_token_id(&self, declared: u32) -> Option<u32> {
if declared != 0 {
return Some(declared);
}
self.encode("<|video_pad|>")
.ok()
.and_then(|ids| if ids.len() == 1 { Some(ids[0]) } else { None })
}
pub fn expand_vision_pads(
&self,
tokens: Vec<u32>,
pad_counts: &[usize],
declared: (u32, u32),
) -> Vec<u32> {
if pad_counts.is_empty() || pad_counts.iter().all(|&c| c <= 1) {
return tokens;
}
fan_out_pads(
tokens,
pad_counts,
self.image_pad_token_id(declared.0),
self.video_pad_token_id(declared.1),
)
}
}
pub(crate) fn fan_out_pads(
tokens: Vec<u32>,
pad_counts: &[usize],
image_pad: Option<u32>,
video_pad: Option<u32>,
) -> Vec<u32> {
if image_pad.is_none() && video_pad.is_none() {
return tokens;
}
let extra: usize = pad_counts.iter().map(|c| c.saturating_sub(1)).sum();
let mut out = Vec::with_capacity(tokens.len() + extra);
let mut img_idx = 0usize;
for t in tokens {
if Some(t) == image_pad || Some(t) == video_pad {
let count = pad_counts.get(img_idx).copied().unwrap_or(1).max(1);
for _ in 0..count {
out.push(t);
}
img_idx += 1;
} else {
out.push(t);
}
}
out
}
#[cfg(test)]
mod tests {
use super::fan_out_pads;
#[test]
fn a_declared_id_expands_where_a_literal_probe_would_not_have() {
let glm_image = 154_854u32;
let tokens = vec![1, 154_830, glm_image, 154_831, 2];
let out = fan_out_pads(tokens.clone(), &[256], Some(glm_image), None);
assert_eq!(out.len(), tokens.len() + 255);
assert_eq!(out.iter().filter(|&&t| t == glm_image).count(), 256);
assert_eq!(out[1], 154_830);
assert_eq!(*out.last().unwrap(), 2);
assert_eq!(out[out.len() - 2], 154_831);
assert_eq!(fan_out_pads(tokens.clone(), &[256], None, None), tokens);
}
#[test]
fn counts_are_consumed_in_order_across_both_modalities() {
let (img, vid) = (100u32, 101u32);
let out = fan_out_pads(vec![img, 7, vid, img], &[2, 3, 1], Some(img), Some(vid));
assert_eq!(out, vec![img, img, 7, vid, vid, vid, img]);
}
#[test]
fn a_short_count_list_does_not_reuse_the_last_count() {
let img = 100u32;
let out = fan_out_pads(vec![img, img], &[3], Some(img), None);
assert_eq!(out, vec![img, img, img, img]);
}
}