rehan953 commited on
Commit
870dc2a
·
verified ·
1 Parent(s): ade3f1c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +45 -19
app.py CHANGED
@@ -1024,12 +1024,17 @@ def _extract_textlayer_rows(pdf_path: str, page_num: int):
1024
  # Line looks like: Jan 16 Jan 16 CAPITAL ONE MOBILE PYMT - $500.00
1025
  # After consuming first date, check if next tokens are also a date
1026
  remaining = line[desc_start:]
 
 
1027
  if remaining and month_re.match(remaining[0]):
1028
  if len(remaining) > 1 and day_re.match(remaining[1]):
1029
- # Skip the post date
1030
  remaining = remaining[2:]
1031
  elif len(remaining) > 0:
1032
  remaining = remaining[1:]
 
 
 
1033
 
1034
  if len(remaining) < 2:
1035
  continue
@@ -1051,7 +1056,7 @@ def _extract_textlayer_rows(pdf_path: str, page_num: int):
1051
  if not desc:
1052
  continue
1053
 
1054
- rows.append({"date": date_str, "desc": desc, "amount": amount_candidate})
1055
 
1056
  # Guard: require at least 2 rows to avoid false positives on non-transaction pages
1057
  return rows if len(rows) >= 2 else []
@@ -1187,26 +1192,47 @@ def _patch_ocr_with_textlayer(page_md: str, pdf_path: str, page_num: int) -> str
1187
  new_grid.append(list(row))
1188
  to_inject[key] = 0
1189
 
1190
- # Case B: append completely missing rows from the text layer.
1191
- # These are rows the OCR model dropped entirely (not just undercounted).
1192
- # We build new table rows using the text-layer data, placing values in
1193
- # the correct columns as identified from the OCR table header.
1194
- ncols = len(grid[0])
1195
- for key, (count, tl_row_data) in to_inject_new.items():
1196
- for _ in range(count):
1197
- new_row = [""] * ncols
1198
- new_row[date_col] = tl_row_data["date"]
1199
- new_row[desc_col] = tl_row_data["desc"]
1200
- new_row[amt_col] = tl_row_data["amount"]
1201
- new_grid.append(new_row)
1202
- log.info(
1203
- "page %d: injected missing row from text layer: %s %s",
1204
- page_num, tl_row_data["date"], tl_row_data["desc"][:40]
1205
- )
1206
-
1207
  new_table_html = _grid_to_html(new_grid)
1208
  result = result.replace(table_html, new_table_html, 1)
1209
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1210
  return result
1211
 
1212
  except Exception as e:
 
1024
  # Line looks like: Jan 16 Jan 16 CAPITAL ONE MOBILE PYMT - $500.00
1025
  # After consuming first date, check if next tokens are also a date
1026
  remaining = line[desc_start:]
1027
+ # Capture post_date if next tokens are also a date
1028
+ post_date_str = ""
1029
  if remaining and month_re.match(remaining[0]):
1030
  if len(remaining) > 1 and day_re.match(remaining[1]):
1031
+ post_date_str = remaining[0] + " " + remaining[1]
1032
  remaining = remaining[2:]
1033
  elif len(remaining) > 0:
1034
  remaining = remaining[1:]
1035
+ elif remaining and date_re.match(remaining[0]) and not month_re.match(remaining[0]):
1036
+ post_date_str = remaining[0]
1037
+ remaining = remaining[1:]
1038
 
1039
  if len(remaining) < 2:
1040
  continue
 
1056
  if not desc:
1057
  continue
1058
 
1059
+ rows.append({"date": date_str, "post_date": post_date_str, "desc": desc, "amount": amount_candidate})
1060
 
1061
  # Guard: require at least 2 rows to avoid false positives on non-transaction pages
1062
  return rows if len(rows) >= 2 else []
 
1192
  new_grid.append(list(row))
1193
  to_inject[key] = 0
1194
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1195
  new_table_html = _grid_to_html(new_grid)
1196
  result = result.replace(table_html, new_table_html, 1)
1197
 
1198
+ # Case B: completely missing rows → build a SEPARATE new table
1199
+ # appended after the patched OCR table. Using a separate table
1200
+ # preserves the original PDF structure (e.g. Capital One has
1201
+ # separate "Payments" and "Transactions" sections).
1202
+ if to_inject_new:
1203
+ ncols = len(grid[0])
1204
+ header_row = grid[0]
1205
+
1206
+ # Find post_date column index if it exists in the header
1207
+ post_date_col = None
1208
+ for ci, h in enumerate(header_row):
1209
+ hh = str(h or "").strip().upper()
1210
+ if "POST" in hh and "DATE" in hh:
1211
+ post_date_col = ci
1212
+ break
1213
+
1214
+ new_rows = []
1215
+ for key, (count, tl_row_data) in to_inject_new.items():
1216
+ for _ in range(count):
1217
+ new_row = [""] * ncols
1218
+ new_row[date_col] = tl_row_data["date"]
1219
+ new_row[desc_col] = tl_row_data["desc"]
1220
+ new_row[amt_col] = tl_row_data["amount"]
1221
+ if post_date_col is not None:
1222
+ new_row[post_date_col] = tl_row_data.get("post_date", "")
1223
+ new_rows.append(new_row)
1224
+ log.info(
1225
+ "page %d: new table row from text layer: %s %s",
1226
+ page_num, tl_row_data["date"], tl_row_data["desc"][:40]
1227
+ )
1228
+
1229
+ if new_rows:
1230
+ extra_grid = [header_row] + new_rows
1231
+ extra_html = "\n\n" + _grid_to_html(extra_grid)
1232
+ # Insert immediately after the patched table
1233
+ insert_pos = result.find(new_table_html) + len(new_table_html)
1234
+ result = result[:insert_pos] + extra_html + result[insert_pos:]
1235
+
1236
  return result
1237
 
1238
  except Exception as e: