fix(tables): Detect dense body-font tables and fix table-only page rendering
Raise BodyFont max_rows from 100 to 200 so tables with ~115 rows (like the Closed Business Accounts PDF) pass validation. Add date pattern recognition (MM/DD/YYYY, YYYY-MM-DD) to looks_like_table_data() so date columns count toward the 30% data threshold. Fix a bug where pages whose text is entirely consumed by tables produced empty output — the post-loop cleanup only checked current_page (stuck at 0), missing all table content. Now iterates all pages with uninserted tables/images. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
b2510ffe3e
commit
b6907494b6
+33
-22
@@ -489,32 +489,43 @@ fn to_markdown_from_lines_with_tables_and_images(
|
||||
in_paragraph = true;
|
||||
}
|
||||
|
||||
// Insert any remaining tables for the last page
|
||||
if let Some(tables) = page_tables.get(¤t_page) {
|
||||
for (idx, (_, table_md)) in tables.iter().enumerate() {
|
||||
if !inserted_tables.contains(&(current_page, idx)) {
|
||||
if in_paragraph {
|
||||
output.push_str("\n\n");
|
||||
in_paragraph = false;
|
||||
// Insert any remaining tables and images for all pages
|
||||
// (handles the case where all text was consumed by tables, leaving no lines to iterate)
|
||||
let mut remaining_pages: Vec<u32> = page_tables
|
||||
.keys()
|
||||
.chain(page_images.keys())
|
||||
.copied()
|
||||
.collect();
|
||||
remaining_pages.sort();
|
||||
remaining_pages.dedup();
|
||||
|
||||
for page in remaining_pages {
|
||||
if let Some(tables) = page_tables.get(&page) {
|
||||
for (idx, (_, table_md)) in tables.iter().enumerate() {
|
||||
if !inserted_tables.contains(&(page, idx)) {
|
||||
if in_paragraph {
|
||||
output.push_str("\n\n");
|
||||
in_paragraph = false;
|
||||
}
|
||||
output.push('\n');
|
||||
output.push_str(table_md);
|
||||
output.push('\n');
|
||||
inserted_tables.insert((page, idx));
|
||||
}
|
||||
output.push('\n');
|
||||
output.push_str(table_md);
|
||||
output.push('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert any remaining images for the last page
|
||||
if let Some(images) = page_images.get(¤t_page) {
|
||||
for (idx, (_, image_md)) in images.iter().enumerate() {
|
||||
if !inserted_images.contains(&(current_page, idx)) {
|
||||
if in_paragraph {
|
||||
output.push_str("\n\n");
|
||||
in_paragraph = false;
|
||||
if let Some(images) = page_images.get(&page) {
|
||||
for (idx, (_, image_md)) in images.iter().enumerate() {
|
||||
if !inserted_images.contains(&(page, idx)) {
|
||||
if in_paragraph {
|
||||
output.push_str("\n\n");
|
||||
in_paragraph = false;
|
||||
}
|
||||
output.push('\n');
|
||||
output.push_str(image_md);
|
||||
output.push('\n');
|
||||
inserted_images.insert((page, idx));
|
||||
}
|
||||
output.push('\n');
|
||||
output.push_str(image_md);
|
||||
output.push('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-1
@@ -373,7 +373,7 @@ fn detect_table_in_region(items: &[(usize, &TextItem)], mode: TableDetectionMode
|
||||
// Validation 3: tables shouldn't have too many rows (likely misdetected text)
|
||||
let max_rows = match mode {
|
||||
TableDetectionMode::SmallFont => 200,
|
||||
TableDetectionMode::BodyFont => 100,
|
||||
TableDetectionMode::BodyFont => 200,
|
||||
};
|
||||
if rows.len() > max_rows {
|
||||
return None;
|
||||
@@ -550,6 +550,16 @@ fn looks_like_table_data(s: &str) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dates: MM/DD/YYYY, DD/MM/YYYY, YYYY-MM-DD, etc.
|
||||
if s.len() <= 10
|
||||
&& s.chars().filter(|c| c.is_ascii_digit()).count() >= 4
|
||||
&& (s.contains('/') || s.contains('-'))
|
||||
&& s.chars()
|
||||
.all(|c| c.is_ascii_digit() || c == '/' || c == '-')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Part numbers / model codes (alphanumeric, typically short)
|
||||
// e.g., "NA555", "NE555", "LM358"
|
||||
if s.len() <= 10
|
||||
|
||||
Reference in New Issue
Block a user