Image-Text-to-Text
Safetensors
Arabic
qwen3_5
conversational

💜 Github   |   🤗 Hugging Face   |   📚 Cookbooks  
🖥️ Demo  

🕌 Arabic-Qwen3.5-OCR-v4

Arabic-Qwen3.5-OCR-v4 is an advanced Optical Character Recognition (OCR) model, an improvement over Qwen/Qwen3.5-0.8B. This model is specifically designed for handling Arabic text, with enhanced performance for printed text. It excels in handling various text types, including handwritten, classical, and diacritical marks.

In this training, the model was given "thinking ability" at each stage of page reading and text generation. The model became better able to understand the complex context in the middle and end of a sentence, which transforms raw information from attention into a true understanding of language.

This version offers an improved methodology and significant enhancements to data generation, focusing on complex formats, low-quality document images, PDFs, photos, and diacritical marks.

🌍 Full support for Arabic scripts. 📝 Diverse Text Types: Capable of reading Handwritten, Printed, Classical, and Voweled text. ⚡ Fast Inference: Optimized for speed ~4 images/second . 🎯 High Accuracy:

CER < 5% for clear printed text. CER ~5-25% for complex handwritten text.

Datasets Used

The model was trained on a mix of synthetic and real-world data, including:

Internal Synthetic Data: Generated with extensive variations. Public Datasets and Previous Model Data: Enhanced with new samples for better robustness.

Data Augmentation & Layouts

Fonts: Over 70 Arabic fonts (e.g., Amiri, Traditional Arabic, Sakkal Majalla, Scheherazade). Degradation: Physics-based optical simulation to apply realistic scan artifacts (paper texture, ink bleed, blur, warping, ISO noise) with intensities ranging from Light to Heavy.

🧠 Understands complex page structures:

  • Poetry formatting (multi-line verse)
  • Footnotes & references
  • Marginal annotations
  • Multi-column academic layouts

Comparison: v3 vs v4

Performance Metric v3 v4 Performance Delta
⏱️ Time per Image 0.31 seconds 0.25 seconds +25% Faster
🚀 Images per Second 3.23 images 4 images 20% throughput
⚡ Printed Performance 70% 90% 30% percentage points
🚀 Page per Second seconds 3.5 seconds Faster Average of 100 samples

Layout:

Single column / Multi-column Headers / Footers Page numbers Footnotes Poetry blocks Tables Marginal notes

Page Characteristics:

✅ 2-column layout detection ✅ Poetry-style split lines ✅ Footnotes at bottom ✅ Marginalia (side notes) ✅ Numbered lists ✅ Sparse English technical terms ✅ Diacritics (تشكيل)

🔮 Future Roadmap (Next Version v5)

Planned improvements for the upcoming release include:

  • 📊 Table extraction (structured OCR)
  • 🧾 Invoice & receipt parsing
  • 📚 Full document understanding (DocAI)
  • 🔤 Improving some other languages
  • ⚡ Ultra-light quantized version (<500MB)

💡 Why this model?

Unlike traditional OCR systems, this model:

  • Understands layout (not just text)
  • Handles Arabic diacritics natively
  • Works on both printed and handwritten text
  • Is optimized for real-world noisy scans

🖼️ Visualizations.

🛠️ How to use


import os
import torch
from PIL import Image
from transformers import AutoProcessor, Qwen3_5ForConditionalGeneration
from qwen_vl_utils import process_vision_info

# ==================== ⚙️ إعدادات الجهاز ====================
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.float16 if device == "cuda" else torch.float32

# ==================== 🔄 تحميل النموذج ====================
print("[INFO] Loading model...")
model_path = "sherif1313/Arabic-Qwen3.5-OCR-v4"  # ← غيّر لمسار نموذجك

processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True)
model = Qwen3_5ForConditionalGeneration.from_pretrained(
    model_path,
    dtype=dtype,
    device_map="auto" if device == "cuda" else None,
    trust_remote_code=True
)
model.eval()
print("[INFO] Model loaded!")

