Search K
Arsitektur
SnapOtter adalah monorepo yang dikelola dengan workspace pnpm dan Turborepo. Ia di-deploy sebagai stack Docker Compose 3 kontainer: image aplikasi SnapOtter, PostgreSQL 17, dan Redis 8.
Struktur proyek
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 configPaket
@snapotter/image-engine
Pustaka pemrosesan gambar inti yang dibangun di atas Sharp. Ia menangani semua operasi non-AI: resize, crop, rotate, flip, convert, compress, strip metadata, dan penyesuaian warna (kecerahan, kontras, saturasi, grayscale, sepia, invert, saluran warna).
Paket ini tidak memiliki dependensi jaringan dan berjalan sepenuhnya dalam proses.
@snapotter/ai
Lapisan penghubung yang memanggil skrip Python untuk operasi ML. Pada penggunaan pertama, penghubung memulai proses dispatcher Python yang persisten yang mengimpor terlebih dahulu pustaka berat (PIL, NumPy, MediaPipe, rembg) sehingga panggilan AI berikutnya melewati overhead impor. Jika dispatcher belum siap, penghubung mundur ke pemunculan subproses Python baru per permintaan.
Model tidak dimuat terlebih dahulu. Setiap skrip tool memuat bobot modelnya dari disk pada waktu permintaan dan membuangnya saat permintaan selesai. Lihat Jejak sumber daya untuk profil memori lengkap.
Operasi yang didukung: penghapusan latar belakang (rembg/BiRefNet), upscaling (RealESRGAN), blur wajah (MediaPipe), penyempurnaan wajah (GFPGAN/CodeFormer), penghapusan objek (LaMa ONNX), OCR (PaddleOCR/Tesseract), pewarnaan (DDColor), penghapusan derau, penghapusan mata merah, restorasi foto, pembuatan foto paspor, pemperbaiki transparansi (matting HR BiRefNet), dan pengubahan ukuran sadar-konten (biner Go caire).
Skrip Python berada di packages/ai/python/. Image Docker mengunduh terlebih dahulu semua bobot model selama build sehingga kontainer bekerja sepenuhnya offline.
@snapotter/shared
Tipe TypeScript bersama, konstanta (seperti APP_VERSION dan definisi tool), dan string terjemahan i18n yang digunakan oleh frontend dan backend.
Aplikasi
API (apps/api)
Server Fastify v5 yang mengekspos 241 route tool di lima modalitas (image, video, audio, PDF, file) yang menangani:
- Unggahan file, manajemen workspace sementara, dan penyimpanan file persisten
- Pustaka file pengguna dengan rantai versi (tabel
user_files) - setiap hasil yang diproses tertaut kembali ke file sumbernya dan mencatat tool mana yang diterapkan, dengan thumbnail yang dibuat otomatis untuk halaman Files - Eksekusi tool (mengarahkan setiap permintaan tool ke image engine atau AI bridge)
- Orkestrasi pipeline (merangkai beberapa tool secara berurutan)
- Pemrosesan batch dengan kontrol konkurensi melalui antrean job BullMQ (pool: image, media, ai, docs, system)
- Autentikasi pengguna, RBAC (peran admin/user dengan set izin lengkap), manajemen kunci API, dan pembatasan laju
- Manajemen Teams - CRUD hanya-admin; pengguna ditugaskan ke sebuah tim melalui field
teamdi profil mereka - Pengaturan runtime - penyimpanan key-value di tabel
settingsyang mengontroldisabledTools,enableExperimentalTools,loginAttemptLimit, dan tombol operasional lainnya tanpa deploy ulang - Branding kustom dan preferensi runtime melalui pengaturan yang didukung basis data
- Dokumentasi Scalar/OpenAPI di
/api/docs - Menyajikan frontend yang telah dibangun sebagai SPA dalam produksi
Dependensi utama: Fastify, Drizzle ORM (pg-core, node-postgres), Sharp, BullMQ, ioredis, Zod untuk validasi.
Server menangani penghentian yang mulus pada SIGTERM/SIGINT: ia menguras koneksi HTTP, menghentikan worker BullMQ, mematikan dispatcher Python, dan menutup koneksi basis data.
Web (apps/web)
Aplikasi single-page React 19 yang dibangun dengan Vite. Menggunakan Zustand untuk manajemen state, Tailwind CSS v4 untuk penataan, dan Lucide untuk ikon. Berkomunikasi dengan API melalui REST dan SSE (untuk pelacakan progres).
Halaman mencakup workspace tool, halaman Files untuk mengelola unggahan dan hasil persisten, pembuat automasi/pipeline, dan panel pengaturan admin.
Frontend yang telah dibangun disajikan oleh backend Fastify dalam produksi, jadi tidak ada server web terpisah di kontainer Docker.
Docs (apps/docs)
Situs VitePress ini. Di-deploy ke Cloudflare Pages secara otomatis saat push ke main.
Bagaimana sebuah permintaan mengalir
- Pengguna memilih sebuah tool di UI web dan mengunggah file.
- Frontend mengirim POST multipart ke
/api/v1/tools/:section/:toolIddengan file dan pengaturan. - Route API memvalidasi input dengan Zod, lalu mengirim pemrosesan.
- Untuk tool standar, job dimasukkan ke antrean ke pool BullMQ yang sesuai (image, media, atau docs berdasarkan modalitas). Worker BullMQ dalam proses secara otomatis mengorientasikan gambar berdasarkan metadata EXIF, menjalankan fungsi proses tool, dan mengembalikan hasilnya.
- Untuk tool AI, penghubung TypeScript mengirim permintaan ke dispatcher Python yang persisten (atau memunculkan subproses baru sebagai fallback), menunggunya selesai, dan membaca file keluaran.
- Progres job dipertahankan ke tabel
jobsdi PostgreSQL sehingga state bertahan saat kontainer dimulai ulang. Pembaruan waktu nyata dikirimkan melalui SSE di/api/v1/jobs/:jobId/progress. - API mengembalikan
jobIddandownloadUrl. Pengguna mengunduh file yang telah diproses dari/api/v1/download/:jobId/:filename.
Untuk pipeline, API memberi output setiap langkah sebagai input ke langkah berikutnya, menjalankannya secara berurutan.
Untuk pemrosesan batch, API menggunakan flow BullMQ dengan child job per langkah dan mengembalikan file ZIP berisi semua file yang diproses.
Jejak sumber daya
SnapOtter dirancang untuk penggunaan memori idle yang rendah. Tidak ada yang dimuat terlebih dahulu atau dijaga tetap hangat saat startup.
Saat idle
Proses Node.js/Fastify, PostgreSQL, dan Redis berjalan. RAM idle tipikal adalah ~200-300 MB di ketiga kontainer (proses Node.js, Postgres, dan Redis). Tidak ada proses Python, tidak ada bobot model di memori.
Apa yang mulai, dan kapan
| Komponen | Mulai saat | Memori saat aktif |
|---|---|---|
| Server Fastify + Postgres + Redis | Kontainer mulai | ~200-300 MB total |
| Worker BullMQ | Kontainer mulai (dalam proses) | Satu worker per pool (image, media, ai, docs, system) |
| Dispatcher Python | Permintaan tool AI pertama | Interpreter Python + pustaka yang diimpor terlebih dahulu (PIL, NumPy, MediaPipe, rembg) - tanpa bobot model |
| Bobot model AI | Selama permintaan tool spesifik | Dimuat dari disk, dibebaskan saat permintaan selesai |
Pemuatan model
Semua file bobot model (berjumlah beberapa GB) berada di disk di /opt/models/ setiap saat. Setiap skrip tool AI hanya memuat model miliknya sendiri ke memori selama durasi permintaan, lalu melepaskannya. Beberapa skrip secara eksplisit memanggil del model dan torch.cuda.empty_cache() setelah inferensi untuk memastikan memori segera dikembalikan.
Tidak ada cache model antar permintaan. Menjalankan tool AI yang sama berturut-turut memuat ulang model setiap kali. Ini menjaga memori idle mendekati nol dengan biaya penundaan pemuatan model pada setiap permintaan AI.
Cold start permintaan AI pertama
Dispatcher Python tidak berjalan saat kontainer dimulai. Permintaan AI pertama memicu dua hal secara paralel: dispatcher mulai memanas di latar belakang, dan permintaan itu sendiri mundur ke pemunculan subproses Python sekali pakai. Setelah dispatcher menandakan siap, semua permintaan AI berikutnya menggunakannya secara langsung dan melewati biaya pemunculan subproses.
