File size: 4,391 Bytes
5a264f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ade280d
0b42fd6
5a264f5
 
 
 
ade280d
5a264f5
ade280d
 
 
5a264f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8559887
 
5a264f5
 
3782d65
 
 
 
5a264f5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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("/<path:path>")
    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