Solo project
H-Tech
Hybrid movie recommender
A movie recommender that blends content-based and collaborative filtering, trained on MovieLens 25M and enriched with TMDB posters and metadata.
The code is in a private repo. Happy to walk you through it: ask me.
The first load can take 30–60 seconds. The backend runs on Google Cloud Run's free tier and needs a moment to wake up.
- Context
- Solo project
- Role
- Solo, end to end: data pipelines, models, API, frontend and deployment
- Team
- Solo
- When
- July 2026 – September 2026
The problem
Movie recommenders that rely on one signal fail in predictable ways. Collaborative filtering has nothing to say about new users or unrated films, and content-only models can't capture taste. I also wanted to serve it on free tiers, where a PyTorch runtime was too heavy for the API.
Approach
Content-based scoring (tag-genome, TF-IDF and sentence embeddings) and collaborative filtering (SVD and item-kNN), blended per request. A Dockerized FastAPI backend on Google Cloud Run, with PostgreSQL on Supabase, serves a Next.js frontend on Vercel with swipe-card onboarding and semantic search, all on free tiers.
How it works
- 01YouSwipe-card onboarding and semantic search
- 02Next.js on VercelThe frontend
- 03FastAPI on Google Cloud RunRecommendations and ONNX Runtime embeddings
- 04Postgres on SupabaseThe data
Key decision
A hybrid recommender that routes each request to the signal that works best for it. New users go to popularity and content instead of collaborative filtering, and serving-time embeddings moved from PyTorch to ONNX Runtime plus the tokenizers library.
Why
Collaborative filtering has nothing to say about new users or unrated films, so those requests go to the signals that can answer them. Running the embedding model through PyTorch added runtime overhead the API didn't need, so the Docker build converts it to ONNX once and PyTorch never ships. That made the image much smaller, but it wasn't the whole answer, and the API still runs at 4 GiB on Cloud Run.
Models
- Content-based scoringTag-genome, TF-IDF and sentence embeddings (ONNX Runtime)
- Collaborative filteringSVD and item-kNN, trained on MovieLens 25M
- Cold-start routingNew users get popularity and content signals
Why I built it
I'm aiming for internships and jobs in AI/ML and software development, and I wanted one project that shows both. A recommender needs data pipelines, several ML models, an API, a frontend and a live deployment. Building it end to end on free-tier limits taught me to design around real constraints like memory, cold starts and cost. I wrote down and measured each decision, so I can explain my choices, not just show that it runs.
Stack
- Python
- scikit-learn
- Polars
- ONNX Runtime
- FastAPI
- SQLAlchemy
- PostgreSQL
- Supabase
- Next.js
- TypeScript
- Docker
- Google Cloud Run
- Vercel
- GitHub Actions
Results
- Item-kNN reached 0.332 precision@10 from a single liked film, against 0.187 for plain popularity and 0.146 for TF-IDF content scoring.
- Ranking only films with at least 1,000 ratings lifted collaborative filtering's precision@10 from 0.046 to 0.189, with the model untouched.
- Evaluating the feed as served caught a shipped bug: score-based randomness had cut precision@10 at 50 ratings from 0.338 to 0.187. Sampling by rank brought it back to 0.323, with about 4 of 10 films changing per refresh.
- On a fresh sample of users that no tuning had seen, the served feed reached 0.319 precision@10 at one liked film.
- Measured on MovieLens 25M with simulated new users, so the constants are specific to this dataset.