Files
meida_backend/apps/api/main.py
T
xsl d974526904 chore(prep): shared groundwork for batch-4 (report pipeline)
第四批(T15 编排/T16 视觉诊断/T17 文案校验)协调提交:
- 迁移 0006:rp_report(result JSONB 按阶段键承载中间态)/rp_input
 (derived_features 视觉中间态)/rp_share(V1 只建结构)
- ORM 三模型;错误码 40420/40920(文案无价格字样)
- 配置:report_pipeline_stages(dotted path 动态装配)+ vision/tier
- packages/report/pipeline.py:Stage Protocol + ReportContext(三任务共同契约,
  动态 import 的动机与代价写在 docstring)
- 路由桩 reports.py 已注册
2026-08-14 21:51:05 +08:00

101 lines
2.8 KiB
Python

"""FastAPI application factory (架构文档 §3.1 L3 API 层).
The API layer only orchestrates: auth, validation, idempotency, quota,
unified response, OpenAPI. Business rules live in ``packages/<domain>``.
"""
from __future__ import annotations
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from fastapi import FastAPI
from apps.api.deps import build_llm_gateway
from apps.api.routers import (
agent,
auth,
auth_sms,
events,
health,
kb,
quota,
reports,
tasks,
uploads,
)
from packages.shared.config import Settings, get_settings
from packages.shared.db import dispose_engine
from packages.shared.handlers import install_exception_handlers
from packages.shared.logging import configure_logging, get_logger
from packages.shared.middleware import RequestContextMiddleware, install_version_alias
from packages.shared.observability import setup_tracing
from packages.shared.redis_client import close_redis
logger = get_logger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
settings: Settings = get_settings()
app.state.llm_gateway = build_llm_gateway(settings)
logger.info(
"api_started",
env=settings.app_env,
api_prefix=settings.api_prefix,
llm_primary=settings.llm_primary_provider,
llm_model=settings.deepseek_model,
)
try:
yield
finally:
await app.state.llm_gateway.aclose()
await close_redis()
await dispose_engine()
logger.info("api_stopped")
def create_app(settings: Settings | None = None) -> FastAPI:
cfg = settings or get_settings()
configure_logging(
level=cfg.log_level, json_output=cfg.log_json, extra_redact_keys=cfg.extra_redact_keys
)
app = FastAPI(
title="美搭 backend",
version="0.1.0",
description=(
"AI 穿搭美学助手服务端。统一响应见架构文档 §9.2;"
"所有业务接口在 " + cfg.api_prefix + " 之下(/v1 为等价别名)。"
),
openapi_url=f"{cfg.api_prefix}/openapi.json",
docs_url=f"{cfg.api_prefix}/docs" if cfg.is_local else None,
redoc_url=None,
lifespan=lifespan,
)
install_version_alias(app, cfg.api_prefix)
app.add_middleware(RequestContextMiddleware)
install_exception_handlers(app)
setup_tracing(app, cfg)
app.include_router(health.router)
routers = (
auth.router,
auth_sms.router,
agent.router,
quota.router,
tasks.router,
events.router,
uploads.router,
kb.router,
reports.router,
)
for router in routers:
app.include_router(router, prefix=cfg.api_prefix)
return app
app = create_app()