Spaces:
Sleeping
Sleeping
Update app.py
Browse files1. MaaS 400 on header/footer crops
2. Single shared parser (fewer asyncio issues)
3. Asyncio BaseEventLoop.__del__ message
app.py
CHANGED
|
@@ -17,6 +17,22 @@ FORMATTER_PATH = os.path.join(GLMOCR_BASE, "postprocess", "result_formatter.py")
|
|
| 17 |
# When MaaS is enabled, the cloud API ignores local layout config and does not return
|
| 18 |
# header/footer regions. We always run client-side OCR on top/bottom bands as fallback.
|
| 19 |
DEFAULT_ZONE_FRAC = float(os.environ.get("GLMOCR_DEFAULT_ZONE_FRAC", "0.12"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
# ---------------------------------------------------------------------------
|
| 22 |
# 1. Config: set MaaS and optionally include headers/footers for non-MaaS
|
|
@@ -102,9 +118,9 @@ def extract_zone_text_pdf(pdf_path, page_num, y_start_frac, y_end_frac):
|
|
| 102 |
|
| 103 |
|
| 104 |
def ocr_zone(image_path, y_start_frac, y_end_frac):
|
|
|
|
| 105 |
try:
|
| 106 |
from PIL import Image
|
| 107 |
-
from glmocr import parse
|
| 108 |
img = Image.open(image_path).convert("RGB")
|
| 109 |
w, h = img.size
|
| 110 |
y0 = max(0, int(h * y_start_frac))
|
|
@@ -112,11 +128,15 @@ def ocr_zone(image_path, y_start_frac, y_end_frac):
|
|
| 112 |
if y1 <= y0:
|
| 113 |
return ""
|
| 114 |
crop = img.crop((0, y0, w, y1))
|
| 115 |
-
|
|
|
|
|
|
|
|
|
|
| 116 |
os.close(fd)
|
| 117 |
-
crop.save(path)
|
| 118 |
try:
|
| 119 |
-
|
|
|
|
|
|
|
| 120 |
if not isinstance(out, list):
|
| 121 |
out = [out]
|
| 122 |
if out and getattr(out[0], "markdown_result", None):
|
|
@@ -153,11 +173,11 @@ def run_ocr(uploaded_file):
|
|
| 153 |
if uploaded_file is None:
|
| 154 |
return "Please upload a file."
|
| 155 |
try:
|
| 156 |
-
from glmocr import parse
|
| 157 |
import pymupdf as fitz
|
| 158 |
|
| 159 |
path = uploaded_file.name if hasattr(uploaded_file, "name") else str(uploaded_file)
|
| 160 |
is_pdf = path.lower().endswith(".pdf")
|
|
|
|
| 161 |
|
| 162 |
if is_pdf:
|
| 163 |
doc = fitz.open(path)
|
|
@@ -168,10 +188,10 @@ def run_ocr(uploaded_file):
|
|
| 168 |
pix.save(img_path)
|
| 169 |
page_images.append(img_path)
|
| 170 |
doc.close()
|
| 171 |
-
results = parse(page_images)
|
| 172 |
else:
|
| 173 |
page_images = [path]
|
| 174 |
-
results = parse(path)
|
| 175 |
|
| 176 |
if not isinstance(results, list):
|
| 177 |
results = [results]
|
|
|
|
| 17 |
# When MaaS is enabled, the cloud API ignores local layout config and does not return
|
| 18 |
# header/footer regions. We always run client-side OCR on top/bottom bands as fallback.
|
| 19 |
DEFAULT_ZONE_FRAC = float(os.environ.get("GLMOCR_DEFAULT_ZONE_FRAC", "0.12"))
|
| 20 |
+
# MaaS rejects very small images (400). Only send crops that meet minimum dimensions.
|
| 21 |
+
MIN_CROP_HEIGHT = int(os.environ.get("GLMOCR_MIN_CROP_HEIGHT", "112"))
|
| 22 |
+
MIN_CROP_PIXELS = int(os.environ.get("GLMOCR_MIN_CROP_PIXELS", "12544")) # 112*112
|
| 23 |
+
|
| 24 |
+
# Single shared parser to avoid "GLM-OCR initialized" per request and asyncio cleanup issues.
|
| 25 |
+
_parser = None
|
| 26 |
+
|
| 27 |
+
def get_parser():
|
| 28 |
+
global _parser
|
| 29 |
+
if _parser is None:
|
| 30 |
+
from glmocr import GlmOcr
|
| 31 |
+
_parser = GlmOcr(
|
| 32 |
+
api_key=os.environ.get("GLMOCR_API_KEY", "4570c28bdea5493c9efae9dae68edc66.sGbA9DLlcX1GlvqV"),
|
| 33 |
+
mode="maas",
|
| 34 |
+
)
|
| 35 |
+
return _parser
|
| 36 |
|
| 37 |
# ---------------------------------------------------------------------------
|
| 38 |
# 1. Config: set MaaS and optionally include headers/footers for non-MaaS
|
|
|
|
| 118 |
|
| 119 |
|
| 120 |
def ocr_zone(image_path, y_start_frac, y_end_frac):
|
| 121 |
+
"""Run OCR on a horizontal band of the image. Skips MaaS if crop is too small (API returns 400)."""
|
| 122 |
try:
|
| 123 |
from PIL import Image
|
|
|
|
| 124 |
img = Image.open(image_path).convert("RGB")
|
| 125 |
w, h = img.size
|
| 126 |
y0 = max(0, int(h * y_start_frac))
|
|
|
|
| 128 |
if y1 <= y0:
|
| 129 |
return ""
|
| 130 |
crop = img.crop((0, y0, w, y1))
|
| 131 |
+
cw, ch = crop.size
|
| 132 |
+
if ch < MIN_CROP_HEIGHT or (cw * ch) < MIN_CROP_PIXELS:
|
| 133 |
+
return "" # MaaS rejects very small images with 400
|
| 134 |
+
fd, path = tempfile.mkstemp(suffix=".jpg")
|
| 135 |
os.close(fd)
|
|
|
|
| 136 |
try:
|
| 137 |
+
crop.save(path, "JPEG", quality=92)
|
| 138 |
+
parser = get_parser()
|
| 139 |
+
out = parser.parse(path)
|
| 140 |
if not isinstance(out, list):
|
| 141 |
out = [out]
|
| 142 |
if out and getattr(out[0], "markdown_result", None):
|
|
|
|
| 173 |
if uploaded_file is None:
|
| 174 |
return "Please upload a file."
|
| 175 |
try:
|
|
|
|
| 176 |
import pymupdf as fitz
|
| 177 |
|
| 178 |
path = uploaded_file.name if hasattr(uploaded_file, "name") else str(uploaded_file)
|
| 179 |
is_pdf = path.lower().endswith(".pdf")
|
| 180 |
+
parser = get_parser()
|
| 181 |
|
| 182 |
if is_pdf:
|
| 183 |
doc = fitz.open(path)
|
|
|
|
| 188 |
pix.save(img_path)
|
| 189 |
page_images.append(img_path)
|
| 190 |
doc.close()
|
| 191 |
+
results = parser.parse(page_images)
|
| 192 |
else:
|
| 193 |
page_images = [path]
|
| 194 |
+
results = parser.parse(path)
|
| 195 |
|
| 196 |
if not isinstance(results, list):
|
| 197 |
results = [results]
|