mod byte_fallback;
mod byte_level;
mod replace;
use crate::json_structs::{DecoderConfig, DecoderKind};
pub use self::byte_fallback::ByteFallbackDecoder;
pub use self::byte_level::ByteLevelDecoder;
pub use self::replace::ReplaceDecoder;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("invalid config value: {0}")]
Json(#[from] serde_json::Error),
#[error("regex error: {0}")]
Regex(#[from] fancy_regex::Error),
#[error("unsupported decoder type: {0}")]
Unsupported(String),
}
impl From<crate::normalizers::Error> for Error {
fn from(e: crate::normalizers::Error) -> Self {
match e {
crate::normalizers::Error::Json(j) => Self::Json(j),
crate::normalizers::Error::Regex(r) => Self::Regex(r),
crate::normalizers::Error::Unsupported(s) => Self::Unsupported(s),
}
}
}
#[derive(Debug)]
pub enum Decoder {
ByteFallback(ByteFallbackDecoder),
ByteLevel(ByteLevelDecoder),
Replace(ReplaceDecoder),
Fuse,
Strip {
content: char,
start: usize,
stop: usize,
},
Sequence(Vec<Decoder>),
}
fn strip_token(token: &str, content: char, start: usize, stop: usize) -> String {
let chars: Vec<char> = token.chars().collect();
let mut start_cut = 0;
for (i, &c) in chars.iter().enumerate().take(start) {
if c == content {
start_cut = i + 1;
} else {
break;
}
}
let mut stop_cut = chars.len();
for (i, &c) in chars.iter().rev().enumerate().take(stop) {
if c == content {
stop_cut = chars.len() - (i + 1);
} else {
break;
}
}
if start_cut >= stop_cut {
return String::new();
}
chars[start_cut..stop_cut].iter().collect()
}
impl Decoder {
pub fn from_config(config: DecoderConfig) -> Result<Self, Error> {
match config {
DecoderConfig::ByteFallback => Ok(Self::ByteFallback(ByteFallbackDecoder)),
DecoderConfig::ByteLevel => Ok(Self::ByteLevel(ByteLevelDecoder)),
DecoderConfig::Replace { pattern, content } => Ok(Self::Replace(
ReplaceDecoder::from_config(pattern, content)?,
)),
DecoderConfig::Strip {
content,
start,
stop,
} => Ok(Self::Strip {
content,
start,
stop,
}),
DecoderConfig::Fuse => Ok(Self::Fuse),
DecoderConfig::Sequence { decoders } => {
let steps = decoders
.into_iter()
.map(Self::from_config)
.collect::<Result<Vec<_>, _>>()?;
Ok(Self::Sequence(steps))
}
DecoderConfig::Other(v) => {
let typ = v.get("type").and_then(|t| t.as_str()).unwrap_or("unknown");
Err(Error::Unsupported(typ.to_string()))
}
other => {
let kind = DecoderKind::from(&other);
Err(Error::Unsupported(kind.to_string()))
}
}
}
pub fn decode_chain(&self, tokens: Vec<String>) -> Result<Vec<String>, Error> {
match self {
Self::ByteFallback(bf) => Ok(bf.decode_chain(tokens)),
Self::ByteLevel(bl) => Ok(bl.decode_chain(tokens)),
Self::Replace(repl) => Ok(repl.decode_chain(tokens)),
Self::Fuse => Ok(vec![tokens.concat()]),
Self::Strip {
content,
start,
stop,
} => Ok(tokens
.into_iter()
.map(|t| strip_token(&t, *content, *start, *stop))
.collect()),
Self::Sequence(steps) => {
let mut current = tokens;
for step in steps {
current = step.decode_chain(current)?;
}
Ok(current)
}
}
}
pub fn decode(&self, tokens: Vec<String>) -> Result<String, Error> {
let result = self.decode_chain(tokens)?;
Ok(result.join(""))
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn toks(v: &[&str]) -> Vec<String> {
v.iter().map(|s| s.to_string()).collect()
}
#[test]
fn strip_token_removes_leading_and_trailing() {
assert_eq!(strip_token(" hi ", ' ', 1, 0), " hi ");
assert_eq!(strip_token(" hi ", ' ', 2, 1), "hi");
assert_eq!(strip_token("hi", ' ', 1, 1), "hi");
assert_eq!(strip_token(" ", ' ', 1, 1), " ");
assert_eq!(strip_token(" ", ' ', 3, 0), "");
}
#[test]
fn fuse_then_strip_matches_sentencepiece() {
let dec = Decoder::from_config(DecoderConfig::Sequence {
decoders: vec![
DecoderConfig::Replace {
pattern: json!({ "String": "\u{2581}" }),
content: " ".to_string(),
},
DecoderConfig::Fuse,
DecoderConfig::Strip {
content: ' ',
start: 1,
stop: 0,
},
],
})
.unwrap();
assert_eq!(
dec.decode(toks(&["\u{2581}Hello", "\u{2581}world"]))
.unwrap(),
"Hello world"
);
}
#[test]
fn fuse_alone_concatenates() {
let dec = Decoder::from_config(DecoderConfig::Fuse).unwrap();
assert_eq!(
dec.decode_chain(toks(&["a", "b", "c"])).unwrap(),
vec!["abc"]
);
}
}