A search engine for manga panels. It detects true comic panel boxes with a manga-tuned YOLO model, indexes each panel — and every detected face/person region within it — with booru-style tags (WD EVA02-Large anime tagger) plus anime face/eyes/hand/person detection, and searches those tags first (with an emotion-aware synonym map: shocked→surprised, embarrassed→blush, etc.) — falling back to OpenCLIP "vibes" embeddings only for free-text queries with no tag match. Includes automated chapter webscraping (MangaDex integration).
The heavy ML is Python-only; the orchestration/API/query work is Java. Each part runs in the stack it's best suited to, communicating over HTTP:
| Service | Stack | Responsibility |
|---|---|---|
services/ml |
Python / FastAPI | Panel detection (YOLO), face/eyes/hand/person detection, WD tagging, OpenCLIP embeddings. Stateless. |
services/api |
Java / Spring Boot | Angular-facing search — tag/vector ranking over Postgres/pgvector; calls ml for the CLIP text vector. |
services/ingestion |
Java / Spring Boot | MangaDex download + orchestration; calls ml per page/panel; writes Postgres + storage. |
frontend |
Angular | UI (points at api). |
backend |
Django (legacy) | The original monolith; superseded by the three services above. |
Shared Postgres + pgvector. Run the whole stack:
docker compose -f deploy/docker-compose.yml up --build
# api:8080 ingestion:8090 ml:8001 db:5432
# search: curl "http://localhost:8080/search?q=angry"
# ingest: curl -X POST localhost:8090/ingest -H 'content-type: application/json' \
# -d '{"url":"https://mangadex.org/chapter/<uuid>","quality":"data-saver"}'Each service has its own README with local (non-Docker) run instructions. The
sections below describe the original Django monolith, still runnable from backend/.
- Tag-first Concept Search: Enter queries like
"eyes","angry","chibi", or"hands". Queries are mapped to booru tags (via a synonym map + underscore-token overlap) and to detected sub-elements (face/eyes/hand/person), ranked by tagger confidence, with CLIP as a free-text fallback. - Flexible Ingestion:
- Direct Image Upload: Upload single pages. The backend detects panel boxes with a YOLO manga-panel model (OpenCV gutter split as fallback), tags + embeds each panel, and uploads images to the selected storage provider.
- Web Scraping Ingestion: Provide a URL to fetch pages and batch-process all panels.
- MangaDex Specific Flow: Seamless integration with MangaDex chapter URLs. Downloads, processes, splits, and indexes chapters automatically.
- Optimized Image Pipeline: Converts uploaded pages into
.avifformats with custom compression configurations to save storage. - Storage Options: Plug-and-play support for local file storage or Amazon S3.
- Modern UI: Clean frontend built with Angular, featuring a responsive search bar, dark mode, and upload tracking.
graph TD
User([User]) -->|Search & Ingest| FE[Angular Frontend]
FE -->|Proxy Request| BE[Django Backend]
subgraph Ingestion Pipeline
BE -->|Process Link| Scraper[Web Scraper / MangaDex Client]
Scraper -->|Pages| YOLO[YOLO Panel Detector]
YOLO -->|Panels| Tagger[WD Tagger + anime face/eye/hand/person detectors]
Tagger -->|Tags + sub-elements| DB[(PostgreSQL + pgvector)]
YOLO -->|Panels| OpenCLIP[OpenCLIP Embedding]
OpenCLIP -->|Vectors| DB
YOLO -->|Compressed Images| Storage{Storage Backend: Local / S3}
end
subgraph Query Pipeline
BE -->|Vector Search| DB
BE -->|Fetch Images| Storage
end
- Frontend: Angular 18+, TypeScript, Vanilla CSS
- Backend: Django 4.2+, Python 3.10+
- Image Processing: OpenCV, Pillow (PIL)
- AI/Embeddings: OpenCLIP, Hugging Face
- Databases: SQLite (dev) / PostgreSQL + pgvector (production)
- Storage: Local filesystem / AWS S3 / Tinify API (compression offloading)
Ensure you have the following installed:
-
Navigate to the
backenddirectory:cd backend -
Create and activate a Python virtual environment:
python3 -m venv .venv source .venv/bin/activate -
Install dependencies:
pip install -r requirements.txt
-
Configure your environment variables:
cp .env.example .env
Open the
.envfile and set the required variables. By default, it will fall back to local storage and SQLite if Postgres/S3 variables are left blank. -
Apply migrations:
python manage.py migrate
-
Run the development server:
python manage.py runserver
The backend server will run on
http://127.0.0.1:8000/.Note: On first ingest/search the backend downloads model weights from the Hugging Face hub (YOLO panel detector + anime detectors + WD tagger), cached under
~/.cache/huggingface. -
(Optional) Re-index existing panels with the current pipeline after a model or algorithm change:
python manage.py reingest # all chapters python manage.py reingest --only <chapter_id> python manage.py reingest --dry-run
MangaDex chapters are re-downloaded and fully re-cropped; direct uploads are re-tagged/re-embedded in place (their original page is no longer available).
-
Navigate to the
frontenddirectory:cd frontend -
Install Node packages:
npm install
-
Start the Angular development server:
ng serve --open
The frontend will compile and automatically open in your default browser at
http://localhost:4200/.
Angular & TypeScript + Django & Python
Search for manga panels by typing in vibes
Search -User types in text-based search query on frontend e.g. "chibi mad expression" -Queries the Postgres database and grabfindss the k most nearest vector embeddedings, returning their image file paths -Backend grabs the actual images from Amazon S3 -Backend gives the filepaths to the frontend
Upload -Angular frontend takes in an image to a manga page -Backend compresses the image by converting it into a smaller image type e.g. .avif format -OpenCV crops the manga panel boxes -runs the OpenCLIP embedding function -stores the path to the file & embedding in Amazon S3 (object keys) and Postgres (vectors) -Uploads the file into or a local folder on your computer, depending on the ____ flag.
Upload-webscrape -Angular frontend takes in a link to manga page. -Webscraper goes onto the manga page and grabs all manga images
- THen follows the upload functionaltiy
frontend
cd frontend
nvm use 22
"Now using node v22.14.0 (npm v10.9.2)"
ng serve --open (will take a couple seconds to build then run on:) http://localhost:4200/
backend