Skip to content

nithinrbharadwaj/Complete-Recommendation-System-with-API

Repository files navigation

Complete Recommendation System 🔥

A production-ready recommendation system microservice built with Python, SQLite, and Flask. Extends the Day 29 engine components into a full-stack application with a REST API, database layer, caching, and evaluation pipeline.

Score: 196 / 200 — Distinction (98%)
128 tests passing · avg latency 12ms · 483 req/s throughput · feedback loop verified


Demo Screenshots

API running and serving live recommendations

API Server Running

Recommendations before feedback

Before Feedback

Feedback recorded (interaction_id: 66, status: 201)

Feedback Recorded

Recommendations after feedback — "Python for Beginners" removed, ranking updated

After Feedback

Postman collection with all 4 endpoints configured

Postman Collection


Feedback Loop Proof

Rated content_id 1 ("Python for Beginners") with 5 stars → system adapted in real time:

Change Before After
Python for Beginners #1 (score 0.6374) Removed (now rated)
SQL Masterclass #4 (score 0.5149) #2 (score 0.5379 — rescored)
React.js Complete Guide Not in list #5 (new entry)
Latency 9.65ms 18.69ms (cache cleared, fresh compute)

Architecture

User Request
     │
     ▼
┌─────────────┐
│  Flask API  │  ← auth, logging, request tracing
│  (api/app)  │
└──────┬──────┘
       │
       ▼
┌─────────────────────────┐
│  RecommendationOrch-    │  ← in-memory cache (5 min TTL)
│  estrator (engine/)     │
└───┬──────┬──────┬───────┘
    │      │      │
    ▼      ▼      ▼
 Cand.  Scorer  Evaluator
  Gen.
    │
    ▼
┌──────────────┐
│  SQLite DB   │  ← 6 tables, repository pattern
│  (data/)     │
└──────────────┘

Project Structure

day30_capstone/
├── data/
│   ├── database.py        # SQLite connection + schema (6 tables)
│   ├── models.py          # Table definitions reference
│   └── repositories.py    # Data access layer (repository pattern)
├── engine/
│   ├── orchestrator.py    # Main engine — ties all components together
│   ├── similarity.py      # Cosine, Jaccard, Pearson similarity
│   ├── candidate_gen.py   # Collaborative, content, popularity, hybrid
│   ├── scorer.py          # Weighted multi-factor scoring + explanations
│   └── evaluator.py       # Precision@K, Recall@K, NDCG@K, F1@K
├── api/
│   └── app.py             # Flask REST API (4 endpoints)
├── tests/
│   ├── test_data.py       # 28 data layer tests
│   ├── test_engine.py     # 62 engine tests
│   └── test_api.py        # 38 API endpoint tests
├── scripts/
│   ├── seed_data.py       # Populate DB (12 users, 22 content, 64 interactions)
│   └── evaluate.py        # Run evaluation + load test → evaluation_report.md
├── screenshots/           # Demo screenshots
├── evaluation_report.md   # Auto-generated performance report
├── postman_collection.json
├── requirements.txt
└── README.md

Quick Start

1. Install dependencies

pip install -r requirements.txt

2. Seed the database

python scripts/seed_data.py

Creates recommendation.db with 12 users, 22 content items, 12 skills, and 64 realistic interactions.

3. Start the API

python api/app.py

API runs at http://localhost:5000

4. Test an endpoint (Windows — use curl.exe)

curl.exe -H "X-API-Key: dev-secret-key-123" http://localhost:5000/recommend/1

5. Post feedback

python -c "import urllib.request, json; req = urllib.request.Request('http://localhost:5000/feedback', data=json.dumps({'user_id':1,'content_id':9,'type':'rate','rating':5.0}).encode(), headers={'X-API-Key':'dev-secret-key-123','Content-Type':'application/json'}, method='POST'); print(urllib.request.urlopen(req).read().decode())"

API Reference

All endpoints except /health require:

X-API-Key: dev-secret-key-123

Override via API_KEY environment variable.

Every response includes X-Request-ID and X-Response-Time-ms headers for tracing.


GET /health

Health check. No auth required.

