page3 / app.py
RushiMane2003's picture
Update app.py
6603da6 verified
from flask import Flask, render_template, session, redirect, url_for, request
import time
import os
import logging
from werkzeug.middleware.proxy_fix import ProxyFix
# ----------------------------------------------------
# 1. Logging Setup (Your code is perfect)
# ----------------------------------------------------
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# ----------------------------------------------------
# 2. Flask App Initialization (WITH THE FIXES)
# ----------------------------------------------------
app = Flask(__name__)
# A. SECRET_KEY setup (Your logic is fine, just made the error message more explicit)
app.secret_key = os.environ.get('SECRET_KEY')
if not app.secret_key:
logging.error("FATAL: SECRET_KEY environment variable is not set. Sessions will fail.")
app.secret_key = 'fallback-key-for-dev-only-not-secure'
logging.warning("⚠️ Using insecure fallback secret key. Set SECRET_KEY in production.")
# B. ProxyFix (Enhanced for robustness on Hugging Face)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=2, x_proto=1, x_host=1, x_prefix=1)
# C. Secure cookie must be true
app.config['SESSION_COOKIE_SECURE'] = True
# D. *** THE CRITICAL ONE-SHOT FIX ***
# Changed from 'Lax' to 'None' to allow the session to work inside the Hugging Face iframe.
app.config['SESSION_COOKIE_SAMESITE'] = 'None'
logging.info("✅ Flask App Initialized with FINAL Production Settings for iframe environments.")
# ----------------------------------------------------
# 3. Game Content (Your code is perfect)
# ----------------------------------------------------
videos = [
"static/videos/Animated_Drought_Relief_Video_Creation.mp4",
"static/videos/Animated_Rainwater_Harvesting_Video.mp4",
"static/videos/Animated_Water_Filtration_Process_Video.mp4",
"static/videos/Water_Filtration_Animation_Ready.mp4",
"static/videos/Animated_Rainwater_Usage_Video.mp4",
"static/videos/Water_Hero_Video_Generation_Complete.mp4"
]
video_descriptions = [
"🌍 Water Crisis Alert", "🏠 Collection Master", "💧 Purification Expert",
"🗃️ Storage Specialist", "♻️ Usage Strategist", "🌱 Environmental Champion"
]
task_scenarios = [
{"question": "🌍 After watching the video, what is the FIRST step to address water scarcity at your home?",
"choices": [
{"action": "🌧️ Start collecting rainwater immediately", "description": "Begin harvesting nature's free water supply", "consequence": "✅ SMART START! You're taking the first step toward water independence! +100 XP", "xp_reward": 100, "icon": "🏆"},
{"action": "🚿 Take longer showers to enjoy water while it lasts", "description": "Use more water before it runs out", "consequence": "❌ WRONG APPROACH! This worsens the problem. Conservation is key! -20 Health", "xp_reward": 0, "icon": "💸"},
{"action": "⏳ Wait for government to solve the problem", "description": "Rely on authorities to fix water issues", "consequence": "❌ MISSED OPPORTUNITY! Individual action is crucial. Start now! -20 Health", "xp_reward": 0, "icon": "⏰"}
]},
{"question": "🌧️ It's raining heavily! Your house has a metal roof. What's your FIRST action as a Water Conservation Hero?",
"choices": [
{"action": "🏠 Install gutters and downspouts on your roof", "description": "Channel rainwater efficiently into collection system", "consequence": "✅ SMART MOVE! You capture 80% of the rainfall. +100 XP", "xp_reward": 100, "icon": "🏆"},
{"action": "🛣️ Let the water flow down the streets", "description": "Allow natural drainage", "consequence": "❌ MISSED OPPORTUNITY! Thousands of liters wasted. -20 Health", "xp_reward": 0, "icon": "💸"},
{"action": "🛍️ Place plastic bags under the roof edge", "description": "Use bags to catch water", "consequence": "❌ INEFFICIENT! Bags tear easily. -20 Health", "xp_reward": 0, "icon": "🗑️"}
]},
{"question": "💧 Your collection tank is filling up with rainwater, but you notice leaves and debris. What's your next step?",
"choices": [
{"action": "🔍 Install a first-flush diverter and filtration system", "description": "Remove initial dirty water", "consequence": "✅ EXCELLENT CHOICE! Clean water ready. +100 XP", "xp_reward": 100, "icon": "🧪"},
{"action": "⚠️ Use dirty water directly", "description": "Proceed with unfiltered water", "consequence": "❌ HEALTH HAZARD! Contamination risk. -20 Health", "xp_reward": 0, "icon": "☠️"},
{"action": "🧪 Add household bleach", "description": "Chemical treatment", "consequence": "❌ WRONG CHEMICAL! Unsafe for water. -20 Health", "xp_reward": 0, "icon": "⚗️"}
]},
{"question": "🏺 You have 500 liters of clean rainwater. Where should you store it?",
"choices": [
{"action": "🏺 Underground concrete tank with cover", "description": "Safe long-term storage", "consequence": "✅ MASTER STRATEGY! Stored safely. +100 XP", "xp_reward": 100, "icon": "🏛️"},
{"action": "🪣 Store in open buckets", "description": "Easy access containers", "consequence": "❌ BREEDING GROUND! Mosquito risk. -20 Health", "xp_reward": 0, "icon": "🦟"},
{"action": "🌍 Dig a pit and let water sit", "description": "Natural storage", "consequence": "❌ CONTAMINATION RISK! Polluted. -20 Health", "xp_reward": 0, "icon": "🳳️"}
]},
{"question": "♻️ Dry season! You have 200L left. Neighbor needs help. What do you do?",
"choices": [
{"action": "🌿 Use for drip irrigation and toilet flushing", "description": "Strategic usage", "consequence": "✅ WATER WISDOM! Saved 300L. +100 XP", "xp_reward": 100, "icon": "🌱"},
{"action": "⏰ Save all water", "description": "Conservative approach", "consequence": "❌ MISSED IMPACT! Water can spoil. -20 Health", "xp_reward": 0, "icon": "⏰"},
{"action": "🚽 Mix with sewage", "description": "Combine with waste", "consequence": "❌ TERRIBLE WASTE! Never mix. -20 Health", "xp_reward": 0, "icon": "🤮"}
]},
{"question": "🌱 How will you inspire your community?",
"choices": [
{"action": "👥 Organize workshops", "description": "Teach others", "consequence": "✅ COMMUNITY HERO! Inspired 50 families. +100 XP", "xp_reward": 100, "icon": "🌟"},
{"action": "🤐 Keep it to yourself", "description": "Exclusive access", "consequence": "❌ SELFISH! Collective action needed. -20 Health", "xp_reward": 0, "icon": "🚫"},
{"action": "📱 Post online occasionally", "description": "Minimal effort", "consequence": "❌ MINIMAL IMPACT! Real change needs more. -20 Health", "xp_reward": 0, "icon": "📱"}
]}
]
achievements_list = [
{"name": "🌟 First Steps", "desc": "Started your water journey", "condition": "start"},
{"name": "💧 Drop Collector", "desc": "Learned about collection", "condition": "video_1"},
{"name": "🔬 Purification Pro", "desc": "Mastered filtration", "condition": "video_2"},
{"name": "🏺 Storage Sage", "desc": "Understood storage methods", "condition": "video_3"},
{"name": "♻️ Usage Expert", "desc": "Optimized water usage", "condition": "video_4"},
{"name": "🎯 Perfect Score", "desc": "100% accuracy achieved", "condition": "perfect"},
{"name": "🔥 On Fire", "desc": "3 correct answers in a row", "condition": "streak_3"},
{"name": "🌍 Water Hero", "desc": "Completed the full quest", "condition": "complete"}
]
# ----------------------------------------------------
# 4. Game Logic (Your code is perfect)
# ----------------------------------------------------
def calculate_level():
return min(10, 1 + session.get('xp_points', 0) // 100)
def add_xp(amount: int):
if 'xp_points' not in session:
resume_or_initialize()
old_level = session.get('player_level', 1)
session['xp_points'] = session.get('xp_points', 0) + amount
session['player_level'] = calculate_level()
if session['player_level'] > old_level:
session['message'] = f"🎉 LEVEL UP! You reached Level {session['player_level']}!"
def unlock_achievement(condition: str):
if 'achievements' not in session:
resume_or_initialize()
for a in achievements_list:
if a["condition"] == condition and a not in session['achievements']:
# Use append to modify the list in place
session['achievements'].append(a)
session.modified = True # Mark session as modified
session['message'] = f"🏆 Achievement Unlocked: {a['name']} - {a['desc']}"
add_xp(50)
def reset_game_state():
session.clear() # Use clear for a full reset
session["video_index"] = 0
session["feedback"] = ""
session["quiz_correct_count"] = 0
session["quiz_attempts"] = 0
session["player_level"] = 1
session["xp_points"] = 0
session["achievements"] = []
session["streak"] = 0
session["health"] = 100
session["video_watched"] = False
session["question_answered"] = False
session["message"] = ""
def resume_or_initialize():
if "player_level" not in session:
logging.info("🔁 No active session found. Initializing new game state...")
reset_game_state()
def next_video_logic():
if session['video_index'] < len(videos) - 1:
session['video_index'] += 1
session['feedback'] = ""
session['video_watched'] = False
session['question_answered'] = False
session['message'] = ""
if session['video_index'] > 0:
unlock_achievement(f"video_{session['video_index']}")
return redirect(url_for('main_app'))
else:
unlock_achievement("complete")
return redirect(url_for('summary_page'))
def select_card_logic(choice_index: int):
current_scenario = task_scenarios[session['video_index']]
choice = current_scenario["choices"][choice_index]
is_correct = choice["xp_reward"] > 0
session['quiz_attempts'] += 1
session['question_answered'] = True
session['feedback'] = choice["consequence"]
session['message'] = ""
if is_correct:
session['quiz_correct_count'] += 1
session['streak'] += 1
add_xp(choice["xp_reward"])
if session['streak'] >= 3:
unlock_achievement("streak_3")
else:
session['streak'] = 0
session['health'] = max(0, session['health'] - 20)
# ----------------------------------------------------
# 5. Flask Routes (Your code is perfect)
# ----------------------------------------------------
@app.route('/')
def welcome_page():
logging.info("ROUTE: / [GET] - Rendering welcome page.")
return render_template('welcome.html')
@app.route('/begin_quest', methods=['POST'])
def begin_quest():
logging.info("ROUTE: /begin_quest [POST] - Quest beginning.")
reset_game_state()
unlock_achievement("start")
logging.info(f"✅ Session after init: {dict(session)}")
return redirect(url_for('main_app'))
@app.route('/main', methods=['GET', 'POST'])
def main_app():
resume_or_initialize()
if request.method == 'POST':
logging.info("ROUTE: /main [POST] - Received POST request. Session is present.")
if 'mark_watched' in request.form:
logging.info("Video marked as watched.")
session['video_watched'] = True
session['message'] = ""
elif 'select_choice' in request.form:
select_card_logic(int(request.form['select_choice']))
elif 'next_level' in request.form or 'continue_quest' in request.form:
return next_video_logic()
elif 'replay_video' in request.form:
session['feedback'] = ""
session['video_watched'] = False
session['question_answered'] = False
session['message'] = "🔄 Video ready for replay!"
elif 'main_menu' in request.form:
return redirect(url_for('welcome_page'))
return redirect(url_for('main_app'))
idx = session['video_index']
context = {
'current_video_index': idx, 'total_videos': len(videos),
'video_src': url_for('static', filename=videos[idx].replace('static/', '', 1)),
'video_description': video_descriptions[idx], 'current_scenario': task_scenarios[idx],
'player_level': session['player_level'], 'xp_points': session['xp_points'],
'health': session['health'], 'streak': session['streak'],
'quiz_correct_count': session['quiz_correct_count'], 'quiz_attempts': session['quiz_attempts'],
'video_watched': session['video_watched'], 'question_answered': session['question_answered'],
'feedback': session['feedback'], 'achievements': session['achievements'],
'message': session.pop('message', '')
}
return render_template('main.html', **context)
@app.route('/summary')
def summary_page():
resume_or_initialize()
total_quizzes = len(task_scenarios)
score = session.get('quiz_correct_count', 0)
if score == total_quizzes and total_quizzes > 0:
unlock_achievement("perfect")
context = {
'player_level': session['player_level'], 'xp_points': session['xp_points'],
'quiz_score': score, 'total_quizzes': total_quizzes,
'accuracy': (score / max(1, session['quiz_attempts'])) * 100,
'achievements': session['achievements'], 'current_date': time.strftime("%B %d, %Y"),
'message': session.pop('message', '')
}
return render_template('summary.html', **context)
@app.route('/restart_quest', methods=['POST'])
def restart_quest():
reset_game_state()
return redirect(url_for('welcome_page'))
# ----------------------------------------------------
# 6. Run App (Your code is perfect)
# ----------------------------------------------------
if __name__ == '__main__':
app.run(debug=True, port=5000)