File size: 6,209 Bytes
cd99dae
9b5b26a
 
 
c19d193
cd99dae
 
 
47fef3f
6aae614
8fe992b
9b5b26a
 
c08f631
4b914c5
cd99dae
c08f631
 
 
cd99dae
 
 
4b914c5
c08f631
cd99dae
c08f631
 
 
 
 
cd99dae
 
47fef3f
cd99dae
 
 
 
4b914c5
 
cd99dae
4b914c5
cd99dae
4b914c5
 
 
cd99dae
 
 
 
4b914c5
 
 
 
cd99dae
 
 
 
 
 
 
 
 
47fef3f
cd99dae
 
 
 
47fef3f
cd99dae
 
 
 
 
 
 
 
 
 
 
4b914c5
cd99dae
4b914c5
cd99dae
8c01ffb
fcb1511
a09556a
0509962
fcb1511
0509962
 
 
 
fcb1511
0509962
 
 
 
 
 
 
fcb1511
a09556a
fcb1511
 
 
 
d6877f7
 
 
0509962
fcb1511
 
 
 
6aae614
cf165b2
f8537ed
27c187e
ae7a494
 
 
 
e121372
cd99dae
 
 
 
13d500a
8c01ffb
9b5b26a
 
8c01ffb
cd99dae
861422e
 
9b5b26a
cd99dae
8c01ffb
8fe992b
cd99dae
 
 
 
 
 
 
fcb1511
cd99dae
8c01ffb
 
 
 
cd99dae
 
b5347b6
 
8fe992b
 
cd99dae
47fef3f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool, VisitWebpageTool, UserInputTool
import datetime
import requests
import pytz
import yaml
import matplotlib.pyplot as plt
import pandas as pd
import re
from bs4 import BeautifulSoup  # Fixed Import
from tools.final_answer import FinalAnswerTool

from Gradio_UI import GradioUI

@tool
def get_box_score_links() -> list:
    """A tool that fetches the URLs to the boxscores for each of last night's NBA games."""
    BASE_URL = "https://www.basketball-reference.com"
    MAIN_URL = f"{BASE_URL}/boxscores/"
    try:
        response = requests.get(MAIN_URL)
        response.raise_for_status()  # Raise exception for HTTP errors
        
        soup = BeautifulSoup(response.text, 'html.parser')
        box_score_links = []

        # Find all box score links
        for link in soup.find_all('a', href=True):
            href = link['href']
            if '/boxscores/' in href and href.endswith('.html') and 's/202' in href:
                box_score_links.append(BASE_URL + href)
        
        # Return unique links while preserving order
        return list(dict.fromkeys(box_score_links))
    
    except requests.exceptions.RequestException as e:
        # Return error message as a list to maintain consistent return type
        return [f"Error fetching boxScore links: {str(e)}"]

def get_box_score_data(links: list) -> dict:
    """A tool that fetches the boxscores data from the provided list of URLs.
    Args:
        links: A list of strings representing the URLs to the box score of each of last night's games.
    """
    try:
        box_scores = {}
        for url in links:
            response = requests.get(url)
            response.raise_for_status()  # Raise exception for HTTP errors
            
            soup = BeautifulSoup(response.text, 'html.parser')
            pattern = r"<h1>(.*?) at (.*?) Box Score"
            match = re.search(pattern, str(soup.find('div', id="content").find('h1')))
            
            if match:
                team1 = match.group(1)
                team2 = match.group(2)
                
                # Read HTML tables
                tables = pd.read_html(url)
                
                # Check if the expected tables exist before accessing
                if len(tables) > 0:
                    df_team1 = tables[0].to_dict(orient='records')
                else:
                    df_team1 = [{"Error": "Team 1 data not found"}]

                if len(tables) > 8:
                    df_team2 = tables[8].to_dict(orient='records')
                else:
                    df_team2 = [{"Error": "Team 2 data not found"}]
                
                # Store box score data
                box_scores[team1] = df_team1
                box_scores[team2] = df_team2
            
            else:
                # If regex pattern did not match
                box_scores[url] = [{"Error": "Team names not found in the page title"}]
        
        return box_scores
    
    except Exception as e:
        return {"Error": f"Error fetching boxScore data: {str(e)}"}

@tool
def get_stats_from_boxScore_data(url: str, stat: str) -> dict:
    """A tool that fetches the player names and box score statistic for the provided box score url.
    Args:
        url: A string representing the URL to the box score for a game.
        stat: A string representing the statistic that this function will return for each player in the box score.
               Must be one of: 'MP', 'FG', 'FGA', 'FG%', '3P', '3PA', '3P%', 'FT', 'FTA', 'FT%', 
               'ORB', 'DRB', 'TRB', 'AST', 'STL', 'BLK', 'TOV', 'PF', 'PTS', 'GmSc', '+/-'
    """
    # Define the allowed stats
    allowed_stats = ['MP', 'FG', 'FGA', 'FG%', '3P', '3PA', '3P%', 'FT', 'FTA', 'FT%', 
                     'ORB', 'DRB', 'TRB', 'AST', 'STL', 'BLK', 'TOV', 'PF', 'PTS', 
                     'GmSc', '+/-']
    # Check if stat is valid
    if stat not in allowed_stats:
        return {"Error": f"Invalid stat '{stat}'. Allowed values are: {', '.join(allowed_stats)}"}
    try:
        box_scores = get_box_score_data(url)
        stats = {}
        stat_key = ('Basic Box Score Stats', stat)
        for teams in box_scores.keys():
            for player in box_scores[teams]:
                if stat_key in player:
                    if player[stat_key] is not None:
                        if player[stat_key].replace('.', '').isdigit():
                            stats[player[list(player.keys())[0]]] = pd.to_numeric(player[stat_key], errors='coerce')
        return stats
    except Exception as e:
        return {"Error": f"Error fetching boxScore data for given statistic: {str(e)}"}

final_answer = FinalAnswerTool()
search_tool = DuckDuckGoSearchTool()
visit_webpage_tool = VisitWebpageTool()
user_input_tool = UserInputTool()

# If the agent does not answer, the model is overloaded, please use another model or the following Hugging Face Endpoint that also contains qwen2.5 coder:
# model_id='https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud' 

model = HfApiModel(
    max_tokens=2096,
    temperature=0.5,
    model_id='Qwen/Qwen2.5-Coder-32B-Instruct',  # It is possible that this model may be overloaded
    custom_role_conversions=None,
)

# Import tool from Hub
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)

# Load prompt templates
with open("prompts.yaml", 'r') as stream:
    prompt_templates = yaml.safe_load(stream)
    
# Setup the Agent
agent = CodeAgent(
    model=model,
    tools=[
        final_answer, 
        image_generation_tool, 
        search_tool, 
        visit_webpage_tool, 
        user_input_tool, 
        get_box_score_links, 
        get_stats_from_boxScore_data
    ],  # Add your tools here (don't remove final answer)
    max_steps=6,
    verbosity_level=1,
    grammar=None,
    planning_interval=None,
    name="NBA Box Scores Agent",
    description="Fetches NBA box scores and player points from last night's games.",
    prompt_templates=prompt_templates, 
    additional_authorized_imports=["matplotlib"]
)

# Launch Gradio UI
GradioUI(agent).launch()