use super::Tokenizer;
use crate::error::{Error, Result};
#[derive(Debug, Clone)]
pub struct DecodeStream<'tok> {
tokenizer: &'tok Tokenizer,
skip_special_tokens: bool,
ids: Vec<u32>,
prefix: String,
prefix_index: usize,
}
impl<'tok> DecodeStream<'tok> {
pub(crate) fn new(tokenizer: &'tok Tokenizer, skip_special_tokens: bool) -> Self {
Self {
tokenizer,
skip_special_tokens,
ids: Vec::new(),
prefix: String::new(),
prefix_index: 0,
}
}
#[must_use]
pub fn prefill(mut self, ids: &[u32]) -> Self {
self.ids.extend_from_slice(ids);
self
}
pub fn step(&mut self, id: u32) -> Result<Option<String>> {
self.step_many(&[id])
}
pub fn step_many(&mut self, ids: &[u32]) -> Result<Option<String>> {
let (tokenizer, skip) = (self.tokenizer, self.skip_special_tokens);
let decode = |ids: &[u32]| tokenizer.decode(ids, skip);
if self.prefix.is_empty() && !self.ids.is_empty() {
let prefix = decode(&self.ids)?;
if !prefix.ends_with('\u{FFFD}') {
self.prefix = prefix;
self.prefix_index = self.ids.len();
}
}
self.ids.extend_from_slice(ids);
let text = decode(&self.ids)?;
if text.len() <= self.prefix.len() || text.ends_with('\u{FFFD}') {
return Ok(None);
}
let Some(new_text) = text.strip_prefix(self.prefix.as_str()) else {
return Err(Error::Decoder(format!(
"stream decode: text {text:?} for id {} does not start with the \
previously decoded {:?}",
self.ids.last().copied().unwrap_or_default(),
self.prefix
)));
};
let new_text = new_text.to_owned();
let new_prefix_index = self.ids.len() - self.prefix_index;
self.ids.drain(..self.prefix_index);
self.prefix = decode(&self.ids)?;
self.prefix_index = new_prefix_index;
Ok(Some(new_text))
}
}