feat(detector): Add per-page OCR routing with pages_needing_ocr field

For mixed PDFs, callers can now see exactly which pages need OCR instead
of re-analyzing the document. Phase 2 scan iterates all pages for Mixed
PDFs (caching sampled results), while TextBased gets empty and
Scanned/ImageBased gets all pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Abimael Martell
2026-02-16 10:13:52 -08:00
co-authored by Claude Opus 4.6
parent d8f341bafc
commit c815de9844
5 changed files with 157 additions and 17 deletions
+17 -1
View File
@@ -24,8 +24,13 @@ fn main() {
let elapsed = start.elapsed();
if json_output {
let ocr_pages: Vec<String> = result
.pages_needing_ocr
.iter()
.map(|p| p.to_string())
.collect();
println!(
r#"{{"pdf_type":"{}","page_count":{},"pages_sampled":{},"pages_with_text":{},"confidence":{:.2},"title":{},"ocr_recommended":{},"detection_time_ms":{}}}"#,
r#"{{"pdf_type":"{}","page_count":{},"pages_sampled":{},"pages_with_text":{},"confidence":{:.2},"title":{},"ocr_recommended":{},"pages_needing_ocr":[{}],"detection_time_ms":{}}}"#,
match result.pdf_type {
PdfType::TextBased => "text_based",
PdfType::Scanned => "scanned",
@@ -42,6 +47,7 @@ fn main() {
.map(|t| format!("\"{}\"", t.replace('"', "\\\"")))
.unwrap_or_else(|| "null".to_string()),
result.ocr_recommended,
ocr_pages.join(","),
elapsed.as_millis()
);
} else {
@@ -67,6 +73,16 @@ fn main() {
"OCR recommended: {}",
if result.ocr_recommended { "YES" } else { "NO" }
);
if !result.pages_needing_ocr.is_empty() {
if result.pages_needing_ocr.len() == result.page_count as usize {
println!("Pages needing OCR: all (of {})", result.page_count);
} else {
println!(
"Pages needing OCR: {:?} (of {})",
result.pages_needing_ocr, result.page_count
);
}
}
if let Some(title) = &result.title {
println!("Title: {}", title);
}