-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
89 lines (73 loc) · 2.72 KB
/
Copy pathserver.py
File metadata and controls
89 lines (73 loc) · 2.72 KB
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
"""
server.py — Single Flask app that mounts all API routes.
Used for Docker / self-hosted deployment (Oracle Cloud, Render, etc.).
Vercel uses the individual api/*.py files instead.
Usage:
gunicorn server:app --bind 0.0.0.0:8000 --workers 2 --timeout 120
python server.py (dev)
"""
import os
import sys
_PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
if _PROJECT_ROOT not in sys.path:
sys.path.insert(0, _PROJECT_ROOT)
from flask import Flask
from flask import Response
from flask import jsonify
from flask import request
# Import the individual Flask apps and re-register their routes
# on a single combined app using blueprints.
from api.products import app as products_app
from api.forecast import app as forecast_app
from api.anomalies import app as anomalies_app
from api.importance import app as importance_app
from api.inventory import app as inventory_app
from api.simulation import app as simulation_app
app = Flask(__name__)
# ---------------------------------------------------------------------------
# CORS — allow the Vercel-hosted frontend to call this Render backend.
# VITE_ALLOWED_ORIGIN defaults to * so local dev still works.
# ---------------------------------------------------------------------------
_ALLOWED_ORIGIN = os.environ.get("ALLOWED_ORIGIN", "*")
@app.before_request
def handle_cors_preflight():
if request.method == "OPTIONS":
return Response(status=204)
@app.after_request
def add_cors_headers(response):
response.headers["Access-Control-Allow-Origin"] = _ALLOWED_ORIGIN
response.headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
response.headers["Access-Control-Allow-Headers"] = "Content-Type"
return response
@app.route("/api/<path:path>", methods=["OPTIONS"])
def handle_options(path):
return Response(status=204)
@app.route("/health", methods=["GET"])
@app.route("/api/health", methods=["GET"])
def health_check():
return jsonify({"status": "ok"}), 200
# Merge all routes from each sub-app into the combined app
for sub_app in (
products_app,
forecast_app,
anomalies_app,
importance_app,
inventory_app,
simulation_app,
):
for rule in sub_app.url_map.iter_rules():
# Skip the built-in static/favicon routes
if rule.endpoint == "static":
continue
view_func = sub_app.view_functions[rule.endpoint]
# Avoid duplicate endpoint names across sub-apps
endpoint = f"{sub_app.name}.{rule.endpoint}"
app.add_url_rule(
str(rule),
endpoint=endpoint,
view_func=view_func,
methods=rule.methods,
)
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8000))
app.run(host="0.0.0.0", port=port, debug=False)