rehan953 commited on
Commit
60b8c65
·
verified ·
1 Parent(s): 53ff59a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -23
app.py CHANGED
@@ -25,7 +25,8 @@ Primary goals for reconcile rate:
25
  Beginning/Ending balance rows (UCB-style wide summary tables)
26
  - Fix 14: UCB 3-col tables where Beginning Balance amount is fused into description and Amount is $0.00
27
  - Fix 15: UCB (and similar) 3-col rows where Date+Description are fused in col1 and Amount sits in col2 with col3 empty
28
- - Post-pass: drop later duplicate subset Date|Description|Amount tables (repeated deposit blocks)
 
29
  """
30
 
31
  # Patch asyncio first (before Gradio imports it) to suppress Python 3.13 cleanup noise
@@ -3108,9 +3109,11 @@ def normalize_html_tables(text: str) -> str:
3108
 
3109
  def _dedupe_subset_transaction_tables_html(text: str) -> str:
3110
  """
3111
- Remove duplicate 3-column transaction tables where a later table's rows are a
3112
- strict subset of an earlier table's rows (same Date|Description|Amount header).
3113
- Used when OCR repeats the same deposit block under a section heading.
 
 
3114
  """
3115
  if not text or "<table" not in text.lower():
3116
  return text
@@ -3132,42 +3135,55 @@ def _dedupe_subset_transaction_tables_html(text: str) -> str:
3132
  for m in matches:
3133
  grids.append((m, _parse_grid(m.group(0))))
3134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3135
  drop_idx = set()
3136
  for i in range(1, len(grids)):
 
 
3137
  mi, gi = grids[i]
3138
- if not gi or len(gi) < 2:
3139
  continue
3140
- h = [re.sub(r"\s+", " ", str(c or "").strip().lower()) for c in gi[0]]
3141
- if len(h) != 3 or h != ["date", "description", "amount"]:
3142
  continue
3143
 
3144
  for j in range(i):
3145
  if j in drop_idx:
3146
  continue
3147
  mj, gj = grids[j]
3148
- if not gj or len(gj) < 2:
3149
  continue
3150
- hj = [re.sub(r"\s+", " ", str(c or "").strip().lower()) for c in gj[0]]
3151
- if len(hj) != 3 or hj != ["date", "description", "amount"]:
3152
  continue
3153
 
3154
- def _row_set(g):
3155
- s = set()
3156
- for r in g[1:]:
3157
- if not any(str(c or "").strip() for c in r):
3158
- continue
3159
- t = tuple(str(c or "").strip() for c in r)
3160
- if any(t):
3161
- s.add(t)
3162
- return s
3163
-
3164
- si, sj = _row_set(gi), _row_set(gj)
3165
- if not si or not sj:
3166
  continue
3167
- # Drop later table if it is a strict subset of an earlier one (repeated block).
 
3168
  if si <= sj and len(si) < len(sj):
3169
  drop_idx.add(i)
3170
  break
 
3171
  if si == sj:
3172
  drop_idx.add(i)
3173
  break
 
25
  Beginning/Ending balance rows (UCB-style wide summary tables)
26
  - Fix 14: UCB 3-col tables where Beginning Balance amount is fused into description and Amount is $0.00
27
  - Fix 15: UCB (and similar) 3-col rows where Date+Description are fused in col1 and Amount sits in col2 with col3 empty
28
+ - Post-pass: dedupe 3-col Date|Description|Amount tables when one is a duplicate fragment
29
+ (later subset of earlier, earlier subset of later, or identical row sets)
30
  """
31
 
32
  # Patch asyncio first (before Gradio imports it) to suppress Python 3.13 cleanup noise
 
3109
 
3110
  def _dedupe_subset_transaction_tables_html(text: str) -> str:
3111
  """
3112
+ Remove duplicate 3-column Date|Description|Amount tables:
3113
+ - Later table is a strict subset of an earlier one drop later (original).
3114
+ - Earlier table is a strict subset of a later one → drop earlier (UCB-style
3115
+ "Deposits (continued)" preview before the same rows appear in the full list).
3116
+ - Identical row sets → drop the later table.
3117
  """
3118
  if not text or "<table" not in text.lower():
3119
  return text
 
3135
  for m in matches:
3136
  grids.append((m, _parse_grid(m.group(0))))
3137
 
3138
+ hdr_ok = ["date", "description", "amount"]
3139
+
3140
+ def _header_matches(grid):
3141
+ if not grid or len(grid) < 2:
3142
+ return False
3143
+ h = [re.sub(r"\s+", " ", str(c or "").strip().lower()) for c in grid[0]]
3144
+ return len(h) == 3 and h == hdr_ok
3145
+
3146
+ def _row_set(g):
3147
+ s = set()
3148
+ for r in g[1:]:
3149
+ if not any(str(c or "").strip() for c in r):
3150
+ continue
3151
+ t = tuple(str(c or "").strip() for c in r)
3152
+ if any(t):
3153
+ s.add(t)
3154
+ return s
3155
+
3156
  drop_idx = set()
3157
  for i in range(1, len(grids)):
3158
+ if i in drop_idx:
3159
+ continue
3160
  mi, gi = grids[i]
3161
+ if not _header_matches(gi):
3162
  continue
3163
+ si = _row_set(gi)
3164
+ if not si:
3165
  continue
3166
 
3167
  for j in range(i):
3168
  if j in drop_idx:
3169
  continue
3170
  mj, gj = grids[j]
3171
+ if not _header_matches(gj):
3172
  continue
3173
+ sj = _row_set(gj)
3174
+ if not sj:
3175
  continue
3176
 
3177
+ # Earlier j fully contained in later i (preview + full list) → drop earlier.
3178
+ if sj <= si and len(sj) < len(si):
3179
+ drop_idx.add(j)
 
 
 
 
 
 
 
 
 
3180
  continue
3181
+
3182
+ # Later i strict subset of earlier j → drop later.
3183
  if si <= sj and len(si) < len(sj):
3184
  drop_idx.add(i)
3185
  break
3186
+
3187
  if si == sj:
3188
  drop_idx.add(i)
3189
  break