pavan1221 commited on
Commit
a32b225
·
verified ·
1 Parent(s): d11dcf9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -214
app.py CHANGED
@@ -1,214 +1,184 @@
1
- import gradio as gr
2
- import tensorflow as tf
3
- import numpy as np
4
- import cv2
5
- import chess
6
- import chess.svg
7
- import cairosvg
8
- from stockfish import Stockfish
9
- from PIL import Image
10
- import imageio
11
- import io
12
- import os
13
-
14
- # Load model
15
- model = tf.keras.models.load_model("chess_model.keras")
16
-
17
- CLASS_NAMES = [
18
- 'black_bishop', 'black_king', 'black_knight', 'black_pawn',
19
- 'black_queen', 'black_rook', 'empty', 'white_bishop',
20
- 'white_king', 'white_knight', 'white_pawn', 'white_queen',
21
- 'white_rook'
22
- ]
23
-
24
- # Stockfish
25
- stockfish = Stockfish(depth=15)
26
-
27
- def detect_and_crop_board(image_path):
28
- img = cv2.imread(image_path)
29
- img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
30
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
31
- edges = cv2.Canny(gray, 50, 150)
32
- contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
33
- largest_area = 0
34
- board_contour = None
35
- for contour in contours:
36
- area = cv2.contourArea(contour)
37
- if area > largest_area:
38
- largest_area = area
39
- board_contour = contour
40
- x, y, w, h = cv2.boundingRect(board_contour)
41
- board = img_rgb[y:y+h, x:x+w]
42
- board = cv2.resize(board, (400, 400))
43
- return board
44
-
45
- def split_board_into_squares(board_img):
46
- square_size = 400 // 8
47
- squares = []
48
- for row in range(7, -1, -1):
49
- for col in range(8):
50
- x = col * square_size
51
- y = row * square_size
52
- square = board_img[y:y+square_size, x:x+square_size]
53
- squares.append(square)
54
- return squares
55
-
56
- def predict_board(squares):
57
- predictions = []
58
- for square in squares:
59
- img = cv2.resize(square, (64, 64))
60
- img = tf.keras.applications.efficientnet.preprocess_input(img)
61
- img = np.expand_dims(img, axis=0)
62
- pred = model.predict(img, verbose=0)
63
- class_idx = np.argmax(pred)
64
- confidence = np.max(pred)
65
- predictions.append({
66
- "class": CLASS_NAMES[class_idx],
67
- "confidence": float(confidence)
68
- })
69
- predictions = predictions[::-1]
70
- return predictions
71
-
72
- def predictions_to_fen(predictions):
73
- piece_map = {
74
- 'white_king': 'K', 'white_queen': 'Q',
75
- 'white_rook': 'R', 'white_bishop': 'B',
76
- 'white_knight': 'N', 'white_pawn': 'P',
77
- 'black_king': 'k', 'black_queen': 'q',
78
- 'black_rook': 'r', 'black_bishop': 'b',
79
- 'black_knight': 'n', 'black_pawn': 'p',
80
- 'empty': None
81
- }
82
- fen_rows = []
83
- for row in range(7, -1, -1):
84
- empty_count = 0
85
- fen_row = ""
86
- for col in range(8):
87
- idx = row * 8 + col
88
- piece = piece_map[predictions[idx]['class']]
89
- if piece is None:
90
- empty_count += 1
91
- else:
92
- if empty_count > 0:
93
- fen_row += str(empty_count)
94
- empty_count = 0
95
- fen_row += piece
96
- if empty_count > 0:
97
- fen_row += str(empty_count)
98
- fen_rows.append(fen_row)
99
- fen = "/".join(fen_rows)
100
- fen += " w - - 0 1"
101
- return fen
102
-
103
- def get_best_moves(fen, num_moves=3):
104
- stockfish.set_fen_position(fen)
105
- top_moves = stockfish.get_top_moves(num_moves)
106
- results = []
107
- for move in top_moves:
108
- results.append({
109
- "move": move["Move"],
110
- "centipawn": move["Centipawn"],
111
- "mate": move["Mate"]
112
- })
113
- return results
114
-
115
- def create_gif(fen, moves):
116
- frames = []
117
- board = chess.Board(fen)
118
- # Initial position frame
119
- svg = chess.svg.board(board=board, size=400)
120
- png = cairosvg.svg2png(bytestring=svg.encode('utf-8'))
121
- img = Image.open(io.BytesIO(png)).convert('RGB')
122
- # Add initial frame multiple times
123
- for _ in range(10):
124
- frames.append(np.array(img))
125
- # Animate each move
126
- for move_data in moves:
127
- move = chess.Move.from_uci(move_data['move'])
128
- board.push(move)
129
- svg = chess.svg.board(board=board, size=400, lastmove=move)
130
- png = cairosvg.svg2png(bytestring=svg.encode('utf-8'))
131
- img = Image.open(io.BytesIO(png)).convert('RGB')
132
- for _ in range(15):
133
- frames.append(np.array(img))
134
- board.pop()
135
- # Save gif
136
- gif_path = "/tmp/chess_moves.gif"
137
- imageio.mimsave(gif_path, frames, fps=10)
138
- return gif_path
139
-
140
- def analyze(image, output_type):
141
- # Save uploaded image
142
- temp_path = "/tmp/chess_input.png"
143
- Image.fromarray(image).save(temp_path)
144
-
145
- # Run pipeline
146
- board_img = detect_and_crop_board(temp_path)
147
- squares = split_board_into_squares(board_img)
148
- predictions = predict_board(squares)
149
- fen = predictions_to_fen(predictions)
150
- moves = get_best_moves(fen)
151
-
152
- if output_type == "Text":
153
- result = f"FEN: {fen}\n\nBest Moves:\n"
154
- for i, move in enumerate(moves):
155
- score = move['centipawn']
156
- if move['mate']:
157
- score = f"Mate in {move['mate']}"
158
- result += f"{i+1}. {move['move']} | Score: {score}\n"
159
- return result, None
160
-
161
- else: # Video/GIF
162
- gif_path = create_gif(fen, moves)
163
- result = f"FEN: {fen}\n\nBest Moves:\n"
164
- for i, move in enumerate(moves):
165
- score = move['centipawn']
166
- if move['mate']:
167
- score = f"Mate in {move['mate']}"
168
- result += f"{i+1}. {move['move']} | Score: {score}\n"
169
- return result, gif_path
170
-
171
- # Gradio UI
172
- with gr.Blocks(title="Chess Analyzer") as app:
173
- gr.Markdown("# Chess Analyzer")
174
- gr.Markdown("Upload a Chess.com screenshot to get the best moves")
175
-
176
- with gr.Row():
177
- image_input = gr.Image(label="Upload Screenshot", type="numpy")
178
-
179
- with gr.Row():
180
- output_type = gr.Radio(
181
- choices=["Text", "Video"],
182
- value="Text",
183
- label="Output Type"
184
- )
185
-
186
- analyze_btn = gr.Button("Analyze", variant="primary")
187
-
188
- with gr.Row():
189
- text_output = gr.Textbox(label="Analysis Results", lines=8)
190
- gif_output = gr.Image(label="Move Animation", visible=False)
191
-
192
- def toggle_gif_visibility(choice):
193
- return gr.update(visible=choice == "Video")
194
-
195
- output_type.change(
196
- fn=toggle_gif_visibility,
197
- inputs=output_type,
198
- outputs=gif_output
199
- )
200
-
201
- analyze_btn.click(
202
- fn=analyze,
203
- inputs=[image_input, output_type],
204
- outputs=[text_output, gif_output]
205
- )
206
-
207
- app.launch()
208
- ```
209
-
210
- Save as `app.py` then upload all 3 files to Hugging Face:
211
- ```
212
- chess_model.keras
213
- requirements.txt
214
- app.py
 
