rehan953 commited on
Commit
f096f6a
Β·
verified Β·
1 Parent(s): a58a36b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -39
app.py CHANGED
@@ -2,15 +2,16 @@ import gradio as gr
2
  import yaml
3
  import re
4
  import os
 
5
 
6
  import glmocr
7
  GLMOCR_BASE = os.path.dirname(glmocr.__file__)
8
  config_path = os.path.join(GLMOCR_BASE, "config.yaml")
9
  formatter_path = os.path.join(GLMOCR_BASE, "postprocess", "result_formatter.py")
10
 
11
- # Fallback band when API reports no gap (so all PDFs get header/footer)
12
- FALLBACK_HEADER_FRAC = 0.05
13
- FALLBACK_FOOTER_FRAC = 0.05
14
 
15
  # ── STEP 1: Remove header/footer from abandon lists only ──────
16
  with open(config_path, "r") as f:
@@ -20,53 +21,36 @@ config["pipeline"]["maas"]["enabled"] = True
20
  config["pipeline"]["maas"]["api_key"] = "4570c28bdea5493c9efae9dae68edc66.sGbA9DLlcX1GlvqV"
21
 
22
  to_remove = {"header", "footer"}
23
-
24
  if "layout" in config["pipeline"] and "label_task_mapping" in config["pipeline"]["layout"]:
25
  abandon = config["pipeline"]["layout"]["label_task_mapping"].get("abandon")
26
  if isinstance(abandon, list):
27
- config["pipeline"]["layout"]["label_task_mapping"]["abandon"] = [
28
- x for x in abandon if x not in to_remove
29
- ]
30
-
31
  if "result_formatter" in config["pipeline"]:
32
  abandon = config["pipeline"]["result_formatter"].get("abandon")
33
  if isinstance(abandon, list):
34
- config["pipeline"]["result_formatter"]["abandon"] = [
35
- x for x in abandon if x not in to_remove
36
- ]
37
 
38
  with open(config_path, "w") as f:
39
  yaml.dump(config, f, default_flow_style=False, sort_keys=False)
40
 
41
- print("βœ… config.yaml updated (header/footer removed from abandon only)")
42
 
43
  # ── STEP 2: Fix result_formatter.py ──────────────────────────
44
  with open(formatter_path, "r") as f:
45
  source = f.read()
46
-
47
- labels_to_remove = [
48
- '"header"', "'header'",
49
- '"footer"', "'footer'",
50
- '"doc_header"', "'doc_header'",
51
- '"doc_footer"', "'doc_footer'",
52
- ]
53
- for label in labels_to_remove:
54
  source = re.sub(r',\s*' + re.escape(label), '', source)
55
  source = re.sub(re.escape(label) + r'\s*,', '', source)
56
  source = re.sub(re.escape(label), '', source)
57
-
58
  with open(formatter_path, "w") as f:
59
  f.write(source)
60
-
61
  print("βœ… result_formatter.py fixed")
62
 
63
  # ── STEP 3: Helpers ───────────────────────────────────────────
64
  def get_header_footer_zones(regions, norm_height=1000):
65
- """From bbox_2d (0–norm_height) return (header_end_frac, footer_start_frac)."""
66
  if not regions:
67
  return None, None
68
- y_tops = []
69
- y_bottoms = []
70
  for r in regions:
71
  bbox = r.get("bbox_2d")
72
  if bbox and len(bbox) == 4:
@@ -78,7 +62,6 @@ def get_header_footer_zones(regions, norm_height=1000):
78
 
79
 
80
  def extract_zone_text(pdf_path, page_num, y_start_frac, y_end_frac):
81
- """Extract text from a vertical slice of a PDF page."""
82
  import pymupdf as fitz
83
  doc = fitz.open(pdf_path)
84
  page = doc[page_num]
@@ -89,8 +72,38 @@ def extract_zone_text(pdf_path, page_num, y_start_frac, y_end_frac):
89
  return text
90
 
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  def get_page_data(page_result):
93
- """Return (markdown, regions) for one PipelineResult."""
94
  regions = []
95
  if hasattr(page_result, "json_result"):
96
  jr = page_result.json_result
@@ -129,6 +142,7 @@ def run_ocr(uploaded_file):
129
  if not isinstance(results, list):
130
  results = [results]
131
  else:
 
132
  results = parse(path)
133
  if not isinstance(results, list):
134
  results = [results]
@@ -139,21 +153,27 @@ def run_ocr(uploaded_file):
139
  page_md, regions = get_page_data(page_result)
