---
name: arabic-ocr-pipeline
description: >
  معالجة المستندات العربية باستخدام OCR لاستخراج النصوص والبيانات المهيكلة.
  استخدم هذا الـ skill عند: معالجة مستندات عربية، استخراج نصوص من صور أو PDF،
  تحليل وثائق حكومية، استخراج بيانات من نماذج، قراءة مستندات ممسوحة ضوئياً،
  أو أي مهمة تتعلق بـ OCR للنصوص العربية. يشمل المعالجة المسبقة للصور وما بعد المعالجة.
---

# Arabic OCR Pipeline
# خط معالجة OCR العربي

نظام شامل لاستخراج النصوص من المستندات العربية مع معالجة مسبقة وتصحيح لاحق.

## Pipeline Architecture

```
المستند الأصلي
    │
    ▼
[1. المعالجة المسبقة] ─── تحسين جودة الصورة
    │
    ▼
[2. الكشف عن المناطق] ─── تحديد مناطق النص، الجداول، الأختام
    │
    ▼
[3. استخراج OCR] ─── Tesseract / Azure AI / Google Vision
    │
    ▼
[4. التصحيح اللغوي] ─── تصحيح أخطاء OCR الشائعة في العربية
    │
    ▼
[5. الهيكلة] ─── تحويل لبيانات مهيكلة (JSON/XML)
    │
    ▼
[6. الحفظ والفهرسة] ─── حفظ في قاعدة البيانات مع Full-Text Search
```

## Step 1: Image Preprocessing

```python
# preprocessing.py
import cv2
import numpy as np

class ArabicDocumentPreprocessor:
    """معالج المستندات العربية - تحسين جودة الصور قبل OCR"""
    
    def process(self, image_path: str) -> np.ndarray:
        img = cv2.imread(image_path)
        img = self._deskew(img)
        img = self._remove_noise(img)
        img = self._binarize(img)
        img = self._enhance_arabic_text(img)
        return img
    
    def _deskew(self, img: np.ndarray) -> np.ndarray:
        """تصحيح ميل المستند"""
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        coords = np.column_stack(np.where(gray > 0))
        angle = cv2.minAreaRect(coords)[-1]
        if angle < -45:
            angle = -(90 + angle)
        else:
            angle = -angle
        (h, w) = img.shape[:2]
        center = (w // 2, h // 2)
        M = cv2.getRotationMatrix2D(center, angle, 1.0)
        return cv2.warpAffine(img, M, (w, h),
            flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
    
    def _remove_noise(self, img: np.ndarray) -> np.ndarray:
        """إزالة التشويش"""
        return cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 21)
    
    def _binarize(self, img: np.ndarray) -> np.ndarray:
        """التحويل الثنائي التكيفي"""
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        return cv2.adaptiveThreshold(gray, 255,
            cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
    
    def _enhance_arabic_text(self, img: np.ndarray) -> np.ndarray:
        """تعزيز النص العربي - تعامل مع النقاط والتشكيل"""
        kernel = np.ones((1, 1), np.uint8)
        img = cv2.dilate(img, kernel, iterations=1)
        img = cv2.erode(img, kernel, iterations=1)
        return img
```

## Step 2: Region Detection

```python
class DocumentRegionDetector:
    """كشف مناطق المستند: نص، جداول، أختام، تواقيع"""
    
    REGION_TYPES = {
        'text': 'نص',
        'table': 'جدول',
        'stamp': 'ختم',
        'signature': 'توقيع',
        'header': 'ترويسة',
        'logo': 'شعار',
        'barcode': 'باركود',
        'qr': 'رمز QR'
    }
    
    def detect_regions(self, img) -> list[dict]:
        """إرجاع قائمة بالمناطق المكتشفة مع إحداثياتها ونوعها"""
        regions = []
        # Text regions
        text_regions = self._detect_text_blocks(img)
        # Table regions
        table_regions = self._detect_tables(img)
        # Stamp/Signature regions
        stamp_regions = self._detect_stamps(img)
        
        regions.extend(text_regions)
        regions.extend(table_regions)
        regions.extend(stamp_regions)
        
        # Sort RTL (right-to-left, top-to-bottom) for Arabic
        regions.sort(key=lambda r: (r['y'], -r['x']))
        return regions
```

