Closes #578. Rewrites the user file library save-mode description in the English database.md and architecture.md guides (independent-new by default, parent-linked on overwrite) and updates all 20 translated copies of each, with i18n_source_hash re-stamped so the parity gate stays green.
12 KiB
description, i18n_output_hash, i18n_source_hash, i18n_provenance
| description | i18n_output_hash | i18n_source_hash | i18n_provenance |
|---|---|---|---|
| بنية المستودع الأحادي، وبنية التطبيقات والحزم، ودورة حياة الطلب، وبصمة الموارد الخاصة بـ SnapOtter. | 879baf70cf3d | a53946e760b0 | human |
البنية
SnapOtter مستودع أحادي مُدار بمساحات عمل pnpm وTurborepo. يُنشَر كحزمة Docker Compose من 3 حاويات: صورة تطبيق SnapOtter، وPostgreSQL 17، وRedis 8.
بنية المشروع
snapotter/
├── apps/
│ ├── api/ # Fastify backend
│ ├── web/ # React + Vite frontend
│ └── docs/ # This VitePress site
├── packages/
│ ├── image-engine/ # Sharp-based image operations
│ ├── media-engine/ # FFmpeg spawn + progress parsing
│ ├── doc-engine/ # qpdf, LibreOffice, ghostscript wrappers
│ ├── ai/ # Python AI model bridge
│ └── shared/ # Types, constants, i18n
└── docker/ # Dockerfile and Compose config
الحزم
@snapotter/image-engine
مكتبة معالجة الصور الأساسية المبنية على Sharp. تتولى جميع العمليات غير المعتمدة على الذكاء الاصطناعي: تغيير الحجم، والقصّ، والتدوير، والقلب، والتحويل، والضغط، وإزالة البيانات الوصفية، وتعديلات الألوان (السطوع، والتباين، والتشبّع، والتدرّج الرمادي، والسيبيا، والعكس، وقنوات الألوان).
ليس لهذه الحزمة أي اعتماديات شبكية وتعمل بالكامل داخل العملية نفسها.
@snapotter/ai
طبقة جسر تستدعي أوقات التشغيل الأصلية و Python ML. تستخدم معظم أدوات Python dispatcher المستمر الذي يقوم باستيراد المكتبات الثقيلة مسبقًا (PIL، وNumPy، وMediaPipe، وrembg) بحيث تتخطى الاستدعاءات اللاحقة عبء الاستيراد. OCR معزول عن تلك البيئة المشتركة القابلة للتغيير: يستدعي fast Tesseract الأصلي، بينما يستخدم balanced وbest JSONL dispatcher المستمر المخصص والمثبت على الجيل النشط غير القابل للتغيير RapidOCR/ONNX. يحمل كل طلب generation lease. يقوم التنشيط أولاً بتشغيل smoke test على أحد المرشحين، ثم يتحول ذريًا إلى dispatcher الخاص به. يستنزف dispatcher السابق قبل أن يتم تجميع البيانات المهملة.
النماذج لا تُحمَّل مسبقًا. يحمّل كل نص أداة أوزان نموذجه من القرص عند وقت الطلب ويتخلّص منها عند انتهاء الطلب. راجع بصمة الموارد للاطلاع على ملف الذاكرة الكامل.
العمليات المدعومة: إزالة الخلفية (rembg/BiRefNet)، والترقية (RealESRGAN)، وطمس الوجه (MediaPipe)، وتحسين الوجه (GFPGAN/CodeFormer)، ومحو الكائنات (LaMa ONNX)، و OCR (Tesseract و RapidOCR مع نماذج PP-OCR ONNX)، والتلوين (DDColor)، والضوضاء الإزالة، وإزالة العين الحمراء، واستعادة الصور، وإنشاء صور جواز السفر، وتثبيت الشفافية (BiRefNet HR-matting)، وتغيير الحجم مع مراعاة المحتوى (Go caire ثنائي).
البرامج النصية Python موجودة في packages/ai/python/. يتم تثبيت حزم النماذج الاختيارية الكبيرة عند الطلب في وحدة تخزين /data/ai المستمرة. يستخدم OCR الدقيق عناصر موقعة خاصة بالمنصة؛ لا تتطلب طبقة Tesseract المدمجة تنزيل حزمة النموذج.
@snapotter/shared
أنواع TypeScript المشتركة، والثوابت (مثل APP_VERSION وتعريفات الأدوات)، وسلاسل ترجمة i18n المستخدمة من الواجهتين الأمامية والخلفية معًا.
التطبيقات
API (apps/api)
خادم Fastify v5 يكشف 241 مسار أداة عبر خمس وسائط (الصور، والفيديو، والصوت، وPDF، والملف) ويتولى:
- رفع الملفات، وإدارة مساحة العمل المؤقتة، وتخزين الملفات الدائم
- مكتبة ملفات المستخدم (جدول
user_files): يُخزَّن التعديل المحفوظ افتراضيًا كملف جديد مستقل، أو كإصدار مرتبط بالأب عند الكتابة فوق الأصل. تسجّل الأدوات المطبَّقة (toolChain) وتحصل على مصغّر مُولَّد تلقائيًا لصفحة الملفات - تنفيذ الأدوات (يوجّه كل طلب أداة إلى محرك الصور أو جسر الذكاء الاصطناعي)
- تنسيق خطوط الأنابيب (ربط أدوات متعددة بالتتابع)
- المعالجة الدفعية مع التحكم في التزامن عبر طوابير مهام BullMQ (المجمّعات: image، media، ai، docs، system)
- مصادقة المستخدم، وRBAC (أدوار المسؤول/المستخدم مع مجموعة أذونات كاملة)، وإدارة مفاتيح API، وتحديد المعدل
- إدارة الفرق - إنشاء/قراءة/تحديث/حذف للمسؤول فقط؛ يُسنَد المستخدمون إلى فريق عبر حقل
teamفي ملفهم الشخصي - إعدادات وقت التشغيل - مخزن مفتاح-قيمة في جدول
settingsيتحكم فيdisabledToolsوenableExperimentalToolsوloginAttemptLimitومقابض تشغيلية أخرى دون إعادة نشر - علامة تجارية مخصّصة وتفضيلات وقت تشغيل عبر إعدادات مدعومة بقاعدة البيانات
- توثيق Scalar/OpenAPI في
/api/docs - تقديم الواجهة الأمامية المبنية كتطبيق صفحة واحدة في الإنتاج
الاعتماديات الأساسية: Fastify، وDrizzle ORM (pg-core، node-postgres)، وSharp، وBullMQ، وioredis، وZod للتحقق.
يتولى الخادم الإيقاف الأنيق عند SIGTERM/SIGINT: يصرّف اتصالات HTTP، ويوقف عمّال BullMQ، ويوقف موزِّع Python، ويغلق اتصال قاعدة البيانات.
Web (apps/web)
تطبيق React 19 من صفحة واحدة مبني بـ Vite. يستخدم Zustand لإدارة الحالة، وTailwind CSS v4 للتنسيق، وLucide للأيقونات. يتواصل مع API عبر REST وSSE (لتتبّع التقدّم).
تتضمن الصفحات مساحة عمل للأدوات، وصفحة ملفات لإدارة عمليات الرفع والنتائج الدائمة، وأداة بناء أتمتة/خطوط أنابيب، ولوحة إعدادات المسؤول.
تُقدَّم الواجهة الأمامية المبنية بواسطة الواجهة الخلفية Fastify في الإنتاج، لذا لا يوجد خادم ويب منفصل في حاوية Docker.
Docs (apps/docs)
هذا موقع VitePress. يُنشَر إلى Cloudflare Pages تلقائيًا عند الدفع إلى main.
كيف يتدفّق الطلب
- يختار المستخدم أداة في واجهة الويب ويرفع ملفًا.
- ترسل الواجهة الأمامية طلب POST متعدد الأجزاء إلى
/api/v1/tools/:section/:toolIdمع الملف والإعدادات. - يتحقق مسار API من المُدخَل بواسطة Zod، ثم يوزّع المعالجة.
- بالنسبة للأدوات القياسية، تُدرَج المهمة في مجمّع BullMQ المناسب (image أو media أو docs بحسب الوسيط). يوجّه عامل BullMQ داخل العملية الصورة تلقائيًا بناءً على البيانات الوصفية EXIF، ويشغّل دالة معالجة الأداة، ويعيد النتيجة.
- بالنسبة لمعظم أدوات الذكاء الاصطناعي، يرسل جسر TypeScript طلبًا إلى Python dispatcher المستمر. بدلاً من ذلك، يستدعي OCR السريع Tesseract، ويبدأ OCR الدقيق الملف القابل للتنفيذ المثبت من جيل OCR النشط غير القابل للتغيير. يتم تثبيت طبقة OCR المطلوبة عند الدخول ولا يتم تغييرها أبدًا بصمت أثناء التنفيذ.
- يُحفَظ تقدّم المهمة في جدول
jobsفي PostgreSQL بحيث تبقى الحالة عبر إعادة تشغيل الحاوية. تُسلَّم التحديثات في الوقت الفعلي عبر SSE في/api/v1/jobs/:jobId/progress. - يعيد API
jobIdوdownloadUrl. ينزّل المستخدم الملف المعالَج من/api/v1/download/:jobId/:filename.
بالنسبة لخطوط الأنابيب، يغذّي API مُخرَج كل خطوة كمُدخَل للخطوة التالية، ويشغّلها بالتتابع.
بالنسبة للمعالجة الدفعية، يستخدم API تدفّقات BullMQ مع مهام فرعية لكل خطوة ويعيد ملف ZIP يضمّ جميع الملفات المعالَجة.
بصمة الموارد
صُمِّم SnapOtter لاستهلاك ذاكرة منخفض عند الخمول. لا شيء يُحمَّل مسبقًا أو يُبقى دافئًا عند البدء.
عند الخمول
تعمل عملية Node.js/Fastify، وPostgreSQL، وRedis. ذاكرة الخمول المعتادة نحو 200-300 ميغابايت عبر الحاويات الثلاث جميعها (عملية Node.js، وPostgres، وRedis). لا عملية Python، ولا أوزان نماذج في الذاكرة.
ما الذي يبدأ، ومتى
| المكوّن | يبدأ عند | الذاكرة أثناء النشاط |
|---|---|---|
| خادم Fastify + Postgres + Redis | بدء الحاوية | نحو 200-300 ميغابايت إجمالًا |
| عمّال BullMQ | بدء الحاوية (داخل العملية) | عامل واحد لكل مجمّع (image، media، ai، docs، system) |
| موزِّع Python | أول طلب أداة ذكاء اصطناعي | مفسّر Python + المكتبات المستوردة مسبقًا (PIL، NumPy، MediaPipe، rembg) - دون أوزان نماذج |
| أوزان نماذج الذكاء الاصطناعي | أثناء طلب الأداة المحدّدة | تُحمَّل من القرص، وتُحرَّر عند انتهاء الطلب |
تحميل النماذج
كل ملفات أوزان النماذج (بإجمالي عدة غيغابايت) تقيم على القرص في /opt/models/ طوال الوقت. يحمّل كل نص أداة ذكاء اصطناعي نموذجه (نماذجه) وحدها إلى الذاكرة طوال مدة الطلب، ثم يحرّرها. تستدعي بعض النصوص صراحةً del model وtorch.cuda.empty_cache() بعد الاستدلال لضمان إعادة الذاكرة فورًا.
لا توجد ذاكرة تخزين مؤقت للنماذج بين الطلبات. تشغيل أداة الذكاء الاصطناعي نفسها بالتتابع يعيد تحميل النموذج في كل مرة. يبقي هذا ذاكرة الخمول قرب الصفر مقابل تأخير تحميل النموذج في كل طلب ذكاء اصطناعي.
بدء بارد لأول طلب ذكاء اصطناعي
موزِّع Python لا يعمل عند بدء الحاوية. يطلق أول طلب ذكاء اصطناعي أمرين بالتوازي: يبدأ الموزِّع بالإحماء في الخلفية، ويتراجع الطلب نفسه إلى إطلاق عملية Python فرعية لمرة واحدة. وحالما يشير الموزِّع إلى جاهزيته، تستخدمه كل طلبات الذكاء الاصطناعي اللاحقة مباشرة وتتخطّى كلفة إطلاق العملية الفرعية.