Download tools/chess_tools.py from Gabandino/Real_Final_Assignment_AI_Agents_Course: direct link, hf CLI and curl.
- Browser
- Download file 4.22 kB
-
https://huggingface.co/spaces/Gabandino/Real_Final_Assignment_AI_Agents_Course/resolve/main/tools/chess_tools.py
- Command line
-
hf download hf://spaces/Gabandino/Real_Final_Assignment_AI_Agents_Course/tools/chess_tools.py
-
curl -L -o chess_tools.py https://huggingface.co/spaces/Gabandino/Real_Final_Assignment_AI_Agents_Course/resolve/main/tools/chess_tools.py
4.22 kB
| from smolagents import Tool, tool | |
| from openai import OpenAI | |
| import shutil | |
| def chess_engine_locator() -> str | None: | |
| """ | |
| Get the path to the chess engine binary. Can be used with chess.engine.SimpleEngine.popen_uci function from chess.engine Python module. | |
| Returns: | |
| str: Path to the chess engine. | |
| """ | |
| path = shutil.which('stockfish') | |
| return path if path else None | |
| class ImageToChessBoardFENTool(Tool): | |
| name = 'image_to_chess_board_fen' | |
| description = '''Convert a chessboard image to board part of the FEN.''' | |
| inputs = { | |
| 'image_url': { | |
| 'type': 'string', | |
| 'description': 'Public URL of the image (preferred) or base64 encoded image in data URL format', | |
| } | |
| } | |
| output_type = 'string' | |
| def __init__(self, client: OpenAI | None = None, **kwargs): | |
| self.client = client if client is not None else OpenAI() | |
| super().__init__(**kwargs) | |
| def attachment_for(self, task_id: str | None): | |
| self.task_id = task_id | |
| def forward(self, image_url: str) -> str: | |
| """ | |
| Convert a chessboard image to board part of the FEN. | |
| Args: | |
| image_url (str): Public URL of the image (preferred) or base64 encoded image in data URL format. | |
| Returns: | |
| str: Board part of the FEN. | |
| """ | |
| client = self.client | |
| response = client.responses.create( | |
| model='gpt-4.1', | |
| input=[ | |
| { | |
| 'role': 'user', | |
| 'content': [ | |
| { | |
| 'type': 'input_text', | |
| 'text': 'Describe the position of the pieces on the chessboard from the image. Please, nothing else but description.', | |
| }, | |
| {'type': 'input_image', 'image_url': image_url}, | |
| ], | |
| }, | |
| ], | |
| ) | |
| response = client.responses.create( | |
| model='gpt-4.1', | |
| input=[ | |
| { | |
| 'role': 'user', | |
| 'content': [ | |
| { | |
| 'type': 'input_text', | |
| 'text': 'Describe the position of the pieces on the chessboard from the image. Please, nothing else but description.', | |
| }, | |
| ], | |
| }, | |
| ] | |
| + response.output | |
| + [ | |
| { | |
| 'role': 'user', | |
| 'content': [ | |
| { | |
| 'type': 'input_text', | |
| 'text': """\ | |
| Write down all positions with known pieces. | |
| Use a standard one-letter code to name pieces. | |
| It is important to use the correct case for piece code. Use upper case for white and lower case for black. | |
| It is important to include information about all the mentioned positions. | |
| Describe each position in a new line. | |
| Follow format: <piece><position> (piece first, then position, no spaces) | |
| Return nothing but lines with positions. | |
| """, | |
| }, | |
| ], | |
| } | |
| ], | |
| ) | |
| board_pos = response.output_text | |
| pos_dict = {} | |
| for post_str in board_pos.splitlines(): | |
| pos_str = pos_str.strip() | |
| if len(pos_str) != 3: | |
| continue | |
| piece = post_str[0] | |
| pos = pos_str[1:3] | |
| pos_dict[pos] = piece | |
| board_fen = '' | |
| for rank in range (8, 0, -1): | |
| empty = 0 | |
| for file_c in range(ord('a'), ord('h') +1): | |
| file = chr(file_c) | |
| square = file + str(rank) | |
| if square in pos_dict: | |
| if empty > 0: | |
| board_fen += str(empty) | |
| empty = 0 | |
| board_fen += pos_dict[square] | |
| else: | |
| empty += 1 | |
| if empty > 0: | |
| board_fen += str(empty) | |
| if rank != 1: | |
| board_fen += '/' | |
| return board_fen |