multimodalart's picture
multimodalart HF Staff
Upload app.py with huggingface_hub
ab8cd3d verified
Raw
History Blame Contribute Delete
4.46 kB
"""PP-OCRv6 medium recognition model demo.
Upload a cropped text-line image and get recognized text with a confidence score.
PP-OCRv6_medium_rec is a 19M-parameter text recognition model from PaddlePaddle.
"""
import json
import os
import tempfile
# On ZeroGPU, `import spaces` must come before any torch/CUDA import.
# PaddlePaddle doesn't use torch, but the ZeroGPU runtime still requires
# this import and a @spaces.GPU decorator on the inference function.
import spaces
import gradio as gr
from paddleocr import TextRecognition
# Load model at module scope — PaddlePaddle runs on CPU natively.
MODEL_NAME = "PP-OCRv6_medium_rec"
rec_model = TextRecognition(model_name=MODEL_NAME)
@spaces.GPU(duration=30)
def recognize_text(image):
"""Recognize text from a cropped text-line image.
Args:
image: A file path to an image containing a single line of text.
Returns:
A tuple of (recognized_text, confidence_score, raw_json).
"""
if image is None:
return "No image provided", 0.0, ""
img_path = image if isinstance(image, str) else None
if img_path is None:
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f:
image.save(f, format="PNG")
img_path = f.name
try:
output = rec_model.predict(input=img_path, batch_size=1)
results = []
for res in output:
raw_json = getattr(res, "json", None)
if isinstance(raw_json, dict):
data = raw_json
elif isinstance(raw_json, str):
data = json.loads(raw_json)
elif hasattr(res, "to_dict"):
data = res.to_dict()
else:
data = {
"rec_text": getattr(res, "rec_text", str(res)),
"rec_score": getattr(res, "rec_score", 0.0),
}
results.append(data)
if not results:
return "No text recognized", 0.0, ""
# Results may be nested under a "res" key
first = results[0]
if "res" in first:
first = first["res"]
text = first.get("rec_text", "")
score = first.get("rec_score", 0.0)
raw = json.dumps(results, ensure_ascii=False, indent=2)
return text, float(score), raw
except Exception as e:
return f"Error: {e}", 0.0, ""
finally:
if not isinstance(image, str) and os.path.exists(img_path):
os.unlink(img_path)
# --- UI ---
CSS = """
#col-container { max-width: 900px; margin: 0 auto; }
.dark .gradio-container { color: var(--body-text-color); }
"""
with gr.Blocks() as demo:
with gr.Column(elem_id="col-container"):
gr.Markdown("# PP-OCRv6 Medium Text Recognition")
gr.Markdown(
"Upload a cropped image of a single text line to recognize text. "
"This is the [PP-OCRv6_medium_rec](https://huggingface.co/PaddlePaddle/PP-OCRv6_medium_rec) "
"model — a 19M-parameter OCR recognition model from PaddlePaddle that "
"supports 50 languages."
)
with gr.Row():
with gr.Column(scale=1):
input_image = gr.Image(
label="Text-line image",
type="filepath",
height=200,
)
run_btn = gr.Button("Recognize Text", variant="primary")
with gr.Column(scale=1):
text_output = gr.Textbox(label="Recognized text", interactive=False)
score_output = gr.Number(label="Confidence score", precision=4, interactive=False)
raw_output = gr.Code(label="Raw JSON output", language="json")
gr.Examples(
examples=[
["examples/sample_readme.jpeg"],
["examples/sample_text.png"],
["examples/sample_text2.png"],
["examples/sample_text3.png"],
["examples/sample_text4.png"],
],
inputs=input_image,
outputs=[text_output, score_output, raw_output],
fn=recognize_text,
cache_examples=True,
cache_mode="lazy",
)
run_btn.click(
fn=recognize_text,
inputs=input_image,
outputs=[text_output, score_output, raw_output],
api_name="recognize",
)
if __name__ == "__main__":
demo.launch(mcp_server=True, theme=gr.themes.Citrus(), css=CSS)