Files changed (1) hide show
  1. main.py +32 -69
main.py CHANGED
@@ -3,12 +3,10 @@ from pydantic import BaseModel
3
  from fastapi.middleware.cors import CORSMiddleware
4
  from pinecone import Pinecone
5
  from sentence_transformers import SentenceTransformer
 
6
  import random
7
  import os
8
 
9
- # ============================
10
- # 🔑 CONFIGURATION
11
- # ============================
12
  PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY")
13
  INDEX_NAME = "cine-match"
14
 
@@ -43,10 +41,6 @@ pc = Pinecone(api_key=PINECONE_API_KEY)
43
  index = pc.Index(INDEX_NAME)
44
  print("✅ Brain Online!")
45
 
46
- # ============================
47
- # 🛠 MODELS
48
- # ============================
49
-
50
  class SearchRequest(BaseModel):
51
  query: str
52
  filter_type: str = "All"
@@ -59,10 +53,6 @@ class FinalRecommendationRequest(BaseModel):
59
  selected_titles: list[str]
60
  genre: str
61
 
62
- # ============================
63
- # 🔍 MODE 1: SIMPLE SEARCH
64
- # ============================
65
-
66
  @app.post("/search")
67
  def semantic_search(req: SearchRequest):
68
  try:
@@ -73,86 +63,78 @@ def semantic_search(req: SearchRequest):
73
 
74
  results = index.query(
75
  vector=query_vector,
76
- top_k=20,
77
  include_metadata=True,
78
  filter=filter_dict if filter_dict else None
79
  )
80
 
81
- matches = []
82
  for match in results['matches']:
83
  meta = match['metadata']
84
- matches.append({
85
  "id": meta['original_id'],
86
  "title": meta['title'],
87
  "type": meta['type'],
88
  "score": match['score'],
89
  "rating": meta.get('rating', 0)
90
  })
91
- return {"results": matches}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  except Exception as e:
 
93
  raise HTTPException(status_code=500, detail=str(e))
94
 
95
  @app.post("/mood")
96
  def mood_search(mood: str):
97
- # Simple mapping for the "Search Mode" mood buttons
98
  mood_map = {
99
  "Happy": "Feel good movie, comedy, lighthearted, happy ending",
100
  "Dark": "Dark, psychological thriller, disturbing, gritty, noir",
101
- "Adrenaline": "High stakes action, fast paced, car chases",
102
  "Mind-Bending": "Confusing plot, time travel, philosophy, deep thoughts",
103
- "Romantic": "Love story, romance, heartbreak",
104
- "Scary": "Horror, ghosts, jump scares"
105
  }
106
  search_query = mood_map.get(mood, mood)
107
  return semantic_search(SearchRequest(query=search_query))
108
 
109
- # ============================
110
- # 🧙‍♂️ MODE 2: WIZARD / HYBRID
111
- # ============================
112
-
113
  @app.post("/get-quiz-items")
114
  def get_quiz_items(req: QuizRequest):
115
  query = f"Popular, famous, high rated {req.genre} movies or anime"
116
  vector = model.encode(query).tolist()
117
-
118
  results = index.query(
119
- vector=vector,
120
- top_k=20,
121
- include_metadata=True,
122
  filter={"type": "Anime" if req.genre == "Anime" else "Movie"}
123
  )
124
-
125
- items = []
126
- for match in results['matches']:
127
- meta = match['metadata']
128
- items.append({
129
- "id": meta['original_id'],
130
- "title": meta['title'],
131
- "type": meta['type'],
132
- "poster": None
133
- })
134
  return {"items": items}
135
 
136
  @app.post("/hybrid-recommend")
137
  def hybrid_recommend(req: FinalRecommendationRequest):
138
  joined_titles = ", ".join(req.selected_titles)
139
  semantic_query = f"{req.mood} {req.genre} similar to {joined_titles}"
140
-
141
  query_vector = model.encode(semantic_query).tolist()
142
-
143
- results = index.query(
144
- vector=query_vector,
145
- top_k=60,
146
- include_metadata=True
147
- )
148
 
149
  recommendations = []
150
  for match in results['matches']:
151
  meta = match['metadata']
152
  if meta['title'] in req.selected_titles: continue
153
-
154
  reason = f"Because you liked {random.choice(req.selected_titles)} and wanted something {req.mood}."
155
-
156
  recommendations.append({
157
  "id": meta['original_id'],
158
  "title": meta['title'],
@@ -161,35 +143,16 @@ def hybrid_recommend(req: FinalRecommendationRequest):
161
  "rating": meta.get('rating', 0),
162
  "reason": reason
163
  })
164
-
165
  return {"results": recommendations}
166
 
167
  @app.get("/lucky")
168
  def lucky_pick():
169
- """
170
- Picks a random high-rated movie from the database.
171
- """
172
- # Query for generally good movies
173
  vector = model.encode("Masterpiece, highly rated, famous, classic, 5 stars").tolist()
174
-
175
- # Get 50 candidates
176
- results = index.query(
177
- vector=vector,
178
- top_k=50,
179
- include_metadata=True
180
- )
181
-
182
- if not results['matches']:
183
- raise HTTPException(status_code=404, detail="No movies found")
184
-
185
- # Pick one random movie
186
  match = random.choice(results['matches'])
