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 --- @app.route('/') 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) @app.route('/whatsapp', methods=['POST']) 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)