Narendra9009 commited on
Commit
19ece66
·
2 Parent(s): 04aa7ca d1fd5c0

mergedd getFen

Browse files
.gitattributes ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ *.pt filter=lfs diff=lfs merge=lfs -text
2
+ *.exe filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ api_tokens
Dockerfile ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9
2
+
3
+ # Set the working directory in the container
4
+ WORKDIR /app
5
+
6
+ COPY requirements.txt .
7
+ RUN pip install --no-cache-dir -r requirements.txt
8
+
9
+ # Copy everything from the current directory to the container
10
+ COPY . .
11
+
12
+ EXPOSE 7860
13
+
14
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
__pycache__/main.cpython-311.pyc DELETED
Binary file (7.24 kB)
 
__pycache__/main.cpython-313.pyc ADDED
Binary file (5.26 kB). View file
 
assets/openings_master.csv ADDED
The diff for this file is too large to render. See raw diff
 
main.py CHANGED
@@ -1,12 +1,24 @@
1
  import io
 
 
2
  from fastapi import FastAPI, File, UploadFile, Form
3
  from fastapi.responses import JSONResponse, StreamingResponse
4
  from PIL import Image, UnidentifiedImageError
5
  from routes.segmentation import segment_chess_board
6
  from routes.detection import detect_pieces
7
  from routes.fen_generator import gen_fen
 
8
  from typing import List, Dict, Any, Union
9
  from pydantic import BaseModel
 
 
 
 
 
 
 
 
 
10
 
11
  app = FastAPI()
12
 
@@ -15,76 +27,13 @@ class DetectionResults(BaseModel):
15
  confidences: list
16
  classes: list
17
 
18
- @app.get("/")
19
  async def read_root():
20
  return {
21
  "name": "Narendra",
22
  "age": 20,
23
  "Gender": "Male"
24
  }
25
-
26
- @app.post("/getSeg")
27
- async def get_seg(file: UploadFile = File(...)):
28
- print(f'Image received: {file.filename}')
29
-
30
- try:
31
- image_content = await file.read()
32
- if not image_content:
33
- return JSONResponse(content={"error": "Empty file uploaded"}, status_code=400)
34
-
35
- try:
36
- image = Image.open(io.BytesIO(image_content))
37
- except UnidentifiedImageError:
38
- return JSONResponse(content={"error": "Invalid image format"}, status_code=400)
39
-
40
- # If segment_chess_board is async, use `await`, otherwise remove `await`
41
- segmented_image = await segment_chess_board(image)
42
-
43
- if isinstance(segmented_image, dict):
44
- return JSONResponse(content=segmented_image, status_code=400)
45
-
46
- # Save to in-memory bytes
47
- img_bytes = io.BytesIO()
48
- segmented_image.save(img_bytes, format="PNG")
49
- img_bytes.seek(0)
50
-
51
- print("Image successfully processed and returned")
52
- return StreamingResponse(
53
- img_bytes,
54
- media_type="image/png",
55
- headers={"Content-Disposition": "inline; filename=output.png"}
56
- )
57
-
58
-
59
- except Exception as e:
60
- return JSONResponse(content={"error": str(e)}, status_code=500)
61
-
62
-
63
- @app.post("/getCoords")
64
- async def get_coords(file: UploadFile = File(...)):
65
- try:
66
- image_content = await file.read()
67
-
68
- if not image_content:
69
- print("No image found")
70
- return JSONResponse(content={"error": "Empty file uploaded"}, status_code=400)
71
-
72
- try:
73
- image = Image.open(io.BytesIO(image_content))
74
- except UnidentifiedImageError:
75
- return JSONResponse(content={"error": "Invalid image format"}, status_code=400)
76
-
77
- detection_results = await detect_pieces(image)
78
-
79
- if "error" in detection_results:
80
- return JSONResponse(content=detection_results, status_code=400)
81
-
82
- print("Image successfully processed and returned")
83
- return JSONResponse(content={"detections": detection_results}, status_code=200)
84
-
85
- except Exception as e:
86
- print(f"Unexpected error: {str(e)}")
87
- return JSONResponse(content={"error": "Unexpected error occurred", "details": str(e)}, status_code=500)
88
 
