Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -816,6 +816,7 @@ class ChessAnalysisInput(BaseModel):
|
|
| 816 |
image_path: str = Field(description="Path to chess board image file")
|
| 817 |
description: str = Field(description="Any additional context about the position (optional)", default="")
|
| 818 |
|
|
|
|
| 819 |
@tool(args_schema=ChessAnalysisInput)
|
| 820 |
def analyze_chess_position(image_path: str, description: str = "") -> str:
|
| 821 |
"""
|
|
@@ -832,6 +833,10 @@ def analyze_chess_position(image_path: str, description: str = "") -> str:
|
|
| 832 |
- An image file shows a chess board
|
| 833 |
- Need to find the best move in a position
|
| 834 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 835 |
Returns: Best move in algebraic notation (e.g., "Qh5", "Nf6+", "Rd5")
|
| 836 |
"""
|
| 837 |
if not image_path:
|
|
@@ -879,27 +884,49 @@ def analyze_chess_position(image_path: str, description: str = "") -> str:
|
|
| 879 |
temperature=0
|
| 880 |
)
|
| 881 |
|
| 882 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 883 |
|
| 884 |
CRITICAL INSTRUCTIONS:
|
| 885 |
1. Carefully identify each piece:
|
| 886 |
- White pieces (UPPERCASE): K=King, Q=Queen, R=Rook, B=Bishop, N=Knight, P=Pawn
|
| 887 |
- Black pieces (lowercase): k, q, r, b, n, p
|
| 888 |
|
| 889 |
-
2.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 890 |
- Use numbers (1-8) for consecutive empty squares
|
| 891 |
- Use '/' to separate ranks
|
|
|
|
|
|
|
| 892 |
|
| 893 |
-
|
| 894 |
-
- Look for text like "Black to move" or "White to move"
|
| 895 |
-
- If unclear, analyze the position context
|
| 896 |
-
- Return 'w' for white, 'b' for black
|
| 897 |
-
|
| 898 |
-
4. Return ONLY the FEN string in this format:
|
| 899 |
piece_placement active_color castling en_passant halfmove fullmove
|
| 900 |
-
|
| 901 |
Example: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
|
| 902 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 903 |
Return ONLY the FEN string, nothing else."""
|
| 904 |
|
| 905 |
message = HumanMessage(
|
|
@@ -931,6 +958,40 @@ Return ONLY the FEN string, nothing else."""
|
|
| 931 |
|
| 932 |
print(f"β Extracted FEN: {fen}")
|
| 933 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 934 |
# ====================================================================
|
| 935 |
# STEP 2: Validate FEN with python-chess
|
| 936 |
# ====================================================================
|
|
|
|
| 816 |
image_path: str = Field(description="Path to chess board image file")
|
| 817 |
description: str = Field(description="Any additional context about the position (optional)", default="")
|
| 818 |
|
| 819 |
+
@tool(args_schema=ChessAnalysisInput)
|
| 820 |
@tool(args_schema=ChessAnalysisInput)
|
| 821 |
def analyze_chess_position(image_path: str, description: str = "") -> str:
|
| 822 |
"""
|
|
|
|
| 833 |
- An image file shows a chess board
|
| 834 |
- Need to find the best move in a position
|
| 835 |
|
| 836 |
+
Args:
|
| 837 |
+
image_path: Path to chess board image
|
| 838 |
+
description: The full question text - IMPORTANT for determining whose turn it is!
|
| 839 |
+
|
| 840 |
Returns: Best move in algebraic notation (e.g., "Qh5", "Nf6+", "Rd5")
|
| 841 |
"""
|
| 842 |
if not image_path:
|
|
|
|
| 884 |
temperature=0
|
| 885 |
)
|
| 886 |
|
| 887 |
+
# Check if the question explicitly states whose turn it is
|
| 888 |
+
whose_turn = None
|
| 889 |
+
if description:
|
| 890 |
+
desc_lower = description.lower()
|
| 891 |
+
if "black" in desc_lower and ("turn" in desc_lower or "move" in desc_lower):
|
| 892 |
+
whose_turn = "b"
|
| 893 |
+
elif "white" in desc_lower and ("turn" in desc_lower or "move" in desc_lower):
|
| 894 |
+
whose_turn = "w"
|
| 895 |
+
|
| 896 |
+
fen_prompt = f"""Analyze this chess board image and provide the position in FEN notation.
|
| 897 |
|
| 898 |
CRITICAL INSTRUCTIONS:
|
| 899 |
1. Carefully identify each piece:
|
| 900 |
- White pieces (UPPERCASE): K=King, Q=Queen, R=Rook, B=Bishop, N=Knight, P=Pawn
|
| 901 |
- Black pieces (lowercase): k, q, r, b, n, p
|
| 902 |
|
| 903 |
+
2. BOARD ORIENTATION - This is CRITICAL:
|
| 904 |
+
- In chess diagrams, the board is shown from the perspective of the player to move
|
| 905 |
+
- Look at the BOTTOM rank (closest to viewer):
|
| 906 |
+
* If bottom pieces are BLACK (lowercase in FEN) β Black to move β active color = 'b'
|
| 907 |
+
* If bottom pieces are WHITE (uppercase in FEN) β White to move β active color = 'w'
|
| 908 |
+
- The rank labels (1-8) on the side can help:
|
| 909 |
+
* If rank 8 is at bottom and rank 1 at top β Black's perspective β use 'b'
|
| 910 |
+
* If rank 1 is at bottom and rank 8 at top β White's perspective β use 'w'
|
| 911 |
+
{"- OVERRIDE: The question explicitly states BLACK's turn, so use 'b'" if whose_turn == "b" else ""}
|
| 912 |
+
{"- OVERRIDE: The question explicitly states WHITE's turn, so use 'w'" if whose_turn == "w" else ""}
|
| 913 |
+
|
| 914 |
+
3. FEN Format (read from rank 8 to rank 1, left to right):
|
| 915 |
- Use numbers (1-8) for consecutive empty squares
|
| 916 |
- Use '/' to separate ranks
|
| 917 |
+
- IMPORTANT: Always write FEN from White's perspective (rank 8 first, rank 1 last)
|
| 918 |
+
- But set the active_color based on whose perspective the board shows
|
| 919 |
|
| 920 |
+
4. Return ONLY the FEN string in this exact format:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 921 |
piece_placement active_color castling en_passant halfmove fullmove
|
| 922 |
+
|
| 923 |
Example: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
|
| 924 |
|
| 925 |
+
DOUBLE-CHECK:
|
| 926 |
+
- Did you identify whose pieces are at the BOTTOM of the board?
|
| 927 |
+
- Did you set active_color correctly based on board orientation?
|
| 928 |
+
- Did you write piece_placement from rank 8 to rank 1?
|
| 929 |
+
|
| 930 |
Return ONLY the FEN string, nothing else."""
|
| 931 |
|
| 932 |
message = HumanMessage(
|
|
|
|
| 958 |
|
| 959 |
print(f"β Extracted FEN: {fen}")
|
| 960 |
|
| 961 |
+
# Override the turn indicator if we know from the question
|
| 962 |
+
if whose_turn:
|
| 963 |
+
fen_parts = fen.split()
|
| 964 |
+
if len(fen_parts) >= 2:
|
| 965 |
+
old_turn = fen_parts[1]
|
| 966 |
+
fen_parts[1] = whose_turn
|
| 967 |
+
fen = ' '.join(fen_parts)
|
| 968 |
+
print(f"π Corrected turn from '{old_turn}' to '{whose_turn}' based on question")
|
| 969 |
+
print(f"β Corrected FEN: {fen}")
|
| 970 |
+
|
| 971 |
+
# Additional verification: Check if board orientation matches turn
|
| 972 |
+
# In FEN, rank 8 is first, rank 1 is last
|
| 973 |
+
# If bottom of image shows black pieces, it's black's turn
|
| 974 |
+
fen_parts = fen.split()
|
| 975 |
+
piece_placement = fen_parts[0]
|
| 976 |
+
active_color = fen_parts[1] if len(fen_parts) > 1 else 'w'
|
| 977 |
+
|
| 978 |
+
# Get last rank (rank 1 in FEN, which is bottom if white's perspective)
|
| 979 |
+
ranks = piece_placement.split('/')
|
| 980 |
+
rank_1 = ranks[-1] # Last rank in FEN
|
| 981 |
+
rank_8 = ranks[0] # First rank in FEN
|
| 982 |
+
|
| 983 |
+
# Check which color dominates bottom rank
|
| 984 |
+
# If showing from black's perspective, rank 8 should be at bottom
|
| 985 |
+
# and active color should be 'b'
|
| 986 |
+
black_pieces_in_rank8 = sum(1 for c in rank_8 if c.islower() and c.isalpha())
|
| 987 |
+
white_pieces_in_rank8 = sum(1 for c in rank_8 if c.isupper() and c.isalpha())
|
| 988 |
+
|
| 989 |
+
if black_pieces_in_rank8 > white_pieces_in_rank8 and active_color == 'w':
|
| 990 |
+
print(f"β οΈ Warning: Rank 8 has more black pieces, likely black's perspective")
|
| 991 |
+
print(f" Changing active color from 'w' to 'b'")
|
| 992 |
+
fen_parts[1] = 'b'
|
| 993 |
+
fen = ' '.join(fen_parts)
|
| 994 |
+
|
| 995 |
# ====================================================================
|
| 996 |
# STEP 2: Validate FEN with python-chess
|
| 997 |
# ====================================================================
|