# ==================== 🔍 دالة الاستدلال (تُعرّف أولاً!) ====================
def extract_text(image_path: str, prompt: str = None) -> str:
    """استخراج النص من صورة واحدة"""
    if prompt is None:
        prompt = "اقرأ النص في هذه الصورة كاملاً من البداية إلى النهاية."
    
    image = Image.open(image_path).convert("RGB")
    
    # ضبط الأبعاد لمضاعفات 64
    w, h = image.size
    new_w = ((w + 63) // 64) * 64
    new_h = ((h + 63) // 64) * 64
    image = image.resize((new_w, new_h), Image.LANCZOS)
    
    messages = [{
        "role": "user",
        "content": [
            {"type": "image", "image": image},
            {"type": "text", "text": prompt}
        ]
    }]
    
    text_input = processor.apply_chat_template(
        messages, tokenize=False, add_generation_prompt=True
    )
    image_inputs, _ = process_vision_info(messages)
    
    inputs = processor(
        text=[text_input],
        images=image_inputs,
        padding=True,
        return_tensors="pt"
    ).to(device)
    
    with torch.no_grad():
        generated_ids = model.generate(
            **inputs,
            max_new_tokens=512,
            do_sample=False,
            repetition_penalty=1.2,
            no_repeat_ngram_size=3,
            pad_token_id=processor.tokenizer.pad_token_id,
            eos_token_id=processor.tokenizer.eos_token_id,
        )
    
    input_len = inputs.input_ids.shape[1]
    output_text = processor.batch_decode(
        generated_ids[:, input_len:],
        skip_special_tokens=True,
        clean_up_tokenization_spaces=False
    )[0]
    
    return output_text.strip()

# ==================== 🚀 نقطة الدخول (تُستدعى بعد تعريف الدالة) ====================
if __name__ == "__main__":
    # ✅ الآن يمكن استدعاء extract_text لأنها مُعرّفة أعلاه
    image_path = "/home/sheriff/Downloads/PIC.png"
    
    if os.path.exists(image_path):
        print(f"🔍 Processing: {image_path}")
        result = extract_text(image_path)
        print(f"📝 Extracted Text:\n{result}")
    else:
        print(f"❌ File not found: {image_path}")

🛠️ How to use it web

import os
import time
import torch
from PIL import Image
import gradio as gr
from transformers import AutoProcessor, Qwen3_5ForConditionalGeneration
from qwen_vl_utils import process_vision_info

# ==================== ⚙️ إعدادات الجهاز ====================
if torch.cuda.is_available():
    device = "cuda"
    dtype = torch.float16
    print(f"✅ Using GPU: {torch.cuda.get_device_name(0)}")
elif torch.backends.mps.is_available():
    device = "mps"
    dtype = torch.float16
    print("✅ Using Apple Silicon (MPS)")
else:
    device = "cpu"
    dtype = torch.float32
    print("⚠️ Using CPU (slower inference)")

print(f"[INFO] Device: {device} | Dtype: {dtype}")

# ==================== 🔄 تحميل النموذج ====================
def load_model():
    """تحميل النموذج والمعالج مع إدارة الذاكرة"""
    model_path = os.getenv("MODEL_PATH", "sherif1313/Arabic-Qwen3.5-OCR-v4")
    
    print(f"[INFO] Loading model from: {model_path}")
    
    processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True)
    
    model = Qwen3_5ForConditionalGeneration.from_pretrained(
        model_path,
        dtype=dtype,
        device_map="auto" if device == "cuda" else None,
        trust_remote_code=True,
        low_cpu_mem_usage=True,
    )
    
    model.eval()
    print("[INFO] Model loaded successfully!")
    return model, processor

# تحميل عالمي (يتم مرة واحدة عند بدء التطبيق)
try:
    model, processor = load_model()
except Exception as e:
    print(f"[ERROR] Failed to load model: {e}")
    model = None
    processor = None

# ==================== 🧹 دوال مساعدة ====================
def prepare_image(image: Image.Image, max_size: int = 768) -> Image.Image:
    """تحضير الصورة: ضغط + ضبط الأبعاد لمضاعفات 64"""
    if max(image.size) > max_size:
        image.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
    
    w, h = image.size
    new_w = ((w + 63) // 64) * 64
    new_h = ((h + 63) // 64) * 64
    if (new_w, new_h) != image.size:
        image = image.resize((new_w, new_h), Image.Resampling.LANCZOS)
    
    return image

def clean_output(text: str, max_repetitions: int = 2) -> str:
    """تنظيف التكرار في المخرجات"""
    if not text:
        return text
    
    import re
    text = re.sub(r'(.)\1{4,}', r'\1\1\1', text)
    
    lines = text.strip().split('\n')
    cleaned = []
    seen = {}
    for line in lines:
        line_stripped = line.strip()
        if not line_stripped:
            continue
        count = seen.get(line_stripped, 0) + 1
        if count <= max_repetitions:
            cleaned.append(line)
        seen[line_stripped] = count
    
    return '\n'.join(cleaned).strip()

# ==================== 🔍 دالة الاستدلال ====================
def extract_text(image, prompt: str = None) -> tuple[str, str]:
    """استخراج النص من الصورة"""
    if model is None or processor is None:
        return "❌ Error: Model not loaded", "0.00"
    
    if image is None:
        return "⚠️ Please upload an image", "0.00"
    
    start_time = time.time()
    
    try:
        if isinstance(image, str):
            image_pil = Image.open(image).convert("RGB")
        elif isinstance(image, Image.Image):
            image_pil = image.convert("RGB")
        else:
            image_pil = Image.fromarray(image).convert("RGB")
        
        image_pil = prepare_image(image_pil)
        
        if prompt is None or not prompt.strip():
            prompt = "اقرأ النص في هذه الصورة كاملاً من البداية إلى النهاية."
        
        messages = [{
            "role": "user",
            "content": [
                {"type": "image", "image": image_pil},
                {"type": "text", "text": prompt}
            ]
        }]
        
        text_input = processor.apply_chat_template(
            messages, tokenize=False, add_generation_prompt=True
        )
        image_inputs, _ = process_vision_info(messages)
        
        inputs = processor(
            text=[text_input],
            images=image_inputs,
            padding=True,
            return_tensors="pt"
        ).to(device)
        
        with torch.inference_mode():
            generated_ids = model.generate(
                **inputs,
                max_new_tokens=512,
                do_sample=False,
                temperature=1.0,
                repetition_penalty=1.2,
                no_repeat_ngram_size=3,
                pad_token_id=processor.tokenizer.pad_token_id,
                eos_token_id=processor.tokenizer.eos_token_id,
            )
        
        input_len = inputs.input_ids.shape[1]
        output_text = processor.batch_decode(
            generated_ids[:, input_len:],
            skip_special_tokens=True,
            clean_up_tokenization_spaces=False
        )[0]
        
        output_text = clean_output(output_text.strip())
        
        elapsed = time.time() - start_time
        
        return output_text, f"{elapsed:.2f} seconds"
        
    except torch.cuda.OutOfMemoryError:
        torch.cuda.empty_cache()
        return "❌ Out of Memory. Try a smaller image.", "0.00"
    except Exception as e:
        print(f"[ERROR] {e}")
        import traceback
        traceback.print_exc()
        return f"❌ Error: {str(e)}", "0.00"

# ==================== 🎨 واجهة Gradio ====================
def create_interface():
    """إنشاء واجهة المستخدم"""
    
    with gr.Blocks(
        title="Arabic OCR - Qwen3.5-0.8B",
        theme=gr.themes.Soft(),
        css="""
        .header { text-align: center; margin-bottom: 20px; }
        .output-box { min-height: 200px; }
        """
    ) as demo:
        
        gr.Markdown("""
        # 📝 Arabic Handwritten & Printed OCR V4
        ### Powered by Qwen3.5-0.8B
        
        Upload an image containing Arabic text, and the model will extract it.
        
        ✨ **Features:**
        - 🌍 Arabic support
        - ✍️ Handwritten & printed text
        - 🔤 Preserves diacritics (تشكيل)
        - ⚡ Full precision (no quantization)
        """, elem_classes="header")
        
        with gr.Row():
            with gr.Column(scale=1):
                # ✅ تعريف المكونات أولاً
                image_input = gr.Image(
                    label="📷 Upload Image",
                    type="pil",
                    height=300,
                    sources=["upload", "clipboard"]
                )
                
                prompt_input = gr.Textbox(
                    label="📝 Custom Prompt (Optional)",
                    placeholder="اقرأ النص في هذه الصورة...",
                    value="اقرأ النص في هذه الصورة كاملاً من البداية إلى النهاية.",
                    lines=2
                )
                
                submit_btn = gr.Button(
                    "🔍 Extract Text",
                    variant="primary",
                    size="lg"
                )
                
                # ✅ الأمثلة داخل الدالة - مسارات محلية فقط (لا روابط خارجية)
                # لإضافة أمثلة، انسخ الصور إلى مجلد 'examples/' في مستودع الـ Space
                # ثم استخدم: examples=[["examples/sample1.jpg"], ...]
                gr.Examples(
                    label="📋 Examples (Optional)",
                    examples=[
],  # اتركها فارغة أو استخدم مسارات محلية
                    inputs=[image_input],  # ✅ الآن يعمل لأن image_input مُعرّف أعلاه
                    cache_examples=False
                )
                
            with gr.Column(scale=1):
                output_text = gr.Textbox(
                    label="📄 Extracted Text",
                    lines=12,
                    show_copy_button=True,
                    elem_classes="output-box"
                )
                
                time_output = gr.Textbox(
                    label="⏱️ Inference Time",
                    interactive=False,
                    value="-"
                )
                
                clear_btn = gr.Button("🗑️ Clear", variant="secondary")
        
        # ✅ ربط الأحداث (بعد تعريف جميع المكونات)
        submit_btn.click(
            fn=extract_text,
            inputs=[image_input, prompt_input],
            outputs=[output_text, time_output]
        )
        
        clear_btn.click(
            fn=lambda: (None, "", "-"),
            inputs=[],
            outputs=[image_input, prompt_input, time_output]
        )
        
        gr.Markdown("""
        ### 💡 Tips for Best Results:
        1. Use clear, well-lit images
        2. Crop to the text region if possible
        3. For handwritten text, ensure good contrast
        4. Custom prompts can improve accuracy for specific formats
        """)
    
    return demo  # ✅ إرجاع الـ demo

# ==================== 🚀 نقطة الدخول ====================
if __name__ == "__main__":
    print("[INFO] Creating Gradio interface...")
    
    demo = create_interface()
    
    # إعدادات التشغيل لـ Spaces
    demo.launch(
        server_name="0.0.0.0",
        server_port=int(os.getenv("PORT", 7860)),
        share=False,
        debug=os.getenv("DEBUG", "false").lower() == "true",
        show_error=True
    )

🛠️ How to use it PDF

pip install pdf2image poppler-utils pymupdf

python pdf.py --pdf /home/sheriff/Desktop/222.pdf --output result.txt

import os
import sys
import time
import torch
from PIL import Image
from transformers import AutoProcessor, Qwen3_5ForConditionalGeneration
from qwen_vl_utils import process_vision_info
import fitz  # PyMuPDF

# ==================== ⚙️ إعدادات الجهاز ====================
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32
print(f"[INFO] Using device: {DEVICE} | dtype: {DTYPE}")

# ==================== 🔄 تحميل النموذج ====================
def load_model(model_path: str):
    """تحميل النموذج والمعالج"""
    print(f"[INFO] Loading model from: {model_path}")
    
    processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True)
    
    model = Qwen3_5ForConditionalGeneration.from_pretrained(
        model_path,
        torch_dtype=DTYPE,
        device_map="auto" if DEVICE == "cuda" else None,
        trust_remote_code=True,
        low_cpu_mem_usage=True
    )
    model.eval()
    print("[INFO] ✅ Model loaded successfully!")
    return model, processor

# ==================== 🖼️ تحويل صفحة PDF إلى صورة ====================
def pdf_page_to_image(pdf_path: str, page_num: int, dpi: int = 150) -> Image.Image:
    """تحويل صفحة من ملف PDF إلى صورة PIL"""
    doc = fitz.open(pdf_path)
    page = doc[page_num]
    
    # إعداد مصفوفة التكبير للدقة المطلوبة
    zoom = dpi / 72  # 72 DPI هو الافتراضي في PDF
    mat = fitz.Matrix(zoom, zoom)
    
    # الحصول على الصورة
    pix = page.get_pixmap(matrix=mat)
    img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
    
    doc.close()
    return img

# ==================== 🧹 تنظيف المخرجات من التكرار ====================
def clean_output(text: str, max_repetitions: int = 2) -> str:
    """إزالة التكرار المفرط في النص المستخرج"""
    import re
    if not text:
        return text
    
    # إزالة تكرار الحروف المفرط
    text = re.sub(r'(.)\1{4,}', r'\1\1\1', text)
    
    # إزالة تكرار الأسطر
    lines = text.strip().split('\n')
    cleaned = []
    seen = {}
    for line in lines:
        line_stripped = line.strip()
        if not line_stripped:
            continue
        count = seen.get(line_stripped, 0) + 1
        if count <= max_repetitions:
            cleaned.append(line)
        seen[line_stripped] = count
    
    return '\n'.join(cleaned).strip()

# ==================== 🔍 استخراج نص من صورة ====================
def extract_text_from_image(model, processor, image: Image.Image, prompt: str = None) -> str:
    """استخراج النص من صورة واحدة باستخدام النموذج"""
    if prompt is None:
        prompt = "اقرأ النص في هذه الصورة كاملاً من البداية إلى النهاية."
    
    # تحضير الصورة: ضبط الأبعاد لمضاعفات 64
    w, h = image.size
    new_w = ((w + 63) // 64) * 64
    new_h = ((h + 63) // 64) * 64
    if (new_w, new_h) != (w, h):
        image = image.resize((new_w, new_h), Image.Resampling.LANCZOS)
    
    messages = [{
        "role": "user",
        "content": [
            {"type": "image", "image": image},
            {"type": "text", "text": prompt}
        ]
    }]
    
    text_input = processor.apply_chat_template(
        messages, tokenize=False, add_generation_prompt=True
    )
    image_inputs, _ = process_vision_info(messages)
    
    inputs = processor(
        text=[text_input],
        images=image_inputs,
        padding=True,
        return_tensors="pt"
    ).to(DEVICE)
    
    with torch.inference_mode():
        generated_ids = model.generate(
            **inputs,
            max_new_tokens=2048,
            do_sample=False,
            repetition_penalty=1.2,
            no_repeat_ngram_size=3,
            pad_token_id=processor.tokenizer.pad_token_id,
            eos_token_id=processor.tokenizer.eos_token_id,
        )
    
    input_len = inputs.input_ids.shape[1]
    output_text = processor.batch_decode(
        generated_ids[:, input_len:],
        skip_special_tokens=True,
        clean_up_tokenization_spaces=False
    )[0]
    
    return clean_output(output_text.strip())

# ==================== 📄 معالجة ملف PDF كامل ====================
def process_pdf(
    pdf_path: str,
    model,
    processor,
    output_path: str = None,
    start_page: int = 0,
    end_page: int = None,
    dpi: int = 150,
    prompt: str = None
) -> dict:
    """
    معالجة ملف PDF كامل واستخراج النص من كل صفحة
    
    Args:
        pdf_path: مسار ملف الـ PDF
        model: النموذج المُحمّل
        processor: معالج النموذج
        output_path: مسار ملف المخرجات (اختياري)
        start_page: رقم الصفحة الأولى (0-مفهرس)
        end_page: رقم الصفحة الأخيرة (None = حتى النهاية)
        dpi: دقة تحويل الصفحة إلى صورة
        prompt: البرومبت المستخدم للاستخراج
    
    Returns:
        dict: {
            'total_pages': int,
            'processed_pages': int,
            'results': [ { 'page': int, 'text': str, 'time': float }, ... ],
            'total_time': float
        }
    """
    import fitz
    
    doc = fitz.open(pdf_path)
    total_pages = len(doc)
    
    if end_page is None:
        end_page = total_pages
    
    results = []
    total_start = time.time()
    
    print(f"[INFO] Processing: {pdf_path}")
    print(f"[INFO] Pages: {start_page+1} to {end_page} of {total_pages}")
    
    for page_num in range(start_page, min(end_page, total_pages)):
        page_start = time.time()
        
        try:
            # تحويل الصفحة إلى صورة
            image = pdf_page_to_image(pdf_path, page_num, dpi=dpi)
            
            # استخراج النص
            text = extract_text_from_image(model, processor, image, prompt)
            
            page_time = time.time() - page_start
            
            results.append({
                'page': page_num + 1,  # صفحات مفهرسة من 1
                'text': text,
                'time': round(page_time, 2),
                'image_size': image.size
            })
            
            print(f"[✓] Page {page_num+1}/{total_pages} | Time: {page_time:.2f}s | Chars: {len(text)}")
            
        except Exception as e:
            print(f"[✗] Page {page_num+1} Error: {str(e)}")
            results.append({
                'page': page_num + 1,
                'text': f"[ERROR: {str(e)}]",
                'time': 0,
                'error': True
            })
    
    total_time = time.time() - total_start
    doc.close()
    
    # حفظ النتائج في ملف نصي إذا طُلب
    if output_path:
        save_results_to_file(results, output_path)
        print(f"[INFO] Results saved to: {output_path}")
    
    return {
        'total_pages': total_pages,
        'processed_pages': len(results),
        'results': results,
        'total_time': round(total_time, 2),
        'avg_time_per_page': round(total_time / len(results), 2) if results else 0
    }

# ==================== 💾 حفظ النتائج ====================
def save_results_to_file(results: list, output_path: str, format: str = 'txt'):
    """حفظ نتائج الاستخراج في ملف"""
    os.makedirs(os.path.dirname(output_path) or '.', exist_ok=True)
    
    if format == 'txt':
        with open(output_path, 'w', encoding='utf-8') as f:
            for item in results:
                f.write(f"\n{'='*60}\n")
                f.write(f"📄 الصفحة {item['page']}\n")
                f.write(f"⏱️ الوقت: {item['time']} ثانية\n")
                f.write(f"{'='*60}\n\n")
                f.write(item['text'])
                f.write("\n\n")
    
    elif format == 'json':
        import json
        with open(output_path, 'w', encoding='utf-8') as f:
            json.dump(results, f, ensure_ascii=False, indent=2)
    
    elif format == 'md':
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write("# 📄 نتائج استخراج النص من PDF\n\n")
            for item in results:
                f.write(f"## الصفحة {item['page']}\n")
                f.write(f"- ⏱️ الوقت: {item['time']} ثانية\n")
                f.write(f"- 📏 حجم الصورة: {item['image_size']}\n\n")
                f.write("```text\n")
                f.write(item['text'])
                f.write("\n```\n\n")

# ==================== 🚀 نقطة الدخول ====================
if __name__ == "__main__":
    import argparse
    
    parser = argparse.ArgumentParser(description="📄 Arabic OCR for PDF using Qwen3.5-0.8B")
    parser.add_argument('--pdf', type=str, required=True, help='مسار ملف الـ PDF')
    parser.add_argument('--model', type=str, default='sherif1313/Arabic-Qwen3.5-OCR-v4', help='مسار النموذج')
    parser.add_argument('--output', type=str, default=None, help='مسار ملف المخرجات')
    parser.add_argument('--pages', type=str, default='all', help='الصفحات: all أو 1-5 أو 3')
    parser.add_argument('--dpi', type=int, default=150, help='دقة التحويل (افتراضي: 150)')
    parser.add_argument('--prompt', type=str, default=None, help='برومبت مخصص')
    parser.add_argument('--format', type=str, default='txt', choices=['txt', 'json', 'md'], help='تنسيق المخرجات')
    
    args = parser.parse_args()
    
    # تحليل نطاق الصفحات
    if args.pages == 'all':
        start_page, end_page = 0, None
    elif '-' in args.pages:
        parts = args.pages.split('-')
        start_page = int(parts[0]) - 1
        end_page = int(parts[1]) if len(parts) > 1 and parts[1] else None
    else:
        page = int(args.pages) - 1
        start_page, end_page = page, page + 1
    
    # تحميل النموذج
    model, processor = load_model(args.model)
    
    # معالجة الـ PDF
    results = process_pdf(
        pdf_path=args.pdf,
        model=model,
        processor=processor,
        output_path=args.output,
        start_page=start_page,
        end_page=end_page,
        dpi=args.dpi,
        prompt=args.prompt
    )
    
    # طباعة ملخص
    print(f"\n{'='*60}")
    print("📊 ملخص المعالجة")
    print(f"{'='*60}")
    print(f"📄 إجمالي الصفحات: {results['total_pages']}")
    print(f"✅ الصفحات المُعالَجة: {results['processed_pages']}")
    print(f"⏱️ الوقت الكلي: {results['total_time']} ثانية")
    print(f"⚡ متوسط الوقت/صفحة: {results['avg_time_per_page']} ثانية")
    print(f"{'='*60}")

📝 Citation

If you use this model, please cite it as follows:

@misc{arabic-qwen-ocr-v4, title={sherif1313/Arabic-Qwen3.5-OCR-v4}, author={Sheriff}, year={2026}, url={https://huggingface.co/sherif1313/Arabic-Qwen3.5-OCR-v4} }

Downloads last month
432
Safetensors
Model size
0.9B params
Tensor type
BF16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for sherif1313/Arabic-Qwen3.5-OCR-v4

Finetuned
(326)
this model
Quantizations
1 model

Datasets used to train sherif1313/Arabic-Qwen3.5-OCR-v4

Spaces using sherif1313/Arabic-Qwen3.5-OCR-v4 2

Collection including sherif1313/Arabic-Qwen3.5-OCR-v4