Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
|
@@ -14,6 +14,7 @@ app = FastAPI(title="Deepcastle Engine API")
|
|
| 14 |
# βββ Multiplaying / Challenge Manager ββββββββββββββββββββββββββββββββββββββββββ
|
| 15 |
class ConnectionManager:
|
| 16 |
def __init__(self):
|
|
|
|
| 17 |
self.active_connections: Dict[str, List[WebSocket]] = {}
|
| 18 |
|
| 19 |
async def connect(self, websocket: WebSocket, match_id: str):
|
|
@@ -73,7 +74,6 @@ DEEPCASTLE_ENGINE_PATH = os.environ.get(
|
|
| 73 |
"DEEPCASTLE_ENGINE_PATH",
|
| 74 |
os.environ.get("ENGINE_PATH", "/app/engine_bin/deepcastle"),
|
| 75 |
)
|
| 76 |
-
STOCKFISH_ENGINE_PATH = os.environ.get("STOCKFISH_ENGINE_PATH", "/usr/games/stockfish")
|
| 77 |
NNUE_PATH = os.environ.get("NNUE_PATH", "/app/engine_bin/output.nnue")
|
| 78 |
NNUE_SMALL_PATH = os.environ.get("NNUE_SMALL_PATH", "/app/engine_bin/small_output.nnue")
|
| 79 |
|
|
@@ -120,32 +120,23 @@ def home():
|
|
| 120 |
|
| 121 |
@app.get("/health")
|
| 122 |
def health():
|
| 123 |
-
missing = []
|
| 124 |
if not os.path.exists(DEEPCASTLE_ENGINE_PATH):
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
missing.append("stockfish")
|
| 128 |
-
if missing:
|
| 129 |
-
return {"status": "error", "message": f"Missing engine binary: {', '.join(missing)}"}
|
| 130 |
-
return {"status": "ok", "engines": ["deepcastle", "stockfish"]}
|
| 131 |
|
| 132 |
# Global engine instances to save memory and improve performance
|
| 133 |
_GLOBAL_DEEPCASTLE_ENGINE = None
|
| 134 |
-
_GLOBAL_STOCKFISH_ENGINE = None
|
| 135 |
|
| 136 |
async def _get_or_start_engine(engine_path: str, *, role: str, options: Optional[dict] = None):
|
| 137 |
-
global _GLOBAL_DEEPCASTLE_ENGINE
|
| 138 |
|
| 139 |
-
current_engine = _GLOBAL_DEEPCASTLE_ENGINE
|
| 140 |
if current_engine is not None:
|
| 141 |
try:
|
| 142 |
if not current_engine.is_terminated():
|
| 143 |
return current_engine
|
| 144 |
except Exception:
|
| 145 |
-
|
| 146 |
-
_GLOBAL_DEEPCASTLE_ENGINE = None
|
| 147 |
-
else:
|
| 148 |
-
_GLOBAL_STOCKFISH_ENGINE = None
|
| 149 |
|
| 150 |
if not os.path.exists(engine_path):
|
| 151 |
raise HTTPException(status_code=500, detail=f"{role} binary NOT FOUND at {engine_path}")
|
|
@@ -158,28 +149,25 @@ async def _get_or_start_engine(engine_path: str, *, role: str, options: Optional
|
|
| 158 |
if options:
|
| 159 |
await engine.configure(options)
|
| 160 |
|
| 161 |
-
if
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
print(f"[WARNING] DeepCastle big net not found at {NNUE_PATH}")
|
| 170 |
-
|
| 171 |
-
if os.path.exists(NNUE_SMALL_PATH):
|
| 172 |
-
try:
|
| 173 |
-
await engine.configure({"EvalFileSmall": NNUE_SMALL_PATH})
|
| 174 |
-
print("[DEBUG] DeepCastle small net loaded successfully.")
|
| 175 |
-
except Exception as ne:
|
| 176 |
-
print(f"[ERROR] DeepCastle small net load failed: {str(ne)}")
|
| 177 |
-
else:
|
| 178 |
-
print(f"[WARNING] DeepCastle small net not found at {NNUE_SMALL_PATH}")
|
| 179 |
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
else:
|
| 182 |
-
|
|
|
|
|
|
|
| 183 |
|
| 184 |
return engine
|
| 185 |
except Exception as e:
|
|
@@ -201,11 +189,8 @@ async def get_deepcastle_engine():
|
|
| 201 |
)
|
| 202 |
|
| 203 |
async def get_stockfish_engine():
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
role="stockfish",
|
| 207 |
-
options={"Hash": 128, "Threads": 1},
|
| 208 |
-
)
|
| 209 |
|
| 210 |
def get_normalized_score(info) -> tuple[float, Optional[int]]:
|
| 211 |
"""Returns the score from White's perspective in centipawns."""
|
|
|
|
| 14 |
# βββ Multiplaying / Challenge Manager ββββββββββββββββββββββββββββββββββββββββββ
|
| 15 |
class ConnectionManager:
|
| 16 |
def __init__(self):
|
| 17 |
+
# match_id -> list of websockets
|
| 18 |
self.active_connections: Dict[str, List[WebSocket]] = {}
|
| 19 |
|
| 20 |
async def connect(self, websocket: WebSocket, match_id: str):
|
|
|
|
| 74 |
"DEEPCASTLE_ENGINE_PATH",
|
| 75 |
os.environ.get("ENGINE_PATH", "/app/engine_bin/deepcastle"),
|
| 76 |
)
|
|
|
|
| 77 |
NNUE_PATH = os.environ.get("NNUE_PATH", "/app/engine_bin/output.nnue")
|
| 78 |
NNUE_SMALL_PATH = os.environ.get("NNUE_SMALL_PATH", "/app/engine_bin/small_output.nnue")
|
| 79 |
|
|
|
|
| 120 |
|
| 121 |
@app.get("/health")
|
| 122 |
def health():
|
|
|
|
| 123 |
if not os.path.exists(DEEPCASTLE_ENGINE_PATH):
|
| 124 |
+
return {"status": "error", "message": "Missing engine binary: deepcastle"}
|
| 125 |
+
return {"status": "ok", "engine": "deepcastle"}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
|
| 127 |
# Global engine instances to save memory and improve performance
|
| 128 |
_GLOBAL_DEEPCASTLE_ENGINE = None
|
|
|
|
| 129 |
|
| 130 |
async def _get_or_start_engine(engine_path: str, *, role: str, options: Optional[dict] = None):
|
| 131 |
+
global _GLOBAL_DEEPCASTLE_ENGINE
|
| 132 |
|
| 133 |
+
current_engine = _GLOBAL_DEEPCASTLE_ENGINE
|
| 134 |
if current_engine is not None:
|
| 135 |
try:
|
| 136 |
if not current_engine.is_terminated():
|
| 137 |
return current_engine
|
| 138 |
except Exception:
|
| 139 |
+
_GLOBAL_DEEPCASTLE_ENGINE = None
|
|
|
|
|
|
|
|
|
|
| 140 |
|
| 141 |
if not os.path.exists(engine_path):
|
| 142 |
raise HTTPException(status_code=500, detail=f"{role} binary NOT FOUND at {engine_path}")
|
|
|
|
| 149 |
if options:
|
| 150 |
await engine.configure(options)
|
| 151 |
|
| 152 |
+
if os.path.exists(NNUE_PATH):
|
| 153 |
+
try:
|
| 154 |
+
await engine.configure({"EvalFile": NNUE_PATH})
|
| 155 |
+
print("[DEBUG] DeepCastle big net loaded successfully.")
|
| 156 |
+
except Exception as ne:
|
| 157 |
+
print(f"[ERROR] DeepCastle big net load failed: {str(ne)}")
|
| 158 |
+
else:
|
| 159 |
+
print(f"[WARNING] DeepCastle big net not found at {NNUE_PATH}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
+
if os.path.exists(NNUE_SMALL_PATH):
|
| 162 |
+
try:
|
| 163 |
+
await engine.configure({"EvalFileSmall": NNUE_SMALL_PATH})
|
| 164 |
+
print("[DEBUG] DeepCastle small net loaded successfully.")
|
| 165 |
+
except Exception as ne:
|
| 166 |
+
print(f"[ERROR] DeepCastle small net load failed: {str(ne)}")
|
| 167 |
else:
|
| 168 |
+
print(f"[WARNING] DeepCastle small net not found at {NNUE_SMALL_PATH}")
|
| 169 |
+
|
| 170 |
+
_GLOBAL_DEEPCASTLE_ENGINE = engine
|
| 171 |
|
| 172 |
return engine
|
| 173 |
except Exception as e:
|
|
|
|
| 189 |
)
|
| 190 |
|
| 191 |
async def get_stockfish_engine():
|
| 192 |
+
# Compatibility alias: analysis now also uses DeepCastle.
|
| 193 |
+
return await get_deepcastle_engine()
|
|
|
|
|
|
|
|
|
|
| 194 |
|
| 195 |
def get_normalized_score(info) -> tuple[float, Optional[int]]:
|
| 196 |
"""Returns the score from White's perspective in centipawns."""
|