1
+ import gradio as gr
2
+ import tensorflow as tf
3
+ import numpy as np
4
+ import cv2
5
+ import chess
6
+ import chess.svg
7
+ import cairosvg
8
+ from stockfish import Stockfish
9
+ from PIL import Image
10
+ import imageio
11
+ import io
12
+ import os
13
+
14
+ model = tf.keras.models.load_model("chess_model.keras")
15
+
16
+ CLASS_NAMES = [
17
+ 'black_bishop', 'black_king', 'black_knight', 'black_pawn',
18
+ 'black_queen', 'black_rook', 'empty', 'white_bishop',
19
+ 'white_king', 'white_knight', 'white_pawn', 'white_queen',
20
+ 'white_rook'
21
+ ]
22
+
23
+ stockfish = Stockfish(depth=15)
24
+
25
+ def detect_and_crop_board(image_path):
26
+ img = cv2.imread(image_path)
27
+ img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
28
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
29
+ edges = cv2.Canny(gray, 50, 150)
30
+ contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
31
+ largest_area = 0
32
+ board_contour = None
33
+ for contour in contours:
34
+ area = cv2.contourArea(contour)
35
+ if area > largest_area:
36
+ largest_area = area
37
+ board_contour = contour
38
+ x, y, w, h = cv2.boundingRect(board_contour)
39
+ board = img_rgb[y:y+h, x:x+w]
40
+ board = cv2.resize(board, (400, 400))
41
+ return board
42
+
43
+ def split_board_into_squares(board_img):
44
+ square_size = 400 // 8
45
+ squares = []
46
+ for row in range(7, -1, -1):
47
+ for col in range(8):
48
+ x = col * square_size
49
+ y = row * square_size
50
+ square = board_img[y:y+square_size, x:x+square_size]
51
+ squares.append(square)
52
+ return squares
53
+
54
+ def predict_board(squares):
55
+ predictions = []
56
+ for square in squares:
57
+ img = cv2.resize(square, (64, 64))
58
+ img = tf.keras.applications.efficientnet.preprocess_input(img)
59
+ img = np.expand_dims(img, axis=0)
60
+ pred = model.predict(img, verbose=0)
61
+ class_idx = np.argmax(pred)
62
+ confidence = np.max(pred)
63
+ predictions.append({
64
+ "class": CLASS_NAMES[class_idx],
65
+ "confidence": float(confidence)
66
+ })
67
+ predictions = predictions[::-1]
68
+ return predictions
69
+
70
+ def predictions_to_fen(predictions):
71
+ piece_map = {
72
+ 'white_king': 'K', 'white_queen': 'Q',
73
+ 'white_rook': 'R', 'white_bishop': 'B',
74
+ 'white_knight': 'N', 'white_pawn': 'P',
75
+ 'black_king': 'k', 'black_queen': 'q',
76
+ 'black_rook': 'r', 'black_bishop': 'b',
77
+ 'black_knight': 'n', 'black_pawn': 'p',
78
+ 'empty': None
79
+ }
80
+ fen_rows = []
81
+ for row in range(7, -1, -1):
82
+ empty_count = 0
83
+ fen_row = ""
84
+ for col in range(8):
85
+ idx = row * 8 + col
86
+ piece = piece_map[predictions[idx]['class']]
87
+ if piece is None:
88
+ empty_count += 1
89
+ else:
90
+ if empty_count > 0:
91
+ fen_row += str(empty_count)
92
+ empty_count = 0
93
+ fen_row += piece
94
+ if empty_count > 0:
95
+ fen_row += str(empty_count)
96
+ fen_rows.append(fen_row)
97
+ fen = "/".join(fen_rows)
98
+ fen += " w - - 0 1"
99
+ return fen
100
+
101
+ def get_best_moves(fen, num_moves=3):
102
+ stockfish.set_fen_position(fen)
103
+ top_moves = stockfish.get_top_moves(num_moves)
104
+ results = []
105
+ for move in top_moves:
106
+ results.append({
107
+ "move": move["Move"],
108
+ "centipawn": move["Centipawn"],
109
+ "mate": move["Mate"]
110
+ })
111
+ return results
112
+
113
+ def create_gif(fen, moves):
114
+ frames = []
115
+ board = chess.Board(fen)
116
+ svg = chess.svg.board(board=board, size=400)
117
+ png = cairosvg.svg2png(bytestring=svg.encode('utf-8'))
118
+ img = Image.open(io.BytesIO(png)).convert('RGB')
119
+ for _ in range(10):
120
+ frames.append(np.array(img))
121
+ for move_data in moves:
122
+ move = chess.Move.from_uci(move_data['move'])
123
+ board.push(move)
124
+ svg = chess.svg.board(board=board, size=400, lastmove=move)
125
+ png = cairosvg.svg2png(bytestring=svg.encode('utf-8'))
126
+ img = Image.open(io.BytesIO(png)).convert('RGB')
127
+ for _ in range(15):
128
+ frames.append(np.array(img))
129
+ board.pop()
130
+ gif_path = "/tmp/chess_moves.gif"
131
+ imageio.mimsave(gif_path, frames, fps=10)
132
+ return gif_path
133
+
134
+ def analyze(image, output_type):
135
+ temp_path = "/tmp/chess_input.png"
136
+ Image.fromarray(image).save(temp_path)
137
+ board_img = detect_and_crop_board(temp_path)
138
+ squares = split_board_into_squares(board_img)
139
+ predictions = predict_board(squares)
140
+ fen = predictions_to_fen(predictions)
141
+ moves = get_best_moves(fen)
142
+ result = f"FEN: {fen}\n\nBest Moves:\n"
143
+ for i, move in enumerate(moves):
144
+ score = move['centipawn']
145
+ if move['mate']:
146
+ score = f"Mate in {move['mate']}"
147
+ result += f"{i+1}. {move['move']} | Score: {score}\n"
148
+ if output_type == "Text":
149
+ return result, None
150
+ else:
151
+ gif_path = create_gif(fen, moves)
152
+ return result, gif_path
153
+
154
+ with gr.Blocks(title="Chess Analyzer") as app:
155
+ gr.Markdown("# Chess Analyzer")
156
+ gr.Markdown("Upload a Chess.com screenshot to get the best moves")
157
+ with gr.Row():
158
+ image_input = gr.Image(label="Upload Screenshot", type="numpy")
159
+ with gr.Row():
160
+ output_type = gr.Radio(
161
+ choices=["Text", "Video"],
162
+ value="Text",
163
+ label="Output Type"
164
+ )
165
+ analyze_btn = gr.Button("Analyze", variant="primary")
166
+ with gr.Row():
167
+ text_output = gr.Textbox(label="Analysis Results", lines=8)
168
+ gif_output = gr.Image(label="Move Animation", visible=False)
169
+
170
+ def toggle_gif_visibility(choice):
171
+ return gr.update(visible=choice == "Video")
172
+
173
+ output_type.change(
174
+ fn=toggle_gif_visibility,
175
+ inputs=output_type,
176
+ outputs=gif_output
177
+ )
178
+ analyze_btn.click(
179
+ fn=analyze,
180
+ inputs=[image_input, output_type],
181
+ outputs=[text_output, gif_output]
182
+ )
183
+
184
+ app.launch()