Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -123,8 +123,11 @@ Primary goals for reconcile rate:
|
|
| 123 |
| Amount | Amount | (date+desc | amount | balance) or a four-column variant (date+desc
|
| 124 |
fragment | desc tail | amount | balance). CONT may be omitted by OCR. Downstream mis-maps
|
| 125 |
amount vs balance. Normalize to Date | Transaction Description | Transaction Amount | Balance.
|
| 126 |
-
- Fix DA4-dedupe: In 4-column
|
| 127 |
-
|
|
|
|
|
|
|
|
|
|
| 128 |
- Fix MD-1: Markdown fidelity — (a) collapse adjacent HTML tables that are the same register
|
| 129 |
(identical multiset of date + debit + credit + balance per row, descriptions may differ);
|
| 130 |
keep the table with richer description text so output matches the PDF once. (b) Common OCR
|
|
@@ -2985,9 +2988,22 @@ _BUSINESS_COOP_BANNER_FIRST_CELL_RE = re.compile(
|
|
| 2985 |
)
|
| 2986 |
|
| 2987 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2988 |
def _first_cell_is_business_coop_banner(s: str) -> bool:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2989 |
t = str(s or "").strip()
|
| 2990 |
-
|
|
|
|
|
|
|
| 2991 |
|
| 2992 |
|
| 2993 |
def _fix_business_coop_cont_three_col_register_grid(grid):
|
|
@@ -3007,9 +3023,11 @@ def _fix_business_coop_cont_three_col_register_grid(grid):
|
|
| 3007 |
scan = min(5, len(grid))
|
| 3008 |
for ri in range(scan):
|
| 3009 |
cells = [str(c or "").strip() for c in grid[ri]]
|
|
|
|
|
|
|
| 3010 |
while len(cells) < 3:
|
| 3011 |
cells.append("")
|
| 3012 |
-
if len(cells)
|
| 3013 |
continue
|
| 3014 |
if _first_cell_is_business_coop_banner(cells[0]) and _tight_cell(
|
| 3015 |
cells[1]
|
|
@@ -3094,13 +3112,13 @@ def _fix_business_coop_cont_four_col_register_grid(grid):
|
|
| 3094 |
hdr_idx = None
|
| 3095 |
for ri in range(min(6, len(grid))):
|
| 3096 |
cells = [str(c or "").strip() for c in grid[ri]]
|
| 3097 |
-
while len(cells)
|
| 3098 |
-
cells.
|
| 3099 |
-
if len(cells)
|
| 3100 |
continue
|
| 3101 |
if not _first_cell_is_business_coop_banner(cells[0]):
|
| 3102 |
continue
|
| 3103 |
-
if _tight_cell(cells[
|
| 3104 |
continue
|
| 3105 |
hdr_idx = ri
|
| 3106 |
break
|
|
@@ -3856,7 +3874,9 @@ def _is_da4_date_desc_amount_balance_header(grid):
|
|
| 3856 |
return False
|
| 3857 |
if "description" not in h[1]:
|
| 3858 |
return False
|
| 3859 |
-
|
|
|
|
|
|
|
| 3860 |
return False
|
| 3861 |
if "balance" not in h[3]:
|
| 3862 |
return False
|
|
|
|
| 123 |
| Amount | Amount | (date+desc | amount | balance) or a four-column variant (date+desc
|
| 124 |
fragment | desc tail | amount | balance). CONT may be omitted by OCR. Downstream mis-maps
|
| 125 |
amount vs balance. Normalize to Date | Transaction Description | Transaction Amount | Balance.
|
| 126 |
+
- Fix DA4-dedupe: In 4-column registers whose amount header is SEFCU-style (contains both \"transaction\"
|
| 127 |
+
and \"amount\"), consecutive rows identical on all four cells are OCR stutters — collapse to one;
|
| 128 |
+
honour text-layer counts when present. Skips tables with plain \"Amount\" / \"Balance($)\" headers.
|
| 129 |
+
- Fix SE-CONT banner guard: reject cells containing product words (checking, savings, inspire, advantage, …)
|
| 130 |
+
so Amegy / BofA marketing rows and Navy \"Business Checking-…\" continuations are never rewritten.
|
| 131 |
- Fix MD-1: Markdown fidelity — (a) collapse adjacent HTML tables that are the same register
|
| 132 |
(identical multiset of date + debit + credit + balance per row, descriptions may differ);
|
| 133 |
keep the table with richer description text so output matches the PDF once. (b) Common OCR
|
|
|
|
| 2988 |
)
|
| 2989 |
|
| 2990 |
|
| 2991 |
+
_BUSINESS_COOP_BANNER_REJECT_RE = re.compile(
|
| 2992 |
+
r"\b(checking|savings|inspire|advantage|mbr|premier|relationship)\b",
|
| 2993 |
+
re.IGNORECASE,
|
| 2994 |
+
)
|
| 2995 |
+
|
| 2996 |
+
|
| 2997 |
def _first_cell_is_business_coop_banner(s: str) -> bool:
|
| 2998 |
+
"""
|
| 2999 |
+
True only for CO-OP-style account banner cells (BUSINESS - <digits> [CONT]).
|
| 3000 |
+
Reject product lines like 'BUSINESS INSPIRE CHECKING …', 'Business Checking-…',
|
| 3001 |
+
or 'BUSINESS ADVANTAGE' so wide summary / Navy / Amegy tables are not rewritten.
|
| 3002 |
+
"""
|
| 3003 |
t = str(s or "").strip()
|
| 3004 |
+
if not t or _BUSINESS_COOP_BANNER_REJECT_RE.search(t):
|
| 3005 |
+
return False
|
| 3006 |
+
return bool(_BUSINESS_COOP_BANNER_FIRST_CELL_RE.match(t))
|
| 3007 |
|
| 3008 |
|
| 3009 |
def _fix_business_coop_cont_three_col_register_grid(grid):
|
|
|
|
| 3023 |
scan = min(5, len(grid))
|
| 3024 |
for ri in range(scan):
|
| 3025 |
cells = [str(c or "").strip() for c in grid[ri]]
|
| 3026 |
+
while len(cells) > 3 and cells[-1] == "":
|
| 3027 |
+
cells.pop()
|
| 3028 |
while len(cells) < 3:
|
| 3029 |
cells.append("")
|
| 3030 |
+
if len(cells) != 3:
|
| 3031 |
continue
|
| 3032 |
if _first_cell_is_business_coop_banner(cells[0]) and _tight_cell(
|
| 3033 |
cells[1]
|
|
|
|
| 3112 |
hdr_idx = None
|
| 3113 |
for ri in range(min(6, len(grid))):
|
| 3114 |
cells = [str(c or "").strip() for c in grid[ri]]
|
| 3115 |
+
while len(cells) > 4 and cells[-1] == "":
|
| 3116 |
+
cells.pop()
|
| 3117 |
+
if len(cells) != 4:
|
| 3118 |
continue
|
| 3119 |
if not _first_cell_is_business_coop_banner(cells[0]):
|
| 3120 |
continue
|
| 3121 |
+
if _tight_cell(cells[2]) != "amount" or _tight_cell(cells[3]) != "amount":
|
| 3122 |
continue
|
| 3123 |
hdr_idx = ri
|
| 3124 |
break
|
|
|
|
| 3874 |
return False
|
| 3875 |
if "description" not in h[1]:
|
| 3876 |
return False
|
| 3877 |
+
# Require "transaction" in the amount header (SEFCU-style) so fee / ledger /
|
| 3878 |
+
# daily tables with plain "Amount" or "Balance($)" are not deduped.
|
| 3879 |
+
if "transaction" not in h[2] or "amount" not in h[2]:
|
| 3880 |
return False
|
| 3881 |
if "balance" not in h[3]:
|
| 3882 |
return False
|