This page was machine-translated. Spotted a mistake?Help improve it.
Skip to content

البنية

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 البرمجية لعمليات التعلّم الآلي. عند أول استخدام، يبدأ الجسر عملية موزِّع Python دائمة تستورد مسبقًا المكتبات الثقيلة (PIL وNumPy وMediaPipe وrembg) بحيث تتخطّى استدعاءات الذكاء الاصطناعي اللاحقة كلفة الاستيراد. إذا لم يكن الموزِّع جاهزًا بعد، يتراجع الجسر إلى إطلاق عملية Python فرعية جديدة لكل طلب.

النماذج لا تُحمَّل مسبقًا. يحمّل كل نص أداة أوزان نموذجه من القرص عند وقت الطلب ويتخلّص منها عند انتهاء الطلب. راجع بصمة الموارد للاطلاع على ملف الذاكرة الكامل.

العمليات المدعومة: إزالة الخلفية (rembg/BiRefNet)، والتكبير (RealESRGAN)، وطمس الوجوه (MediaPipe)، وتحسين الوجوه (GFPGAN/CodeFormer)، ومسح الكائنات (LaMa ONNX)، وOCR (PaddleOCR/Tesseract)، والتلوين (DDColor)، وإزالة التشويش، وإزالة العين الحمراء، وترميم الصور، وإنشاء صور جواز السفر، وإصلاح الشفافية (مَطّ BiRefNet عالي الدقة)، وتغيير الحجم المدرك للمحتوى (ثنائي caire المكتوب بلغة Go).

توجد نصوص Python البرمجية في packages/ai/python/. تنزّل صورة Docker مسبقًا جميع أوزان النماذج أثناء البناء لتعمل الحاوية دون اتصال بالكامل.

@snapotter/shared

أنواع TypeScript المشتركة، والثوابت (مثل APP_VERSION وتعريفات الأدوات)، وسلاسل ترجمة i18n المستخدمة من الواجهتين الأمامية والخلفية معًا.

التطبيقات

API (apps/api)

خادم Fastify v5 يكشف 241 مسار أداة عبر خمس وسائط (الصور، والفيديو، والصوت، وPDF، والملف) ويتولى:

  • رفع الملفات، وإدارة مساحة العمل المؤقتة، وتخزين الملفات الدائم
  • مكتبة ملفات المستخدم بسلاسل نُسَخ (جدول user_files) - كل نتيجة معالَجة تربط بملفها المصدري وتسجّل الأداة المُطبَّقة، مع مصغّرات مُولَّدة تلقائيًا لصفحة الملفات
  • تنفيذ الأدوات (يوجّه كل طلب أداة إلى محرك الصور أو جسر الذكاء الاصطناعي)
  • تنسيق خطوط الأنابيب (ربط أدوات متعددة بالتتابع)
  • المعالجة الدفعية مع التحكم في التزامن عبر طوابير مهام 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.

كيف يتدفّق الطلب

  1. يختار المستخدم أداة في واجهة الويب ويرفع ملفًا.
  2. ترسل الواجهة الأمامية طلب POST متعدد الأجزاء إلى /api/v1/tools/:section/:toolId مع الملف والإعدادات.
  3. يتحقق مسار API من المُدخَل بواسطة Zod، ثم يوزّع المعالجة.
  4. بالنسبة للأدوات القياسية، تُدرَج المهمة في مجمّع BullMQ المناسب (image أو media أو docs بحسب الوسيط). يوجّه عامل BullMQ داخل العملية الصورة تلقائيًا بناءً على البيانات الوصفية EXIF، ويشغّل دالة معالجة الأداة، ويعيد النتيجة.
  5. بالنسبة لأدوات الذكاء الاصطناعي، يرسل جسر TypeScript طلبًا إلى موزِّع Python الدائم (أو يطلق عملية فرعية جديدة كخيار احتياطي)، وينتظر انتهاءه، ويقرأ ملف الإخراج.
  6. يُحفَظ تقدّم المهمة في جدول jobs في PostgreSQL بحيث تبقى الحالة عبر إعادة تشغيل الحاوية. تُسلَّم التحديثات في الوقت الفعلي عبر SSE في /api/v1/jobs/:jobId/progress.
  7. يعيد 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 فرعية لمرة واحدة. وحالما يشير الموزِّع إلى جاهزيته، تستخدمه كل طلبات الذكاء الاصطناعي اللاحقة مباشرة وتتخطّى كلفة إطلاق العملية الفرعية.