rehan953 commited on
Commit
7cb1629
·
verified ·
1 Parent(s): fa03d3c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -13
app.py CHANGED
@@ -8,6 +8,12 @@ Scope (intentionally small):
8
  - Footer band: same pattern, with light dedup so we do not paste a full
9
  transaction dump twice when the body already captured it
10
 
 
 
 
 
 
 
11
  Explicitly omitted vs the heavy Space build:
12
  - No HTML table rewriting, text-layer row injection, institution-specific
13
  splits (UCB / Navy / TD / First Horizon / …), or doc-wide dedupe passes
@@ -55,19 +61,33 @@ log = logging.getLogger("glmocr_simple_app")
55
  logging.basicConfig(level=logging.INFO)
56
 
57
  # ---------------------------------------------------------------------------
58
- # Settings
59
  # ---------------------------------------------------------------------------
60
 
61
- GLMOCR_API_KEY = "cee1d52dd91a4ab591b3f6e105f8ad89.LgbQTECuzX0zrito"
62
  if not GLMOCR_API_KEY:
63
  log.warning("GLMOCR_API_KEY is not set; GlmOcr() will fail until you export it.")
64
 
65
- RENDER_SCALE = 2.2
66
- PAD_LEFT_FRAC = 0.02
67
- PAD_RIGHT_FRAC = 0.06
68
- PAD_TOP_FRAC = 0.01
69
- PAD_BOTTOM_FRAC = 0.01
 
 
 
 
 
 
70
  ENABLE_CONTRAST = True
 
 
 
 
 
 
 
 
71
 
72
  DEFAULT_ZONE_FRAC = 0.12
73
  PDF_HEADER_BAND_FRAC = 0.10
@@ -78,9 +98,35 @@ PDF_FOOTER_BAND_FRAC = 0.88
78
  MIN_CROP_HEIGHT = 112
79
  MIN_CROP_PIXELS = 112 * 112
80
 
 
 
 
 
 
81
  _parser = None
82
 
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  def get_parser():
85
  global _parser
86
  if glmocr is None:
@@ -186,7 +232,7 @@ def ocr_zone(image_path, y_start_frac, y_end_frac):
186
  fd, path = tempfile.mkstemp(suffix=".jpg")
187
  os.close(fd)
188
  try:
189
- crop.save(path, "JPEG", quality=92)
190
  parser = get_parser()
191
  out = parser.parse(path)
192
  if not isinstance(out, list):
@@ -308,7 +354,7 @@ def light_stabilize_markdown(page_md: str) -> str:
308
 
309
  def render_pdf_pages_to_images(pdf_path: str) -> Tuple[List[str], List[int]]:
310
  import pymupdf as fitz
311
- from PIL import Image, ImageEnhance
312
 
313
  doc = fitz.open(pdf_path)
314
  page_images: List[str] = []
@@ -319,9 +365,7 @@ def render_pdf_pages_to_images(pdf_path: str) -> Tuple[List[str], List[int]]:
319
  pix = page.get_pixmap(matrix=fitz.Matrix(RENDER_SCALE, RENDER_SCALE), alpha=False)
320
 
321
  img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
322
-
323
- if ENABLE_CONTRAST:
324
- img = ImageEnhance.Contrast(img).enhance(1.12)
325
 
326
  w, h = img.size
327
  pad_l = int(w * PAD_LEFT_FRAC)
@@ -335,7 +379,7 @@ def render_pdf_pages_to_images(pdf_path: str) -> Tuple[List[str], List[int]]:
335
  img = canvas
336
 
337
  img_path = os.path.join(tempfile.gettempdir(), f"glmocr_page_{os.getpid()}_{i}.png")
338
- img.save(img_path, "PNG", compress_level=6)
339
  page_images.append(img_path)
340
  page_heights.append(img.height)
341
 
 
8
  - Footer band: same pattern, with light dedup so we do not paste a full
9
  transaction dump twice when the body already captured it
10
 
11
+ Universal image pipeline (same for every PDF, no keywords / no bank logic):
12
+ - Higher rasterization scale + extra white padding so fine print, boxed
13
+ section labels, and right-aligned amounts sit farther from the clip edge.
14
+ - Mild contrast + unsharp mask on every raster sent to the model so
15
+ thin rules and small glyphs are easier to read before recognition.
16
+
17
  Explicitly omitted vs the heavy Space build:
18
  - No HTML table rewriting, text-layer row injection, institution-specific
