Three pieces: offline scripts that build the embeddings, a Docker API that only encodes the query and compares, and this Astro website, which calls the API and shows the results.
Swipe to see the full map →
- 01
The catalogue
It all starts with a catalogue of 9,883 movies with title, release date, genres, overview and poster. For each one, the title + overview text is used.
- 02
From text to vector
That text goes through the all-MiniLM-L6-v2 model. With mean pooling and L2 normalisation, each movie becomes a vector that captures its meaning.
- 03
Computed only once
The vectors are stored in
embeddings.npy. The API loads them into memory at startup, so they are never recomputed in production. - 04
A search comes in
From the browser, the description and filters go to
GET /search, a FastAPI service running in a Docker container on Render. - 05
The query becomes a vector too
The description is tokenised and encoded with ONNX Runtime, using the same model, pooling and normalisation as the catalogue, so queries and movies live in the same space.
- 06
Filters
Before comparing, movies outside the selected genre or year range are dropped.
- 07
The closest matches
Cosine similarity is computed against the remaining movies and the top-k come back as JSON. The browser renders them and loads the posters from TMDB. In the first search above, Spider-Man (2002) wins with 0.752.