File size: 7,194 Bytes
ea2fe88 4e33a26 ea2fe88 4e33a26 ea2fe88 4e33a26 ea2fe88 4e33a26 ea2fe88 5de4b4b ea2fe88 |
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 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
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
import logging
import inspect
from bs4 import BeautifulSoup # Fixed Import
from tools.final_answer import FinalAnswerTool
from Gradio_UI import GradioUI
import pdb
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
@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/"
logging.debug(f"[Line {inspect.currentframe().f_lineno}] Fetching box score links from: {MAIN_URL}")
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)
logging.info(f"[Line {inspect.currentframe().f_lineno}] Found {len(box_score_links)} box score links.")
# Return unique links while preserving order
return list(dict.fromkeys(box_score_links))
except requests.exceptions.RequestException as e:
logging.error(f"[Line {inspect.currentframe().f_lineno}] Error fetching boxScore links: {str(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(url: str) -> dict:
"""A tool that fetches the boxscores data from a provided URL.
Args:
url: A string representing the URL to a box score of an nba game from last night.
"""
logging.debug(f"[Line {inspect.currentframe().f_lineno}] Fetching box score data from URL: {url}")
try:
box_scores = {}
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)
logging.info(f"[Line {inspect.currentframe().f_lineno}] Game found: {team1} vs {team2}")
# 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
logging.warning(f"[Line {inspect.currentframe().f_lineno}] Team names not found in the page title for URL: {url}")
box_scores[url] = [{"Error": "Team names not found in the page title"}]
return box_scores
except Exception as e:
logging.error(f"[Line {inspect.currentframe().f_lineno}] Error fetching boxScore data: {str(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', '+/-'
"""
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:
logging.error(f"[Line {inspect.currentframe().f_lineno}] Invalid stat requested: {stat}")
return {"Error": f"Invalid stat '{stat}'. Allowed values are: {', '.join(allowed_stats)}"}
try:
box_scores = get_box_score_data(url)
logging.debug(f"[Line {inspect.currentframe().f_lineno}] Box Scores: {box_scores}")
stats = {}
stat_key = ('Basic Box Score Stats', stat)
for teams in box_scores.keys():
logging.debug(f"[Line {inspect.currentframe().f_lineno}] Processing team: {teams}")
for player in box_scores[teams]:
if stat_key in player:
if player[stat_key] is not None and player[stat_key].replace('.', '').isdigit():
if player[list(player.keys())[0]] != "Team Totals":
stats[player[list(player.keys())[0]]] = pd.to_numeric(player[stat_key], errors='coerce')
logging.info(f"[Line {inspect.currentframe().f_lineno}] Stats for {stat}: {stats}")
return stats
except Exception as e:
logging.error(f"[Line {inspect.currentframe().f_lineno}] Error fetching boxScore data for given statistic: {str(e)}")
return {"Error": f"Error fetching boxScore data for given statistic: {str(e)}"}
# Instantiate Tools and Model
final_answer = FinalAnswerTool()
search_tool = DuckDuckGoSearchTool()
visit_webpage_tool = VisitWebpageTool()
user_input_tool = UserInputTool()
import os
from smolagents import OpenAIServerModel
model = OpenAIServerModel(
model_id="gpt-4o",
api_base="https://api.openai.com/v1",
api_key=os.environ["OPENAI_API_KEY"]
)
# 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)
# pdb.set_trace()
# 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
],
max_steps=6,
verbosity_level=1,
name="NBA_BoxScores_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()
|