MohamedMotaz commited on
Commit
411d2c3
1 Parent(s): 5b2221d

Adding app file

Browse files
Files changed (3) hide show
  1. .gitignore +1 -0
  2. app.py +412 -2
  3. requirements.txt +5 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ Models/similarity_matrix.pkl
app.py CHANGED
@@ -1,4 +1,414 @@
1
  import streamlit as st
 
 
 
 
 
2
 
3
- x = st.slider('Select a value')
4
- st.write(x, 'squared is', x * x)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import requests
3
+ import pandas as pd
4
+ import pickle
5
+ import gdown
6
+ import os
7
 
8
+ # CSV files URLs as raw data from GitHub repository
9
+ moviesCSV = "Data/movies.csv"
10
+ ratingsCSV = "Data/ratings.csv"
11
+ linksCSV = "Data/links.csv"
12
+
13
+ # the folloing code is used to download the similarity matrix from google drive if not exist
14
+ file_url = 'https://drive.google.com/file/d/1-1bpusE96_Hh0rUxU7YmBo6RiwYLQGVy/view?usp=sharing'
15
+ output_path = 'Models/similarity_matrix.pkl'
16
+
17
+ @st.cache_data
18
+ def download_model_from_google_drive(file_url, output_path):
19
+ gdown.download(file_url, output_path, quiet=False)
20
+
21
+
22
+ # # Check if the file already exists
23
+ if not os.path.exists(output_path):
24
+ print("Downloading the similarity matrix from Googlr Drive...")
25
+ # download_model_from_google_drive(file_url, output_path)
26
+
27
+
28
+ # Set page configuration
29
+ st.set_page_config(page_title="Movie Recommendation", page_icon="🎬", layout="wide")
30
+
31
+ # Dummy data for user recommendations
32
+ user_recommendations = {
33
+ "1": ["Inception", "The Matrix", "Interstellar"],
34
+ "2": ["The Amazing Spider-Man", "District 9", "Titanic"]
35
+ }
36
+
37
+ # Function to hash passwords
38
+ def hash_password(password):
39
+ return password
40
+
41
+ # Dummy user database
42
+ user_db = {
43
+ "1": hash_password("password123"),
44
+ "2": hash_password("mypassword")
45
+ }
46
+
47
+ # Login function
48
+ def login(email, password):
49
+ if email in user_db:
50
+ return True
51
+ return False
52
+
53
+ # Function to fetch movie details from OMDb API
54
+ def fetch_movie_details(title, api_key="23f109b2"):
55
+ url = f"http://www.omdbapi.com/?t={title}&apikey={api_key}"
56
+ response = requests.get(url)
57
+ return response.json()
58
+
59
+ # Display movie details
60
+ def display_movie_details(movie):
61
+ if movie['Response'] == 'False':
62
+ st.write(f"Movie not found: {movie['Error']}")
63
+ return
64
+ if movie['imdbRating'] == 'N/A':
65
+ movie['imdbRating'] = 0
66
+ imdb_rating = float(movie['imdbRating'])
67
+ url = f"https://www.imdb.com/title/{movie['imdbID']}/"
68
+ st.markdown(
69
+ f"""
70
+ <div style="
71
+ background-color: #313131;
72
+ border-radius: 15px;
73
+ padding: 10px;
74
+ margin: 10px 0;
75
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
76
+ ">
77
+ <div style="display: flex;">
78
+ <div style="flex: 1;">
79
+ <BR>
80
+ <a href="{url}" target="_blank" >
81
+ <img src="{movie['Poster']}" style="width: 100%; border-radius: 10px;" />
82
+ </a>
83
+ </div>
84
+ <div style="flex: 3; padding-left: 20px;">
85
+ <h2 style="margin: 0;" anchor="{url}">{movie['Title']}</h2>
86
+ <p style="color: gray;">
87
+ <b>Year:</b> {movie['Year']} Rated: {movie['Rated']} <br>
88
+ <b>Genre:</b> {movie['Genre'].replace(',',' |')} <br>
89
+ </p>
90
+ <p>{movie['Plot']}</p>
91
+ <div style="margin-top: 10px;">
92
+ <div style="background-color: #e0e0e0; border-radius: 5px; overflow: hidden;">
93
+ <div style="width: {imdb_rating * 10}%; background-color: #4caf50; padding: 5px 0; text-align: center; color: white;">
94
+ {imdb_rating}
95
+ </div>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ """, unsafe_allow_html=True
102
+ )
103
+
104
+
105
+
106
+
107
+ def print_movie_details(movie):
108
+ st.markdown(
109
+ f"""
110
+ <div class="recommendation">
111
+ <div style="display: flex;">
112
+ <div style="flex: 1;">
113
+ <a href="https://www.imdb.com/title/tt{movie['imdb_id']:07d}/" target="_blank">
114
+ <img src="{movie['poster_url']}" />
115
+ </a>
116
+ </div>
117
+ <div style="flex: 3; padding-left: 20px;">
118
+ <h4 style="margin: 0;">{' '.join(movie['title'].split(" ")[:-1])}</h4>
119
+ <p style="color: gray;">
120
+ <b>Year:</b> {movie['title'].split(" ")[-1]}<br>
121
+ <b>Genre:</b> {', '.join(movie['genres'])}<br>
122
+ <b>Number of Ratings:</b> {movie['num_ratings']}<br>
123
+ <b>IMDb Rating: </b>{round(movie["imdb_rating"],1)}<br>
124
+ </p>
125
+ <div style="margin-top: 10px;">
126
+ <div style="background-color: #e0e0e0; border-radius: 5px; overflow: hidden;">
127
+ <div style="width: {movie['avg_rating'] * 20}%; background-color: #4caf50; padding: 5px 0; text-align: center; color: white;">
128
+ {movie['avg_rating']}
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ """,
136
+ unsafe_allow_html=True
137
+ )
138
+
139
+
140
+
141
+ # Function to load data
142
+ @st.cache_data
143
+ def load_data():
144
+ movies_df = pd.read_csv(moviesCSV)
145
+ ratings_df = pd.read_csv(ratingsCSV)
146
+ links_df = pd.read_csv(linksCSV)
147
+ return movies_df, ratings_df, links_df
148
+
149
+ # Function to load similarity matrix
150
+ @st.cache_data
151
+ def load_similarity_matrix():
152
+ with open('Models/similarity_matrix.pkl', 'rb') as f:
153
+ similarity_df = pickle.load(f)
154
+ return similarity_df
155
+
156
+ # Function to get movie details
157
+ def get_movie_details(movie_id, df_movies, df_ratings, df_links):
158
+ try:
159
+ imdb_id = df_links[df_links['movieId'] == movie_id]['imdbId'].values[0]
160
+ tmdb_id = df_links[df_links['movieId'] == movie_id]['tmdbId'].values[0]
161
+
162
+ movie_data = df_movies[df_movies['movieId'] == movie_id].iloc[0]
163
+ genres = movie_data['genres'].split('|') if 'genres' in movie_data else []
164
+
165
+ avg_rating = df_ratings[df_ratings['movieId'] == movie_id]['rating'].mean()
166
+ num_ratings = df_ratings[df_ratings['movieId'] == movie_id].shape[0]
167
+
168
+ api_key = 'b8c96e534866701532768a313b978c8b'
169
+ response = requests.get(f'https://api.themoviedb.org/3/movie/{tmdb_id}?api_key={api_key}' )
170
+ poster_url = response.json().get('poster_path', '')
171
+ full_poster_url = f'https://image.tmdb.org/t/p/w500{poster_url}' if poster_url else ''
172
+ imdb_rating = response.json().get('vote_average', 0)
173
+
174
+ return {
175
+ "title": movie_data['title'],
176
+ "genres": genres,
177
+ "avg_rating": round(avg_rating, 2),
178
+ "num_ratings": num_ratings,
179
+ "imdb_id": imdb_id,
180
+ "tmdb_id": tmdb_id,
181
+ "poster_url": full_poster_url,
182
+ "imdb_rating": imdb_rating
183
+ }
184
+ except Exception as e:
185
+ st.error(f"Error fetching details for movie ID {movie_id}: {e}")
186
+ return None
187
+
188
+ # Function to recommend movies
189
+ def recommend(movie, similarity_df, movies_df, ratings_df, links_df, k=5):
190
+ try:
191
+ index = movies_df[movies_df['title'] == movie].index[0]
192
+ distances = sorted(list(enumerate(similarity_df.iloc[index])), reverse=True, key=lambda x: x[1])
193
+ recommended_movies = []
194
+ for i in distances[1:k+1]:
195
+ movie_id = movies_df.iloc[i[0]]['movieId']
196
+ movie_details = get_movie_details(movie_id, movies_df, ratings_df, links_df)
197
+ if movie_details:
198
+ recommended_movies.append(movie_details)
199
+ return recommended_movies
200
+ except Exception as e:
201
+ st.error(f"Error generating recommendations: {e}")
202
+ return []
203
+
204
+ # Main app
205
+
206
+ def main():
207
+ st.markdown(
208
+ """
209
+ <style>
210
+ body {
211
+ background-image: url("https://repository-images.githubusercontent.com/275336521/20d38e00-6634-11eb-9d1f-6a5232d0f84f");
212
+ color: #FFFFFF;
213
+ font-family: 'Arial', sans-serif;
214
+ }
215
+
216
+ .stApp {
217
+ background: rgba(0, 0, 0, 0.7);
218
+ border-radius: 15px;
219
+ padding: 20px;
220
+ }
221
+
222
+ .title {
223
+ font-size: 3em;
224
+ text-align: center;
225
+ margin-bottom: 20px;
226
+ font-weight: bold;
227
+ color: #FF0000;
228
+ }
229
+
230
+ .section-title {
231
+ font-size: 2em;
232
+ margin-top: 30px;
233
+ margin-bottom: 20px;
234
+ text-align: center;
235
+ color: #FFD700;
236
+ }
237
+
238
+ .recommendation {
239
+ border: 1px solid #FFD700;
240
+ padding: 20px;
241
+ margin-bottom: 20px;
242
+ border-radius: 15px;
243
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
244
+ transition: transform 0.2s, box-shadow 0.2s;
245
+ background-color: rgba(0, 0, 0, 0.8);
246
+ overflow: hidden;
247
+ }
248
+
249
+ .recommendation:hover {
250
+ transform: translateY(-10px);
251
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.5);
252
+ }
253
+
254
+ .recommendation img {
255
+ width: 100%;
256
+ height: 200px;
257
+ object-fit: cover;
258
+ border-radius: 10px;
259
+ margin-bottom: 10px;
260
+ }
261
+
262
+ .movie-details-container {
263
+ display: flex;
264
+ align-items: center;
265
+ margin-bottom: 20px;
266
+ }
267
+
268
+ .movie-details-container .movie-poster {
269
+ flex: 0 0 auto;
270
+ width: 30%;
271
+ margin-right: 20px;
272
+ }
273
+
274
+ .movie-details-container .movie-poster img {
275
+ width: 100%;
276
+ border-radius: 10px;
277
+ }
278
+
279
+ .movie-details-container .movie-details {
280
+ flex: 1 1 auto;
281
+ }
282
+
283
+ .movie-details-container .movie-details p {
284
+ margin: 5px 0;
285
+ }
286
+
287
+ a {
288
+ color: #FFD700;
289
+ text-decoration: none;
290
+ }
291
+
292
+ a:hover {
293
+ text-decoration: underline;
294
+ }
295
+
296
+ .stSidebar .element-container {
297
+ background: rgba(0, 0, 0, 0.7);
298
+ border-radius: 15px;
299
+ padding: 15px;
300
+ }
301
+
302
+ .stSidebar .stButton button {
303
+ background-color: #FFD700;
304
+ color: #000;
305
+ border: none;
306
+ border-radius: 10px;
307
+ padding: 10px;
308
+ transition: background-color 0.2s, transform 0.2s;
309
+ }
310
+
311
+ .stSidebar .stButton button:hover {
312
+ background-color: #FFAA00;
313
+ transform: scale(1.05);
314
+ }
315
+ </style>
316
+ """,
317
+ unsafe_allow_html=True
318
+ )
319
+
320
+ movies_df, ratings_df, links_df = load_data()
321
+ similarity_df = load_similarity_matrix()
322
+
323
+ st.sidebar.title("Navigation")
324
+ menu = ["Login", "Movie Similarity"]
325
+ choice = st.sidebar.selectbox("Select an option", menu)
326
+
327
+ if choice == "Login":
328
+ st.title("Movie Recommendations")
329
+ st.write("Welcome to the Movie Recommendation App!")
330
+ st.write("Please login to get personalized movie recommendations. username between (1 and 800)")
331
+ st.write("leve password blank for now.")
332
+
333
+ # Login form
334
+ st.sidebar.header("Login")
335
+ email = st.sidebar.text_input("Username")
336
+ # password = st.sidebar.text_input("Password", type="password")
337
+ if st.sidebar.button("Login"):
338
+ if login(email, 'password'):
339
+ st.sidebar.success("Login successful!")
340
+ recommendations = user_recommendations.get(email, [])
341
+ st.write(f"Recommendations for user number {email}:")
342
+ num_cols = 2
343
+ cols = st.columns(num_cols)
344
+ for i, movie_title in enumerate(recommendations):
345
+ movie = fetch_movie_details(movie_title)
346
+ if movie['Response'] == 'True':
347
+ with cols[i % num_cols]:
348
+ display_movie_details(movie)
349
+ else:
350
+ st.write(f"Movie details for '{movie_title}' not found.")
351
+ else:
352
+ st.sidebar.error("Invalid email or password")
353
+
354
+ elif choice == "Movie Similarity":
355
+ num_cols = 2
356
+ cols = st.columns(num_cols)
357
+
358
+ # Movie similarity search
359
+ with cols[0]:
360
+ st.title("Find Similar Movies")
361
+ selected_movie = st.selectbox("Type or select a movie from the dropdown", movies_df['title'].unique())
362
+ k = st.slider("Select the number of recommendations (k)", min_value=1, max_value=50, value=5)
363
+ button = st.button("Find Similar Movies")
364
+ with cols[1]:
365
+ st.title("Choosen Movie Details:")
366
+ if selected_movie:
367
+ correct_Name = selected_movie[:-7]
368
+ movie = fetch_movie_details(correct_Name)
369
+ if movie['Response'] == 'True':
370
+ display_movie_details(movie)
371
+ else:
372
+ st.write(f"Movie details for '{selected_movie}' not found.")
373
+ if button:
374
+ st.write("The rating bar here is token from our dataset and it's between 0 and 5.")
375
+ if selected_movie:
376
+ recommendations = recommend(selected_movie, similarity_df, movies_df, ratings_df, links_df, k)
377
+ if recommendations:
378
+ st.write(f"Similar movies to '{selected_movie}':")
379
+ num_cols = 2
380
+ cols = st.columns(num_cols)
381
+
382
+ # movie_id = movies_df[movies_df['title'] == selected_movie]['movieId'].values[0]
383
+ # movie_details = get_movie_details(movie_id, movies_df, ratings_df, links_df)
384
+ # if movie_details:
385
+ # st.markdown(f'<h2 class="section-title">{movie_details["title"]} Details:</h2>', unsafe_allow_html=True)
386
+ # st.markdown(
387
+ # f"""
388
+ # <div class="movie-details-container">
389
+ # <div class="movie-poster">
390
+ # <img src="{movie_details['poster_url']}" alt="Movie Poster">
391
+ # </div>
392
+ # <div class="movie-details">
393
+ # <p><b>Genres:</b> {', '.join(movie_details['genres'])}</p>
394
+ # <p><b>Average Rating:</b> {movie_details['avg_rating']}</p>
395
+ # <p><b>Number of Ratings:</b> {movie_details['num_ratings']}</p>
396
+ # <p><b>IMDb :</b> <a href="https://www.imdb.com/title/tt{movie_details['imdb_id']:07d}/" target="_blank">movie link</a></p>
397
+ # </div>
398
+ # </div>
399
+ # """,
400
+ # unsafe_allow_html=True
401
+ # )
402
+
403
+
404
+
405
+ for i, movie in enumerate(recommendations):
406
+ with cols[i % num_cols]:
407
+ print_movie_details(movie)
408
+ else:
409
+ st.write("No recommendations found.")
410
+ else:
411
+ st.write("Please select a movie.")
412
+
413
+ if __name__ == "__main__":
414
+ main()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit==1.36.0
2
+ requests==2.31.0
3
+ pandas==2.2.2
4
+ pickleshare==0.7.5
5
+ gdown==5.1.0