# -*- coding: utf-8 -*- """FastAPI 应用入口(接口层组装)。 启动方式(项目根目录): uv run uvicorn app.main:app --host 127.0.0.1 --port 8090 或使用脚本:``uv run python -m app`` """ from __future__ import annotations from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app import config from app.infrastructure.repositories import Database from app.api.routers import agents as agents_router from app.api.routers import auth as auth_router from app.api.routers import bootstrap as bootstrap_router from app.api.routers import rbac_admin as rbac_admin_router from app.api.routers import rbac_hall as rbac_hall_router from app.api.routers import rbac_service_market as rbac_service_market_router from app.api.routers import rbac_pages as rbac_pages_router from app.api.routers import rbac_opc as rbac_opc_router from app.api.routers import rbac_operator as rbac_operator_router from app.api.routers import rbac_agents as rbac_agents_router from app.api.routers import rbac_public as rbac_public_router from app.api.routers import rbac_org as rbac_org_router from app.api.routers import rbac_portals as rbac_portals_router from app.api.routers import rbac_certifications as rbac_certifications_router from app.api.routers import rbac_training as rbac_training_router from app.api.routers import rbac_credit as rbac_credit_router from app.api.routers import rbac_ecosystem as rbac_ecosystem_router from app.api.routers import rbac_enterprise as rbac_enterprise_router from app.api.routers import rbac_ent_onboard as rbac_ent_onboard_router from app.api.routers import rbac_teams as rbac_teams_router from app.api.routers import rbac_desktop_updates as rbac_desktop_updates_router from app.api.routers import rbac_moderation as rbac_moderation_router from app.api.routers import templates as templates_router from app.api.routers import relay as relay_router from app.pay import routers as pay_router from app.market import routers as market_router from app.incubator import routers as incubator_router from app.api.routers import invite as invite_router from app.api.routers import rbac_compute_pricing as compute_pricing_router from app.im import router as im_router APP_NAME = "云超服Agents 演示后端" @asynccontextmanager async def lifespan(app: FastAPI): """启动时初始化数据库(建表 + 幂等种子)+ Redis 缓存连接。 若 ``app.state.db`` 已由外部注入(如测试夹具),则直接复用, 不重新创建,避免覆盖调用方准备的数据库实例。 """ from .infrastructure.cache import cache as redis_cache db = getattr(app.state, "db", None) if db is None: db = Database() await db.initialize() app.state.db = db # 连接 Redis(失败自动降级为无缓存) await redis_cache.connect() app.state.cache = redis_cache yield # 关闭 Redis await redis_cache.close() if db is not None and db._owns_session: await db.close() # 释放引擎连接池,避免连接残留导致下次启动 initialize() 被锁挂起/连接泄漏 engine = getattr(db, "_engine", None) if engine is not None: try: await engine.dispose() except Exception: # noqa: BLE001 pass app = FastAPI( title=APP_NAME, description=( "云超服核心服务端:身份/平台 API + 培训子应用(/api/*),统一对外 opc.pinesound.cn。" "异步四层架构(接口/业务/领域/基础设施)。" ), version="0.1.0", lifespan=lifespan, ) # 演示服务允许任意来源(实际生产由主后端网关收敛)。 app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) app.include_router(auth_router.router) app.include_router(agents_router.router) app.include_router(templates_router.router) app.include_router(bootstrap_router.router) app.include_router(rbac_admin_router.router) app.include_router(rbac_opc_router.router) app.include_router(rbac_operator_router.router) app.include_router(rbac_agents_router.router) app.include_router(rbac_public_router.router) app.include_router(rbac_org_router.router) app.include_router(rbac_portals_router.router) app.include_router(rbac_hall_router.router) app.include_router(rbac_service_market_router.router) app.include_router(rbac_pages_router.router) app.include_router(rbac_certifications_router.router) app.include_router(rbac_training_router.router) app.include_router(rbac_credit_router.router) app.include_router(rbac_ecosystem_router.router) app.include_router(rbac_enterprise_router.router) app.include_router(rbac_ent_onboard_router.router) app.include_router(rbac_teams_router.router) app.include_router(rbac_desktop_updates_router.router) app.include_router(rbac_desktop_updates_router.public_router) app.include_router(rbac_hall_router.community_router) app.include_router(rbac_moderation_router.router) app.include_router(rbac_moderation_router.report_router) app.include_router(rbac_hall_router.dm_router) # compute_pricing 必须在 relay_router 之前注册:relay 有 /{path:path} catch-all, # 会吞掉 /api/compute/* 导致全部 404。 app.include_router(compute_pricing_router.router) app.include_router(relay_router.router) app.include_router(pay_router.router) app.include_router(market_router.router) app.include_router(market_router.admin_router) app.include_router(incubator_router.router) app.include_router(invite_router.router) app.include_router(im_router.router) @app.get("/health", tags=["meta"], summary="健康检查") async def health(): return { "status": "ok", "service": "pineagents-demo-server", "auth_enabled": config.AUTH_ENABLED, } @app.get("/", tags=["meta"], include_in_schema=False) async def root(): return { "service": APP_NAME, "docs": "/docs", "health": "/health", }