140
  parts = []
141
 
142
- if is_pdf:
143
  header_end, footer_start = get_header_footer_zones(regions, 1000)
144
  he = max(header_end, FALLBACK_HEADER_FRAC) if header_end is not None else FALLBACK_HEADER_FRAC
145
  fs = min(footer_start, 1.0 - FALLBACK_FOOTER_FRAC) if footer_start is not None else (1.0 - FALLBACK_FOOTER_FRAC)
146
 
 
147
  if he > 0:
148
  hdr = extract_zone_text(path, page_num, 0, he)
 
 
149
  if hdr and hdr.strip():
150
  parts.append(hdr.strip())
151
 
152
  if page_md:
153
  parts.append(page_md)
154
 
 
155
  if fs < 1.0:
156
  ftr = extract_zone_text(path, page_num, fs, 1.0)
 
 
157
  if ftr and ftr.strip():
158
  parts.append(ftr.strip())
159
  else:
@@ -173,18 +193,9 @@ def run_ocr(uploaded_file):
173
 
174
  # ── STEP 5: Gradio UI ─────────────────────────────────────────
175
  with gr.Blocks(title="GLM-OCR") as demo:
176
- gr.Markdown("""
177
- # πŸ” GLM-OCR
178
- Upload a PDF or image. Headers and footers from PDF text layer (all PDFs).
179
- """)
180
-
181
- file_input = gr.File(
182
- label="Upload PDF or Image",
183
- file_types=[".pdf", ".png", ".jpg", ".jpeg", ".tiff", ".bmp"]
184
- )
185
  run_btn = gr.Button("β–Ά Run OCR", variant="primary", size="lg")
186
  output_box = gr.Textbox(lines=40, label="Output")
187
-
188
  run_btn.click(fn=run_ocr, inputs=file_input, outputs=output_box)
189
-
190
  demo.launch()
 
2
  import yaml
3
  import re
4
  import os
5
+ import tempfile
6
 
7
  import glmocr
8
  GLMOCR_BASE = os.path.dirname(glmocr.__file__)
9
  config_path = os.path.join(GLMOCR_BASE, "config.yaml")
10
  formatter_path = os.path.join(GLMOCR_BASE, "postprocess", "result_formatter.py")
11
 
12
+ FALLBACK_HEADER_FRAC = 0.12
13
+ FALLBACK_FOOTER_FRAC = 0.12
14
+ OCR_FALLBACK_HEADER_FOOTER = True # When text layer is empty, OCR the crop
15
 
16
  # ── STEP 1: Remove header/footer from abandon lists only ──────
17
  with open(config_path, "r") as f:
 
21
  config["pipeline"]["maas"]["api_key"] = "4570c28bdea5493c9efae9dae68edc66.sGbA9DLlcX1GlvqV"
22
 
23
  to_remove = {"header", "footer"}
 
24
  if "layout" in config["pipeline"] and "label_task_mapping" in config["pipeline"]["layout"]:
25
  abandon = config["pipeline"]["layout"]["label_task_mapping"].get("abandon")
26
  if isinstance(abandon, list):
27
+ config["pipeline"]["layout"]["label_task_mapping"]["abandon"] = [x for x in abandon if x not in to_remove]
 
 
 
28
  if "result_formatter" in config["pipeline"]:
29
  abandon = config["pipeline"]["result_formatter"].get("abandon")
30
  if isinstance(abandon, list):
31
+ config["pipeline"]["result_formatter"]["abandon"] = [x for x in abandon if x not in to_remove]
 
 
32
 
33
  with open(config_path, "w") as f:
34
  yaml.dump(config, f, default_flow_style=False, sort_keys=False)
35
 
36
+ print("βœ… config.yaml updated")
37
 
38
  # ── STEP 2: Fix result_formatter.py ──────────────────────────
39
  with open(formatter_path, "r") as f:
40
  source = f.read()
41
+ for label in ['"header"', "'header'", '"footer"', "'footer'", '"doc_header"', "'doc_header'", '"doc_footer"', "'doc_footer'"]:
 
 
 
 
 
 
 
42
  source = re.sub(r',\s*' + re.escape(label), '', source)
43
  source = re.sub(re.escape(label) + r'\s*,', '', source)
44
  source = re.sub(re.escape(label), '', source)
 
45
  with open(formatter_path, "w") as f:
46
  f.write(source)
 
47
  print("βœ… result_formatter.py fixed")
48
 
49
  # ── STEP 3: Helpers ───────────────────────────────────────────
