vighnesh-shetty-vs commited on
Commit
488b318
Β·
1 Parent(s): fe378f2

Add updated files

Browse files
Files changed (1) hide show
  1. app.py +107 -100
app.py CHANGED
@@ -200,108 +200,114 @@ def format_alt_button(text, impact):
200
  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"
201
 
202
  def generate_victory_dashboard(state):
203
- total_w_saved, total_e_saved, total_c_saved = 0.0, 0.0, 0.0
204
- rows = ""
205
- for item in state.get("history", []):
206
- alt_name = item.get('alt_name', 'None')
207
- saved_w = item.get('water_ml', 0.0)
208
- saved_e = max(0.0, item.get('energy_wh', 0.0) - 0.001)
209
- saved_c = max(0.0, item.get('co2_g', 0.0) - 0.01)
210
- total_w_saved += saved_w
211
- total_e_saved += saved_e
212
- total_c_saved += saved_c
 
 
 
 
 
 
 
 
 
 
 
213
 
214
- rows += f"""
215
- <tr style="border-bottom: 1px solid rgba(255,255,255,0.1); background: rgba(0,0,0,0.2);">
216
- <td style="padding: 15px; font-style: italic;">"{item.get('query', '')}"</td>
217
- <td style="padding: 15px; color: #fca5a5; line-height: 1.5;">πŸ’§ {item.get('water_ml', 0):.1f} mL<br>⚑ {item.get('energy_wh', 0):.2f} Wh<br>☁️ {item.get('co2_g', 0):.2f} g</td>
218
- <td style="padding: 15px;"><span style='color: #34d399; font-weight: bold;'>{alt_name}</span></td>
219
- <td style="padding: 15px; color: #60a5fa; font-weight: bold; line-height: 1.5;">πŸ’§ {saved_w:.1f} mL<br>⚑ {saved_e:.2f} Wh<br>☁️ {saved_c:.2f} g</td>
220
- </tr>
221
- """
222
- confetti_elements = "".join([f'<div class="confetti-piece" style="left: {random.randint(0, 100)}%; background-color: hsl({random.randint(0, 360)}, 100%, 60%); animation-duration: {random.uniform(2.5, 5)}s; animation-delay: {random.uniform(0, 2)}s;"></div>' for _ in range(60)])
223
-
224
- return f"""
225
- <div class="endgame-wrapper">
226
- {confetti_elements}
227
- <div class="victory-dashboard">
228
- <h1 class="victory-title">πŸŽ‰ PLANET SAVED! πŸŽ‰</h1>
229
- <p style="text-align: center; font-size: 1.3em; color: #a7f3d0; margin-bottom: 30px;">Congratulations! You reached {state.get('points', 0)} points!</p>
230
- <div class="victory-stats-row">
231
- <div class="v-stat-box" style="border-top: 4px solid #34d399;">
232
- <h4 style="color: #34d399;">Planetary Savings</h4>
233
- <p style="color: #34d399; font-size: 1.3em; font-weight: bold; margin: 8px 0;">πŸ’§ {total_w_saved:.1f} mL Saved</p>
234
- <p style="color: #facc15; font-size: 1.3em; font-weight: bold; margin: 8px 0;">⚑ {total_e_saved:.2f} Wh Saved</p>
235
- <p style="color: #a8a29e; font-size: 1.3em; font-weight: bold; margin: 8px 0;">☁️ {total_c_saved:.2f} g Saved</p>
236
  </div>
237
- <div class="v-stat-box" style="border-top: 4px solid #fca5a5;">
238
- <h4 style="color: #fca5a5;">Total Wasted</h4>
239
- <p style="color: #fca5a5; font-size: 1.1em; margin: 8px 0;">πŸ’§ {1.0 - state.get('water', 1.0):.3f} L</p>
240
- <p style="color: #fca5a5; font-size: 1.1em; margin: 8px 0;">⚑ {state.get('energy', 0):.4f} kWh</p>
241
- <p style="color: #fca5a5; font-size: 1.1em; margin: 8px 0;">☁️ {state.get('co2', 0):.2f} g</p>
 
 
 
242
  </div>
243
  </div>
244
- <h3 style="margin-top: 40px; color: #38bdf8; font-size: 1.8em; text-align: center;">πŸ“Š AI Usage Audit Log</h3>
245
- <div style="max-height: 500px; overflow-y: auto; background: rgba(15, 23, 42, 0.9); border-radius: 12px; border: 1px solid rgba(255,255,255,0.1); padding: 10px;">
246
- <table style="width: 100%; text-align: left; border-collapse: collapse; font-size: 1.05em;">
247
- <tr style="background: rgba(56, 189, 248, 0.1); border-bottom: 2px solid #38bdf8;">
248
- <th style="padding: 15px; color: #e2e8f0;">User Query</th><th style="padding: 15px; color: #fca5a5;">LLM Cost</th><th style="padding: 15px; color: #34d399;">Alternative Selected</th><th style="padding: 15px; color: #60a5fa;">Resources Saved</th>
249
- </tr>
250
- {rows}
251
- </table>
252
- </div>
253
  </div>
254
- </div>
255
- """
 
