ذكاء المستندات
ذكاء المستندات
Section titled “ذكاء المستندات”تستوعب منصة المستندات في كاظمه المستندات وتحلّلها وتتعرّف عليها ضوئيًا (OCR) وتفهرسها وتولّدها وتحوّلها وتحجبها عبر طبقة تنسيق واحدة، مع عمّال معزولين، وسجل تدقيق للإلحاق فقط، وإعداد حي. وما قيس وما لم يُقس مذكور تحت ما ليس مؤهَّلًا.
روابط سريعة:
- خريطة المراحل (0–10) — ما شحنته كل مرحلة بناء
- فهرس الأدوات — أدوات
document_*الموجّهة للوكيل - تشغيل معالجة المستندات — المقاييس، والضغط العكسي، وGC، والنسخ الاحتياطي
- أمان المستندات — نموذج التهديد وبنية الأمان
- مسارات API —
/api/documents/* - الأوامر المائلة —
/documents//docs
البنية
Section titled “البنية”User Input (file upload / workspace import / tool call / slash / TUI) │ ▼DocumentIngestionService ◄── tenant + actor ACL, capacity gate, audit │ (durable public boundary for Web/API/tools/gateway/TUI) ▼Durable Job Queue ◄── CAS transitions, leases, retries, dead-letter │ ▼DocumentService ◄── single *execution* boundary (sniff / parse / OCR / render) │ every step below runs in an isolated worker │ (process or container profile) ├─ Sniff (MIME, OOXML defenses, PDF active-content policy) ├─ Parse (one parser per format) ├─ OCR (per-page quality routing, the neural engine or Tesseract, ruled tables cell by cell) ├─ Index (structural chunking → Knowledge library — explicit action) ├─ Generate / Convert (render workers) └─ Mutate / Redact (verified redaction pipeline)طبقتان، ومسار واحد للعمل الدائم.
| الطبقة | الصنف | من يستدعيها |
|---|---|---|
| المنسّق الدائم | DocumentIngestionService | /api/documents/* في الويب، وأدوات document-platform الأصلية، و/documents في البوابة، ولوحة المستندات في واجهة الطرفية (عبر API الويب) |
| محرّك التنفيذ | DocumentService | عمّال الاستيعاب فقط للمهام الدائمة؛ وكذلك التحليل العابر لمرفقات الدردشة عبر attachments.py في البوابة |
لا تستورد البوابة ولا الواجهة داخليات المحلّل/OCR/المُعرِض
(documents.parsers، وdocuments.ocr، والعمّال). وقد تستدعي الدردشة DocumentService
لمقتطف مسيَّج على أفضل جهد من ملف مرفق — وهذا مقصود ولا ينشئ مخزنًا دائمًا ثانيًا.
الفهرسة التلقائية معطّلة افتراضيًا. التحليل الناجح يضع المستند في حالة
ready. أما النشر في مكتبة معرفة فهو إجراء فهرسة صريح
(API / أداة / واجهة).
الميزات الأساسية
Section titled “الميزات الأساسية”المجلدات الإضافية (منح المسارات)
Section titled “المجلدات الإضافية (منح المسارات)”المسارات خارج مساحة العمل مرفوضة افتراضيًا. لفتح مجلد بإذن:
- الدردشة (بسلاسة): حين تفشل أداة ملفات، يستدعي الوكيل
request_path_access(بطاقة موافقة HITL). وعند الموافقة تُنشأ منحة جلسة لذلك المجلد ويعيد الوكيل محاولة الأداة. - صفحة مساحة العمل / API: مساحة العمل ← مجلدات خارج مساحة العمل
تعرض القائمة الدائمة
workspace.extra_rootsوتضيف إليها (قراءة فقط، أو قراءة وكتابة) وتحذف منها (GET/PUT /api/workspace/extra-roots:path،mode:read|write،label). يجب أن يكون المجلد الجديد مسارًا كاملًا لمجلد موجود، لا قرصًا كاملًا، ولا مجلدًا يحوي تثبيت كاظمه أو بياناتها (مفاتيحها، ومخازنها)؛ وتقول الصفحة أي قاعدة خالفها المسار المرفوض.
مدة منح الجلسة نحو ساعة؛ وتبقى الجذور الدائمة حتى تُزال. ومنح القراءة
لا تسمح بالكتابة. انظر kazma_core.workspace.path_policy.
الاستلام الآمن
Section titled “الاستلام الآمن”- حدود منصة المستندات (الافتراضية): 50 MiB للملف، و10 ملفات للطلب
(
documents.intake.max_bytes،documents.intake.max_files). وتُقبل الأسماء البديلةdocuments.intake_max_bytes/documents.intake_max_files. - مرفقات دردشة البوابة (واجهة منفصلة): 20 MiB للملف، و10 ملفات، و50 MiB إجمالًا — فتبقى حمولات الموجّه محدودة.
- القبول قبل الجسم: يُجاب عن رفع الويب قبل قراءة أي بايت من جسمه (الطول المُعلَن، والكتابات المعطّلة، وأرضية المساحة الحرة محسوبًا فيها الملف القادم، والطابور، وحدود المستأجر، ونافذة المعدل)؛ انظر الضغط العكسي. وتقرأ مسارات JSON العشرة (التوليد، والتحويل، والفهرسة، والبحث، …) جسمها عبر قارئ محدود بـ 2 MiB: فالجسم الأكبر يُرَد بـ 413، وJSON المشوّه بـ 422.
- تخزين ثابت معنون بالمحتوى: إزالة التكرار بـ SHA-256؛ يصل الرفع إلى الحجر ويُرقّى إلى مخزن الأصول الثابت حين يجتاز التحقق (الفحص، الذي يجري في العامل).
- فحص MIME قبل التحليل (داخل العامل): رفض عدم تطابق الامتداد/المحتوى،
ودفاع بنيوي عن OOXML (XXE، والماكرو، والعلاقات الخارجية، والأرشيفات المتداخلة،
وقنابل الضغط)، وسياسة واحدة للمحتوى النشط في PDF (
documents/pdf_policy.py). ملفات PDF المرفوضة: المشفّرة، والسكربت (JavaScript، ونماذج XFA)، والأفعال التي تشغّل أو تفتح أو ترسل أو تجلب خارج المستند (Launch، وGoTo البعيد — ومنه GoTo أو Thread يسمّي ملفًا آخر — وSubmitForm، وImportData، والعروض البديلة (renditions)، والوسائط الغنية، والصوت، والفيلم)، والملفات المضمّنة، والروابط التي ليس هدفها URI مطلقًا من نوعhttpأوhttpsأوmailto. ويبقى التنقل داخل المستند وروابط الويب. ولا يوجد إعداد يعطّل هذا الرفض. وتجري السياسة نفسها على كل مُدخَل ومُخرَج للتعديل وعلى كل PDF مُعرَض. - كل محتوى يراه نموذج اللغة مسيَّج: تستخدم قراءات المنصة
<kazma:data source="document" untrusted="true">…</kazma:data>. وقد تستخدم مقتطفات مرفقات الدردشةsource="document_attachment".
التحليل المعزول
Section titled “التحليل المعزول”يجري كل تحليل وOCR وتعديل وعرض في عامل خارج عملية كاظمه. ويختار
KAZMA_DOCUMENT_WORKER_ISOLATION النمط
(documents/worker_container.py):
process(الافتراضي): عملية فرعية على المضيف (python -I) ببيئة منقّاة (تُنزع أسرار الأب)، ومهلة العامل (documents.workers.timeout_seconds، وتُقتل شجرة العمليات)، وحدود للمخرجات. وعلى Windows يحمل Job Object حدّ الذاكرة (documents.workers.memory_mb)، وحدًّا لمعدل المعالج، وسقفًا للعمليات النشطة (32)؛ وينتظر العامل خلف بوابة إطلاق حتى تُطبَّق، والإعداد الفاشل يوقفه قبل أن يبدأ المحلّل. وعلى Unix الحدود هي الذاكرة ووقت المعالج (setrlimit)؛ ولا سقف لعدد العمليات. وهذا النمط لا عزل فيه لنظام الملفات ولا للشبكة: تُبلغ الجاهزيةhostile_document_profile: unqualified.container: يذهب كل تشغيل إلى وسيط عمّال المستندات (documents/worker_broker.py)، الحائز الوحيد لمقبس Docker، الذي يشغّله في حاوية جديدة من صورة واحدة مثبّتة: بلا شبكة، وبلا تركيبات، وجذر للقراءة فقط، وtmpfs محدود الحجم، وحدود للذاكرة/المعالج/PID، وكل الصلاحيات (capabilities) منزوعة، وno-new-privileges، ومستخدم غير جذر. ويتحقق الوسيط من هذه السياسة من داخل حاوية مهمة قبل أن يخدم. وتنتقل المدخلات والمخرجات حزمًا يُتحقَّق من بصمتها (digest). والوسيط غير المضبوط أو المتوقف أو غير المُصدَّق أو المشغول يرفض التشغيل (worker_isolation_unavailable/worker_isolation_busy، ويعيد الطابور المحاولة)؛ ولا رجوع إلىprocess. والمحرّكات الموجودة هي ما تبلغ عنه الصورة نفسها، وتنبّه الجاهزية إلى صورة بُنيت من شيفرة مستندات أخرى (document_worker_image_outdated). ولا تتضمن الصورة Docling، فالإنقاذ المحلي ليس جزءًا من هذا النمط.- أي قيمة أخرى ترفض كل تشغيل (
worker_isolation_invalid). والإعدادsecurity.execution.container_requiredيرفض نمطprocess(worker_isolation_required).
الانهيارات والمهلات والمخرجات المفقودة تفشل مغلقة: لا تغادر العامل بيانات جزئية. وتُعاد محاولة إخفاقات الموارد (المهلة، ونفاد الذاكرة، والعامل المقتول، وغياب النتيجة) ضمن ميزانية الطابور المحدودة ثم تُحال إلى الرسائل الميتة. وتتشارك الحاويات نواة المضيف؛ وما أُهِّل فيه نمط الحاوية وما لم يُؤهَّل فيه مذكور في أمان المستندات.
استخراج نص PDF (العربية + تعدد المحرّكات)
Section titled “استخراج نص PDF (العربية + تعدد المحرّكات)”ملفات PDF الإلكترونية (ذات طبقة النص) لا تمر بـ OCR افتراضيًا. يشغّل المحلّل مفاضلة مسجَّلة الدرجات بين محرّكات متعددة ويحتفظ بأفضل تمثيل وسيط:
| الترتيب | المحرّك | الدور |
|---|---|---|
| 1 | PyMuPDF | الأساسي — عربية بالترتيب المنطقي، وجداول، وتخطيط متعدد الأعمدة |
| 2 | pypdfium2 (اختياري) | نظير PDFium في مفاضلة الدرجات (نص فقط؛ القدرة DEGRADED دون PyMuPDF/pdfplumber فلا تُعلَن الجداول) |
| 3 | pdfplumber | جداول قوية؛ وقد تنعكس العربية إن استُخدم وحده |
| 4 | pypdf | نص فقط، الملجأ الأخير |
- التسجيل: يفضّل
score_document_extractionيونيكود النظيف، ويعاقب أشكال العرض العربية ومخرجات(cid:N)، ويمنح علاوة ترتيب صغيرة (PyMuPDF > pypdfium2 > pdfplumber). والدرجات القوية تختصر المفاضلة. - التخطيط: تستخدم الصفحات متعددة الأعمدة / القانونية هندسة
dictفي PyMuPDF (parsers/pdf_layout.py) — الأعمدة من الأعلى إلى الأسفل، LTR أو RTL حين تغلب العربية. ويحتفظ العمود الواحد بالنص العادي (عربية متصلة أفضل). - تُعاد قراءة الأسطر المكتوبة من اليمين إلى اليسار حرفًا رسوميًا تلو الآخر
(
parsers/pdf_rtl.py). يعكس PyMuPDF مثل هذا السطر حرفًا حرفًا، فكان يقلب الأرقام والحروف المركّبة («١٢٣٤٥٦٧» تُقرأ «٧٦٥٤٣٢١»، و«في» تُقرأ «يف») ويعكس خلايا الجداول العربية. تُقرأ الحروف الرسومية (glyphs) بترتيب رسمها، ولا تُعكس إلا المقاطع المكتوبة من اليمين إلى اليسار، حروفًا رسومية كاملة. ويحصل كل عنقود أرقام على القراءة التي ترسمها خوارزمية ثنائية الاتجاه (arabic.visual_order) كما تُظهرها الصفحة، فالتاريخ المكتوب «في 2026-09-30» يعود كما كُتب مع أن الصفحة ترسمه «30-09-2026». وتُقرأ أعمدة جدول RTL من اليمين إلى اليسار. والفجوة الأعرض من نصف حجم الخط فاصلٌ بين كلمتين. - الجداول والصفحات ثنائية اللغة: يُقرأ كل جدول مرة واحدة، من شبكته، في موضعه من الصفحة. ويأتي نص الخلايا من الحروف الرسومية في كل صفحة، فيُقرأ حرف مركّب مثل “fi” كما كُتب؛ والأسطر الملتفّة في الخلية قيمة واحدة، والخلية الرقمية وحدها في جدول من اليمين إلى اليسار تُقرأ من اليمين إلى اليسار. ولا يُعدّ جانبا الصفحة عمودين إلا إذا وقفا جنبًا إلى جنب، فتبقى الأسطر العربية والإنجليزية القصيرة المكدّسة بعضها فوق بعض في عمود واحد. والفقرة التي تحمل علامة اتجاه (RLM، أو عازلًا) لم تعد تُنهي نص الصفحة.
- البيانات الوصفية:
extractor، وextraction_score، وextractors_tried، ولكل صفحةlayout.method/column_count. - ذهاب وإياب التوليد←التحليل: تستخدم عناوين RTL تغطية رموز تقريبية (تتحمل ضجيج الحروف)، لا «أي 20 حرفًا».
التثبيت: pip install -e ".[document-platform]" (يشمل pymupdf +
pypdfium2). ودون PyMuPDF، قد تنعكس ملفات PDF العربية الإلكترونية مع
pdfplumber وحده.
إنقاذ ملفات PDF الصعبة: إن كانت الدرجة الأصلية ضعيفة، يعمل Docling
(pip install -e ".[docling]") داخل عامل المحلّل المحدود حين يسمح به
documents.security.local_salvage (مفعّل افتراضيًا). أما LlamaParse /
Reducto فيعملان من عملية كاظمه، لا من العامل أبدًا، وفقط بموافقة صريحة عبر
documents.security.remote_parse (معطّلة افتراضيًا) ومفتاح مزوّد. والمفاتيح وحدها
لا تأذن بالرفع أبدًا. وكل محاولة تتطلب تدقيقًا دائمًا يحمل مستأجر المهمة وفاعلها
ومساحة عملها ومستندها ونسختها؛ وتُفحص الموافقة مجددًا قبل كل محاولة لدى مزوّد.
ومقتطفات المرفقات العابرة ليس لها نطاق خروج دائم ولا يمكنها الرفع عن بُعد. ولا
تدخل مفاتيح API العامل أبدًا. ويُجرَّب المزوّدون بالترتيب: يُدقَّق المزوّد الفاشل
بوصفه إخفاقًا ويُجرَّب المزوّد المضبوط التالي، بعد قراءة السياسة الحية مجددًا.
ويتجاهل عميل المزوّد متغيرات الوكيل (proxy) المحيطة، ولا يتبع أي إعادة توجيه،
ويرفض جوابًا يتجاوز 32 MiB (remote_parse_response_limit). اعتراضات إضافية:
KAZMA_DOCLING=0، وKAZMA_REMOTE_PARSE=0 (يمكنها إيقاف طبقة، لا تشغيلها أبدًا).
ولـ Markdown الإنقاذ مقاطع اصطناعية، موسومة صراحةً بأنها بلا استشهادات بصفحات
المصدر الفعلية. وفي نمط container لا توجد طبقة Docling.
التعرّف الضوئي متعدد اللغات
Section titled “التعرّف الضوئي متعدد اللغات”- يُقرأ المستند الممسوح الطويل بضع صفحات في كل مرة (2026-10-22). يستغرق
التعرّف الضوئي نحو 15 إلى 45 ثانية للصفحة على نواة واحدة (المحرّك العصبي في
الطرف البطيء)، فالمستند الممسوح من 54 صفحة يستغرق نحو نصف ساعة. يقرأ تشغيل
العامل الواحد من الصفحات ما يتسع له حده الزمني على الأكثر ويسمّي الباقي؛
وتقرأها تشغيلات لاحقة، يُحدَّد حجم كل منها من الثواني التي استغرقتها الصفحة
حتى الآن (
DocumentService.ocr_in_batches). تقرأ المهمة الدائمة كل الصفحات بهذه الطريقة، وتعرض حالتها الصفحات المقروءة حتى الآن (progress؛ ويقولdocument_status“OCR: 12 of 54 pages read”). أما استدعاء الأداة (read_documentوocr_documentوfile_read) فيقرأ طبقة النص أولًا، ثم يُجري التعرّف الضوئي على الصفحات الممسوحة ضمن النطاق بقدر ما يسمح وقت الاستدعاء (agent.tool_timeout_secondsناقصًا هامشًا)، ويسمّي الصفحات التي لم يصل إليها، مع الاستدعاء الذي يُكمل وdocument_importللملف كله. - ملف Word للمستند الممسوح هو نص التعرّف الضوئي. يبني
document_convertإلىdocxأوmdلمستند جاءت قراءته من التعرّف الضوئي الملفَّ من ذلك النص، قسمًا لكل صفحة؛ فتحويل الصورة الممسوحة نفسها ينتج صور صفحات بلا نص. والمستند الذي له طبقة نص يُحوَّل من ملفه كما كان. - الملف المحوَّل أو المحجوب جاهز للإرسال. يحفظ
document_convertوdocument_redactالملف الجديد في مجلدdocumentsضمن مجلد البيانات (حيث تكتب أدوات الإنشاء) ويذكران مساره، فيمرّره الوكيل إلىsend_file. وكانا يجيبان بـartifact_idوحده، ولا تقبله أي أداة لدى الوكيل. وتبقى القطعة في مخزن المستندات، قابلة للتنزيل من صفحة المستندات. - الاستدعاء الذي يُوقَف يوقف عامله. حين يُنهى استدعاء أداة (بحده الزمني أو بالإيقاف)، يُوقَف تشغيل عامله أيضًا: تُزال الحاوية، أو تُقتل شجرة العمليات المحلية. كان يستمر حتى حده الخاص.
- توجيه بالجودة لكل صفحة: قد تتخطى الصفحات عالية كثافة النص OCR (يُحفظ النص الأصلي)؛ أما الصفحات كثيفة الصور / فقيرة النص، والطبقات الكثيرة بأشكال العرض / المشوّهة بـ CID، وطبقات النص الفارغة فتُوجَّه إلى OCR.
- محرّكان (
documents.ocr.engine، الإعدادات ← المستندات):auto(الافتراضي) يقرأ بـ المحرّك العصبي حين تكون حزمه ونماذجه مثبّتة، وإلا بـ Tesseract؛ وneuralيفعل الشيء نفسه ويذكر على المستند متى اضطر Tesseract إلى قراءته؛ وtesseractيستخدم Tesseract وحده.- المحرّك العصبي (
documents/ocr/neural.py) هو الذي سجّل أفضل قياس على العربية والأرقام العربية الهندية (2026-10-15): كشف النص بـ PaddleOCR PP-OCRv5، ومُتعرِّف EasyOCR العربي (arabic_g1: الحروف العربية واللاتينية، ومجموعتا الأرقام) معenglish_g2للأسطر الخالية من العربية، وتصويت على الحروف مع مُتعرِّف PaddleOCR PP-OCRv5 العربي وكلمات Tesseract (اتفاق قارئَين، أو كلمة PaddleOCR واثقة، يحلّ محل كلمة EasyOCR؛ وقراءة EasyOCR الثانية لحرف شكّ فيه تُعدّ قارئًا؛ والرقم وعلامات ترقيم الكلمة دائمًا من EasyOCR). ولا يكتب EasyOCR الحركات: فحيث كتب همزة ورأى قارئ آخر للحروف نفسها تنوينًا هناك (“ريالاً”)، يُحتفظ بالتنوين. والعلامة الأخيرة في السطر يقرّرها قارئان: يقول EasyOCR إن هناك علامة، وتقول قراءة Tesseract للكلمة نفسها أيّ علامة هي (فنموذج EasyOCR الإنجليزي كثيرًا ما يقرأ ”.” الأخيرة ”:”)؛ والعلامة التي لا يقرؤها إلا Tesseract لا تُضاف أبدًا. وتُزال النقاط الأصغر من قلم السطر نفسه قبل قراءة السطر، وتُعاد ”,” أو ”.” بين الأرقام العربية الهندية إلى الفاصل العربي ٫ أو ٬ حين تحسم قواعدُ الرقم ذلك (وقبل ثلاثة أرقام بالضبط تبقى كما قُرئت: آلاف، أو ثلاث خانات عشرية). وتعمل النماذج الأربعة كلها على ONNX Runtime داخل عامل المستندات؛ ويُوضع السطر المرسوم في الترتيب المنطقي بقاعدة قارئ PDF، لا بقاعدة المُتعرِّف نفسه أبدًا. والنماذج كلها برخصة Apache-2.0. - الكلفة: نحو 15 ث لصفحة نص عربي و30–45 ث لصفحة فيها جداول مسطّرة على
نواة واحدة (حدّ عامل المستندات)، مقابل 2–8 ث مع Tesseract؛ ونحو 800 MB من
الذاكرة في العامل (ضمن الـ 1 GiB الخاصة به). وقرب حدّ وقت العامل
(
documents.workers.timeout_seconds، 300 ث) يقرأ Tesseract الصفحات المتبقية ويذكر المستند من أي صفحة؛ ارفع الحدّ لإبقاء المسوحات الطويلة على المحرّك العصبي.
- اختيار اللغة: قائمة حزم لغات قابلة للضبط (يشمل الافتراضي الإنجليزية +
العربية حين تكون مثبّتة). والترتيب التلقائي
ara+engحين تُضبط الاثنتان — فـeng+araكثيرًا ما يقرأ المسوحات العربية الخالصة هراءً لاتينيًا. - دمج حتمي: يُدمج النص الأصلي ونص OCR بقواعد قائمة على التشابه
(عتبات
SequenceMatcher+ الثقة)، لا بدمج إحداثيات هندسي بحت. وتُستبدل الطبقات الأصلية المعروفة بسوئها (أشكال العرض / CID) حين تكون ثقة OCR مقبولة. وقد تحمل كتل OCR إحداثيات البكسل من TSV للاستخدام اللاحق. - الاحتياطي: تُنقَّط الصفحات الكبيرة بدقة DPI قابلة للضبط (200 افتراضيًا،
72–600). ويبقى OCR في العامل المعزول (
apply_ocr) — ولا يستدعي محلّل PDF Tesseract مباشرة أبدًا. - تُقرأ الجداول المسطّرة خليةً خلية (
documents/ocr/tables.py، وdocuments.ocr.tables، مفعّل افتراضيًا، ومفتاحه في الإعدادات ← المستندات). فقراءة Tesseract للصفحة كاملةً لا تحفظ صفوف الجدول المسطّر ولا معظم أرقامه. يجد هذا المرور الشبكة من خطوط التسطير ويقرأ كل خلية وحدها؛ والخلية التي لا حرف فيها أو ذات القراءة المشكوك فيها تُقرأ مجددًا أرقامًا فقط (حين تكونengمثبّتة)، ولا تفوز تلك القراءة إلا حين تكون واثقة. ولا يُعثر إلا على الشبكات المسطّرة: فالجدول بلا خطوط تسطير، والجدول الضيق، والخلايا المدموجة التي تعبر الخطوط، كلها تحتفظ بقراءة الصفحة نفسها. والمرور محدود بـ 600 خلية و120 ث لكل صفحة؛ وبعد تجاوز أيٍّ منهما، أو حين تتعذر قراءة خلية، تحتفظ الصفحة بقراءتها ويسمّي تحذيرٌ الصفحة. وله كلفة زمنية: على المسح بدقة 300 dpi الذي قيس في 2026-10-13 استغرقت الصفحة نحو 8 ث بدل 2. - ترتيب الكلمات العربية: الرقم الذي يقرؤه OCR من سطر عربي يُعاد إلى الترتيب
المنطقي بالقاعدة نفسها المطبَّقة على نص PDF (
arabic.number_in_logical_orderلكلمات Tesseract، وparsers.pdf_rtl.logical_lineلأسطر المحرّك العصبي). - مؤهَّل مع المحرّك العصبي: التعرّف الضوئي العربي على صفحة نظيفة (
ar-ocr: كل كلمة ورقم، CER 0). ومع Tesseract لا يكون التعرّف الضوئي العربي مؤهَّلًا: فـaraلا يقرأ الأرقام العربية الهندية في أي خط أو نموذج قيس، ويتخطى بعض الأسطر. وغير مؤهَّل مع أيٍّ منهما: الصفحة العربية ذات الجدول المسطّر (كلمة واحدة أخطأ المحرّك العصبي قراءتها)، والأرقام المقروءة من مسوحات متدهورة، والأعداد العشرية والتواريخ العربية المكتوبة بالفواصل العربية (ليس لدى المُتعرِّف٫ونادرًا ما يقرأ/بين الأرقام العربية الهندية). انظر ما ليس مؤهَّلًا.
فهرسة المعرفة
Section titled “فهرسة المعرفة”- تقطيع بنيوي: تُقسم المستندات عند حدودها الطبيعية (الصفحة، والقسم، والجدول) مع تداخل، محافظةً على الاستشهادات.
- تبديل النسخة النشطة: يعكس الفهرس دائمًا النسخة المنشورة الحالية؛ ويراعي شواهد الحذف.
- عزل المستأجر: المقاطع محصورة بالمستأجر + الفاعل.
- استرجاع بسياج واحد: يُغلَّف السياق المسترجع بأسيجة البيانات غير الموثوقة للنموذج.
- البحث العربي: يطوي فهرس الكلمات المفتاحية للمكتبة النص العربي
(
arabic.fold_for_search) وقت الفهرسة ووقت الاستعلام. - إجراء صريح:
POST /api/documents/{id}/indexأو أداةdocument_indexمعlibrary_id— انظر مكتبة المعرفة. - حذف مستند يُخرجه من كل مكتبة أولًا. والمكتبة التي لا يمكنه مغادرتها توقف
الحذف (
document_unindex_failed، مع تسمية المكتبة)، كي تتمكن إعادة المحاولة من إتمامه؛ ولا يبقى مستند محذوف قابلًا للبحث أبدًا. وما دامت مكتبة المعرفة غير متاحة، فلا يُحذف كذلك مستند يسجّله المخزن مفهرسًا (document_unindex_failed، “nothing was deleted”)؛ فأعد المحاولة حين تعود. ويمسك الحذف قفل النشر الخاص بالمستند طوال الوقت، فلا يمكن لفهرس يُنشر في الأثناء أن ينجو منه. - يُسوّى الفهرس عند كل بدء للعمّال
(
DocumentIngestionService.reconcile_index): كل نسخة يسجّلها المخزن مفهرسةً ولا تحملها أي مكتبة يُعاد نشرها من ملف بيانها الخاص، تحت قفل النشر الخاص بالمستند، فلا يُتراجَع أبدًا عن إلغاء فهرسة متزامن. والمكتبة المفقودة أو النسخة المستبدَلة أو ملف البيان المفقود يُبلَّغ عنه، ولا يُختلَق. وهذا ما يعيد المكتبات بعد استعادة مخزن المستندات وحده.
التوليد والتحويل
Section titled “التوليد والتحويل”- توليد المستندات: حمولة منظّمة ← PDF/DOCX/HTML/markdown عبر عمّال عرض معزولين. حمولة التوليد محدودة بـ 1 MiB. وتُعاد النتائج للاستيعاب كمستندات يملكها المستأجر.
- تحويل الصيغ: تحويل مستند معالَج إلى صيغة هدف
(
document_idمعتم فقط — لا مسارات خادم خامًا من العملاء). - أسلوب دار واحد: تستخدم المستندات المولَّدة، وكل ملف HTML يُحوَّل إلى PDF، خط
العلامة التجارية لكاظمه وعناوينها وجداولها ورأس الصفحة وتذييلها، مع تخطيط كل
فقرة وجدول باتجاه لغته هو. وتأخذ أداة
convert_documentالقائمة على المسارkeep_source_style=trueلتحفظ تصميم ملف HTML نفسه؛ أما تحويلات المنصة فتستخدم أسلوب الدار دائمًا. انظر عرض المستندات. - عمليات PDF: استخراج المعلومات، والتقسيم، والدمج، وملء حقول النماذج.
- الحجب: خط حجب فعلي/نقطي مُتحقَّق منه مع فحوصات لاحقة.
واجهة الويب تؤكد عبر
kazmaConfirmقبل استدعاء API. أما API وأدوات الوكيل فيمكنها استدعاء الحجب دون ذلك الحوار (مع بقاء المستأجر/ACL). - العرض لا يجلب شيئًا أبدًا. لا يُقرأ إلا عناوين
data:في المصدر والأصول المنسوخة إلى المهمة؛ ومصدر HTML أو Markdown يسمّي URL خارجيًا أو ملفًا محليًا آخر يُرفض (external_resource_denied). ويجتاز كل PDF مُعرَض سياسة المحتوى النشط في PDF قبل أن يغادر العامل. - المحرّكات الاختيارية: قد تغيب
pymupdf/ WeasyPrint / LibreOffice. وتظهر المحرّكات الغائبة جاهزيةً متدهورة واستجابات HTTP صادقة 422/503 — وقد تبقى المحلّلات النصية الأساسية جاهزة. وفي نمطcontainerتكون المحرّكات محرّكات صورة العامل، كما تبلغ عنها الصورة.
المسار القديم: مهارة document-generator (generate_pdf / generate_docx
/ …) تعرض عبر العمّال المعزولين أنفسهم (DocumentService.generate) لكنها تكتب
ملفات عادية تحت kazma-data/documents/ ولا تمر عبر المنصة الدائمة. فضّل
أدوات document-platform للعمل بمعرّفات معتمة، محصورًا بالمستأجر، آمنًا عند
إعادة التشغيل. ويقرأ generate_pdf ملف PDF المكتمل من جديد ويتحقق من أن الكلمات
المميِّزة لكل قسم، وكل ترويسة جدول وخلية من صفّه الأول، قد وصلت إليه، مقارنًا
علامات الترقيم والحروف المركّبة بالطريقة نفسها في الجانبين. وإن لم تصل، يجيب
الاستدعاء بخطأ يسمّي الملف الناقص ويطلب استدعاءً جديدًا: خطأ عادي يستطيع الوكيل
تصحيحه، لا أثر مجهول.
التشغيل
Section titled “التشغيل”الإعداد الحي
Section titled “الإعداد الحي”كل الحدود، والاستبقاء، وGC، والسعة، ورايات الإطلاق مخزّنة في ConfigStore
(المفاتيح الأساسية متداخلة). وتقرأ كل عملية لقطة واحدة ثابتة من إعدادات
documents حين تبدأ وتحتفظ بها حتى نهايتها، فيسري التغيير من العملية التالية
دون إعادة تشغيل — باستثناء الإعدادات المرتبطة بالمخازن والعمّال المُنشأة:
documents.storage_root، وdocuments.quotas.tenant_bytes،
وdocuments.workers.concurrency، وdocuments.workers.lease_seconds،
وdocuments.workers.heartbeat_seconds، وdocuments.workers.retry_base_seconds،
وdocuments.workers.retry_max_seconds، فهذه تسري عند إعادة التشغيل التالية؛
وحتى ذلك الحين تسردها الجاهزية تحت policy.pending_restart. والإعدادات التي
تتعذر قراءتها، أو القيمة المحفوظة غير الصالحة، ترفض العمل الجديد (HTTP 503
document_policy_unavailable) بدل الرجوع إلى القيم الافتراضية.
| كيف تضبط | المسار |
|---|---|
| واجهة الإعدادات | /settings?tab=documents (الإطلاق، والاستلام، والعمّال، وOCR وقراءة الجداول، والبرمجيات الخبيثة، وGC، والفهرسة) |
| REST | GET/PUT /api/settings/documents أو PUT /api/settings/single |
| YAML | يبذر kazma.yaml القيم عند الإقلاع الأول؛ وتفوز تجاوزات قاعدة البيانات بعد ذلك |
| البيئة (للواجهات الخلفية والعزل) | KAZMA_DOCUMENTS_JOBS_BACKEND، KAZMA_DOCUMENTS_METADATA_BACKEND، KAZMA_DOCUMENT_WORKER_ISOLATION (+ KAZMA_DOCUMENT_BROKER_URL، KAZMA_DOCUMENT_BROKER_TOKEN_FILE) |
حدود المستندات ليست مدفوعة بالبيئة أساسًا — استخدم مفاتيح ConfigStore.
| المجال | بادئة المفتاح الأساسي | ملاحظات |
|---|---|---|
| الاستلام | documents.intake.* | أسماء بديلة: documents.intake_max_*؛ وdocuments.intake.lease_seconds |
| المحلّل / الحدود | documents.limits.* | مثل documents.limits.max_pages |
| الأمان | documents.security.* | البرمجيات الخبيثة: malware_scan + malware_fail_closed |
| OCR | documents.ocr.* | documents.ocr.tables (قراءة الجداول خليةً خلية) |
| العرض | documents.render.* | documents.render.embed_html_fonts |
| العمّال | documents.workers.* | المهلة، والذاكرة، والتزامن، وعقود الإيجار |
| الفهرسة | documents.indexing.* | |
| الاستبقاء / GC | documents.retention.*، documents.gc.* | |
| السعة | documents.capacity.* | |
| الحصص | documents.quotas.* | |
| الإطلاق | documents.enabled، documents.shadow، documents.default_authoritative |
صحة الطابور (آلة حالات حقيقية)
Section titled “صحة الطابور (آلة حالات حقيقية)”تستخدم المهام الحالات الدائمة في DocumentJobState (لا خط
PENDING/ACCEPTED عامًا):
received → quarantined → validating → ready_to_parse | ocr_required | rejected → parsing | ocr_running → normalizing → indexing → verifying → readyالمسارات الجانبية: retry_wait (عابرة / استعادة عقد الإيجار)، وcancelled، وdead_letter.
- عقود الإيجار مع نبض تمنع العمل النشط العالق.
- إعادة المحاولة مع تراجع أسّي (قابل للضبط).
- الرسائل الميتة بعد أقصى المحاولات (
documents.workers.max_attempts، افتراضيًا 3) لمراجعة المشغّل. - الانقطاعات تُعاد محاولتها؛ ولا يُرفض إلا المحتوى. الماسح المطلوب للبرمجيات
الخبيثة الذي يتعذر تشغيله، والقرص الممتلئ (
storage_full)، ومخزن البيانات الوصفية المقفل أو غير القابل للوصول (metadata_unavailable، SQLite أو Postgres)، ووسيط العمّال المتوقف، كلها تمر عبر ميزانية إعادة المحاولة ثم تُحال إلى الرسائل الميتة — ولا تصيرrejectedأبدًا. وخطأ المخزن أثناء تسجيل نتيجة مرحلة يترك المهمة مؤجَّرة؛ وتستأنفها استعادة عقود الإيجار. - الاستعادة عند إعادة التشغيل: تُستعاد عقود الإيجار المنتهية على حالات المعالجة النشطة، ويُتراجَع عن عمليات الاستلام التي قطعتها عملية ميتة (انظر الضغط العكسي).
- مطالبات عادلة: يأخذ العمّال المهام أولًا من المستأجر صاحب أقل عدد من المهام الجارية، ثم بحسب وقت جاهزية المهمة (في الواجهتين الخلفيتين).
- كل قراءة لمهمة تسمّي مستدعيها. حالة المهمة، وأحداثها، ومهام مستند ما،
كلها تتحقق من أن الفاعل يستطيع قراءة مستند المهمة؛ أما الإلغاء وإعادة المحاولة
فيحتاجان صلاحية الكتابة. والاستدعاء الذي لا يسمّي مستدعيًا يُرفض قبل البحث عن
المهمة.
والمهمة التي لا يستطيع المستدعي قراءتها تجيب تمامًا كمهمة مجهولة (404 على
مسارات الويب) على كل واجهة؛ وإعادة إرسال مفتاح رفع يخص فاعلًا آخر هي
idempotency_conflict. وفي تثبيت بمشغّل واحد تعمل صفحة الويب والدردشة وأدوات الوكيل بهوية واحدة، هي مشغّل التثبيت (documents.principal.OPERATOR): فالمستند المستوعَب على واجهة يُقرأ على الأخريات. والمستندات المستوعَبة تحت اسم أقدم (agent، أو اسم مستخدم مسجّل الدخول) تحصل على صف ACL من نوعownerللمشغّل، يمنحه مالكها ويُدقَّق؛ ولا تتغير الملكية أبدًا. ومع مستخدمي المنصة تعمل الصفحة باسم كل مستخدم وترفض الدردشة والوكيل (مشغّل واحد لكل تثبيت؛ وهوية الدردشة لكل مستخدم غير مبنية).
الضغط العكسي
Section titled “الضغط العكسي”يُرفض الاستلام برموز حالة HTTP صادقة حين تُبلغ الحدود:
| الحالة | الرمز | Retry-After | مفتاح الإعداد |
|---|---|---|---|
| أرضية المساحة الحرة للتخزين | 507 | نعم | documents.capacity.storage_free_floor_bytes (افتراضيًا 512 MiB) |
| سقف الطابور العام | 503 | نعم | documents.capacity.max_queued_jobs |
| حدّ المهام المنتظرة/النشطة لكل مستأجر | 429 | نعم | documents.capacity.max_tenant_queued_jobs / .max_tenant_active_jobs |
| نافذة معدل/بايتات الاستلام | 429 | نعم | documents.capacity.intake_rate_per_minute / .intake_bytes_per_minute |
| رفوع كثيرة جدًا قيد الاستلام (لكل عملية) | 503 uploads_busy | نعم | documents.capacity.max_concurrent_uploads (افتراضيًا 4) |
| تجاوز الرفع عقد إيجاره فاستُولي عليه | 409 intake_taken_over | لا (أعد الرفع) | documents.intake.lease_seconds (افتراضيًا 300) |
يُجاب عن رفع الويب قبل قراءة جسمه: فلا ينتظر الرفض أبدًا وصول الملف. والميزانيات حجوزات دائمة في قاعدة بيانات المهام، فتصمد عبر العمليات؛ والجسم الذي بلا طول مُعلَن يُحسب بقدر حدّ الاستلام حتى يُعرف حجمه الحقيقي. والقياس الذي تتعذر قراءته (التخزين، والطابور، وعدّادات المستأجر، ومخزن القبول) يرفض بـ 503 بدل القبول.
الاستلام الذي ماتت عمليته على هذا المضيف يُتراجَع عنه عند البدء التالي وبكنسٍ
يجري كل دقيقة. والاستلام الذي لا يمكن إثبات موت مالكه (مضيف آخر) يجدّد عقد إيجار
ما دام يعمل؛ وحين ينقضي العقد يُستولى عليه ويُتراجَع عنه، وإن استأنف المالك القديم
فلا يمكنه النشر: لا تُنشأ مهمته إلا ما دام الحجز ما زال له، وتُزال الصفوف التي
كتبها. والحجز الذي بلا مالك أو بلا عقد إيجار (كتبه إصدار أقدم) لا يُستولى عليه
أبدًا: تعدّه الجاهزية ضمن stranded_intake_reservations
(document_intake_reservations_stranded) للمشغّل. وتُحسب خانات تخزين الرفع
المؤقت (spool) لكل عملية، وعدالة المطالبة بحسب أقل عدد من المهام الجارية، لا
موزونة.
الاستبقاء وGC
Section titled “الاستبقاء وGC”يعمل جامع وسم/كنس آمن من الانهيار وفق جدول قابل للضبط:
- قاعدة البيانات هي المرجع الوحيد (لا يتامى على نظام الملفات وحده)؛ والوسم/الكنس هو نفسه على بيانات SQLite وPostgres الوصفية.
- نسخ الحجر بعد الترقية، ومحتوى شواهد الحذف المنتهية، ومحتوى النسخ الفاشلة نهائيًا، والكتل اليتيمة، وصفوف التدقيق المتقادمة.
- ما تركه انهيار من ملفات مؤقتة تحت جذر التخزين: ملفات الرفع المؤقتة (spools)، والنسخ المرحلية، وأدلة تشغيل المحلّل والعمليات.
- الكتل التي ثبّتتها نسخة احتياطية جارية لـ Postgres تُحفظ حتى تنسخها.
- فترات سماح، وحذوف محدودة في كل تشغيل، ورفض الروابط الرمزية/نقاط الوصل.
- لا يعمل المرور المجدول (
documents.gc.auto_maintain، كلdocuments.gc.interval_hours) إلا ما دامت الكتابات الدائمة مفعّلة.
التدقيق
Section titled “التدقيق”يُلحق كل إجراء موجّه للمشغّل/المستأجر بجدول
document_audit_events. وعلى SQLite ترفض مُشغِّلات قاعدة البيانات التحديثات وأي
حذف سوى تقليم الاستبقاء؛ أما جدول Postgres فليس فيه مثل هذه المُشغِّلات، ولا
تفعل كاظمه به سوى الإلحاق والتقليم. والتفاصيل مقصورة على قيم مفردة آمنة — لا يدخل
المحتوى سجل التدقيق أبدًا. ولكل رفع لتحليل بعيد صف egress يُكتب قبل أن تتحرك
البايتات. وقراءة السجل (GET /api/documents/ops/audit) للمسؤول فقط.
النسخ الاحتياطي والترحيل
Section titled “النسخ الاحتياطي والترحيل”يُنسخ مخزن المستندات احتياطيًا كل ست ساعات، مع النسخة الاحتياطية الأصلية للذاكرة
(مهمة native_backup).
- مخزن SQLite: تُلتقط لقطة
documents.dbأولًا، ثم تُنسخ الشجرة المعنونة بالمحتوى المشار إليها وملفات البيان المطبَّعة. ويفحص التحقق قاعدة البيانات والكتل وملفات البيان المنسوخة، ويرفض جرد مجاميع اختبارية غائبًا أو غير صالح. ويعدّ الاستبقاء نقاط الاستعادة المُتحقَّق منها. - مخزن Postgres (
documents/backup_pg.py، يُؤخذ تلقائيًا حين تكون البيانات الوصفية أو المهام المثبّتة على Postgres): لقطةREPEATABLE READواحدة مُصدَّرة تخدم كلًّا منpg_dump --snapshotلجداول المستندات وقائمة الملفات التي تشير إليها؛ وتُثبَّت تلك الملفات في وجه جمع المهملات وتُنسخ مع مجاميع اختبارية. ولا تجري الاستعادة إلا إلى قاعدة بيانات وجذر تخزين فارغَين، وتعيد فحص عدد صفوف كل جدول مقابل اللقطة، وتُنهي عقود إيجار المصدر الميت، وتتراجع عن عمليات الاستلام التي لم يُتمّها. أوامر المشغّل:scripts/document_pg_backup.py(backup،verify،restore،index). - فهرس المعرفة: مقاطع المكتبات ومتجهاتها مخزن منفصل وليست في أيٍّ من النسختين الاحتياطيتين. وبعد الاستعادة تعيد الخدمة نشر كل مستند يسجّله المخزن مفهرسًا، عند البدء التالي للعمّال (انظر فهرسة المعرفة).
تحمل حزم الترحيل عبر kazma migrate ملف documents.db + شجرة المحتوى
(انظر الترحيل و
تشغيل معالجة المستندات). وأرقام نقطة
الاستعادة وزمن الاستعادة لنشر معيّن تأتي من تشغيل تدريبات الاستعادة على عتاده
الخاص؛ ولا يُؤكَّد هنا أي رقم منها.
ضوابط الإطلاق
Section titled “ضوابط الإطلاق”| الوضع | enabled | shadow | default_authoritative | الأثر |
|---|---|---|---|---|
| معطّل | false | — | — | لا كتابات دائمة؛ وتُحفظ البيانات الموجودة |
| ظلّي | true | true | false | تُقبل الكتابات؛ ويُبلَّغ عنه بوصفه shadow |
| توافق | true | false | false | تُقبل الكتابات (وضع الشحن الافتراضي) |
| مرجعي | true | false | true | تُقبل الكتابات؛ ويُبلَّغ عنه بوصفه authoritative |
لا يغيّر السلوك اليوم إلا enabled: فهو يتحكم بالكتابات الدائمة وبجمع المهملات
المجدول. أما shadow وdefault_authoritative فيُسجَّلان ويُبلَّغ عنهما (الجاهزية
rollout.mode، وفحص safe_rollout لدى المُعتمِد)؛ ولا يوجّه أي مسار شيفرة
بحسبهما. وحين يُضبطان معًا يفوز المرجعي. والإعدادات التي تتعذر قراءتها تُعدّ
معطّلة للكتابات.
تراجع آمن: ضبط documents.enabled=false يوقف الكتابات الدائمة الجديدة لكنه
يحفظ كل الكتل والمهام والبيانات الوصفية وملفات البيان. ولا تُحذف البيانات أبدًا
عند تعطيل الإطلاق.
الواجهات
Section titled “الواجهات”| الواجهة | المدخل |
|---|---|
| واجهة الويب | /documents — الرفع، والمكتبة، والتفاصيل، ولوحة التشغيل (تجربة GC جافة + تأكيد) |
| الإعدادات | /settings?tab=documents — الإطلاق الحي، والاستلام، وOCR، والبرمجيات الخبيثة، وGC، والعمّال |
| REST | /api/documents/* — انظر مسارات API |
| أدوات الوكيل | document_import، وdocument_read، وdocument_index، … (مهارة document-platform) |
| دردشة البوابة | /documents أو /docs — السرد، والحالة، والقراءة، والتحويل، وpdf-info، والحجب، والبحث، والصحة |
| واجهة الطرفية | تبويب المستندات (السرد والمعاينة عبر API الويب) |
| الاعتماد | python scripts/certify_documents.py |
الاعتماد
Section titled “الاعتماد”يبلّغ المُعتمِد عمّا شغّله فعلًا على هذا الجهاز، مع النمط المضبوط:
python scripts/certify_documents.py # CI smokepython scripts/certify_documents.py --soak # Extended smoke (100 iterations), not a multi-day soakpython scripts/certify_documents.py --output report.json| الفحص | ما هو | الحالة التي يمكن أن يبلغها |
|---|---|---|
hostile_corpus | الحالات العدائية الـ 26 الملتزم بها، كلٌّ منها مرفوض أو مسيَّج كما هو مُعلَن | PASS / FAIL |
bounded_performance_event_loop_resources | تحليلات متكررة بحدود للمدة ولتوقف حلقة الأحداث وللذاكرة | PASS / FAIL |
runtime_capabilities | جاهزية المحلّل وOCR والمُعرِض والمُعدِّل | CONDITIONAL حين يغيب محرّك اختياري، وFAIL حين لا يكون أي محلّل جاهزًا |
safe_rollout | وضع الإطلاق الحي | CONDITIONAL في الوضع المرجعي أو المعطّل |
worker_isolation | نمط العزل المضبوط | process دائمًا CONDITIONAL؛ وcontainer يكون PASS حين يكون الوسيط جاهزًا ولم تُبنَ صورته من شيفرة مستندات أخرى، وإلا FAIL؛ والنمط غير الصالح FAIL |
extraction_fidelity | مجموعة الدقة مقابل أهداف الإصدار | CONDITIONAL ما دامت أي حالة دون الهدف أو تتعذر قياسها (اليوم: ثلاث حالات دونه) |
backup_restore_sqlite | مستند جاهز واحد يُنسخ احتياطيًا ويُتحقَّق منه ويُستعاد ويُقرأ ثانيةً | PASS / FAIL |
postgres_multi_replica، metadata_multi_replica، multi_day_soak، external_security_review | لا يجريها تشغيل محلي | دائمًا NOT RUN |
ويسمّي التقرير أيضًا نمط العزل، وصورة العامل، والواجهات الخلفية المضبوطة للبيانات الوصفية/المهام، ولا تكون حالته الإجمالية أفضل من CONDITIONAL ما دام أي فحص CONDITIONAL أو NOT RUN.
تُولَّد المجموعة العدائية برمجيًا — لا ملفات ثنائية معتمة في
المستودع. لكل حالة وصف مراجَع، وتصرّف متوقع
(رفض/تسييج)، ورموز أخطاء متوقعة. ويُتحقَّق من ملف البيان الملتزم به تحت
tests/fixtures/documents/hostile_manifest.json وقت الإصدار.
دقة الاستخراج (documents/fidelity.py، والعتبات في
tests/fixtures/documents/fidelity_thresholds.json): مجموعة ذات إصدارات مبنية
بمحرّكات كاظمه نفسها — DOCX وPDF وHTML بالإنجليزية والعربية وثنائية اللغة،
ومستندات طويلة، وعمودان من مُنتِج آخر، وجداول عريضة، وصفحات OCR (عادية، وبجدول
مسطّر، ومسح متدهور) — تُقاس على المحلّل الحقيقي من حيث استرجاع الكلمات والمقاطع
والأرقام وخلايا الجداول، وترتيب القراءة، وصدق الصفحات، والمحاذاة، وCER/WER
للتعرّف الضوئي. وللإصدار 5 من المجموعة 19 حالة (أدخل الإصدار 4 عناصر الصفحة
الثابتة في مرجع OCR؛ ويعدّ الإصدار 5 علامات الترقيم). وتُقاس حالات OCR الخمس بكل
محرّك مقابل أرضياته الخاصة: مع المحرّك العصبي تبلغ الحالات 19 كلها أهداف
الإصدار؛ ومع Tesseract 16. غير مؤهَّلة مع Tesseract: ar-ocr وar-ocr-table (لا
تُقرأ الأرقام العربية الهندية) وen-ocr-degraded (قُرئ 3.75 على أنه 3:75). ويعيد python scripts/document_fidelity.py
قياسها بكل محرّك مثبّت هنا.
ملاحظة: بوابات البنية وإمكانية الوصول ومصفوفة الانهيار الكاملة تعيش في
tests/test_document_certification_phase10.py. ولاستعادة موت العمليات،
والاستيلاء على الاستلام، وتدريبات الاستعادة، ونمط الحاوية مجموعات اختبار خاصة بها
(انظر خريطة المراحل).
انظر خريطة المراحل وتقرير التدقيق في المستودع
docs/audits/AUDIT_DOCUMENT_CERTIFICATION.md (ليس جزءًا من شجرة Docusaurus).
تعدد النسخ
Section titled “تعدد النسخ”| الطبقة | الواجهة الخلفية | متعدد النسخ؟ |
|---|---|---|
| المطالبة بالمهام | Postgres حين يكون المجمّع قائمًا (jobs_pg.py) | نعم — SELECT … FOR UPDATE SKIP LOCKED |
| البيانات الوصفية (المستندات/النسخ/الكتل/المخرجات/المقاطع) | تتبع واجهة المهام الخلفية افتراضيًا (auto)؛ ويفرضها KAZMA_DOCUMENTS_METADATA_BACKEND=sqlite أو postgres (repository_pg.py) | نعم حين تكون بيانات Postgres الوصفية نشطة |
| قبول الاستلام | حجوزات في قاعدة بيانات المهام؛ ويُستولى على عقد الإيجار المنقضي ويُسيَّج مالكه | نعم على مهام Postgres |
| كتل المحتوى | شجرة معنونة بالمحتوى تحت documents.storage_root | يلزم نظام ملفات / وحدة تخزين مشتركة بين النسخ |
| وسم/كنس GC | مستقل عن الواجهة الخلفية — يوجّه retention._mark إلى repository.gc_mark الذي تنفذه الواجهتان | نعم |
هذا ما بُنيت كل واجهة خلفية من أجله. أما تشغيل عدة نسخ فليس مؤهَّلًا: يبلّغ
المُعتمِد عن postgres_multi_replica وmetadata_multi_replica بوصفهما NOT RUN،
وتُحسب خانات تخزين الرفع المؤقت لكل عملية. وتبلّغ الجاهزية عن بيانات SQLite
الوصفية بأنها أحادية النسخة كلما كانت هي الواجهة الخلفية العاملة.
البيئة:
| المتغير | القيم | الأثر |
|---|---|---|
KAZMA_DOCUMENTS_JOBS_BACKEND | auto (افتراضي) / sqlite | فرض مهام SQLite، أو اتباع Postgres المنصة |
KAZMA_DOCUMENTS_METADATA_BACKEND | auto / sqlite / postgres | auto يتبع واجهة المهام الخلفية |
الفحص: GET /api/documents/ops/readiness ← jobs_multi_replica، وmetadata_multi_replica، وdegraded_reasons
(وأيضًا worker_isolation، وstranded_intake_reservations، وpolicy، وmalware،
وaccepting_durable_writes).
التثبيت والتفعيل
Section titled “التثبيت والتفعيل”إضافات Python
Section titled “إضافات Python”# Simple PDF/DOCX/XLSX generators only (legacy skill)pip install -e ".[document]"
# Full platform engines (OCR helpers, WeasyPrint, PyMuPDF, pypdfium2 bake-off)pip install -e ".[document-platform]"
# The neural OCR engine: its packages (part of the ocr extra, which# document-platform includes), then its models, oncepip install -e ".[ocr]"python scripts/ocr_models.py install
# Everythingpip install -e ".[all]"حزم النظام (اختيارية)
Section titled “حزم النظام (اختيارية)”| الحزمة | الغرض |
|---|---|
Tesseract + حزم اللغات (eng، ara، …) | OCR (المسوحات / طبقة النص السيئة؛ وara لازمة للمسوحات العربية؛ وeng تخدم أيضًا مرور الأرقام فقط لخلايا الجداول)؛ وهو أيضًا القارئ الثالث في تصويت الحروف لدى المحرّك العصبي |
ClamAV (clamscan / clamdscan على PATH) | فحص البرمجيات الخبيثة عند الاستلام |
| LibreOffice | تحليل ملفات .doc / .xls / .ppt القديمة، وبعض تحويلات الصيغ، ومسار توليد PDF للمستندات التي تحوي العربية |
| خطوط النظام | WeasyPrint من HTML إلى PDF (يُشحن IBM Plex Sans Arabic وAmiri مع كاظمه للمستندات المولَّدة) |
في نمط container تأتي هذه من صورة العامل
(deploy/document-worker/Dockerfile)، لا من المضيف — بما فيها محرّك OCR العصبي
ونماذجه (مرحلة بناء ocr-models تنزّلها وتحوّلها؛ والعامل بلا شبكة).
نماذج محرّك OCR العصبي
Section titled “نماذج محرّك OCR العصبي”ينزّل python scripts/ocr_models.py install أربعة ملفات مثبّتة بعنوان URL والحجم
وSHA-256 في documents/ocr/neural_models.py (كشف PP-OCRv5 والتعرّف العربي من
PaddleOCR بصيغة تحويلات RapidAI إلى ONNX، وarabic_g1 وenglish_g2 من EasyOCR)،
ويحوّل نموذجَي EasyOCR من PyTorch إلى ONNX ويتحقق من التحويل مقابل PyTorch على
مدخلات ثابتة، ويكتبها مع manifest.json في KAZMA_OCR_MODEL_DIR (افتراضيًا
<data dir>/models/ocr، نحو 240 MB، لا يُنسخ احتياطيًا ولا يُحمل في حزمة: بل
يُعاد تثبيته). ويحتاج التحويل إلى PyTorch مرة واحدة: فحين يخلو منه المفسّر يشغّله
البرنامج في بيئة مؤقتة تُرمى بعده عبر uv، ولا يُضاف شيء إلى بيئة كاظمه نفسها.
ويتحقق python scripts/ocr_models.py verify من مجموعة مثبّتة. ولا يستخدم عامل
المستندات النماذج إلا حين يطابق كل ملف ملف البيان، ولا ينزّل أي شيء أبدًا.
جولة المشغّل الأولى
Section titled “جولة المشغّل الأولى”- شغّل كاظمه وافتح
/documents. - (اختياري) الإعدادات ← المستندات — اترك
enabled، واضبط البرمجيات الخبيثة علىautoأوonإن كان ClamAV مثبّتًا. - ارفع ملف PDF صغيرًا أو
.txt← انتظر الحالةready. - عاين المحتوى (آمن ثنائي الاتجاه مع
dir="auto"). - اضبط
library_id← فهرسة ← ابحث عبر الواجهة/API/document_search. - لوحة التشغيل: السعة، والجاهزية، والتدقيق؛ وGC = تجربة جافة ثم تأكيد.
- اختبار دخان الاعتماد:
python scripts/certify_documents.py
الدردشة والوكيل
Section titled “الدردشة والوكيل”- أرفق ملف PDF في الدردشة ← مقتطف من طبقة نصه (مسيَّج) حين يتوفر محلّل. ولا يمر الملف الممسوح بالتعرّف الضوئي قبل أن يرى النموذج الرسالة: يُخبَر النموذج بأنه ممسوح، وبعدد صفحاته، وبالأدوات التي تقرؤه.
- أدوات الوكيل:
document_import(مسار في مساحة العمل)، وdocument_read، وdocument_index، … - البوابة:
/documents list،/documents read <id>، …
الصيغ المدعومة (المعتادة)
Section titled “الصيغ المدعومة (المعتادة)”| النوع | أمثلة | ملاحظات |
|---|---|---|
| نص / بيانات | .txt، .md، .markdown، .log، .csv، .tsv، .json، .html، .htm، .rtf | الفحص + محلّلات النص (UTF-8 صارم) |
| Office OOXML | .docx، .xlsx، .pptx | دفاعات بنيوية قبل التحليل؛ وتُرفض الامتدادات المفعَّل فيها الماكرو |
| Office القديم | .doc، .xls، .ppt | يحوّلها LibreOffice داخل العامل، ثم تُحلَّل |
.pdf | ترفض سياسة المحتوى النشط في PDF الملفات المشفّرة، والسكربت، والأفعال الخارجية، والملفات المضمّنة | |
| الصور | .png، .jpg، .jpeg، .tif، .tiff، .bmp، .webp | مسار OCR حين يكون مفعّلًا |
تُبلَّغ الجاهزية الدقيقة لكل محلّل/مُعرِض في GET /api/documents/health.
فحص البرمجيات الخبيثة
Section titled “فحص البرمجيات الخبيثة”يفحص الاستلام البايتات المحجورة عبر documents.security.malware_scan:
| الوضع | السلوك |
|---|---|
auto (افتراضي) | يفحص إن كان ClamAV على PATH؛ وإلا يتخطى (ما لم يكن الفشل مغلقًا). ويُعامَل خطأ الماسح بوصفه تخطيًا ما لم يكن الفشل مغلقًا |
on | يشترط ماسحًا يعمل |
off | لا يفحص أبدًا |
يجعل documents.security.malware_fail_closed الوضع auto يشترط ماسحًا هو الآخر؛
وهو مفعّل افتراضيًا حين KAZMA_PRODUCTION=1. وحين يتعذر تشغيل ماسح مطلوب، يُرفض
الرفع الجديد بـ malware_scanner_unavailable وتبلّغ الجاهزية
accepting_durable_writes: false؛ أما المهمة المنتظرة أصلًا في الطابور (فهي
تُفحص مجددًا قبل التحليل، وفق سياسة اليوم) فتُحتجز وتُعاد محاولتها، ثم تُحال إلى
الرسائل الميتة — ولا تُرفض أبدًا كأن محتواها غير آمن. الملفات المصابة ← رمز الخطأ
malware_detected. انظر أمان المستندات.
استكشاف الأخطاء
Section titled “استكشاف الأخطاء”| العَرَض | افحص |
|---|---|
| الرفع 413 / 429 / 503 / 507 | حدود السعة؛ الإعدادات أو لقطة سعة لوحة التشغيل |
الرفع 409 intake_taken_over | تجاوز الرفع عقد إيجاره فجرى التراجع عنه؛ أرسله مجددًا |
كل عملية 503 document_policy_unavailable | تتعذر قراءة إعدادات المستندات المحفوظة أو أحدها غير صالح؛ أصلح الإعداد |
مهام تعيد المحاولة أو تفشل بـ worker_isolation_* | _unavailable / _busy (تُعاد محاولتها): وسيط نمط container متوقف أو غير مُصدَّق أو ممتلئ. _required: التثبيت يشترط نمط الحاوية. _invalid: نمط مكتوب خطأً. وتقول جاهزية worker_isolation أيّها |
| الحالة عالقة / dead_letter | أحداث المهمة؛ هل العامل يعمل؛ GET /api/documents/health؛ وجاهزية stranded_intake_reservations |
| معاينة فارغة | لم يصل إلى ready بعد؛ رمز فشل المحلّل على المهمة |
| التحويل/الحجب 422/503 | محرّك اختياري غائب — ثبّت document-platform + تبعيات النظام (أو صورة العامل، في نمط container) |
| رفوض برمجيات خبيثة غير متوقعة | إيجابية كاذبة من ClamAV، أو ماسح مطلوب (on، أو الفشل المغلق في الإنتاج) يتعذر تشغيله |
| غرابة تعدد النسخ | ops/readiness؛ ووحدة الكتل المشتركة؛ وتشغيل عدة نسخ غير مؤهَّل |
| 404 بين المستأجرين | متوقع — ACL المستأجر/الفاعل؛ والمهمة التي لا تُقرأ تجيب كمهمة مجهولة |
مزيد من تفاصيل التشغيل: معالجة المستندات.
الحدود في لمحة
Section titled “الحدود في لمحة”| المورد | الافتراضي | مفتاح ConfigStore الأساسي |
|---|---|---|
| أقصى حجم للملف | 50 MiB | documents.intake.max_bytes |
| أقصى ملفات للطلب | 10 | documents.intake.max_files |
| أقصى صفحات | 500 | documents.limits.max_pages |
| أقصى صفوف للورقة | 100,000 | documents.limits.max_rows_per_sheet |
| أقصى خلايا | 2,000,000 | documents.limits.max_cells |
| أقصى بايتات بعد الفك | 256 MiB | documents.limits.max_expanded_bytes |
| أقصى أعضاء الأرشيف | 10,000 | documents.limits.max_archive_members |
| دقة OCR (DPI) | 200 | documents.ocr.dpi |
| مهلة العامل | 300 ث | documents.workers.timeout_seconds |
| ذاكرة العامل | 1 GiB | documents.workers.memory_mb |
| حصة المستأجر | 10 GiB | documents.quotas.tenant_bytes |
| استبقاء التدقيق | 365 يومًا | documents.retention.audit_days |
| أرضية المساحة الحرة للتخزين | 512 MiB | documents.capacity.storage_free_floor_bytes |
| رفوع الويب المتزامنة | 4 لكل عملية | documents.capacity.max_concurrent_uploads |
| عقد إيجار الاستلام | 300 ث | documents.intake.lease_seconds |
| خلايا الجداول المقروءة لكل صفحة ممسوحة | 600 خلية / 120 ث | ثابت (documents/ocr/pipeline.py) |
| صفحات التعرّف الضوئي في كل تشغيل للعامل | بقدر ما يتسع له حد التشغيل (12 على الأكثر) | ثابت (documents/service.py) |
| محرّك OCR | auto | documents.ocr.engine (auto، neural، tesseract) |
| جسم طلب JSON | 2 MiB | ثابت (documents_api.py) |
| حمولة التوليد | 1 MiB | ثابت (ingestion.py) |
| جواب التحليل البعيد | 32 MiB | ثابت (extract_salvage.py) |
قائمة الحقول الكاملة: kazma_core.documents.config.DocumentConfig (75 حقلًا).
ما ليس مؤهَّلًا
Section titled “ما ليس مؤهَّلًا”هذه حدود مُعلَنة للإصدار الحالي، مأخوذة من الشيفرة والمُعتمِد ومجموعة الدقة — لا خطط:
- المستندات العدائية على نمط
processالافتراضي. فهو يحدّ الذاكرة والمعالج والوقت لكنه لا يحصر نظام الملفات ولا الشبكة. ولا يفعل ذلك إلا نمطcontainer، وحاوياته تتشارك نواة المضيف. - التعرّف الضوئي مع Tesseract: العربية (
ar-ocr،ar-ocr-table: لا تُقرأ الأرقام العربية الهندية) والأرقام من المسوحات المتدهورة (en-ocr-degraded: قُرئ 3.75 على أنه 3:75). ومع المحرّك العصبي تبلغ كل حالة OCR في المجموعة أهداف الإصدار، لكن المسوحات الحقيقية قيست على مسح واحد فقط (تفوّق فيه على Tesseract في معظم الصفحات وخسر في بعض الكلمات). والجداول بلا خطوط تسطير والخلايا المدموجة لا تُقرأ خليةً خلية. - تشغيل عدة نسخ (فحصا
postgres_multi_replicaوmetadata_multi_replicaلدى المُعتمِد هما NOT RUN). - التشغيل المستدام: نجح اختبار تحمّل واحد بحمل مختلط لمدة 48 ساعة
(
scripts/document_soak.py، من 2026-10-17 إلى 2026-10-19، مضيف Windows واحد، ومخازن SQLite خاصة، ونمطprocess): 12,865 مستندًا أُرسلت واكتملت، و190 إعادة تشغيل، و143 انهيارًا مُحقنًا، ولا أخطاء، ولا ملفات مؤقتة متبقية؛ و4.5 مستندات في الدقيقة (يفحص ClamAV كل رفع)، وp95 14.1 s. ولم يُختبر تحمّل Postgres ولا نمطcontainer. ولا يزال--soakلدى المُعتمِد اختبار دخان ممتدًا. - مراجعة أمنية مستقلة: مراجعة واحدة لملف أمان المستندات (2026-10-15،
docs/audits/Q04_REVIEW_RESULTS_2026-10-15.md): صمد 13 ادعاءً من 14، والملاحظة الوحيدة (FIND-01) أُصلحت وأكّدها اختبار المراجع المُعاد. وقد غطّت مضيف Windows Docker Desktop واحدًا؛ وكان خارج نطاقها نمطprocessبوصفه دفاعًا ضد المستندات العدائية، والإشراف على Linux، وتعدد النسخ، والحمل المستدام. ولا يزالexternal_security_reviewلدى المُعتمِد يقرأ NOT RUN: فالتشغيل المحلي لا يستطيع إجراء مراجعة كهذه. - أهداف نقطة الاستعادة وزمن الاستعادة لنشر معيّن: تقيسها تدريبات الاستعادة؛ ولا يُوعَد بأي رقم.
- إنقاذ Docling في نمط
container: ليس في صورة العامل.

