AdrienVDS05 commited on
Commit
6a507cd
Β·
verified Β·
1 Parent(s): a9393f0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -56
app.py CHANGED
@@ -5,53 +5,105 @@ import plotly.graph_objects as go
5
  # ── load data ──────────────────────────────────────────────
6
  df = pd.read_csv("restaurant_master_scored.csv")
7
 
8
- CUISINES = ["All"] + sorted(df["cuisine_type"].unique().tolist())
9
- PRICES = ["All"] + ["€", "€€", "€€€", "€€€€"]
10
- ARRONDS = ["All"] + sorted(df["arrondissement"].unique().tolist())
11
 
12
  LABEL_COLOR = {"Worth It": "#1A6B3C", "Maybe": "#7D5A00", "Skip It": "#8B1A1A"}
13
- LABEL_BG = {"Worth It": "#EAF3DE", "Maybe": "#FAEEDA", "Skip It": "#FCEBEB"}
14
 
15
- # ── score component chart ──────────────────────────────────
16
- def make_chart(row):
 
 
17
  components = {
18
- "Sentiment adj": round(row["sentiment_adj_norm"] * 0.35 * 100, 1),
19
- "Price fairness": round(row["price_fairness"] * 0.25 * 100, 1),
20
- "Consistency": round(row["consistency_index"] * 0.20 * 100, 1),
21
- "Trust": round(row["trust_score"] * 0.10 * 100, 1),
22
- "Divergence βˆ’": round(-row["star_sentiment_divergence"] * 0.10 * 100, 1),
23
  }
 
24
  colors = ["#3D2B8E", "#7B6FCA", "#1A6B3C", "#7D5A00", "#8B1A1A"]
25
- fig = go.Figure(go.Bar(
26
- x=list(components.values()),
27
- y=list(components.keys()),
28
- orientation="h",
29
- marker_color=colors,
30
- text=[f"{v:+.1f}" for v in components.values()],
31
- textposition="outside",
32
- ))
33
- fig.update_layout(
 
 
 
 
34
  margin=dict(l=10, r=60, t=10, b=10),
35
  height=220,
36
- xaxis=dict(showgrid=False, zeroline=True,
37
- zerolinecolor="#cccccc", title="Points"),
 
 
 
 
38
  yaxis=dict(showgrid=False),
39
  paper_bgcolor="rgba(0,0,0,0)",
40
  plot_bgcolor="rgba(0,0,0,0)",
41
  font=dict(size=12),
42
  )
43
- return fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  # ── AI explanation (rule-based, no API key needed) ─────────
46
  def explain(row):
47
- name = row["restaurant_name"]
48
- label = row["worth_it_label"]
49
- score = row["true_score"]
50
- price = row["price_category"]
51
- sent = row["sentiment_score"]
52
- stars = row["star_rating"]
53
- vols = row["sentiment_volatility"]
54
- pf = row["price_fairness"]
55
 
56
  sentiment_word = "positive" if sent > 0.2 else ("neutral" if sent > -0.2 else "negative")
57
  volatility_note = (
@@ -81,9 +133,11 @@ def explain(row):
81
  f"and the star rating is {stars:.1f}/5.{volatility_note}{value_note}"
82
  )
83
 
 
84
  # ── main function ──────────────────────────────────────────
85
  def search(cuisine, price, arrond, top_n):
86
  filtered = df.copy()
 
87
  if cuisine != "All":
88
  filtered = filtered[filtered["cuisine_type"] == cuisine]
89
  if price != "All":
@@ -92,41 +146,54 @@ def search(cuisine, price, arrond, top_n):
92
  filtered = filtered[filtered["arrondissement"] == arrond]
93
 
94
  if filtered.empty:
95
- return "No restaurants match your filters.", None, ""
 
96
 
97
  top = filtered.nlargest(int(top_n), "true_score").reset_index(drop=True)
98
  best = top.iloc[0]
99
 
100
  # Results table
101
- display = top[[
102
- "restaurant_name", "cuisine_type", "arrondissement",
103
- "price_category", "star_rating", "true_score", "worth_it_label"
104
- ]].rename(columns={
105
- "restaurant_name": "Name",
106
- "cuisine_type": "Cuisine",
107
- "arrondissement": "Area",
108
- "price_category": "Price",
109
- "star_rating": "Stars",
110
- "true_score": "True Score",
111
- "worth_it_label": "Verdict",
112
- })
113
-
114
- chart = make_chart(best)
 
 
 
 
 
 
 
 
 
115
  explanation = explain(best)
116
 
117
- return display, chart, explanation
 
118
 
119
  # ── interface ──────────────────────────────────────────────
120
  with gr.Blocks(title="Restaurant Worth-It Score β€” Paris") as demo:
121
- gr.Markdown("## Restaurant Worth-It Score β€” Paris\n"
122
- "AI-powered ratings that go beyond the stars. "
123
- "Select your filters to find restaurants that truly deliver.")
 
 
124
 
125
  with gr.Row():
126
  cuisine_dd = gr.Dropdown(CUISINES, value="All", label="Cuisine type")
127
- price_dd = gr.Dropdown(PRICES, value="All", label="Price tier")
128
- arrond_dd = gr.Dropdown(ARRONDS, value="All", label="Arrondissement")
129
- top_n_sl = gr.Slider(3, 20, value=10, step=1, label="Results to show")
130
 
131
  search_btn = gr.Button("Find restaurants", variant="primary")
132
 
@@ -137,14 +204,18 @@ with gr.Blocks(title="Restaurant Worth-It Score β€” Paris") as demo:
137
  with gr.Column(scale=1):
138
  gr.Markdown("#### Score breakdown β€” top result")
139
  score_chart = gr.Plot(label="")
 
140
  with gr.Column(scale=1):
141
- gr.Markdown("#### AI explanation β€” top result")
142
- explanation_box = gr.Markdown()
 
 
 
143
 
144
  search_btn.click(
145
  fn=search,
146
  inputs=[cuisine_dd, price_dd, arrond_dd, top_n_sl],
147
- outputs=[results_table, score_chart, explanation_box],
148
  )
149
 
150
  demo.launch()
 
5
  # ── load data ──────────────────────────────────────────────
6
  df = pd.read_csv("restaurant_master_scored.csv")
7
 
8
+ CUISINES = ["All"] + sorted(df["cuisine_type"].unique().tolist())
9
+ PRICES = ["All"] + ["€", "€€", "€€€", "€€€€"]
10
+ ARRONDS = ["All"] + sorted(df["arrondissement"].unique().tolist())
11
 
12
  LABEL_COLOR = {"Worth It": "#1A6B3C", "Maybe": "#7D5A00", "Skip It": "#8B1A1A"}
13
+ LABEL_BG = {"Worth It": "#EAF3DE", "Maybe": "#FAEEDA", "Skip It": "#FCEBEB"}
14
 
15
+
16
+ # ── charts ──────────────────────────────────────────────
17
+ def make_chart(row, filtered_df):
18
+ # First chart: score component chart for top result
19
  components = {
20
+ "Sentiment adj": round(row["sentiment_adj_norm"] * 0.35 * 100, 1),
21
+ "Price fairness": round(row["price_fairness"] * 0.25 * 100, 1),
22
+ "Consistency": round(row["consistency_index"] * 0.20 * 100, 1),
23
+ "Trust": round(row["trust_score"] * 0.10 * 100, 1),
24
+ "Divergence βˆ’": round(-row["star_sentiment_divergence"] * 0.10 * 100, 1),
25
  }
26
+
27
  colors = ["#3D2B8E", "#7B6FCA", "#1A6B3C", "#7D5A00", "#8B1A1A"]
28
+
29
+ fig_bar = go.Figure(
30
+ go.Bar(
31
+ x=list(components.values()),
32
+ y=list(components.keys()),
33
+ orientation="h",
34
+ marker_color=colors,
35
+ text=[f"{v:+.1f}" for v in components.values()],
36
+ textposition="outside",
37
+ )
38
+ )
39
+
40
+ fig_bar.update_layout(
41
  margin=dict(l=10, r=60, t=10, b=10),
42
  height=220,
43
+ xaxis=dict(
44
+ showgrid=False,
45
+ zeroline=True,
46
+ zerolinecolor="#cccccc",
47
+ title="Points",
48
+ ),
49
  yaxis=dict(showgrid=False),
50
  paper_bgcolor="rgba(0,0,0,0)",
51
  plot_bgcolor="rgba(0,0,0,0)",
52
  font=dict(size=12),
53
  )
54
+
55
+ # Second chart: scatter plot of all filtered restaurants
56
+ fig_scatter = go.Figure()
57
+
58
+ for label in ["Worth It", "Maybe", "Skip It"]:
59
+ subset = filtered_df[filtered_df["worth_it_label"] == label]
60
+ if not subset.empty:
61
+ fig_scatter.add_trace(
62
+ go.Scatter(
63
+ x=subset["star_rating"],
64
+ y=subset["true_score"],
65
+ mode="markers",
66
+ name=label,
67
+ marker=dict(
68
+ size=10,
69
+ color=LABEL_COLOR.get(label, "#666666"),
70
+ line=dict(width=1, color="white"),
71
+ ),
72
+ text=subset["restaurant_name"],
73
+ hovertemplate=(
74
+ "<b>%{text}</b><br>"
75
+ "Stars: %{x:.1f}<br>"
76
+ "True Score: %{y:.1f}<br>"
77
+ "Verdict: " + label +
78
+ "<extra></extra>"
79
+ ),
80
+ )
81
+ )
82
+
83
+ fig_scatter.update_layout(
84
+ margin=dict(l=10, r=10, t=40, b=10),
85
+ height=320,
86
+ xaxis=dict(title="Star rating", showgrid=True, gridcolor="#eeeeee"),
87
+ yaxis=dict(title="True score", showgrid=True, gridcolor="#eeeeee"),
88
+ paper_bgcolor="rgba(0,0,0,0)",
89
+ plot_bgcolor="rgba(0,0,0,0)",
90
+ font=dict(size=12),
91
+ legend=dict(orientation="h", y=1.12, x=0),
92
+ )
93
+
94
+ return fig_bar, fig_scatter
95
+
96
 
97
  # ── AI explanation (rule-based, no API key needed) ─────────
98
  def explain(row):
99
+ name = row["restaurant_name"]
100
+ label = row["worth_it_label"]
101
+ score = row["true_score"]
102
+ price = row["price_category"]
103
+ sent = row["sentiment_score"]
104
+ stars = row["star_rating"]
105
+ vols = row["sentiment_volatility"]
106
+ pf = row["price_fairness"]
107
 
108
  sentiment_word = "positive" if sent > 0.2 else ("neutral" if sent > -0.2 else "negative")
109
  volatility_note = (
 
133
  f"and the star rating is {stars:.1f}/5.{volatility_note}{value_note}"
134
  )
135
 
136
+
137
  # ── main function ──────────────────────────────────────────
138
  def search(cuisine, price, arrond, top_n):
139
  filtered = df.copy()
140
+
141
  if cuisine != "All":
142
  filtered = filtered[filtered["cuisine_type"] == cuisine]
143
  if price != "All":
 
146
  filtered = filtered[filtered["arrondissement"] == arrond]
147
 
148
  if filtered.empty:
149
+ empty_fig = go.Figure()
150
+ return "No restaurants match your filters.", empty_fig, empty_fig, ""
151
 
152
  top = filtered.nlargest(int(top_n), "true_score").reset_index(drop=True)
153
  best = top.iloc[0]
154
 
155
  # Results table
156
+ display = top[
157
+ [
158
+ "restaurant_name",
159
+ "cuisine_type",
160
+ "arrondissement",
161
+ "price_category",
162
+ "star_rating",
163
+ "true_score",
164
+ "worth_it_label",
165
+ ]
166
+ ].rename(
167
+ columns={
168
+ "restaurant_name": "Name",
169
+ "cuisine_type": "Cuisine",
170
+ "arrondissement": "Area",
171
+ "price_category": "Price",
172
+ "star_rating": "Stars",
173
+ "true_score": "True Score",
174
+ "worth_it_label": "Verdict",
175
+ }
176
+ )
177
+
178
+ score_chart, scatter_chart = make_chart(best, top)
179
  explanation = explain(best)
180
 
181
+ return display, score_chart, scatter_chart, explanation
182
+
183
 
184
  # ── interface ──────────────────────────────────────────────
185
  with gr.Blocks(title="Restaurant Worth-It Score β€” Paris") as demo:
186
+ gr.Markdown(
187
+ "## Restaurant Worth-It Score β€” Paris\n"
188
+ "AI-powered ratings that go beyond the stars. "
189
+ "Select your filters to find restaurants that truly deliver."
190
+ )
191
 
192
  with gr.Row():
193
  cuisine_dd = gr.Dropdown(CUISINES, value="All", label="Cuisine type")
194
+ price_dd = gr.Dropdown(PRICES, value="All", label="Price tier")
195
+ arrond_dd = gr.Dropdown(ARRONDS, value="All", label="Arrondissement")
196
+ top_n_sl = gr.Slider(3, 20, value=10, step=1, label="Results to show")
197
 
198
  search_btn = gr.Button("Find restaurants", variant="primary")
199
 
 
204
  with gr.Column(scale=1):
205
  gr.Markdown("#### Score breakdown β€” top result")
206
  score_chart = gr.Plot(label="")
207
+
208
  with gr.Column(scale=1):
209
+ gr.Markdown("#### All filtered restaurants")
210
+ scatter_chart = gr.Plot(label="")
211
+
212
+ gr.Markdown("#### AI explanation β€” top result")
213
+ explanation_box = gr.Markdown()
214
 
215
  search_btn.click(
216
  fn=search,
217
  inputs=[cuisine_dd, price_dd, arrond_dd, top_n_sl],
218
+ outputs=[results_table, score_chart, scatter_chart, explanation_box],
219
  )
220
 
221
  demo.launch()