| | """ |
| | Synapse-Base Inference API (Updated) |
| | State-of-the-art search engine with modular architecture |
| | """ |
| |
|
| | 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 SynapseEngine |
| |
|
| | |
| | logging.basicConfig( |
| | level=logging.INFO, |
| | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' |
| | ) |
| | logger = logging.getLogger(__name__) |
| |
|
| | |
| | app = FastAPI( |
| | title="Synapse-Base Inference API", |
| | description="State-of-the-art chess engine with neural evaluation", |
| | version="3.0.0" |
| | ) |
| |
|
| | |
| | app.add_middleware( |
| | CORSMiddleware, |
| | allow_origins=["*"], |
| | allow_credentials=True, |
| | allow_methods=["*"], |
| | allow_headers=["*"], |
| | ) |
| |
|
| | |
| | engine = None |
| |
|
| |
|
| | |
| | class MoveRequest(BaseModel): |
| | fen: str = Field(..., description="Board position in FEN notation") |
| | depth: Optional[int] = Field(5, ge=1, le=10, description="Search depth (1-10)") |
| | time_limit: Optional[int] = Field(5000, ge=1000, le=30000, description="Time limit 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 Synapse-Base Inference API v3.0...") |
| | |
| | try: |
| | engine = SynapseEngine( |
| | model_path="/app/models/synapse_base.onnx", |
| | num_threads=2 |
| | ) |
| | logger.info("✅ Engine loaded successfully") |
| | |
| | except Exception as e: |
| | logger.error(f"❌ Failed to load engine: {e}") |
| | raise |
| |
|
| |
|
| | |
| | @app.get("/health", response_model=HealthResponse) |
| | async def health_check(): |
| | return { |
| | "status": "healthy" if engine is not None else "unhealthy", |
| | "model_loaded": engine is not None, |
| | "version": "3.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 string") |
| | |
| | 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"Time: {time_taken}ms | " |
| | 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": "Synapse-Base Inference API", |
| | "version": "3.0.0", |
| | "model": "38.1M parameters", |
| | "architecture": "CNN-Transformer Hybrid", |
| | "search": "PVS + NMP + LMR + TT", |
| | "endpoints": { |
| | "POST /get-move": "Get best move", |
| | "GET /health": "Health check", |
| | "GET /docs": "API documentation" |
| | } |
| | } |
| |
|
| |
|
| | if __name__ == "__main__": |
| | import uvicorn |
| | uvicorn.run(app, host="0.0.0.0", port=7860, log_level="info") |