MatanYehudaDataAnalyst commited on
Commit
896f562
·
verified ·
1 Parent(s): 08e20a5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -22
app.py CHANGED
@@ -9,14 +9,14 @@ from sklearn.metrics.pairwise import cosine_similarity
9
  # ==========================================
10
  # 1. SETUP & DATA LOADING
11
  # ==========================================
12
- # File paths (Assuming files are in the same root directory as app.py on Hugging Face)
13
  CSV_PATH = "cleaned_dataset_10k.csv"
14
  PKL_PATH = "final_embeddings_10k.pkl"
15
 
16
  if not os.path.exists(CSV_PATH) or not os.path.exists(PKL_PATH):
17
- raise FileNotFoundError("Missing required data files. Please ensure CSV and PKL are uploaded.")
18
 
19
- # Load the dataset
20
  df = pd.read_csv(CSV_PATH)
21
  df.columns = [c.strip().lower().replace(' ', '_') for c in df.columns]
22
 
@@ -25,10 +25,10 @@ with open(PKL_PATH, 'rb') as f:
25
  embedding_data = pickle.load(f)
26
  dataset_embeddings = embedding_data['embeddings'] if isinstance(embedding_data, dict) else embedding_data
27
 
28
- # Load the semantic model (MPNet for high accuracy)
29
  model = SentenceTransformer('sentence-transformers/all-mpnet-base-v2')
30
 
31
- # Pre-calculate Persona Taste Profiles (Mean vectors)
32
  persona_profiles = {}
33
  for persona in df['reviewer_persona'].unique():
34
  if pd.isna(persona): continue
@@ -41,38 +41,37 @@ for persona in df['reviewer_persona'].unique():
41
  # ==========================================
42
  def run_ven_engine(budget, dietary, company, purpose, noise):
43
  """
44
- Finds the best restaurant match using a combination of
45
- Persona Matching and Contextual Semantic Similarity.
46
  """
47
- # Create the user's context string
48
  user_context = f"Searching for a {budget} experience, {dietary} friendly. Group: {company}. Occasion: {purpose}. Atmosphere: {noise}."
49
  query_vec = model.encode([user_context])
50
 
51
- # Step A: Identify the closest Persona Profile
52
  persona_sims = {p: cosine_similarity(query_vec, v.reshape(1, -1))[0][0]
53
  for p, v in persona_profiles.items()}
54
  closest_persona = max(persona_sims, key=persona_sims.get)
55
 
56
- # Step B: Filter reviews by that persona
57
  persona_indices = df[df['reviewer_persona'] == closest_persona].index
58
  persona_embeddings = dataset_embeddings[persona_indices]
59
 
60
  # Step C: Calculate Contextual Similarity for specific reviews within that persona
61
- # This prevents getting the same result every time
62
  sub_similarities = cosine_similarity(query_vec, persona_embeddings)[0]
63
 
64
  persona_df = df.loc[persona_indices].copy()
65
  persona_df['semantic_fit'] = sub_similarities
66
  persona_df['norm_rating'] = persona_df['rating_score'] / 5.0
67
 
68
- # HYBRID SCORE: 70% Contextual Fit + 30% Rating Quality
69
  persona_df['final_score'] = (persona_df['semantic_fit'] * 0.7) + (persona_df['norm_rating'] * 0.3)
70
 
71
- # Pick the top result after re-ranking
72
  top_match = persona_df.sort_values(by='final_score', ascending=False).iloc[0]
73
  match_pct = int(top_match['final_score'] * 100)
74
 
75
- # Format Recommendation Card (HTML)
76
  return f"""
77
  <div style="background: white; border-radius: 20px; padding: 25px; color: #0f172a !important; text-align: left; border-left: 10px solid #f97316; box-shadow: 0 10px 25px rgba(0,0,0,0.2);">
78
  <div style="display:flex; justify-content:space-between; align-items: flex-start;">
@@ -97,20 +96,28 @@ def run_ven_engine(budget, dietary, company, purpose, noise):
97
  """
98
 
99
  # ==========================================
100
- # 3. GRADIO UI SETUP (HF OPTIMIZED)
101
  # ==========================================
102
- # CSS Fixes for Visibility and Theme consistency
103
  ven_css = """
 
104
  .gradio-container { background-color: #0f172a !important; }
105
  h1 { color: white !important; text-align: center; font-weight: 900 !important; font-size: 2.5rem !important; margin-bottom: 20px !important; }
106
 
107
- /* Force input labels to be white and readable */
108
- label span { color: white !important; font-weight: 700 !important; font-size: 15px !important; margin-bottom: 5px !important; }
 
 
 
 
109
 
110
- /* Force Radio button text options to be white and bold */
111
- .gr-radio label span { color: white !important; font-weight: 600 !important; }
 
 
 
 
112
 
113
- /* Style the primary orange button */
114
  .ven-button {
115
  background-color: #f97316 !important;
116
  color: white !important;
@@ -121,7 +128,7 @@ label span { color: white !important; font-weight: 700 !important; font-size: 15
121
  border-radius: 12px !important;
122
  }
123
 
124
- /* Fix example table colors */
125
  .gr-samples-table { background-color: #1e293b !important; color: white !important; }
126
  """
