import gradio as gr import pickle import pandas as pd import numpy as np from surprise import SVD import warnings warnings.filterwarnings('ignore') # Load models and data print("Loading models...") with open('svd_model.pkl', 'rb') as f: svd_model = pickle.load(f) with open('movies.pkl', 'rb') as f: movies = pickle.load(f) with open('ratings.pkl', 'rb') as f: ratings = pickle.load(f) print("Models loaded successfully!") def recommend_movies(user_id, num_recommendations, min_rating): """ Generate movie recommendations for a user """ try: user_id = int(user_id) num_recommendations = int(num_recommendations) min_rating = float(min_rating) # Check if user exists if user_id not in ratings['userId'].values: return f"⚠️ User ID {user_id} not found in database. Please try a different user ID (1-{ratings['userId'].max()})." # Get all movies all_movie_ids = movies['movieId'].unique() # Get movies the user has already rated rated_movies = ratings[ratings['userId'] == user_id]['movieId'].values # Get movies the user hasn't rated movies_to_predict = [mid for mid in all_movie_ids if mid not in rated_movies] # Predict ratings predictions = [] for movie_id in movies_to_predict: pred = svd_model.predict(user_id, movie_id) if pred.est >= min_rating: predictions.append({ 'movieId': movie_id, 'predicted_rating': pred.est }) if not predictions: return f"No movies found with predicted rating >= {min_rating}. Try lowering the minimum rating." # Sort and get top N predictions_df = pd.DataFrame(predictions) predictions_df = predictions_df.sort_values('predicted_rating', ascending=False) top_recommendations = predictions_df.head(num_recommendations) # Merge with movie details recommendations = top_recommendations.merge(movies, on='movieId') recommendations['predicted_rating'] = recommendations['predicted_rating'].round(2) # Format output output = f"🎬 Top {len(recommendations)} Movie Recommendations for User {user_id}\n\n" for idx, row in recommendations.iterrows(): output += f"{idx + 1}. **{row['title']}**\n" output += f" ⭐ Predicted Rating: {row['predicted_rating']}/5.0\n" output += f" 🎭 Genres: {row['genres']}\n\n" return output except Exception as e: return f"❌ Error: {str(e)}" def get_user_history(user_id): """ Get user's rating history """ try: user_id = int(user_id) if user_id not in ratings['userId'].values: return f"⚠️ User ID {user_id} not found." user_ratings = ratings[ratings['userId'] == user_id].merge(movies, on='movieId') user_ratings = user_ratings.sort_values('rating', ascending=False).head(10) output = f"📊 User {user_id}'s Top Rated Movies:\n\n" for idx, row in user_ratings.iterrows(): output += f"• **{row['title']}** - ⭐ {row['rating']}/5.0\n" output += f" Genres: {row['genres']}\n\n" return output except Exception as e: return f"❌ Error: {str(e)}" # Create Gradio interface with gr.Blocks(theme=gr.themes.Soft()) as demo: gr.Markdown( """ # 🎬 MovieLens Recommendation System ### Powered by SVD Matrix Factorization Get personalized movie recommendations based on collaborative filtering! """ ) with gr.Tab("🎯 Get Recommendations"): with gr.Row(): with gr.Column(): user_id_input = gr.Number( label="User ID", value=1, info=f"Enter a user ID (1 to {ratings['userId'].max()})" ) num_rec_input = gr.Slider( minimum=5, maximum=20, value=10, step=1, label="Number of Recommendations" ) min_rating_input = gr.Slider( minimum=1.0, maximum=5.0, value=3.5, step=0.5, label="Minimum Predicted Rating" ) recommend_btn = gr.Button("🎬 Get Recommendations", variant="primary") with gr.Column(): recommendations_output = gr.Markdown(label="Recommendations") recommend_btn.click( fn=recommend_movies, inputs=[user_id_input, num_rec_input, min_rating_input], outputs=recommendations_output ) with gr.Tab("📊 User History"): with gr.Row(): with gr.Column(): history_user_id = gr.Number( label="User ID", value=1, info="Enter a user ID to see their rating history" ) history_btn = gr.Button("📊 View History", variant="primary") with gr.Column(): history_output = gr.Markdown(label="User History") history_btn.click( fn=get_user_history, inputs=history_user_id, outputs=history_output ) gr.Markdown( """ --- ### 📈 Model Information - **Algorithm**: SVD (Singular Value Decomposition) - **Dataset**: MovieLens Small (100K ratings) - **Evaluation Metrics**: RMSE, Precision@K, Recall@K, NDCG@K - **Best Performance**: Lowest RMSE and Highest NDCG among tested models """ ) if __name__ == "__main__": demo.launch()