File size: 3,441 Bytes
1eb2368
 
 
 
 
078fee7
 
dfb673b
078fee7
58fac9f
078fee7
 
1eb2368
 
 
dfb673b
 
 
078fee7
58fac9f
078fee7
6ee4115
078fee7
1eb2368
 
 
dfb673b
6ee4115
078fee7
dfb673b
 
 
078fee7
dfb673b
078fee7
dfb673b
 
 
078fee7
0eec7e8
 
1eb2368
 
 
 
dfb673b
078fee7
0eec7e8
1eb2368
dfb673b
1eb2368
6ee4115
0eec7e8
1eb2368
dfb673b
1eb2368
 
078fee7
 
 
1eb2368
6ee4115
0eec7e8
1eb2368
 
 
 
078fee7
0eec7e8
078fee7
 
dfb673b
 
 
 
 
 
 
1eb2368
dfb673b
 
 
 
 
 
 
 
1eb2368
dfb673b
 
 
 
 
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
import streamlit as st
import pandas as pd
import numpy as np
import tensorflow as tf
import joblib
import os

# Define file paths (assuming all files are in the same folder as this script)
BASE_DIR = os.path.dirname(__file__)
KERAS_MODEL_PATH = os.path.join(BASE_DIR, "recommender_model.keras")
MOVIES_PATH = os.path.join(BASE_DIR, "movies.csv")
ENCODINGS_PATH = os.path.join(BASE_DIR, "encodings.pkl")

@st.cache_resource
def load_model():
    if not os.path.exists(KERAS_MODEL_PATH):
        st.error(f"❌ Model file not found at: {KERAS_MODEL_PATH}")
        st.stop()
    try:
        return tf.keras.models.load_model(KERAS_MODEL_PATH)
    except Exception as e:
        st.error(f"❌ Failed to load model:\n\n{e}")
        st.stop()

@st.cache_data
def load_assets():
    if not os.path.exists(MOVIES_PATH):
        st.error("❌ movies.csv not found.")
        st.stop()
    if not os.path.exists(ENCODINGS_PATH):
        st.error("❌ encodings.pkl not found.")
        st.stop()
    try:
        df_movies = pd.read_csv(MOVIES_PATH)
        user_map, movie_map = joblib.load(ENCODINGS_PATH)
        return df_movies, user_map, movie_map
    except Exception as e:
        st.error(f"❌ Failed to load assets:\n\n{e}")
        st.stop()

# Load model and assets
model = load_model()
movies_df, user2idx, movie2idx = load_assets()
reverse_movie_map = {v: k for k, v in movie2idx.items()}

# UI
st.title("🎬 TensorFlow Movie Recommender")
st.write("Select some movies you've liked to get personalized recommendations:")

# Movie title selection
movie_titles = movies_df.set_index("movieId")["title"].to_dict()
movie_choices = [movie_titles[mid] for mid in movie2idx if mid in movie_titles]
selected_titles = st.multiselect("🎞️ Liked movies", sorted(movie_choices))

# User ratings dict
user_ratings = {}
for title in selected_titles:
    movie_id = next((k for k, v in movie_titles.items() if v == title), None)
    if movie_id:
        user_ratings[movie_id] = 5.0

# Generate recommendations
if st.button("🎯 Get Recommendations"):
    if not user_ratings:
        st.warning("Please select at least one movie.")
    else:
        liked_indices = [movie2idx[m] for m in user_ratings if m in movie2idx]
        if not liked_indices:
            st.error("⚠️ No valid movie encodings found.")
            st.stop()

        try:
            # Calculate average embedding and similarity scores
            avg_embedding = tf.reduce_mean(model.layers[2](tf.constant(liked_indices)), axis=0, keepdims=True)
            all_movie_indices = tf.range(len(movie2idx))
            movie_embeddings = model.layers[3](all_movie_indices)
            scores = tf.reduce_sum(avg_embedding * movie_embeddings, axis=1).numpy()
            top_indices = np.argsort(scores)[::-1]

            # Top 10 recommendations excluding already liked
            recommended = []
            for idx in top_indices:
                mid = reverse_movie_map.get(idx)
                if mid not in user_ratings and mid in movie_titles:
                    recommended.append((movie_titles[mid], scores[idx]))
                if len(recommended) >= 10:
                    break

            st.subheader("🍿 Top 10 Recommendations")
            for title, score in recommended:
                st.write(f"**{title}** β€” Score: `{score:.3f}`")
        except Exception as e:
            st.error(f"❌ Error generating recommendations:\n\n{e}")