import os from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_cors import CORS db = SQLAlchemy() # Paths resolved relative to this file's location _HERE = os.path.dirname(__file__) _FRONT = os.path.join(_HERE, "..", "frontend") _DIST = os.path.join(_FRONT, "dist") # React production build _TEMPLATES = os.path.join(_FRONT, "templates") # Vanilla HTML fallback def create_app(config_override: dict | None = None) -> Flask: # Prefer React build if it exists if os.path.isdir(_DIST): template_folder = _DIST static_folder = os.path.join(_DIST, "assets") static_url_path = "/assets" else: template_folder = _TEMPLATES static_folder = os.path.join(_FRONT, "static") static_url_path = "/static" app = Flask( __name__, template_folder=template_folder, static_folder=static_folder, static_url_path=static_url_path, ) # ── Configuration ──────────────────────────────────────────────────────── app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY", "change-me-in-production") app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( "DATABASE_URL", "sqlite:///breathe.db" ) app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False app.config["SESSION_COOKIE_HTTPONLY"] = True app.config["SESSION_COOKIE_SAMESITE"] = "None" app.config["SESSION_COOKIE_SECURE"] = True if config_override: app.config.update(config_override) # ── Extensions ─────────────────────────────────────────────────────── db.init_app(app) default_origins = "http://localhost:5173,http://127.0.0.1:5173,https://huggingface.co,https://hf.space" origins = os.environ.get("CORS_ORIGINS", default_origins).split(",") CORS(app, supports_credentials=True, origins=origins) # ── Blueprints ─────────────────────────────────────────────────────────── from .routes.auth import auth_bp from .routes.assessments import assess_bp from .routes.profile import profile_bp from .routes.gratitude import gratitude_bp app.register_blueprint(auth_bp) app.register_blueprint(assess_bp) app.register_blueprint(profile_bp) app.register_blueprint(gratitude_bp) # ── Serve SPA ──────────────────────────────────────────────────────────── from flask import send_from_directory _dist_or_tmpl = _DIST if os.path.isdir(_DIST) else _TEMPLATES @app.route("/") def index(): return send_from_directory(_dist_or_tmpl, "index.html") @app.route("/") def catch_all(path): # Serve any real file that lives inside the dist/template dir target = os.path.join(_dist_or_tmpl, path) if os.path.isfile(target): return send_from_directory(_dist_or_tmpl, path) # SPA fallback return send_from_directory(_dist_or_tmpl, "index.html") # ── Create tables ──────────────────────────────────────────────────────── with app.app_context(): db.create_all() # ── ML model loading ───────────────────────────────────────────────────── from .ml.ml_engine import init_models init_models( psycho_model_dir=os.environ.get("PSYCHO_MODEL_DIR", "models/psychometric"), roberta_ckpt =os.environ.get("ROBERTA_CKPT", "models/text/roberta-model.pt"), ) # ── Background scheduler ───────────────────────────────────────────────── from .utils.scheduler import init_scheduler init_scheduler(app, db) return app