""" FastAPI HTTP 推理服务 提供 REST API 识别验证码: POST /solve - 上传图片,返回识别结果 GET /health - 健康检查 启动方式: uv run python cli.py serve --port 8080 请求示例: curl -X POST http://localhost:8080/solve -F "image=@captcha.png" 响应示例: {"type": "normal", "result": "A3B8", "confidence": 0.95, "time_ms": 45} """ from __future__ import annotations def create_app(): """ 创建 FastAPI 应用实例(工厂函数)。 cli.py 的 cmd_serve 依赖此签名。 需要安装 server 可选依赖: uv sync --extra server """ from fastapi import FastAPI, File, Query, UploadFile from fastapi.responses import JSONResponse from inference.pipeline import CaptchaPipeline app = FastAPI( title="CaptchaBreaker", description="验证码识别多模型系统 - HTTP 推理服务", version="0.1.0", ) pipeline: CaptchaPipeline | None = None @app.on_event("startup") def _load_models(): nonlocal pipeline try: pipeline = CaptchaPipeline() except FileNotFoundError: # 模型未导出时允许启动,但 /solve 会返回 503 pipeline = None @app.get("/health") def health(): models_loaded = pipeline is not None return {"status": "ok" if models_loaded else "no_models", "models_loaded": models_loaded} @app.post("/solve") async def solve( image: UploadFile = File(...), type: str | None = Query(None, description="指定类型跳过分类"), ): if pipeline is None: return JSONResponse( status_code=503, content={"error": "模型未加载,请先训练并导出 ONNX 模型"}, ) data = await image.read() if not data: return JSONResponse( status_code=400, content={"error": "空文件"}, ) try: result = pipeline.solve(data, captcha_type=type) except RuntimeError as e: return JSONResponse( status_code=400, content={"error": str(e)}, ) return { "type": result["type"], "result": result["result"], "raw": result["raw"], "time_ms": result["time_ms"], } return app