Self-hosted AI image gallery with Python-subprocess ML pipelines, SQLite FTS5 search, and federation across instances.
Live demo: Screenshots in /docs/screenshots/; local run via docker compose up
Stack: Node.js / Express 5 · React · SQLite (better-sqlite3) · Python subprocess ML (WD Tagger, BLIP) · JWT auth · Socket.io
Status: Active
A self-hosted AI image gallery with ML-powered auto-tagging, content analysis, and federation support. Artifex lets you upload, organize, search, and share AI-generated images with intelligent metadata extraction handled automatically in the background.
Artifex is a full-stack application split into a Node.js backend and a React frontend. When images are uploaded, a background job queue processes them through multiple ML pipelines: WD Tagger and a ViT-based classifier tag content, and BLIP generates natural language captions. All metadata is indexed in SQLite for fast full-text search.
The application supports multi-user authentication with role-based access, image collections, and a federation system that allows multiple Artifex instances to sync and share galleries with each other.
- Backend: Express 5, SQLite (better-sqlite3), JWT authentication
- Frontend: React 19, Vite, Tailwind CSS 4
- ML Vision: Python subprocess servers for WD Tagger (port 7865) and BLIP Captioner (port 7866)
- ML Classification: ViT-based content classifier via @huggingface/transformers in Node
- Job Queue: SQLite-backed, polls every 3 seconds, single concurrency
- Media Processing: Sharp for image manipulation, FFmpeg for video frame extraction
- Auto-tagging: Images are automatically classified with content tags via WD Tagger (SwinV2) and a ViT-based classifier
- Caption generation: BLIP generates natural language descriptions for each image
- Full-text search: Search across tags, captions, filenames, and metadata
- Collections: Organize images into named collections
- Multi-user auth: JWT-based authentication with admin and standard roles
- Federation: Peer-to-peer galleries — add peer URLs, browse their public images and videos at full quality with complete metadata
- Video support: Upload videos with automatic frame extraction and thumbnail generation
- Rate limiting: Built-in rate limiting on public-facing endpoints
- API documentation: Swagger UI available at
/api-docs
Artifex instances federate directly with each other — no central registry, no relay, no account on the other side.
- Simple peer list — an admin adds another instance by URL in Admin → Federation. The peer is verified through its
/api/federation/manifestbefore it's saved (bareip:portworks as long as the instance answers). - Full-metadata sync — a background engine (30-minute interval, plus manual sync) pulls each peer's public catalog into a local cache: prompts, negative prompts, workflow JSON, sampler/steps/CFG/seed, video metadata, and file hashes. Browsing and search keep working while a peer is offline. Thumbnails are cached to disk, and failed thumbnail downloads self-heal on later sync cycles.
- Direct media loading — full-resolution images and videos are never mirrored or proxied. The viewer's browser streams them straight from the source peer's CORS-enabled endpoints (
/api/federation/media/:id/full,/media/:id/preview,/image/:id/thumbnail). Onlyvisibility: publicitems are ever served to peers. - Cached vs Live, per peer — each peer runs in Cached mode (default: metadata + thumbnails stored locally) or Live mode (nothing stored: feeds query the peer at browse time with a short cache, and its items simply drop out of feeds while it's offline). Switching to Live purges everything cached from that peer; switching back triggers a fresh full sync.
- Live status — peer online/offline dots update within ~10 seconds via a lightweight health poll, independent of sync state.
- One merged library — peer content shows in the Network tab and interleaves into the Public and All tabs, deduplicated against local copies by file hash (a local copy always wins). Remote images support compare, selection, and saving to collections (by reference — Cached peers only), and uploader names link to the profile on the source instance.
- Peers must be reachable from the viewer's browser (LAN or public URL) since media loads directly; use matching http/https schemes to avoid mixed-content blocking. Set
PUBLIC_URLso peers and their browsers know how to reach you. - Federation endpoints are public-read by design: only public images are exposed, no peer-to-peer credentials are exchanged, and a dedicated rate limit (300 req/min/IP) covers the media-heavy direct-load traffic.
- Toggling federation on/off in the admin panel applies at runtime — no restart needed.
| Layer | Technology |
|---|---|
| Runtime | Node.js |
| Backend Framework | Express 5 |
| Database | SQLite (better-sqlite3) |
| Frontend Framework | React 19 |
| Bundler | Vite 8 |
| CSS | Tailwind CSS 4 |
| Auth | JSON Web Tokens (bcryptjs) |
| Image Processing | Sharp |
| Video Processing | FFmpeg (fluent-ffmpeg) |
| ML Inference | ONNX Runtime, @huggingface/transformers |
| ML Vision Servers | Python (WD Tagger, BLIP) |
| Icons | Phosphor Icons |
| Testing | Jest, Supertest |
| Linting | ESLint with security plugin |
- Node.js 18+
- Python 3.10+ (for ML vision servers)
- FFmpeg (for video processing)
# Clone the repository
git clone https://github.com/RogerSquare/Artifex.git
cd Artifex
# Install backend dependencies
cd backend
npm install
# Install frontend dependencies
cd ../frontend
npm installCopy the environment example file and configure it:
cp .env.example .envKey environment variables:
| Variable | Description | Default |
|---|---|---|
JWT_SECRET |
Secret for signing auth tokens | Auto-generated on first run |
PORT |
Backend server port | 3002 |
FFMPEG_PATH |
Path to FFmpeg binary | System PATH |
FFPROBE_PATH |
Path to FFprobe binary | System PATH |
PUBLIC_URL |
This instance's URL as peers and their browsers reach it (seeds instance settings on first boot; admin UI owns it after) | — |
INSTANCE_NAME |
Display name shown to federation peers (first boot only) | Artifex Gallery |
FEDERATION_ENABLED |
Enable federation on first boot (toggleable later in the admin UI) | false (true in docker-compose) |
# Start the backend
cd backend
node server.js
# Start the frontend (separate terminal)
cd frontend
npm run devThe backend runs on port 3002 and the frontend on port 5175 by default.
A docker-compose.yml is provided for containerized deployment:
docker compose up -dcd backend
npm test # Run 65 integration tests
npm run lint # Run ESLint with security rulesbackend/
server.js # Express app entry point
db.js # SQLite schema and migrations
routes/
images.js # Image upload, search, CRUD
auth.js # Login, registration, token refresh
admin.js # User management, system settings
tags.js # Tag management and search
collections.js # Collection CRUD (local + remote references)
federation.js # Peer management, public federation API, feeds
lib/
federation-sync.js # Pull-sync engine (metadata + thumbnail cache)
federation-feed.js # Live-mode peer feed assembly
federation-urls.js # Direct browser-to-peer media URLs
jobQueue.js # Background ML processing queue
authMiddleware.js # JWT verification middleware
visionClient.js # Python ML server communication
nsfwClassifier.js # Node-based ViT content classifier
frontend/
src/
App.jsx # Root component and routing
components/ # React components
config.js # API endpoint configuration
MIT