127
 
 
9
  # ==========================================
10
  # 1. SETUP & DATA LOADING
11
  # ==========================================
12
+ # Assuming files are in the same root directory as app.py
13
  CSV_PATH = "cleaned_dataset_10k.csv"
14
  PKL_PATH = "final_embeddings_10k.pkl"
15
 
16
  if not os.path.exists(CSV_PATH) or not os.path.exists(PKL_PATH):
17
+ raise FileNotFoundError("Missing required data files. Ensure CSV and PKL are uploaded.")
18
 
19
+ # Load the restaurant dataset
20
  df = pd.read_csv(CSV_PATH)
21
  df.columns = [c.strip().lower().replace(' ', '_') for c in df.columns]
22
 
 
25
  embedding_data = pickle.load(f)
26
  dataset_embeddings = embedding_data['embeddings'] if isinstance(embedding_data, dict) else embedding_data
27
 
28
+ # Load the semantic transformer model (MPNet for high fidelity)
29
  model = SentenceTransformer('sentence-transformers/all-mpnet-base-v2')
30
 
31
+ # Pre-calculate Persona Taste Profiles (Mean Vectors)
32
  persona_profiles = {}
33
  for persona in df['reviewer_persona'].unique():
34
  if pd.isna(persona): continue
 
41
  # ==========================================
42
  def run_ven_engine(budget, dietary, company, purpose, noise):
43
  """
44
+ Finds the best restaurant match using Hybrid Scoring:
45
+ 70% Semantic Contextual Fit + 30% User Rating.
46
  """
47
+ # Construct the user's semantic context
48
  user_context = f"Searching for a {budget} experience, {dietary} friendly. Group: {company}. Occasion: {purpose}. Atmosphere: {noise}."
49
  query_vec = model.encode([user_context])
50
 
51
+ # Step A: Identify the closest overall Persona Profile
52
  persona_sims = {p: cosine_similarity(query_vec, v.reshape(1, -1))[0][0]
53
  for p, v in persona_profiles.items()}
54
  closest_persona = max(persona_sims, key=persona_sims.get)
55
 
56
+ # Step B: Filter reviews belonging to that persona
57
  persona_indices = df[df['reviewer_persona'] == closest_persona].index
58
  persona_embeddings = dataset_embeddings[persona_indices]
59
 
60
  # Step C: Calculate Contextual Similarity for specific reviews within that persona
 
61
  sub_similarities = cosine_similarity(query_vec, persona_embeddings)[0]
62
 
63
  persona_df = df.loc[persona_indices].copy()
64
  persona_df['semantic_fit'] = sub_similarities
65
  persona_df['norm_rating'] = persona_df['rating_score'] / 5.0
66
 
67
+ # CALCULATE FINAL SCORE
68
  persona_df['final_score'] = (persona_df['semantic_fit'] * 0.7) + (persona_df['norm_rating'] * 0.3)
69
 
70
+ # Select the top re-ranked result
71
  top_match = persona_df.sort_values(by='final_score', ascending=False).iloc[0]
72
  match_pct = int(top_match['final_score'] * 100)
73
 
74
+ # Return Styled HTML Result Card
75
  return f"""
76
  <div style="background: white; border-radius: 20px; padding: 25px; color: #0f172a !important; text-align: left; border-left: 10px solid #f97316; box-shadow: 0 10px 25px rgba(0,0,0,0.2);">
77
  <div style="display:flex; justify-content:space-between; align-items: flex-start;">
 
96
  """
97
 
98
  # ==========================================
99
+ # 3. GRADIO UI SETUP (FINAL VISIBILITY FIX)
100
  # ==========================================
 
101
  ven_css = """
102
+ /* 1. Dark background for the whole app */
103
  .gradio-container { background-color: #0f172a !important; }
104
  h1 { color: white !important; text-align: center; font-weight: 900 !important; font-size: 2.5rem !important; margin-bottom: 20px !important; }
105
 
106
+ /* 2. Main Labels (e.g., "3. Social Context") -> MUST BE WHITE */
107
+ label span {
108
+ color: white !important;
109
+ font-weight: 700 !important;
110
+ font-size: 15px !important;
111
+ }
112
 
113
+ /* 3. RADIO CHOICE TEXT (e.g., "Solo", "Date") -> MUST BE DARK SATE */
114
+ /* Since radio buttons have white backgrounds, white text is invisible. We force it to dark blue/grey. */
115
+ .gr-radio label span, .gr-radio span {
116
+ color: #1e293b !important;
117
+ font-weight: 600 !important;
118
+ }
119
 
120
+ /* 4. Orange primary button styling */
121
  .ven-button {
122
  background-color: #f97316 !important;
123
  color: white !important;
 
128
  border-radius: 12px !important;
129
  }
130
 
131
+ /* 5. Quick Vibe Starters table colors */
132
  .gr-samples-table { background-color: #1e293b !important; color: white !important; }
133
  """
134