| | """ |
| | 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.basicConfig( |
| | level=logging.INFO, |
| | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' |
| | ) |
| | logger = logging.getLogger(__name__) |
| |
|
| | |
| | app = FastAPI( |
| | title="Nexus-Core Inference API", |
| | description="13.2M parameter Resnet-10 chess engine", |
| | version="2.0.0" |
| | ) |
| |
|
| | |
| | app.add_middleware( |
| | CORSMiddleware, |
| | allow_origins=["*"], |
| | allow_credentials=True, |
| | allow_methods=["*"], |
| | allow_headers=["*"], |
| | ) |
| |
|
| | |
| | engine = None |
| |
|
| |
|
| | |
| | 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 |
| |
|
| |
|
| | |
| | @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 |
| |
|
| |
|
| | |
| | @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 |
| | } |
| |
|
| |
|
| | |
| | @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)) |
| |
|
| |
|
| | |
| | @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") |