89
 
90
  @app.post("/getFen")
@@ -125,3 +74,30 @@ async def get_fen(file : UploadFile = File(), perspective : str = Form("w"), nex
125
 
126
  except Exception as e:
127
  return JSONResponse(content={"error": "Unexpected error occurred", "details": str(e)}, status_code=500)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import io
2
+ import os
3
+ import tempfile
4
  from fastapi import FastAPI, File, UploadFile, Form
5
  from fastapi.responses import JSONResponse, StreamingResponse
6
  from PIL import Image, UnidentifiedImageError
7
  from routes.segmentation import segment_chess_board
8
  from routes.detection import detect_pieces
9
  from routes.fen_generator import gen_fen
10
+ from routes.chess_review import analyze_pgn
11
  from typing import List, Dict, Any, Union
12
  from pydantic import BaseModel
13
+ import asyncio
14
+ import sys
15
+ import tracemalloc
16
+ tracemalloc.start()
17
+
18
+
19
+ if sys.platform == "win32":
20
+ asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
21
+
22
 
23
  app = FastAPI()
24
 
 
27
  confidences: list
28
  classes: list
29
 
30
+ @app.get("/test")
31
  async def read_root():
32
  return {
33
  "name": "Narendra",
34
  "age": 20,
35
  "Gender": "Male"
36
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
 
39
  @app.post("/getFen")
 
74
 
75
  except Exception as e:
76
  return JSONResponse(content={"error": "Unexpected error occurred", "details": str(e)}, status_code=500)
77
+
78
+ @app.post('/getReview')
79
+ async def getReview(file: UploadFile = File(...)):
80
+ print(os.getcwd())
81
+ print("call recieved")
82
+
83
+ if not file.filename.endswith(".pgn"):
84
+ return JSONResponse(content={"error": "Invalid file format. Please upload a PGN file"}, status_code=400)
85
+
86
+ try:
87
+ # Save the uploaded file to a temporary file
88
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".pgn") as tmp_file:
89
+ tmp_file.write(await file.read())
90
+ tmp_file_path = tmp_file.name
91
+
92
+ # Analyze the PGN file
93
+ analysis_result = analyze_pgn(tmp_file_path)
94
+
95
+ # Clean up the temporary file
96
+ os.remove(tmp_file_path)
97
+
98
+ if not analysis_result:
99
+ return JSONResponse(content={"error": "No game found in the PGN file"}, status_code=400)
100
+ return analysis_result
101
+
102
+ except Exception as e:
103
+ return JSONResponse(content={"error": "Unexpected error occurred", "details": str(e)}, status_code=500)
models/SegModel (1).pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d577a96ac47f8a6222719816b4810cf4b207de17885599e6e068eacc36e252cf
3
+ size 6787281
models/chessDetection3d.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e1b2e9d61b0ea9f1ce81341d1aa7e54ff5721797925dbc960133d578021a0e4c
3
+ size 114439558
models/stockfish-windows-x86-64-avx2.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0b24c22f7894fa13ab27e32a29763055d0867dfb123d8763579dea5b7a91f419
3
+ size 79811584
requirements.txt ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ annotated-types==0.7.0
2
+ anyio==4.8.0
3
+ certifi==2025.1.31
4
+ charset-normalizer==3.4.1
5
+ chess==1.11.1
6
+ click==8.1.8
7
+ colorama==0.4.6
8
+ contourpy==1.3.1
9
+ cycler==0.12.1
10
+ dnspython==2.7.0
11
+ email_validator==2.2.0
12
+ fastapi==0.115.8
13
+ fastapi-cli==0.0.7
14
+ filelock==3.17.0
15
+ fonttools==4.56.0
16
+ fsspec==2025.2.0
17
+ h11==0.14.0
18
+ httpcore==1.0.7
19
+ httptools==0.6.4
20
+ httpx==0.28.1
21
+ idna==3.10
22
+ Jinja2==3.1.5
23
+ kiwisolver==1.4.8
24
+ markdown-it-py==3.0.0
25
+ MarkupSafe==3.0.2
26
+ matplotlib==3.10.0
27
+ mdurl==0.1.2
28
+ mpmath==1.3.0
29
+ networkx==3.4.2
30
+ numpy==2.1.1
31
+ opencv-python==4.11.0.86
32
+ packaging==24.2
33
+ pandas==2.2.3
34
+ pillow==11.1.0
35
+ psutil==7.0.0
36
+ py-cpuinfo==9.0.0
37
+ pydantic==2.10.6
38
+ pydantic_core==2.27.2
39
+ Pygments==2.19.1
40
+ pyparsing==3.2.1
41
+ python-dateutil==2.9.0.post0
42
+ python-dotenv==1.0.1
43
+ python-multipart==0.0.20
44
+ pytz==2025.1
45
+ PyYAML==6.0.2
46
+ requests==2.32.3
47
+ rich==13.9.4
48
+ rich-toolkit==0.13.2
49
+ scipy==1.15.2
50
+ seaborn==0.13.2
51
+ setuptools==75.8.0
52
+ shellingham==1.5.4
53
+ six==1.17.0
54
+ sniffio==1.3.1
55
+ starlette==0.45.3
56
+ sympy==1.13.1
57
+ torch==2.6.0
58
+ torchvision==0.21.0
59
+ tqdm==4.67.1
60
+ typer==0.15.1
61
+ typing_extensions==4.12.2
62
+ tzdata==2025.1
63
+ ultralytics==8.3.76
64
+ ultralytics-thop==2.0.14
65
+ urllib3==2.3.0
66
+ uvicorn==0.34.0
67
+ watchfiles==1.0.4
68
+ websockets==15.0
routes/__pycache__/chess_review.cpython-313.pyc ADDED
Binary file (14.2 kB). View file
 
routes/__pycache__/chess_review_helper.cpython-313.pyc ADDED
Binary file (14.2 kB). View file
 
routes/__pycache__/detection.cpython-311.pyc DELETED
Binary file (1.5 kB)
 
routes/__pycache__/detection.cpython-313.pyc ADDED
Binary file (1.57 kB). View file
 
routes/__pycache__/fen_generator.cpython-311.pyc DELETED
Binary file (5.36 kB)
 
routes/__pycache__/fen_generator.cpython-313.pyc ADDED
Binary file (4.62 kB). View file
 
routes/__pycache__/segmentation.cpython-311.pyc DELETED
Binary file (1.27 kB)
 
routes/__pycache__/segmentation.cpython-313.pyc ADDED
Binary file (1.3 kB). View file
 
routes/chess_review.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ import os
3
+ import tempfile
4
+ import chess.pgn
5
+ import chess.engine
6
+ from enum import Enum
7
+ from typing import List, Dict
8
+ from datetime import datetime
9
+ import csv
10
+ import json
11
+ from fastapi.responses import JSONResponse
12
+
13
+ app = FastAPI()
14
+
15
+ class GamePhase(Enum):
16
+ OPENING = "opening"
17
+ MIDDLEGAME = "middlegame"
18
+ ENDGAME = "endgame"
19
+
20
+ class Classification(Enum):
21
+ BRILLIANT = "brilliant"
22
+ GREAT = "great"
23
+ BEST = "best"
24
+ EXCELLENT = "excellent"
25
+ GOOD = "good"
26
+ INACCURACY = "inaccuracy"
27
+ MISTAKE = "mistake"
28
+ MISS = "miss"
29
+ BLUNDER = "blunder"
30
+ BOOK = "book"
31
+ FORCED = "forced"
32
+
33
+ classification_values = {
34
+ Classification.BLUNDER: 0,
35
+ Classification.MISTAKE: 0.2,
36
+ Classification.MISS: 0.3,
37
+ Classification.INACCURACY: 0.4,
38
+ Classification.GOOD: 0.65,
39
+ Classification.EXCELLENT: 0.9,
40
+ Classification.BEST: 1,
41
+ Classification.GREAT: 1,
42
+ Classification.BRILLIANT: 1,
43
+ Classification.BOOK: 1,
44
+ Classification.FORCED: 1,
45
+ }
46
+
47
+ centipawn_classifications = [
48
+ Classification.BEST,
49
+ Classification.EXCELLENT,
50
+ Classification.GOOD,
51
+ Classification.INACCURACY,
52
+ Classification.MISS,
53
+ Classification.MISTAKE,
54
+ Classification.BLUNDER,
55
+ ]
56
+
57
+ # Analysis parameters
58
+ FORCED_WIN_THRESHOLD = 500
59
+ MISS_CENTIPAWN_LOSS = 300
60
+ MISS_MATE_THRESHOLD = 3
61
+ ENDGAME_MATERIAL_THRESHOLD = 24
62
+ QUEEN_VALUE = 9
63
+
64
+ def detect_game_phase(board: chess.Board, in_opening: bool) -> GamePhase:
65
+ if in_opening:
66
+ return GamePhase.OPENING
67
+
68
+ total_material = 0
69
+ queens = 0
70
+
71
+ for color in [chess.WHITE, chess.BLACK]:
72
+ for piece_type in chess.PIECE_TYPES:
73
+ if piece_type == chess.KING:
74
+ continue
75
+
76
+ count = len(board.pieces(piece_type, color))
77
+ value = {
78
+ chess.PAWN: 1,
79
+ chess.KNIGHT: 3,
80
+ chess.BISHOP: 3,
81
+ chess.ROOK: 5,
82
+ chess.QUEEN: QUEEN_VALUE
83
+ }[piece_type]
84
+
85
+ total_material += count * value
86
+ if piece_type == chess.QUEEN:
87
+ queens += count
88
+
89
+ endgame_conditions = [
90
+ total_material <= ENDGAME_MATERIAL_THRESHOLD,
91
+ queens == 0 and total_material <= ENDGAME_MATERIAL_THRESHOLD * 2,
92
+ ]
93
+
94
+ return GamePhase.ENDGAME if any(endgame_conditions) else GamePhase.MIDDLEGAME
95
+
96
+ def get_evaluation_loss_threshold(classif: Classification, prev_eval: float) -> float:
97
+ prev_eval = abs(prev_eval)
98
+ if classif == Classification.BEST:
99
+ return max(0.0001 * prev_eval**2 + 0.0236 * prev_eval - 3.7143, 0)
100
+ elif classif == Classification.EXCELLENT:
101
+ return max(0.0002 * prev_eval**2 + 0.1231 * prev_eval + 27.5455, 0)
102
+ elif classif == Classification.GOOD:
103
+ return max(0.0002 * prev_eval**2 + 0.2643 * prev_eval + 60.5455, 0)
104
+ elif classif == Classification.INACCURACY:
105
+ return max(0.0002 * prev_eval**2 + 0.3624 * prev_eval + 108.0909, 0)
106
+ elif classif == Classification.MISS:
107
+ return max(0.00025 * prev_eval**2 + 0.38255 * prev_eval + 166.9541, 0)
108
+ elif classif == Classification.MISTAKE:
109
+ return max(0.0003 * prev_eval**2 + 0.4027 * prev_eval + 225.8182, 0)
110
+ else:
111
+ return float("inf")
112
+
113
+ def load_opening_book(csv_path):
114
+ opening_book = {}
115
+ try:
116
+ with open(csv_path, newline='', encoding='utf-8') as csvfile:
117
+ reader = csv.reader(csvfile)
118
+ next(reader)
119
+ for row in reader:
120
+ if len(row) < 3:
121
+ continue
122
+ pgn_moves = row[2]
123
+ game = chess.pgn.Game()
124
+ board = game.board()
125
+ for move in pgn_moves.split():
126
+ if "." in move:
127
+ continue
128
+ try:
129
+ chess_move = board.push_san(move)
130
+ fen = " ".join(board.fen().split()[:4])
131
+ opening_book[fen] = chess_move.uci()
132
+ except ValueError:
133
+ break
134
+ except Exception as e:
135
+ print(f"Error loading opening book: {e}")
136
+ return opening_book
137
+
138
+ def is_book_move(board, opening_book, max_depth=8):
139
+ if board.fullmove_number > max_depth:
140
+ return None
141
+ fen = " ".join(board.fen().split()[:4])
142
+ return opening_book.get(fen)
143
+
144
+
145
+ engine_path = os.path.join(os.getcwd(), "models", "stockfish-windows-x86-64-avx2.exe")
146
+ book_csv_path = os.path.join(os.getcwd(), "assets", "openings_master.csv")
147
+
148
+ def analyze_pgn(pgn_file: str) -> Dict:
149
+ opening_book = load_opening_book(book_csv_path)
150
+
151
+ with open(pgn_file) as pgn:
152
+ game = chess.pgn.read_game(pgn)
153
+
154
+ if not game:
155
+ return {"error": "No game found in the PGN file."}
156
+
157
+ result = {
158
+ "move_analysis": [],
159
+ "phase_analysis": {},
160
+ "player_summaries": {}
161
+ }
162
+
163
+ with chess.engine.SimpleEngine.popen_uci(engine_path) as engine:
164
+ board = game.board()
165
+ classifications = {
166
+ "white": {phase: [] for phase in GamePhase},
167
+ "black": {phase: [] for phase in GamePhase}
168
+ }
169
+ phase_data = {phase: [] for phase in GamePhase}
170
+ in_opening = True
171
+
172
+ for move_number, node in enumerate(game.mainline(), start=1):
173
+ # Analyze position before the move
174
+ pre_info = engine.analyse(board, chess.engine.Limit(depth=20))
175
+ pre_eval = pre_info["score"].white().score(mate_score=10000) or 0
176
+ best_move = pre_info.get("pv", [None])[0]
177
+
178
+ # Make the move
179
+ move = node.move
180
+ board.push(move)
181
+
182
+ # Analyze position after the move
183
+ post_info = engine.analyse(board, limit = chess.engine.Limit(time = 0.3))
184
+ post_eval = post_info["score"].white().score(mate_score=10000) or 0
185
+
186
+ # Determine game phase
187
+ book_move = is_book_move(board, opening_book)
188
+ current_phase = detect_game_phase(board, in_opening)
189
+ if not book_move and in_opening:
190
+ in_opening = False
191
+
192
+ # Calculate evaluation loss
193
+ eval_loss = abs(pre_eval - post_eval)
194
+
195
+ # Initial classification
196
+ classification = Classification.BOOK if book_move else None
197
+ if not classification:
198
+ for classif in centipawn_classifications:
199
+ threshold = get_evaluation_loss_threshold(classif, pre_eval)
200
+ if eval_loss <= threshold:
201
+ classification = classif
202
+ break
203
+ classification = classification or Classification.BLUNDER
204
+
205
+ # Check for missed opportunities
206
+ is_winning = abs(pre_eval) >= FORCED_WIN_THRESHOLD
207
+ is_forced_win = pre_info["score"].is_mate() and pre_info["score"].relative.mate() <= MISS_MATE_THRESHOLD
208
+ if is_winning and move != best_move and (eval_loss >= MISS_CENTIPAWN_LOSS or is_forced_win):
209
+ classification = Classification.MISS
210
+
211
+ # Check for brilliant moves
212
+ if classification == Classification.BEST:
213
+ if pre_eval < -150 and post_eval >= 150:
214
+ classification = Classification.GREAT
215
+ elif pre_eval < -300 and post_eval >= 300:
216
+ classification = Classification.BRILLIANT
217
+
218
+ # Track classifications
219
+ player = "white" if board.turn == chess.BLACK else "black"
220
+ classifications[player][current_phase].append(classification)
221
+ phase_data[current_phase].append(classification)
222
+
223
+ # Add move analysis to result
224
+ result["move_analysis"].append({
225
+ "move_number": move_number,
226
+ "player": "White" if board.turn == chess.BLACK else "Black",
227
+ "move": move.uci(),
228
+ "evaluation": post_eval / 100,
229
+ "evaluation_loss": eval_loss / 100,
230
+ "classification": classification.value
231
+ })
232
+
233
+ # Phase analysis
234
+ for phase in GamePhase:
235
+ moves = phase_data[phase]
236
+ if moves:
237
+ rating = get_phase_rating(moves)
238
+ result["phase_analysis"][phase.value] = {
239
+ "rating": rating.value,
240
+ "move_count": len(moves)
241
+ }
242
+
243
+ # Player summaries
244
+ for color in ["white", "black"]:
245
+ player = game.headers["White" if color == "white" else "Black"]
246
+ counts = {c.value: 0 for c in Classification}
247
+
248
+ for phase in GamePhase:
249
+ phase_moves = classifications[color][phase]
250
+ for m in phase_moves:
251
+ counts[m.value] += 1
252
+
253
+ result["player_summaries"][player] = counts
254
+
255
+ def convert_enums(obj):
256
+ if isinstance(obj, Enum): # Convert Enum to its value
257
+ return obj.value
258
+ if isinstance(obj, dict): # Recursively handle dicts
259
+ return {k: convert_enums(v) for k, v in obj.items()}
260
+ if isinstance(obj, list): # Recursively handle lists
261
+ return [convert_enums(i) for i in obj]
262
+ return obj # Return other types as they are
263
+
264
+ json_result = convert_enums(result)
265
+
266
+ return JSONResponse(content=json_result)
267
+
268
+
269
+ def get_phase_rating(classified_moves: List[Classification]) -> Classification:
270
+ if not classified_moves:
271
+ return Classification.GOOD
272
+
273
+ total = sum(classification_values[m] for m in classified_moves)
274
+ average = total / len(classified_moves)
275
+
276
+ rating_order = [
277
+ (Classification.BRILLIANT, 0.95),
278
+ (Classification.GREAT, 0.85),
279
+ (Classification.BEST, 0.75),
280
+ (Classification.EXCELLENT, 0.65),
281
+ (Classification.GOOD, 0.5),
282
+ (Classification.INACCURACY, 0.35),
283
+ (Classification.MISS, 0.25),
284
+ (Classification.MISTAKE, 0.15)
285
+ ]
286
+
287
+ return next((c for c, t in rating_order if average >= t), Classification.BLUNDER)
routes/detection.py CHANGED
@@ -1,6 +1,10 @@
1
  from ultralytics import YOLO
2
  from PIL import Image
3
- detect_model = YOLO(r'D:\venv\chess-vision\models\chessDetection3d.pt')
 
 
 
 
4
 
5
  async def detect_pieces(image : Image):
6
  if image is None:
 
1
  from ultralytics import YOLO
2
  from PIL import Image
3
+ import os
4
+
5
+ curr = os.getcwd()
6
+ detect_model_path = os.path.join(curr, 'models', 'chessDetection3d.pt')
7
+ detect_model = YOLO(detect_model_path)
8
 
9
  async def detect_pieces(image : Image):
10
  if image is None:
routes/segmentation.py CHANGED
@@ -1,7 +1,11 @@
1
  from ultralytics import YOLO
2
  from PIL import Image
 
3
 
4
- seg_model = YOLO(r'D:\venv\chess-vision\models\SegModel (1).pt')
 
 
 
5
 
6
  async def segment_chess_board(image : Image):
7
  if image is None:
 
1
  from ultralytics import YOLO
2
  from PIL import Image
3
+ import os
4
 
5
+ curr = os.getcwd()
6
+ seg_model_path = os.path.join(curr, 'models', 'SegModel (1).pt')
7
+
8
+ seg_model = YOLO(seg_model_path)
9
 
10
  async def segment_chess_board(image : Image):
11
  if image is None: