Pythonista993 commited on
Commit
ff7d684
·
verified ·
1 Parent(s): d06c457

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +64 -0
app.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Qari-OCR ZeroGPU Space — Arabic page OCR for the history-textbook project.
3
+
4
+ Deploy this as a Gradio Space with ZeroGPU hardware (free on HF PRO).
5
+ It exposes an API endpoint "/ocr" that takes a page image and returns the
6
+ transcribed Arabic text. The local batch script (../batch_ocr.py) drives it
7
+ over all 120 pages.
8
+ """
9
+ import spaces
10
+ import torch
11
+ import gradio as gr
12
+ from transformers import Qwen2VLForConditionalGeneration, AutoProcessor
13
+ from qwen_vl_utils import process_vision_info
14
+
15
+ MODEL_ID = "NAMAA-Space/Qari-OCR-v0.3-VL-2B-Instruct"
16
+
17
+ # High max_pixels keeps small Arabic glyphs + tashkeel legible (OCR needs detail).
18
+ # 28 is Qwen2-VL's patch factor; 4096*28*28 ≈ 3.2M px ≈ a 300-DPI textbook page.
19
+ processor = AutoProcessor.from_pretrained(
20
+ MODEL_ID, min_pixels=256 * 28 * 28, max_pixels=4096 * 28 * 28
21
+ )
22
+ # Loaded on CPU at startup — ZeroGPU only attaches a GPU inside @spaces.GPU functions.
23
+ model = Qwen2VLForConditionalGeneration.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)
24
+
25
+ PROMPT = (
26
+ "Below is an image of one page of an Arabic school textbook. "
27
+ "Transcribe ALL the Arabic text exactly as printed, preserving line breaks, "
28
+ "headings, and right-to-left reading order. Keep diacritics (tashkeel) if present. "
29
+ "Ignore any faint diagonal draft watermark. Output only the transcribed text."
30
+ )
31
+
32
+
33
+ @spaces.GPU(duration=120)
34
+ def ocr(image):
35
+ if image is None:
36
+ return ""
37
+ model.to("cuda")
38
+ messages = [{"role": "user", "content": [
39
+ {"type": "image", "image": image},
40
+ {"type": "text", "text": PROMPT},
41
+ ]}]
42
+ text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
43
+ image_inputs, video_inputs = process_vision_info(messages)
44
+ inputs = processor(
45
+ text=[text], images=image_inputs, videos=video_inputs,
46
+ padding=True, return_tensors="pt",
47
+ ).to("cuda")
48
+ with torch.no_grad():
49
+ generated = model.generate(**inputs, max_new_tokens=4096, do_sample=False)
50
+ trimmed = [g[len(i):] for i, g in zip(inputs.input_ids, generated)]
51
+ return processor.batch_decode(
52
+ trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False
53
+ )[0]
54
+
55
+
56
+ with gr.Blocks(title="Qari-OCR — Arabic page OCR") as demo:
57
+ gr.Markdown("## Qari-OCR — Arabic textbook page OCR\nUpload a page image, or call the `/ocr` API.")
58
+ with gr.Row():
59
+ inp = gr.Image(type="pil", label="Page image")
60
+ out = gr.Textbox(label="Transcribed Arabic", lines=25, rtl=True)
61
+ gr.Button("Run OCR", variant="primary").click(ocr, inp, out, api_name="ocr")
62
+
63
+ if __name__ == "__main__":
64
+ demo.queue(max_size=16).launch()