187
  meta = match['metadata']
188
-
189
  return {
190
- "id": meta['original_id'],
191
- "title": meta['title'],
192
- "type": meta['type'],
193
- "rating": meta.get('rating', 0),
194
- "reason": "Serendipity ✨"
195
  }
 
3
  from fastapi.middleware.cors import CORSMiddleware
4
  from pinecone import Pinecone
5
  from sentence_transformers import SentenceTransformer
6
+ from thefuzz import process, fuzz
7
  import random
8
  import os
9
 
 
 
 
10
  PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY")
11
  INDEX_NAME = "cine-match"
12
 
 
41
  index = pc.Index(INDEX_NAME)
42
  print("✅ Brain Online!")
43
 
 
 
 
 
44
  class SearchRequest(BaseModel):
45
  query: str
46
  filter_type: str = "All"
 
53
  selected_titles: list[str]
54
  genre: str
55
 
 
 
 
 
56
  @app.post("/search")
57
  def semantic_search(req: SearchRequest):
58
  try:
 
63
 
64
  results = index.query(
65
  vector=query_vector,
66
+ top_k=80,
67
  include_metadata=True,
68
  filter=filter_dict if filter_dict else None
69
  )
70
 
71
+ candidates = []
72
  for match in results['matches']:
73
  meta = match['metadata']
74
+ candidates.append({
75
  "id": meta['original_id'],
76
  "title": meta['title'],
77
  "type": meta['type'],
78
  "score": match['score'],
79
  "rating": meta.get('rating', 0)
80
  })
81
+
82
+ final_results = []
83
+ for item in candidates:
84
+ fuzzy_score = fuzz.ratio(req.query.lower(), item['title'].lower())
85
+
86
+ if fuzzy_score > 85:
87
+ item['score'] += 2.0
88
+
89
+ elif fuzz.partial_ratio(req.query.lower(), item['title'].lower()) > 90:
90
+ item['score'] += 0.5
91
+
92
+ final_results.append(item)
93
+
94
+ final_results.sort(key=lambda x: x['score'], reverse=True)
95
+
96
+ return {"results": final_results[:20]}
97
+
98
  except Exception as e:
99
+ print(f"Error: {e}")
100
  raise HTTPException(status_code=500, detail=str(e))
101
 
102
  @app.post("/mood")
103
  def mood_search(mood: str):
 
104
  mood_map = {
105
  "Happy": "Feel good movie, comedy, lighthearted, happy ending",
106
  "Dark": "Dark, psychological thriller, disturbing, gritty, noir",
107
+ "Adrenaline": "High stakes action, fast paced, car chases, explosions",
108
  "Mind-Bending": "Confusing plot, time travel, philosophy, deep thoughts",
109
+ "Romantic": "Love story, romance, heartbreak, relationship",
110
+ "Scary": "Horror, ghosts, jump scares, terrifying"
111
  }
112
  search_query = mood_map.get(mood, mood)
113
  return semantic_search(SearchRequest(query=search_query))
114
 
 
 
 
 
115
  @app.post("/get-quiz-items")
116
  def get_quiz_items(req: QuizRequest):
117
  query = f"Popular, famous, high rated {req.genre} movies or anime"
118
  vector = model.encode(query).tolist()
 
119
  results = index.query(
120
+ vector=vector, top_k=20, include_metadata=True,
 
 
121
  filter={"type": "Anime" if req.genre == "Anime" else "Movie"}
122
  )
123
+ items = [{"id": m['metadata']['original_id'], "title": m['metadata']['title'], "type": m['metadata']['type'], "poster": None} for m in results['matches']]
 
 
 
 
 
 
 
 
 
124
  return {"items": items}
125
 
126
  @app.post("/hybrid-recommend")
127
  def hybrid_recommend(req: FinalRecommendationRequest):
128
  joined_titles = ", ".join(req.selected_titles)
129
  semantic_query = f"{req.mood} {req.genre} similar to {joined_titles}"
 
130
  query_vector = model.encode(semantic_query).tolist()
131
+ results = index.query(vector=query_vector, top_k=60, include_metadata=True)
 
 
 
 
 
132
 
133
  recommendations = []
134
  for match in results['matches']:
135
  meta = match['metadata']
136
  if meta['title'] in req.selected_titles: continue
 
137
  reason = f"Because you liked {random.choice(req.selected_titles)} and wanted something {req.mood}."
 
138
  recommendations.append({
139
  "id": meta['original_id'],
140
  "title": meta['title'],
 
143
  "rating": meta.get('rating', 0),
144
  "reason": reason
145
  })
 
146
  return {"results": recommendations}
147
 
148
  @app.get("/lucky")
149
  def lucky_pick():
 
 
 
 
150
  vector = model.encode("Masterpiece, highly rated, famous, classic, 5 stars").tolist()
151
+ results = index.query(vector=vector, top_k=50, include_metadata=True)
152
+ if not results['matches']: raise HTTPException(status_code=404, detail="No movies found")
 
 
 
 
 
 
 
 
 
 
153
  match = random.choice(results['matches'])
154
  meta = match['metadata']
 
155
  return {
156
+ "id": meta['original_id'], "title": meta['title'], "type": meta['type'],
157
+ "rating": meta.get('rating', 0), "reason": "Serendipity ✨"
 
 
 
158
  }