Spaces:
Running on Zero
Running on Zero
| import gradio as gr | |
| import spaces | |
| import torch | |
| from PIL import Image | |
| from transformers import AutoModelForCausalLM, AutoProcessor | |
| from upsampler_theme import UPSAMPLER_THEME, UPSAMPLER_CSS, footer_html, header_html | |
| MODEL_ID = "PaddlePaddle/PaddleOCR-VL" | |
| # Pinned to the last transformers-4.x-compatible revision: the repo's current | |
| # code straddles the v5 API break (v5 create_causal_mask naming with v4 rope | |
| # tables) and imports on no released transformers version. | |
| MODEL_REV = "7faba727a1c11ec07247fd41a52868ed966c7cb3" | |
| PROMPTS = { | |
| "Text (OCR)": "OCR:", | |
| "Table": "Table Recognition:", | |
| "Formula": "Formula Recognition:", | |
| "Chart": "Chart Recognition:", | |
| } | |
| model = ( | |
| AutoModelForCausalLM.from_pretrained( | |
| MODEL_ID, revision=MODEL_REV, trust_remote_code=True, torch_dtype=torch.bfloat16 | |
| ) | |
| .to("cuda") | |
| .eval() | |
| ) | |
| processor = AutoProcessor.from_pretrained(MODEL_ID, revision=MODEL_REV, trust_remote_code=True) | |
| def get_duration(image, task, progress=None): | |
| # 0.9B model: a page is well under 30s; scale a little with input size and | |
| # never over-request (anonymous quota pre-checks the requested duration). | |
| if image is None: | |
| return 10 | |
| mp = (image.width * image.height) / 1_000_000 | |
| return min(60, int(20 + 10 * mp)) | |
| def extract_text(image, task, progress=gr.Progress(track_tqdm=True)): | |
| if image is None: | |
| raise gr.Error("Please upload an image first.") | |
| image = image.convert("RGB") | |
| # Bound the longest side; the NaViT encoder handles native ratios, and | |
| # very large scans only slow decoding without helping accuracy. | |
| if max(image.size) > 2048: | |
| scale = 2048 / max(image.size) | |
| image = image.resize( | |
| (int(image.width * scale), int(image.height * scale)), Image.LANCZOS | |
| ) | |
| messages = [ | |
| { | |
| "role": "user", | |
| "content": [ | |
| {"type": "image", "image": image}, | |
| {"type": "text", "text": PROMPTS.get(task, "OCR:")}, | |
| ], | |
| } | |
| ] | |
| inputs = processor.apply_chat_template( | |
| messages, | |
| tokenize=True, | |
| add_generation_prompt=True, | |
| return_dict=True, | |
| return_tensors="pt", | |
| ).to("cuda") | |
| with torch.inference_mode(): | |
| outputs = model.generate(**inputs, max_new_tokens=2048, do_sample=False) | |
| generated = outputs[:, inputs["input_ids"].shape[1] :] | |
| text = processor.batch_decode(generated, skip_special_tokens=True)[0] | |
| return text.strip() | |
| with gr.Blocks(theme=UPSAMPLER_THEME, css=UPSAMPLER_CSS) as demo: | |
| gr.HTML( | |
| header_html( | |
| "PaddleOCR-VL: Image to Text", | |
| "Extract text, tables, formulas, and chart data from any image", | |
| ) | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| input_image = gr.Image(type="pil", label="Image") | |
| task = gr.Dropdown( | |
| choices=list(PROMPTS.keys()), | |
| value="Text (OCR)", | |
| label="What to extract", | |
| ) | |
| run = gr.Button("Extract Text", variant="primary") | |
| with gr.Column(scale=1): | |
| output = gr.Textbox( | |
| label="Extracted text", | |
| lines=18, | |
| show_copy_button=True, | |
| ) | |
| run.click(extract_text, inputs=[input_image, task], outputs=output, api_name="extract_text") | |
| gr.HTML( | |
| footer_html( | |
| "PaddleOCR-VL is a 0.9B vision-language OCR model by PaddlePaddle that " | |
| "converts images to text in 109 languages, including handwriting, and " | |
| "reads tables, mathematical formulas, and charts from photos, scans, and " | |
| "screenshots.", | |
| "https://upsampler.com/free-image-to-text-no-signup", | |
| "free image to text converter", | |
| ) | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch(ssr_mode=False) | |