Spaces:
Sleeping
Sleeping
File size: 3,639 Bytes
36fc296 9b6f854 36fc296 9b6f854 36fc296 a3b7c3c 36fc296 9b6f854 36fc296 1daba9a edc7b9c 36fc296 edc7b9c 36fc296 edc7b9c 9b6f854 a3b7c3c 9b6f854 edc7b9c 36fc296 9b6f854 edc7b9c 9b6f854 36fc296 9b6f854 36fc296 9b6f854 a3b7c3c 36fc296 edc7b9c 36fc296 f6f1db4 9b6f854 36fc296 9b6f854 36fc296 9b6f854 36fc296 a3b7c3c 36fc296 9b6f854 36fc296 9b6f854 a3b7c3c |
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
import sys
import os
from werkzeug.serving import run_simple
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from dotenv import load_dotenv
load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), ".env"))
from flask import Flask, send_from_directory
from flask_cors import CORS
from constants import Constants
from api.api_blueprint import api_blueprint
from models.base import db # 保留原本 import(即使現在沒用到)
from models.combined_labels import CombinedLabels # 同上
import logging
# --- 1. 確保 sessions 目錄有合理預設值 ---
SESSION_DIR = Constants.SESSIONS_DIR_NAME or "/app/sessions"
Constants.SESSIONS_DIR_NAME = SESSION_DIR
def create_session_dir():
path = Constants.SESSIONS_DIR_NAME
if not os.path.isdir(path):
os.makedirs(path, exist_ok=True)
def create_app():
create_session_dir()
# --- 2. 靜態檔:dist/ ---
# static_folder 指向 Vite build 出來的 dist
# static_url_path 設成 "",讓 /assets/... 之類的路徑正確
app = Flask(__name__, static_folder="dist", static_url_path="")
# --- 3. API 一律掛在 /api ---
app.register_blueprint(api_blueprint, url_prefix="/api")
# --- 4. 簡單 health check ---
@app.route("/api/ping")
def ping():
return {"status": "ok"}
# --- 5. React / Vite SPA:所有非靜態路徑 fallback 到 index.html ---
@app.route("/", defaults={"path": ""})
@app.route("/<path:path>")
def serve_spa(path: str):
"""
1. 如果 dist 裡真的有這個檔案,就當成靜態檔案回傳
2. 如果沒有,就回 dist/index.html,交給 React Router 處理
例如 /case/PanTS_00009391 這種 route
"""
# 先嘗試當成靜態檔
if path:
full_path = os.path.join(app.static_folder, path)
if os.path.isfile(full_path):
return send_from_directory(app.static_folder, path)
# 找不到對應實體檔案 → 交給前端路由
return send_from_directory(app.static_folder, "index.html")
# --- 6. Log 過濾:不要一直印 /api/progress ---
class FilterProgressRequests(logging.Filter):
def filter(self, record):
return "/api/progress/" not in record.getMessage()
logging.getLogger("werkzeug").addFilter(FilterProgressRequests())
# --- 7. CORS ---
CORS(app)
# --- 8. SharedArrayBuffer / WebGL 相關 header ---
@app.after_request
def add_security_headers(response):
response.headers["Cross-Origin-Opener-Policy"] = "same-origin"
response.headers["Cross-Origin-Embedder-Policy"] = "require-corp"
return response
return app
# 給 gunicorn 用的 WSGI app
app = create_app()
# --- 9. 本機開發(可選) ---
def find_watch_files():
watch_dirs = ["api", "models", "services"]
base_path = os.path.dirname(__file__)
all_files = []
for d in watch_dirs:
dir_path = os.path.join(base_path, d)
for root, _, files in os.walk(dir_path):
for f in files:
if f.endswith(".py"):
all_files.append(os.path.join(root, f))
return all_files
if __name__ == "__main__":
use_ssl = os.environ.get("USE_SSL", "false").lower() == "true"
ssl_context = (
("../certs/localhost-cert.pem", "../certs/localhost-key.pem") if use_ssl else None
)
run_simple(
hostname="0.0.0.0",
port=5001,
application=app,
use_debugger=True,
use_reloader=True,
extra_files=find_watch_files(),
ssl_context=ssl_context,
)
|