256
 
257
  def generate_defeat_dashboard(state):
258
- rows = ""
259
- for item in state.get("history", []):
260
- rows += f"""
261
- <tr style="border-bottom: 1px solid rgba(255,255,255,0.1); background: rgba(0,0,0,0.2);">
262
- <td style="padding: 15px; font-style: italic;">"{item.get('query', '')}"</td>
263
- <td style="padding: 15px; color: #fca5a5; line-height: 1.5;">πŸ’§ {item.get('water_ml', 0):.1f} mL<br>⚑ {item.get('energy_wh', 0):.2f} Wh<br>☁️ {item.get('co2_g', 0):.2f} g</td>
264
- </tr>
265
- """
266
- ash_elements = "".join([f'<div class="ash-piece" style="left: {random.randint(0, 100)}%; animation-duration: {random.uniform(3, 6)}s; animation-delay: {random.uniform(0, 2)}s;"></div>' for _ in range(60)])
267
-
268
- return f"""
269
- <div class="endgame-wrapper">
270
- {ash_elements}
271
- <div class="defeat-dashboard">
272
- <h1 class="defeat-title">πŸ’€ DRIP EVAPORATED! πŸ’€</h1>
273
- <p style="text-align: center; font-size: 1.3em; color: #fca5a5; margin-bottom: 30px;">You ran out of water before reaching 500 points.</p>
274
- <div class="victory-stats-row">
275
- <div class="v-stat-box" style="border-top: 4px solid #ef4444; background: rgba(239, 68, 68, 0.1);">
276
- <h4 style="color: #ef4444;">Total Resources Wasted</h4>
277
- <p style="color: #fca5a5; font-size: 1.3em; font-weight: bold; margin: 8px 0;">πŸ’§ 1.0 L (Tank Empty)</p>
278
- <p style="color: #fca5a5; font-size: 1.3em; font-weight: bold; margin: 8px 0;">⚑ {state.get('energy', 0):.4f} kWh</p>
279
- <p style="color: #fca5a5; font-size: 1.3em; font-weight: bold; margin: 8px 0;">☁️ {state.get('co2', 0):.2f} g</p>
 
 
 
 
 
 
280
  </div>
281
- <div class="v-stat-box" style="border-top: 4px solid #94a3b8;">
282
- <h4 style="color: #94a3b8;">Final Score</h4>
283
- <p style="color: white; font-size: 3.5em; font-weight: bold; margin: 10px 0;">{state.get('points', 0)}</p>
 
 
 
 
 
284
  </div>
285
  </div>
286
- <h3 style="margin-top: 40px; color: #fca5a5; font-size: 1.8em; text-align: center;">πŸ”₯ Wasted Resources Log</h3>
287
- <div style="max-height: 400px; overflow-y: auto; background: rgba(15, 23, 42, 0.9); border-radius: 12px; border: 1px solid rgba(239, 68, 68, 0.3); padding: 10px;">
288
- <table style="width: 100%; text-align: left; border-collapse: collapse; font-size: 1.05em;">
289
- <tr style="background: rgba(239, 68, 68, 0.15); border-bottom: 2px solid #ef4444;">
290
- <th style="padding: 15px; color: #fca5a5;">User Query</th><th style="padding: 15px; color: #fca5a5;">Resources Drained</th>
291
- </tr>
292
- {rows}
293
- </table>
294
- </div>
295
  </div>
296
- </div>
297
- """
 
