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

Architecture

SnapOtter एक मोनोरेपो है जिसे pnpm workspaces और Turborepo के साथ प्रबंधित किया जाता है। यह एक 3-कंटेनर Docker Compose स्टैक के रूप में परिनियोजित होता है: SnapOtter ऐप इमेज, PostgreSQL 17, और Redis 8।

Project structure

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

Packages

@snapotter/image-engine

Sharp पर बनी मुख्य इमेज प्रोसेसिंग लाइब्रेरी। यह सभी नॉन-AI ऑपरेशन संभालती है: resize, crop, rotate, flip, convert, compress, strip metadata, और रंग समायोजन (brightness, contrast, saturation, grayscale, sepia, invert, color channels)।

इस पैकेज की कोई नेटवर्क डिपेंडेंसी नहीं है और यह पूरी तरह इन-प्रोसेस चलता है।

@snapotter/ai

एक ब्रिज लेयर जो ML ऑपरेशन के लिए Python स्क्रिप्ट को कॉल करती है। पहले उपयोग पर, ब्रिज एक स्थायी Python डिस्पैचर प्रक्रिया शुरू करता है जो भारी लाइब्रेरी (PIL, NumPy, MediaPipe, rembg) को पहले से इम्पोर्ट कर लेता है ताकि बाद के AI कॉल इम्पोर्ट ओवरहेड को छोड़ दें। यदि डिस्पैचर अभी तैयार नहीं है, तो ब्रिज प्रति अनुरोध एक नई Python सबप्रोसेस स्पॉन करने पर वापस लौट आता है।

मॉडल पहले से लोड नहीं होते। प्रत्येक टूल स्क्रिप्ट अनुरोध के समय डिस्क से अपने मॉडल वेट लोड करती है और अनुरोध समाप्त होने पर उन्हें त्याग देती है। पूर्ण मेमोरी प्रोफ़ाइल के लिए Resource footprint देखें।

समर्थित ऑपरेशन: बैकग्राउंड हटाना (rembg/BiRefNet), अपस्केलिंग (RealESRGAN), चेहरा धुंधला करना (MediaPipe), चेहरा सुधार (GFPGAN/CodeFormer), ऑब्जेक्ट मिटाना (LaMa ONNX), OCR (PaddleOCR/Tesseract), कलराइज़ेशन (DDColor), नॉइज़ हटाना, रेड आई हटाना, फ़ोटो रीस्टोरेशन, पासपोर्ट फ़ोटो जनरेशन, पारदर्शिता फ़िक्सिंग (BiRefNet HR-matting), और कंटेंट-अवेयर रीसाइज़ (Go caire बाइनरी)।

Python स्क्रिप्ट packages/ai/python/ में रहती हैं। Docker इमेज बिल्ड के दौरान सभी मॉडल वेट पूर्व-डाउनलोड कर लेती है ताकि कंटेनर पूरी तरह ऑफ़लाइन काम करे।

@snapotter/shared

साझा TypeScript प्रकार, स्थिरांक (जैसे APP_VERSION और टूल परिभाषाएँ), और i18n अनुवाद स्ट्रिंग्स जो फ़्रंटएंड और बैकएंड दोनों द्वारा उपयोग की जाती हैं।

Applications

API (apps/api)

