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 API", 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 @app.on_event("startup") async def startup_event(): global engine logger.info("🚀 Starting Nexus-Core...") # FIXED: Check both possible paths possible_paths = [ "/app/app/models/nexus-core.onnx", # When uploaded to app/models/ "/app/models/nexus-core.onnx" # When uploaded to models/ ] model_path = None for path in possible_paths: if os.path.exists(path): model_path = path logger.info(f"✅ Found model at: {path}") break if not model_path: logger.error("❌ Model not found in any expected location") logger.error(f"Checked paths: {possible_paths}") # List all .onnx files for root, dirs, files in os.walk("/app"): for file in files: if file.endswith('.onnx'): logger.error(f"Found .onnx at: {os.path.join(root, file)}") raise FileNotFoundError("Model not found") try: engine = NexusCoreEngine(model_path=model_path, num_threads=2) logger.info("✅ Engine loaded!") except Exception as e: logger.error(f"❌ Failed: {e}", exc_info=True) 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"} @app.post("/get-move", response_model=MoveResponse) async def get_move(request: MoveRequest): if not engine: raise HTTPException(503, "Not loaded") if not engine.validate_fen(request.fen): raise HTTPException(400, "Invalid FEN") start = time.time() try: result = engine.get_best_move(request.fen, request.depth, request.time_limit) logger.info(f"✓ {result['best_move']} | {result['evaluation']:+.2f} | {result['time_taken']}ms") return MoveResponse(**result) except Exception as e: logger.error(f"Error: {e}", exc_info=True) raise HTTPException(500, str(e)) @app.get("/") async def root(): return {"name": "Nexus-Core", "version": "2.0.0", "status": "online" if engine else "starting"} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=7860, log_level="info")