| import streamlit as st |
| st.set_page_config(page_title="Chess Openings Suggestion Tool", layout="wide") |
|
|
| import requests |
| import os |
| from bs4 import BeautifulSoup |
|
|
| |
| 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: |
| |
| 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: |
| |
| 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 = [] |
| |
| paragraphs = soup.find_all('p') |
| for p in paragraphs[:5]: |
| text = p.get_text(strip=True) |
| if text and len(text) > 50: |
| content.append(text) |
| |
| return "\n\n".join(content[:3]) |
| 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_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" |
| } |
|
|
| |
| 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" |
| } |
|
|
|
|
| |
| st.title("♟️ Chess Openings Suggestion Tool") |
| st.markdown("### Get personalized chess opening recommendations based on your preferences and style.") |
|
|
| |
| 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]}" |
| ) |
|
|
| |
| 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]], |
| 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..."): |
| |
| 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) |
| |
| |
| 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) |
| |