{ "status": "healthy", "request_id": "a1b2c3d4", "timestamp": 1712134800.123 }

GET /recommend/<user_id>

Parameter Type Default Description
limit int 10 Items to return (1–50)
strategy string hybrid collaborative | content | popular | hybrid
refresh bool false Bypass cache

Response:

{
  "user_id": 1,
  "strategy": "hybrid",
  "cached": false,
  "latency_ms": 12.4,
  "recommendations": [
    {
      "content_id": 9,
      "title": "Building REST APIs with Flask",
      "category": "Web Dev",
      "difficulty": "intermediate",
      "score": 0.6821,
      "explanation": ["Users with similar taste rated this highly"],
      "breakdown": { "collaborative": 0.72, "content": 0.68, "popularity": 0.50, "skill_match": 0.80 }
    }
  ]
}

Errors: 401 no key · 400 bad params · 404 user not found

Cold start: Users with fewer than 3 interactions get popular items filtered by their declared interests. Response has "strategy": "cold_start".


POST /feedback

Field Type Required Description
user_id int Yes User ID
content_id int Yes Content ID
type string Yes view | like | complete | skip | rate
rating float If rate 1.0 – 5.0

Response (201):

{ "interaction_id": 87, "status": "recorded", "request_id": "b2c3d4e5" }

Clears the user's recommendation cache and refreshes engine data in real time.


GET /metrics

{ "total_users": 12, "total_content": 22, "total_skills": 12, "cached_users": 3, "cache_size": 8 }

Running Tests

python tests/test_data.py    # 28 tests — database & repositories
python tests/test_engine.py  # 62 tests — similarity, candidates, scorer, evaluator, orchestrator
python tests/test_api.py     # 38 tests — all 4 API endpoints

All 128 tests use isolated temp databases — never touch recommendation.db.


Evaluation

python scripts/evaluate.py

Outputs evaluation_report.md with all metrics + load test.

Strategy P@5 R@5 NDCG@5 HR@5 Avg ms
collaborative 0.15 0.19 0.135 0.58 5.7ms
content 0.15 0.19 0.139 0.42 1.9ms
popular 0.15 0.19 0.135 0.58 2.2ms
hybrid 0.15 0.19 0.135 0.58 5.7ms

Load test: 10 concurrent users · avg 11ms · 483 req/s · 0 failures


Database Schema

users          (id, name, interests, created_at)
content        (id, title, category, difficulty, popularity, created_at)
skills         (id, name)
user_skills    (user_id, skill_id, proficiency)
content_skills (content_id, skill_id)
interactions   (id, user_id, content_id, type, rating, created_at)

Foreign keys enforced. Types constrained to: view, like, complete, skip, rate.


How Scoring Works

Signal Weight Description
Collaborative 45% Predicted rating from similar users
Content 30% Category + difficulty match with liked items
Popularity 15% Fraction of users who interacted with item
Skill match 10% Overlap between user skills and content skill tags

Weights are configurable when instantiating RecommendationOrchestrator.


Caching

  • In-memory cache, 5-minute TTL (configurable)
  • Key = (user_id, limit, strategy) — different params cached separately
  • Invalidated automatically on feedback submission
  • Cold-start results cached independently

Postman Collection

  1. Open Postman → Import → select postman_collection.json
  2. Set base_url = http://localhost:5000
  3. Set api_key = dev-secret-key-123
  4. Run — all 12 requests include automated assertions

Extending the System

  • New scoring signal: Add method to RecommendationScorer, add to calculate_score() with a weight
  • New strategy: Add method to CandidateGenerator, register in strategy_map in orchestrator.py
  • Redis cache: Replace _cache dict in orchestrator.py with a Redis client
  • Docker:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
RUN python scripts/seed_data.py
EXPOSE 5000
CMD ["python", "api/app.py"]

Requirements

  • Python 3.10+
  • Flask 3.0+
  • No external ML libraries — pure Python standard library for all algorithms

About

Production-ready recommendation system microservice with Flask REST API, SQLite database, in-memory caching, and real-time feedback loop. Built with collaborative filtering, content-based, and hybrid recommendation strategies. 128 tests · 483 req/s · <20ms latency.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages