vighnesh-shetty-vs commited on
Commit
526fab1
·
1 Parent(s): 2bf4a82

Add updated files

Browse files
Files changed (1) hide show
  1. app.py +45 -70
app.py CHANGED
@@ -131,40 +131,33 @@ def get_impact_cards(impact, category):
131
  """
132
 
133
  def format_alt_button(text, impact):
134
- """Formats the button text with spacing and potential savings metrics."""
135
  icon = "💡"
136
  if "Search" in text or "Google" in text: icon = "🔍"
137
  elif "Wikipedia" in text or "Encyclopedia" in text: icon = "📚"
138
  elif "Expert" in text or "Quora" in text: icon = "👤"
139
  elif "Wolfram" in text or "Geogebra" in text or "Desmos" in text: icon = "🧮"
140
  elif "Reddit" in text or "Gutenberg" in text or "Thesaurus" in text: icon = "📝"
141
-
142
  return f"{icon} {text}\n\n🏆 Score: +10 Pts\n💧 Save: {impact['water_ml']} mL\n⚡ Save: {impact['energy_wh']} Wh\n☁️ Save: {impact['co2_g']} g"
143
 
144
  def generate_victory_dashboard(state):
145
- """Generates a massive, celebratory end-game report with detailed analytics."""
146
-
147
- # Calculate Total Savings
148
- total_water_saved = 0
149
- total_energy_saved = 0
150
- total_co2_saved = 0
151
 
152
  rows = ""
153
  for item in state["history"]:
154
- # If it was a justified complex query, there are no savings
155
  if item['alt_name'] == "None (Justified Use)":
156
  saved_w, saved_e, saved_c = 0.0, 0.0, 0.0
157
  alt_display = "<span style='color: #94a3b8;'>Justified Use (No Alternative)</span>"
158
  else:
159
- # Calculate savings (LLM cost - Eco-Alternative cost)
160
- saved_w = max(0, item['water_ml'] - 0.0)
161
  saved_e = max(0, item['energy_wh'] - 0.001)
162
  saved_c = max(0, item['co2_g'] - 0.01)
163
 
164
- total_water_saved += saved_w
165
- total_energy_saved += saved_e
166
- total_co2_saved += saved_c
167
-
168
  alt_display = f"<span style='color: #34d399;'>{item['alt_name']}</span>"
169
 
170
  rows += f"""
@@ -177,55 +170,40 @@ def generate_victory_dashboard(state):
177
  """
178
 
179
  return f"""
