Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -51,6 +51,10 @@ Primary goals for reconcile rate:
|
|
| 51 |
and the first is mostly credit/deposit rows while the second is mostly debit/withdrawal-style
|
| 52 |
rows (generic keywords), drop the second β fixes OCR pasting the withdrawals block again.
|
| 53 |
- Fix 23b: Loose multiset keys use normalized float amounts so comma/spacing variants still match.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
"""
|
| 55 |
|
| 56 |
# Patch asyncio first (before Gradio imports it) to suppress Python 3.13 cleanup noise
|
|
@@ -3476,6 +3480,37 @@ def _strip_orphan_continued_da3_flatline(text: str) -> str:
|
|
| 3476 |
return "".join(out)
|
| 3477 |
|
| 3478 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3479 |
def _patch_da3_msft_g_ref_amounts_across_tables(text: str) -> str:
|
| 3480 |
"""
|
| 3481 |
Fix 21: Build MICROSOFT#G⦠-> strict Amount from any DA3 row, then patch other DA3 rows
|
|
@@ -3723,18 +3758,29 @@ def _dedupe_subset_transaction_tables_html(text: str) -> str:
|
|
| 3723 |
ci = _row_counter_loose_da3(gi)
|
| 3724 |
cj = _row_counter_loose_da3(gj)
|
| 3725 |
ni, nj = sum(ci.values()), sum(cj.values())
|
| 3726 |
-
if ni >=
|
| 3727 |
oi_j = _overlap_ratio_counter(ci, cj)
|
| 3728 |
oj_i = _overlap_ratio_counter(cj, ci)
|
| 3729 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3730 |
drop_idx.add(i)
|
| 3731 |
break
|
| 3732 |
-
if
|
| 3733 |
-
|
| 3734 |
-
|
| 3735 |
-
|
| 3736 |
-
|
| 3737 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3738 |
|
| 3739 |
if not drop_idx:
|
| 3740 |
return t
|
|
@@ -3905,6 +3951,7 @@ def stabilize_tables_and_text(page_md: str) -> str:
|
|
| 3905 |
stabilized = "\n\n".join(out_blocks)
|
| 3906 |
stabilized = convert_plaintext_bank_sections(stabilized)
|
| 3907 |
stabilized = _strip_orphan_continued_da3_flatline(stabilized)
|
|
|
|
| 3908 |
stabilized = normalize_html_tables(stabilized)
|
| 3909 |
stabilized = _trim_adjacent_da3_suffix_duplicating_next_table_prefix(stabilized)
|
| 3910 |
stabilized = _split_ucb_deposits_electronic_sections_html(stabilized)
|
|
@@ -3912,6 +3959,7 @@ def stabilize_tables_and_text(page_md: str) -> str:
|
|
| 3912 |
stabilized = _dedupe_subset_transaction_tables_html(stabilized)
|
| 3913 |
stabilized = _drop_da3_misplaced_debit_after_deposit_heading_tables(stabilized)
|
| 3914 |
stabilized = _strip_orphan_continued_da3_flatline(stabilized)
|
|
|
|
| 3915 |
return close_unclosed_html(stabilized)
|
| 3916 |
|
| 3917 |
# --------------------------
|
|
@@ -4036,6 +4084,7 @@ def run_ocr(uploaded_file):
|
|
| 4036 |
if is_pdf and not is_nfcu_doc:
|
| 4037 |
stabilized = _patch_ocr_with_textlayer(stabilized, path, page_num)
|
| 4038 |
stabilized = _strip_orphan_continued_da3_flatline(stabilized)
|
|
|
|
| 4039 |
# _patch_ocr_with_textlayer may append Case B rows from the PDF text layer
|
| 4040 |
# with fused UCB-style cells; run the same HTML table pass again (Fix 13/14).
|
| 4041 |
stabilized = normalize_html_tables(stabilized)
|
|
@@ -4044,6 +4093,7 @@ def run_ocr(uploaded_file):
|
|
| 4044 |
stabilized = _patch_da3_msft_g_ref_amounts_across_tables(stabilized)
|
| 4045 |
stabilized = _dedupe_subset_transaction_tables_html(stabilized)
|
| 4046 |
stabilized = _drop_da3_misplaced_debit_after_deposit_heading_tables(stabilized)
|
|
|
|
| 4047 |
elif is_pdf and is_nfcu_doc:
|
| 4048 |
# Navy-only additive fix: rebuild malformed summary table from
|
| 4049 |
# text layer, but keep GLM body/header/footer unchanged.
|
|
@@ -4125,12 +4175,14 @@ def run_ocr(uploaded_file):
|
|
| 4125 |
# Cross-page: UCB section split + same transaction tables dedupe once on full doc.
|
| 4126 |
if all_pages and merged and not merged.startswith("Error") and "<table" in merged.lower():
|
| 4127 |
merged = _strip_orphan_continued_da3_flatline(merged)
|
|
|
|
| 4128 |
merged = _trim_adjacent_da3_suffix_duplicating_next_table_prefix(merged)
|
| 4129 |
merged = _split_ucb_deposits_electronic_sections_html(merged)
|
| 4130 |
merged = _patch_da3_msft_g_ref_amounts_across_tables(merged)
|
| 4131 |
merged = _dedupe_subset_transaction_tables_html(merged)
|
| 4132 |
merged = _drop_da3_misplaced_debit_after_deposit_heading_tables(merged)
|
| 4133 |
merged = _strip_orphan_continued_da3_flatline(merged)
|
|
|
|
| 4134 |
return merged
|
| 4135 |
|
| 4136 |
except Exception as e:
|
|
@@ -4155,4 +4207,3 @@ with gr.Blocks(title="GLM-OCR") as demo:
|
|
| 4155 |
|
| 4156 |
if __name__ == "__main__":
|
| 4157 |
demo.launch()
|
| 4158 |
-
|
|
|
|
| 51 |
and the first is mostly credit/deposit rows while the second is mostly debit/withdrawal-style
|
| 52 |
rows (generic keywords), drop the second β fixes OCR pasting the withdrawals block again.
|
| 53 |
- Fix 23b: Loose multiset keys use normalized float amounts so comma/spacing variants still match.
|
| 54 |
+
- Fix 26: Drop small DA3 fragments (3β14 rows) that are a multiset subset of an earlier larger DA3
|
| 55 |
+
table β matches PDF layouts that re-print a header and repeat a few rows.
|
| 56 |
+
- Fix 27: Strip a lone ββ¦(continued)β account banner line (no DATE/DESCRIPTION/AMOUNT) between
|
| 57 |
+
page separators β duplicate header noise without the long flatline.
|
| 58 |
"""
|
| 59 |
|
| 60 |
# Patch asyncio first (before Gradio imports it) to suppress Python 3.13 cleanup noise
|
|
|
|
| 3480 |
return "".join(out)
|
| 3481 |
|
| 3482 |
|
| 3483 |
+
def _strip_standalone_continued_banner_line(text: str) -> str:
|
| 3484 |
+
"""
|
| 3485 |
+
Fix 27: Remove a single line that is only an account/section β(continued)β banner
|
| 3486 |
+
(no transaction columns), often duplicated between page-separator and the next heading/table.
|
| 3487 |
+
"""
|
| 3488 |
+
if not text or "(continued)" not in text.lower():
|
| 3489 |
+
return text
|
| 3490 |
+
lines = text.splitlines(keepends=True)
|
| 3491 |
+
out = []
|
| 3492 |
+
for line in lines:
|
| 3493 |
+
core = line.rstrip("\r\n")
|
| 3494 |
+
if not core.strip():
|
| 3495 |
+
out.append(line)
|
| 3496 |
+
continue
|
| 3497 |
+
c = core.lower()
|
| 3498 |
+
if "$" in core or "=" in core:
|
| 3499 |
+
out.append(line)
|
| 3500 |
+
continue
|
| 3501 |
+
if (
|
| 3502 |
+
"(continued)" in c
|
| 3503 |
+
and "date" not in c
|
| 3504 |
+
and "description" not in c
|
| 3505 |
+
and "amount" not in c
|
| 3506 |
+
and len(re.findall(r"\d{2}/\d{2}", core)) == 0
|
| 3507 |
+
and len(core) < 240
|
| 3508 |
+
):
|
| 3509 |
+
continue
|
| 3510 |
+
out.append(line)
|
| 3511 |
+
return "".join(out)
|
| 3512 |
+
|
| 3513 |
+
|
| 3514 |
def _patch_da3_msft_g_ref_amounts_across_tables(text: str) -> str:
|
| 3515 |
"""
|
| 3516 |
Fix 21: Build MICROSOFT#G⦠-> strict Amount from any DA3 row, then patch other DA3 rows
|
|
|
|
| 3758 |
ci = _row_counter_loose_da3(gi)
|
| 3759 |
cj = _row_counter_loose_da3(gj)
|
| 3760 |
ni, nj = sum(ci.values()), sum(cj.values())
|
| 3761 |
+
if ni >= 1 and nj >= 1:
|
| 3762 |
oi_j = _overlap_ratio_counter(ci, cj)
|
| 3763 |
oj_i = _overlap_ratio_counter(cj, ci)
|
| 3764 |
+
# Short re-printed fragment (often 3β5 rows after a repeated header on same PDF page)
|
| 3765 |
+
if (
|
| 3766 |
+
nj >= 8
|
| 3767 |
+
and 3 <= ni <= 14
|
| 3768 |
+
and ni < nj
|
| 3769 |
+
and _multiset_leq(ci, cj)
|
| 3770 |
+
and oi_j >= 0.9
|
| 3771 |
+
):
|
| 3772 |
drop_idx.add(i)
|
| 3773 |
break
|
| 3774 |
+
if ni >= 6 and nj >= 6:
|
| 3775 |
+
if oi_j >= 0.88 and oj_i >= 0.88:
|
| 3776 |
+
drop_idx.add(i)
|
| 3777 |
+
break
|
| 3778 |
+
if _multiset_leq(ci, cj) and ni < nj and oi_j >= 0.9:
|
| 3779 |
+
drop_idx.add(i)
|
| 3780 |
+
break
|
| 3781 |
+
if _multiset_leq(cj, ci) and nj < ni and oj_i >= 0.9:
|
| 3782 |
+
drop_idx.add(j)
|
| 3783 |
+
continue
|
| 3784 |
|
| 3785 |
if not drop_idx:
|
| 3786 |
return t
|
|
|
|
| 3951 |
stabilized = "\n\n".join(out_blocks)
|
| 3952 |
stabilized = convert_plaintext_bank_sections(stabilized)
|
| 3953 |
stabilized = _strip_orphan_continued_da3_flatline(stabilized)
|
| 3954 |
+
stabilized = _strip_standalone_continued_banner_line(stabilized)
|
| 3955 |
stabilized = normalize_html_tables(stabilized)
|
| 3956 |
stabilized = _trim_adjacent_da3_suffix_duplicating_next_table_prefix(stabilized)
|
| 3957 |
stabilized = _split_ucb_deposits_electronic_sections_html(stabilized)
|
|
|
|
| 3959 |
stabilized = _dedupe_subset_transaction_tables_html(stabilized)
|
| 3960 |
stabilized = _drop_da3_misplaced_debit_after_deposit_heading_tables(stabilized)
|
| 3961 |
stabilized = _strip_orphan_continued_da3_flatline(stabilized)
|
| 3962 |
+
stabilized = _strip_standalone_continued_banner_line(stabilized)
|
| 3963 |
return close_unclosed_html(stabilized)
|
| 3964 |
|
| 3965 |
# --------------------------
|
|
|
|
| 4084 |
if is_pdf and not is_nfcu_doc:
|
| 4085 |
stabilized = _patch_ocr_with_textlayer(stabilized, path, page_num)
|
| 4086 |
stabilized = _strip_orphan_continued_da3_flatline(stabilized)
|
| 4087 |
+
stabilized = _strip_standalone_continued_banner_line(stabilized)
|
| 4088 |
# _patch_ocr_with_textlayer may append Case B rows from the PDF text layer
|
| 4089 |
# with fused UCB-style cells; run the same HTML table pass again (Fix 13/14).
|
| 4090 |
stabilized = normalize_html_tables(stabilized)
|
|
|
|
| 4093 |
stabilized = _patch_da3_msft_g_ref_amounts_across_tables(stabilized)
|
| 4094 |
stabilized = _dedupe_subset_transaction_tables_html(stabilized)
|
| 4095 |
stabilized = _drop_da3_misplaced_debit_after_deposit_heading_tables(stabilized)
|
| 4096 |
+
stabilized = _strip_standalone_continued_banner_line(stabilized)
|
| 4097 |
elif is_pdf and is_nfcu_doc:
|
| 4098 |
# Navy-only additive fix: rebuild malformed summary table from
|
| 4099 |
# text layer, but keep GLM body/header/footer unchanged.
|
|
|
|
| 4175 |
# Cross-page: UCB section split + same transaction tables dedupe once on full doc.
|
| 4176 |
if all_pages and merged and not merged.startswith("Error") and "<table" in merged.lower():
|
| 4177 |
merged = _strip_orphan_continued_da3_flatline(merged)
|
| 4178 |
+
merged = _strip_standalone_continued_banner_line(merged)
|
| 4179 |
merged = _trim_adjacent_da3_suffix_duplicating_next_table_prefix(merged)
|
| 4180 |
merged = _split_ucb_deposits_electronic_sections_html(merged)
|
| 4181 |
merged = _patch_da3_msft_g_ref_amounts_across_tables(merged)
|
| 4182 |
merged = _dedupe_subset_transaction_tables_html(merged)
|
| 4183 |
merged = _drop_da3_misplaced_debit_after_deposit_heading_tables(merged)
|
| 4184 |
merged = _strip_orphan_continued_da3_flatline(merged)
|
| 4185 |
+
merged = _strip_standalone_continued_banner_line(merged)
|
| 4186 |
return merged
|
| 4187 |
|
| 4188 |
except Exception as e:
|
|
|
|
| 4207 |
|
| 4208 |
if __name__ == "__main__":
|
| 4209 |
demo.launch()
|
|
|