""" Nexus-Core Inference API 13.2M parameter chess engine """ from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel, Field import time import logging from typing import Optional, List from engine import NexusCoreEngine # Logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) # FastAPI app = FastAPI( title="Nexus-Core Inference API", description="13.2M parameter Resnet-10 chess engine", version="2.0.0" ) # CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Global engine engine = None # Models class MoveRequest(BaseModel): fen: str = Field(..., description="FEN notation") depth: Optional[int] = Field(5, ge=1, le=8, description="Search depth") time_limit: Optional[int] = Field(3000, ge=1000, le=15000, description="Time in ms") class MoveResponse(BaseModel): best_move: str evaluation: float depth_searched: int seldepth: int nodes_evaluated: int time_taken: int nps: int pv: List[str] tt_hit_rate: Optional[float] = None class HealthResponse(BaseModel): status: str model_loaded: bool version: str model_size_mb: Optional[float] = None # Startup @app.on_event("startup") async def startup_event(): global engine logger.info("🚀 Starting Nexus-Core API v2.0...") try: engine = NexusCoreEngine( model_path="/app/models/nexus-core.onnx", num_threads=2 ) logger.info("✅ Engine loaded") except Exception as e: logger.error(f"❌ Failed: {e}") raise # Health @app.get("/health", response_model=HealthResponse) async def health_check(): return { "status": "healthy" if engine else "unhealthy", "model_loaded": engine is not None, "version": "2.0.0", "model_size_mb": engine.get_model_size() if engine else None } # Main endpoint @app.post("/get-move", response_model=MoveResponse) async def get_move(request: MoveRequest): if engine is None: raise HTTPException(status_code=503, detail="Engine not loaded") if not engine.validate_fen(request.fen): raise HTTPException(status_code=400, detail="Invalid FEN") start_time = time.time() try: result = engine.get_best_move( fen=request.fen, depth=request.depth, time_limit=request.time_limit ) time_taken = int((time.time() - start_time) * 1000) logger.info( f"Move: {result['best_move']} | " f"Eval: {result['evaluation']:+.2f} | " f"Depth: {result['depth_searched']}/{result['seldepth']} | " f"Nodes: {result['nodes_evaluated']} | " f"NPS: {result['nps']}" ) return MoveResponse( best_move=result['best_move'], evaluation=result['evaluation'], depth_searched=result['depth_searched'], seldepth=result['seldepth'], nodes_evaluated=result['nodes_evaluated'], time_taken=time_taken, nps=result['nps'], pv=result['pv'], tt_hit_rate=result['tt_stats']['hit_rate'] ) except Exception as e: logger.error(f"Error: {e}") raise HTTPException(status_code=500, detail=str(e)) # Root @app.get("/") async def root(): return { "name": "Nexus-Core Inference API", "version": "2.0.0", "model": "13.2M parameters (Resnet-10)", "search": "PVS + NMP + LMR", "endpoints": { "POST /get-move": "Get best move", "GET /health": "Health check", "GET /docs": "Documentation" } } if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=7860, log_level="info")