Spaces:
Sleeping
Sleeping
| from flask import Flask, render_template, request, redirect, url_for, flash, jsonify | |
| from flask_sqlalchemy import SQLAlchemy | |
| from flask_login import LoginManager, login_user, login_required, logout_user, current_user | |
| from werkzeug.security import generate_password_hash, check_password_hash | |
| from models import db, User | |
| import os | |
| import google.generativeai as genai | |
| app = Flask(__name__) | |
| app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'your_secret_key_here') | |
| # Use absolute path for database | |
| basedir = os.path.abspath(os.path.dirname(__file__)) | |
| instance_path = os.path.join(basedir, 'instance') | |
| if not os.path.exists(instance_path): | |
| os.makedirs(instance_path) | |
| db_path = os.path.join(instance_path, 'tarist.db') | |
| app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///' + db_path) | |
| app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False | |
| app.config['GOOGLE_API_KEY'] = os.environ.get('GOOGLE_API_KEY', 'placeholder_key') | |
| # Configure AI | |
| genai.configure(api_key=app.config['GOOGLE_API_KEY']) | |
| db.init_app(app) | |
| try: | |
| with app.app_context(): | |
| db.create_all() | |
| except Exception as e: | |
| print(f"Error creating database: {e}") | |
| login_manager = LoginManager() | |
| login_manager.login_view = 'login' | |
| login_manager.init_app(app) | |
| def load_user(user_id): | |
| return User.query.get(int(user_id)) | |
| # --- Routes --- | |
| def home(): | |
| return render_template('new 1.html') | |
| def explore(): | |
| return render_template('explore.html', experiences=experiences_data) | |
| def dashboard(): | |
| # Mock data for demonstration | |
| trips = [1] # Simulating one planned trip | |
| return render_template('dashboard.html', trips=trips) | |
| def how_it_works(): | |
| return render_template('how_it_works.html') | |
| def about(): | |
| return render_template('about.html') | |
| # --- Data --- | |
| experiences_data = [ | |
| { | |
| "id": 1, | |
| "title": "From Stone to Sky: The Evolution of the Pyramids", | |
| "short_desc": "See the pyramids the way history intended.", | |
| "full_desc": "See the pyramids the way history intended. This experience walks you through Egypt’s pyramid-building journey in chronological order—from early step pyramids to the iconic giants of Giza—so you understand how and why these monuments evolved, not just what they look like.", | |
| "image": "pyramids_evolution.png", | |
| "duration": "4–6 hours", | |
| "price": "Contact for Price", | |
| "rating": "4.9 ★", | |
| "category": "History • Architecture", | |
| "location": "Saqqara → Dahshur → Giza Plateau", | |
| "focus_points": [ | |
| {"icon": "📐", "title": "Architectural Evolution", "desc": "Trace the design shifts from step pyramids to the smooth-sided giants."}, | |
| {"icon": "👑", "title": "Political & Religious", "desc": "Political and religious motivations behind each phase."}, | |
| {"icon": "🏗️", "title": "Engineering", "desc": "Engineering breakthroughs and failures."}, | |
| {"icon": "🏜️", "title": "Context", "desc": "Context beyond “the three pyramids”."} | |
| ] | |
| }, | |
| { | |
| "id": 2, | |
| "title": "One Street, Three Faiths", | |
| "short_desc": "Experience centuries of coexistence in Old Cairo.", | |
| "full_desc": "In one compact area, experience centuries of coexistence. This walk through Old Cairo’s Religious Complex explores Islamic, Christian, and Jewish landmarks side by side—revealing how belief, culture, and daily life intersected in Cairo long before modern borders and labels.", | |
| "image": "rel_complex.png", | |
| "duration": "2–3 hours", | |
| "price": "Contact for Price", | |
| "rating": "4.8 ★", | |
| "category": "Culture • Religion", | |
| "location": "Old Cairo (Coptic Cairo)", | |
| "focus_points": [ | |
| {"icon": "🤝", "title": "Coexistence", "desc": "Religious coexistence in Egyptian history."}, | |
| {"icon": "✝️", "title": "Coptic Heritage", "desc": "Coptic Christianity and early churches."}, | |
| {"icon": "✡️", "title": "Jewish History", "desc": "Jewish heritage in Cairo."}, | |
| {"icon": "🕌", "title": "Islamic Rules", "desc": "Islamic rule and urban layering."} | |
| ] | |
| }, | |
| { | |
| "id": 3, | |
| "title": "Breakfast on Wheels: Egypt’s Foul Ritual", | |
| "short_desc": "Foul isn’t just food—it’s a daily ritual.", | |
| "full_desc": "Foul isn’t just food—it’s a daily ritual. This experience takes you to a classic street cart where locals start their morning, showing how one humble dish became a national constant across class, neighborhood, and generation.", | |
| "image": "foul_cart.png", | |
| "duration": "30–45 mins", | |
| "price": "Contact for Price", | |
| "rating": "5.0 ★", | |
| "category": "Food • Street Culture", | |
| "location": "Local neighborhoods across Cairo", | |
| "focus_points": [ | |
| {"icon": "🥘", "title": "Street Food", "desc": "Egyptian street food culture."}, | |
| {"icon": "☕", "title": "Morning Rituals", "desc": "Social rituals around breakfast."}, | |
| {"icon": "🍋", "title": "Ingredients", "desc": "Ingredients, preparation, and variations."}, | |
| {"icon": "🥄", "title": "Eat Like a Local", "desc": "Eating like a local, respectfully."} | |
| ] | |
| }, | |
| { | |
| "id": 4, | |
| "title": "Money Talks: Egypt’s History in Your Wallet", | |
| "short_desc": "Your cash is a hidden guidebook.", | |
| "full_desc": "Your cash is a hidden guidebook. This experience connects Egyptian banknotes to the real monuments printed on them, taking you from paper to place. You’ll visit the Sultan Hassan Mosque, Al-Rifa’i Mosque, and the Citadel of Saladin, uncovering why these landmarks were chosen to represent Egypt’s power, faith, and identity.", | |
| "image": "money_history.jpg", | |
| "duration": "3–4 hours", | |
| "price": "Contact for Price", | |
| "rating": "4.9 ★", | |
| "category": "Culture • Urban Exploration", | |
| "location": "Islamic Cairo & Citadel area", | |
| "focus_points": [ | |
| {"icon": "💶", "title": "Symbolism", "desc": "Symbolism behind Egyptian currency design."}, | |
| {"icon": "🕌", "title": "Power", "desc": "Mamluk and Ottoman architectural power."}, | |
| {"icon": "🆔", "title": "Identity", "desc": "How nations curate identity through money."}, | |
| {"icon": "🔗", "title": "Connections", "desc": "Linking everyday objects to historical sites."} | |
| ] | |
| } | |
| ] | |
| def experience_details(id): | |
| experience = next((exp for exp in experiences_data if exp['id'] == id), None) | |
| if not experience: | |
| return redirect(url_for('explore')) | |
| return render_template('experience_details.html', experience=experience) | |
| def questionnaire(): | |
| return render_template('questionnaire.html') | |
| # --- Auth Routes --- | |
| def login(): | |
| if request.method == 'POST': | |
| email = request.form.get('email') # or username | |
| password = request.form.get('password') | |
| remember = True if request.form.get('remember') else False | |
| user = User.query.filter_by(email=email).first() | |
| if not user or not check_password_hash(user.password, password): | |
| flash('Please check your login details and try again.') | |
| return redirect(url_for('login')) | |
| login_user(user, remember=remember) | |
| return redirect(url_for('explore')) | |
| return render_template('login.html') | |
| def signup(): | |
| if request.method == 'POST': | |
| email = request.form.get('email') | |
| name = request.form.get('name') | |
| password = request.form.get('password') | |
| user = User.query.filter_by(email=email).first() | |
| if user: | |
| flash('Email address already exists') | |
| return redirect(url_for('signup')) | |
| new_user = User(email=email, name=name, password=generate_password_hash(password, method='scrypt')) | |
| db.session.add(new_user) | |
| db.session.commit() | |
| # Log user in immediately after signup | |
| login_user(new_user) | |
| return redirect(url_for('questionnaire')) | |
| return render_template('signup.html') | |
| def logout(): | |
| logout_user() | |
| return redirect(url_for('home')) | |
| def auth_status(): | |
| if current_user.is_authenticated: | |
| return jsonify({ | |
| 'is_authenticated': True, | |
| 'name': current_user.name, | |
| 'trip_count': current_user.trip_count | |
| }) | |
| return jsonify({'is_authenticated': False}) | |
| def book_trip(): | |
| current_user.trip_count += 1 | |
| db.session.commit() | |
| return jsonify({ | |
| 'success': True, | |
| 'trip_count': current_user.trip_count | |
| }) | |
| # --- AI Chat Route --- | |
| def chat(): | |
| data = request.json | |
| user_message = data.get('message') | |
| try: | |
| model = genai.GenerativeModel('gemini-2.0-flash') | |
| response = model.generate_content(user_message) | |
| return jsonify({'response': response.text}) | |
| except Exception as e: | |
| app.logger.error(f"AI Error: {e}") | |
| return jsonify({'response': "I am currently busy exploring the Nile. Please try again in a moment!"}), 500 | |
| if __name__ == '__main__': | |
| app.run(debug=True) | |