## Step 3: OCR Extraction

Support multiple OCR engines with Arabic optimization:

```python
from enum import Enum

class OCREngine(Enum):
    TESSERACT = "tesseract"
    AZURE_AI = "azure_ai"
    GOOGLE_VISION = "google_vision"

class ArabicOCRExtractor:
    def __init__(self, engine: OCREngine = OCREngine.TESSERACT):
        self.engine = engine
    
    def extract(self, img, regions: list[dict]) -> list[dict]:
        results = []
        for region in regions:
            cropped = self._crop_region(img, region)
            
            if self.engine == OCREngine.TESSERACT:
                text = self._tesseract_extract(cropped)
            elif self.engine == OCREngine.AZURE_AI:
                text = self._azure_extract(cropped)
            else:
                text = self._google_extract(cropped)
            
            results.append({
                'region': region,
                'raw_text': text,
                'confidence': self._calculate_confidence(text),
                'direction': 'rtl'
            })
        return results
    
    def _tesseract_extract(self, img) -> str:
        """Tesseract with Arabic language pack"""
        import pytesseract
        config = '--oem 3 --psm 6 -l ara+eng'
        return pytesseract.image_to_string(img, config=config)
```

## Step 4: Arabic Post-Processing

```python
class ArabicTextPostProcessor:
    """تصحيح الأخطاء الشائعة في OCR العربي"""
    
    # Common OCR mistakes in Arabic
    COMMON_FIXES = {
        'أ': ['ا', 'إ', 'آ'],   # Alef variants
        'ة': ['ه'],              # Ta marbuta / Ha
        'ي': ['ى'],              # Ya / Alef maksura
        'لا': ['ﻻ'],            # Lam-Alef ligature
    }
    
    # Government-specific terms dictionary
    GOV_TERMS = {
        'المملكة العربية السعودية',
        'وزارة', 'هيئة', 'مؤسسة',
        'رقم الهوية', 'تاريخ الميلاد',
        'السجل المدني', 'رخصة',
    }
    
    def correct(self, text: str) -> str:
        text = self._fix_common_errors(text)
        text = self._fix_numbers(text)
        text = self._fix_dates(text)
        text = self._normalize_arabic(text)
        return text
    
    def _fix_numbers(self, text: str) -> str:
        """Convert Arabic-Indic numerals to Arabic numerals"""
        arabic_indic = '٠١٢٣٤٥٦٧٨٩'
        western = '0123456789'
        trans = str.maketrans(arabic_indic, western)
        return text.translate(trans)
    
    def _fix_dates(self, text: str) -> str:
        """Detect and normalize Hijri and Gregorian dates"""
        import re
        # Pattern: dd/mm/yyyy or dd-mm-yyyy
        date_pattern = r'(\d{1,2})[/\-](\d{1,2})[/\-](\d{2,4})'
        return re.sub(date_pattern, self._normalize_date, text)
    
    def _normalize_arabic(self, text: str) -> str:
        """Normalize Arabic characters"""
        import unicodedata
        text = unicodedata.normalize('NFKC', text)
        # Remove tatweel (kashida)
        text = text.replace('\u0640', '')
        return text
```

## Step 5: Structured Output

