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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -156
app.py CHANGED
@@ -1,127 +1,54 @@
1
- import gradio as gr
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:
18
  config = yaml.safe_load(f)
19
 
20
  config["pipeline"]["maas"]["enabled"] = True
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:
57
- y_tops.append(bbox[1])
58
- y_bottoms.append(bbox[3])
59
- if not y_tops:
60
- return None, None
61
- return min(y_tops) / norm_height, max(y_bottoms) / norm_height
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]
68
- h, w = page.rect.height, page.rect.width
69
- rect = fitz.Rect(0, h * y_start_frac, w, h * y_end_frac)
70
- text = page.get_text(clip=rect).strip()
71
- doc.close()
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
110
- if isinstance(jr, list) and len(jr) > 0:
111
- r = jr[0] if isinstance(jr[0], list) else jr
112
- if isinstance(r, list):
113
- regions = r
114
- md = ""
115
- if hasattr(page_result, "markdown_result") and page_result.markdown_result:
116
- md = page_result.markdown_result.strip()
117
- return md, regions
118
-
119
-
120
- # ── STEP 4: Main OCR ─────────────────────────────────────────
121
  def run_ocr(uploaded_file):
122
  if uploaded_file is None:
123
  return "Please upload a file."
124
-
125
  try:
126
  from glmocr import parse
127
  import pymupdf as fitz
@@ -139,63 +66,29 @@ def run_ocr(uploaded_file):
139
  page_images.append(img_path)
140
  doc.close()
141
  results = parse(page_images)
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]
149
-
150
- all_pages_md = []
151
-
152
- for page_num, page_result in enumerate(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:
180
- if page_md:
181
- parts.append(page_md)
182
-
183
- if parts:
184
- all_pages_md.append("\n\n".join(parts))
185
-
186
- final = "\n\n---\n\n".join(all_pages_md) if all_pages_md else "(No content)"
187
  return final
188
-
189
  except Exception as e:
190
  import traceback
191
- return "Error: " + str(e) + "\n\n" + traceback.format_exc()
192
-
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()
 
 
 
 
1
  import os
2
+ import re
3
+ import yaml
4
+ import gradio as gr
5
 
6
  import glmocr
 
 
 
7
 
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
+ # ─── 1. Config: include headers and footers (remove from abandon lists) ───
13
+ with open(CONFIG_PATH, "r") as f:
14
  config = yaml.safe_load(f)
15
 
16
  config["pipeline"]["maas"]["enabled"] = True
17
+ api_key = os.environ.get("GLMOCR_MaaS_API_KEY") or os.environ.get("ZHIPU_API_KEY")
18
+ if api_key:
19
+ config["pipeline"]["maas"]["api_key"] = api_key
20
 
21
  to_remove = {"header", "footer"}
22
+ for key in ("layout", "result_formatter"):
23
+ if key not in config.get("pipeline", {}):
24
+ continue
25
+ section = config["pipeline"][key]
26
+ if key == "layout" and "label_task_mapping" in section:
27
+ abandon = section["label_task_mapping"].get("abandon")
28
+ if isinstance(abandon, list):
29
+ section["label_task_mapping"]["abandon"] = [x for x in abandon if x not in to_remove]
30
+ elif key == "result_formatter" and "abandon" in section:
31
+ abandon = section["abandon"]
32
+ if isinstance(abandon, list):
33
+ section["abandon"] = [x for x in abandon if x not in to_remove]
34
+
35
+ with open(CONFIG_PATH, "w") as f:
36
  yaml.dump(config, f, default_flow_style=False, sort_keys=False)
37
 
38
+ # ─── 2. result_formatter: stop stripping header/footer in postprocess ───
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
 
48
+ # ─── 3. Run OCR (no custom header/footer logic; pipeline returns full content) ───
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def run_ocr(uploaded_file):
50
  if uploaded_file is None:
51
  return "Please upload a file."
 
52
  try:
53
  from glmocr import parse
54
  import pymupdf as fitz
 
66
  page_images.append(img_path)
67
  doc.close()
68
  results = parse(page_images)
 
 
69
  else:
 
70
  results = parse(path)
 
 
 
 
 
 
 
 
71
 
72
+ if not isinstance(results, list):
73
+ results = [results]
 
 
74
 
75
+ parts = []
76
+ for r in results:
77
+ md = getattr(r, "markdown_result", None) or ""
78
+ if isinstance(md, str) and md.strip():
79
+ parts.append(md.strip())
80
+ final = "\n\n---\n\n".join(parts) if parts else "(No content)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  return final
 
82
  except Exception as e:
83
  import traceback
84
+ return f"Error: {e}\n\n{traceback.format_exc()}"
 
85
 
86
+ # ─── 4. UI ───
87
  with gr.Blocks(title="GLM-OCR") as demo:
88
+ gr.Markdown("# GLM-OCR\nUpload a PDF or image. Headers and footers are included.")
89
+ file_in = gr.File(label="Upload PDF or image", file_types=[".pdf", ".png", ".jpg", ".jpeg", ".tiff", ".bmp"])
90
+ run_btn = gr.Button("Run OCR", variant="primary")
91
+ out = gr.Textbox(lines=40, label="Output")
92
+ run_btn.click(fn=run_ocr, inputs=file_in, outputs=out)
93
+
94
  demo.launch()