CrimsonREwind commited on
Commit
4d39f31
·
verified ·
1 Parent(s): ffbe32a

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +167 -0
main.py ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, redirect, url_for, session, flash
2
+ import pandas as pd
3
+ import joblib
4
+ from fuzzywuzzy import process
5
+ from flask_bcrypt import Bcrypt
6
+ from functools import wraps
7
+ import os
8
+ from supabase import create_client, Client
9
+ from dotenv import load_dotenv
10
+
11
+
12
+ load_dotenv()
13
+
14
+ app = Flask(__name__)
15
+ app.secret_key = os.getenv("SECRET_KEY")
16
+ bcrypt = Bcrypt(app)
17
+
18
+ SUPABASE_URL = os.getenv("URL")
19
+ SUPABASE_KEY = os.getenv("KEY")
20
+
21
+ supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
22
+
23
+ movies = pd.read_csv('core/data/processed_movies_with_posters.csv')
24
+ cosine_sim = joblib.load('core/model/cosine_sim.pkl')
25
+
26
+ def login_required(f):
27
+ @wraps(f)
28
+ def decorated_function(*args, **kwargs):
29
+ if 'logged_in' not in session:
30
+ flash('Please log in to access this page.', 'warning')
31
+ return redirect(url_for('login'))
32
+ return f(*args, **kwargs)
33
+ return decorated_function
34
+
35
+ @app.route('/login', methods=['GET', 'POST'])
36
+ def login():
37
+ if request.method == 'POST':
38
+ username = request.form['username']
39
+ password = request.form['password']
40
+
41
+ response = supabase.table('users').select('*').eq('username', username).execute()
42
+ if response.data:
43
+ user = response.data[0]
44
+ if bcrypt.check_password_hash(user['password'], password):
45
+ session['logged_in'] = True
46
+ session['username'] = username
47
+ return redirect(url_for('home'))
48
+
49
+ flash('Invalid username or password.', 'warning')
50
+
51
+ return render_template('login.html')
52
+
53
+ @app.route('/register', methods=['GET', 'POST'])
54
+ def register():
55
+ if request.method == 'POST':
56
+ username = request.form['username']
57
+ password = bcrypt.generate_password_hash(request.form['password']).decode('utf-8')
58
+
59
+ try:
60
+ response = supabase.table('users').insert({"username": username, "password": password}).execute()
61
+ if not response.data:
62
+ flash('Username already exists. Please choose a different one.', 'warning')
63
+ else:
64
+ flash('Registration successful! You can now log in.', 'success')
65
+ return redirect(url_for('login'))
66
+ except Exception as e:
67
+ if "duplicate key value violates unique constraint" in str(e):
68
+ flash(f"Username already exits", 'warning')
69
+ else:
70
+ flash(f"An error occurred: {str(e)}", 'warning')
71
+
72
+ return render_template('register.html')
73
+
74
+ @app.route('/logout')
75
+ @login_required
76
+ def logout():
77
+ session.clear()
78
+ flash('You have been logged out.', 'info')
79
+ return redirect(url_for('login'))
80
+
81
+
82
+ def get_recommendations(title, cosine_sim=cosine_sim):
83
+ title = title.lower()
84
+ if title not in movies['title'].str.lower().values:
85
+ close_matches = process.extract(title, movies['title'].str.lower().values, limit=5)
86
+ return None, [movies[movies['title'].str.lower() == match[0]].iloc[0] for match in close_matches]
87
+ idx = movies[movies['title'].str.lower() == title].index[0]
88
+ sim_scores = list(enumerate(cosine_sim[idx]))
89
+ sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
90
+ sim_scores = sim_scores[1:11]
91
+ movie_indices = [i[0] for i in sim_scores]
92
+ return movies.iloc[movie_indices], None
93
+
94
+ def get_recommendations_by_id(movie_id, cosine_sim=cosine_sim):
95
+ idx = movies[movies['id'] == movie_id].index[0]
96
+ sim_scores = list(enumerate(cosine_sim[idx]))
97
+ sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
98
+ sim_scores = sim_scores[1:6]
99
+ movie_indices = [i[0] for i in sim_scores]
100
+ return movies.iloc[movie_indices]
101
+
102
+ @app.route('/')
103
+ @login_required
104
+ def home():
105
+ return render_template('recommendation.html', movies=movies.sample(20).to_dict(orient='records'))
106
+
107
+ @app.route('/movie/<int:id>')
108
+ @login_required
109
+ def movie_details(id):
110
+ movie = movies[movies['id'] == id].iloc[0]
111
+ recommendations = get_recommendations_by_id(id).to_dict(orient='records')
112
+ return render_template('movie_details.html', movie=movie, recommendations=recommendations)
113
+
114
+ @app.route('/recommend', methods=['POST'])
115
+ @login_required
116
+ def recommend():
117
+ title = request.form['title']
118
+ recommendations, close_matches = get_recommendations(title)
119
+ if recommendations is None:
120
+ flash("Movie title not found. Did you mean one of these?", 'warning')
121
+ return render_template('recommendation.html', movies=[match.to_dict() for match in close_matches])
122
+ return render_template('recommendation.html', movies=recommendations.to_dict(orient='records'))
123
+
124
+ @app.route('/search', methods=['GET', 'POST'])
125
+ @login_required
126
+ def search():
127
+ if request.method == 'POST':
128
+ query = request.form['query']
129
+ results = movies[movies['title'].str.contains(query, case=False, na=False)]
130
+ return render_template('search.html', movies=results.to_dict(orient='records'))
131
+ return render_template('search.html', movies=None)
132
+
133
+ @app.route('/filter', methods=['GET', 'POST'])
134
+ @login_required
135
+ def filter():
136
+ genres = sorted(movies['genre'].str.split(',', expand=True).stack().dropna().unique())
137
+ languages = sorted(movies['original_language'].dropna().unique())
138
+
139
+ if request.method == 'POST':
140
+ selected_genre = request.form.get('genre')
141
+ selected_language = request.form.get('language')
142
+
143
+ if not selected_genre and not selected_language:
144
+ return render_template('filter.html', movies=None, genres=genres, languages=languages,
145
+ error_message="No movies found. Please adjust your filters.")
146
+
147
+ filtered_movies = movies.copy()
148
+
149
+ if selected_genre:
150
+ filtered_movies = filtered_movies[filtered_movies['genre'].str.contains(selected_genre, na=False)]
151
+
152
+ if selected_language:
153
+ filtered_movies = filtered_movies[filtered_movies['original_language'] == selected_language]
154
+
155
+ filtered_movies['genre'] = filtered_movies['genre'].fillna('').astype(str)
156
+
157
+ sample_size = min(50, len(filtered_movies))
158
+
159
+ filtered_movies = filtered_movies.sample(sample_size).to_dict(orient='records')
160
+
161
+ return render_template('filter.html', movies=filtered_movies, genres=genres, languages=languages,
162
+ error_message=None)
163
+
164
+ return render_template('filter.html', movies=None, genres=genres, languages=languages, error_message=None)
165
+
166
+ if __name__ == '__main__':
167
+ app.run(host='0.0.0.0', port=7860)