Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -53,8 +53,10 @@ Primary goals for reconcile rate:
|
|
| 53 |
debits. Reorder to Credits + ITM table + Electronic Debits + merged debits; drop dup keys from the
|
| 54 |
second table against the first; merge remaining orphan rows into the debits table.
|
| 55 |
- Fix 17i: After Fix 17b splits ITM prefix from debits, OCR often leaves *credit* rows (POS Return, DDA
|
| 56 |
-
Transfer IN, Apple Cash INST R / CUPERTINO)
|
| 57 |
-
tail
|
|
|
|
|
|
|
| 58 |
- Fix 17e: Repeat EC/ED fused + 17d passes until stable (handles chained replacements). Centered section titles
|
| 59 |
match both align=\"center\" and style=\"text-align:center\" on divs.
|
| 60 |
- Post-pass: dedupe 3-col Date|Description|Amount tables when one is a duplicate fragment
|
|
@@ -94,6 +96,9 @@ Primary goals for reconcile rate:
|
|
| 94 |
relocated to just before the orphan table. Guards: no debit heading already before
|
| 95 |
table; credit context must precede table; no other table between orphan and heading;
|
| 96 |
try/except wrapper (safe no-op on any error).
|
|
|
|
|
|
|
|
|
|
| 97 |
- Fix 20-override: _dedupe_duplicate_rows_in_da3_table now uses the PDF text-layer frequency
|
| 98 |
map (_tl_freq_context) as its cap so legitimate repeated transactions (e.g. 6x
|
| 99 |
Temporary Credit Reversal on the same date/amount) are preserved rather than
|
|
@@ -3021,18 +3026,20 @@ def _is_ucb_electronic_credit_row_after_split(grid, r: int) -> bool:
|
|
| 3021 |
|
| 3022 |
|
| 3023 |
def _ucb_move_trailing_credit_rows_from_ed_to_ec(g_ec, g_ed):
|
| 3024 |
-
"""Fix 17i:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3025 |
if not g_ec or not g_ed or len(g_ed) < 2 or not _is_da3_header(g_ec) or not _is_da3_header(g_ed):
|
| 3026 |
return g_ec, g_ed
|
| 3027 |
-
|
| 3028 |
-
|
| 3029 |
-
i -= 1
|
| 3030 |
-
tail_start = i + 1
|
| 3031 |
-
if tail_start >= len(g_ed):
|
| 3032 |
return g_ec, g_ed
|
| 3033 |
-
|
| 3034 |
-
|
| 3035 |
-
|
|
|
|
| 3036 |
max_c = max(len(r) for r in g_ec_new + g_ed_new)
|
| 3037 |
for row in g_ec_new + g_ed_new:
|
| 3038 |
while len(row) < max_c:
|
|
@@ -3483,6 +3490,82 @@ def _ucb_prune_ed_fragment_dupes_vs_prev_table(text: str) -> str:
|
|
| 3483 |
return text
|
| 3484 |
|
| 3485 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3486 |
def _split_ucb_fused_ec_ed_headings_single_table_html(text: str) -> str:
|
| 3487 |
if not text or "electronic credits" not in text.lower():
|
| 3488 |
return text
|
|
@@ -3547,6 +3630,7 @@ def _split_ucb_deposits_electronic_sections_html(text: str) -> str:
|
|
| 3547 |
nxt = _split_ucb_fused_ec_ed_headings_single_table_html(nxt)
|
| 3548 |
nxt = _ucb_strip_redundant_ed_subset_fragment(nxt)
|
| 3549 |
nxt = _ucb_prune_ed_fragment_dupes_vs_prev_table(nxt)
|
|
|
|
| 3550 |
if nxt == text:
|
| 3551 |
break
|
| 3552 |
text = nxt
|
|
@@ -4265,6 +4349,20 @@ def _fix29_move_debit_heading_before_orphan_table(text: str) -> str:
|
|
| 4265 |
orphan_m = da3_matches[i]
|
| 4266 |
orphan_start = orphan_m.start()
|
| 4267 |
orphan_end = orphan_m.end()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4268 |
|
| 4269 |
before_window = text[max(0, orphan_start - _HEADING_SCAN_WINDOW): orphan_start]
|
| 4270 |
before_clean = re.sub(r"<[^>]+>", " ", before_window)
|
|
@@ -4326,6 +4424,73 @@ def _fix29_move_debit_heading_before_orphan_table(text: str) -> str:
|
|
| 4326 |
return text
|
| 4327 |
|
| 4328 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4329 |
def stabilize_tables_and_text(page_md: str) -> str:
|
| 4330 |
if not page_md:
|
| 4331 |
return page_md
|
|
@@ -4359,6 +4524,7 @@ def stabilize_tables_and_text(page_md: str) -> str:
|
|
| 4359 |
stabilized = _fix29_move_debit_heading_before_orphan_table(stabilized) # Fix 29
|
| 4360 |
stabilized = _strip_orphan_continued_da3_flatline(stabilized)
|
| 4361 |
stabilized = _strip_standalone_continued_banner_line(stabilized)
|
|
|
|
| 4362 |
return close_unclosed_html(stabilized)
|
| 4363 |
|
| 4364 |
# --------------------------
|
|
@@ -4489,6 +4655,7 @@ def run_ocr(uploaded_file):
|
|
| 4489 |
stabilized = _strip_credits_prefix_from_debit_da3_table(stabilized) # Fix 28
|
| 4490 |
stabilized = _fix29_move_debit_heading_before_orphan_table(stabilized) # Fix 29
|
| 4491 |
stabilized = _strip_standalone_continued_banner_line(stabilized)
|
|
|
|
| 4492 |
elif is_pdf and is_nfcu_doc:
|
| 4493 |
nfcu_summary = _extract_nfcu_summary_table(path, page_num)
|
| 4494 |
if nfcu_summary:
|
|
@@ -4567,6 +4734,7 @@ def run_ocr(uploaded_file):
|
|
| 4567 |
merged = _fix29_move_debit_heading_before_orphan_table(merged) # Fix 29
|
| 4568 |
merged = _strip_orphan_continued_da3_flatline(merged)
|
| 4569 |
merged = _strip_standalone_continued_banner_line(merged)
|
|
|
|
| 4570 |
return merged
|
| 4571 |
|
| 4572 |
except Exception as e:
|
|
|
|
| 53 |
debits. Reorder to Credits + ITM table + Electronic Debits + merged debits; drop dup keys from the
|
| 54 |
second table against the first; merge remaining orphan rows into the debits table.
|
| 55 |
- Fix 17i: After Fix 17b splits ITM prefix from debits, OCR often leaves *credit* rows (POS Return, DDA
|
| 56 |
+
Transfer IN, Apple Cash INST R / CUPERTINO) in the debits grid — move those rows to Electronic
|
| 57 |
+
Credits (contiguous-tail case on g_ed after 17b, or any matching row via 17j).
|
| 58 |
+
- Fix 17j: When OCR emits a *second* Electronic Debits table (duplicate block), credit-only rows often appear
|
| 59 |
+
only there — relocate them to the nearest preceding Electronic Credits table (same patterns as 17i).
|
| 60 |
- Fix 17e: Repeat EC/ED fused + 17d passes until stable (handles chained replacements). Centered section titles
|
| 61 |
match both align=\"center\" and style=\"text-align:center\" on divs.
|
| 62 |
- Post-pass: dedupe 3-col Date|Description|Amount tables when one is a duplicate fragment
|
|
|
|
| 96 |
relocated to just before the orphan table. Guards: no debit heading already before
|
| 97 |
table; credit context must precede table; no other table between orphan and heading;
|
| 98 |
try/except wrapper (safe no-op on any error).
|
| 99 |
+
- Fix 31: On check / receipt image pages, GLM sometimes emits bogus table rows (e.g. \"Witness LA…\",
|
| 100 |
+
\"[hotline Control]\" after amounts, long trace ids). Strip those rows and bracket junk after
|
| 101 |
+
currency amounts; drop a stray \"## UCB\" heading before such tables. Safe no-op when absent.
|
| 102 |
- Fix 20-override: _dedupe_duplicate_rows_in_da3_table now uses the PDF text-layer frequency
|
| 103 |
map (_tl_freq_context) as its cap so legitimate repeated transactions (e.g. 6x
|
| 104 |
Temporary Credit Reversal on the same date/amount) are preserved rather than
|
|
|
|
| 3026 |
|
| 3027 |
|
| 3028 |
def _ucb_move_trailing_credit_rows_from_ed_to_ec(g_ec, g_ed):
|
| 3029 |
+
"""Fix 17i: credit-like rows that landed in g_ed (POS Return, DDA Transfer IN, Apple INST R) -> g_ec.
|
| 3030 |
+
|
| 3031 |
+
OCR often orders them after outgoing debits on the same date block, so a contiguous tail scan
|
| 3032 |
+
misses them; we relocate every matching data row while preserving relative order.
|
| 3033 |
+
"""
|
| 3034 |
if not g_ec or not g_ed or len(g_ed) < 2 or not _is_da3_header(g_ec) or not _is_da3_header(g_ed):
|
| 3035 |
return g_ec, g_ed
|
| 3036 |
+
credit_indices = [r for r in range(1, len(g_ed)) if _is_ucb_electronic_credit_row_after_split(g_ed, r)]
|
| 3037 |
+
if not credit_indices:
|
|
|
|
|
|
|
|
|
|
| 3038 |
return g_ec, g_ed
|
| 3039 |
+
credit_rows = [list(g_ed[r]) for r in credit_indices]
|
| 3040 |
+
drop = set(credit_indices)
|
| 3041 |
+
g_ed_new = [list(g_ed[0])] + [list(g_ed[r]) for r in range(1, len(g_ed)) if r not in drop]
|
| 3042 |
+
g_ec_new = [list(g_ec[0])] + [list(r) for r in g_ec[1:]] + credit_rows
|
| 3043 |
max_c = max(len(r) for r in g_ec_new + g_ed_new)
|
| 3044 |
for row in g_ec_new + g_ed_new:
|
| 3045 |
while len(row) < max_c:
|
|
|
|
| 3490 |
return text
|
| 3491 |
|
| 3492 |
|
| 3493 |
+
_UCB_ED_DIV_AND_TABLE = re.compile(
|
| 3494 |
+
_UCB_CENTER_DIV + r"\s*Electronic\s+Debits\s*</div>\s*(?P<tbl><table[^>]*>.*?</table>)",
|
| 3495 |
+
re.DOTALL | re.IGNORECASE,
|
| 3496 |
+
)
|
| 3497 |
+
_UCB_EC_DIV_AND_TABLE = re.compile(
|
| 3498 |
+
_UCB_CENTER_DIV + r"\s*Electronic\s+Credits\s*</div>\s*(?P<tbl><table[^>]*>.*?</table>)",
|
| 3499 |
+
re.DOTALL | re.IGNORECASE,
|
| 3500 |
+
)
|
| 3501 |
+
|
| 3502 |
+
|
| 3503 |
+
def _ucb_relocate_credit_rows_from_ed_tables_to_ec_html(text: str) -> str:
|
| 3504 |
+
"""
|
| 3505 |
+
Fix 17j: Credit-side rows (POS Return, DDA Transfer IN, Apple Cash INST R) sometimes appear only under a
|
| 3506 |
+
duplicate Electronic Debits table, not in the fused EC table — move them to the preceding EC table.
|
| 3507 |
+
"""
|
| 3508 |
+
if not text or "electronic debits" not in text.lower():
|
| 3509 |
+
return text
|
| 3510 |
+
try:
|
| 3511 |
+
while True:
|
| 3512 |
+
replaced = False
|
| 3513 |
+
for ed_m in _UCB_ED_DIV_AND_TABLE.finditer(text):
|
| 3514 |
+
g_ed = _parse_da3_grid_from_table_html(ed_m.group("tbl"))
|
| 3515 |
+
if not g_ed or len(g_ed) < 2 or not _is_da3_header(g_ed):
|
| 3516 |
+
continue
|
| 3517 |
+
credit_ix = [
|
| 3518 |
+
r
|
| 3519 |
+
for r in range(1, len(g_ed))
|
| 3520 |
+
if _is_ucb_electronic_credit_row_after_split(g_ed, r)
|
| 3521 |
+
]
|
| 3522 |
+
if not credit_ix:
|
| 3523 |
+
continue
|
| 3524 |
+
before = text[: ed_m.start()]
|
| 3525 |
+
ec_matches = list(_UCB_EC_DIV_AND_TABLE.finditer(before))
|
| 3526 |
+
if not ec_matches:
|
| 3527 |
+
continue
|
| 3528 |
+
ec_m = ec_matches[-1]
|
| 3529 |
+
g_ec = _parse_da3_grid_from_table_html(ec_m.group("tbl"))
|
| 3530 |
+
if not g_ec or len(g_ec) < 2 or not _is_da3_header(g_ec):
|
| 3531 |
+
continue
|
| 3532 |
+
drop = set(credit_ix)
|
| 3533 |
+
credit_rows = [list(g_ed[r]) for r in credit_ix]
|
| 3534 |
+
g_ed_new = [list(g_ed[0])] + [list(g_ed[r]) for r in range(1, len(g_ed)) if r not in drop]
|
| 3535 |
+
g_ec_new = [list(g_ec[0])] + [list(r) for r in g_ec[1:]] + credit_rows
|
| 3536 |
+
max_c = max(len(r) for r in g_ec_new + g_ed_new)
|
| 3537 |
+
for row in g_ec_new + g_ed_new:
|
| 3538 |
+
while len(row) < max_c:
|
| 3539 |
+
row.append("")
|
| 3540 |
+
new_ec = _grid_to_html(g_ec_new)
|
| 3541 |
+
if len(g_ed_new) <= 1:
|
| 3542 |
+
text = (
|
| 3543 |
+
text[: ec_m.start("tbl")]
|
| 3544 |
+
+ new_ec
|
| 3545 |
+
+ text[ec_m.end("tbl") : ed_m.start()]
|
| 3546 |
+
+ text[ed_m.end() :]
|
| 3547 |
+
)
|
| 3548 |
+
else:
|
| 3549 |
+
new_ed = _grid_to_html(g_ed_new)
|
| 3550 |
+
text = (
|
| 3551 |
+
text[: ec_m.start("tbl")]
|
| 3552 |
+
+ new_ec
|
| 3553 |
+
+ text[ec_m.end("tbl") : ed_m.start()]
|
| 3554 |
+
+ text[ed_m.start() : ed_m.start("tbl")]
|
| 3555 |
+
+ new_ed
|
| 3556 |
+
+ text[ed_m.end() :]
|
| 3557 |
+
)
|
| 3558 |
+
log.info("Fix 17j: relocated %d credit row(s) from Electronic Debits to Electronic Credits", len(credit_rows))
|
| 3559 |
+
replaced = True
|
| 3560 |
+
break
|
| 3561 |
+
if not replaced:
|
| 3562 |
+
break
|
| 3563 |
+
return text
|
| 3564 |
+
except Exception as e:
|
| 3565 |
+
log.warning("_ucb_relocate_credit_rows_from_ed_tables_to_ec_html failed: %s", e)
|
| 3566 |
+
return text
|
| 3567 |
+
|
| 3568 |
+
|
| 3569 |
def _split_ucb_fused_ec_ed_headings_single_table_html(text: str) -> str:
|
| 3570 |
if not text or "electronic credits" not in text.lower():
|
| 3571 |
return text
|
|
|
|
| 3630 |
nxt = _split_ucb_fused_ec_ed_headings_single_table_html(nxt)
|
| 3631 |
nxt = _ucb_strip_redundant_ed_subset_fragment(nxt)
|
| 3632 |
nxt = _ucb_prune_ed_fragment_dupes_vs_prev_table(nxt)
|
| 3633 |
+
nxt = _ucb_relocate_credit_rows_from_ed_tables_to_ec_html(nxt)
|
| 3634 |
if nxt == text:
|
| 3635 |
break
|
| 3636 |
text = nxt
|
|
|
|
| 4349 |
orphan_m = da3_matches[i]
|
| 4350 |
orphan_start = orphan_m.start()
|
| 4351 |
orphan_end = orphan_m.end()
|
| 4352 |
+
orphan_tbl_html = orphan_m.group(0)
|
| 4353 |
+
|
| 4354 |
+
# Do not treat UCB Electronic Credits ITM-only tables as "orphan debits" needing a heading
|
| 4355 |
+
# moved ahead of them — Fix 17b leaves ED after the ITM block; moving ED here stacks both
|
| 4356 |
+
# headings above ITM and leaves debits under the wrong banner.
|
| 4357 |
+
try:
|
| 4358 |
+
og = _parse_da3_grid_from_table_html(orphan_tbl_html)
|
| 4359 |
+
if og and (
|
| 4360 |
+
_ucb_table_credits_only_no_strong_debits(og)
|
| 4361 |
+
or _ucb_html_table_body_looks_itm_credits_only(orphan_tbl_html)
|
| 4362 |
+
):
|
| 4363 |
+
continue
|
| 4364 |
+
except Exception:
|
| 4365 |
+
pass
|
| 4366 |
|
| 4367 |
before_window = text[max(0, orphan_start - _HEADING_SCAN_WINDOW): orphan_start]
|
| 4368 |
before_clean = re.sub(r"<[^>]+>", " ", before_window)
|
|
|
|
| 4424 |
return text
|
| 4425 |
|
| 4426 |
|
| 4427 |
+
def _strip_check_image_ocr_junk_html(text: str) -> str:
|
| 4428 |
+
"""
|
| 4429 |
+
Fix 31: Remove hallucinated rows on scanned check/receipt regions and normalize amount cells.
|
| 4430 |
+
"""
|
| 4431 |
+
if not text or "<table" not in text.lower():
|
| 4432 |
+
return text
|
| 4433 |
+
try:
|
| 4434 |
+
text = re.sub(
|
| 4435 |
+
r"(\$[\d,]+\.\d{2})\s*\[[^\]]+\]",
|
| 4436 |
+
r"\1",
|
| 4437 |
+
text,
|
| 4438 |
+
)
|
| 4439 |
+
tbl_pat = re.compile(r"(<table[^>]*>)([\s\S]*?)(</table>)", re.IGNORECASE)
|
| 4440 |
+
|
| 4441 |
+
def _tr_effectively_empty(tr: str) -> bool:
|
| 4442 |
+
core = re.sub(r"<[^>]+>", " ", tr)
|
| 4443 |
+
return not core.strip()
|
| 4444 |
+
|
| 4445 |
+
def repl(m) -> str:
|
| 4446 |
+
open_tag, body, close_tag = m.group(1), m.group(2), m.group(3)
|
| 4447 |
+
low = body.lower()
|
| 4448 |
+
if not any(
|
| 4449 |
+
k in low
|
| 4450 |
+
for k in (
|
| 4451 |
+
"hotline",
|
| 4452 |
+
"witness la",
|
| 4453 |
+
"itm checking",
|
| 4454 |
+
"care none",
|
| 4455 |
+
"processed ",
|
| 4456 |
+
"course dut",
|
| 4457 |
+
"n00590409",
|
| 4458 |
+
)
|
| 4459 |
+
):
|
| 4460 |
+
return m.group(0)
|
| 4461 |
+
kept: List[str] = []
|
| 4462 |
+
for trm in re.finditer(r"<tr\b[^>]*>[\s\S]*?</tr>", body, re.IGNORECASE):
|
| 4463 |
+
tr = trm.group(0)
|
| 4464 |
+
tl = tr.lower()
|
| 4465 |
+
if _tr_effectively_empty(tr):
|
| 4466 |
+
continue
|
| 4467 |
+
if "[hotline" in tl or "hotline control" in tl:
|
| 4468 |
+
continue
|
| 4469 |
+
if "witness la" in tl and ("course" in tl or "dut" in tl):
|
| 4470 |
+
continue
|
| 4471 |
+
if "itm checking witness" in tl or (
|
| 4472 |
+
"itm checking" in tl and "witness" in tl
|
| 4473 |
+
):
|
| 4474 |
+
continue
|
| 4475 |
+
if "care none" in tl and "account" in tl:
|
| 4476 |
+
continue
|
| 4477 |
+
if "processed " in tl and " @ " in tl and "items" in tl:
|
| 4478 |
+
continue
|
| 4479 |
+
if re.search(r"\bN\d{15,}\b", tr):
|
| 4480 |
+
continue
|
| 4481 |
+
kept.append(tr)
|
| 4482 |
+
if not kept:
|
| 4483 |
+
return m.group(0)
|
| 4484 |
+
return open_tag + "".join(kept) + close_tag
|
| 4485 |
+
|
| 4486 |
+
text = tbl_pat.sub(repl, text)
|
| 4487 |
+
text = re.sub(r"\n## UCB\s*\n+(?=<table)", "\n", text, flags=re.IGNORECASE)
|
| 4488 |
+
return text
|
| 4489 |
+
except Exception as e:
|
| 4490 |
+
log.warning("_strip_check_image_ocr_junk_html failed: %s", e)
|
| 4491 |
+
return text
|
| 4492 |
+
|
| 4493 |
+
|
| 4494 |
def stabilize_tables_and_text(page_md: str) -> str:
|
| 4495 |
if not page_md:
|
| 4496 |
return page_md
|
|
|
|
| 4524 |
stabilized = _fix29_move_debit_heading_before_orphan_table(stabilized) # Fix 29
|
| 4525 |
stabilized = _strip_orphan_continued_da3_flatline(stabilized)
|
| 4526 |
stabilized = _strip_standalone_continued_banner_line(stabilized)
|
| 4527 |
+
stabilized = _strip_check_image_ocr_junk_html(stabilized) # Fix 31
|
| 4528 |
return close_unclosed_html(stabilized)
|
| 4529 |
|
| 4530 |
# --------------------------
|
|
|
|
| 4655 |
stabilized = _strip_credits_prefix_from_debit_da3_table(stabilized) # Fix 28
|
| 4656 |
stabilized = _fix29_move_debit_heading_before_orphan_table(stabilized) # Fix 29
|
| 4657 |
stabilized = _strip_standalone_continued_banner_line(stabilized)
|
| 4658 |
+
stabilized = _strip_check_image_ocr_junk_html(stabilized) # Fix 31
|
| 4659 |
elif is_pdf and is_nfcu_doc:
|
| 4660 |
nfcu_summary = _extract_nfcu_summary_table(path, page_num)
|
| 4661 |
if nfcu_summary:
|
|
|
|
| 4734 |
merged = _fix29_move_debit_heading_before_orphan_table(merged) # Fix 29
|
| 4735 |
merged = _strip_orphan_continued_da3_flatline(merged)
|
| 4736 |
merged = _strip_standalone_continued_banner_line(merged)
|
| 4737 |
+
merged = _strip_check_image_ocr_junk_html(merged) # Fix 31
|
| 4738 |
return merged
|
| 4739 |
|
| 4740 |
except Exception as e:
|