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()