Spaces:
Sleeping
Sleeping
vighnesh-shetty-vs commited on
Commit Β·
88d4a8f
1
Parent(s): f55bc01
Add updated files
Browse files- app.py +235 -30
- requirements.txt +2 -1
app.py
CHANGED
|
@@ -1,13 +1,18 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
from transformers import pipeline
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
from game_data import calculate_impact
|
|
|
|
|
|
|
| 4 |
|
| 5 |
-
#
|
| 6 |
-
# (This runs server-side and uses the free CPU tier effectively)
|
| 7 |
print("Loading classification model (facebook/bart-large-mnli)...")
|
| 8 |
classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
|
| 9 |
|
| 10 |
-
# Predefined categories mapping to your zero-shot labels
|
| 11 |
CATEGORIES = [
|
| 12 |
"simple factual question",
|
| 13 |
"mathematical calculation",
|
|
@@ -15,43 +20,243 @@ CATEGORIES = [
|
|
| 15 |
"complex research query"
|
| 16 |
]
|
| 17 |
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
"""
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
"""
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
impact = calculate_impact(category, confidence, user_input)
|
| 33 |
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
)
|
| 40 |
-
return result_text
|
| 41 |
|
| 42 |
-
#
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
-
|
| 51 |
-
|
| 52 |
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
-
# Launch the app
|
| 56 |
if __name__ == "__main__":
|
| 57 |
demo.launch()
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
from transformers import pipeline
|
| 3 |
+
import random
|
| 4 |
+
from gtts import gTTS
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
# Import your local modules (Ensure game_data.py, dialogues.py, alternatives.py exist in the same folder)
|
| 8 |
from game_data import calculate_impact
|
| 9 |
+
from dialogues import get_dialogue
|
| 10 |
+
from alternatives import ALTERNATIVES
|
| 11 |
|
| 12 |
+
# --- 1. Load AI Models ---
|
|
|
|
| 13 |
print("Loading classification model (facebook/bart-large-mnli)...")
|
| 14 |
classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
|
| 15 |
|
|
|
|
| 16 |
CATEGORIES = [
|
| 17 |
"simple factual question",
|
| 18 |
"mathematical calculation",
|
|
|
|
| 20 |
"complex research query"
|
| 21 |
]
|
| 22 |
|
| 23 |
+
# --- 2. Helper Functions & UI Generators ---
|
| 24 |
+
|
| 25 |
+
def generate_audio(text):
|
| 26 |
+
"""Generates instant TTS audio using gTTS to prevent CPU timeouts."""
|
| 27 |
+
tts = gTTS(text, lang='en')
|
| 28 |
+
filepath = "temp_drip_voice.mp3"
|
| 29 |
+
tts.save(filepath)
|
| 30 |
+
return filepath
|
| 31 |
+
|
| 32 |
+
def get_drip_visuals(water_level):
|
| 33 |
+
"""Generates the CSS/HTML for Drip based on dehydration."""
|
| 34 |
+
if water_level > 70:
|
| 35 |
+
emoji, size, animation = "π§", "80px", "bounce 2s infinite"
|
| 36 |
+
status = "Plump & Hydrated"
|
| 37 |
+
elif 30 <= water_level <= 70:
|
| 38 |
+
emoji, size, animation = "π§", "60px", "none"
|
| 39 |
+
status = "Shrinking & Tired"
|
| 40 |
+
elif water_level > 0:
|
| 41 |
+
emoji, size, animation = "ποΈ", "40px", "none"
|
| 42 |
+
status = "Cracked & Raspy"
|
| 43 |
+
else:
|
| 44 |
+
emoji, size, animation = "π¨", "30px", "none"
|
| 45 |
+
status = "Evaporated!"
|
| 46 |
+
|
| 47 |
+
return f"""
|
| 48 |
+
<div style="text-align: center; margin-bottom: 20px;">
|
| 49 |
+
<div style="font-size: {size}; animation: {animation}; transition: all 0.5s;">{emoji}</div>
|
| 50 |
+
<h3 style="margin: 0;">Drip Status: {status}</h3>
|
| 51 |
+
</div>
|
| 52 |
"""
|
| 53 |
+
|
| 54 |
+
def get_impact_cards(impact, category):
|
| 55 |
+
"""Generates side-by-side comparison cards."""
|
| 56 |
+
# Relatable translations
|
| 57 |
+
water_trans = f"{impact['water']}L is like leaving a tap running for {int(impact['water']*12)} seconds."
|
| 58 |
+
if impact['water'] >= 5:
|
| 59 |
+
water_trans = f"{impact['water']}L = A whole day's drinking water for a family."
|
| 60 |
+
|
| 61 |
+
energy_trans = f"{impact['energy']}kWh could charge your phone {int(impact['energy']*100)} times."
|
| 62 |
+
if impact['energy'] >= 0.5:
|
| 63 |
+
energy_trans = f"{impact['energy']}kWh = Powering a fridge for several hours."
|
| 64 |
+
|
| 65 |
+
return f"""
|
| 66 |
+
<div style="display: flex; gap: 20px; justify-content: center; margin-top: 20px;">
|
| 67 |
+
<div style="flex: 1; padding: 15px; background: #ffebee; border-left: 5px solid #f44336; border-radius: 5px;">
|
| 68 |
+
<h3 style="color: #c62828; margin-top: 0;">LLM Impact (Massive Servers)</h3>
|
| 69 |
+
<p><strong>Water Wasted:</strong> {impact['water']}L</p>
|
| 70 |
+
<p><strong>Energy Wasted:</strong> {impact['energy']}kWh</p>
|
| 71 |
+
<p><em>{water_trans}</em></p>
|
| 72 |
+
<p><em>{energy_trans}</em></p>
|
| 73 |
+
</div>
|
| 74 |
+
<div style="flex: 1; padding: 15px; background: #e8f5e9; border-left: 5px solid #4caf50; border-radius: 5px;">
|
| 75 |
+
<h3 style="color: #2e7d32; margin-top: 0;">Eco-Alternative (Local/Search)</h3>
|
| 76 |
+
<p><strong>Water Wasted:</strong> ~0.0L</p>
|
| 77 |
+
<p><strong>Energy Wasted:</strong> ~0.001kWh</p>
|
| 78 |
+
<p><em>Save the planet, use appropriate tools!</em></p>
|
| 79 |
+
</div>
|
| 80 |
+
</div>
|
| 81 |
"""
|
| 82 |
+
|
| 83 |
+
def generate_report(state):
|
| 84 |
+
"""Generates the final game over report."""
|
| 85 |
+
badges = []
|
| 86 |
+
if state['water'] > 50: badges.append("π Water Warrior")
|
| 87 |
+
if state['eco_score'] >= 80: badges.append("πΏ Conscious Querier")
|
| 88 |
+
if not badges: badges.append("π₯ Resource Drainer")
|
| 89 |
|
| 90 |
+
return f"""
|
| 91 |
+
<div style="background: #2c3e50; color: white; padding: 30px; border-radius: 10px; text-align: center;">
|
| 92 |
+
<h1>Game Over! Here is your AI Audit.</h1>
|
| 93 |
+
<h2>Final Score: {state['points']} Points</h2>
|
| 94 |
+
<p>You asked {state['queries']} queries.</p>
|
| 95 |
+
<p><strong>Total Water Drained:</strong> {100 - state['water']:.2f}L</p>
|
| 96 |
+
<p><strong>Total Energy Consumed:</strong> {state['energy']:.3f}kWh</p>
|
| 97 |
+
<p><strong>Eco-Score:</strong> {state['eco_score']:.1f}%</p>
|
| 98 |
+
<h3>Badges Earned:</h3>
|
| 99 |
+
<h2>{' | '.join(badges)}</h2>
|
| 100 |
+
<p style="margin-top: 20px; font-size: 0.9em;"><em>Tip: Match the tool to the task. Don't use a supercomputer to ask for a recipe! Review the UNESCO guidelines on proportional AI usage.</em></p>
|
| 101 |
+
</div>
|
| 102 |
+
"""
|
| 103 |
|
| 104 |
+
# --- 3. Core Game Logic ---
|
| 105 |
+
|
| 106 |
+
def process_query(user_input, state):
|
| 107 |
+
if state["game_over"] or not user_input.strip():
|
| 108 |
+
return state, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(visible=False), gr.update(visible=False)
|
| 109 |
+
|
| 110 |
+
# 1. Classification & Impact Calculation
|
| 111 |
+
result = classifier(user_input, CATEGORIES)
|
| 112 |
+
category = result['labels'][0]
|
| 113 |
+
confidence = result['scores'][0]
|
| 114 |
+
|
| 115 |
impact = calculate_impact(category, confidence, user_input)
|
| 116 |
|
| 117 |
+
# 2. Update Basic State
|
| 118 |
+
state["queries"] += 1
|
| 119 |
+
state["water"] = max(0, state["water"] - impact["water"])
|
| 120 |
+
state["energy"] += impact["energy"]
|
| 121 |
+
state["history"].append(category)
|
|
|
|
|
|
|
| 122 |
|
| 123 |
+
# 3. Category Specific Logic (Points & Alternatives)
|
| 124 |
+
show_alts = False
|
| 125 |
+
alt_choices = []
|
| 126 |
+
correct_alt = None
|
| 127 |
|
| 128 |
+
if category == "complex research query":
|
| 129 |
+
# Justified use: +50 points, no alternatives needed
|
| 130 |
+
state["points"] += 50
|
| 131 |
+
dialogue = "Finally, a real question! This is what my servers were built for. Draining, but worth it."
|
| 132 |
+
else:
|
| 133 |
+
# Unjustified/Avoidable: Fetch alternatives
|
| 134 |
+
show_alts = True
|
| 135 |
+
alt_choices = ALTERNATIVES.get(category, ["Google", "Wikipedia", "Book"])
|
| 136 |
+
correct_alt = alt_choices[0] # For MVP, the first item in the list is the "best" one
|
| 137 |
+
random.shuffle(alt_choices) # Shuffle so it's not always button 1
|
| 138 |
+
state["current_best_alt"] = correct_alt
|
| 139 |
+
|
| 140 |
+
# Get sarcastic Drip dialogue based on water level
|
| 141 |
+
dialogue = get_dialogue(state["water"], category)
|
| 142 |
+
|
| 143 |
+
# 4. Generate outputs
|
| 144 |
+
drip_ui = get_drip_visuals(state["water"])
|
| 145 |
+
impact_ui = get_impact_cards(impact, category)
|
| 146 |
+
audio_path = generate_audio(dialogue)
|
| 147 |
+
|
| 148 |
+
# Check Win/Loss
|
| 149 |
+
if state["points"] >= 500 or state["water"] <= 0:
|
| 150 |
+
state["game_over"] = True
|
| 151 |
+
return (state, drip_ui, gr.update(value=state["water"]), gr.update(value=f"{state['energy']:.3f} kWh"),
|
| 152 |
+
generate_report(state), gr.update(visible=False), audio_path, gr.update(visible=False), gr.update(visible=False))
|
| 153 |
+
|
| 154 |
+
# Return updated UI components
|
| 155 |
+
if show_alts:
|
| 156 |
+
return (state, drip_ui, gr.update(value=state["water"]), gr.update(value=f"{state['energy']:.3f} kWh"),
|
| 157 |
+
impact_ui, gr.update(value=f"**{category.upper()}** Detected! {dialogue}"), audio_path,
|
| 158 |
+
gr.update(visible=True), gr.update(value=alt_choices[0]), gr.update(value=alt_choices[1]), gr.update(value=alt_choices[2]))
|
| 159 |
+
else:
|
| 160 |
+
return (state, drip_ui, gr.update(value=state["water"]), gr.update(value=f"{state['energy']:.3f} kWh"),
|
| 161 |
+
impact_ui, gr.update(value=f"**{category.upper()}** Detected! {dialogue}"), audio_path,
|
| 162 |
+
gr.update(visible=False), gr.update(), gr.update(), gr.update())
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
def select_alternative(choice, state):
|
| 166 |
+
"""Handles logic when a user clicks an Eco-Alternative button."""
|
| 167 |
+
if state["game_over"] or not state.get("current_best_alt"):
|
| 168 |
+
return state, gr.update()
|
| 169 |
+
|
| 170 |
+
msg = ""
|
| 171 |
+
if choice == state["current_best_alt"]:
|
| 172 |
+
state["points"] += 10
|
| 173 |
+
state["eco_choices"] += 1
|
| 174 |
+
msg = "β
**Great choice!** You earned +10 Eco Points for picking the right tool for the job."
|
| 175 |
+
else:
|
| 176 |
+
msg = "β **Not quite.** That works, but there was a better eco-friendly option. Still better than an LLM though!"
|
| 177 |
|
| 178 |
+
# Update Eco-Score
|
| 179 |
+
state["eco_score"] = (state["eco_choices"] / state["queries"]) * 100 if state["queries"] > 0 else 0
|
| 180 |
|
| 181 |
+
# Hide alternatives after selection
|
| 182 |
+
return state, gr.update(value=msg), gr.update(visible=False)
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
# --- 4. Gradio Interface Layout ---
|
| 186 |
+
|
| 187 |
+
custom_css = """
|
| 188 |
+
.gradio-container { max-width: 800px !important; margin: auto; }
|
| 189 |
+
.progress-bar-container { background: #e0e0e0; border-radius: 10px; height: 30px; width: 100%; overflow: hidden; margin-top: 5px; }
|
| 190 |
+
.progress-bar { background: #2196f3; height: 100%; transition: width 0.5s ease-in-out; }
|
| 191 |
+
"""
|
| 192 |
+
|
| 193 |
+
with gr.Blocks(css=custom_css, title="EcoQueryQuest") as demo:
|
| 194 |
+
|
| 195 |
+
# Initialize Game State
|
| 196 |
+
game_state = gr.State({
|
| 197 |
+
"water": 100.0, "energy": 0.0, "points": 0, "queries": 0,
|
| 198 |
+
"eco_choices": 0, "eco_score": 0.0, "history": [], "game_over": False,
|
| 199 |
+
"current_best_alt": None
|
| 200 |
+
})
|
| 201 |
+
|
| 202 |
+
gr.Markdown("# π EcoQueryQuest")
|
| 203 |
+
gr.Markdown("Type your query below. Watch Drip (π§) react to the environmental cost of your prompt! Reach 500 points to win, but don't run out of water.")
|
| 204 |
+
|
| 205 |
+
# TOP SECTION: Visuals & Trackers
|
| 206 |
+
with gr.Row():
|
| 207 |
+
with gr.Column(scale=1):
|
| 208 |
+
drip_html = gr.HTML(get_drip_visuals(100))
|
| 209 |
+
with gr.Column(scale=2):
|
| 210 |
+
gr.Markdown("### π° Water Tank (100L Limit)")
|
| 211 |
+
water_slider = gr.Slider(minimum=0, maximum=100, value=100, interactive=False, show_label=False)
|
| 212 |
+
gr.Markdown("### β‘ Energy Wasted")
|
| 213 |
+
energy_text = gr.Textbox(value="0.000 kWh", interactive=False, show_label=False)
|
| 214 |
+
gr.Markdown("### π Points")
|
| 215 |
+
points_text = gr.Textbox(value="0", interactive=False, show_label=False)
|
| 216 |
+
|
| 217 |
+
# MIDDLE SECTION: Interaction
|
| 218 |
+
with gr.Group() as interaction_group:
|
| 219 |
+
user_input = gr.Textbox(label="Ask an AI a question...", placeholder="e.g., What is 25 * 42? or Write me a poem about dogs.")
|
| 220 |
+
submit_btn = gr.Button("Send Query", variant="primary")
|
| 221 |
+
|
| 222 |
+
main_display_html = gr.HTML()
|
| 223 |
+
drip_dialogue_text = gr.Markdown()
|
| 224 |
+
drip_audio = gr.Audio(label="Drip's Reaction", autoplay=True, interactive=False)
|
| 225 |
+
|
| 226 |
+
# BOTTOM SECTION: Alternatives (Hidden by default)
|
| 227 |
+
with gr.Group(visible=False) as alternatives_group:
|
| 228 |
+
gr.Markdown("### β³ Drip says: 'Choose a better alternative to save me!'")
|
| 229 |
+
with gr.Row():
|
| 230 |
+
alt_btn_1 = gr.Button("Alt 1")
|
| 231 |
+
alt_btn_2 = gr.Button("Alt 2")
|
| 232 |
+
alt_btn_3 = gr.Button("Alt 3")
|
| 233 |
+
alt_feedback = gr.Markdown()
|
| 234 |
+
|
| 235 |
+
# EVENT WIRING
|
| 236 |
+
|
| 237 |
+
# 1. Submit Query
|
| 238 |
+
submit_btn.click(
|
| 239 |
+
fn=process_query,
|
| 240 |
+
inputs=[user_input, game_state],
|
| 241 |
+
outputs=[game_state, drip_html, water_slider, energy_text, main_display_html, drip_dialogue_text, drip_audio, alternatives_group, alt_btn_1, alt_btn_2, alt_btn_3]
|
| 242 |
+
).then(
|
| 243 |
+
fn=lambda s: gr.update(value=str(s["points"])), # Update points UI after processing
|
| 244 |
+
inputs=[game_state],
|
| 245 |
+
outputs=[points_text]
|
| 246 |
+
)
|
| 247 |
+
|
| 248 |
+
# 2. Click Alternative Buttons
|
| 249 |
+
for btn in [alt_btn_1, alt_btn_2, alt_btn_3]:
|
| 250 |
+
btn.click(
|
| 251 |
+
fn=select_alternative,
|
| 252 |
+
inputs=[btn, game_state],
|
| 253 |
+
outputs=[game_state, alt_feedback, alternatives_group]
|
| 254 |
+
).then(
|
| 255 |
+
fn=lambda s: gr.update(value=str(s["points"])), # Update points UI after clicking alternative
|
| 256 |
+
inputs=[game_state],
|
| 257 |
+
outputs=[points_text]
|
| 258 |
+
)
|
| 259 |
|
| 260 |
+
# Launch the app
|
| 261 |
if __name__ == "__main__":
|
| 262 |
demo.launch()
|
requirements.txt
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
gradio
|
| 2 |
transformers
|
| 3 |
torch
|
| 4 |
-
Pillow
|
|
|
|
|
|
| 1 |
gradio
|
| 2 |
transformers
|
| 3 |
torch
|
| 4 |
+
Pillow
|
| 5 |
+
gTTS
|