Spaces:
Sleeping
Sleeping
| """ | |
| Nexus-Core Inference API - Path Fixed | |
| Model: /app/models/nexus-core.onnx | |
| """ | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel, Field | |
| import time | |
| import logging | |
| import os | |
| from typing import Optional | |
| from engine import NexusCoreEngine | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format='%(asctime)s - %(levelname)s - %(message)s' | |
| ) | |
| logger = logging.getLogger(__name__) | |
| app = FastAPI( | |
| title="Nexus-Core Inference API", | |
| description="Fast chess engine (13M params)", | |
| version="2.0.0" | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| engine = None | |
| class MoveRequest(BaseModel): | |
| fen: str | |
| depth: Optional[int] = Field(4, ge=1, le=6) | |
| time_limit: Optional[int] = Field(3000, ge=1000, le=10000) | |
| class MoveResponse(BaseModel): | |
| best_move: str | |
| evaluation: float | |
| depth_searched: int | |
| nodes_evaluated: int | |
| time_taken: int | |
| class HealthResponse(BaseModel): | |
| status: str | |
| model_loaded: bool | |
| version: str | |
| model_path: Optional[str] = None | |
| async def startup_event(): | |
| global engine | |
| logger.info("🚀 Starting Nexus-Core API...") | |
| # FIXED: Correct model path with hyphen | |
| model_path = "/app/models/nexus-core.onnx" | |
| # Debug logging | |
| logger.info(f"Looking for model at: {model_path}") | |
| if os.path.exists("/app/models"): | |
| logger.info("📂 Files in /app/models/:") | |
| for f in os.listdir("/app/models"): | |
| full_path = os.path.join("/app/models", f) | |
| if os.path.isfile(full_path): | |
| size = os.path.getsize(full_path) / (1024*1024) | |
| logger.info(f" ✓ {f} ({size:.2f} MB)") | |
| else: | |
| logger.error("❌ /app/models/ directory does not exist!") | |
| raise FileNotFoundError("/app/models/ not found") | |
| if not os.path.exists(model_path): | |
| logger.error(f"❌ Model not found at: {model_path}") | |
| logger.error("💡 Available files:", os.listdir("/app/models")) | |
| raise FileNotFoundError(f"Model file missing: {model_path}") | |
| logger.info(f"✅ Model found: {os.path.getsize(model_path)/(1024*1024):.2f} MB") | |
| try: | |
| engine = NexusCoreEngine( | |
| model_path=model_path, | |
| num_threads=2 | |
| ) | |
| logger.info("✅ Nexus-Core engine loaded successfully!") | |
| except Exception as e: | |
| logger.error(f"❌ Engine load failed: {e}", exc_info=True) | |
| raise | |
| async def health_check(): | |
| return { | |
| "status": "healthy" if engine else "unhealthy", | |
| "model_loaded": engine is not None, | |
| "version": "2.0.0", | |
| "model_path": "/app/models/nexus-core.onnx" | |
| } | |
| async def get_move(request: MoveRequest): | |
| if not engine: | |
| 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() | |
| try: | |
| result = engine.get_best_move( | |
| fen=request.fen, | |
| depth=request.depth, | |
| time_limit=request.time_limit | |
| ) | |
| logger.info( | |
| f"✓ Move: {result['best_move']} | " | |
| f"Eval: {result['evaluation']:+.2f} | " | |
| f"Depth: {result['depth_searched']} | " | |
| f"Nodes: {result['nodes_evaluated']} | " | |
| f"Time: {result['time_taken']}ms" | |
| ) | |
| return MoveResponse(**result) | |
| except Exception as e: | |
| logger.error(f"❌ Search error: {e}", exc_info=True) | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def root(): | |
| return { | |
| "name": "Nexus-Core Inference API", | |
| "version": "2.0.0", | |
| "model": "13M parameters", | |
| "architecture": "ResNet CNN", | |
| "speed": "0.5-1s per move @ depth 4", | |
| "status": "online" if engine else "starting", | |
| "endpoints": { | |
| "POST /get-move": "Get best chess move", | |
| "GET /health": "API health check", | |
| "GET /docs": "Interactive API documentation" | |
| } | |
| } | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run( | |
| app, | |
| host="0.0.0.0", | |
| port=7860, | |
| log_level="info", | |
| access_log=True | |
| ) |