180
- <style>
181
- @keyframes pulseGlow {{
182
- 0% {{ box-shadow: 0 0 20px rgba(52, 211, 153, 0.4); }}
183
- 50% {{ box-shadow: 0 0 60px rgba(52, 211, 153, 0.8); }}
184
- 100% {{ box-shadow: 0 0 20px rgba(52, 211, 153, 0.4); }}
185
- }}
186
- .victory-dashboard {{ background: linear-gradient(135deg, #0f172a, #1e293b); padding: 40px; border-radius: 24px; border: 2px solid #34d399; animation: pulseGlow 2s infinite; color: white; }}
187
- .victory-title {{ text-align: center; color: #34d399; font-size: 3.5em !important; text-shadow: 0 0 20px rgba(52, 211, 153, 0.6); margin-bottom: 5px; }}
188
- .victory-subtitle {{ text-align: center; font-size: 1.3em; color: #a7f3d0; margin-bottom: 30px; }}
189
- .victory-stats-row {{ display: flex; gap: 20px; margin-top: 30px; margin-bottom: 40px; }}
190
- .v-stat-box {{ flex: 1; background: rgba(0,0,0,0.4); padding: 25px; border-radius: 16px; text-align: center; border: 1px solid rgba(52, 211, 153, 0.3); }}
191
- .v-stat-box h4 {{ color: #94a3b8; font-size: 0.9em; text-transform: uppercase; letter-spacing: 1.5px; margin: 0 0 10px 0; }}
192
- .v-stat-box h2 {{ color: #38bdf8; font-size: 2.8em; margin: 0; }}
193
- .v-stat-highlight h2 {{ color: #34d399; }}
194
- </style>
195
-
196
  <div class="victory-dashboard">
197
- <h1 class="victory-title">🏆 YOU BEAT THE SYSTEM! 🏆</h1>
198
- <p class="victory-subtitle">You successfully navigated the AI ecosystem, reached {state['points']} points, and saved Drip!</p>
 
199
 
200
  <div class="victory-stats-row">
201
  <div class="v-stat-box">
202
- <h4>Water Remaining</h4>
203
  <h2>{state['water']:.2f} L</h2>
204
  </div>
205
- <div class="v-stat-box v-stat-highlight">
206
- <h4>Total Metrics Saved</h4>
207
- <p style="font-size: 1.2em; color: #34d399; margin:0;">💧 {total_water_saved:.1f} mL</p>
208
- <p style="font-size: 1.2em; color: #facc15; margin:0;">⚡ {total_energy_saved:.2f} Wh</p>
209
- <p style="font-size: 1.2em; color: #a8a29e; margin:0;">☁️ {total_co2_saved:.2f} g</p>
210
  </div>
211
  <div class="v-stat-box" style="border-color: #fca5a5;">
212
- <h4 style="color: #fca5a5;">Metrics Wasted</h4>
213
- <p style="font-size: 1.2em; color: #fca5a5; margin:0;">💧 {10.0 - state['water']:.2f} L</p>
214
- <p style="font-size: 1.2em; color: #fca5a5; margin:0;">⚡ {state['energy']:.4f} kWh</p>
215
- <p style="font-size: 1.2em; color: #fca5a5; margin:0;">☁️ {state['co2']:.2f} g</p>
216
  </div>
217
  </div>
218
 
219
- <h3 style="margin-top: 30px; color: #38bdf8; font-size: 1.8em;">📊 Your AI Audit Log</h3>
220
- <p style="opacity: 0.9; margin-bottom: 20px; font-size: 1.1em;">Review your query history below to see exactly what you could have saved by choosing eco-friendly alternatives.</p>
221
 
222
  <div style="max-height: 400px; overflow-y: auto; background: rgba(15, 23, 42, 0.9); border-radius: 12px; border: 1px solid rgba(255,255,255,0.1);">
223
- <table style="width: 100%; text-align: left; border-collapse: collapse; font-size: 1.05em;">
224
  <tr style="background: rgba(56, 189, 248, 0.1); border-bottom: 2px solid #38bdf8;">
225
- <th style="padding: 15px; color: #38bdf8;">Your Query</th>
226
- <th style="padding: 15px; color: #fca5a5;">LLM Cost (Wasted)</th>
227
- <th style="padding: 15px; color: #34d399;">Better Alternative</th>
228
- <th style="padding: 15px; color: #60a5fa;">Potential Savings</th>
229
  </tr>
230
  {rows}
231
  </table>
@@ -254,19 +232,17 @@ def process_query(user_input, selected_model, state):
254
 
255
  if category == "complex research query":
256
  state["points"] += 50
257
- dialogue = f"Finally, a real question! Draining my {selected_model} servers, but totally justified."
258
  else:
259
  show_alts = True
260
  raw_alts = ALTERNATIVES.get(category, [{"text": "Google", "url": "https://google.com"}])
261
  state["current_best_alt"] = raw_alts[0]
262
  best_alt_name = raw_alts[0]["text"]
263
-
264
  random.shuffle(raw_alts)
265
  state["current_shuffled_alts"] = raw_alts
266
  alt_choices = [format_alt_button(a["text"], impact) for a in raw_alts]
267
  dialogue = get_dialogue(state["water"], category)
268
 
269
- # Log the exact metrics for the victory dashboard
270
  state["history"].append({
271
  "query": user_input,
272
  "water_ml": impact["water_ml"],
@@ -279,9 +255,8 @@ def process_query(user_input, selected_model, state):
279
  drip_ui = get_drip_visuals(state["water"])
280
  impact_ui = get_impact_cards(impact, category)
281
  audio_path = generate_audio(dialogue)
282
- feedback_text = f"<div class='feedback-box'>🧠 <strong>{category.upper()}</strong> Detected on {selected_model}!<br><br><em>\"{dialogue}\"</em></div>"
283
 
284
- # Check for Win/Loss immediately upon sending query
285
  if state["points"] >= 500 or state["water"] <= 0:
286
  state["game_over"] = True
287
  victory_html = generate_victory_dashboard(state)
@@ -297,7 +272,7 @@ def select_alternative(choice_text, state):
297
  if state["game_over"] or not state.get("current_best_alt"):
298
  return state, gr.update(), gr.update(), gr.update(), gr.update(visible=True), gr.update(visible=False), gr.update()
299
 
300
- clean_choice = choice_text.split("\n")[1].strip()
301
  selected_dict = next((item for item in state["current_shuffled_alts"] if item["text"] == clean_choice), None)
302
 
303
  if clean_choice == state["current_best_alt"]["text"]:
@@ -308,7 +283,6 @@ def select_alternative(choice_text, state):
308
 
309
  stats_ui = get_stats_html(state["water"], state["energy"], state["co2"], state["points"])
310
 
311
- # Check for win after points are awarded from selecting an alternative
312
  if state["points"] >= 500:
313
  state["game_over"] = True
314
  victory_html = generate_victory_dashboard(state)
@@ -353,19 +327,27 @@ h1 { text-align: center; color: #38bdf8; text-shadow: 0 0 15px rgba(56, 189, 248
353
  .bad-impact { background: linear-gradient(180deg, rgba(127, 29, 29, 0.3), rgba(69, 10, 10, 0.5)); border-top: 3px solid #ef4444; }
354
  .good-impact { background: linear-gradient(180deg, rgba(20, 83, 45, 0.3), rgba(6, 78, 59, 0.5)); border-top: 3px solid #10b981; }
355
 
356
- /* Enhanced Alternative Cards */
357
  .alt-group { padding: 25px; background: linear-gradient(145deg, rgba(16, 185, 129, 0.05), rgba(6, 95, 70, 0.1)); border-radius: 20px; border: 1px solid rgba(16, 185, 129, 0.3); margin-top: 25px; box-shadow: 0 10px 30px rgba(0,0,0,0.2);}
358
  .alt-card { background: linear-gradient(145deg, #1e293b, #0f172a) !important; border: 1px solid #10b981 !important; color: #a7f3d0 !important; height: auto !important; min-height: 180px !important; border-radius: 16px !important; font-size: 1.05em !important; font-weight: 500 !important; white-space: pre-wrap !important; line-height: 1.5 !important; padding: 15px !important; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; cursor: pointer; box-shadow: 0 4px 15px rgba(0,0,0,0.4) !important;}
359
  .alt-card:hover { background: linear-gradient(145deg, #064e3b, #065f46) !important; transform: translateY(-8px) !important; box-shadow: 0 12px 30px rgba(16, 185, 129, 0.3) !important; color: white !important; border-color: #34d399 !important;}
360
  .custom-dropdown { background: rgba(30, 41, 59, 0.8) !important; border: 1px solid #38bdf8 !important; border-radius: 12px !important; }
361
 
362
- /* Victory Dashboard CSS */
363
- .victory-dashboard { background: linear-gradient(135deg, #0f172a, #1e293b); padding: 40px; border-radius: 24px; border: 2px solid #34d399; box-shadow: 0 0 50px rgba(52, 211, 153, 0.3); color: white; animation: floatUp 1s ease-out; }
364
- .victory-title { text-align: center; color: #34d399; font-size: 3em !important; text-shadow: 0 0 20px rgba(52, 211, 153, 0.6); margin-bottom: 10px; }
 
365
  .victory-stats-row { display: flex; gap: 20px; margin-top: 30px; }
366
- .v-stat-box { flex: 1; background: rgba(0,0,0,0.3); padding: 20px; border-radius: 16px; text-align: center; border: 1px solid rgba(255,255,255,0.1); }
367
  .v-stat-box h4 { color: #94a3b8; font-size: 0.9em; text-transform: uppercase; letter-spacing: 1px; margin: 0 0 10px 0; }
368
  .v-stat-box h2 { color: #38bdf8; font-size: 2.5em; margin: 0; }
 
 
 
 
 
 
 
 
369
  """
370
 
371
  with gr.Blocks(title="EcoQueryQuest") as demo:
@@ -377,10 +359,8 @@ with gr.Blocks(title="EcoQueryQuest") as demo:
377
  gr.Markdown("<h1>🌍 EcoQueryQuest</h1>")
378
  gr.Markdown("<div class='subtitle'>Select a model, type a query, and watch Drip react. Reach 500 points to win!</div>")
379
 
380
- # The main stats dashboard remains visible
381
  stats_html = gr.HTML(get_stats_html(10.0, 0.0, 0.0, 0))
382
 
383
- # ---- MAIN GAME UI ----
384
  with gr.Column(visible=True) as main_game_ui:
385
  with gr.Row():
386
  with gr.Column(scale=1, elem_classes=["drip-pod"]):
@@ -390,11 +370,9 @@ with gr.Blocks(title="EcoQueryQuest") as demo:
390
 
391
  with gr.Column(scale=2):
392
  model_selector = gr.Dropdown(choices=list(MODELS.keys()), value="GPT-5.4", label="Select Target LLM Backend", elem_classes=["custom-dropdown"])
393
-
394
  with gr.Row(elem_classes=["input-row"]):
395
- user_input = gr.Textbox(show_label=False, placeholder="Type your query here...\n(Press Shift+Enter for new line)", elem_classes=["custom-textbox"], scale=4, lines=3)
396
  submit_btn = gr.Button("Send Query", elem_classes=["custom-btn"], scale=1)
397
-
398
  impact_display = gr.HTML()
399
 
400
  with gr.Group(visible=False, elem_classes=["alt-group"]) as alternatives_group:
@@ -405,18 +383,15 @@ with gr.Blocks(title="EcoQueryQuest") as demo:
405
  alt_btn_3 = gr.Button("", elem_classes=["alt-card"])
406
  alt_feedback = gr.Markdown()
407
 
408
- # ---- VICTORY SCREEN UI ----
409
  with gr.Column(visible=False) as victory_ui:
410
  victory_display = gr.HTML()
411
 
412
- # Ensure these outputs match EXACTLY with the 15 return items in process_query
413
  submit_btn.click(
414
  fn=process_query,
415
  inputs=[user_input, model_selector, game_state],
416
  outputs=[game_state, stats_html, drip_html, drip_audio, impact_display, drip_feedback, alternatives_group, alt_btn_1, alt_btn_2, alt_btn_3, alt_feedback, user_input, main_game_ui, victory_ui, victory_display]
417
  )
418
 
419
- # Ensure these outputs match EXACTLY with the 7 return items in select_alternative
420
  for btn in [alt_btn_1, alt_btn_2, alt_btn_3]:
421
  btn.click(
422
  fn=select_alternative,
 
131
  """
132
 
133
  def format_alt_button(text, impact):
 
134
  icon = "💡"
135
  if "Search" in text or "Google" in text: icon = "🔍"
136
  elif "Wikipedia" in text or "Encyclopedia" in text: icon = "📚"
137
  elif "Expert" in text or "Quora" in text: icon = "👤"
138
  elif "Wolfram" in text or "Geogebra" in text or "Desmos" in text: icon = "🧮"
139
  elif "Reddit" in text or "Gutenberg" in text or "Thesaurus" in text: icon = "📝"
 
140
  return f"{icon} {text}\n\n🏆 Score: +10 Pts\n💧 Save: {impact['water_ml']} mL\n⚡ Save: {impact['energy_wh']} Wh\n☁️ Save: {impact['co2_g']} g"
141
 
142
  def generate_victory_dashboard(state):
143
+ """Generates a celebratory end-game report with detailed query analytics[cite: 14, 41]."""
144
+ total_w_saved = 0
145
+ total_e_saved = 0
146
+ total_c_saved = 0
 
 
147
 
148
  rows = ""
149
  for item in state["history"]:
 
150
  if item['alt_name'] == "None (Justified Use)":
151
  saved_w, saved_e, saved_c = 0.0, 0.0, 0.0
152
  alt_display = "<span style='color: #94a3b8;'>Justified Use (No Alternative)</span>"
153
  else:
154
+ saved_w = item['water_ml']
 
155
  saved_e = max(0, item['energy_wh'] - 0.001)
156
  saved_c = max(0, item['co2_g'] - 0.01)
157
 
158
+ total_w_saved += saved_w
159
+ total_e_saved += saved_e
160
+ total_c_saved += saved_c
 
161
  alt_display = f"<span style='color: #34d399;'>{item['alt_name']}</span>"
162
 
163
  rows += f"""
 
170
  """
171
 
172
  return f"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  <div class="victory-dashboard">
174
+ <div class="confetti"></div>
175
+ <h1 class="victory-title">🏆 PLANET SAVED! 🏆</h1>
176
+ <p style="text-align: center; font-size: 1.3em; color: #a7f3d0; margin-bottom: 30px;">You reached {state['points']} points and kept Drip alive!</p>
177
 
178
  <div class="victory-stats-row">
179
  <div class="v-stat-box">
180
+ <h4>Final Water</h4>
181
  <h2>{state['water']:.2f} L</h2>
182
  </div>
183
+ <div class="v-stat-box" style="border-color: #34d399;">
184
+ <h4 style="color: #34d399;">Planetary Savings</h4>
185
+ <p style="color: #34d399; margin: 5px 0;">💧 {total_w_saved:.1f} mL Saved</p>
186
+ <p style="color: #facc15; margin: 5px 0;">⚡ {total_e_saved:.2f} Wh Saved</p>
187
+ <p style="color: #a8a29e; margin: 5px 0;">☁️ {total_c_saved:.2f} g Saved</p>
188
  </div>
189
  <div class="v-stat-box" style="border-color: #fca5a5;">
190
+ <h4 style="color: #fca5a5;">Total Usage</h4>
191
+ <p style="color: #fca5a5; margin: 5px 0;">💧 {10.0 - state['water']:.2f} L</p>
192
+ <p style="color: #fca5a5; margin: 5px 0;">⚡ {state['energy']:.4f} kWh</p>
193
+ <p style="color: #fca5a5; margin: 5px 0;">☁️ {state['co2']:.2f} g</p>
194
  </div>
195
  </div>
196
 
197
+ <h3 style="margin-top: 40px; color: #38bdf8; font-size: 1.8em;">📊 AI Usage Audit Log</h3>
198
+ <p style="opacity: 0.9; margin-bottom: 20px;">Detailed breakdown of your session's environmental impact[cite: 14].</p>
199
 
200
  <div style="max-height: 400px; overflow-y: auto; background: rgba(15, 23, 42, 0.9); border-radius: 12px; border: 1px solid rgba(255,255,255,0.1);">
201
+ <table style="width: 100%; text-align: left; border-collapse: collapse; font-size: 1em;">
202
  <tr style="background: rgba(56, 189, 248, 0.1); border-bottom: 2px solid #38bdf8;">
203
+ <th style="padding: 15px;">User Query</th>
204
+ <th style="padding: 15px;">LLM Cost (Wasted)</th>
205
+ <th style="padding: 15px;">Best Alternative</th>
206
+ <th style="padding: 15px;">Potential Savings</th>
207
  </tr>
208
  {rows}
209
  </table>
 
232
 
233
  if category == "complex research query":
234
  state["points"] += 50
235
+ dialogue = f"A legitimate research query! Finally, a worthy use of my massive architecture. Drain away!"
236
  else:
237
  show_alts = True
238
  raw_alts = ALTERNATIVES.get(category, [{"text": "Google", "url": "https://google.com"}])
239
  state["current_best_alt"] = raw_alts[0]
240
  best_alt_name = raw_alts[0]["text"]
 
241
  random.shuffle(raw_alts)
242
  state["current_shuffled_alts"] = raw_alts
243
  alt_choices = [format_alt_button(a["text"], impact) for a in raw_alts]
244
  dialogue = get_dialogue(state["water"], category)
245
 
 
246
  state["history"].append({
247
  "query": user_input,
248
  "water_ml": impact["water_ml"],
 
255
  drip_ui = get_drip_visuals(state["water"])
256
  impact_ui = get_impact_cards(impact, category)
257
  audio_path = generate_audio(dialogue)
258
+ feedback_text = f"<div class='feedback-box'>🧠 <strong>{category.upper()}</strong> Detected!<br><br><em>\"{dialogue}\"</em></div>"
259
 
 
260
  if state["points"] >= 500 or state["water"] <= 0:
261
  state["game_over"] = True
262
  victory_html = generate_victory_dashboard(state)
 
272
  if state["game_over"] or not state.get("current_best_alt"):
273
  return state, gr.update(), gr.update(), gr.update(), gr.update(visible=True), gr.update(visible=False), gr.update()
274
 
275
+ clean_choice = choice_text.split("\n")[0][2:].strip()
276
  selected_dict = next((item for item in state["current_shuffled_alts"] if item["text"] == clean_choice), None)
277
 
278
  if clean_choice == state["current_best_alt"]["text"]:
 
283
 
284
  stats_ui = get_stats_html(state["water"], state["energy"], state["co2"], state["points"])
285
 
 
286
  if state["points"] >= 500:
287
  state["game_over"] = True
288
  victory_html = generate_victory_dashboard(state)
 
327
  .bad-impact { background: linear-gradient(180deg, rgba(127, 29, 29, 0.3), rgba(69, 10, 10, 0.5)); border-top: 3px solid #ef4444; }
328
  .good-impact { background: linear-gradient(180deg, rgba(20, 83, 45, 0.3), rgba(6, 78, 59, 0.5)); border-top: 3px solid #10b981; }
329
 
 
330
  .alt-group { padding: 25px; background: linear-gradient(145deg, rgba(16, 185, 129, 0.05), rgba(6, 95, 70, 0.1)); border-radius: 20px; border: 1px solid rgba(16, 185, 129, 0.3); margin-top: 25px; box-shadow: 0 10px 30px rgba(0,0,0,0.2);}
331
  .alt-card { background: linear-gradient(145deg, #1e293b, #0f172a) !important; border: 1px solid #10b981 !important; color: #a7f3d0 !important; height: auto !important; min-height: 180px !important; border-radius: 16px !important; font-size: 1.05em !important; font-weight: 500 !important; white-space: pre-wrap !important; line-height: 1.5 !important; padding: 15px !important; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; cursor: pointer; box-shadow: 0 4px 15px rgba(0,0,0,0.4) !important;}
332
  .alt-card:hover { background: linear-gradient(145deg, #064e3b, #065f46) !important; transform: translateY(-8px) !important; box-shadow: 0 12px 30px rgba(16, 185, 129, 0.3) !important; color: white !important; border-color: #34d399 !important;}
333
  .custom-dropdown { background: rgba(30, 41, 59, 0.8) !important; border: 1px solid #38bdf8 !important; border-radius: 12px !important; }
334
 
335
+ /* Victory Dashboard & Celebration */
336
+ @keyframes pulseGlow { 0% { box-shadow: 0 0 20px rgba(52, 211, 153, 0.4); } 50% { box-shadow: 0 0 50px rgba(52, 211, 153, 0.8); } 100% { box-shadow: 0 0 20px rgba(52, 211, 153, 0.4); } }
337
+ .victory-dashboard { background: linear-gradient(135deg, #0f172a, #1e293b); padding: 40px; border-radius: 24px; border: 2px solid #34d399; animation: pulseGlow 2s infinite; color: white; position: relative; overflow: hidden; }
338
+ .victory-title { text-align: center; color: #34d399; font-size: 3.5em !important; text-shadow: 0 0 20px rgba(52, 211, 153, 0.6); margin-bottom: 5px; }
339
  .victory-stats-row { display: flex; gap: 20px; margin-top: 30px; }
340
+ .v-stat-box { flex: 1; background: rgba(0,0,0,0.4); padding: 25px; border-radius: 16px; text-align: center; border: 1px solid rgba(52, 211, 153, 0.3); }
341
  .v-stat-box h4 { color: #94a3b8; font-size: 0.9em; text-transform: uppercase; letter-spacing: 1px; margin: 0 0 10px 0; }
342
  .v-stat-box h2 { color: #38bdf8; font-size: 2.5em; margin: 0; }
343
+
344
+ /* Confetti Blast Animation */
345
+ .confetti { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 10; }
346
+ .confetti::before { content: '🎉'; position: absolute; font-size: 2rem; animation: scatter 3s infinite linear; }
347
+ @keyframes scatter {
348
+ 0% { transform: translate(50vw, 50vh) rotate(0deg); opacity: 1; }
349
+ 100% { transform: translate(calc(100vw * var(--x)), calc(100vh * var(--y))) rotate(360deg); opacity: 0; }
350
+ }
351
  """
352
 
353
  with gr.Blocks(title="EcoQueryQuest") as demo:
 
359
  gr.Markdown("<h1>🌍 EcoQueryQuest</h1>")
360
  gr.Markdown("<div class='subtitle'>Select a model, type a query, and watch Drip react. Reach 500 points to win!</div>")
361
 
 
362
  stats_html = gr.HTML(get_stats_html(10.0, 0.0, 0.0, 0))
363
 
 
364
  with gr.Column(visible=True) as main_game_ui:
365
  with gr.Row():
366
  with gr.Column(scale=1, elem_classes=["drip-pod"]):
 
370
 
371
  with gr.Column(scale=2):
372
  model_selector = gr.Dropdown(choices=list(MODELS.keys()), value="GPT-5.4", label="Select Target LLM Backend", elem_classes=["custom-dropdown"])
 
373
  with gr.Row(elem_classes=["input-row"]):
374
+ user_input = gr.Textbox(show_label=False, placeholder="Type your query here...", elem_classes=["custom-textbox"], scale=4, lines=3)
375
  submit_btn = gr.Button("Send Query", elem_classes=["custom-btn"], scale=1)
 
376
  impact_display = gr.HTML()
377
 
378
  with gr.Group(visible=False, elem_classes=["alt-group"]) as alternatives_group:
 
383
  alt_btn_3 = gr.Button("", elem_classes=["alt-card"])
384
  alt_feedback = gr.Markdown()
385
 
 
386
  with gr.Column(visible=False) as victory_ui:
387
  victory_display = gr.HTML()
388
 
 
389
  submit_btn.click(
390
  fn=process_query,
391
  inputs=[user_input, model_selector, game_state],
392
  outputs=[game_state, stats_html, drip_html, drip_audio, impact_display, drip_feedback, alternatives_group, alt_btn_1, alt_btn_2, alt_btn_3, alt_feedback, user_input, main_game_ui, victory_ui, victory_display]
393
  )
394
 
 
395
  for btn in [alt_btn_1, alt_btn_2, alt_btn_3]:
396
  btn.click(
397
  fn=select_alternative,