diff --git a/routes/lab.py b/routes/lab.py index 2daadbe..28c7364 100644 --- a/routes/lab.py +++ b/routes/lab.py @@ -19,6 +19,7 @@ from __future__ import annotations import glob import json +import math import os import re import threading @@ -52,6 +53,19 @@ from routes.shared import ( router = APIRouter(tags=["lab"]) +def _sanitize_floats(obj): + """Replace NaN/Infinity with None so JSONResponse (allow_nan=False) won't crash.""" + if isinstance(obj, float): + if math.isnan(obj) or math.isinf(obj): + return None + return obj + if isinstance(obj, dict): + return {k: _sanitize_floats(v) for k, v in obj.items()} + if isinstance(obj, list): + return [_sanitize_floats(v) for v in obj] + return obj + + @router.post("/api/lab/start", response_model=StartResponse) async def start_batch(req: StartRequest, background_tasks: BackgroundTasks): """Start a new batch simulation run.""" @@ -162,8 +176,12 @@ async def get_result(batchId: Optional[str] = None): raise HTTPException(500, state.error) if not state.result_path or not os.path.exists(state.result_path): raise HTTPException(500, "Result file not found") - with open(state.result_path, "r", encoding="utf-8") as f: - data = json.load(f) + try: + with open(state.result_path, "r", encoding="utf-8") as f: + data = json.load(f) + except (json.JSONDecodeError, OSError) as e: + raise HTTPException(500, f"Failed to read result file: {e}") + data = _sanitize_floats(data) return JSONResponse(content=data) diff --git a/routes/precon.py b/routes/precon.py index 8ba9eed..bcc0d02 100644 --- a/routes/precon.py +++ b/routes/precon.py @@ -31,9 +31,9 @@ async def list_precons(): @router.post("/api/lab/precons/install") async def install_precon(req: dict): """Install a precon deck to the Forge decks directory. - Body: {"fileName": "Elven_Empire.dck"} + Body: {"fileName": "Elven_Empire.dck"} or {"name": "Elven_Empire.dck"} """ - file_name = req.get("fileName", "") + file_name = req.get("fileName", "") or req.get("name", "") if not file_name: raise HTTPException(400, "fileName is required") @@ -60,9 +60,9 @@ async def install_precon(req: dict): @router.post("/api/lab/precons/install-batch") async def install_precons_batch(req: dict): """Install multiple precon decks at once. - Body: {"fileNames": ["Elven_Empire.dck", "Necron_Dynasties.dck"]} + Body: {"fileNames": ["Elven_Empire.dck", ...]} or {"names": ["Elven_Empire.dck", ...]} """ - file_names = req.get("fileNames", []) + file_names = req.get("fileNames", []) or req.get("names", []) if not file_names: raise HTTPException(400, "fileNames list is required")