298
 
299
  # --- 3. EVENT HANDLERS ---
300
 
301
  def process_query(user_input, selected_model, state):
302
- # CRITICAL FIX: If game is already over, return empty gr.updates so we don't accidentally hide the endgame screen
303
  if state["game_over"] or not user_input.strip():
304
- return [state] + [gr.update()]*14
305
 
306
  result = classifier(user_input, CATEGORIES)
307
  category = result['labels'][0]
@@ -346,24 +352,24 @@ def process_query(user_input, selected_model, state):
346
  state["game_over"] = True
347
  return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(), gr.update(visible=False),
348
  gr.update(), gr.update(), gr.update(), gr.update(), gr.update(value=""),
349
- gr.update(visible=False), gr.update(visible=True), gr.update(value=generate_victory_dashboard(state)))
350
 
351
  # LOSS CONDITION
352
- elif state["water"] <= 0.001: # Using 0.001 to prevent floating point math errors
353
  state["game_over"] = True
354
  return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(), gr.update(visible=False),
355
  gr.update(), gr.update(), gr.update(), gr.update(), gr.update(value=""),
356
- gr.update(visible=False), gr.update(visible=True), gr.update(value=generate_defeat_dashboard(state)))
357
 
358
  # REGULAR GAMEPLAY RETURN
359
  return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(value=feedback_text), gr.update(visible=True),
360
  gr.update(value=alt_choices[0], visible=True), gr.update(value=alt_choices[1], visible=True), gr.update(value=alt_choices[2], visible=True), gr.update(value=""), gr.update(value=""),
361
- gr.update(visible=True), gr.update(visible=False), gr.update())
362
 
363
  def select_alternative(choice_text, state):
364
- # CRITICAL FIX: Empty gr.updates to prevent UI reset if accidentally clicked after game over
365
  if state["game_over"] or not state.get("current_best_alt"):
366
- return [state] + [gr.update()]*6
367
 
368
  first_line = choice_text.split("\n")[0]
369
  clean_choice = first_line.split(" ", 1)[1].strip() if " " in first_line else first_line
@@ -382,9 +388,9 @@ def select_alternative(choice_text, state):
382
  # WIN CONDITION FROM ALTERNATIVE CLICK
383
  if state["points"] >= 500:
384
  state["game_over"] = True
385
- return state, stats_ui, gr.update(), gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), gr.update(value=generate_victory_dashboard(state))
386
 
387
- return state, stats_ui, gr.update(value=msg), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update()
388
 
389
  # --- 4. CSS STYLING ---
390
 
@@ -460,6 +466,7 @@ with gr.Blocks(css=custom_css, title="EcoQueryQuest") as demo:
460
 
461
  stats_html = gr.HTML(get_stats_html(1.0, 0.0, 0.0, 0))
462
 
 
463
  with gr.Column(visible=True) as main_game_ui:
464
  with gr.Row():
465
  with gr.Column(scale=1, elem_classes=["drip-pod"]):
@@ -482,27 +489,27 @@ with gr.Blocks(css=custom_css, title="EcoQueryQuest") as demo:
482
  alt_btn_3 = gr.Button("", elem_classes=["alt-card"])
483
  alt_feedback = gr.Markdown()
484
 
485
- with gr.Column(visible=False) as victory_ui:
486
- victory_display = gr.HTML()
 
487
 
488
- # Pressing Enter in the Textbox triggers the same function
489
  user_input.submit(
490
  fn=process_query,
491
  inputs=[user_input, model_selector, game_state],
492
- 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]
493
  )
494
 
495
  submit_btn.click(
496
  fn=process_query,
497
  inputs=[user_input, model_selector, game_state],
498
- 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]
499
  )
500
 
501
  for btn in [alt_btn_1, alt_btn_2, alt_btn_3]:
502
  btn.click(
503
  fn=select_alternative,
504
  inputs=[btn, game_state],
505
- outputs=[game_state, stats_html, alt_feedback, alternatives_group, main_game_ui, victory_ui, victory_display]
506
  )
