"""FastAPI 静态服务:托管单页前端 + 媒体/抽帧落盘目录。 启动: CK_ENV_FILE=/path/.env uvicorn creation_knowledge.api:app --host 0.0.0.0 --port 8123 前端单页在 /,媒体在 /data,视频帧在 /frames。 """ from __future__ import annotations import os from functools import lru_cache from pathlib import Path from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import RedirectResponse from fastapi.staticfiles import StaticFiles from core.config import Settings _ROOT = Path(__file__).resolve().parent.parent WEB_DIR = _ROOT / "acquisition" / "web" # 前端工程目录(仅 app/ 下的 Vite 产物) def _env_file() -> str: return os.getenv("CK_ENV_FILE", ".env") @lru_cache(maxsize=1) def _settings() -> Settings: return Settings.from_env(_env_file()) app = FastAPI(title="创作知识") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"] ) # 视频帧静态服务(card.url = /frames//) _frames_dir = Path(_settings().frames_dir) _frames_dir.mkdir(parents=True, exist_ok=True) app.mount("/frames", StaticFiles(directory=str(_frames_dir)), name="frames") # 媒体静态服务(card.url = /data////) _data_dir = Path(_settings().data_dir or "data") _data_dir.mkdir(parents=True, exist_ok=True) app.mount("/data", StaticFiles(directory=str(_data_dir)), name="data") # 取数接口(分页/筛选) from acquisition.web_api import router as api_router # noqa: E402 app.include_router(api_router) # 根路径直接送到前端 @app.get("/") def _root() -> RedirectResponse: return RedirectResponse(url="/app/") # 唯一前端:Vite+React 构建产物挂在 /app(旧静态看板已下线) _APP_DIST = WEB_DIR / "app" / "dist" if _APP_DIST.exists(): app.mount("/app", StaticFiles(directory=str(_APP_DIST), html=True), name="app")