Spaces:
Sleeping
Sleeping
Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -3,7 +3,6 @@ import yaml
|
|
| 3 |
import re
|
| 4 |
import os
|
| 5 |
|
| 6 |
-
# Paths from installed glmocr package
|
| 7 |
import glmocr
|
| 8 |
GLMOCR_BASE = os.path.dirname(glmocr.__file__)
|
| 9 |
config_path = os.path.join(GLMOCR_BASE, "config.yaml")
|
|
@@ -13,8 +12,8 @@ formatter_path = os.path.join(GLMOCR_BASE, "postprocess", "result_formatter.py")
|
|
| 13 |
with open(config_path, "r") as f:
|
| 14 |
config = yaml.safe_load(f)
|
| 15 |
|
| 16 |
-
config["pipeline"]["maas"]["enabled"]
|
| 17 |
-
config["pipeline"]["maas"]["api_key"]
|
| 18 |
|
| 19 |
config["pipeline"]["result_formatter"]["abandon"] = [
|
| 20 |
"number", "footnote", "aside_text",
|
|
@@ -50,9 +49,8 @@ print("β
result_formatter.py fixed")
|
|
| 50 |
ABANDON = set(config["pipeline"]["result_formatter"]["abandon"])
|
| 51 |
|
| 52 |
# ββ STEP 3: Extract header/footer from PDF text layer βββββββββ
|
| 53 |
-
# The MaaS API only returns 'text' and 'table' labels
|
| 54 |
-
#
|
| 55 |
-
# directly from the PDF text layer using PyMuPDF instead.
|
| 56 |
def extract_pdf_headers(path):
|
| 57 |
import fitz
|
| 58 |
page_headers = []
|
|
@@ -60,9 +58,7 @@ def extract_pdf_headers(path):
|
|
| 60 |
for page in doc:
|
| 61 |
page_rect = page.rect
|
| 62 |
page_height = page_rect.height
|
| 63 |
-
# Top 12% = header area
|
| 64 |
header_rect = fitz.Rect(0, 0, page_rect.width, page_height * 0.12)
|
| 65 |
-
# Bottom 12% = footer area
|
| 66 |
footer_rect = fitz.Rect(0, page_height * 0.88, page_rect.width, page_height)
|
| 67 |
header_text = page.get_text(clip=header_rect).strip()
|
| 68 |
footer_text = page.get_text(clip=footer_rect).strip()
|
|
@@ -70,7 +66,29 @@ def extract_pdf_headers(path):
|
|
| 70 |
doc.close()
|
| 71 |
return page_headers
|
| 72 |
|
| 73 |
-
# ββ STEP 4:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
def run_ocr(uploaded_file):
|
| 75 |
if uploaded_file is None:
|
| 76 |
return "Please upload a file.", "No regions detected."
|
|
@@ -80,7 +98,6 @@ def run_ocr(uploaded_file):
|
|
| 80 |
|
| 81 |
path = uploaded_file.name if hasattr(uploaded_file, "name") else str(uploaded_file)
|
| 82 |
|
| 83 |
-
# Convert PDF to images + extract headers from text layer
|
| 84 |
if path.lower().endswith(".pdf"):
|
| 85 |
import fitz
|
| 86 |
pdf_headers = extract_pdf_headers(path)
|
|
@@ -92,30 +109,26 @@ def run_ocr(uploaded_file):
|
|
| 92 |
pix.save(img_path)
|
| 93 |
page_images.append(img_path)
|
| 94 |
doc.close()
|
| 95 |
-
|
|
|
|
|
|
|
|
|
|
| 96 |
else:
|
| 97 |
pdf_headers = []
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
pages_data = result.json_result if hasattr(result, "json_result") else []
|
| 102 |
-
if not isinstance(pages_data, list):
|
| 103 |
-
pages_data = [pages_data] if pages_data else []
|
| 104 |
|
| 105 |
total_headers = 0
|
| 106 |
total_footers = 0
|
| 107 |
all_markdown = []
|
| 108 |
all_summary = []
|
| 109 |
|
| 110 |
-
for page_num,
|
| 111 |
-
if not isinstance(page_regions, list):
|
| 112 |
-
page_regions = [page_regions] if page_regions else []
|
| 113 |
-
|
| 114 |
page_md = []
|
| 115 |
-
page_summary = [f"ββ PAGE {page_num + 1} of {len(
|
| 116 |
|
| 117 |
# Inject header/footer from PDF text layer
|
| 118 |
-
# (API never returns these as separate labeled regions)
|
| 119 |
if pdf_headers and page_num < len(pdf_headers):
|
| 120 |
hdr = pdf_headers[page_num]["header"]
|
| 121 |
ftr = pdf_headers[page_num]["footer"]
|
|
@@ -128,38 +141,47 @@ def run_ocr(uploaded_file):
|
|
| 128 |
page_md.append("<!-- FOOTER -->\n" + ftr)
|
| 129 |
page_summary.append("π’ FOOTER: " + ftr[:100])
|
| 130 |
|
| 131 |
-
#
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
|
| 155 |
all_markdown.append("\n\n".join(page_md))
|
| 156 |
all_summary.extend(page_summary)
|
| 157 |
all_summary.append("")
|
| 158 |
|
| 159 |
summary = (
|
| 160 |
-
"Total pages : " + str(len(
|
| 161 |
-
"Headers found : " + str(total_headers) + "\n"
|
| 162 |
-
"Footers found : " + str(total_footers) + "\n"
|
| 163 |
+ "β" * 40 + "\n"
|
| 164 |
+ "\n".join(all_summary)
|
| 165 |
)
|
|
@@ -171,7 +193,7 @@ def run_ocr(uploaded_file):
|
|
| 171 |
import traceback
|
| 172 |
return "Error: " + str(e) + "\n\n" + traceback.format_exc(), "Failed."
|
| 173 |
|
| 174 |
-
# ββ STEP
|
| 175 |
with gr.Blocks(title="GLM-OCR β MaaS (Header & Footer)") as demo:
|
| 176 |
gr.Markdown("""
|
| 177 |
# π GLM-OCR β Zhipu MaaS
|
|
@@ -196,4 +218,4 @@ with gr.Blocks(title="GLM-OCR β MaaS (Header & Footer)") as demo:
|
|
| 196 |
run_btn.click(fn=run_ocr, inputs=file_input,
|
| 197 |
outputs=[markdown_out, regions_out])
|
| 198 |
|
| 199 |
-
demo.launch()
|
|
|
|
| 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")
|
|
|
|
| 12 |
with open(config_path, "r") as f:
|
| 13 |
config = yaml.safe_load(f)
|
| 14 |
|
| 15 |
+
config["pipeline"]["maas"]["enabled"] = True
|
| 16 |
+
config["pipeline"]["maas"]["api_key"] = "4570c28bdea5493c9efae9dae68edc66.sGbA9DLlcX1GlvqV"
|
| 17 |
|
| 18 |
config["pipeline"]["result_formatter"]["abandon"] = [
|
| 19 |
"number", "footnote", "aside_text",
|
|
|
|
| 49 |
ABANDON = set(config["pipeline"]["result_formatter"]["abandon"])
|
| 50 |
|
| 51 |
# ββ STEP 3: Extract header/footer from PDF text layer βββββββββ
|
| 52 |
+
# The MaaS API only returns 'text' and 'table' labels.
|
| 53 |
+
# Headers and footers are extracted directly from the PDF using PyMuPDF.
|
|
|
|
| 54 |
def extract_pdf_headers(path):
|
| 55 |
import fitz
|
| 56 |
page_headers = []
|
|
|
|
| 58 |
for page in doc:
|
| 59 |
page_rect = page.rect
|
| 60 |
page_height = page_rect.height
|
|
|
|
| 61 |
header_rect = fitz.Rect(0, 0, page_rect.width, page_height * 0.12)
|
|
|
|
| 62 |
footer_rect = fitz.Rect(0, page_height * 0.88, page_rect.width, page_height)
|
| 63 |
header_text = page.get_text(clip=header_rect).strip()
|
| 64 |
footer_text = page.get_text(clip=footer_rect).strip()
|
|
|
|
| 66 |
doc.close()
|
| 67 |
return page_headers
|
| 68 |
|
| 69 |
+
# ββ STEP 4: Parse one page result into regions list βββββββββββ
|
| 70 |
+
# result from parse() is a LIST of PipelineResult objects (one per page)
|
| 71 |
+
# Each PipelineResult has:
|
| 72 |
+
# .json_result β list of region dicts with 'label' and 'content'
|
| 73 |
+
# .markdown_result β plain markdown string
|
| 74 |
+
def get_page_regions(page_result):
|
| 75 |
+
# Try json_result first (structured regions)
|
| 76 |
+
if hasattr(page_result, "json_result"):
|
| 77 |
+
jr = page_result.json_result
|
| 78 |
+
if isinstance(jr, list) and len(jr) > 0:
|
| 79 |
+
# json_result is a list of lists (one list per page image)
|
| 80 |
+
# since we pass one image per call, take index 0
|
| 81 |
+
regions = jr[0] if isinstance(jr[0], list) else jr
|
| 82 |
+
if isinstance(regions, list):
|
| 83 |
+
return regions, "json"
|
| 84 |
+
# Fallback to markdown_result
|
| 85 |
+
if hasattr(page_result, "markdown_result"):
|
| 86 |
+
md = page_result.markdown_result
|
| 87 |
+
if md and isinstance(md, str) and md.strip():
|
| 88 |
+
return md.strip(), "raw"
|
| 89 |
+
return [], "empty"
|
| 90 |
+
|
| 91 |
+
# ββ STEP 5: Main OCR function βββββββββββββββββββββββββββββββββ
|
| 92 |
def run_ocr(uploaded_file):
|
| 93 |
if uploaded_file is None:
|
| 94 |
return "Please upload a file.", "No regions detected."
|
|
|
|
| 98 |
|
| 99 |
path = uploaded_file.name if hasattr(uploaded_file, "name") else str(uploaded_file)
|
| 100 |
|
|
|
|
| 101 |
if path.lower().endswith(".pdf"):
|
| 102 |
import fitz
|
| 103 |
pdf_headers = extract_pdf_headers(path)
|
|
|
|
| 109 |
pix.save(img_path)
|
| 110 |
page_images.append(img_path)
|
| 111 |
doc.close()
|
| 112 |
+
# parse() returns a LIST β one PipelineResult per page
|
| 113 |
+
results = parse(page_images)
|
| 114 |
+
if not isinstance(results, list):
|
| 115 |
+
results = [results]
|
| 116 |
else:
|
| 117 |
pdf_headers = []
|
| 118 |
+
results = parse(path)
|
| 119 |
+
if not isinstance(results, list):
|
| 120 |
+
results = [results]
|
|
|
|
|
|
|
|
|
|
| 121 |
|
| 122 |
total_headers = 0
|
| 123 |
total_footers = 0
|
| 124 |
all_markdown = []
|
| 125 |
all_summary = []
|
| 126 |
|
| 127 |
+
for page_num, page_result in enumerate(results):
|
|
|
|
|
|
|
|
|
|
| 128 |
page_md = []
|
| 129 |
+
page_summary = [f"ββ PAGE {page_num + 1} of {len(results)} ββ"]
|
| 130 |
|
| 131 |
# Inject header/footer from PDF text layer
|
|
|
|
| 132 |
if pdf_headers and page_num < len(pdf_headers):
|
| 133 |
hdr = pdf_headers[page_num]["header"]
|
| 134 |
ftr = pdf_headers[page_num]["footer"]
|
|
|
|
| 141 |
page_md.append("<!-- FOOTER -->\n" + ftr)
|
| 142 |
page_summary.append("π’ FOOTER: " + ftr[:100])
|
| 143 |
|
| 144 |
+
# Get regions from this page result
|
| 145 |
+
data, dtype = get_page_regions(page_result)
|
| 146 |
+
|
| 147 |
+
if dtype == "json":
|
| 148 |
+
for region in data:
|
| 149 |
+
if not isinstance(region, dict):
|
| 150 |
+
continue
|
| 151 |
+
label = region.get("label", "text")
|
| 152 |
+
content = str(region.get("content", ""))
|
| 153 |
+
|
| 154 |
+
if label in ABANDON:
|
| 155 |
+
continue
|
| 156 |
+
|
| 157 |
+
if label == "header":
|
| 158 |
+
total_headers += 1
|
| 159 |
+
page_summary.append("π΅ HEADER (API): " + content[:100])
|
| 160 |
+
page_md.append("<!-- HEADER -->\n" + content)
|
| 161 |
+
elif label == "footer":
|
| 162 |
+
total_footers += 1
|
| 163 |
+
page_summary.append("π’ FOOTER (API): " + content[:100])
|
| 164 |
+
page_md.append("<!-- FOOTER -->\n" + content)
|
| 165 |
+
else:
|
| 166 |
+
page_summary.append("[" + label + "]: " + content[:100])
|
| 167 |
+
page_md.append(content)
|
| 168 |
+
|
| 169 |
+
elif dtype == "raw":
|
| 170 |
+
page_md.append(data)
|
| 171 |
+
page_summary.append("[markdown output]")
|
| 172 |
+
page_summary.append("Content length: " + str(len(data)) + " chars")
|
| 173 |
+
|
| 174 |
+
else:
|
| 175 |
+
page_summary.append("[empty page]")
|
| 176 |
|
| 177 |
all_markdown.append("\n\n".join(page_md))
|
| 178 |
all_summary.extend(page_summary)
|
| 179 |
all_summary.append("")
|
| 180 |
|
| 181 |
summary = (
|
| 182 |
+
"Total pages : " + str(len(results)) + "\n"
|
| 183 |
+
+ "Headers found : " + str(total_headers) + "\n"
|
| 184 |
+
+ "Footers found : " + str(total_footers) + "\n"
|
| 185 |
+ "β" * 40 + "\n"
|
| 186 |
+ "\n".join(all_summary)
|
| 187 |
)
|
|
|
|
| 193 |
import traceback
|
| 194 |
return "Error: " + str(e) + "\n\n" + traceback.format_exc(), "Failed."
|
| 195 |
|
| 196 |
+
# ββ STEP 6: Gradio UI βββββββββββββββββββββββββββββββββββββββββ
|
| 197 |
with gr.Blocks(title="GLM-OCR β MaaS (Header & Footer)") as demo:
|
| 198 |
gr.Markdown("""
|
| 199 |
# π GLM-OCR β Zhipu MaaS
|
|
|
|
| 218 |
run_btn.click(fn=run_ocr, inputs=file_input,
|
| 219 |
outputs=[markdown_out, regions_out])
|
| 220 |
|
| 221 |
+
demo.launch()
|