const PER_MESSAGE_OVERHEAD: u64 = 4;
pub fn estimate_text(text: &str) -> u64 {
(text.len() as u64).div_ceil(4)
}
pub fn estimate_prompt<'a>(system: Option<&str>, parts: impl IntoIterator<Item = &'a str>) -> u64 {
let mut total = 0;
if let Some(s) = system {
total += estimate_text(s) + PER_MESSAGE_OVERHEAD;
}
for part in parts {
total += estimate_text(part) + PER_MESSAGE_OVERHEAD;
}
total
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ascii_is_about_four_chars_per_token() {
assert_eq!(estimate_text("abcdefghijklmnop"), 4);
}
#[test]
fn cyrillic_is_denser_per_char() {
assert_eq!(estimate_text("текс"), 2);
}
#[test]
fn non_empty_text_is_at_least_one_token() {
assert_eq!(estimate_text("a"), 1);
assert_eq!(estimate_text(""), 0);
}
#[test]
fn prompt_sums_messages_with_overhead() {
let est = estimate_prompt(Some("ab"), ["cd", "cd"]);
assert_eq!(est, 5 + 10);
}
}