use crate::character::merge_splits;
use crate::language::Language;
use crate::TextSplitter;
pub struct RecursiveCharacterTextSplitter {
separators: Vec<String>,
chunk_size: usize,
chunk_overlap: usize,
}
impl RecursiveCharacterTextSplitter {
pub fn new(chunk_size: usize) -> Self {
Self {
separators: vec![
"\n\n".to_string(),
"\n".to_string(),
" ".to_string(),
String::new(),
],
chunk_size,
chunk_overlap: 0,
}
}
pub fn with_separators(mut self, separators: Vec<String>) -> Self {
self.separators = separators;
self
}
pub fn from_language(language: Language, chunk_size: usize, chunk_overlap: usize) -> Self {
Self {
separators: language.separators(),
chunk_size,
chunk_overlap,
}
}
pub fn with_chunk_overlap(mut self, overlap: usize) -> Self {
self.chunk_overlap = overlap;
self
}
fn split_recursive(&self, text: &str, separator_idx: usize) -> Vec<String> {
if text.len() <= self.chunk_size {
return vec![text.to_string()];
}
if separator_idx >= self.separators.len() {
return text
.chars()
.collect::<Vec<char>>()
.chunks(self.chunk_size)
.map(|c| c.iter().collect::<String>())
.collect();
}
let separator = &self.separators[separator_idx];
if separator.is_empty() {
return text
.chars()
.collect::<Vec<char>>()
.chunks(self.chunk_size)
.map(|c| c.iter().collect::<String>())
.collect();
}
let splits: Vec<&str> = text.split(separator.as_str()).collect();
let mut final_chunks = Vec::new();
let mut good_splits: Vec<&str> = Vec::new();
for split in &splits {
if split.len() <= self.chunk_size {
good_splits.push(split);
} else {
if !good_splits.is_empty() {
let merged =
merge_splits(&good_splits, self.chunk_size, self.chunk_overlap, separator);
final_chunks.extend(merged);
good_splits.clear();
}
let sub_chunks = self.split_recursive(split, separator_idx + 1);
final_chunks.extend(sub_chunks);
}
}
if !good_splits.is_empty() {
let merged = merge_splits(&good_splits, self.chunk_size, self.chunk_overlap, separator);
final_chunks.extend(merged);
}
final_chunks
}
}
impl TextSplitter for RecursiveCharacterTextSplitter {
fn split_text(&self, text: &str) -> Vec<String> {
self.split_recursive(text, 0)
}
}