Spaces:
Sleeping
Sleeping
vighnesh-shetty-vs commited on
Commit Β·
2bf4a82
1
Parent(s): 4ae6245
Add updated files
Browse files
app.py
CHANGED
|
@@ -142,47 +142,90 @@ def format_alt_button(text, impact):
|
|
| 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."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
rows = ""
|
| 147 |
for item in state["history"]:
|
| 148 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
rows += f"""
|
| 150 |
-
<tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
|
| 151 |
-
<td style="padding:
|
| 152 |
-
<td style="padding:
|
| 153 |
-
<td style="padding:
|
|
|
|
| 154 |
</tr>
|
| 155 |
"""
|
| 156 |
|
| 157 |
return f"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
<div class="victory-dashboard">
|
| 159 |
-
<h1 class="victory-title">
|
| 160 |
-
<p
|
| 161 |
|
| 162 |
<div class="victory-stats-row">
|
| 163 |
<div class="v-stat-box">
|
| 164 |
-
<h4>
|
| 165 |
<h2>{state['water']:.2f} L</h2>
|
| 166 |
</div>
|
| 167 |
-
<div class="v-stat-box">
|
| 168 |
-
<h4>
|
| 169 |
-
<
|
|
|
|
|
|
|
| 170 |
</div>
|
| 171 |
-
<div class="v-stat-box" style="border-color: #
|
| 172 |
-
<h4 style="color: #
|
| 173 |
-
<
|
|
|
|
|
|
|
| 174 |
</div>
|
| 175 |
</div>
|
| 176 |
|
| 177 |
-
<h3 style="margin-top: 30px; color: #38bdf8;">
|
| 178 |
-
<p style="opacity: 0.
|
| 179 |
|
| 180 |
-
<div style="max-height:
|
| 181 |
-
<table style="width: 100%; text-align: left; border-collapse: collapse;">
|
| 182 |
-
<tr style="background: rgba(
|
| 183 |
-
<th style="padding:
|
| 184 |
-
<th style="padding:
|
| 185 |
-
<th style="padding:
|
|
|
|
| 186 |
</tr>
|
| 187 |
{rows}
|
| 188 |
</table>
|
|
@@ -192,7 +235,6 @@ def generate_victory_dashboard(state):
|
|
| 192 |
|
| 193 |
def process_query(user_input, selected_model, state):
|
| 194 |
if state["game_over"] or not user_input.strip():
|
| 195 |
-
# Update 14 fields (see outputs mapping below)
|
| 196 |
return [state, gr.update()] + [gr.update()]*10 + [gr.update(visible=True), gr.update(visible=False), gr.update()]
|
| 197 |
|
| 198 |
result = classifier(user_input, CATEGORIES)
|
|
@@ -208,7 +250,7 @@ def process_query(user_input, selected_model, state):
|
|
| 208 |
|
| 209 |
show_alts = False
|
| 210 |
alt_choices = ["", "", ""]
|
| 211 |
-
best_alt_name = ""
|
| 212 |
|
| 213 |
if category == "complex research query":
|
| 214 |
state["points"] += 50
|
|
@@ -221,16 +263,16 @@ def process_query(user_input, selected_model, state):
|
|
| 221 |
|
| 222 |
random.shuffle(raw_alts)
|
| 223 |
state["current_shuffled_alts"] = raw_alts
|
| 224 |
-
# Inject the impact metrics into the button formatting
|
| 225 |
alt_choices = [format_alt_button(a["text"], impact) for a in raw_alts]
|
| 226 |
dialogue = get_dialogue(state["water"], category)
|
| 227 |
|
| 228 |
-
# Log the
|
| 229 |
state["history"].append({
|
| 230 |
"query": user_input,
|
| 231 |
"water_ml": impact["water_ml"],
|
| 232 |
"energy_wh": impact["energy_wh"],
|
| 233 |
-
"
|
|
|
|
| 234 |
})
|
| 235 |
|
| 236 |
stats_ui = get_stats_html(state["water"], state["energy"], state["co2"], state["points"])
|
|
@@ -239,16 +281,14 @@ def process_query(user_input, selected_model, state):
|
|
| 239 |
audio_path = generate_audio(dialogue)
|
| 240 |
feedback_text = f"<div class='feedback-box'>π§ <strong>{category.upper()}</strong> Detected on {selected_model}!<br><br><em>\"{dialogue}\"</em></div>"
|
| 241 |
|
| 242 |
-
# Check for Win/Loss
|
| 243 |
if state["points"] >= 500 or state["water"] <= 0:
|
| 244 |
state["game_over"] = True
|
| 245 |
victory_html = generate_victory_dashboard(state)
|
| 246 |
-
# Hide main game, Show victory screen
|
| 247 |
return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(), gr.update(),
|
| 248 |
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(value=""),
|
| 249 |
gr.update(visible=False), gr.update(visible=True), gr.update(value=victory_html))
|
| 250 |
|
| 251 |
-
# Standard Return
|
| 252 |
return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(value=feedback_text), gr.update(visible=show_alts),
|
| 253 |
gr.update(value=alt_choices[0]), gr.update(value=alt_choices[1]), gr.update(value=alt_choices[2]), gr.update(value=""), gr.update(value=""),
|
| 254 |
gr.update(visible=True), gr.update(visible=False), gr.update())
|
|
@@ -257,7 +297,6 @@ def select_alternative(choice_text, state):
|
|
| 257 |
if state["game_over"] or not state.get("current_best_alt"):
|
| 258 |
return state, gr.update(), gr.update(), gr.update(), gr.update(visible=True), gr.update(visible=False), gr.update()
|
| 259 |
|
| 260 |
-
# Extract just the name from the formatted button text (second line)
|
| 261 |
clean_choice = choice_text.split("\n")[1].strip()
|
| 262 |
selected_dict = next((item for item in state["current_shuffled_alts"] if item["text"] == clean_choice), None)
|
| 263 |
|
|
@@ -269,7 +308,7 @@ def select_alternative(choice_text, state):
|
|
| 269 |
|
| 270 |
stats_ui = get_stats_html(state["water"], state["energy"], state["co2"], state["points"])
|
| 271 |
|
| 272 |
-
# Check for win
|
| 273 |
if state["points"] >= 500:
|
| 274 |
state["game_over"] = True
|
| 275 |
victory_html = generate_victory_dashboard(state)
|
|
@@ -277,7 +316,6 @@ def select_alternative(choice_text, state):
|
|
| 277 |
|
| 278 |
return state, stats_ui, gr.update(value=msg), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update()
|
| 279 |
|
| 280 |
-
|
| 281 |
custom_css = """
|
| 282 |
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700&display=swap');
|
| 283 |
body, .gradio-container { background-color: #0B1120 !important; font-family: 'Outfit', sans-serif !important; color: #e2e8f0 !important; }
|
|
@@ -371,13 +409,14 @@ with gr.Blocks(title="EcoQueryQuest") as demo:
|
|
| 371 |
with gr.Column(visible=False) as victory_ui:
|
| 372 |
victory_display = gr.HTML()
|
| 373 |
|
| 374 |
-
#
|
| 375 |
submit_btn.click(
|
| 376 |
fn=process_query,
|
| 377 |
inputs=[user_input, model_selector, game_state],
|
| 378 |
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]
|
| 379 |
)
|
| 380 |
|
|
|
|
| 381 |
for btn in [alt_btn_1, alt_btn_2, alt_btn_3]:
|
| 382 |
btn.click(
|
| 383 |
fn=select_alternative,
|
|
|
|
| 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"""
|
| 171 |
+
<tr style="border-bottom: 1px solid rgba(255,255,255,0.1); background: rgba(0,0,0,0.2);">
|
| 172 |
+
<td style="padding: 15px; font-style: italic;">"{item['query']}"</td>
|
| 173 |
+
<td style="padding: 15px; color: #fca5a5;">{item['water_ml']:.1f}mL / {item['energy_wh']:.2f}Wh / {item['co2_g']:.2f}g</td>
|
| 174 |
+
<td style="padding: 15px;">{alt_display}</td>
|
| 175 |
+
<td style="padding: 15px; color: #60a5fa; font-weight: bold;">{saved_w:.1f}mL / {saved_e:.2f}Wh / {saved_c:.2f}g</td>
|
| 176 |
</tr>
|
| 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>
|
|
|
|
| 235 |
|
| 236 |
def process_query(user_input, selected_model, state):
|
| 237 |
if state["game_over"] or not user_input.strip():
|
|
|
|
| 238 |
return [state, gr.update()] + [gr.update()]*10 + [gr.update(visible=True), gr.update(visible=False), gr.update()]
|
| 239 |
|
| 240 |
result = classifier(user_input, CATEGORIES)
|
|
|
|
| 250 |
|
| 251 |
show_alts = False
|
| 252 |
alt_choices = ["", "", ""]
|
| 253 |
+
best_alt_name = "None (Justified Use)"
|
| 254 |
|
| 255 |
if category == "complex research query":
|
| 256 |
state["points"] += 50
|
|
|
|
| 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"],
|
| 273 |
"energy_wh": impact["energy_wh"],
|
| 274 |
+
"co2_g": impact["co2_g"],
|
| 275 |
+
"alt_name": best_alt_name
|
| 276 |
})
|
| 277 |
|
| 278 |
stats_ui = get_stats_html(state["water"], state["energy"], state["co2"], state["points"])
|
|
|
|
| 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)
|
|
|
|
| 288 |
return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(), gr.update(),
|
| 289 |
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(value=""),
|
| 290 |
gr.update(visible=False), gr.update(visible=True), gr.update(value=victory_html))
|
| 291 |
|
|
|
|
| 292 |
return (state, stats_ui, drip_ui, audio_path, impact_ui, gr.update(value=feedback_text), gr.update(visible=show_alts),
|
| 293 |
gr.update(value=alt_choices[0]), gr.update(value=alt_choices[1]), gr.update(value=alt_choices[2]), gr.update(value=""), gr.update(value=""),
|
| 294 |
gr.update(visible=True), gr.update(visible=False), gr.update())
|
|
|
|
| 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 |
|
|
|
|
| 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)
|
|
|
|
| 316 |
|
| 317 |
return state, stats_ui, gr.update(value=msg), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update()
|
| 318 |
|
|
|
|
| 319 |
custom_css = """
|
| 320 |
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;500;700&display=swap');
|
| 321 |
body, .gradio-container { background-color: #0B1120 !important; font-family: 'Outfit', sans-serif !important; color: #e2e8f0 !important; }
|
|
|
|
| 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,
|