File size: 13,087 Bytes
c3c7748 63361d4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
import pandas as pd
import streamlit as st
from anime_recommender.model_trainer.content_based_modelling import ContentBasedRecommender
from anime_recommender.model_trainer.collaborative_modelling import CollaborativeAnimeRecommender
from anime_recommender.model_trainer.top_anime_filtering import PopularityBasedFiltering
import joblib
from anime_recommender.constant import *
from huggingface_hub import hf_hub_download
from datasets import load_dataset
def run_app():
"""
Initializes the Streamlit app, loads necessary datasets and models,
and provides a UI for anime recommendations based on three methods:
Content-Based, Collaborative, and Popularity-Based Filtering. ๐ฌ๐ฎ
"""
# Set page configuration
st.set_page_config(page_title="Anime Recommendation System", layout="wide")
# Load datasets if not present in session state
if "anime_data" not in st.session_state or "anime_user_ratings" not in st.session_state:
# Load datasets from Hugging Face (assuming no splits)
animedataset = load_dataset(ANIME_FILE_PATH, split=None)
mergeddataset = load_dataset(ANIMEUSERRATINGS_FILE_PATH, split=None)
# Convert the dataset to Pandas DataFrame
st.session_state.anime_data = pd.DataFrame(animedataset["train"])
st.session_state.anime_user_ratings = pd.DataFrame(mergeddataset["train"])
# Load models only once
if "models_loaded" not in st.session_state:
st.session_state.models_loaded = {}
# Load models
st.session_state.models_loaded["cosine_similarity_model"] = hf_hub_download(MODELS_FILEPATH, MODEL_TRAINER_COSINESIMILARITY_MODEL_NAME)
st.session_state.models_loaded["item_based_knn_model_path"] = hf_hub_download(MODELS_FILEPATH, MODEL_TRAINER_ITEM_KNN_TRAINED_MODEL_NAME)
st.session_state.models_loaded["user_based_knn_model_path"] = hf_hub_download(MODELS_FILEPATH, MODEL_TRAINER_USER_KNN_TRAINED_MODEL_NAME)
st.session_state.models_loaded["svd_model_path"] = hf_hub_download(MODELS_FILEPATH, MODEL_TRAINER_SVD_TRAINED_MODEL_NAME)
# Load the models using joblib
with open(st.session_state.models_loaded["item_based_knn_model_path"], "rb") as f:
st.session_state.models_loaded["item_based_knn_model"] = joblib.load(f)
with open(st.session_state.models_loaded["user_based_knn_model_path"], "rb") as f:
st.session_state.models_loaded["user_based_knn_model"] = joblib.load(f)
with open(st.session_state.models_loaded["svd_model_path"], "rb") as f:
st.session_state.models_loaded["svd_model"] = joblib.load(f)
print("Models loaded successfully!")
# Access the data from session state
anime_data = st.session_state.anime_data
anime_user_ratings = st.session_state.anime_user_ratings
# # Display dataset info
# st.write("Anime Data:")
# st.dataframe(anime_data.head())
# st.write("Anime User Ratings Data:")
# st.dataframe(anime_user_ratings.head())
# Access the models from session state
cosine_similarity_model_path = hf_hub_download(MODELS_FILEPATH, MODEL_TRAINER_COSINESIMILARITY_MODEL_NAME)
item_based_knn_model = st.session_state.models_loaded["item_based_knn_model"]
user_based_knn_model = st.session_state.models_loaded["user_based_knn_model"]
svd_model = st.session_state.models_loaded["svd_model"]
print("Models loaded successfully!")
# Streamlit UI
app_selector = st.sidebar.radio(
"Select App", ("Content-Based Recommender", "Collaborative Recommender", "Top Anime Recommender")
)
# Content-Based Recommender App
if app_selector == "Content-Based Recommender":
st.title("Content-Based Recommendation System")
try:
anime_list = anime_data["name"].tolist()
anime_name = st.selectbox("Pick an anime..unlock similar anime recommendations..", anime_list)
# Set number of recommendations
max_recommendations = min(len(anime_data), 100)
n_recommendations = st.slider("Number of Recommendations", 1, max_recommendations, 10)
# Inject custom CSS for anime name font size
st.markdown(
"""
<style>
.anime-title {
font-size: 14px !important;
font-weight: bold;
text-align: center;
margin-top: 5px;
}
</style>
""",
unsafe_allow_html=True,
)
# Get Recommendations
if st.button("Get Recommendations"):
try:
recommender = ContentBasedRecommender(anime_data)
recommendations = recommender.get_rec_cosine(anime_name, n_recommendations=n_recommendations,model_path=cosine_similarity_model_path)
if isinstance(recommendations, str):
st.warning(recommendations)
elif recommendations.empty:
st.warning("No recommendations found.๐ง")
else:
st.write(f"Here are the Content-based Recommendations for {anime_name}:")
cols = st.columns(5)
for i, row in enumerate(recommendations.iterrows()):
col = cols[i % 5]
with col:
st.image(row[1]['Image URL'], use_container_width=True)
st.markdown(
f"<div class='anime-title'>{row[1]['Anime name']}</div>",
unsafe_allow_html=True,
)
st.caption(f"Genres: {row[1]['Genres']} | Rating: {row[1]['Rating']}")
except Exception as e:
st.error(f"Unexpected error: {str(e)}")
except Exception as e:
st.error(f"Unexpected error: {str(e)}")
elif app_selector == "Collaborative Recommender":
st.title("Collaborative Recommender System ๐งโ๐คโ๐ง๐ฌ")
try:
# Sidebar for choosing the collaborative filtering method
collaborative_method = st.sidebar.selectbox(
"Choose a collaborative filtering method:",
["SVD Collaborative Filtering", "User-Based Collaborative Filtering", "Anime-Based KNN Collaborative Filtering"]
)
# User input
if collaborative_method == "SVD Collaborative Filtering" or collaborative_method == "User-Based Collaborative Filtering":
user_ids = anime_user_ratings['user_id'].unique()
user_id = st.selectbox("Select your MyAnimeList user ID to get anime recommendations based on similar users", user_ids)
n_recommendations = st.slider("Number of Recommendations:", min_value=1, max_value=50, value=10)
elif collaborative_method == "Anime-Based KNN Collaborative Filtering":
anime_list = anime_user_ratings["name"].dropna().unique().tolist()
anime_name = st.selectbox("Pick an anime, and we'll suggest more titles you'll love", anime_list)
n_recommendations = st.slider("Number of Recommendations:", min_value=1, max_value=50, value=10)
# Get recommendations
if st.button("Get Recommendations"):
# Load the recommender
recommender = CollaborativeAnimeRecommender(anime_user_ratings)
if collaborative_method == "SVD Collaborative Filtering":
recommendations = recommender.get_svd_recommendations(user_id, n=n_recommendations, svd_model=svd_model)
elif collaborative_method == "User-Based Collaborative Filtering":
recommendations = recommender.get_user_based_recommendations(user_id, n_recommendations=n_recommendations, knn_user_model=user_based_knn_model)
elif collaborative_method == "Anime-Based KNN Collaborative Filtering":
if anime_name:
recommendations = recommender.get_item_based_recommendations(anime_name, n_recommendations=n_recommendations, knn_item_model=item_based_knn_model)
else:
st.error("Invalid Anime Name. Please enter a valid anime title.")
if isinstance(recommendations, pd.DataFrame) and not recommendations.empty:
if len(recommendations) < n_recommendations:
st.warning(f"Oops...Only {len(recommendations)} recommendations available, fewer than the requested {n_recommendations}.")
st.write(f"Here are the {collaborative_method} Recommendations:")
cols = st.columns(5)
for i, row in enumerate(recommendations.iterrows()):
col = cols[i % 5]
with col:
st.image(row[1]['Image URL'], use_container_width=True)
st.markdown(
f"<div class='anime-title'>{row[1]['Anime Name']}</div>",
unsafe_allow_html=True,
)
st.caption(f"Genres: {row[1]['Genres']} | Rating: {row[1]['Rating']}")
else:
st.error("No recommendations found.")
except Exception as e:
st.error(f"An error occurred: {e}")
elif app_selector == "Top Anime Recommender":
st.title("Top Anime Recommender System ๐ฅ")
try:
popularity_method = st.sidebar.selectbox(
"Choose a Popularity-Based Filtering method:",
[
"Popular Animes",
"Top Ranked Animes",
"Overall Top Rated Animes",
"Favorite Animes",
"Top Animes by Members",
"Popular Anime Among Members",
"Top Average Rated Animes",
]
)
n_recommendations = st.slider("Number of Recommendations:", min_value=1, max_value=500 , value=10)
if st.button("Get Recommendations"):
recommender = PopularityBasedFiltering(anime_data)
# Get recommendations based on selected method
if popularity_method == "Popular Animes":
recommendations = recommender.popular_animes(n=n_recommendations)
elif popularity_method == "Top Ranked Animes":
recommendations = recommender.top_ranked_animes(n=n_recommendations)
elif popularity_method == "Overall Top Rated Animes":
recommendations = recommender.overall_top_rated_animes(n=n_recommendations)
elif popularity_method == "Favorite Animes":
recommendations = recommender.favorite_animes(n=n_recommendations)
elif popularity_method == "Top Animes by Members":
recommendations = recommender.top_animes_members(n=n_recommendations)
elif popularity_method == "Popular Anime Among Members":
recommendations = recommender.popular_anime_among_members(n=n_recommendations)
elif popularity_method == "Top Average Rated Animes":
recommendations = recommender.top_avg_rated(n=n_recommendations)
else:
st.error("Invalid selection. Please choose a valid method.")
recommendations = None
# Display recommendations
if isinstance(recommendations, pd.DataFrame) and not recommendations.empty:
st.write(f" Here are the Recommendations:")
cols = st.columns(5)
for i, row in recommendations.iterrows():
col = cols[i % 5]
with col:
st.image(row['Image URL'], use_container_width=True)
st.markdown(
f"<div class='anime-title'>{row['Anime name']}</div>",
unsafe_allow_html=True,
)
st.caption(f"Genres: {row['Genres']} | Rating: {row['Rating']}")
else:
st.error("No recommendations found.")
except Exception as e:
st.error(f"An error occurred: {e}")
if __name__ == "__main__":
run_app() |