Rafs-an09002 commited on
Commit
e2a8333
·
verified ·
1 Parent(s): 43a67ce

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -56
app.py CHANGED
@@ -1,7 +1,6 @@
1
  """
2
- Synapse-Base Inference API
3
- FastAPI server for chess move prediction
4
- Optimized for HF Spaces CPU environment
5
  """
6
 
7
  from fastapi import FastAPI, HTTPException
@@ -9,7 +8,7 @@ from fastapi.middleware.cors import CORSMiddleware
9
  from pydantic import BaseModel, Field
10
  import time
11
  import logging
12
- from typing import Optional
13
 
14
  from engine import SynapseEngine
15
 
@@ -20,30 +19,30 @@ logging.basicConfig(
20
  )
21
  logger = logging.getLogger(__name__)
22
 
23
- # Initialize FastAPI app
24
  app = FastAPI(
25
  title="Synapse-Base Inference API",
26
- description="High-performance chess engine powered by 38M parameter neural network",
27
  version="3.0.0"
28
  )
29
 
30
- # CORS middleware (allow your frontend domain)
31
  app.add_middleware(
32
  CORSMiddleware,
33
- allow_origins=["*"], # Change to your domain in production
34
  allow_credentials=True,
35
  allow_methods=["*"],
36
  allow_headers=["*"],
37
  )
38
 
39
- # Global engine instance (loaded once at startup)
40
  engine = None
41
 
42
 
43
- # Request/Response models
44
  class MoveRequest(BaseModel):
45
  fen: str = Field(..., description="Board position in FEN notation")
46
- depth: Optional[int] = Field(3, ge=1, le=5, description="Search depth (1-5)")
47
  time_limit: Optional[int] = Field(5000, ge=1000, le=30000, description="Time limit in ms")
48
 
49
 
@@ -51,131 +50,114 @@ class MoveResponse(BaseModel):
51
  best_move: str
52
  evaluation: float
53
  depth_searched: int
 
54
  nodes_evaluated: int
55
  time_taken: int
56
- pv: Optional[list] = None # Principal variation
 
 
57
 
58
 
59
  class HealthResponse(BaseModel):
60
  status: str
61
  model_loaded: bool
62
  version: str
 
63
 
64
 
65
- # Startup event
66
  @app.on_event("startup")
67
  async def startup_event():
68
- """Load model on startup"""
69
  global engine
70
 
71
- logger.info("🚀 Starting Synapse-Base Inference API...")
72
 
73
  try:
74
  engine = SynapseEngine(
75
  model_path="/app/models/synapse_base.onnx",
76
- num_threads=2 # Match HF Spaces 2 vCPU
77
  )
78
- logger.info("✅ Model loaded successfully")
79
- logger.info(f"📊 Model size: {engine.get_model_size():.2f} MB")
80
 
81
  except Exception as e:
82
- logger.error(f"❌ Failed to load model: {e}")
83
  raise
84
 
85
 
86
- # Health check endpoint
87
  @app.get("/health", response_model=HealthResponse)
88
  async def health_check():
89
- """Health check endpoint"""
90
  return {
91
  "status": "healthy" if engine is not None else "unhealthy",
92
  "model_loaded": engine is not None,
93
- "version": "3.0.0"
 
94
  }
95
 
96
 
97
- # Main inference endpoint
98
  @app.post("/get-move", response_model=MoveResponse)
99
  async def get_move(request: MoveRequest):
100
- """
101
- Get best move for given position
102
-
103
- Args:
104
- request: MoveRequest with FEN, depth, and time_limit
105
-
106
- Returns:
107
- MoveResponse with best_move and evaluation
108
- """
109
-
110
  if engine is None:
111
- raise HTTPException(status_code=503, detail="Model not loaded")
112
 
113
- # Validate FEN
114
  if not engine.validate_fen(request.fen):
115
  raise HTTPException(status_code=400, detail="Invalid FEN string")
116
 
117
- # Start timing
118
  start_time = time.time()
119
 
120
  try:
121
- # Get best move from engine
122
  result = engine.get_best_move(
123
  fen=request.fen,
124
  depth=request.depth,
125
  time_limit=request.time_limit
126
  )
127
 
128
- # Calculate time taken
129
  time_taken = int((time.time() - start_time) * 1000)
130
 
131
- # Log request
132
  logger.info(
133
  f"Move: {result['best_move']} | "
134
- f"Eval: {result['evaluation']:.3f} | "
135
- f"Depth: {result['depth_searched']} | "
136
  f"Nodes: {result['nodes_evaluated']} | "
137
- f"Time: {time_taken}ms"
 
138
  )
139
 
140
  return MoveResponse(
141
  best_move=result['best_move'],
142
  evaluation=result['evaluation'],
143
  depth_searched=result['depth_searched'],
 
144
  nodes_evaluated=result['nodes_evaluated'],
145
  time_taken=time_taken,
146
- pv=result.get('pv', None)
 
 
147
  )
148
 
149
  except Exception as e:
150
- logger.error(f"Error processing move: {e}")
151
  raise HTTPException(status_code=500, detail=str(e))
152
 
153
 
154
- # Root endpoint
155
  @app.get("/")
156
  async def root():
157
- """Root endpoint with API info"""
158
  return {
159
  "name": "Synapse-Base Inference API",
160
  "version": "3.0.0",
161
  "model": "38.1M parameters",
162
  "architecture": "CNN-Transformer Hybrid",
 
163
  "endpoints": {
164
- "POST /get-move": "Get best move for position",
165
  "GET /health": "Health check",
166
  "GET /docs": "API documentation"
167
  }
168
  }
