Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -129,6 +129,8 @@ Primary goals for reconcile rate:
|
|
| 129 |
- Fix MD-3: Check image pages — GLM often emits  plus <div align="center"> fragments
|
| 130 |
(e.g. 2293 $6,721.00 4/29/2025). Collapse detected gallery pages into one Check #|Amount|Date
|
| 131 |
table when bbox/image markers + repeated check lines are present; skips chunks with YOUR CHECKS SEQUENCED.
|
|
|
|
|
|
|
| 132 |
"""
|
| 133 |
|
| 134 |
# Patch asyncio first (before Gradio imports it) to suppress Python 3.13 cleanup noise
|
|
@@ -609,6 +611,59 @@ def _merge_blank_header_text_columns(grid):
|
|
| 609 |
return new_grid
|
| 610 |
|
| 611 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 612 |
def _fill_headless_trailing_amount_headers(grid):
|
| 613 |
"""
|
| 614 |
Fix 32a: PDF layouts often omit a header above the rightmost amount column; OCR leaves a
|
|
@@ -3142,6 +3197,9 @@ def normalize_html_tables(text: str) -> str:
|
|
| 3142 |
|
| 3143 |
grid = _drop_truly_empty_columns(grid)
|
| 3144 |
grid = _merge_blank_header_text_columns(grid)
|
|
|
|
|
|
|
|
|
|
| 3145 |
|
| 3146 |
grid = _fill_headless_trailing_amount_headers(grid)
|
| 3147 |
grid = _normalize_date_desc_money_table_alignment(grid)
|
|
|
|
| 129 |
- Fix MD-3: Check image pages — GLM often emits  plus <div align="center"> fragments
|
| 130 |
(e.g. 2293 $6,721.00 4/29/2025). Collapse detected gallery pages into one Check #|Amount|Date
|
| 131 |
table when bbox/image markers + repeated check lines are present; skips chunks with YOUR CHECKS SEQUENCED.
|
| 132 |
+
- Fix MD-4: YOUR CHECKS SEQUENCED wide grid (N×DATE|CHECK#|AMOUNT per row) is unfolded to one DATE|CHECK#|AMOUNT
|
| 133 |
+
table so narrow viewers show every check, not only the first date column.
|
| 134 |
"""
|
| 135 |
|
| 136 |
# Patch asyncio first (before Gradio imports it) to suppress Python 3.13 cleanup noise
|
|
|
|
| 611 |
return new_grid
|
| 612 |
|
| 613 |
|
| 614 |
+
def _split_wide_checks_sequenced_grid(grid: List[List[str]]) -> Optional[List[List[str]]]:
|
| 615 |
+
"""
|
| 616 |
+
Fix MD-4: Banks print YOUR CHECKS SEQUENCED as 2–3 side-by-side DATE|CHECK #|AMOUNT groups per row.
|
| 617 |
+
OCR HTML keeps that as 6–9 columns; narrow markdown previews only show the first date column.
|
| 618 |
+
Unfold into a single standard 3-column table (one row per check).
|
| 619 |
+
"""
|
| 620 |
+
if not grid or len(grid) < 2:
|
| 621 |
+
return None
|
| 622 |
+
header = [str(c or "").strip() for c in grid[0]]
|
| 623 |
+
header_join = " ".join(header).upper()
|
| 624 |
+
if "SEQUENCED" not in header_join or "CHECK" not in header_join:
|
| 625 |
+
return None
|
| 626 |
+
ncols = max(len(r) for r in grid if isinstance(r, list))
|
| 627 |
+
if ncols < 6 or ncols % 3 != 0:
|
| 628 |
+
return None
|
| 629 |
+
amt_cols = sum(1 for c in header if str(c or "").strip().upper() == "AMOUNT")
|
| 630 |
+
if amt_cols < 2 and ncols < 9:
|
| 631 |
+
return None
|
| 632 |
+
|
| 633 |
+
date_re = re.compile(r"^\d{1,2}/\d{2}(?:/\d{2,4})?$")
|
| 634 |
+
out: List[List[str]] = [["DATE", "CHECK #", "AMOUNT"]]
|
| 635 |
+
|
| 636 |
+
for row in grid[1:]:
|
| 637 |
+
cells = [str(c or "").strip() for c in row]
|
| 638 |
+
while len(cells) < ncols:
|
| 639 |
+
cells.append("")
|
| 640 |
+
cells = cells[:ncols]
|
| 641 |
+
c0 = cells[0] if cells else ""
|
| 642 |
+
joined = " ".join(cells)
|
| 643 |
+
|
| 644 |
+
if c0.startswith("=") and ("=" * 3 in c0 or len(c0) >= 8):
|
| 645 |
+
continue
|
| 646 |
+
if c0 and "=" in c0 and not c0.replace("=", "").strip():
|
| 647 |
+
continue
|
| 648 |
+
if "DATE" in c0.upper() and "CHECK" in c0.upper() and "AMOUNT" in c0.upper():
|
| 649 |
+
continue
|
| 650 |
+
if "GAP IN CHECK" in joined.upper() and "SEQUENCE" in joined.upper():
|
| 651 |
+
continue
|
| 652 |
+
|
| 653 |
+
for g in range(0, ncols, 3):
|
| 654 |
+
if g + 2 >= len(cells):
|
| 655 |
+
break
|
| 656 |
+
d, ck, am = cells[g], cells[g + 1], cells[g + 2]
|
| 657 |
+
if not d and not ck and not am:
|
| 658 |
+
continue
|
| 659 |
+
if d and date_re.match(d):
|
| 660 |
+
out.append([d, ck, am])
|
| 661 |
+
|
| 662 |
+
if len(out) < 2:
|
| 663 |
+
return None
|
| 664 |
+
return out
|
| 665 |
+
|
| 666 |
+
|
| 667 |
def _fill_headless_trailing_amount_headers(grid):
|
| 668 |
"""
|
| 669 |
Fix 32a: PDF layouts often omit a header above the rightmost amount column; OCR leaves a
|
|
|
|
| 3197 |
|
| 3198 |
grid = _drop_truly_empty_columns(grid)
|
| 3199 |
grid = _merge_blank_header_text_columns(grid)
|
| 3200 |
+
_seq_linear = _split_wide_checks_sequenced_grid(grid)
|
| 3201 |
+
if _seq_linear is not None:
|
| 3202 |
+
grid = _seq_linear
|
| 3203 |
|
| 3204 |
grid = _fill_headless_trailing_amount_headers(grid)
|
| 3205 |
grid = _normalize_date_desc_money_table_alignment(grid)
|