rehan953 commited on
Commit
7b52db5
Β·
verified Β·
1 Parent(s): 44afe78

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -9
app.py CHANGED
@@ -2,6 +2,7 @@
2
 
3
  import logging
4
  import os
 
5
  import tempfile
6
  import uuid
7
  from typing import List, Tuple
@@ -10,10 +11,9 @@ log = logging.getLogger("glmocr_simple_app")
10
  logging.basicConfig(level=logging.INFO)
11
 
12
  # ── Fine-tuned model repo on HuggingFace ─────────────────────────────────────
13
- # Loads from HF Hub at runtime β€” no local storage needed in the Space
14
  MERGED_MODEL_DIR = os.environ.get("MODEL_DIR", "SimpleCodeAI/glm-ocr-finetuned")
15
 
16
-
17
  PAD_LEFT_FRAC = 0.035
18
  PAD_RIGHT_FRAC = 0.10
19
  PAD_TOP_FRAC = 0.018
@@ -27,9 +27,8 @@ UNSHARP_PERCENT = 76
27
  UNSHARP_THRESHOLD = 1
28
 
29
  PAGE_PNG_COMPRESS_LEVEL = 3
30
- RENDER_SCALE = 2.0 # was 3.0 β€” reduce render size so resize isn't as aggressive
31
- MAX_IMAGE_SIDE = 1568 # was 1344 β€” allow slightly larger input to model
32
- MAX_NEW_TOKENS = 3000 # resize longest side to this before inference
33
 
34
  # ── Model singleton ───────────────────────────────────────────────────────────
35
  _model = None
@@ -88,6 +87,98 @@ def _resize_for_inference(img):
88
  return img.resize(new_size, Image.LANCZOS)
89
 
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  def _infer_image(image_path: str) -> str:
92
  """Run fine-tuned model on a single image file and return markdown string."""
93
  import torch
@@ -127,13 +218,19 @@ def _infer_image(image_path: str) -> str:
127
  **inputs,
128
  max_new_tokens=MAX_NEW_TOKENS,
129
  do_sample=False,
130
- repetition_penalty=1.1,
 
131
  )
 
132
  result = processor.decode(
133
  ids[0][inputs["input_ids"].shape[1]:],
134
  skip_special_tokens=True,
135
  )
136
- return result.strip()
 
 
 
 
137
 
138
  finally:
139
  try:
@@ -247,7 +344,5 @@ def _create_gradio_demo():
247
 
248
 
249
  if __name__ == "__main__":
250
- # Force model to load at startup
251
  _load_model()
252
-
253
  _create_gradio_demo().launch()
 
2
 
3
  import logging
4
  import os
5
+ import re
6
  import tempfile
7
  import uuid
8
  from typing import List, Tuple
 
11
  logging.basicConfig(level=logging.INFO)
12
 
13
  # ── Fine-tuned model repo on HuggingFace ─────────────────────────────────────
 
14
  MERGED_MODEL_DIR = os.environ.get("MODEL_DIR", "SimpleCodeAI/glm-ocr-finetuned")
15
 
16
+ RENDER_SCALE = 2.0
17
  PAD_LEFT_FRAC = 0.035
18
  PAD_RIGHT_FRAC = 0.10
19
  PAD_TOP_FRAC = 0.018
 
27
  UNSHARP_THRESHOLD = 1
28
 
29
  PAGE_PNG_COMPRESS_LEVEL = 3
30
+ MAX_IMAGE_SIDE = 1568
31
+ MAX_NEW_TOKENS = 3000
 
32
 
33
  # ── Model singleton ───────────────────────────────────────────────────────────
34
  _model = None
 
87
  return img.resize(new_size, Image.LANCZOS)
88
 
89
 