169
 
170
 
171
- # Run server
172
  if __name__ == "__main__":
173
  import uvicorn
174
-
175
- uvicorn.run(
176
- app,
177
- host="0.0.0.0",
178
- port=7860,
179
- log_level="info",
180
- access_log=True
181
- )
 
1
  """
2
+ Synapse-Base Inference API (Updated)
3
+ State-of-the-art search engine with modular architecture
 
4
  """
5
 
6
  from fastapi import FastAPI, HTTPException
 
8
  from pydantic import BaseModel, Field
9
  import time
10
  import logging
11
+ from typing import Optional, List
12
 
13
  from engine import SynapseEngine
14
 
 
19
  )
20
  logger = logging.getLogger(__name__)
21
 
22
+ # Initialize FastAPI
23
  app = FastAPI(
24
  title="Synapse-Base Inference API",
25
+ description="State-of-the-art chess engine with neural evaluation",
26
  version="3.0.0"
27
  )
28
 
29
+ # CORS
30
  app.add_middleware(
31
  CORSMiddleware,
32
+ allow_origins=["*"],
33
  allow_credentials=True,
34
  allow_methods=["*"],
35
  allow_headers=["*"],
36
  )
37
 
38
+ # Global engine
39
  engine = None
40
 
41
 
42
+ # Models
43
  class MoveRequest(BaseModel):
44
  fen: str = Field(..., description="Board position in FEN notation")
45
+ depth: Optional[int] = Field(5, ge=1, le=10, description="Search depth (1-10)")
46
  time_limit: Optional[int] = Field(5000, ge=1000, le=30000, description="Time limit in ms")
47
 
48
 
 
50
  best_move: str
51
  evaluation: float
52
  depth_searched: int
53
+ seldepth: int
54
  nodes_evaluated: int
55
  time_taken: int
56
+ nps: int
57
+ pv: List[str]
58
+ tt_hit_rate: Optional[float] = None
59
 
60
 
61
  class HealthResponse(BaseModel):
62
  status: str
63
  model_loaded: bool
64
  version: str
65
+ model_size_mb: Optional[float] = None
66
 
67
 
68
+ # Startup
69
  @app.on_event("startup")
70
  async def startup_event():
 
71
  global engine
72
 
73
+ logger.info("🚀 Starting Synapse-Base Inference API v3.0...")
74
 
75
  try:
76
  engine = SynapseEngine(
77
  model_path="/app/models/synapse_base.onnx",
78
+ num_threads=2
79
  )
80
+ logger.info("✅ Engine loaded successfully")
 
81
 
82
  except Exception as e:
83
+ logger.error(f"❌ Failed to load engine: {e}")
84
  raise
85
 
86
 
87
+ # Health check
88
  @app.get("/health", response_model=HealthResponse)
89
  async def health_check():
 
90
  return {
91
  "status": "healthy" if engine is not None else "unhealthy",
92
  "model_loaded": engine is not None,
93
+ "version": "3.0.0",
94
+ "model_size_mb": engine.get_model_size() if engine else None
95
  }
96
 
97
 
98
+ # Main endpoint
99
  @app.post("/get-move", response_model=MoveResponse)
100
  async def get_move(request: MoveRequest):
 
 
 
 
 
 
 
 
 
 
101
  if engine is None:
102
+ raise HTTPException(status_code=503, detail="Engine not loaded")
103
 
 
104
  if not engine.validate_fen(request.fen):
105
  raise HTTPException(status_code=400, detail="Invalid FEN string")
106
 
 
107
  start_time = time.time()
108
 
109
  try:
 
110
  result = engine.get_best_move(
111
  fen=request.fen,
112
  depth=request.depth,
113
  time_limit=request.time_limit
114
  )
115
 
 
116
  time_taken = int((time.time() - start_time) * 1000)
117
 
 
118
  logger.info(
119
  f"Move: {result['best_move']} | "
120
+ f"Eval: {result['evaluation']:+.2f} | "
121
+ f"Depth: {result['depth_searched']}/{result['seldepth']} | "
122
  f"Nodes: {result['nodes_evaluated']} | "
123
+ f"Time: {time_taken}ms | "
124
+ f"NPS: {result['nps']}"
125
  )
126
 
127
  return MoveResponse(
128
  best_move=result['best_move'],
129
  evaluation=result['evaluation'],
130
  depth_searched=result['depth_searched'],
131
+ seldepth=result['seldepth'],
132
  nodes_evaluated=result['nodes_evaluated'],
133
  time_taken=time_taken,
134
+ nps=result['nps'],
135
+ pv=result['pv'],
136
+ tt_hit_rate=result['tt_stats']['hit_rate']
137
  )
138
 
139
  except Exception as e:
140
+ logger.error(f"Error: {e}")
141
  raise HTTPException(status_code=500, detail=str(e))
142
 
143
 
144
+ # Root
145
  @app.get("/")
146
  async def root():
 
147
  return {
148
  "name": "Synapse-Base Inference API",
149
  "version": "3.0.0",
150
  "model": "38.1M parameters",
151
  "architecture": "CNN-Transformer Hybrid",
152
+ "search": "PVS + NMP + LMR + TT",
153
  "endpoints": {
154
+ "POST /get-move": "Get best move",
155
  "GET /health": "Health check",
156
  "GET /docs": "API documentation"
157
  }
158
  }
159
 
160
 
 
161
  if __name__ == "__main__":
162
  import uvicorn
163
+ uvicorn.run(app, host="0.0.0.0", port=7860, log_level="info")