""" 内部回归评测 API 入口:与 app.main 进程隔离部署。 启动示例(在 api/ 目录;端口与 INTERNAL_EVAL_PORT 一致,development.sh 默认 7999):: uv run uvicorn app.internal_main:internal_app --host 0.0.0.0 --port 7999 """ from __future__ import annotations from contextlib import asynccontextmanager from pathlib import Path from app.core.logging import get_logger, setup_logging setup_logging() from app.core.config import settings from app.core.runtime_constants import otel_defaults from app.core.telemetry import instrument_fastapi_app, setup_telemetry setup_telemetry( service_name=otel_defaults.service_name or "life-echo-internal-api", ) from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from app.core.errors import register_exception_handlers from app.core.middleware import RequestIdMiddleware from app.features.evaluation import models as _eval_models # noqa: F401 from app.features.evaluation.router import router as eval_router from app.features.evaluation.constants import eval_cfg logger = get_logger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): import asyncio from app.core.alembic_startup import run_alembic_upgrade_at_startup logger.info("内部评测 API 启动中…") await asyncio.to_thread(run_alembic_upgrade_at_startup) try: from app.core.celery_broker_dev import maybe_purge_celery_broker_on_startup from app.core.redis import redis_service _redis = await redis_service.get_client() logger.info("Redis 已连接(评测任务可用)") await maybe_purge_celery_broker_on_startup(_redis) except Exception as e: logger.warning("Redis 连接失败: {}", e) yield logger.info("内部评测 API 关闭中…") try: from app.core.telemetry import shutdown_telemetry shutdown_telemetry() except Exception as e: logger.warning("关闭 OpenTelemetry 失败: {}", e) try: from app.core.redis import redis_service await redis_service.close() except Exception as e: logger.warning("关闭 Redis 失败: {}", e) internal_app = FastAPI( title="Life Echo Internal Evaluation API", version="0.1.0", docs_url="/docs" if eval_cfg.internal_enable_docs else None, redoc_url="/redoc" if eval_cfg.internal_enable_docs else None, openapi_url="/openapi.json" if eval_cfg.internal_enable_docs else None, lifespan=lifespan, ) instrument_fastapi_app(internal_app) internal_app.add_middleware(RequestIdMiddleware) _origins = [ o.strip() for o in (eval_cfg.internal_cors_origins or "").split(",") if o.strip() ] _allow_creds = bool(_origins) internal_app.add_middleware( CORSMiddleware, allow_origins=_origins if _origins else ["*"], allow_credentials=_allow_creds, allow_methods=["*"], allow_headers=["*"], ) register_exception_handlers(internal_app) @internal_app.get("/", include_in_schema=False, response_class=HTMLResponse) async def internal_eval_landing(): """浏览器打开内部评测 API 根路径时提示:界面在 Vite(默认 5174),本进程仅为 API。""" docs_hint = ( '

OpenAPI 文档 /docs

' if eval_cfg.internal_enable_docs else "

(未开启文档;在 config/development.toml 的 [eval] internal_enable_docs = true)

" ) return f""" 内部评测 API

Life Echo · 内部回归评测 API

这里是 HTTP API(端口由启动命令决定),没有内置网页。 浏览「回归评测台」请在仓库执行 ./development.shcd app-eval-web && npm run dev, 在终端里打开 Vite 给出的地址(一般为 http://127.0.0.1:5174/)。

健康检查:/health

{docs_hint}

会话与对比接口前缀:/internal/api/evaluation/

""" internal_app.include_router(eval_router, prefix="/internal/api/evaluation") _static_dir = Path(__file__).resolve().parent.parent / "static" if _static_dir.is_dir(): internal_app.mount( "/static", StaticFiles(directory=str(_static_dir)), name="static" ) @internal_app.get("/health", include_in_schema=False) async def health(): return {"status": "ok", "service": "internal-eval"}