Spaces:
Runtime error
Runtime error
import streamlit as st | |
import pandas as pd | |
import re | |
import requests | |
# DATA: | |
movies = pd.read_csv('https://raw.githubusercontent.com/tobiasaurer/movie-recommender-streamlit/main/data/movies.csv') | |
ratings = pd.read_csv('https://raw.githubusercontent.com/tobiasaurer/movie-recommender-streamlit/main/data/ratings.csv') | |
links = pd.read_csv('https://raw.githubusercontent.com/tobiasaurer/movie-recommender-streamlit/main/data/links.csv') | |
# clean titles column by moving "The" and "A" to the beginning of the string | |
# this makes it more searchable for users | |
movies.loc[lambda df: df["title"].str.contains(", The", regex=True), 'title'] = 'The ' + movies['title'] | |
movies.loc[lambda df: df["title"].str.contains(", The", regex=True), 'title'] = movies['title'].str.replace(", The", '', regex=True) | |
movies.loc[lambda df: df["title"].str.contains(", A", regex=True), 'title'] = 'A ' + movies['title'] | |
movies.loc[lambda df: df["title"].str.contains(", A", regex=True), 'title'] = movies['title'].str.replace(", A", '', regex=True) | |
# extract year from title and store it in new column | |
movies= movies.assign(year = lambda df_ : df_['title'].replace(r'(.*)\((\d{4})\)', r'\2', regex= True)) | |
movies.year = pd.to_numeric(movies.year, errors= 'coerce').fillna(0).astype('int') | |
# INSTRUCTIONS: | |
st.title("Popularity-Based Recommender") | |
# FUNCTIONS: | |
def get_popular_recommendations(n, genres, time_range): | |
recommendations = ( | |
ratings | |
.groupby('movieId') | |
.agg(avg_rating = ('rating', 'mean'), num_ratings = ('rating', 'count')) | |
.merge(movies, on='movieId') | |
.assign(combined_rating = lambda x: x['avg_rating'] * x['num_ratings']**0.5) | |
[lambda df: df["genres"].str.contains(genres, regex=True)] | |
.loc[lambda df : ((df['year'] >= time_range[0]) & ( df['year'] <= time_range[1]))] | |
.sort_values('combined_rating', ascending=False) | |
.head(n) | |
[['title', 'avg_rating', 'genres']] | |
.rename(columns= {'title': 'Movie Title', 'avg_rating': 'Average Rating', 'genres': 'Genres'}) | |
) | |
return recommendations | |
def get_popular_recommendations_streaming(n, genres, time_range, country, url, headers): | |
recommendations = ( | |
ratings | |
.groupby('movieId') | |
.agg(avg_rating = ('rating', 'mean'), num_ratings = ('rating', 'count')) | |
.merge(movies, on='movieId') | |
.assign(combined_rating = lambda x: x['avg_rating'] * x['num_ratings']**0.5) | |
[lambda df: df["genres"].str.contains(genres, regex=True)] | |
.loc[lambda df : ((df['year'] >= time_range[0]) & ( df['year'] <= time_range[1]))] | |
.sort_values('combined_rating', ascending=False) | |
.head(n) | |
[['title', 'avg_rating', 'genres', 'movieId']] | |
) | |
# merge recommendations with links df to get imdbIds for the API calls | |
recommendations_ids = ( | |
recommendations | |
.merge(links, how = 'left', on = 'movieId') | |
# [['title', 'genres', 'imdbId']] | |
) | |
recommendations_ids['imdbId'] = 'tt0' + recommendations_ids['imdbId'].astype('str') | |
imdb_ids = list(recommendations_ids['imdbId']) | |
# create new column for streaming links | |
recommendations_ids['Streaming Availability'] = "" | |
# loop through imdb_ids to make one api call for each to get available streaming links | |
for id in imdb_ids: | |
# make api call | |
try: | |
querystring = {"country":country,"imdb_id":id,"output_language":"en"} | |
response = requests.request("GET", url, headers=headers, params=querystring) | |
streaming_info = response.json() | |
for streaming_service in streaming_info['streamingInfo']: | |
recommendations_ids.loc[recommendations_ids['imdbId'] == id, 'Streaming Availability'] += f"{streaming_service}: {streaming_info['streamingInfo'][streaming_service][country]['link']} \n" | |
except: | |
continue | |
recommendations_ids.rename(columns= {'title': 'Movie Title', 'genres': 'Genres'}, inplace = True) | |
return recommendations_ids[['Movie Title', 'Genres', 'Streaming Availability']] | |
def transform_genre_to_regex(genres): | |
regex = "" | |
for genre in genres: | |
regex += f"(?=.*{genre})" | |
return regex | |
# USER INPUT: | |
st.write(""" | |
Move the slider to the desired number of recommendations you wish to receive. | |
""") | |
number_of_recommendations = st.slider("Number of recommendations", 1, 10, 5) | |
st.write(""" | |
Move the sliders to choose a timeperiod for your recommendations. | |
""") | |
time_range = st.slider('Time-period:', min_value=1900, max_value=2018, value=(1900, 2018), step=1) | |
st.write(""" | |
__Optional__: You can narrow down the recommendations by picking one or several genre(s). | |
However, the more genres you choose, the fewer movies will be recommended. | |
""") | |
genre_list = list(set([inner for outer in movies.genres.str.split('|') for inner in outer])) | |
genre_list.sort() | |
genres = st.multiselect('Optional: Select one or more genres', genre_list, default=None, key=None, help=None, on_change=None, args=None, kwargs=None, disabled=False) | |
genres_regex = transform_genre_to_regex(genres) | |
st.write(""" | |
__Optional__: You can receive links for popular streaming services for each recommendation (if available) by selecting your countrycode. | |
Select none if you don't want to get streaming links. | |
""") | |
streaming_country = st.selectbox('Optional: Country for streaming information', ('none', 'de', 'us')) | |
# API INFORMATION: | |
# Streaming availability | |
url = "https://streaming-availability.p.rapidapi.com/get/basic" | |
headers = { | |
"X-RapidAPI-Key": st.secrets["api_key"], | |
"X-RapidAPI-Host": "streaming-availability.p.rapidapi.com" | |
} | |
# EXECUTION: | |
if st.button("Get Recommendations"): | |
if streaming_country == 'none': | |
st.write(get_popular_recommendations(number_of_recommendations, genres_regex, time_range)) | |
else: | |
try: | |
recommendations = get_popular_recommendations_streaming(number_of_recommendations, genres_regex, time_range, streaming_country, url, headers) | |
st.write("Double-click on a Streaming-Availability cell to see all options.", recommendations) | |
except: | |
recommendations = get_popular_recommendations(number_of_recommendations, genres_regex, time_range) | |
st.write('Error: Streaming information could not be gathered. Providing output without streaming availability instead.', recommendations) |