एक Fastify v5 सर्वर जो पाँच मोडैलिटी (image, video, audio, PDF, file) में 241 टूल रूट प्रकट करता है, जो निम्न को संभालता है:

  • फ़ाइल अपलोड, अस्थायी वर्कस्पेस प्रबंधन, और स्थायी फ़ाइल स्टोरेज
  • संस्करण श्रृंखलाओं के साथ उपयोगकर्ता फ़ाइल लाइब्रेरी (user_files तालिका) - प्रत्येक प्रोसेस किया गया परिणाम अपनी स्रोत फ़ाइल से वापस लिंक होता है और रिकॉर्ड करता है कि कौन सा टूल लागू किया गया था, Files पेज के लिए स्वतः-जनरेट किए गए थंबनेल के साथ
  • टूल निष्पादन (प्रत्येक टूल अनुरोध को इमेज इंजन या AI ब्रिज पर रूट करता है)
  • पाइपलाइन ऑर्केस्ट्रेशन (कई टूल को क्रमिक रूप से श्रृंखलाबद्ध करना)
  • BullMQ जॉब क्यू के माध्यम से समवर्तीता नियंत्रण के साथ बैच प्रोसेसिंग (पूल: image, media, ai, docs, system)
  • उपयोगकर्ता प्रमाणीकरण, RBAC (पूर्ण अनुमति सेट के साथ admin/user भूमिकाएँ), API कुंजी प्रबंधन, और रेट लिमिटिंग
  • Teams प्रबंधन - केवल-admin CRUD; उपयोगकर्ताओं को उनके प्रोफ़ाइल पर team फ़ील्ड के माध्यम से एक टीम को सौंपा जाता है
  • रनटाइम सेटिंग्स - settings तालिका में एक key-value स्टोर जो पुनः परिनियोजन के बिना disabledTools, enableExperimentalTools, loginAttemptLimit, और अन्य परिचालन नियंत्रण संभालता है
  • डेटाबेस-समर्थित सेटिंग्स के माध्यम से कस्टम ब्रांडिंग और रनटाइम प्राथमिकताएँ
  • /api/docs पर Scalar/OpenAPI दस्तावेज़ीकरण
  • प्रोडक्शन में निर्मित फ़्रंटएंड को एक SPA के रूप में सर्व करना

मुख्य डिपेंडेंसी: Fastify, Drizzle ORM (pg-core, node-postgres), Sharp, BullMQ, ioredis, सत्यापन के लिए Zod।

सर्वर SIGTERM/SIGINT पर सुशोभित शटडाउन संभालता है: यह HTTP कनेक्शन को खाली करता है, BullMQ वर्कर को रोकता है, Python डिस्पैचर को बंद करता है, और डेटाबेस कनेक्शन बंद करता है।

Web (apps/web)

Vite के साथ बनाया गया एक React 19 सिंगल-पेज ऐप। स्टेट प्रबंधन के लिए Zustand, स्टाइलिंग के लिए Tailwind CSS v4, और आइकन के लिए Lucide का उपयोग करता है। REST और SSE (प्रगति ट्रैकिंग के लिए) पर API के साथ संवाद करता है।

पेजों में एक टूल वर्कस्पेस, स्थायी अपलोड और परिणामों के प्रबंधन के लिए एक Files पेज, एक ऑटोमेशन/पाइपलाइन बिल्डर, और एक admin सेटिंग्स पैनल शामिल हैं।

निर्मित फ़्रंटएंड प्रोडक्शन में Fastify बैकएंड द्वारा सर्व किया जाता है, इसलिए Docker कंटेनर में कोई अलग वेब सर्वर नहीं है।

Docs (apps/docs)

यह VitePress साइट। main पर पुश होने पर स्वचालित रूप से Cloudflare Pages पर परिनियोजित।

How a request flows

  1. उपयोगकर्ता वेब UI में एक टूल चुनता है और एक फ़ाइल अपलोड करता है।
  2. फ़्रंटएंड फ़ाइल और सेटिंग्स के साथ /api/v1/tools/:section/:toolId पर एक multipart POST भेजता है।
  3. API रूट इनपुट को Zod के साथ सत्यापित करता है, फिर प्रोसेसिंग डिस्पैच करता है।
  4. मानक टूल के लिए, जॉब को उपयुक्त BullMQ पूल (मोडैलिटी के आधार पर image, media, या docs) में क्यू में डाला जाता है। इन-प्रोसेस BullMQ वर्कर EXIF मेटाडेटा के आधार पर इमेज को स्वतः-ओरिएंट करता है, टूल के प्रोसेस फ़ंक्शन को चलाता है, और परिणाम लौटाता है।
  5. AI टूल के लिए, TypeScript ब्रिज स्थायी Python डिस्पैचर को एक अनुरोध भेजता है (या फ़ॉलबैक के रूप में एक नई सबप्रोसेस स्पॉन करता है), इसके समाप्त होने की प्रतीक्षा करता है, और आउटपुट फ़ाइल पढ़ता है।
  6. जॉब प्रगति PostgreSQL में jobs तालिका में बनी रहती है ताकि स्टेट कंटेनर पुनरारंभ के दौरान बना रहे। वास्तविक समय अपडेट /api/v1/jobs/:jobId/progress पर SSE के माध्यम से वितरित किए जाते हैं।
  7. API एक jobId और downloadUrl लौटाता है। उपयोगकर्ता /api/v1/download/:jobId/:filename से प्रोसेस की गई फ़ाइल डाउनलोड करता है।