90
+ def _normalize_tables(text: str) -> str:
91
+ """
92
+ Convert plain-text table rows (no pipe boundaries) into proper
93
+ markdown table rows with | boundaries.
94
+
95
+ Handles rows like:
96
+ 10/01 CCD DEBIT, SOME MERCHANT 654.00
97
+ 10/01 DEBIT 2,500.00
98
+ and header rows like:
99
+ POSTING DATE DESCRIPTION AMOUNT
100
+ """
101
+ lines = text.split('\n')
102
+ result = []
103
+ i = 0
104
+
105
+ # Amount pattern: number like 1,234.56 or 123.45
106
+ amt_re = re.compile(r'[\d,]+\.\d{2}$')
107
+ # Date pattern at start of line: MM/DD
108
+ date_re = re.compile(r'^\d{2}/\d{2}\s')
109
+ # Header pattern
110
+ header_re = re.compile(
111
+ r'^(POSTING\s+DATE|DATE)\s+(DESCRIPTION|SERIAL\s+NO\.?|NO\.?\s+CHECKS)',
112
+ re.IGNORECASE
113
+ )
114
+
115
+ in_plain_table = False
116
+
117
+ while i < len(lines):
118
+ line = lines[i]
119
+ stripped = line.strip()
120
+
121
+ # Skip empty lines β€” reset table tracking
122
+ if not stripped:
123
+ in_plain_table = False
124
+ result.append(line)
125
+ i += 1
126
+ continue
127
+
128
+ # Already a proper markdown table row β€” pass through
129
+ if stripped.startswith('|'):
130
+ in_plain_table = False
131
+ result.append(line)
132
+ i += 1
133
+ continue
134
+
135
+ # Detect plain-text table header row
136
+ if header_re.match(stripped):
137
+ # Split by 2+ spaces
138
+ parts = re.split(r'\s{2,}', stripped)
139
+ parts = [p.strip() for p in parts if p.strip()]
140
+ if len(parts) >= 2:
141
+ result.append('| ' + ' | '.join(parts) + ' |')
142
+ result.append('| ' + ' | '.join(['---'] * len(parts)) + ' |')
143
+ in_plain_table = True
144
+ i += 1
145
+ continue
146
+
147
+ # Detect plain-text data row starting with date
148
+ if date_re.match(stripped):
149
+ # Split by 2+ spaces to separate columns
150
+ parts = re.split(r'\s{2,}', stripped)
151
+ parts = [p.strip() for p in parts if p.strip()]
152
+
153
+ # If only one part (description runs together), try splitting off amount
154
+ if len(parts) == 1 and amt_re.search(stripped):
155
+ # Split last amount token off
156
+ m = re.search(r'^(.*?)\s+([\d,]+\.\d{2})$', stripped)
157
+ if m:
158
+ parts = [m.group(1).strip(), m.group(2).strip()]
159
+
160
+ if len(parts) >= 2:
161
+ result.append('| ' + ' | '.join(parts) + ' |')
162
+ in_plain_table = True
163
+ i += 1
164
+ continue
165
+
166
+ # Detect subtotal lines inside a plain table
167
+ if in_plain_table and re.match(r'^Subtotal:', stripped, re.IGNORECASE):
168
+ m = re.match(r'^(Subtotal:)\s+([\d,]+\.\d{2})', stripped, re.IGNORECASE)
169
+ if m:
170
+ result.append(f'| | **{m.group(1)}** | **{m.group(2)}** |')
171
+ i += 1
172
+ continue
173
+
174
+ # Not a table row
175
+ in_plain_table = False
176
+ result.append(line)
177
+ i += 1
178
+
179
+ return '\n'.join(result)
180
+
181
+
182
  def _infer_image(image_path: str) -> str:
183
  """Run fine-tuned model on a single image file and return markdown string."""
184
  import torch
 
218
  **inputs,
219
  max_new_tokens=MAX_NEW_TOKENS,
220
  do_sample=False,
221
+ repetition_penalty=1.15,
222
+ no_repeat_ngram_size=5,
223
  )
224
+
225
  result = processor.decode(
226
  ids[0][inputs["input_ids"].shape[1]:],
227
  skip_special_tokens=True,
228
  )
229
+
230
+ # Normalize plain-text tables to proper markdown tables
231
+ result = _normalize_tables(result.strip())
232
+
233
+ return result
234
 
235
  finally:
236
  try:
 
344
 
345
 
346
  if __name__ == "__main__":
 
347
  _load_model()
 
348
  _create_gradio_demo().launch()