507
 
508
  if __name__ == "__main__":
 
200
  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"
201
 
202
  def generate_victory_dashboard(state):
203
+ try:
204
+ total_w_saved, total_e_saved, total_c_saved = 0.0, 0.0, 0.0
205
+ rows = ""
206
+ for item in state.get("history", []):
207
+ alt_name = item.get('alt_name', 'None')
208
+ saved_w = item.get('water_ml', 0.0)
209
+ saved_e = max(0.0, item.get('energy_wh', 0.0) - 0.001)
210
+ saved_c = max(0.0, item.get('co2_g', 0.0) - 0.01)
211
+ total_w_saved += saved_w
212
+ total_e_saved += saved_e
213
+ total_c_saved += saved_c
214
+
215
+ rows += f"""
216
+ <tr style="border-bottom: 1px solid rgba(255,255,255,0.1); background: rgba(0,0,0,0.2);">
217
+ <td style="padding: 15px; font-style: italic;">"{item.get('query', '')}"</td>
218
+ <td style="padding: 15px; color: #fca5a5; line-height: 1.5;">πŸ’§ {item.get('water_ml', 0):.1f} mL<br>⚑ {item.get('energy_wh', 0):.2f} Wh<br>☁️ {item.get('co2_g', 0):.2f} g</td>
219
+ <td style="padding: 15px;"><span style='color: #34d399; font-weight: bold;'>{alt_name}</span></td>
220
+ <td style="padding: 15px; color: #60a5fa; font-weight: bold; line-height: 1.5;">πŸ’§ {saved_w:.1f} mL<br>⚑ {saved_e:.2f} Wh<br>☁️ {saved_c:.2f} g</td>
221
+ </tr>
222
+ """
223
+ confetti_elements = "".join([f'<div class="confetti-piece" style="left: {random.randint(0, 100)}%; background-color: hsl({random.randint(0, 360)}, 100%, 60%); animation-duration: {random.uniform(2.5, 5)}s; animation-delay: {random.uniform(0, 2)}s;"></div>' for _ in range(60)])
224
 
225
+ return f"""
226
+ <div class="endgame-wrapper">
227
+ {confetti_elements}
228
+ <div class="victory-dashboard">
229
+ <h1 class="victory-title">πŸŽ‰ PLANET SAVED! πŸŽ‰</h1>
230
+ <p style="text-align: center; font-size: 1.3em; color: #a7f3d0; margin-bottom: 30px;">Congratulations! You reached {state.get('points', 0)} points!</p>
231
+ <div class="victory-stats-row">
232
+ <div class="v-stat-box" style="border-top: 4px solid #34d399;">
233
+ <h4 style="color: #34d399;">Planetary Savings</h4>
234
+ <p style="color: #34d399; font-size: 1.3em; font-weight: bold; margin: 8px 0;">πŸ’§ {total_w_saved:.1f} mL Saved</p>
235
+ <p style="color: #facc15; font-size: 1.3em; font-weight: bold; margin: 8px 0;">⚑ {total_e_saved:.2f} Wh Saved</p>
236
+ <p style="color: #a8a29e; font-size: 1.3em; font-weight: bold; margin: 8px 0;">☁️ {total_c_saved:.2f} g Saved</p>
237
+ </div>
238
+ <div class="v-stat-box" style="border-top: 4px solid #fca5a5;">
239
+ <h4 style="color: #fca5a5;">Total Wasted</h4>
240
+ <p style="color: #fca5a5; font-size: 1.1em; margin: 8px 0;">πŸ’§ {1.0 - state.get('water', 1.0):.3f} L</p>
241
+ <p style="color: #fca5a5; font-size: 1.1em; margin: 8px 0;">⚑ {state.get('energy', 0):.4f} kWh</p>
242
+ <p style="color: #fca5a5; font-size: 1.1em; margin: 8px 0;">☁️ {state.get('co2', 0):.2f} g</p>
243
+ </div>
 
 
 
244
  </div>
245
+ <h3 style="margin-top: 40px; color: #38bdf8; font-size: 1.8em; text-align: center;">πŸ“Š AI Usage Audit Log</h3>
246
+ <div style="max-height: 500px; overflow-y: auto; background: rgba(15, 23, 42, 0.9); border-radius: 12px; border: 1px solid rgba(255,255,255,0.1); padding: 10px;">
247
+ <table style="width: 100%; text-align: left; border-collapse: collapse; font-size: 1.05em;">
248
+ <tr style="background: rgba(56, 189, 248, 0.1); border-bottom: 2px solid #38bdf8;">
249
+ <th style="padding: 15px; color: #e2e8f0;">User Query</th><th style="padding: 15px; color: #fca5a5;">LLM Cost</th><th style="padding: 15px; color: #34d399;">Alternative Selected</th><th style="padding: 15px; color: #60a5fa;">Resources Saved</th>
250
+ </tr>
251
+ {rows}
252
+ </table>
253
  </div>
254
  </div>
 
 
 
 
 
 
 
 
 
255
  </div>
256
+ """
257
+ except Exception as e:
258
+ return f"<div style='color:red;'>Error generating dashboard: {str(e)}</div>"
259
 