पाइपलाइनों के लिए, API प्रत्येक चरण के आउटपुट को अगले के इनपुट के रूप में फ़ीड करता है, उन्हें क्रमिक रूप से चलाता है।

बैच प्रोसेसिंग के लिए, API प्रति-चरण चाइल्ड जॉब के साथ BullMQ फ़्लो का उपयोग करता है और सभी प्रोसेस की गई फ़ाइलों के साथ एक ZIP फ़ाइल लौटाता है।

Resource footprint

SnapOtter को कम निष्क्रिय मेमोरी उपयोग के लिए डिज़ाइन किया गया है। स्टार्टअप पर कुछ भी पहले से लोड या गर्म नहीं रखा जाता।

At idle

Node.js/Fastify प्रक्रिया, PostgreSQL, और Redis चल रहे हैं। सामान्य निष्क्रिय RAM तीनों कंटेनरों में ~200-300 MB है (Node.js प्रक्रिया, Postgres, और Redis)। कोई Python प्रक्रिया नहीं, मेमोरी में कोई मॉडल वेट नहीं।

What starts, and when

घटककब शुरू होता हैसक्रिय रहते समय मेमोरी
Fastify सर्वर + Postgres + Redisकंटेनर शुरूकुल ~200-300 MB
BullMQ वर्करकंटेनर शुरू (इन-प्रोसेस)प्रति पूल एक वर्कर (image, media, ai, docs, system)
Python डिस्पैचरपहला AI टूल अनुरोधPython इंटरप्रेटर + पूर्व-इम्पोर्ट की गई लाइब्रेरी (PIL, NumPy, MediaPipe, rembg) - कोई मॉडल वेट नहीं
AI मॉडल वेटविशिष्ट टूल के अनुरोध के दौरानडिस्क से लोड, अनुरोध समाप्त होने पर मुक्त

Model loading

सभी मॉडल वेट फ़ाइलें (कुल मिलाकर कई GB) हर समय /opt/models/ में डिस्क पर रहती हैं। प्रत्येक AI टूल स्क्रिप्ट केवल अपने स्वयं के मॉडल को एक अनुरोध की अवधि के लिए मेमोरी में लोड करती है, फिर उन्हें रिलीज़ कर देती है। कुछ स्क्रिप्ट इंफ़रेंस के बाद स्पष्ट रूप से del model और torch.cuda.empty_cache() को कॉल करती हैं ताकि यह सुनिश्चित हो सके कि मेमोरी तुरंत वापस दी जाए।

अनुरोधों के बीच कोई मॉडल कैश नहीं है। एक ही AI टूल को लगातार चलाने से हर बार मॉडल फिर से लोड होता है। यह हर AI अनुरोध पर एक मॉडल-लोड विलंब की कीमत पर निष्क्रिय मेमोरी को शून्य के करीब रखता है।

First AI request cold start

जब कंटेनर शुरू होता है तो Python डिस्पैचर नहीं चल रहा होता। पहला AI अनुरोध समानांतर में दो चीज़ें ट्रिगर करता है: डिस्पैचर बैकग्राउंड में गर्म होना शुरू होता है, और अनुरोध स्वयं एक बार की Python सबप्रोसेस स्पॉन पर वापस लौट आता है। एक बार डिस्पैचर तैयार होने का संकेत देता है, तो बाद के सभी AI अनुरोध सीधे इसका उपयोग करते हैं और सबप्रोसेस स्पॉन लागत को छोड़ देते हैं।