use std::sync::Arc;
use tokenizers::Tokenizer;
use super::StreamError;
const REPLACEMENT_CHARACTER: char = '\u{FFFD}';
pub trait TokenizerDecoder: Send {
fn decode_ids(&self, ids: &[u32], skip_special_tokens: bool) -> Result<String, String>;
}
impl TokenizerDecoder for Tokenizer {
fn decode_ids(&self, ids: &[u32], skip_special_tokens: bool) -> Result<String, String> {
self.decode(ids, skip_special_tokens)
.map_err(|error| error.to_string())
}
}
impl<T> TokenizerDecoder for Arc<T>
where
T: TokenizerDecoder + Sync,
{
fn decode_ids(&self, ids: &[u32], skip_special_tokens: bool) -> Result<String, String> {
(**self).decode_ids(ids, skip_special_tokens)
}
}
pub struct StreamDecoder {
decoder: Box<dyn TokenizerDecoder>,
ids: Vec<u32>,
pending: usize,
}
impl StreamDecoder {
pub fn new(decoder: Box<dyn TokenizerDecoder>) -> Self {
Self {
decoder,
ids: Vec::new(),
pending: 0,
}
}
pub fn decode(&mut self, token_id: u32) -> Result<Option<(String, usize)>, StreamError> {
self.pending += 1;
self.ids.push(token_id);
let content = self
.decoder
.decode_ids(&self.ids, false)
.map_err(|detail| StreamError::Decode { detail })?;
if content.is_empty() || content.ends_with(REPLACEMENT_CHARACTER) {
return Ok(None);
}
self.ids.clear();
Ok(Some((content, std::mem::take(&mut self.pending))))
}
}