Downloads · 30 days
10
4% of all-time downloads
mohamedashraff22/arabic-menu-ocr-v2
arabic-menu-ocr-v2 is a image-to-text model from mohamedashraff22. Use it when you need a caption or text from an image.
This is a specialized Vision-Language Model (VLM) fine-tuned exclusively for extracting food/drink items and prices from Arabic restaurant menus. It processes raw menu images and outputs a highly structured, clean JSO…
Downloads · 30 days
10
4% of all-time downloads
All-time downloads
250
Public
Parameters
3.8B
10 GB on disk
Likes
1
Public
Click a slice to open those files.
.safetensors8.5 GB · 82%
From the Hugging Face model README
This is a specialized Vision-Language Model (VLM) fine-tuned exclusively for extracting food/drink items and prices from Arabic restaurant menus. It processes raw menu images and outputs a highly structured, clean JSON array, making it perfect for automated data entry, food delivery apps, and digital menu generation.
This model is a fully merged version of the powerful Qwen2.5-VL-3B-Instruct, fine-tuned using the LLaMA-Factory framework.
Because this model uses the Qwen 2.5 architecture, you must install the official Qwen utilities alongside transformers to properly process image inputs.
pip install -U torch torchvision transformers accelerate optimum vllm
pip install qwen-vl-utils[decord]==0.0.8
The prompt must match the exact formatting used during training. Use the standard pipeline below for accurate generation.
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info
import torch
model_id = "mohamedashraff22/arabic-menu-ocr-v2"
# 1. Load Model
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
model_id,
torch_dtype=torch.bfloat16,
device_map="auto",
trust_remote_code=True
).eval()
processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
# 2. Strict Training Prompt
prompt = """Extract every food or drink item and its price from this menu image.
Keep item names and prices exactly as written in the image.
If an item has multiple sizes, list each size as a separate entry.
Only include items that have a visible price. Skip anything without a price.
Return a JSON object with one key "items" containing an array. Each item has "name" (string) and "price" (string)."""
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": "file:///path/to/your/menu_image.jpg"},
{"type": "text", "text": prompt}
]
}
]
# 3. Process & Format
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
image_inputs, video_inputs = process_vision_info(messages)
inputs = processor(
text=[text],
images=image_inputs,
videos=video_inputs,
padding=True,
return_tensors="pt"
).to(model.device)
# 4. Generate Output
with torch.inference_mode():
generated_ids = model.generate(
**inputs,
max_new_tokens=2048,
do_sample=False,
repetition_penalty=1.15 # Recommended to prevent looping on dense menus
)
generated_ids_trimmed = [out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)]
output = processor.batch_decode(generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
print(output)
For production environments and bulk processing, we highly recommend using vLLM to utilize PagedAttention.
from transformers import AutoProcessor
from vllm import LLM, SamplingParams
model_id = "mohamedashraff22/arabic-menu-ocr-v2"
prompt = "..." # (Use the exact same prompt string as above)
# Load Processor & Engine
processor = AutoProcessor.from_pretrained(model_id)
llm = LLM(
model=model_id,
trust_remote_code=True,
dtype="bfloat16",
max_model_len=4096,
gpu_memory_utilization=0.60
)
# Format for vLLM
vllm_messages = [{"role": "user", "content": [{"type": "image"}, {"type": "text", "text": prompt}]}]
formatted_prompt = processor.apply_chat_template(vllm_messages, add_generation_prompt=True, tokenize=False)
# Configure Sampling Settings
sampling_params = SamplingParams(
temperature=0.0,
max_tokens=5000,
repetition_penalty=1.15
)
# Run Inference
outputs = llm.generate({
"prompt": formatted_prompt,
"multi_modal_data": {"image": "file:///path/to/your/menu_image.jpg"}
}, sampling_params=sampling_params)
print(outputs[0].outputs[0].text)