Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1808,6 +1808,84 @@ def _normalize_daily_balance_table(grid):
|
|
| 1808 |
return [new_header] + new_rows
|
| 1809 |
|
| 1810 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1811 |
def normalize_html_tables(text: str) -> str:
|
| 1812 |
"""
|
| 1813 |
For every <table>...</table>:
|
|
@@ -1862,6 +1940,9 @@ def normalize_html_tables(text: str) -> str:
|
|
| 1862 |
# Fix 9: normalize DAILY BALANCE SUMMARY tables with stacked dates
|
| 1863 |
grid = _normalize_daily_balance_table(grid)
|
| 1864 |
|
|
|
|
|
|
|
|
|
|
| 1865 |
# Fix 6: merge split rows where description wraps to next line
|
| 1866 |
# (Hardin County Bank and similar monospace statement formats)
|
| 1867 |
grid = _merge_split_rows(grid)
|
|
|
|
| 1808 |
return [new_header] + new_rows
|
| 1809 |
|
| 1810 |
|
| 1811 |
+
def _normalize_checks_paid_table(grid):
|
| 1812 |
+
"""
|
| 1813 |
+
Fix OCR artifact in CHECKS PAID SUMMARY tables where:
|
| 1814 |
+
- Header col0 = "DATE CHECK # DATE CHECK # DATE CHECK #" (fused repeating groups)
|
| 1815 |
+
- Remaining headers = "AMOUNT AMOUNT AMOUNT"
|
| 1816 |
+
- Data col0 = "01/24 4701 01/18 4704 * 01/18 916831 *" (all groups fused)
|
| 1817 |
+
- Remaining data cells = amount values
|
| 1818 |
+
|
| 1819 |
+
Expands to proper: DATE | CHECK # | AMOUNT | DATE | CHECK # | AMOUNT | ...
|
| 1820 |
+
|
| 1821 |
+
Detection: first header cell matches pattern (DATE CHECK #)+
|
| 1822 |
+
and remaining headers are all AMOUNT.
|
| 1823 |
+
"""
|
| 1824 |
+
if not grid or len(grid) < 2:
|
| 1825 |
+
return grid
|
| 1826 |
+
|
| 1827 |
+
ncols = len(grid[0])
|
| 1828 |
+
if ncols < 2:
|
| 1829 |
+
return grid
|
| 1830 |
+
|
| 1831 |
+
first_h = str(grid[0][0] or "").strip()
|
| 1832 |
+
_CHECKS_HDR = re.compile(r"^(DATE\s+CHECK\s+#\s*)+$", re.IGNORECASE)
|
| 1833 |
+
if not _CHECKS_HDR.match(first_h):
|
| 1834 |
+
return grid
|
| 1835 |
+
|
| 1836 |
+
# Remaining headers must be AMOUNT (or empty)
|
| 1837 |
+
rest_h = [str(c or "").strip().upper() for c in grid[0][1:]]
|
| 1838 |
+
if not all(h in ("AMOUNT", "") for h in rest_h if h):
|
| 1839 |
+
return grid
|
| 1840 |
+
|
| 1841 |
+
# Count groups from how many times DATE appears in the fused header
|
| 1842 |
+
n_groups = len(re.findall(r"\bDATE\b", first_h, re.IGNORECASE))
|
| 1843 |
+
if n_groups < 1:
|
| 1844 |
+
return grid
|
| 1845 |
+
|
| 1846 |
+
# Build new header: DATE | CHECK # | AMOUNT repeated n_groups times
|
| 1847 |
+
new_header = []
|
| 1848 |
+
for _ in range(n_groups):
|
| 1849 |
+
new_header.extend(["DATE", "CHECK #", "AMOUNT"])
|
| 1850 |
+
|
| 1851 |
+
_DATE_RE = re.compile(r"^\d{1,2}/\d{2}$")
|
| 1852 |
+
|
| 1853 |
+
new_rows = [new_header]
|
| 1854 |
+
for row in grid[1:]:
|
| 1855 |
+
cells = [str(c or "").strip() for c in row]
|
| 1856 |
+
while len(cells) < ncols:
|
| 1857 |
+
cells.append("")
|
| 1858 |
+
|
| 1859 |
+
fused_data = cells[0]
|
| 1860 |
+
amounts = cells[1:]
|
| 1861 |
+
|
| 1862 |
+
# Split fused data into groups by date boundary
|
| 1863 |
+
tokens = fused_data.split()
|
| 1864 |
+
groups = []
|
| 1865 |
+
current = []
|
| 1866 |
+
for tok in tokens:
|
| 1867 |
+
if _DATE_RE.match(tok) and current:
|
| 1868 |
+
groups.append(current)
|
| 1869 |
+
current = [tok]
|
| 1870 |
+
else:
|
| 1871 |
+
current.append(tok)
|
| 1872 |
+
if current and current[0]:
|
| 1873 |
+
groups.append(current)
|
| 1874 |
+
|
| 1875 |
+
# Build one output row
|
| 1876 |
+
new_row = [""] * len(new_header)
|
| 1877 |
+
for i, grp in enumerate(groups):
|
| 1878 |
+
if i >= n_groups:
|
| 1879 |
+
break
|
| 1880 |
+
new_row[i * 3] = grp[0] # DATE
|
| 1881 |
+
new_row[i * 3 + 1] = " ".join(grp[1:]).strip() # CHECK #
|
| 1882 |
+
new_row[i * 3 + 2] = amounts[i] if i < len(amounts) else "" # AMOUNT
|
| 1883 |
+
|
| 1884 |
+
new_rows.append(new_row)
|
| 1885 |
+
|
| 1886 |
+
return new_rows
|
| 1887 |
+
|
| 1888 |
+
|
| 1889 |
def normalize_html_tables(text: str) -> str:
|
| 1890 |
"""
|
| 1891 |
For every <table>...</table>:
|
|
|
|
| 1940 |
# Fix 9: normalize DAILY BALANCE SUMMARY tables with stacked dates
|
| 1941 |
grid = _normalize_daily_balance_table(grid)
|
| 1942 |
|
| 1943 |
+
# Fix 10: normalize CHECKS PAID SUMMARY repeating-group tables
|
| 1944 |
+
grid = _normalize_checks_paid_table(grid)
|
| 1945 |
+
|
| 1946 |
# Fix 6: merge split rows where description wraps to next line
|
| 1947 |
# (Hardin County Bank and similar monospace statement formats)
|
| 1948 |
grid = _merge_split_rows(grid)
|