-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Infrastructural Changes made to the app
- Loading branch information
Showing
3 changed files
with
205 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
from flask import Flask, jsonify, request | ||
import pickle | ||
import redis | ||
from database import load_movies | ||
from scipy.sparse import load_npz | ||
import logging | ||
|
||
app = Flask(__name__) | ||
|
||
# Set up logging | ||
logging.basicConfig(level=logging.INFO) | ||
|
||
# Redis connection setup | ||
redis_client = redis.StrictRedis( | ||
host='redis-14520.c305.ap-south-1-1.ec2.redns.redis-cloud.com', | ||
port=14520, | ||
password='oDEwiX0SSQIKnc4PNJngPJJ9ziRe0gvP', | ||
decode_responses=False # Ensure binary responses | ||
) | ||
|
||
# Load sparse similarity matrix from file | ||
similarity = load_npz("similarity_matrix.npz") | ||
|
||
# Load the movie list from PostgreSQL | ||
movies = load_movies() | ||
|
||
|
||
@app.route('/recommend', methods=['GET']) | ||
def recommend(): | ||
try: | ||
movie_title = request.args.get('movie') | ||
|
||
# Validate movie title | ||
if not movie_title: | ||
return jsonify({"error": "Movie title is required"}), 400 | ||
|
||
# Check cache first | ||
cached_recommendations = redis_client.get(movie_title) | ||
if cached_recommendations: | ||
try: | ||
if isinstance(cached_recommendations, bytes): | ||
recommendations = pickle.loads(cached_recommendations) | ||
else: | ||
raise TypeError("Cached data is not in bytes format") | ||
|
||
return jsonify(recommendations=recommendations) | ||
except pickle.PickleError as e: | ||
logging.error(f"Error decoding cached recommendations: {e}") | ||
return jsonify({"error": "Error decoding cached recommendations"}), 500 | ||
|
||
# Check if the movie is in the dataset | ||
if movie_title in movies['title'].values: | ||
index = movies[movies['title'] == movie_title].index[0] | ||
|
||
# Extract the row of similarities for the given movie | ||
distances = similarity[index].toarray().flatten() | ||
|
||
# Get indices and sort by similarity score | ||
distance_with_index = list(enumerate(distances)) | ||
distance_with_index.sort(key=lambda x: x[1], reverse=True) | ||
|
||
recommendations = [] | ||
# Get top 5 similar movies (excluding the queried movie) | ||
for i in distance_with_index[1:6]: | ||
recommend_movie = movies.iloc[i[0]].title | ||
recommendations.append(recommend_movie) | ||
|
||
# Cache the recommendations | ||
try: | ||
redis_client.set(movie_title, pickle.dumps(recommendations), ex=86400) | ||
except pickle.PickleError: | ||
return jsonify({"error": "Error encoding recommendations for cache"}), 500 | ||
|
||
return jsonify(recommendations=recommendations) | ||
|
||
else: | ||
return jsonify({"error": "Movie not found"}), 404 | ||
|
||
except Exception as e: | ||
logging.error(f"An error occurred: {e}") | ||
return jsonify({"error": "An internal server error occurred"}), 500 | ||
|
||
|
||
if __name__ == '__main__': | ||
app.run(debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import psycopg2 | ||
from psycopg2.extras import RealDictCursor | ||
import pandas as pd | ||
import logging | ||
|
||
# Set up logging | ||
logging.basicConfig(level=logging.INFO) | ||
|
||
# Database connection details | ||
url = 'https://qdsijfxkqpidkurjjkwb.supabase.co' | ||
USER = 'postgres.qdsijfxkqpidkurjjkwb' | ||
PASSWORD = 'Onvkw6d32uEr3Nr6' | ||
HOST = 'aws-0-ap-south-1.pooler.supabase.com' | ||
PORT = '6543' | ||
|
||
|
||
def get_db_connection(): | ||
try: | ||
conn = psycopg2.connect( | ||
dbname='postgres', | ||
user=USER, | ||
password=PASSWORD, | ||
host=HOST, | ||
port=PORT | ||
) | ||
return conn | ||
except Exception as e: | ||
logging.error(f"Error connecting to database: {e}") | ||
return None | ||
|
||
|
||
def insert_movies(movie_list): | ||
conn = get_db_connection() | ||
if conn is None: | ||
return False | ||
|
||
try: | ||
with conn.cursor() as cursor: | ||
for movie in movie_list: | ||
cursor.execute(""" | ||
INSERT INTO movies (id, title) | ||
VALUES (%s, %s) | ||
ON CONFLICT (title) DO NOTHING; | ||
""", (movie['id'], movie['title'])) | ||
conn.commit() | ||
except Exception as e: | ||
logging.error(f"Error inserting movies: {e}") | ||
conn.rollback() | ||
finally: | ||
conn.close() | ||
|
||
|
||
def load_movies(): | ||
conn = get_db_connection() | ||
if conn is None: | ||
return pd.DataFrame() | ||
|
||
try: | ||
query = "SELECT id, title FROM movies;" | ||
df = pd.read_sql(query, conn) | ||
return df | ||
except Exception as e: | ||
logging.error(f"Error loading movies: {e}") | ||
return pd.DataFrame() | ||
finally: | ||
conn.close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,69 @@ | ||
import streamlit as st | ||
import pickle | ||
import requests | ||
import streamlit.components.v1 as components | ||
from database import load_movies | ||
|
||
# Load movie list | ||
try: | ||
movies_df = load_movies() # This should return a DataFrame | ||
if movies_df.empty: | ||
st.error("No movies found in the database.") | ||
st.stop() | ||
except Exception as e: | ||
st.error(f"Error loading movie list: {e}") | ||
st.stop() | ||
|
||
def fetch_poster(movie_id): | ||
url = "https://api.themoviedb.org/3/movie/{}?api_key=c7ec19ffdd3279641fb606d19ceb9bb1&language=en-US".format( | ||
movie_id) | ||
data = requests.get(url) | ||
data = data.json() | ||
poster_path = data['poster_path'] | ||
full_path = "https://image.tmdb.org/t/p/w500/" + poster_path | ||
return full_path | ||
# Prepare movie titles and IDs | ||
movies_dict = {row['title']: row['id'] for _, row in movies_df.iterrows()} | ||
|
||
def fetch_poster(movie_id): | ||
try: | ||
url = f"https://api.themoviedb.org/3/movie/{movie_id}?api_key=c7ec19ffdd3279641fb606d19ceb9bb1&language=en-US" | ||
response = requests.get(url) | ||
response.raise_for_status() # Raise an exception for HTTP errors | ||
data = response.json() | ||
poster_path = data.get('poster_path') | ||
if poster_path: | ||
return f"https://image.tmdb.org/t/p/w500/{poster_path}" | ||
except requests.RequestException as e: | ||
st.error(f"Error fetching poster: {e}") | ||
return None | ||
|
||
movies = pickle.load(open("movies_list.pkl", 'rb')) | ||
similarity = pickle.load(open("similarity.pkl", 'rb')) | ||
movies_list = movies['title'].values | ||
def fetch_recommendations(movie_title): | ||
try: | ||
# Replace with your actual Flask API URL | ||
response = requests.get(f'http://127.0.0.1:5000/recommend?movie={movie_title}') | ||
response.raise_for_status() # Raise an exception for HTTP errors | ||
return response.json().get('recommendations', []) | ||
except requests.RequestException as e: | ||
st.error(f"Error fetching recommendations: {e}") | ||
return [] | ||
|
||
st.header("Movie Recommender System") | ||
|
||
import streamlit.components.v1 as components | ||
|
||
# Example carousel component usage (assuming correct implementation) | ||
imageCarouselComponent = components.declare_component("image-carousel-component", path="frontend/public") | ||
|
||
imageUrls = [ | ||
fetch_poster(1632), | ||
fetch_poster(299536), | ||
fetch_poster(17455), | ||
fetch_poster(2830), | ||
fetch_poster(429422), | ||
fetch_poster(9722), | ||
fetch_poster(13972), | ||
fetch_poster(240), | ||
fetch_poster(155), | ||
fetch_poster(598), | ||
fetch_poster(914), | ||
fetch_poster(255709), | ||
fetch_poster(572154) | ||
|
||
] | ||
|
||
# Replace with your dynamic image URLs | ||
imageUrls = [fetch_poster(movie_id) for movie_id in [1632, 299536, 17455, 2830, 429422, 9722, 13972, 240, 155, 598, 914, 255709, 572154]] | ||
imageUrls = [url for url in imageUrls if url is not None] # Filter out None values | ||
imageCarouselComponent(imageUrls=imageUrls, height=200) | ||
selectvalue = st.selectbox("Select movie from dropdown", movies_list) | ||
|
||
|
||
def recommend(movie): | ||
index = movies[movies['title'] == movie].index[0] | ||
distance = sorted(list(enumerate(similarity[index])), reverse=True, key=lambda vector: vector[1]) | ||
recommend_movie = [] | ||
recommend_poster = [] | ||
for i in distance[1:6]: | ||
movies_id = movies.iloc[i[0]].id | ||
recommend_movie.append(movies.iloc[i[0]].title) | ||
recommend_poster.append(fetch_poster(movies_id)) | ||
return recommend_movie, recommend_poster | ||
|
||
selectvalue = st.selectbox("Pick movie from dropdown", list(movies_dict.keys())) | ||
|
||
if st.button("Show Recommend"): | ||
movie_name, movie_poster = recommend(selectvalue) | ||
col1, col2, col3, col4, col5 = st.columns(5) | ||
with col1: | ||
st.text(movie_name[0]) | ||
st.image(movie_poster[0]) | ||
with col2: | ||
st.text(movie_name[1]) | ||
st.image(movie_poster[1]) | ||
with col3: | ||
st.text(movie_name[2]) | ||
st.image(movie_poster[2]) | ||
with col4: | ||
st.text(movie_name[3]) | ||
st.image(movie_poster[3]) | ||
with col5: | ||
st.text(movie_name[4]) | ||
st.image(movie_poster[4]) | ||
recommendations = fetch_recommendations(selectvalue) | ||
if recommendations: | ||
cols = st.columns(5) | ||
for i, movie in enumerate(recommendations[:5]): | ||
if i < 5: | ||
movie_id = movies_dict.get(movie) | ||
poster_url = fetch_poster(movie_id) if movie_id else None | ||
with cols[i]: | ||
st.text(movie) | ||
if poster_url: | ||
st.image(poster_url) | ||
else: | ||
st.text("Poster not available") | ||
else: | ||
st.error("No recommendations found") |