260
  def generate_defeat_dashboard(state):
261
+ try:
262
+ rows = ""
263
+ for item in state.get("history", []):
264
+ rows += f"""
265
+ <tr style="border-bottom: 1px solid rgba(255,255,255,0.1); background: rgba(0,0,0,0.2);">
266
+ <td style="padding: 15px; font-style: italic;">"{item.get('query', '')}"</td>
267
+ <td style="padding: 15px; color: #fca5a5; line-height: 1.5;">πŸ’§ {item.get('water_ml', 0):.1f} mL<br>⚑ {item.get('energy_wh', 0):.2f} Wh<br>☁️ {item.get('co2_g', 0):.2f} g</td>
268
+ </tr>
269
+ """
270
+ ash_elements = "".join([f'<div class="ash-piece" style="left: {random.randint(0, 100)}%; animation-duration: {random.uniform(3, 6)}s; animation-delay: {random.uniform(0, 2)}s;"></div>' for _ in range(60)])
271
+
272
+ return f"""
273
+ <div class="endgame-wrapper">
274
+ {ash_elements}
275
+ <div class="defeat-dashboard">
276
+ <h1 class="defeat-title">πŸ’€ DRIP EVAPORATED! πŸ’€</h1>
277
+ <p style="text-align: center; font-size: 1.3em; color: #fca5a5; margin-bottom: 30px;">You ran out of water before reaching 500 points.</p>
278
+ <div class="victory-stats-row">
279
+ <div class="v-stat-box" style="border-top: 4px solid #ef4444; background: rgba(239, 68, 68, 0.1);">
280
+ <h4 style="color: #ef4444;">Total Resources Wasted</h4>
281
+ <p style="color: #fca5a5; font-size: 1.3em; font-weight: bold; margin: 8px 0;">πŸ’§ 1.0 L (Tank Empty)</p>
282
+ <p style="color: #fca5a5; font-size: 1.3em; font-weight: bold; margin: 8px 0;">⚑ {state.get('energy', 0):.4f} kWh</p>
283
+ <p style="color: #fca5a5; font-size: 1.3em; font-weight: bold; margin: 8px 0;">☁️ {state.get('co2', 0):.2f} g</p>
284
+ </div>
285
+ <div class="v-stat-box" style="border-top: 4px solid #94a3b8;">
286
+ <h4 style="color: #94a3b8;">Final Score</h4>
287
+ <p style="color: white; font-size: 3.5em; font-weight: bold; margin: 10px 0;">{state.get('points', 0)}</p>
288
+ </div>
289
  </div>
290
+ <h3 style="margin-top: 40px; color: #fca5a5; font-size: 1.8em; text-align: center;">πŸ”₯ Wasted Resources Log</h3>
291
+ <div style="max-height: 400px; overflow-y: auto; background: rgba(15, 23, 42, 0.9); border-radius: 12px; border: 1px solid rgba(239, 68, 68, 0.3); padding: 10px;">
292
+ <table style="width: 100%; text-align: left; border-collapse: collapse; font-size: 1.05em;">
293
+ <tr style="background: rgba(239, 68, 68, 0.15); border-bottom: 2px solid #ef4444;">
294
+ <th style="padding: 15px; color: #fca5a5;">User Query</th><th style="padding: 15px; color: #fca5a5;">Resources Drained</th>
295
+ </tr>
296
+ {rows}
297
+ </table>
298
  </div>
299
  </div>
 
 
 
 
 
 
 
 
 
300
  </div>
301
+ """
302
+ except Exception as e:
303
+ return f"<div style='color:red;'>Error generating dashboard: {str(e)}</div>"
304
 
