
Full-Stack
Filmoji
Emoji-to-movie recommendations built on a shared embedding space
Category
Full-Stack
Duration
5 months
Technologies
React 19, Vite, Spring Boot, FastAPI, sentence-transformers, PostgreSQL + pgvector, Firebase Auth, Docker Compose
Project Overview
Pick an emoji, get a film. Filmoji embeds emojis and movies into the same 384-dimension vector space so 'closest movie to this mood' becomes a nearest-neighbour search rather than a set of hand-tuned rules. A quiz and a swipe deck build a personal taste vector that is blended into every later query, so results drift toward the individual user over time.
Key Features
- Multi-emoji queries blended into a single embedding, so 🚀 + 😂 differs from 🚀 alone
- Onboarding quiz and Tinder-style swipe deck that seed a 384-dim taste profile
- Incremental profile learning — every swipe nudges the stored vector and renormalises it
- pgvector ivfflat cosine search over movie embeddings, blended 80/20 with the user profile
- Four containerised services orchestrated by a single Docker Compose file
Project Writeup
Overview
Filmoji answers one question — what should I watch, given how I feel right now? — by putting emojis and movies into the same vector space. Choosing 😱 or 🥹 is not matched against a rules table; it is embedded and resolved as a nearest-neighbour search over movie vectors. A team project built across four containerised services.
How the recommendation works
- The chosen emojis are resolved to emotion text through a catalogue of 50+ mappings.
- That text is embedded by a
sentence-transformersMiniLM model into a 384-dim vector. - If the user is signed in, their stored profile vector is blended in at 80/20 and the result is renormalised.
- pgvector runs an
ivfflatcosine search over movie embeddings, optionally filtered by the genres associated with the emoji. - Results are deduplicated, enriched with TMDB posters and trailers, and returned with a plain-language reason for the pick.
Learning a taste profile
Onboarding does double duty as training data. A short personality quiz maps categorical answers to weighted genre scores, which are turned into text and embedded as the initial profile vector. A swipe deck of curated films then refines it incrementally — a like moves the profile a small step toward the film's vector, a dislike nudges it away, and the result is renormalised to the unit sphere each time. Every later interaction can keep applying the same update, so the profile drifts toward the user rather than being fixed at signup.
Architecture
Four services behind one Docker Compose file: a React 19 + Vite frontend served by nginx, a Spring Boot backend owning auth, watchlists and TMDB lookups, a FastAPI service owning embeddings and similarity search, and Postgres with pgvector holding both movie and profile vectors.
Notes
- Keeping emojis and movies in one embedding space is what removes the rules engine — the "closest movie to this emoji" question becomes ordinary vector math.
- The
ivfflatindex needed recall tuning; a naive configuration returned confidently wrong neighbours. - The AI service stays in Docker because the model downloads are large enough to make local setup the slow path for a team.