```python
class DocumentStructurer:
    """تحويل النص المستخرج لبيانات مهيكلة"""
    
    def structure(self, ocr_results: list[dict], doc_type: str) -> dict:
        if doc_type == 'national_id':
            return self._structure_national_id(ocr_results)
        elif doc_type == 'commercial_register':
            return self._structure_cr(ocr_results)
        elif doc_type == 'government_letter':
            return self._structure_letter(ocr_results)
        elif doc_type == 'invoice':
            return self._structure_invoice(ocr_results)
        else:
            return self._structure_generic(ocr_results)
    
    def _structure_government_letter(self, results) -> dict:
        """هيكلة خطاب حكومي"""
        return {
            'document_type': 'خطاب حكومي',
            'reference_number': self._extract_field(results, 'رقم الإشارة'),
            'date_hijri': self._extract_field(results, 'التاريخ'),
            'from_entity': self._extract_field(results, 'من'),
            'to_entity': self._extract_field(results, 'إلى'),
            'subject': self._extract_field(results, 'الموضوع'),
            'body': self._extract_body(results),
            'attachments_count': self._extract_field(results, 'المرفقات'),
        }
```

## Step 6: Database Storage with Full-Text Search

```sql
-- Arabic Full-Text Search Configuration
CREATE FULLTEXT CATALOG ArabicDocumentsCatalog AS DEFAULT;

CREATE TABLE [Documents].[OcrResults] (
    [Id] INT IDENTITY(1,1) PRIMARY KEY,
    [DocumentId] INT NOT NULL FOREIGN KEY REFERENCES [Documents].[Archive]([Id]),
    [ExtractedTextAr] NVARCHAR(MAX),
    [ExtractedTextEn] NVARCHAR(MAX),
    [StructuredData] NVARCHAR(MAX), -- JSON
    [Confidence] DECIMAL(5,2),
    [OcrEngine] NVARCHAR(50),
    [ProcessedAt] DATETIME2 NOT NULL DEFAULT GETUTCDATE()
);

CREATE FULLTEXT INDEX ON [Documents].[OcrResults](
    [ExtractedTextAr] LANGUAGE 'Arabic',
    [ExtractedTextEn] LANGUAGE 'English'
) KEY INDEX PK__OcrResults;

-- Search stored procedure
CREATE PROCEDURE [Documents].[SearchOcrText]
    @SearchTerm NVARCHAR(200),
    @PageNumber INT = 1,
    @PageSize INT = 10
AS
BEGIN
    SELECT d.*, o.ExtractedTextAr, o.Confidence,
           KEY_TBL.RANK
    FROM [Documents].[OcrResults] o
    INNER JOIN [Documents].[Archive] d ON d.Id = o.DocumentId
    INNER JOIN CONTAINSTABLE([Documents].[OcrResults], 
        ExtractedTextAr, @SearchTerm) AS KEY_TBL
    ON o.Id = KEY_TBL.[KEY]
    ORDER BY KEY_TBL.RANK DESC
    OFFSET (@PageNumber - 1) * @PageSize ROWS
    FETCH NEXT @PageSize ROWS ONLY;
END;
```

## Integration with .NET Backend

```csharp
public interface IOcrService
{
    Task<OcrResult> ProcessDocumentAsync(Stream fileStream, string fileName);
    Task<OcrResult> ProcessImageAsync(byte[] imageData);
    Task<List<SearchResult>> SearchTextAsync(string searchTerm, int page, int pageSize);
}

public class OcrService : IOcrService
{
    public async Task<OcrResult> ProcessDocumentAsync(
        Stream fileStream, string fileName)
    {
        // 1. Save to temp
        // 2. Preprocess
        // 3. Extract OCR
        // 4. Post-process Arabic text
        // 5. Structure data
        // 6. Save to database
        // 7. Index for full-text search
    }
}
```

## Supported Document Types

| النوع | Document Type | الحقول المستخرجة |
|--------|--------------|-----------------|
| هوية وطنية | National ID | الاسم، رقم الهوية، تاريخ الميلاد |
| سجل تجاري | Commercial Register | اسم المنشأة، رقم السجل، النشاط |
| خطاب حكومي | Government Letter | المرسل، المستقبل، الموضوع، التاريخ |
| فاتورة | Invoice | المبلغ، التاريخ، البنود |
| عقد | Contract | الأطراف، المدة، القيمة |
