Skip to content

Commit 0ec801d

Browse files
authored
Update Movie-Recommendation-Engine.py
1 parent 074096e commit 0ec801d

1 file changed

Lines changed: 48 additions & 19 deletions

File tree

143-Recommendation engine-for-movies/Movie-Recommendation-Engine.py

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import tkinter as tk
44
from tkinter import messagebox
55
from dataclasses import dataclass
6-
from typing import List, Tuple, Optional, Dict
6+
from typing import List, Tuple, Dict, Optional
77
import requests
88
import io
99
from PIL import Image, ImageTk # pip install pillow
@@ -26,12 +26,16 @@
2626
@dataclass
2727
class Movie:
2828
title: str
29+
imdb_id: str
2930
url: str
30-
display_url: str
3131
description: str
3232
poster_url: str
33+
genres: List[str] = None
34+
director: str = ""
35+
actors: List[str] = None
36+
rating: float = 0.0
3337

34-
# ---------------- SEARCH LOGIC ---------------- #
38+
# ---------------- SEARCH / FETCH ---------------- #
3539
def fetch_movies(query: str) -> List[Movie]:
3640
"""Fetch movies from OMDb API matching the query."""
3741
movies: List[Movie] = []
@@ -51,13 +55,19 @@ def fetch_movies(query: str) -> List[Movie]:
5155
timeout=10
5256
).json()
5357

58+
genres = detail_resp.get("Genre", "")
59+
actors = detail_resp.get("Actors", "")
5460
movies.append(
5561
Movie(
5662
title=detail_resp.get("Title", "Unknown"),
63+
imdb_id=imdb_id,
5764
url=f"https://www.imdb.com/title/{imdb_id}/",
58-
display_url=f"imdb.com › {imdb_id}",
5965
description=detail_resp.get("Plot", ""),
60-
poster_url=detail_resp.get("Poster", "")
66+
poster_url=detail_resp.get("Poster", ""),
67+
genres=[g.strip() for g in genres.split(",")] if genres else [],
68+
director=detail_resp.get("Director", ""),
69+
actors=[a.strip() for a in actors.split(",")] if actors else [],
70+
rating=float(detail_resp.get("imdbRating", 0.0)) if detail_resp.get("imdbRating") != "N/A" else 0.0
6171
)
6272
)
6373
except requests.RequestException as e:
@@ -66,9 +76,27 @@ def fetch_movies(query: str) -> List[Movie]:
6676
messagebox.showerror("Error", str(e))
6777
return movies
6878

69-
def rank_movies(query: str, movies: List[Movie]) -> List[Tuple[Movie, float]]:
70-
"""Placeholder ranking logic; can implement TF-IDF or other metrics."""
71-
return [(m, 0.0) for m in movies]
79+
# ---------------- RECOMMENDATION ENGINE ---------------- #
80+
def recommend_movies(query: str, candidates: List[Movie], top_n=RESULTS_PER_PAGE) -> List[Tuple[Movie, float]]:
81+
"""
82+
Simple content-based recommendation:
83+
Scores movies by overlap with query in title, description, and genres
84+
"""
85+
query_tokens = set(query.lower().split())
86+
recommendations: List[Tuple[Movie, float]] = []
87+
88+
for movie in candidates:
89+
text_to_match = " ".join([
90+
movie.title.lower(),
91+
movie.description.lower(),
92+
" ".join(movie.genres or [])
93+
])
94+
score = sum(1 for token in query_tokens if token in text_to_match)
95+
recommendations.append((movie, score))
96+
97+
# Sort descending by score
98+
recommendations.sort(key=lambda x: x[1], reverse=True)
99+
return recommendations[:top_n]
72100

73101
# ---------------- UI HELPERS ---------------- #
74102
def open_url(url: str):
@@ -104,14 +132,14 @@ def display_page():
104132
update_pagination()
105133
return
106134

107-
for idx, (movie, _) in enumerate(page_results):
108-
# Movie Title
135+
for idx, (movie, score) in enumerate(page_results):
136+
# Title
109137
text.insert("end", f"{movie.title}\n", f"title_{idx}")
110138
text.tag_config(f"title_{idx}", foreground="#1a0dab", font=("Segoe UI", 14, "bold"))
111139
text.tag_bind(f"title_{idx}", "<Double-Button-1>", lambda e, url=movie.url: open_url(url))
112140

113-
# Display URL
114-
text.insert("end", f"{movie.display_url}\n", f"url_{idx}")
141+
# Display URL and IMDB rating
142+
text.insert("end", f"{movie.url} | Rating: {movie.rating}\n", f"url_{idx}")
115143
text.tag_config(f"url_{idx}", foreground="#006621", font=("Segoe UI", 10))
116144

117145
# Poster
@@ -120,8 +148,9 @@ def display_page():
120148
text.image_create("end", image=poster)
121149
text.insert("end", "\n")
122150

123-
# Description
124-
text.insert("end", f"{movie.description}\n\n")
151+
# Description & genres
152+
genres = ", ".join(movie.genres or [])
153+
text.insert("end", f"{movie.description}\nGenres: {genres}\n\n")
125154

126155
text.configure(state="disabled")
127156
update_pagination()
@@ -149,24 +178,24 @@ def update_pagination():
149178
def perform_search():
150179
query = query_entry.get().strip()
151180
if not query:
152-
messagebox.showwarning("Input Required", "Enter a movie title.")
181+
messagebox.showwarning("Input Required", "Enter a movie title or keywords.")
153182
return
154183
threading.Thread(target=search_thread, args=(query,), daemon=True).start()
155184

156185
def search_thread(query: str):
157186
global all_ranked_movies, current_page
158187
current_page = 1
159-
all_movies = fetch_movies(query)
160-
all_ranked_movies = rank_movies(query, all_movies)
188+
candidates = fetch_movies(query)
189+
all_ranked_movies = recommend_movies(query, candidates, top_n=50) # get top 50 recommendations
161190
display_page()
162191

163192
# ---------------- UI SETUP ---------------- #
164-
app = tb.Window(title="Live Movie Search", themename="flatly", size=(980, 720), resizable=(True, True))
193+
app = tb.Window(title="Movie Recommendation Engine", themename="flatly", size=(980, 720), resizable=(True, True))
165194

166195
# Top frame
167196
top = tb.Frame(app, padding=15)
168197
top.pack(fill=tk.X)
169-
tb.Label(top, text="Search Movies (Live)", font=("Segoe UI", 16, "bold")).pack(anchor=tk.W)
198+
tb.Label(top, text="Movie Recommendation Engine", font=("Segoe UI", 16, "bold")).pack(anchor=tk.W)
170199

171200
query_entry = tb.Entry(top, font=("Segoe UI", 12))
172201
query_entry.pack(fill=tk.X, pady=8)

0 commit comments

Comments
 (0)