19
  splits (UCB / Navy / TD / First Horizon / …), or doc-wide dedupe passes
 
61
  logging.basicConfig(level=logging.INFO)
62
 
63
  # ---------------------------------------------------------------------------
64
+ # Settings — tuned for dense financial PDFs; applies to every document
65
  # ---------------------------------------------------------------------------
66
 
67
+ GLMOCR_API_KEY = os.environ.get("GLMOCR_API_KEY", "").strip()
68
  if not GLMOCR_API_KEY:
69
  log.warning("GLMOCR_API_KEY is not set; GlmOcr() will fail until you export it.")
70
 
71
+ # Rasterization: higher scale = more pixels per PDF point (helps small type,
72
+ # boxed headers, and narrow columns). Same constant for all uploads.
73
+ RENDER_SCALE = 2.85
74
+
75
+ # White margin as a fraction of page width/height after render. Extra right
76
+ # margin helps right-aligned currency columns that hug the page edge.
77
+ PAD_LEFT_FRAC = 0.03
78
+ PAD_RIGHT_FRAC = 0.10
79
+ PAD_TOP_FRAC = 0.015
80
+ PAD_BOTTOM_FRAC = 0.015
81
+
82
  ENABLE_CONTRAST = True
83
+ # Slight contrast lift only; same factor for every file.
84
+ CONTRAST_FACTOR = 1.12
85
+
86
+ # Subtle edge enhancement after contrast (helps hairlines and small digits).
87
+ ENABLE_UNSHARP = True
88
+ UNSHARP_RADIUS = 0.85
89
+ UNSHARP_PERCENT = 65
90
+ UNSHARP_THRESHOLD = 2
91
 
92
  DEFAULT_ZONE_FRAC = 0.12
93
  PDF_HEADER_BAND_FRAC = 0.10
 
98
  MIN_CROP_HEIGHT = 112
99
  MIN_CROP_PIXELS = 112 * 112
100
 
101
+ # PNG compression 0–9; lower = less loss before GLM-OCR (same for all PDFs).
102
+ PAGE_PNG_COMPRESS_LEVEL = 3
103
+ # JPEG quality for small header/footer crops sent to the API.
104
+ ZONE_JPEG_QUALITY = 95
105
+
106
  _parser = None
107
 
108
 
109
+ def _enhance_raster_for_ocr(img):
110
+ """
111
+ Improve legibility of every raster passed to GLM-OCR (full pages and
112
+ header/footer crops). No document text or keywords — same pipeline for
113
+ all PDFs and images.
114
+ """
115
+ from PIL import ImageEnhance, ImageFilter
116
+
117
+ if ENABLE_CONTRAST:
118
+ img = ImageEnhance.Contrast(img).enhance(CONTRAST_FACTOR)
119
+ if ENABLE_UNSHARP:
120
+ img = img.filter(
121
+ ImageFilter.UnsharpMask(
122
+ radius=UNSHARP_RADIUS,
123
+ percent=UNSHARP_PERCENT,
124
+ threshold=UNSHARP_THRESHOLD,
125
+ )
126
+ )
127
+ return img
128
+
129
+
130
  def get_parser():
131
  global _parser
132
  if glmocr is None:
 
232
  fd, path = tempfile.mkstemp(suffix=".jpg")
233
  os.close(fd)
234
  try:
235
+ crop.save(path, "JPEG", quality=ZONE_JPEG_QUALITY)
236
  parser = get_parser()
237
  out = parser.parse(path)
238
  if not isinstance(out, list):
 
354
 
355
  def render_pdf_pages_to_images(pdf_path: str) -> Tuple[List[str], List[int]]:
356
  import pymupdf as fitz
357
+ from PIL import Image
358
 
359
  doc = fitz.open(pdf_path)
360
  page_images: List[str] = []
 
365
  pix = page.get_pixmap(matrix=fitz.Matrix(RENDER_SCALE, RENDER_SCALE), alpha=False)
366
 
367
  img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
368
+ img = _enhance_raster_for_ocr(img)
 
 
369
 
370
  w, h = img.size
371
  pad_l = int(w * PAD_LEFT_FRAC)
 
379
  img = canvas
380
 
381
  img_path = os.path.join(tempfile.gettempdir(), f"glmocr_page_{os.getpid()}_{i}.png")
382
+ img.save(img_path, "PNG", compress_level=PAGE_PNG_COMPRESS_LEVEL)
383
  page_images.append(img_path)
384
  page_heights.append(img.height)
385