Amogh1221 commited on
Commit
a4f3f5f
·
verified ·
1 Parent(s): a5f4b08

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +36 -0
  2. main.py +98 -0
  3. src.zip +3 -0
Dockerfile ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.12 slim for smaller image
2
+ FROM python:3.12-slim
3
+
4
+ # Install compilation tools and dependencies
5
+ RUN apt-get update && apt-get install -y \
6
+ build-essential \
7
+ make \
8
+ g++ \
9
+ wget \
10
+ git \
11
+ && rm -rf /var/lib/apt/lists/*
12
+
13
+ # Set working directory
14
+ WORKDIR /app
15
+
16
+ # Copy the whole repository (to build the engine)
17
+ COPY . .
18
+
19
+ # Build the C++ Engine
20
+ WORKDIR /app/engine/src
21
+ RUN make -j$(nproc) build ARCH=x86-64-sse41-popcnt
22
+ RUN mv stockfish /app/engine/deepcastle
23
+
24
+ # Copy NNUE (It should be in the engine/ folder in the host)
25
+ # If it's missing, you can add a wget command here to download it from a URL.
26
+ # COPY ../engine/output.nnue /app/engine/output.nnue
27
+
28
+ # Setup Python environment
29
+ WORKDIR /app/server
30
+ RUN pip install --no-cache-dir fastapi uvicorn python-chess pydantic
31
+
32
+ # Expose Hugging Face mandatory port
33
+ EXPOSE 7860
34
+
35
+ # Run FastAPI on 0.0.0.0:7860 (Hugging Face default)
36
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
main.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from pydantic import BaseModel
4
+ import os
5
+ import chess
6
+ import chess.engine
7
+ import asyncio
8
+ from typing import Optional
9
+
10
+ app = FastAPI(title="Deepcastle v7 Engine API")
11
+
12
+ # Allow ALL for easy testing (we can restrict this later if needed)
13
+ app.add_middleware(
14
+ CORSMiddleware,
15
+ allow_origins=["*"],
16
+ allow_methods=["*"],
17
+ allow_headers=["*"],
18
+ )
19
+
20
+ # Paths relative to the Docker container
21
+ ENGINE_PATH = os.environ.get("ENGINE_PATH", "/app/engine/deepcastle")
22
+ NNUE_PATH = os.environ.get("NNUE_PATH", "/app/engine/output.nnue")
23
+
24
+ class MoveRequest(BaseModel):
25
+ fen: str
26
+ time: float = 1.0 # seconds
27
+ depth: Optional[int] = None
28
+
29
+ class MoveResponse(BaseModel):
30
+ bestmove: str
31
+ score: float
32
+ depth: int
33
+ nodes: int
34
+ nps: int
35
+ pv: str
36
+
37
+ @app.get("/")
38
+ def home():
39
+ return {"status": "online", "engine": "Deepcastle v7 Hybrid Neural", "platform": "Hugging Face Spaces"}
40
+
41
+ @app.get("/health")
42
+ def health():
43
+ if not os.path.exists(ENGINE_PATH):
44
+ return {"status": "error", "message": "Engine binary not found"}
45
+ return {"status": "ok", "engine": "Deepcastle v7"}
46
+
47
+ @app.post("/move", response_model=MoveResponse)
48
+ async def get_move(request: MoveRequest):
49
+ if not os.path.exists(ENGINE_PATH):
50
+ raise HTTPException(status_code=500, detail="Engine binary not found")
51
+
52
+ try:
53
+ # Start Engine
54
+ transport, engine = await chess.engine.popen_uci(ENGINE_PATH)
55
+
56
+ # Configure NNUE
57
+ if os.path.exists(NNUE_PATH):
58
+ await engine.configure({"EvalFile": NNUE_PATH})
59
+ # Optimization for server environment
60
+ await engine.configure({"Hash": 512, "Threads": 2})
61
+
62
+ board = chess.Board(request.fen)
63
+
64
+ # ANALYSIS FOR STATS + BEST MOVE
65
+ limit = chess.engine.Limit(time=request.time, depth=request.depth)
66
+
67
+ # Get result
68
+ result = await engine.play(board, limit)
69
+
70
+ # Get info for stats (analysing briefly to get score/pv)
71
+ info_list = await engine.analyse(board, limit)
72
+ info = info_list # analyse returns a list in async context if using multipv, but simple by default
73
+
74
+ # Extract stats
75
+ score = info["score"].relative.score(mate_score=10000) / 100.0 if "score" in info else 0.0
76
+ depth = info.get("depth", 0)
77
+ nodes = info.get("nodes", 0)
78
+ nps = info.get("nps", 0)
79
+ pv = " ".join([board.san(m) for m in info.get("pv", [])[:5]])
80
+
81
+ await engine.quit()
82
+
83
+ return MoveResponse(
84
+ bestmove=result.move.uci(),
85
+ score=score,
86
+ depth=depth,
87
+ nodes=nodes,
88
+ nps=nps,
89
+ pv=pv
90
+ )
91
+ except Exception as e:
92
+ print(f"Error: {e}")
93
+ raise HTTPException(status_code=500, detail=str(e))
94
+
95
+ if __name__ == "__main__":
96
+ import uvicorn
97
+ # Hugging Face Spaces port is 7860
98
+ uvicorn.run(app, host="0.0.0.0", port=7860)
src.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2a67b4ccdc7a179506f33641de77ef2e70448c151ec439385075cce4b3dadb4c
3
+ size 260583