305
  # --- 3. EVENT HANDLERS ---
306
 
307
  def process_query(user_input, selected_model, state):
308
+ # CRITICAL FIX: If game is over, return without changing visibility to avoid hiding endgame screen
309
  if state["game_over"] or not user_input.strip():
310
+ return [state] + [gr.update()]*13
311
 
312
  result = classifier(user_input, CATEGORIES)
313
  category = result['labels'][0]
 
352
  state["game_over"] = True
353
  return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(), gr.update(visible=False),
354
  gr.update(), gr.update(), gr.update(), gr.update(), gr.update(value=""),
355
+ gr.update(visible=False), generate_victory_dashboard(state))
356
 
357
  # LOSS CONDITION
358
+ elif state["water"] <= 0.001:
359
  state["game_over"] = True
360
  return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(), gr.update(visible=False),
361
  gr.update(), gr.update(), gr.update(), gr.update(), gr.update(value=""),
362
+ gr.update(visible=False), generate_defeat_dashboard(state))
363
 
364
  # REGULAR GAMEPLAY RETURN
365
  return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(value=feedback_text), gr.update(visible=True),
366
  gr.update(value=alt_choices[0], visible=True), gr.update(value=alt_choices[1], visible=True), gr.update(value=alt_choices[2], visible=True), gr.update(value=""), gr.update(value=""),
367
+ gr.update(visible=True), gr.update())
368
 
369
  def select_alternative(choice_text, state):
370
+ # CRITICAL FIX: If game is over, return without changing visibility
371
  if state["game_over"] or not state.get("current_best_alt"):
372
+ return [state] + [gr.update()]*5
373
 
374
  first_line = choice_text.split("\n")[0]
375
  clean_choice = first_line.split(" ", 1)[1].strip() if " " in first_line else first_line
 
388
  # WIN CONDITION FROM ALTERNATIVE CLICK
389
  if state["points"] >= 500:
390
  state["game_over"] = True
391
+ return state, stats_ui, gr.update(), gr.update(visible=False), gr.update(visible=False), generate_victory_dashboard(state)
392
 
393
+ return state, stats_ui, gr.update(value=msg), gr.update(visible=False), gr.update(visible=True), gr.update()
394
 
395
  # --- 4. CSS STYLING ---
396
 
 
466
 
467
  stats_html = gr.HTML(get_stats_html(1.0, 0.0, 0.0, 0))
468
 
469
+ # Using standard column; when game is over, we set this to visible=False
470
  with gr.Column(visible=True) as main_game_ui:
471
  with gr.Row():
472
  with gr.Column(scale=1, elem_classes=["drip-pod"]):
 
489
  alt_btn_3 = gr.Button("", elem_classes=["alt-card"])
490
  alt_feedback = gr.Markdown()
491
 
492
+ # The Victory/Defeat screen is ALWAYS attached to the DOM but empty.
493
+ # When game is over, this populates directly, avoiding Gradio's nested visibility bugs.
494
+ endgame_display = gr.HTML("")
495
 
 
496
  user_input.submit(
497
  fn=process_query,
498
  inputs=[user_input, model_selector, game_state],
499
+ 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, endgame_display]
500
  )
501
 
502
  submit_btn.click(
503
  fn=process_query,
504
  inputs=[user_input, model_selector, game_state],
505
+ 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, endgame_display]
506
  )
507
 
508
  for btn in [alt_btn_1, alt_btn_2, alt_btn_3]:
509
  btn.click(
510
  fn=select_alternative,
511
  inputs=[btn, game_state],
512
+ outputs=[game_state, stats_html, alt_feedback, alternatives_group, main_game_ui, endgame_display]
513
  )
514
 
515
  if __name__ == "__main__":