将 Clover 从上层产品包旧仓库中独立出来,建立专属版本控制。 当前状态=纵切片端到端已打通(登录→选品→出文出图→审核→下载包), M1文案质量去套路化已验收。此提交作为后续按核销清单逐条修复的基线。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
96 lines
3.6 KiB
Python
96 lines
3.6 KiB
Python
"""
|
||
main.py — FastAPI 应用入口
|
||
统一响应包络 / 全局异常处理 / 健康检查 / 路由注册
|
||
"""
|
||
|
||
import logging
|
||
import os
|
||
|
||
from fastapi import FastAPI, Request
|
||
from fastapi.middleware.cors import CORSMiddleware
|
||
from fastapi.responses import JSONResponse
|
||
from fastapi.staticfiles import StaticFiles
|
||
|
||
from app.core.config import get_settings
|
||
from app.core.response import CloverHTTPException, ErrorCode
|
||
|
||
logger = logging.getLogger(__name__)
|
||
settings = get_settings()
|
||
|
||
|
||
def create_app() -> FastAPI:
|
||
app = FastAPI(
|
||
title="Clover API",
|
||
version="0.1.0",
|
||
docs_url="/docs" if settings.APP_ENV != "production" else None,
|
||
redoc_url=None,
|
||
)
|
||
|
||
# ── CORS ──────────────────────────────────────────
|
||
app.add_middleware(
|
||
CORSMiddleware,
|
||
allow_origins=["*"], # 生产环境收窄到前端域名
|
||
allow_credentials=True,
|
||
allow_methods=["*"],
|
||
allow_headers=["*"],
|
||
)
|
||
|
||
# ── 全局异常处理(统一包络)──────────────────────
|
||
@app.exception_handler(CloverHTTPException)
|
||
async def clover_http_exception_handler(request: Request, exc: CloverHTTPException):
|
||
return JSONResponse(
|
||
status_code=exc.status_code,
|
||
content={"code": exc.biz_code, "message": exc.biz_message},
|
||
)
|
||
|
||
@app.exception_handler(Exception)
|
||
async def generic_exception_handler(request: Request, exc: Exception):
|
||
logger.error("Unhandled exception: %s %s → %s", request.method, request.url, exc)
|
||
return JSONResponse(
|
||
status_code=500,
|
||
content={"code": ErrorCode.SERVER_ERROR, "message": "服务器内部错误"},
|
||
)
|
||
|
||
# ── 健康检查(Docker 健康检查用)──────────────────
|
||
@app.get("/health")
|
||
async def health():
|
||
return {"status": "ok"}
|
||
|
||
# ── 路由注册(每个模块路由独立文件,这里汇总注册)─
|
||
_register_routers(app)
|
||
|
||
# ── 静态文件(G4坑修复:图片 /uploads 路由)──────
|
||
uploads_dir = os.path.join(os.path.dirname(__file__), "uploads")
|
||
os.makedirs(uploads_dir, exist_ok=True)
|
||
app.mount("/uploads", StaticFiles(directory=uploads_dir), name="uploads")
|
||
|
||
return app
|
||
|
||
|
||
def _register_routers(app: FastAPI) -> None:
|
||
from app.api.v1.auth import router as auth_router
|
||
from app.api.v1.api_keys import router as api_keys_router
|
||
from app.api.v1.products import router as products_router
|
||
from app.api.v1.benchmarks import router as benchmarks_router
|
||
from app.api.v1.tasks import router as tasks_router
|
||
from app.api.v1.task_actions import router as task_actions_router
|
||
from app.api.v1.review import router as review_router
|
||
from app.api.v1.delivery import router as delivery_router
|
||
from app.api.v1.stream import router as stream_router
|
||
from app.api.v1.workspaces import router as workspaces_router
|
||
|
||
prefix = "/api/v1"
|
||
app.include_router(auth_router, prefix=prefix)
|
||
app.include_router(api_keys_router, prefix=prefix)
|
||
app.include_router(products_router, prefix=prefix)
|
||
app.include_router(benchmarks_router, prefix=prefix)
|
||
app.include_router(tasks_router, prefix=prefix)
|
||
app.include_router(task_actions_router, prefix=prefix)
|
||
app.include_router(review_router, prefix=prefix)
|
||
app.include_router(delivery_router, prefix=prefix)
|
||
app.include_router(stream_router, prefix=prefix)
|
||
app.include_router(workspaces_router, prefix=prefix)
|
||
|
||
|
||
app = create_app()
|