"""FateForge v2 — 入口 (HF Spaces Gradio SDK, 不可更名)。 启动: python app.py # 默认 127.0.0.1:7860 set FATEFORGE_PORT=7861 && python app.py """ from __future__ import annotations import logging import gradio as gr from fastapi.routing import APIRoute from fastapi.staticfiles import StaticFiles from starlette.routing import Mount from fateforge.config import HOST, PORT, STATIC_DIR from fateforge.server import cast_seed, favicon, index, read # 压制 Gradio 内部健康检查产生的 httpx 日志噪音 logging.getLogger("httpx").setLevel(logging.WARNING) # ── Gradio 最小化包装器 (HF Spaces 兼容; 真实 UI 是 Vue SPA) ───────────────── with gr.Blocks(title="FateForge") as demo: pass # 不使用 Gradio 组件 UI; Vue SPA 挂载在下方 # ── 构建带有 fateforge 路由的自定义 App ──────────────────────────────────────── from gradio.routes import App as _GradioApp # noqa: E402 _app = _GradioApp.create_app(demo) # 将 fateforge 路由插到 Gradio 默认路由之前 (优先匹配) _fateforge_routes: list = [ APIRoute("/", index, methods=["GET"], include_in_schema=False), APIRoute("/favicon.ico", favicon, methods=["GET"], include_in_schema=False), APIRoute("/api/cast/seed", cast_seed, methods=["POST"]), APIRoute("/api/read", read, methods=["POST"]), ] for _i, _r in enumerate(_fateforge_routes): _app.router.routes.insert(_i, _r) # 静态文件 (Vue SPA 的 JS/CSS/图片等), 插在 API 路由之后、Gradio 路由之前 if STATIC_DIR.exists(): _app.router.routes.insert( len(_fateforge_routes), Mount("/static", app=StaticFiles(directory=STATIC_DIR), name="fateforge_static"), ) # 暴露给 ASGI workers (HF Spaces / uvicorn 直接挂载) app = _app if __name__ == "__main__": demo.launch( server_name=HOST, server_port=PORT, _app=_app, )