import streamlit as st st.set_page_config(page_title="Chess Openings Suggestion Tool", layout="wide") import requests import os from bs4 import BeautifulSoup # Configure OpenAI API (using OPENAI_API_KEY) OPENAI_API_KEY = os.getenv("ChessOpeningKey") OPENAI_ENDPOINT = "https://api.openai.com/v1/chat/completions" def fetch_opening_data(opening_name): """Fetches additional information about a specific chess opening.""" if not opening_name: return None try: # Format the opening name for URL formatted_name = opening_name.replace(" ", "_") url = f"https://en.wikipedia.org/wiki/{formatted_name}" response = requests.get(url, timeout=10) if response.status_code != 200: # Try chess-specific sites as fallback url = f"https://www.chess.com/openings/{formatted_name}" response = requests.get(url, timeout=10) if response.status_code == 200: soup = BeautifulSoup(response.content, "html.parser") content = [] # Extract text from p tags (paragraphs) paragraphs = soup.find_all('p') for p in paragraphs[:5]: # Limit to first 5 paragraphs text = p.get_text(strip=True) if text and len(text) > 50: # Only meaningful paragraphs content.append(text) return "\n\n".join(content[:3]) # Return first 3 substantial paragraphs else: return "No additional information available for this opening." except Exception as e: st.error(f"Error fetching opening data: {str(e)}") return "Failed to retrieve opening information." def generate_chess_openings(player_info): """Generates chess opening recommendations based on player preferences.""" prompt = f"""As a chess opening specialist and grandmaster, recommend personalized chess openings for a player with the following preferences: {player_info} Your recommendations should include: 1. **White Openings:** Recommend exactly 3 openings to study when playing White that match the player's style and first move preferences. 2. **Black Openings:** Recommend exactly 3 openings to study when playing Black that match the player's style. For each opening recommendation, include: - Full name of the opening - Most common lines stemming from the opening(4-8 moves) - Famous players who use/used this opening - Key concepts to master first - Common traps or tactical motifs to be aware of - Why this opening suits the player's described style Format your response in clear markdown with headers and bullet points. Structure it with White openings first, followed by Black openings.""" headers = { "Authorization": f"Bearer {OPENAI_API_KEY}", "Content-Type": "application/json" } data = { "model": "gpt-3.5-turbo", "messages": [ {"role": "system", "content": "You are a chess grandmaster specializing in chess openings and teaching players how to expand their opening repertoire."}, {"role": "user", "content": prompt} ], "temperature": 0.7, "max_tokens": 2000 } try: response = requests.post(OPENAI_ENDPOINT, json=data, headers=headers) response.raise_for_status() return response.json()["choices"][0]["message"]["content"] except Exception as e: st.error(f"API Error: {str(e)}") return None # Chess style descriptions for the dropdown chess_styles = { "Aggressive": "Prefer direct attacks, sacrifices, and tactical complications", "Positional": "Focus on long-term strategic advantages, piece placement, and structure", "Defensive": "Excel at holding positions, counterattacking, and resource-finding", "Tactical": "Enjoy combinations, calculations, and complex positions", "Dynamic": "Like imbalanced positions with active piece play", "Classical": "Prefer solid development and fundamental principles", "Hypermodern": "Control the center with pieces rather than pawns" } # Define common first moves with descriptions first_moves = { "e4": "Open, tactical games with immediate center control", "d4": "More closed, positional games with solid structure", "c4": "Flexible flank opening with transpositional possibilities", "Nf3": "Hypermodern approach controlling center from distance" } # Streamlit UI st.title("♟️ Chess Openings Suggestion Tool") st.markdown("### Get personalized chess opening recommendations based on your preferences and style.") # Player info collection st.markdown("## Your Chess Profile") rating = st.select_slider( "Your approximate rating level", options=["Beginner (<1000)", "Advanced Beginner (1000-1200)", "Novice (1200-1400)", "Intermediate (1400-1600)", "Seasoned Player (1600-1800)", "Advanced (1800-2000)", "Master (2000+)"] ) playing_style = st.selectbox( "Your preferred playing style", options=list(chess_styles.keys()), format_func=lambda x: f"{x} - {chess_styles[x]}" ) # Changed from selectbox to multiselect preferred_first_moves = st.multiselect( "Your preferred first moves as White (select one or more)", options=list(first_moves.keys()), default=[list(first_moves.keys())[0]], # Default to e4 format_func=lambda x: f"{x} - {first_moves[x]}" ) current_openings = st.text_area( "Openings you currently play (optional)", help="List any chess openings you already play and are comfortable with." ) time_control = st.radio( "Preferred time control", ["Bullet/Blitz", "Rapid", "Classical"] ) improvement_goals = st.multiselect( "What aspects of your chess would you like to improve?", ["Tactical vision", "Strategic understanding", "Endgame technique", "Opening theory", "Time management", "Calculation ability"] ) specific_requests = st.text_area( "Any specific requirements or preferences? (optional)", help="E.g., 'I want openings that lead to open positions' or 'I prefer solid, low-risk openings'" ) if st.button("Generate Opening Recommendations"): if not preferred_first_moves: st.warning("Please select at least one preferred first move.") else: with st.spinner("Analyzing your chess profile and finding suitable openings..."): # Format preferred first moves for the prompt formatted_moves = ", ".join([move.split(" (")[0] for move in preferred_first_moves]) player_info = f""" Rating Level: {rating} Playing Style: {playing_style} Preferred First Moves as White: {formatted_moves} Current Openings: {current_openings if current_openings else 'Not provided'} Time Control Preference: {time_control} Improvement Goals: {', '.join(improvement_goals) if improvement_goals else 'Not specified'} Specific Requirements: {specific_requests if specific_requests else 'None provided'} """ recommendations = generate_chess_openings(player_info) if recommendations: st.markdown(recommendations) # Add an option to explore a specific opening in more detail st.markdown("---") st.markdown("## Explore an Opening Further") opening_to_explore = st.text_input("Enter the name of an opening to get more details:", help="Type the full name of one of the recommended openings") if opening_to_explore and st.button("Get Details"): with st.spinner(f"Fetching additional information about {opening_to_explore}..."): opening_details = fetch_opening_data(opening_to_explore) if opening_details: st.markdown(f"### {opening_to_explore} - Additional Information") st.markdown(opening_details)