Skip to content

Repository files navigation

CineMatch

Python FastAPI Streamlit Scikit-Learn TMDB Render License


A full-stack movie recommendation engine combining content-based TF-IDF filtering with the TMDB API — delivering intelligent, visually rich film discovery in real time.


🚀 Live Demo · 📸 Screenshots · 🏗️ Architecture · ⚙️ Installation · 📡 API Reference · 🤝 Contributing


🚀 Live Demo

Service URL
🎨 Frontend movie-recommender-system-complete.streamlit.app
Backend API movie-recommender-system-3n2v.onrender.com
📖 API Docs /docs · /redoc

Note: The backend is hosted on Render's free tier and may take 30–60 seconds to wake up on first request.


📸 Screenshots

🏠 Home — Browsable Movie Feed

Home Page

🔍 Search — Real-time Movie Search

Search Page

🤖 Content-Based Recommendations (TF-IDF)

TF-IDF Recommendations

🎭 Genre Recommendations

Genre Recommendations


✨ Features

Feature Description
🔍 Smart Search Real-time movie search powered by TMDB with instant results
🤖 Content-Based Filtering TF-IDF cosine similarity on movie plots and metadata
🎭 Genre Discovery Discover top-rated films within the same genre via TMDB
🎬 Rich Movie Details Posters, backdrops, ratings, genres, overview, and release info
Async FastAPI Backend High-performance REST API with full OpenAPI documentation
🎨 Cinematic UI Dark-themed Streamlit frontend with hero banners and card grids
🔄 Parallel Fetching Concurrent TMDB poster resolution for fast recommendation rendering
📦 Cached Responses st.cache_data on all API calls for snappy repeat queries

🏗️ Architecture

┌─────────────────────────────────────────────────────────┐
│                    USER BROWSER                         │
└─────────────────────┬───────────────────────────────────┘
                      │  HTTP
                      ▼
┌─────────────────────────────────────────────────────────┐
│              STREAMLIT FRONTEND  (app.py)               │
│                                                         │
│  ┌──────────┐  ┌──────────┐  ┌────────────────────┐    │
│  │  Home    │  │  Search  │  │  Details / Recs    │    │
│  └──────────┘  └──────────┘  └────────────────────┘    │
│                                                         │
│  ThreadPoolExecutor — parallel API calls                │
└────────────────────────┬────────────────────────────────┘
                         │  REST (JSON)
                         ▼
┌─────────────────────────────────────────────────────────┐
│              FASTAPI BACKEND  (app/main.py)             │
│                                                         │
│  ┌──────────────────┐    ┌──────────────────────────┐   │
│  │   TMDB Service   │    │     TF-IDF Engine        │   │
│  │  (httpx async)   │    │  (scikit-learn + numpy)  │   │
│  └────────┬─────────┘    └──────────┬───────────────┘   │
│           │                         │                   │
│           ▼                         ▼                   │
│  ┌──────────────┐         ┌──────────────────────┐      │
│  │  TMDB API    │         │  Pickle Data Store   │      │
│  │  (external)  │         │  df · indices ·      │      │
│  └──────────────┘         │  tfidf · matrix      │      │
│                           └──────────────────────┘      │
└─────────────────────────────────────────────────────────┘

Recommendation Pipeline

User Query
    │
    ├──► TMDB Search  ──► Best Match  ──► Movie Details
    │                                          │
    ├──► TF-IDF Engine                         ▼
    │       │                         Poster + Backdrop
    │       ▼                         Genres, Overview
    │   Cosine Similarity
    │       │
    │       ▼
    │   Top-N Similar Titles
    │       │
    │       ▼
    │   Parallel TMDB Poster Fetch (ThreadPoolExecutor)
    │
    └──► Genre Discovery  ──► TMDB /discover/movie  ──► Genre Grid

🗂️ Project Structure

movie-recommendation/
│
├── app/                          # FastAPI backend
│   ├── api/
│   │   ├── home.py               # /home endpoint — trending/popular feeds
│   │   ├── movie.py              # /movie/id and /movie/search endpoints
│   │   ├── recommend.py          # /recommend/tfidf and /recommend/genre
│   │   └── search.py             # /tmdb/search endpoint
│   │
│   ├── core/
│   │   ├── config.py             # Environment config (pydantic-settings)
│   │   ├── startup.py            # Pickle loading on startup
│   │   └── state.py              # Global in-memory state (df, matrix, etc.)
|   |
|   ├── data/                         # Pre-computed ML artifacts (not in git)
│   |   ├── df.pkl                    # Processed movie DataFrame
│   |   ├── indices.pkl               # Title → matrix index mapping
│   |   ├── tfidf.pkl                 # Fitted TfidfVectorizer
│   |   └── tfidf_matrix.pkl          # Sparse TF-IDF feature matrix
|   | 
│   ├── schemas/
│   │   └── schemas.py            # Pydantic request/response models
│   │
│   ├── services/
│   │   ├── tmdb_services.py      # Async TMDB API client (httpx + retry)
│   │   └── tfidf_services.py     # TF-IDF cosine similarity logic
│   │
│   └── main.py                   # FastAPI app, CORS, router registration
│
├── images/                       # Application screenshots
│   ├── cotent_recommendations.png
│   ├── genre_recommendations.png               
│   ├── home.png                 
│   └── search.png  
|
├── notebooks/                    # Data preparation and model training
|   ├── movies.ipynb 
|   └── movies_metadata.csv   
|
├── app.py                        # Streamlit UI
│
├── .env.example
├── .python-version
├── LICENCE
├── README.md
├── requirements.txt
└── runtime.txt


