Download app4.py from yusiff/MovRecSys: direct link, hf CLI and curl.
- Browser
- Download file 11.5 kB
-
https://huggingface.co/spaces/yusiff/MovRecSys/resolve/main/app4.py
- Command line
-
hf download hf://spaces/yusiff/MovRecSys/app4.py
-
curl -L -o app4.py https://huggingface.co/spaces/yusiff/MovRecSys/resolve/main/app4.py
11.5 kB
| import pickle | |
| import streamlit as st | |
| import requests | |
| from datetime import datetime | |
| # إعداد الصفحة | |
| st.set_page_config(page_title="🎬 Movie Recommender", page_icon="🎞️", layout="wide") | |
| # -------------------- صفحة إدخال اسم المستخدم -------------------- | |
| if 'name' not in st.session_state: | |
| st.session_state.name = None | |
| # التحقق إذا كان المستخدم قد أدخل اسمه بالفعل | |
| if st.session_state.name is None: | |
| # صفحة إدخال الاسم | |
| st.title("🎬 Welcome to the Movie Recommender!") | |
| # عبارة الترحيب حسب الوقت | |
| hour = datetime.now().hour | |
| greeting_time = "Good Morning ☀️" if hour < 12 else "Good Afternoon 🌤️" if hour < 18 else "Good Evening 🌙" | |
| st.markdown(f"### {greeting_time}") | |
| #st.markdown("Please enter your name to continue.") | |
| name = st.text_input("Enter your name", "") | |
| if st.button("Submit"): | |
| if name: | |
| st.session_state.name = name # تخزين الاسم في session_state | |
| st.success(f"Hello, {name}! Welcome to the Movie Recommender 🎬") | |
| # إعادة تحميل الصفحة باستخدام st.empty() | |
| st.empty() # يمكن إعادة تحميل المحتوى هنا أو من خلال استبدال هذا بـ rerun بسيط | |
| else: | |
| st.error("Please enter a valid name.") # إذا لم يتم إدخال اسم | |
| else: | |
| # -------------------- تحسين تنسيق الشريط الجانبي باستخدام CSS -------------------- | |
| st.markdown(""" | |
| <style> | |
| .sidebar .sidebar-content { | |
| background-color: #1c1c1c; /* خلفية داكنة جدًا */ | |
| color: white; | |
| padding: 15px; | |
| border-radius: 10px; | |
| } | |
| .sidebar .sidebar-content h1, .sidebar .sidebar-content h2 { | |
| font-size: 20px; | |
| font-weight: bold; | |
| color: #ecf0f1; /* لون النص */ | |
| } | |
| .sidebar .sidebar-content .stButton button { | |
| background-color: #3498db; /* زر لون أزرق */ | |
| color: white; | |
| font-weight: bold; | |
| border-radius: 5px; | |
| width: 100%; | |
| padding: 10px; | |
| } | |
| .sidebar .sidebar-content .stButton button:hover { | |
| background-color: #2980b9; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # -------------------- تحميل البيانات -------------------- | |
| try: | |
| movies = pickle.load(open('movie_list.pkl', 'rb')) | |
| similarity = pickle.load(open('similarity.pkl', 'rb')) | |
| except FileNotFoundError: | |
| st.error("❌ Required data files (movie_list.pkl and similarity.pkl) not found.") | |
| st.stop() | |
| # -------------------- دوال المساعدة -------------------- | |
| def fetch_poster(movie_id): | |
| try: | |
| url = f"https://api.themoviedb.org/3/movie/{movie_id}?api_key=8265bd1679663a7ea12ac168da84d2e8&language=en-US" | |
| response = requests.get(url) | |
| data = response.json() | |
| poster_path = data.get('poster_path') | |
| return f"https://image.tmdb.org/t/p/w500/{poster_path}" if poster_path else "https://via.placeholder.com/500x750?text=No+Image" | |
| except: | |
| return "https://via.placeholder.com/500x750?text=Error" | |
| def fetch_movie_details(movie_id): | |
| try: | |
| url = f"https://api.themoviedb.org/3/movie/{movie_id}?api_key=8265bd1679663a7ea12ac168da84d2e8&language=en-US" | |
| response = requests.get(url) | |
| data = response.json() | |
| overview = data.get('overview', 'No overview available.') | |
| rating = data.get('vote_average', 'No rating') | |
| release_date = data.get('release_date', 'No release date') | |
| genres = ', '.join([genre['name'] for genre in data.get('genres', [])]) | |
| return overview, rating, release_date, genres | |
| except: | |
| return "No details available.", "No rating", "No release date", "No genres" | |
| def recommend(movie): | |
| if movie not in movies['title'].values: | |
| return [], [], [] | |
| index = movies[movies['title'] == movie].index[0] | |
| distances = sorted(list(enumerate(similarity[index])), reverse=True, key=lambda x: x[1]) | |
| recommended_names = [] | |
| recommended_posters = [] | |
| recommended_ids = [] | |
| for i in distances[1:6]: | |
| movie_id = movies.iloc[i[0]].movie_id | |
| recommended_names.append(movies.iloc[i[0]].title) | |
| recommended_posters.append(fetch_poster(movie_id)) | |
| recommended_ids.append(movie_id) | |
| return recommended_names, recommended_posters, recommended_ids | |
| def fetch_popular_movies(): | |
| url = "https://api.themoviedb.org/3/movie/popular?api_key=8265bd1679663a7ea12ac168da84d2e8&language=en-US&page=1" | |
| try: | |
| response = requests.get(url) | |
| data = response.json() | |
| popular_movies = [] | |
| for movie in data['results'][:60]: | |
| title = movie['title'] | |
| poster_path = movie.get('poster_path') | |
| poster_url = f"https://image.tmdb.org/t/p/w500/{poster_path}" if poster_path else "https://via.placeholder.com/500x750?text=No+Image" | |
| movie_id = movie['id'] | |
| popular_movies.append((title, poster_url, movie_id)) | |
| return popular_movies | |
| except: | |
| return [] | |
| # -------------------- التنقل في الشريط الجانبي -------------------- | |
| st.sidebar.markdown(""" | |
| <div style="text-align:center; color:white; font-size:30px; font-weight:bold;"> | |
| 🎞️ Movie Recommender | |
| </div> | |
| <hr style="border-color: #ecf0f1;"> | |
| """, unsafe_allow_html=True) | |
| st.session_state.selected_section = st.sidebar.radio( | |
| "Navigate", | |
| ["Popular Movies", "Search & Recommend Movies", "Movie Details"] | |
| ) | |
| # -------------------- الصفحة الرئيسية -------------------- | |
| st.markdown(f"### Hello, {st.session_state.get('name', 'Guest')} 👋", unsafe_allow_html=True) | |
| if st.session_state.selected_section == "Popular Movies": | |
| with st.expander("Popular Movies", expanded=True): | |
| popular = fetch_popular_movies() | |
| if popular: | |
| cols = st.columns(5) | |
| for i, (title, poster_url, movie_id) in enumerate(popular): | |
| with cols[i % 5]: | |
| st.image(poster_url, use_container_width=True) | |
| st.markdown(f"<div class='movie-title'>{title}</div>", unsafe_allow_html=True) | |
| # استخدام session_state لتخزين حالة زر التفاصيل (مفتوح أو مغلق) | |
| if f"show_details_{i}" not in st.session_state: | |
| st.session_state[f"show_details_{i}"] = False | |
| # زر التفاصيل | |
| if st.button(" Details 📄", key=f"popular_details_{i}"): | |
| # تغيير حالة الزر عند الضغط عليه | |
| st.session_state[f"show_details_{i}"] = not st.session_state[f"show_details_{i}"] | |
| # عرض التفاصيل إذا كانت الحالة "مفتوحة" | |
| if st.session_state[f"show_details_{i}"]: | |
| overview, rating, release_date, genres = fetch_movie_details(movie_id) | |
| st.markdown(f"**📅 Release Date:** {release_date}") | |
| st.markdown(f"**⭐ Rating:** {rating}") | |
| st.markdown(f"**🎭 Genres:** {genres}") | |
| st.markdown(f"**📝 Overview:** {overview}") | |
| else: | |
| st.markdown("**Details Closed**") | |
| else: | |
| st.warning("Could not fetch popular movies.") | |
| elif st.session_state.selected_section == "Search & Recommend Movies": | |
| movie_list = movies['title'].values | |
| selected_movie = st.selectbox("🎥 Select a Movie", movie_list) | |
| rating = st.slider("⭐ Your Rating", 1, 10, 1) | |
| st.write(f"✅ Your rating: {rating} stars") | |
| if "show_recommendations" not in st.session_state: | |
| st.session_state.show_recommendations = False | |
| if st.button("🎯 Show 5 Recommendations"): | |
| st.session_state.show_recommendations = not st.session_state.show_recommendations | |
| if st.session_state.show_recommendations: | |
| with st.spinner("⏳ Fetching recommendations..."): | |
| names, posters, ids = recommend(selected_movie) | |
| if names: | |
| st.markdown(f"### ✅ Recommended Movies Similar to {selected_movie}:") | |
| cols = st.columns(5) | |
| for i in range(len(names)): | |
| with cols[i % 5]: | |
| st.image(posters[i], use_container_width=True) | |
| st.markdown(f"<div class='movie-title'>{names[i]}</div>", unsafe_allow_html=True) | |
| if st.button("📄 Details", key=f"recommend_details_{i}"): | |
| overview, rating, release_date, genres = fetch_movie_details(ids[i]) | |
| st.markdown(f"**📅 Release Date:** {release_date}") | |
| st.markdown(f"**⭐ Rating:** {rating}") | |
| st.markdown(f"**🎭 Genres:** {genres}") | |
| st.markdown(f"**📝 Overview:** {overview}") | |
| else: | |
| st.warning("No recommendations found.") | |
| elif st.session_state.selected_section == "Movie Details": | |
| if "show_details" not in st.session_state: | |
| st.session_state.show_details = {} | |
| movie_list = movies['title'].values | |
| selected_movie = st.selectbox("🎥 Select a Movie to View Details", movie_list) | |
| index = movies[movies['title'] == selected_movie].index[0] | |
| movie_id = movies.iloc[index].movie_id | |
| overview, rating, release_date, genres = fetch_movie_details(movie_id) | |
| # إضافة زر لفتح أو إغلاق التفاصيل | |
| if selected_movie not in st.session_state.show_details: | |
| st.session_state.show_details[selected_movie] = True # قيمة افتراضية للإخفاء | |
| if st.button(f"Show/Hide Details for {selected_movie} 📄"): | |
| st.session_state.show_details[selected_movie] = not st.session_state.show_details[selected_movie] | |
| # عرض التفاصيل بناءً على حالة الزر | |
| if st.session_state.show_details[selected_movie]: | |
| st.image(fetch_poster(movie_id), use_container_width=True) | |
| st.markdown(f"**📅 Release Date:** {release_date}") | |
| st.markdown(f"**⭐ Rating:** {rating}") | |
| st.markdown(f"**🎭 Genres:** {genres}") | |
| st.markdown(f"**📝 Overview:** {overview}") | |
| else: | |
| st.markdown(f"Details for {selected_movie} are hidden. Click the button to view them.") | |
| # -------------------- Footer -------------------- | |
| st.markdown("<hr>", unsafe_allow_html=True) | |
| st.markdown("<div class='footer'>© 2025 • by Youssef samy • Powered by Youssef Samy API</div>", unsafe_allow_html=True) | |