"""FastAPI REST-API für appRobotBodyTrack.""" from __future__ import annotations import json import tempfile from pathlib import Path from typing import List, Optional from fastapi import FastAPI, File, HTTPException, UploadFile from fastapi.responses import JSONResponse from scripts import __version__, estimate_from_dir _robot_json: Optional[Path] = None def create_app(robot_json: str | Path | None = None) -> FastAPI: """App-Fabrik — setzt optionale Server-weite robot.json-Konfig.""" global _robot_json if robot_json: _robot_json = Path(robot_json).resolve() return _app _app = FastAPI(title="approbot-pipeline", version=__version__) @_app.get("/v1/health") def health(): return {"status": "ok", "version": __version__} @_app.get("/v1/config") def config(): if _robot_json is None or not _robot_json.exists(): raise HTTPException(404, "Keine robot.json konfiguriert") data = json.loads(_robot_json.read_text(encoding="utf-8")) return data.get("pose_estimation", {}) @_app.post("/v1/estimate") async def estimate( images: List[UploadFile] = File(..., description="Kamerabilder (render_.png)"), intrinsics: List[UploadFile] = File(..., description="Kamera-Intrinsiken (render_.npz)"), robot_json: Optional[UploadFile] = File(default=None, description="robot.json (überschreibt Server-Konfig)"), ): """Pose-Schätzung aus Kamerabildern. Multipart-Upload: images[] — render_a.png, render_b.png, ... intrinsics[] — render_a.npz, render_b.npz, ... (gleiche Reihenfolge) robot_json — optional, überschreibt die Server-Konfiguration """ with tempfile.TemporaryDirectory(prefix="approbot_req_") as tmp: tmp_path = Path(tmp) if robot_json is not None: rj_path = tmp_path / "robot.json" rj_path.write_bytes(await robot_json.read()) elif _robot_json and _robot_json.exists(): rj_path = _robot_json else: raise HTTPException(400, "Keine robot.json angegeben (weder Upload noch Server-Konfig)") for img in images: (tmp_path / img.filename).write_bytes(await img.read()) for npz in intrinsics: (tmp_path / npz.filename).write_bytes(await npz.read()) try: result = estimate_from_dir(tmp_path, robot_json=rj_path, eval_dir=tmp_path) except FileNotFoundError as exc: raise HTTPException(400, str(exc)) except Exception as exc: raise HTTPException(500, str(exc)) return JSONResponse({ "joints": result.joints, "confidence": result.confidence, "residual_rms": result.residual_rms, "n_markers": result.n_markers, "processing_ms": result.processing_ms, })