Spaces:
Runtime error
Runtime error
def PNG2FENTool(png_file: str) -> str: | |
"""Tool for converting a PNG file containing a chess board to a FEN position string. | |
Args: | |
png_file (str): The path to the PNG file. | |
Returns: | |
str: The FEN position string representing the chess board. | |
""" | |
# Raises: | |
# - FileNotFoundError: | |
# If the PNG file does not exist. | |
# - ValueError: | |
# If the PNG file cannot be processed or does not contain a valid chess board. | |
try: | |
# Open and preprocess image with modern Pillow | |
img = Image.open(png_file) | |
img = ImageOps.exif_transpose(img).convert("L") | |
# Use LANCZOS instead of ANTIALIAS | |
img = img.resize((img.width*2, img.height*2), Image.Resampling.LANCZOS) | |
# Save temp file for OCR | |
temp_path = "chess_temp.png" | |
img.save(temp_path) | |
# Perform OCR | |
import easyocr | |
reader = easyocr.Reader(['en']) | |
result = reader.readtext(png_file, detail=0) | |
fen_candidates = [text for text in result if validate_fen_format(text)] | |
if not fen_candidates: | |
raise ValueError("No valid FEN found in image") | |
return fen_candidates[0] | |
except Exception as e: | |
raise ValueError(f"OCR processing failed: {str(e)}") | |
# try: | |
# # Open the PNG file using PIL | |
# image = Image.open(png_file) | |
# | |
# # Use pytesseract to extract text from the image | |
# text = pytesseract.image_to_string(image) | |
# | |
# # Process the extracted text to get the FEN position string | |
# fen_position = process_text_to_fen(text) | |
# | |
# return fen_position | |
# | |
except FileNotFoundError: | |
raise FileNotFoundError("PNG file not found.") | |
# | |
# except Exception as e: | |
# raise ValueError("Error processing PNG file: " + str(e)) | |
def process_text_to_fen(text): | |
""" | |
Processes the extracted text from the image to obtain the FEN position string. | |
Parameters: | |
- text: str | |
The extracted text from the image. | |
Returns: | |
- str: | |
The FEN position string representing the chess board. | |
Raises: | |
- ValueError: | |
If the extracted text does not contain a valid chess board. | |
""" | |
# Process the text to remove any unnecessary characters or spaces | |
processed_text = text.strip().replace("\n", "").replace(" ", "") | |
# Check if the processed text matches the expected format of a FEN position string | |
if not validate_fen_format(processed_text): | |
raise ValueError("Invalid chess board.") | |
return processed_text | |
def validate_fen_format(fen_string): | |
""" | |
Validates if a given string matches the format of a FEN (Forsyth–Edwards Notation) position string. | |
Parameters: | |
- fen_string: str | |
The string to be validated. | |
Returns: | |
- bool: | |
True if the string matches the FEN format, False otherwise. | |
""" | |
# FEN format: 8 sections separated by '/' | |
sections = fen_string.split("/") | |
if len(sections) != 8: | |
return False | |
# Check if each section contains valid characters | |
for section in sections: | |
if not validate_section(section): | |
return False | |
return True | |
def validate_section(section): | |
""" | |
Validates if a given section of a FEN (Forsyth–Edwards Notation) position string contains valid characters. | |
Parameters: | |
- section: str | |
The section to be validated. | |
Returns: | |
- bool: | |
True if the section contains valid characters, False otherwise. | |
""" | |
# Valid characters: digits 1-8 or letters 'r', 'n', 'b', 'q', 'k', 'p', 'R', 'N', 'B', 'Q', 'K', 'P' | |
valid_chars = set("12345678rnbqkpRNBQKP") | |
return all(char in valid_chars for char in section) | |
import chess | |
import chess.engine | |
class ChessEngineTool(Tool): | |
name = "chess_engine" | |
description = "Analyzes a chess position (FEN) with Stockfish and returns the best move." | |
inputs = { | |
"fen": {"type": "string", "description": "FEN string of the position."}, | |
"time_limit": {"type": "number", "description": "Time in seconds for engine analysis.", "nullable": True} | |
} | |
output_type = "string" | |
def forward(self, fen: str, time_limit: float = 0.1) -> str: | |
# figure out where the binary actually is | |
sf_bin = shutil.which("stockfish") or "/usr/games/stockfish" | |
if not sf_bin: | |
raise RuntimeError( | |
f"Cannot find stockfish on PATH or at /usr/games/stockfish. " | |
"Did you install it in apt.txt or via apt-get?" | |
) | |
board = chess.Board(fen) | |
engine = chess.engine.SimpleEngine.popen_uci(sf_bin) | |
result = engine.play(board, chess.engine.Limit(time=time_limit)) | |
engine.quit() | |
return board.san(result.move) | |