Spaces:
Sleeping
Sleeping
| import os | |
| from flask import Flask, request, jsonify, render_template | |
| from flask_sqlalchemy import SQLAlchemy | |
| from datetime import datetime, timedelta | |
| import requests | |
| app = Flask(__name__) | |
| # --- Archipelagic Persistence --- | |
| # Hugging Face provides /data for persistent storage if enabled | |
| PERSISTENT_DIR = "/data" if os.path.exists("/data") else "." | |
| db_path = os.path.join(PERSISTENT_DIR, "odistay.db") | |
| app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}' | |
| app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False | |
| db = SQLAlchemy(app) | |
| # --- The Data Models --- | |
| class StayNode(db.Model): | |
| id = db.Column(db.Integer, primary_key=True) | |
| name = db.Column(db.String(100), nullable=False) | |
| island = db.Column(db.String(50)) | |
| category = db.Column(db.String(20)) # Resort, Guesthouse, Safari | |
| lat = db.Column(db.Float) | |
| lng = db.Column(db.Float) | |
| whatsapp = db.Column(db.String(20), unique=True) | |
| rooms = db.Column(db.Integer, default=0) | |
| is_active = db.Column(db.Boolean, default=False) | |
| last_pulse = db.Column(db.DateTime, default=datetime.utcnow) | |
| # --- Logic: FollowMe Sync Simulation --- | |
| def get_live_vessels(): | |
| # In production, this scrapes or calls the FollowMe API | |
| return [ | |
| {"name": "Dhigurah Express", "type": "Speedboat", "lat": 4.17, "lng": 73.51, "status": "En-route"}, | |
| {"name": "Baa Cargo", "type": "Supply", "lat": 4.20, "lng": 73.55, "status": "Docked"} | |
| ] | |
| # --- Routes --- | |
| def index(): | |
| # Only show nodes that have "pulsed" in the last 24 hours (Real-time Truth) | |
| expiry = datetime.utcnow() - timedelta(hours=24) | |
| active_stays = StayNode.query.filter(StayNode.last_pulse > expiry, StayNode.is_active == True).all() | |
| vessels = get_live_vessels() | |
| return render_template('index.html', stays=active_stays, vessels=vessels) | |
| def whatsapp_webhook(): | |
| # This acts as the OdiStay Admin Portal | |
| incoming = request.values.get('Body', '').upper() | |
| sender = request.values.get('From', '') | |
| host = StayNode.query.filter_by(whatsapp=sender).first() | |
| if not host: return "Unauthorized", 403 | |
| if "AVAIL" in incoming: | |
| try: | |
| count = int(incoming.split()[-1]) | |
| host.rooms = count | |
| host.is_active = True | |
| host.last_pulse = datetime.utcnow() | |
| db.session.commit() | |
| return "Success" | |
| except: return "Format Error", 400 | |
| if "FULL" in incoming: | |
| host.is_active = False | |
| db.session.commit() | |
| return "Closed" | |
| return "OK" | |
| if __name__ == "__main__": | |
| with app.app_context(): | |
| db.create_all() | |
| # Seed local nodes for testing if DB is empty | |
| if not StayNode.query.first(): | |
| db.session.add(StayNode(name="OdiStay Sample Maafushi", island="Maafushi", category="Guesthouse", lat=3.94, lng=73.48, whatsapp="whatsapp:+9607770000", is_active=True)) | |
| db.session.commit() | |
| # Port 7860 is mandatory for Hugging Face | |
| app.run(host="0.0.0.0", port=7860, debug=False, use_reloader=False) |