Rafs-an09002 commited on
Commit
5bf0029
Β·
verified Β·
1 Parent(s): c970b1d

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +254 -0
  2. readme.md +53 -0
  3. requirements.txt +9 -0
app.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Nexus-Nano Inference API
3
+ Ultra-lightweight single-file engine
4
+ No modular architecture - pure speed optimization
5
+ """
6
+
7
+ from fastapi import FastAPI, HTTPException
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ from pydantic import BaseModel, Field
10
+ import onnxruntime as ort
11
+ import numpy as np
12
+ import chess
13
+ import time
14
+ import logging
15
+ from pathlib import Path
16
+ from typing import Optional, Tuple
17
+
18
+ logging.basicConfig(level=logging.INFO)
19
+ logger = logging.getLogger(__name__)
20
+
21
+ # ==================== NANO ENGINE (Single File) ====================
22
+
23
+ class NexusNanoEngine:
24
+ """
25
+ Ultra-lightweight chess engine
26
+ Pure alpha-beta, no cache, minimal overhead
27
+ """
28
+
29
+ PIECE_VALUES = {
30
+ chess.PAWN: 1, chess.KNIGHT: 3, chess.BISHOP: 3,
31
+ chess.ROOK: 5, chess.QUEEN: 9, chess.KING: 0
32
+ }
33
+
34
+ def __init__(self, model_path: str):
35
+ sess_options = ort.SessionOptions()
36
+ sess_options.intra_op_num_threads = 2
37
+ sess_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
38
+
39
+ self.session = ort.InferenceSession(
40
+ model_path,
41
+ sess_options=sess_options,
42
+ providers=['CPUExecutionProvider']
43
+ )
44
+
45
+ self.input_name = self.session.get_inputs()[0].name
46
+ self.output_name = self.session.get_outputs()[0].name
47
+ self.nodes = 0
48
+
49
+ logger.info("βœ… Nexus-Nano loaded")
50
+
51
+ def fen_to_tensor(self, fen: str) -> np.ndarray:
52
+ board = chess.Board(fen)
53
+ tensor = np.zeros((1, 12, 8, 8), dtype=np.float32)
54
+
55
+ piece_map = {
56
+ chess.PAWN: 0, chess.KNIGHT: 1, chess.BISHOP: 2,
57
+ chess.ROOK: 3, chess.QUEEN: 4, chess.KING: 5
58
+ }
59
+
60
+ for sq, piece in board.piece_map().items():
61
+ r, f = divmod(sq, 8)
62
+ ch = piece_map[piece.piece_type] + (6 if piece.color == chess.BLACK else 0)
63
+ tensor[0, ch, r, f] = 1.0
64
+
65
+ return tensor
66
+
67
+ def evaluate(self, board: chess.Board) -> float:
68
+ self.nodes += 1
69
+ tensor = self.fen_to_tensor(board.fen())
70
+ output = self.session.run([self.output_name], {self.input_name: tensor})
71
+ score = float(output[0][0][0]) * 400.0
72
+ return -score if board.turn == chess.BLACK else score
73
+
74
+ def order_moves(self, board: chess.Board, moves):
75
+ """Simple MVV-LVA ordering"""
76
+ scored = []
77
+ for m in moves:
78
+ s = 0
79
+ if board.is_capture(m):
80
+ v = board.piece_at(m.to_square)
81
+ a = board.piece_at(m.from_square)
82
+ if v and a:
83
+ s = self.PIECE_VALUES.get(v.piece_type, 0) * 10
84
+ s -= self.PIECE_VALUES.get(a.piece_type, 0)
85
+ if m.promotion == chess.QUEEN:
86
+ s += 90
87
+ scored.append((s, m))
88
+ scored.sort(key=lambda x: x[0], reverse=True)
89
+ return [m for _, m in scored]
90
+
91
+ def alpha_beta(
92
+ self,
93
+ board: chess.Board,
94
+ depth: int,
95
+ alpha: float,
96
+ beta: float
97
+ ) -> Tuple[float, Optional[chess.Move]]:
98
+
99
+ if board.is_game_over():
100
+ return (-10000 if board.is_checkmate() else 0), None
101
+
102
+ if depth == 0:
103
+ return self.evaluate(board), None
104
+
105
+ moves = list(board.legal_moves)
106
+ if not moves:
107
+ return 0, None
108
+
109
+ moves = self.order_moves(board, moves)
110
+
111
+ best_move = moves[0]
112
+ best_score = float('-inf')
113
+
114
+ for move in moves:
115
+ board.push(move)
116
+ score, _ = self.alpha_beta(board, depth - 1, -beta, -alpha)
117
+ score = -score
118
+ board.pop()
119
+
120
+ if score > best_score:
121
+ best_score = score
122
+ best_move = move
123
+
124
+ alpha = max(alpha, score)
125
+ if alpha >= beta:
126
+ break
127
+
128
+ return best_score, best_move
129
+
130
+ def search(self, fen: str, depth: int = 3):
131
+ board = chess.Board(fen)
132
+ self.nodes = 0
133
+
134
+ moves = list(board.legal_moves)
135
+ if len(moves) == 0:
136
+ return {'best_move': '0000', 'evaluation': 0.0, 'nodes': 0}
137
+ if len(moves) == 1:
138
+ return {
139
+ 'best_move': moves[0].uci(),
140
+ 'evaluation': round(self.evaluate(board) / 100.0, 2),
141
+ 'nodes': 1
142
+ }
143
+
144
+ best_move = moves[0]
145
+ best_score = float('-inf')
146
+
147
+ for d in range(1, depth + 1):
148
+ try:
149
+ score, move = self.alpha_beta(board, d, float('-inf'), float('inf'))
150
+ if move:
151
+ best_move = move
152
+ best_score = score
153
+ except:
154
+ break
155
+
156
+ return {
157
+ 'best_move': best_move.uci(),
158
+ 'evaluation': round(best_score / 100.0, 2),
159
+ 'depth': d,
160
+ 'nodes': self.nodes
161
+ }
162
+
163
+
164
+ # ==================== FASTAPI APP ====================
165
+
166
+ app = FastAPI(
167
+ title="Nexus-Nano API",
168
+ description="Ultra-lightweight chess engine",
169
+ version="1.0.0"
170
+ )
171
+
172
+ app.add_middleware(
173
+ CORSMiddleware,
174
+ allow_origins=["*"],
175
+ allow_credentials=True,
176
+ allow_methods=["*"],
177
+ allow_headers=["*"],
178
+ )
179
+
180
+ engine = None
181
+
182
+
183
+ class MoveRequest(BaseModel):
184
+ fen: str
185
+ depth: Optional[int] = Field(3, ge=1, le=5)
186
+
187
+
188
+ class MoveResponse(BaseModel):
189
+ best_move: str
190
+ evaluation: float
191
+ depth_searched: int
192
+ nodes_evaluated: int
193
+ time_taken: int
194
+
195
+
196
+ @app.on_event("startup")
197
+ async def startup():
198
+ global engine
199
+ logger.info("πŸš€ Starting Nexus-Nano...")
200
+ try:
201
+ engine = NexusNanoEngine("/app/models/nexus_nano.onnx")
202
+ except Exception as e:
203
+ logger.error(f"❌ Failed: {e}")
204
+ raise
205
+
206
+
207
+ @app.get("/health")
208
+ async def health():
209
+ return {"status": "healthy", "model": "nexus-nano", "version": "1.0.0"}
210
+
211
+
212
+ @app.post("/get-move", response_model=MoveResponse)
213
+ async def get_move(req: MoveRequest):
214
+ if not engine:
215
+ raise HTTPException(503, "Not loaded")
216
+
217
+ try:
218
+ chess.Board(req.fen)
219
+ except:
220
+ raise HTTPException(400, "Invalid FEN")
221
+
222
+ start = time.time()
223
+ result = engine.search(req.fen, req.depth)
224
+ elapsed = int((time.time() - start) * 1000)
225
+
226
+ logger.info(
227
+ f"Move: {result['best_move']} | "
228
+ f"Eval: {result['evaluation']:+.2f} | "
229
+ f"Nodes: {result['nodes']} | "
230
+ f"Time: {elapsed}ms"
231
+ )
232
+
233
+ return MoveResponse(
234
+ best_move=result['best_move'],
235
+ evaluation=result['evaluation'],
236
+ depth_searched=result['depth'],
237
+ nodes_evaluated=result['nodes'],
238
+ time_taken=elapsed
239
+ )
240
+
241
+
242
+ @app.get("/")
243
+ async def root():
244
+ return {
245
+ "name": "Nexus-Nano API",
246
+ "version": "1.0.0",
247
+ "model": "2.8M parameters",
248
+ "speed": "Lightning-fast"
249
+ }
250
+
251
+
252
+ if __name__ == "__main__":
253
+ import uvicorn
254
+ uvicorn.run(app, host="0.0.0.0", port=7860)
readme.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Nexus-Nano Inference API
3
+ emoji: πŸš€
4
+ colorFrom: yellow
5
+ colorTo: red
6
+ sdk: docker
7
+ pinned: false
8
+ license: cc-by-nc-4.0
9
+ ---
10
+
11
+ # πŸš€ Nexus-Nano Inference API
12
+
13
+ Ultra-lightweight chess engine for instant responses.
14
+
15
+ ## 🎯 Model Info
16
+
17
+ - **Parameters:** 2.8M (Compact ResNet)
18
+ - **Speed:** Lightning-fast (~0.2-0.5s per move)
19
+ - **Strength:** ~1800-2000 ELO
20
+ - **Architecture:** Pure CNN value network
21
+
22
+ ## πŸ“‘ API Endpoint
23
+
24
+ ### `POST /get-move`
25
+
26
+ **Request:**
27
+ ```json
28
+ {
29
+ "fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
30
+ "depth": 3
31
+ }
32
+ ```
33
+
34
+ **Response:**
35
+ ```json
36
+ {
37
+ "best_move": "e2e4",
38
+ "evaluation": 0.18,
39
+ "depth_searched": 3,
40
+ "nodes_evaluated": 2847,
41
+ "time_taken": 234
42
+ }
43
+ ```
44
+
45
+ ## πŸ’» Performance
46
+
47
+ - **Average Response:** 0.2-0.5 seconds @ depth 3
48
+ - **Memory Usage:** ~1GB RAM
49
+ - **Perfect for:** Rapid games, mobile apps, tutorials
50
+
51
+ ---
52
+
53
+ Part of GambitFlow AI Suite ⚑
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ # Nexus-Nano Minimal Dependencies
2
+
3
+ fastapi==0.109.0
4
+ uvicorn[standard]==0.27.0
5
+ onnxruntime==1.17.0
6
+ python-chess==1.999
7
+ numpy==1.24.3
8
+ huggingface-hub==0.20.3
9
+ pydantic==2.5.3