Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -99,6 +99,71 @@ def _build_table_from_entries(entries: List[dict]) -> str:
|
|
| 99 |
return "\n".join(table)
|
| 100 |
|
| 101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
def _normalize_transactions(text: str) -> str:
|
| 103 |
"""
|
| 104 |
Convert loose transaction lines into structured markdown tables using:
|
|
@@ -119,8 +184,9 @@ def _normalize_transactions(text: str) -> str:
|
|
| 119 |
if in_section and (line.strip() == "" or line.strip().startswith("Subtotal")):
|
| 120 |
if table_buffer:
|
| 121 |
clean_rows = []
|
| 122 |
-
|
| 123 |
-
|
|
|
|
| 124 |
match = pattern.search(normalized)
|
| 125 |
if match:
|
| 126 |
date, desc, amount = match.groups()
|
|
@@ -143,8 +209,9 @@ def _normalize_transactions(text: str) -> str:
|
|
| 143 |
|
| 144 |
if table_buffer:
|
| 145 |
clean_rows = []
|
| 146 |
-
|
| 147 |
-
|
|
|
|
| 148 |
match = pattern.search(normalized)
|
| 149 |
if match:
|
| 150 |
date, desc, amount = match.groups()
|
|
|
|
| 99 |
return "\n".join(table)
|
| 100 |
|
| 101 |
|
| 102 |
+
def _is_transaction_start(line: str) -> bool:
|
| 103 |
+
return bool(re.match(r"\d{2}/\d{2}", line.strip()))
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def _ends_with_amount(text: str) -> bool:
|
| 107 |
+
return bool(re.search(r"\d{1,3}(?:,\d{3})*\.\d{2}$", text.strip()))
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def _is_noise_line(line: str) -> bool:
|
| 111 |
+
s = line.strip().lower()
|
| 112 |
+
if not s:
|
| 113 |
+
return True
|
| 114 |
+
if s == "---page-separator---":
|
| 115 |
+
return True
|
| 116 |
+
if "call 1-800-937-2000" in s:
|
| 117 |
+
return True
|
| 118 |
+
if s in ("<table border=\"1\"><tr><td></td></tr></table>", "<table><tr><td></td></tr></table>"):
|
| 119 |
+
return True
|
| 120 |
+
return False
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def _merge_transaction_lines(rows: List[str]) -> List[str]:
|
| 124 |
+
"""
|
| 125 |
+
Step 1/2: Merge multiline OCR rows into single transaction rows.
|
| 126 |
+
A new row begins when a line starts with MM/DD.
|
| 127 |
+
"""
|
| 128 |
+
merged: List[str] = []
|
| 129 |
+
current = ""
|
| 130 |
+
|
| 131 |
+
for raw in rows:
|
| 132 |
+
line = " ".join(raw.strip().split())
|
| 133 |
+
if not line or _is_noise_line(line):
|
| 134 |
+
continue
|
| 135 |
+
|
| 136 |
+
if _is_transaction_start(line):
|
| 137 |
+
if current:
|
| 138 |
+
merged.append(current.strip())
|
| 139 |
+
current = line
|
| 140 |
+
else:
|
| 141 |
+
if current:
|
| 142 |
+
current += " " + line
|
| 143 |
+
else:
|
| 144 |
+
current = line
|
| 145 |
+
|
| 146 |
+
if current:
|
| 147 |
+
merged.append(current.strip())
|
| 148 |
+
|
| 149 |
+
return merged
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def _repair_orphan_amounts(rows: List[str]) -> List[str]:
|
| 153 |
+
"""
|
| 154 |
+
Step 3: Attach lines without ending amount to prior transaction line when possible.
|
| 155 |
+
"""
|
| 156 |
+
fixed: List[str] = []
|
| 157 |
+
for line in rows:
|
| 158 |
+
if _ends_with_amount(line):
|
| 159 |
+
fixed.append(line)
|
| 160 |
+
elif fixed:
|
| 161 |
+
fixed[-1] = f"{fixed[-1]} {line}".strip()
|
| 162 |
+
else:
|
| 163 |
+
fixed.append(line)
|
| 164 |
+
return fixed
|
| 165 |
+
|
| 166 |
+
|
| 167 |
def _normalize_transactions(text: str) -> str:
|
| 168 |
"""
|
| 169 |
Convert loose transaction lines into structured markdown tables using:
|
|
|
|
| 184 |
if in_section and (line.strip() == "" or line.strip().startswith("Subtotal")):
|
| 185 |
if table_buffer:
|
| 186 |
clean_rows = []
|
| 187 |
+
merged_rows = _merge_transaction_lines(table_buffer)
|
| 188 |
+
repaired_rows = _repair_orphan_amounts(merged_rows)
|
| 189 |
+
for normalized in repaired_rows:
|
| 190 |
match = pattern.search(normalized)
|
| 191 |
if match:
|
| 192 |
date, desc, amount = match.groups()
|
|
|
|
| 209 |
|
| 210 |
if table_buffer:
|
| 211 |
clean_rows = []
|
| 212 |
+
merged_rows = _merge_transaction_lines(table_buffer)
|
| 213 |
+
repaired_rows = _repair_orphan_amounts(merged_rows)
|
| 214 |
+
for normalized in repaired_rows:
|
| 215 |
match = pattern.search(normalized)
|
| 216 |
if match:
|
| 217 |
date, desc, amount = match.groups()
|