use serde_json::json;
use super::package::EpubPackage;
use crate::formats::html::common::ChunkRecordInput;
use crate::formats::html::page_aware::build_page_aware_chunks;
use crate::formats::html::section::build_section_chunks;
use crate::formats::html::semantic::build_semantic_chunks;
use crate::formats::html::sentence::build_sentence_chunks;
use crate::formats::html::sliding_window::build_sliding_window_chunks;
use crate::formats::html::structural::build_chunks_from_html_bytes;
use crate::formats::html::to_markdown::html_to_markdown_str;
fn build_for_mode(
bytes: &[u8],
mode: &str,
window_size: usize,
overlap: usize,
sentences_per_chunk: usize,
paragraphs_per_page: usize,
) -> Result<Vec<ChunkRecordInput>, String> {
match mode {
"default" | "structural" => build_chunks_from_html_bytes(bytes),
"section" => build_section_chunks(bytes),
"semantic" => build_semantic_chunks(bytes),
"sentence" => build_sentence_chunks(bytes, sentences_per_chunk),
"page_aware" => build_page_aware_chunks(bytes, paragraphs_per_page),
"sliding_window" => build_sliding_window_chunks(bytes, window_size, overlap),
other => Err(format!("Unknown EPUB mode: {other}")),
}
}
fn doc_metadata(pkg: &EpubPackage) -> serde_json::Value {
json!({
"source_type": "epub",
"title": pkg.title,
"language": pkg.language,
"creator": pkg.creator,
"identifier": pkg.identifier,
"epub_version": pkg.version,
"spine_count": pkg.spine.len(),
})
}
pub fn chunk_package(
pkg: &EpubPackage,
mode: &str,
window_size: usize,
overlap: usize,
sentences_per_chunk: usize,
paragraphs_per_page: usize,
) -> Result<Vec<ChunkRecordInput>, String> {
let meta = doc_metadata(pkg);
let mut out: Vec<ChunkRecordInput> = Vec::new();
for (spine_index, doc) in pkg.spine.iter().enumerate() {
let mut records = build_for_mode(
&doc.bytes,
mode,
window_size,
overlap,
sentences_per_chunk,
paragraphs_per_page,
)
.unwrap_or_default();
for rec in &mut records {
if let serde_json::Value::Object(map) = &mut rec.metadata {
map.insert("document_metadata".to_string(), meta.clone());
map.insert("spine_index".to_string(), json!(spine_index));
map.insert("href".to_string(), json!(doc.href));
}
}
out.append(&mut records);
}
Ok(out)
}
pub fn package_to_markdown(pkg: &EpubPackage) -> String {
let mut parts: Vec<String> = Vec::new();
if let Some(title) = &pkg.title {
parts.push(format!("# {title}"));
}
for doc in &pkg.spine {
let html = String::from_utf8_lossy(&doc.bytes);
let md = html_to_markdown_str(&html);
if !md.trim().is_empty() {
parts.push(md.trim().to_string());
}
}
parts.join("\n\n---\n\n").trim().to_string()
}