/ Модель

Характеристики

Контекст
262 144 токена
Лицензия
Apache 2.0
Архитектура
qwen3_5 · dense
Базовая модель
Qwen3.5-0.8B
Опубликована
22 мар 2026

Arabic-Qwen3.5-OCR-v4

Изображение и текст → текст7 профессий

Компактная мультимодальная модель на базе Qwen3.5-0.8B для извлечения арабского текста из изображений документов, фотографий и сканов.

357скачиваний за 30 дней10лайковвеса обновлены24 мар 2026

Бенчмарки

Как модель справилась с задачами пользователей ailist и что о ней публикуют открытые лидерборды

Тесты пользователейпока нет

Никто ещё не опубликовал тест этой модели. Соберите бенчмарк из своих задач — результат появится здесь.

  1. Добавьте модель в бенчмарк

    Вместе с другими моделями категории «Изображение → текст» — сравнение идёт внутри одной категории.

  2. Опишите свои задачи

    Напишите запросы, при необходимости приложите файлы и эталонные ответы.

  3. Запустите и опубликуйте

    Модели ответят на каждую задачу, судья оценит ответы. Опубликованный результат появится на этой странице.

Публичные оценки

Из открытых лидербордов. Сравнивайте результаты одного теста при одинаковых условиях — отсутствие оценки не значит, что модель хуже.

В подключённых источниках результатов для этой модели пока нет.

Что умеет модель

Описание составлено по карточке модели и метаданным Hugging Face

Arabic-Qwen3.5-OCR-v4 — модель sherif1313, дообученная на основе Qwen/Qwen3.5-0.8B для распознавания текста на изображениях. Она принимает изображение и текстовый запрос и возвращает извлечённый текст; предназначена для арабского письма, включая печатный, рукописный, классический текст и текст с диакритическими знаками. В обучении использованы синтетические сканы, изображения строк текста и данные для распознавания Корана.

Модель построена на мультимодальной плотной архитектуре Qwen3.5 и распространяется в формате safetensors. В README заявлена скорость около четырёх изображений в секунду; она зависит от оборудования и условий запуска. Лицензия — Apache-2.0.

Примеры использования охватывают распознавание текста на фотографиях, сканах, PDF-страницах и документах низкого качества. README также указывает поддержку сложного форматирования, однако не приводит метрик точности и не уточняет, насколько хорошо модель работает с языками помимо арабского. Приведённый пример генерации ограничивает ответ 512 токенами.

Сценарии применения

  • распознавание арабского текста на сканах документов
  • извлечение текста с фотографий и PDF-страниц
  • распознавание рукописного арабского письма
  • чтение арабского текста с диакритическими знаками
  • распознавание классических арабских текстов и страниц Корана

Ограничения

В карточке не приведены численные метрики качества; заявленная скорость около четырёх изображений в секунду зависит от аппаратного обеспечения. Поддержка языков помимо арабского и точность на разных типах изображений не уточнены.

Для каких профессий подходит7

Разделы каталога профессий, в задачах которых используется эта модель

Все профессии

Также подходит для

Карточка модели

README от автора на Hugging Face, как он его опубликовал

Открыть на Hugging Face

🕌 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 Metricv3v4Performance Delta
⏱️ Time per Image0.31 seconds0.25 seconds+25% Faster
🚀 Images per Second3.23 images4 images20% throughput
⚡ Printed Performance70%90%30% percentage points
🚀 Page per Secondseconds3.5 secondsFaster 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} }

Как запустить

На своей GPU в ailist. Цена — по текущим предложениям провайдеров

GPU в ailist

Универсальный рантайм

Можно запустить

Подбираем GPU…

Класс архитектуры
Qwen3_5ForConditionalGeneration
Ревизия весов
a137338

0 моделей