File size: 4,646 Bytes
a08a8a1
456294b
 
f79661f
 
 
 
456294b
aadcdbf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f79661f
 
31ac050
f79661f
456294b
 
4c57269
f79661f
a08a8a1
 
5b1d7f6
f79661f
a08a8a1
 
4c57269
a08a8a1
 
4c57269
a08a8a1
4c57269
f79661f
a08a8a1
31ac050
 
 
 
 
 
a08a8a1
4c57269
31ac050
4c57269
a08a8a1
 
188425d
 
 
 
 
 
 
4c57269
a08a8a1
 
 
188425d
 
 
 
 
 
 
4c57269
a08a8a1
 
31ac050
188425d
31ac050
 
188425d
 
 
 
 
 
 
 
 
31ac050
4c57269
a08a8a1
f79661f
a08a8a1
 
31ac050
f79661f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31ac050
f79661f
4c57269
f79661f
4c57269
f79661f
4c57269
f79661f
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
from sklearn.decomposition import TruncatedSVD
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.neighbors import NearestNeighbors
from sklearn.cluster import KMeans
from sklearn.metrics.pairwise import cosine_similarity
import gradio as gr

def custom_similarity_by_index(idx1, idx2):
    row1 = df.iloc[idx1]
    row2 = df.iloc[idx2]

    def to_set(text):
        if pd.isna(text):
            return set()
        return set(text.lower().split())

    g1, g2 = to_set(row1["genres"]), to_set(row2["genres"])
    k1, k2 = to_set(row1["keywords"]), to_set(row2["keywords"])

    genre_sim = len(g1 & g2) / len(g1 | g2) if g1 and g2 else 0
    keyword_sim = len(k1 & k2) / len(k1 | k2) if k1 and k2 else 0

    d1 = str(row1["director"]).lower()
    d2 = str(row2["director"]).lower()
    director_sim = 1 if d1 == d2 else 0

    return 0.4 * genre_sim + 0.4 * keyword_sim + 0.2 * director_sim

# ------------------ LOAD DATA ------------------
df = pd.read_csv("mov_dataset.csv")
df["title_lower"] = df["title"].str.lower()

tfidf = TfidfVectorizer()
X = tfidf.fit_transform(df["combined_features"])

# ------------------ SVD ------------------
svd = TruncatedSVD(n_components=50, random_state=42)
X_svd = svd.fit_transform(X)

# ------------------ MODELS ------------------
knn = NearestNeighbors(metric='cosine', algorithm='brute')
knn.fit(X_svd)

kmeans = KMeans(n_clusters=10, random_state=42)
clusters = kmeans.fit_predict(X_svd)

cosine_sim = cosine_similarity(X_svd)

# ------------------ RECOMMEND FUNCTION ------------------
def recommend(movie_name, model_type):
    movie_name = movie_name.strip().lower()

    if not movie_name:
        return ["Please enter a movie name"]

    if movie_name not in df["title_lower"].values:
        return ["Movie not found"]

    idx = df[df["title_lower"] == movie_name].index[0]

    if model_type == "KNN":
        distances, indices = knn.kneighbors([X_svd[idx]], n_neighbors=6)
    
        results = []
        for i in indices[0][1:]:
            score = custom_similarity_by_index(idx, i)
            results.append((df.iloc[i]["title"], score))
    
        return sorted(results, key=lambda x: x[1], reverse=True)

    elif model_type == "Cosine":
        scores = list(enumerate(cosine_sim[idx]))
        scores = sorted(scores, key=lambda x: x[1], reverse=True)
    
        results = []
        for i, _ in scores[1:6]:
            score = custom_similarity_by_index(idx, i)
            results.append((df.iloc[i]["title"], score))
    
        return sorted(results, key=lambda x: x[1], reverse=True)

    elif model_type == "KMeans":
        cluster_id = clusters[idx]
        cluster_indices = [i for i in range(len(df)) if clusters[i] == cluster_id and i != idx]
    
        if not cluster_indices:
            return ["No similar movies found"]
    
        results = []
        for i in cluster_indices:
            score = custom_similarity_by_index(idx, i)
            results.append((df.iloc[i]["title"], score))
    
        results = sorted(results, key=lambda x: x[1], reverse=True)
    
        return results[:5]



# ------------------ CARD STYLE OUTPUT ------------------
def recommend_ui(movie, model):
    results = recommend(movie, model)

    if isinstance(results, list) and isinstance(results[0], str):
        return f"❌ {results[0]}"

    cards = ""
    for i, (title, score) in enumerate(results):
        cards += f"""
        <div style="
            background-color:#1f1f1f;
            padding:15px;
            margin:10px;
            border-radius:10px;
            box-shadow:0px 0px 10px rgba(255,0,0,0.3);
        ">
            <h3 style="color:#E50914;">{i+1}. {title}</h3>
            <p style="color:white;">⭐ Similarity Score: <b>{score}</b></p>
        </div>
        """

    return cards


# ------------------ NETFLIX STYLE UI ------------------
css = """
body {
    background-color: #141414;
    color: white;
}

.gradio-container {
    background-color: #141414 !important;
}

h1 {
    text-align: center;
    color: #E50914;
    font-size: 42px;
}

"""


with gr.Blocks(css=css) as demo:

    gr.Markdown("# 🎬 Netflix Movie Recommender")

    with gr.Row():
        movie_input = gr.Textbox(
            label="Enter Movie Name",
            placeholder="Try: Avatar"
        )

        model_input = gr.Dropdown(
            ["KNN", "Cosine", "KMeans"],
            value="KNN",
            label="Select Model"
        )

    btn = gr.Button("🔥 Recommend")

    output = gr.HTML()

    btn.click(fn=recommend_ui, inputs=[movie_input, model_input], outputs=output)

demo.launch()