Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
| 2 |
|
| 3 |
import logging
|
| 4 |
import os
|
|
|
|
| 5 |
import subprocess
|
| 6 |
import tempfile
|
| 7 |
import time
|
|
@@ -150,15 +151,76 @@ def get_parser():
|
|
| 150 |
def _extract_md(result: Any) -> str:
|
| 151 |
if result is None:
|
| 152 |
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
if isinstance(result, list):
|
| 154 |
chunks = []
|
| 155 |
for item in result:
|
| 156 |
md = getattr(item, "markdown_result", "")
|
| 157 |
if md:
|
| 158 |
-
chunks.append(str(md).strip())
|
| 159 |
return "\n\n---page-separator---\n\n".join([c for c in chunks if c]).strip()
|
| 160 |
md = getattr(result, "markdown_result", "")
|
| 161 |
-
return str(md).strip() if md else ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
|
| 163 |
|
| 164 |
def run_ocr(file_obj):
|
|
@@ -175,7 +237,7 @@ def run_ocr(file_obj):
|
|
| 175 |
result = parser.parse(page_images)
|
| 176 |
else:
|
| 177 |
result = parser.parse(path)
|
| 178 |
-
md = _extract_md(result) or "(No content)"
|
| 179 |
return md
|
| 180 |
except Exception as e:
|
| 181 |
import traceback
|
|
|
|
| 2 |
|
| 3 |
import logging
|
| 4 |
import os
|
| 5 |
+
import re
|
| 6 |
import subprocess
|
| 7 |
import tempfile
|
| 8 |
import time
|
|
|
|
| 151 |
def _extract_md(result: Any) -> str:
|
| 152 |
if result is None:
|
| 153 |
return ""
|
| 154 |
+
|
| 155 |
+
def _close_unbalanced_tables(chunk: str) -> str:
|
| 156 |
+
# Some OCR chunks end mid-table near page boundaries, which can cause
|
| 157 |
+
# subsequent content (including page separators) to render inside a cell.
|
| 158 |
+
opens = len(re.findall(r"<table\b", chunk, flags=re.IGNORECASE))
|
| 159 |
+
closes = len(re.findall(r"</table>", chunk, flags=re.IGNORECASE))
|
| 160 |
+
missing = max(0, opens - closes)
|
| 161 |
+
if missing:
|
| 162 |
+
chunk = chunk.rstrip() + ("\n</table>" * missing)
|
| 163 |
+
return chunk
|
| 164 |
+
|
| 165 |
if isinstance(result, list):
|
| 166 |
chunks = []
|
| 167 |
for item in result:
|
| 168 |
md = getattr(item, "markdown_result", "")
|
| 169 |
if md:
|
| 170 |
+
chunks.append(_close_unbalanced_tables(str(md).strip()))
|
| 171 |
return "\n\n---page-separator---\n\n".join([c for c in chunks if c]).strip()
|
| 172 |
md = getattr(result, "markdown_result", "")
|
| 173 |
+
return _close_unbalanced_tables(str(md).strip()) if md else ""
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def _clean_markdown(md: str) -> str:
|
| 177 |
+
if not md:
|
| 178 |
+
return md
|
| 179 |
+
|
| 180 |
+
# Drop frequently repeated bank footer/header lines.
|
| 181 |
+
drop_line_patterns = [
|
| 182 |
+
r"Call 1-800-937-2000 for 24-hour Bank-by-Phone services.*",
|
| 183 |
+
r"Bank Deposits FDIC Insured \| TD Bank, N\.A\. \| Equal Housing Lender.*",
|
| 184 |
+
r"Go paperless\.",
|
| 185 |
+
r"Scan the QR code to opt in to paperless statements\.",
|
| 186 |
+
]
|
| 187 |
+
drop_line_regexes = [re.compile(p, re.IGNORECASE) for p in drop_line_patterns]
|
| 188 |
+
|
| 189 |
+
cleaned_lines: List[str] = []
|
| 190 |
+
for line in md.splitlines():
|
| 191 |
+
s = line.strip()
|
| 192 |
+
if any(rx.fullmatch(s) for rx in drop_line_regexes):
|
| 193 |
+
continue
|
| 194 |
+
cleaned_lines.append(line)
|
| 195 |
+
md = "\n".join(cleaned_lines)
|
| 196 |
+
|
| 197 |
+
# Remove long legal notice section that repeats and is usually not needed
|
| 198 |
+
# for transaction extraction.
|
| 199 |
+
legal_start_markers = [
|
| 200 |
+
"## FOR CONSUMER ACCOUNTS ONLY",
|
| 201 |
+
"## FOR CONSUMER LOAN ACCOUNTS ONLY",
|
| 202 |
+
"## In case of Errors or Questions About Your Bill:",
|
| 203 |
+
]
|
| 204 |
+
lines = md.splitlines()
|
| 205 |
+
kept: List[str] = []
|
| 206 |
+
skipping = False
|
| 207 |
+
for line in lines:
|
| 208 |
+
s = line.strip()
|
| 209 |
+
if any(s.startswith(m) for m in legal_start_markers):
|
| 210 |
+
skipping = True
|
| 211 |
+
continue
|
| 212 |
+
if skipping and s == "---page-separator---":
|
| 213 |
+
skipping = False
|
| 214 |
+
kept.append(line)
|
| 215 |
+
continue
|
| 216 |
+
if not skipping:
|
| 217 |
+
kept.append(line)
|
| 218 |
+
md = "\n".join(kept)
|
| 219 |
+
|
| 220 |
+
# Remove duplicate separators and excessive blank lines.
|
| 221 |
+
md = re.sub(r"(?:\n\s*){3,}", "\n\n", md)
|
| 222 |
+
md = re.sub(r"(?:\n\s*---page-separator---\s*\n){2,}", "\n\n---page-separator---\n\n", md)
|
| 223 |
+
return md.strip()
|
| 224 |
|
| 225 |
|
| 226 |
def run_ocr(file_obj):
|
|
|
|
| 237 |
result = parser.parse(page_images)
|
| 238 |
else:
|
| 239 |
result = parser.parse(path)
|
| 240 |
+
md = _clean_markdown(_extract_md(result)) or "(No content)"
|
| 241 |
return md
|
| 242 |
except Exception as e:
|
| 243 |
import traceback
|