lenawilli commited on
Commit
e27b6a6
Β·
verified Β·
1 Parent(s): f8a11e7

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +88 -48
src/streamlit_app.py CHANGED
@@ -1,48 +1,88 @@
1
- import streamlit as st
2
- import pandas as pd
3
- import joblib
4
- import os
5
-
6
- # Define file paths (assuming files are in the same folder as this script)
7
- BASE_DIR = os.path.dirname(__file__)
8
- MOVIES_PATH = os.path.join(BASE_DIR, "movies.csv")
9
- ENCODINGS_PATH = os.path.join(BASE_DIR, "encodings.pkl")
10
-
11
- @st.cache_data
12
- def load_assets():
13
- if not os.path.exists(MOVIES_PATH):
14
- st.error("❌ movies.csv not found.")
15
- st.stop()
16
- if not os.path.exists(ENCODINGS_PATH):
17
- st.error("❌ encodings.pkl not found.")
18
- st.stop()
19
- try:
20
- df_movies = pd.read_csv(MOVIES_PATH)
21
- user_map, movie_map = joblib.load(ENCODINGS_PATH)
22
- return df_movies, user_map, movie_map
23
- except Exception as e:
24
- st.error(f"❌ Failed to load assets:\n\n{e}")
25
- st.stop()
26
-
27
- # Load only static data
28
- movies_df, user2idx, movie2idx = load_assets()
29
-
30
- # UI
31
- st.title("🎬 TensorFlow Movie Recommender (Mock Version)")
32
- st.write("This is a dummy version of the app without model logic. Select movies to simulate recommendations.")
33
-
34
- # Movie title selection
35
- movie_titles = movies_df.set_index("movieId")["title"].to_dict()
36
- movie_choices = [movie_titles[mid] for mid in movie2idx if mid in movie_titles]
37
- selected_titles = st.multiselect("🎞️ Liked movies", sorted(movie_choices))
38
-
39
- # Simulate recommendations
40
- if st.button("🎯 Get Recommendations (Dummy)"):
41
- if not selected_titles:
42
- st.warning("Please select at least one movie.")
43
- else:
44
- st.subheader("🍿 Mock Recommendations")
45
- st.write("Here are some movies we 'think' you might like... πŸ˜‰")
46
- mock_recommendations = sorted(set(movie_choices) - set(selected_titles))[:10]
47
- for i, title in enumerate(mock_recommendations, 1):
48
- st.write(f"**#{i}** β€” {title}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect } from "react";
2
+ import { Card, CardContent } from "@/components/ui/card";
3
+ import { Button } from "@/components/ui/button";
4
+ import { Slider } from "@/components/ui/slider";
5
+ import moviesData from "./movies.csv"; // Assume a CSV loader or API exposes this
6
+
7
+ export default function MovieRecommender() {
8
+ const [maxQuestions, setMaxQuestions] = useState(5);
9
+ const [questionIndex, setQuestionIndex] = useState(0);
10
+ const [ratedCount, setRatedCount] = useState(0);
11
+ const [ratings, setRatings] = useState([]);
12
+ const [shuffledMovies, setShuffledMovies] = useState([]);
13
+ const [submitted, setSubmitted] = useState(false);
14
+
15
+ useEffect(() => {
16
+ const allTitles = moviesData.map((m) => m.title);
17
+ const shuffled = [...allTitles].sort(() => 0.5 - Math.random());
18
+ setShuffledMovies(shuffled);
19
+ }, []);
20
+
21
+ const handleRating = (choice) => {
22
+ if (choice !== "skip") {
23
+ setRatings([...ratings, { movie: shuffledMovies[questionIndex], rating: choice }]);
24
+ setRatedCount(ratedCount + 1);
25
+ }
26
+
27
+ if ((choice !== "skip" && ratedCount + 1 >= maxQuestions) || questionIndex + 1 >= shuffledMovies.length) {
28
+ setSubmitted(true);
29
+ } else {
30
+ setQuestionIndex(questionIndex + 1);
31
+ }
32
+ };
33
+
34
+ const recommendations = shuffledMovies.filter(
35
+ (movie) => !ratings.map((r) => r.movie).includes(movie)
36
+ ).slice(0, 10).map((title) => ({ title, score: (Math.random() * 100).toFixed(1) }));
37
+
38
+ return (
39
+ <div className="min-h-screen bg-[#0d1b2a] text-white flex flex-col items-center justify-center px-4 py-10">
40
+ <h1 className="text-3xl font-bold mb-8">🎬 Movie Recommender</h1>
41
+
42
+ {!submitted && ratings.length === 0 && (
43
+ <div className="w-full max-w-md">
44
+ <p className="mb-4">How many movies would you like to rate?</p>
45
+ <Slider
46
+ defaultValue={[5]}
47
+ min={1}
48
+ max={15}
49
+ step={1}
50
+ onValueChange={(val) => setMaxQuestions(val[0])}
51
+ />
52
+ <div className="mt-2 text-center">Selected: {maxQuestions}</div>
53
+ </div>
54
+ )}
55
+
56
+ {!submitted && ratings.length < maxQuestions && shuffledMovies.length > 0 && (
57
+ <Card className="mt-10 w-full max-w-xl shadow-2xl transition-transform animate-in fade-in zoom-in rounded-2xl bg-[#1b263b]">
58
+ <CardContent className="p-6 text-center">
59
+ <div className="flex justify-between mb-4">
60
+ <span className="text-sm text-gray-300">Rate the following movie</span>
61
+ <span className="text-sm text-gray-300">#{ratedCount + 1}</span>
62
+ </div>
63
+ <h2 className="text-2xl font-semibold mb-6">{shuffledMovies[questionIndex]}</h2>
64
+ <div className="flex justify-around gap-4">
65
+ <Button onClick={() => handleRating("like")} className="bg-green-600 hover:bg-green-700">πŸ‘ Like</Button>
66
+ <Button onClick={() => handleRating("dislike")} className="bg-red-600 hover:bg-red-700">πŸ‘Ž Dislike</Button>
67
+ <Button onClick={() => handleRating("skip")} className="bg-gray-500 hover:bg-gray-600">⏭ Didn't Watch</Button>
68
+ </div>
69
+ </CardContent>
70
+ </Card>
71
+ )}
72
+
73
+ {submitted && (
74
+ <div className="mt-10 w-full max-w-2xl text-center">
75
+ <h2 className="text-2xl font-semibold mb-4">🎯 Top 10 Recommendations</h2>
76
+ <ul className="space-y-2">
77
+ {recommendations.map((rec, i) => (
78
+ <li key={i} className="bg-[#1e2a3c] rounded-lg px-4 py-3 flex justify-between items-center shadow">
79
+ <span>{rec.title}</span>
80
+ <span className="text-sm text-gray-300">Likelihood: {rec.score}%</span>
81
+ </li>
82
+ ))}
83
+ </ul>
84
+ </div>
85
+ )}
86
+ </div>
87
+ );
88
+ }