50
  def get_header_footer_zones(regions, norm_height=1000):
 
51
  if not regions:
52
  return None, None
53
+ y_tops, y_bottoms = [], []
 
54
  for r in regions:
55
  bbox = r.get("bbox_2d")
56
  if bbox and len(bbox) == 4:
 
62
 
63
 
64
  def extract_zone_text(pdf_path, page_num, y_start_frac, y_end_frac):
 
65
  import pymupdf as fitz
66
  doc = fitz.open(pdf_path)
67
  page = doc[page_num]
 
72
  return text
73
 
74
 
75
+ def ocr_image_zone(image_path, y_start_frac, y_end_frac, is_footer=False):
76
+ """Crop a band from the page image and run parse() on it; return markdown or ''."""
77
+ try:
78
+ from PIL import Image
79
+ from glmocr import parse
80
+ img = Image.open(image_path).convert("RGB")
81
+ w, h = img.size
82
+ y0 = int(h * y_start_frac)
83
+ y1 = int(h * y_end_frac)
84
+ if y1 <= y0:
85
+ return ""
86
+ crop = img.crop((0, y0, w, y1))
87
+ fd, path = tempfile.mkstemp(suffix=".png")
88
+ os.close(fd)
89
+ crop.save(path)
90
+ try:
91
+ out = parse(path)
92
+ if not isinstance(out, list):
93
+ out = [out]
94
+ if out and hasattr(out[0], "markdown_result") and out[0].markdown_result:
95
+ return out[0].markdown_result.strip()
96
+ finally:
97
+ try:
98
+ os.unlink(path)
99
+ except Exception:
100
+ pass
101
+ except Exception:
102
+ pass
103
+ return ""
104
+
105
+
106
  def get_page_data(page_result):
 
107
  regions = []
108
  if hasattr(page_result, "json_result"):
109
  jr = page_result.json_result
 
142
  if not isinstance(results, list):
143
  results = [results]
144
  else:
145
+ page_images = []
146
  results = parse(path)
147
  if not isinstance(results, list):
148
  results = [results]
 
153
  page_md, regions = get_page_data(page_result)
154
  parts = []
155
 
156
+ if is_pdf and page_num < len(page_images):
157
  header_end, footer_start = get_header_footer_zones(regions, 1000)
158
  he = max(header_end, FALLBACK_HEADER_FRAC) if header_end is not None else FALLBACK_HEADER_FRAC
159
  fs = min(footer_start, 1.0 - FALLBACK_FOOTER_FRAC) if footer_start is not None else (1.0 - FALLBACK_FOOTER_FRAC)
160
 
161
+ # Header: PDF text layer first; if empty, OCR the top crop
162
  if he > 0:
163
  hdr = extract_zone_text(path, page_num, 0, he)
164
+ if not (hdr and hdr.strip()) and OCR_FALLBACK_HEADER_FOOTER:
165
+ hdr = ocr_image_zone(page_images[page_num], 0, FALLBACK_HEADER_FRAC, is_footer=False)
166
  if hdr and hdr.strip():
167
  parts.append(hdr.strip())
168
 
169
  if page_md:
170
  parts.append(page_md)
171
 
172
+ # Footer: PDF text layer first; if empty, OCR the bottom crop
173
  if fs < 1.0:
174
  ftr = extract_zone_text(path, page_num, fs, 1.0)
175
+ if not (ftr and ftr.strip()) and OCR_FALLBACK_HEADER_FOOTER:
176
+ ftr = ocr_image_zone(page_images[page_num], 1.0 - FALLBACK_FOOTER_FRAC, 1.0, is_footer=True)
177
  if ftr and ftr.strip():
178
  parts.append(ftr.strip())
179
  else:
 
193
 
194
  # ── STEP 5: Gradio UI ─────────────────────────────────────────
195
  with gr.Blocks(title="GLM-OCR") as demo:
196
+ gr.Markdown("# πŸ” GLM-OCR\nUpload a PDF or image. Headers/footers from text layer or OCR fallback.")
197
+ file_input = gr.File(label="Upload PDF or Image", file_types=[".pdf", ".png", ".jpg", ".jpeg", ".tiff", ".bmp"])
 
 
 
 
 
 
 
198
  run_btn = gr.Button("β–Ά Run OCR", variant="primary", size="lg")
199
  output_box = gr.Textbox(lines=40, label="Output")
 
200
  run_btn.click(fn=run_ocr, inputs=file_input, outputs=output_box)
 
201
  demo.launch()