A web app that turns your watch history (or a list of your favorite anime) into a personalized anime recommendation list.
βΆ Try the live demo β β enter your MyAnimeList username for a ranked list.
The backend is on a free tier, so the first request after it's been idle may take ~60s to wake up. Sorry about that. (,,Β¬οΉΒ¬,,)
Two-stage recommender architecture (retrieval + rerank) β the standard shape for recommenders that must score a large catalog under a latency budget:
- Retrieval β a two-tower model embeds users and anime into one 128-d cosine space: cheap, recall-oriented.
- Ranking β LightGBM (lambdarank) reranks the top 200 candidates on 29 features (userβitem cosine, history affinity, genre/theme overlap, MAL metadata, β¦). Expensive per item, so it only ever sees the shortlist.
- Serving β FastAPI backend + React frontend. Newly released titles the model never trained on (also called cold items) are served as a separate section ranked by cosine, never through the ranker β the ranker is trained on warm items and buries cold ones.
For a detailed description of each stage, see the component README: retriever, ranker, and service.
data/ ββ> model/ ββ> artifacts/ ββ> service/
raw retriever item_vectors FastAPI + React
cleaned + ranker user_tower (read-only consumer)
ranker.txt
artifacts/ is the contract between training and serving: the retriever and ranker save their trained models here, and the service only reads them. Neither side imports the other's training code, so the serving path cannot silently drift from what was trained.
| Path | What's in it |
|---|---|
data/ |
Crawler (TODO), cleaning notebook, schema samples; raw/cleaned CSVs are not committed |
model/retriever/ |
Two-tower model: data prep, training, export to artifacts/ |
model/ranker/ |
LightGBM reranker: pool building, training, eval gate, export to artifacts/ |
artifacts/ |
Model exports (not committed) |
service/backend/ |
FastAPI app + CLI (recommend.py), read-only consumer of artifacts/ |
service/frontend/ |
React + Vite + TypeScript UI |
map/ |
2-D UMAP map of the catalog (TODO) |
Prerequisites: Python 3.9, Node.js 18+, and (optional, for looking up live MAL usernames) a MyAnimeList API Client ID.
# 1. Clone the repo
git clone https://github.com/Salierigator/anime-recommender.git
cd anime-recommender
# 2. Create a virtual environment and install the Python dependencies
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
# 3. (Optional β real mode only) add your MAL Client ID
echo "MAL_CLIENT_ID=your_id_here" > service/.envNote: The run commands below need the trained model files in
artifacts/β a download link will be added later. Mock mode runs without them.
# Backend, mock mode β returns fixtures, loads no model. Best for frontend work.
cd service/backend && MOCK_MODE=1 uvicorn app.main:app --reload --port 8000
# Backend, real mode β needs artifacts/; MAL_CLIENT_ID in service/.env for live usernames
cd service/backend && MOCK_MODE=0 uvicorn app.main:app --port 8000
# Frontend, run it in another terminal
cd service/frontend && npm install && npm run dev
# Open this link in your browser: http://localhost:5173/
# CLI β no server; --mal-ids needs no MAL key
venv/bin/python service/backend/recommend.py --mal-ids service/backend/fixtures/dummy_mal_ids.txt
venv/bin/python service/backend/recommend.py <mal-username> --top-k 20The datasets are MAL-derived and gigabytes in size, so they are not part of this repo; data/samples/ holds the first rows of each file as a schema reference. The model currently in artifacts/ was trained on a mid-2025 snapshot β a fresh crawl is currently running (see data/crawler/README.md).
Retriever training runs on Colab GPU; the ranker trains locally on CPU. Both write into artifacts/, and the service picks up a new model with no code change β see model/README.md for the full retrain loop.
This project grew out of my graduation thesis. The full thesis version (all experiments, baselines, ablations, docs) is frozen at tag thesis-final.
I'd be glad if you find this project interesting, open for discussion anytime. Feel free to reach out:
- Email: hieulhp6@gmail.com
- Discord: salierigator
