mtoft20 commited on
Commit
5d9be63
Β·
verified Β·
1 Parent(s): b4f0e3b

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +81 -0
src/streamlit_app.py CHANGED
@@ -3,6 +3,10 @@ import requests
3
  import pandas as pd
4
  from together import Together
5
  import os
 
 
 
 
6
 
7
  # =============================================================================
8
  # CONFIGURATION - Using Secrets Management
@@ -231,6 +235,68 @@ def extract_unique_names(content_list, field):
231
  unique_names.add(cleaned_name)
232
  return sorted(list(unique_names))
233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  # =============================================================================
235
  # MAIN APP
236
  # =============================================================================
@@ -434,6 +500,21 @@ def main():
434
  # Description
435
  st.write(f"**πŸ“– Description:**")
436
  st.write(content.get('description', 'N/A'))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
 
438
  if filtered_count > 10:
439
  st.info(f"Showing first 10 of {filtered_count:,} titles. Adjust filters to narrow results.")
 
3
  import pandas as pd
4
  from together import Together
5
  import os
6
+ from sklearn.feature_extraction.text import TfidfVectorizer
7
+ from sklearn.preprocessing import StandardScaler
8
+ from sklearn.cluster import KMeans
9
+ import numpy as np
10
 
11
  # =============================================================================
12
  # CONFIGURATION - Using Secrets Management
 
235
  unique_names.add(cleaned_name)
236
  return sorted(list(unique_names))
237
 
238
+ def prepare_movie_features(content_list):
239
+ """Prepare movie features for clustering"""
240
+ # Convert to DataFrame for easier processing
241
+ df = pd.DataFrame(content_list)
242
+
243
+ # Create TF-IDF features from genres and description
244
+ tfidf = TfidfVectorizer(stop_words='english')
245
+
246
+ # Combine genres and description for text features
247
+ df['text_features'] = df['listed_in'].fillna('') + ' ' + df['description'].fillna('')
248
+ text_features = tfidf.fit_transform(df['text_features']).toarray()
249
+
250
+ # Prepare numerical features
251
+ df['release_year'] = pd.to_numeric(df['release_year'], errors='coerce').fillna(0)
252
+
253
+ # Extract duration in minutes for movies
254
+ def extract_duration_minutes(duration):
255
+ if pd.isna(duration) or 'Season' in str(duration):
256
+ return 0
257
+ try:
258
+ return int(str(duration).split()[0])
259
+ except:
260
+ return 0
261
+
262
+ df['duration_minutes'] = df['duration'].apply(extract_duration_minutes)
263
+
264
+ # Scale numerical features
265
+ scaler = StandardScaler()
266
+ numerical_features = scaler.fit_transform(df[['release_year', 'duration_minutes']])
267
+
268
+ # Combine all features
269
+ all_features = np.hstack([text_features, numerical_features])
270
+
271
+ return all_features, df
272
+
273
+ def find_similar_content(content_list, selected_content, n_clusters=20, n_recommendations=5):
274
+ """Find similar content using k-means clustering"""
275
+ # Prepare features
276
+ features, df = prepare_movie_features(content_list)
277
+
278
+ # Perform k-means clustering
279
+ kmeans = KMeans(n_clusters=n_clusters, random_state=42)
280
+ cluster_labels = kmeans.fit_predict(features)
281
+
282
+ # Find the cluster of the selected content
283
+ selected_idx = df[df['title'] == selected_content['title']].index[0]
284
+ selected_cluster = cluster_labels[selected_idx]
285
+
286
+ # Get indices of content in the same cluster
287
+ cluster_indices = np.where(cluster_labels == selected_cluster)[0]
288
+
289
+ # Calculate distances to all points in the same cluster
290
+ cluster_features = features[cluster_indices]
291
+ selected_features = features[selected_idx].reshape(1, -1)
292
+ distances = np.linalg.norm(cluster_features - selected_features, axis=1)
293
+
294
+ # Get the indices of the most similar content (excluding the selected content)
295
+ similar_indices = cluster_indices[np.argsort(distances)][1:n_recommendations+1]
296
+
297
+ # Return the similar content
298
+ return [content_list[idx] for idx in similar_indices]
299
+
300
  # =============================================================================
301
  # MAIN APP
302
  # =============================================================================
 
500
  # Description
501
  st.write(f"**πŸ“– Description:**")
502
  st.write(content.get('description', 'N/A'))
503
+
504
+ # Add Find Similar button
505
+ if st.button(f"πŸ” Find Similar Content", key=f"similar_{i}"):
506
+ with st.spinner("Finding similar content..."):
507
+ similar_content = find_similar_content(all_content, content)
508
+
509
+ if similar_content:
510
+ st.write("**πŸ‘₯ Similar Content You Might Like:**")
511
+ for sim_content in similar_content:
512
+ with st.container():
513
+ st.write(f"**{sim_content.get('title')}** ({sim_content.get('type')}, {sim_content.get('release_year')})")
514
+ st.write(f"*Genres:* {sim_content.get('listed_in')}")
515
+ st.write("---")
516
+ else:
517
+ st.info("No similar content found.")
518
 
519
  if filtered_count > 10:
520
  st.info(f"Showing first 10 of {filtered_count:,} titles. Adjust filters to narrow results.")