⚙️ Installation

Prerequisites

1. Clone the repository

git clone https://github.com/sharif-abusad/movie-recommendation-system.git
cd movie-recommendation-system

2. Create and activate a virtual environment

python -m venv venv

# Windows
venv\Scripts\activate

# macOS / Linux
source venv/bin/activate

3. Install dependencies

pip install -r requirements.txt

4. Configure environment variables

cp .env.example .env

Open .env and fill in your values:

TMDB_API_KEY=your_tmdb_api_key_here

API_HOST=0.0.0.0
API_PORT=8000

DEBUG=False

ALLOWED_ORIGINS=http://localhost:8501

5. Data Setup

Place the pre-computed pickle files in the data/ directory:

data/
├── df.pkl
├── indices.pkl
├── tfidf.pkl
└── tfidf_matrix.pkl

To regenerate these files from scratch, run the notebook in notebooks/.


🖥️ Running Locally

Start the backend

uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
Resource URL
API Base http://localhost:8000
Swagger UI http://localhost:8000/docs
ReDoc http://localhost:8000/redoc

Start the frontend

streamlit run frontend/app.py

The app will open at http://localhost:8501.


📡 API Reference

Base URL

http://localhost:8000

Endpoints

Method Endpoint Description Key Parameters
GET /health Health check
GET /home Trending / popular / top-rated feed category, limit
GET /tmdb/search Full-text TMDB movie search query, page
GET /movie/id/{tmdb_id} Movie details by TMDB ID tmdb_id
GET /movie/search Complete bundle: details + TF-IDF + genre recs query, tfidf_top_n, genre_limit
GET /recommend/tfidf TF-IDF recommendations (titles + scores only) title, top_n
GET /recommend/genre Genre-based discovery via TMDB tmdb_id, limit

Example Requests

# Get trending movies
curl "http://localhost:8000/home?category=trending&limit=12"

# Search for a movie
curl "http://localhost:8000/tmdb/search?query=inception"

# TF-IDF recommendations
curl "http://localhost:8000/recommend/tfidf?title=Inception&top_n=10"

# Full recommendation bundle
curl "http://localhost:8000/movie/search?query=The+Dark+Knight&tfidf_top_n=12&genre_limit=12"
Example Response — GET /recommend/tfidf
[
  { "title": "Batman Begins", "score": 0.612 },
  { "title": "The Dark Knight Rises", "score": 0.589 },
  { "title": "Watchmen", "score": 0.431 }
]
Example Response — GET /movie/id/{tmdb_id}
{
  "tmdb_id": 155,
  "title": "The Dark Knight",
  "overview": "Batman raises the stakes in his war on crime...",
  "release_date": "2008-07-18",
  "poster_url": "https://image.tmdb.org/t/p/w500/qJ2tW6WMUDux911r6m7haRef0WH.jpg",
  "backdrop_url": "https://image.tmdb.org/t/p/w1280/hkBaDkMWbLaf8B1lsWsKX7Ew3Xq.jpg",
  "genres": [
    { "id": 28, "name": "Action" },
    { "id": 80, "name": "Crime" },
    { "id": 18, "name": "Drama" }
  ]
}

🚢 Deployment

Backend — Render

  1. Push your repo to GitHub
  2. Create a new Web Service on Render
  3. Set the following:
Setting Value
Build Command pip install -r requirements.txt
Start Command uvicorn app.main:app --host 0.0.0.0 --port $PORT
Environment Variables TMDB_API_KEY, DEBUG=False

Frontend — Streamlit Community Cloud

  1. Connect your GitHub repo at share.streamlit.io
  2. Set Main file path to frontend/app.py
  3. Add secrets under Settings → Secrets:
API_BASE = "https://your-render-backend.onrender.com"
TIMEOUT  = "60"

🛠️ Tech Stack

Backend

  • FastAPI — async REST API framework
  • Uvicorn — ASGI server
  • HTTPX — async HTTP client for TMDB calls
  • Pydantic — data validation and serialisation
  • Scikit-learn — TF-IDF vectoriser
  • NumPy — cosine similarity computation
  • Pandas — movie DataFrame

Frontend

External APIs

  • TMDB API — movie data, posters, and genre discovery

🗺️ Roadmap

  • Collaborative filtering (user-based / item-based)
  • Hybrid recommendation (TF-IDF + collaborative)
  • User authentication and profiles
  • Watchlist and favourites
  • Server-side recommendation caching (Redis)
  • Docker + docker-compose setup
  • CI/CD pipeline (GitHub Actions)
  • Unit and integration tests (pytest)
  • Structured logging and monitoring (Sentry / Grafana)
  • Mobile-responsive PWA

🤝 Contributing

Contributions are welcome and appreciated.

# 1. Fork the repository
# 2. Create a feature branch
git checkout -b feature/your-feature-name

# 3. Commit your changes
git commit -m "feat: add your feature"

# 4. Push and open a Pull Request
git push origin feature/your-feature-name

Please follow Conventional Commits for commit messages and open an issue before starting large changes.


📄 License

This project is licensed under the MIT License — see the LICENSE file for details.


👤 Author

Sharif Abusad

GitHub LinkedIn

If you found this project useful, consider giving it a ⭐ on GitHub — it helps a lot!


Built with ❤️ using FastAPI, Streamlit, and the TMDB API

About

Built a full-stack Movie Recommendation System with FastAPI and Streamlit that delivers personalized content-based recommendations using TF-IDF while integrating the TMDB API for real-time movie search, posters, ratings, details, and genre-based recommendations.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages