Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2263,6 +2263,18 @@ def _parse_nfcu_page(pdf_path: str, page_num: int) -> str:
|
|
| 2263 |
"Errors",
|
| 2264 |
"Payments",
|
| 2265 |
"SAVINGS DIVIDENDS",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2266 |
)
|
| 2267 |
|
| 2268 |
def parse_account_rows(start_idx):
|
|
@@ -2280,6 +2292,18 @@ def _parse_nfcu_page(pdf_path: str, page_num: int) -> str:
|
|
| 2280 |
break
|
| 2281 |
if any(text.startswith(s) for s in stop_markers):
|
| 2282 |
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2283 |
if text in ("Checking", "Savings"):
|
| 2284 |
break
|
| 2285 |
if text.startswith("Date Transaction Detail"):
|
|
@@ -2318,6 +2342,28 @@ def _parse_nfcu_page(pdf_path: str, page_num: int) -> str:
|
|
| 2318 |
if pending is not None:
|
| 2319 |
mvals = [tok for tok in toks if money_re.match(tok)]
|
| 2320 |
desc_tokens = [tok for tok in toks if not money_re.match(tok)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2321 |
if desc_tokens:
|
| 2322 |
pending["desc"] = (pending["desc"] + " " + " ".join(desc_tokens)).strip()
|
| 2323 |
if len(mvals) >= 2 and (not pending["amount"] or not pending["balance"]):
|
|
@@ -2571,18 +2617,8 @@ def run_ocr(uploaded_file):
|
|
| 2571 |
|
| 2572 |
parts = []
|
| 2573 |
|
| 2574 |
-
#
|
| 2575 |
-
#
|
| 2576 |
-
# detected, the entire page output is replaced with clean text-layer
|
| 2577 |
-
# data and none of the garbled OCR pipeline runs at all.
|
| 2578 |
-
# Safe no-op for all other banks (_parse_nfcu_page returns "").
|
| 2579 |
-
# NFCU-only path; no probing on non-NFCU files.
|
| 2580 |
-
if is_pdf and is_nfcu_doc:
|
| 2581 |
-
nfcu_html = _parse_nfcu_page(path, page_num)
|
| 2582 |
-
if nfcu_html:
|
| 2583 |
-
all_pages.append(nfcu_html)
|
| 2584 |
-
continue # skip ALL OCR processing for this page
|
| 2585 |
-
log.warning("NFCU parser returned empty output for page %d", page_num + 1)
|
| 2586 |
|
| 2587 |
# Header inclusion: PDF text -> band words -> OCR band
|
| 2588 |
hdr = ""
|
|
@@ -2600,7 +2636,7 @@ def run_ocr(uploaded_file):
|
|
| 2600 |
stabilized = stabilize_tables_and_text(page_md.strip())
|
| 2601 |
# Fix 4: restore any rows OCR dropped by cross-checking the PDF text layer.
|
| 2602 |
# Safe no-op for scanned PDFs (no text layer) and non-transaction pages.
|
| 2603 |
-
if is_pdf:
|
| 2604 |
stabilized = _patch_ocr_with_textlayer(stabilized, path, page_num)
|
| 2605 |
|
| 2606 |
# Fix 4D: append Johnson Bank Checks + Daily Account Balance
|
|
|
|
| 2263 |
"Errors",
|
| 2264 |
"Payments",
|
| 2265 |
"SAVINGS DIVIDENDS",
|
| 2266 |
+
"REMITTANCE RECEIVED",
|
| 2267 |
+
"DEPOSIT VOUCHER",
|
| 2268 |
+
"ACCOUNT NUMBER",
|
| 2269 |
+
"MARK \"X\"",
|
| 2270 |
+
"ADDRESS/ORDER",
|
| 2271 |
+
"ITEMS ON REVERSE",
|
| 2272 |
+
"CHANGE OF ADDRESS",
|
| 2273 |
+
"PLEASE PRINT",
|
| 2274 |
+
"RANK/RATE",
|
| 2275 |
+
"PO BOX",
|
| 2276 |
+
"MERRIFIELD",
|
| 2277 |
+
"Questions about this Statement",
|
| 2278 |
)
|
| 2279 |
|
| 2280 |
def parse_account_rows(start_idx):
|
|
|
|
| 2292 |
break
|
| 2293 |
if any(text.startswith(s) for s in stop_markers):
|
| 2294 |
break
|
| 2295 |
+
# Some boilerplate lines include prefixes/suffixes; match by containment too.
|
| 2296 |
+
upper_text = text.upper()
|
| 2297 |
+
if (
|
| 2298 |
+
"REMITTANCE RECEIVED" in upper_text
|
| 2299 |
+
or "DEPOSIT VOUCHER" in upper_text
|
| 2300 |
+
or "ACCOUNT NUMBER" in upper_text
|
| 2301 |
+
or "ADDRESS/ORDER" in upper_text
|
| 2302 |
+
or "ITEMS ON REVERSE" in upper_text
|
| 2303 |
+
or "CHANGE OF ADDRESS" in upper_text
|
| 2304 |
+
or "PLEASE PRINT" in upper_text
|
| 2305 |
+
):
|
| 2306 |
+
break
|
| 2307 |
if text in ("Checking", "Savings"):
|
| 2308 |
break
|
| 2309 |
if text.startswith("Date Transaction Detail"):
|
|
|
|
| 2342 |
if pending is not None:
|
| 2343 |
mvals = [tok for tok in toks if money_re.match(tok)]
|
| 2344 |
desc_tokens = [tok for tok in toks if not money_re.match(tok)]
|
| 2345 |
+
|
| 2346 |
+
# Stop if we have already captured a balance and now hit
|
| 2347 |
+
# known non-transaction boilerplate lines.
|
| 2348 |
+
upper = text.upper()
|
| 2349 |
+
if pending["balance"] and (
|
| 2350 |
+
"REMITTANCE" in upper
|
| 2351 |
+
or "DEPOSIT VOUCHER" in upper
|
| 2352 |
+
or "ACCOUNT NUMBER" in upper
|
| 2353 |
+
or "ADDRESS/ORDER" in upper
|
| 2354 |
+
or "ITEMS ON REVERSE" in upper
|
| 2355 |
+
or "PO BOX" in upper
|
| 2356 |
+
):
|
| 2357 |
+
break
|
| 2358 |
+
|
| 2359 |
+
# Beginning/Ending balance rows are single logical rows.
|
| 2360 |
+
# Do not absorb unrelated continuation text.
|
| 2361 |
+
if (
|
| 2362 |
+
("BEGINNING BALANCE" in pending["desc"].upper() or "ENDING BALANCE" in pending["desc"].upper())
|
| 2363 |
+
and not mvals
|
| 2364 |
+
and not (toks and date_re.match(toks[0]))
|
| 2365 |
+
):
|
| 2366 |
+
break
|
| 2367 |
if desc_tokens:
|
| 2368 |
pending["desc"] = (pending["desc"] + " " + " ".join(desc_tokens)).strip()
|
| 2369 |
if len(mvals) >= 2 and (not pending["amount"] or not pending["balance"]):
|
|
|
|
| 2617 |
|
| 2618 |
parts = []
|
| 2619 |
|
| 2620 |
+
# Keep GLM-OCR as the primary parser for all pages.
|
| 2621 |
+
# Navy-specific helpers run only as additive post-processing.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2622 |
|
| 2623 |
# Header inclusion: PDF text -> band words -> OCR band
|
| 2624 |
hdr = ""
|
|
|
|
| 2636 |
stabilized = stabilize_tables_and_text(page_md.strip())
|
| 2637 |
# Fix 4: restore any rows OCR dropped by cross-checking the PDF text layer.
|
| 2638 |
# Safe no-op for scanned PDFs (no text layer) and non-transaction pages.
|
| 2639 |
+
if is_pdf and not is_nfcu_doc:
|
| 2640 |
stabilized = _patch_ocr_with_textlayer(stabilized, path, page_num)
|
| 2641 |
|
| 2642 |
# Fix 4D: append Johnson Bank Checks + Daily Account Balance
|