Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -7,6 +7,7 @@ import matplotlib.pyplot as plt
|
|
7 |
import pandas as pd
|
8 |
import re
|
9 |
import logging
|
|
|
10 |
from bs4 import BeautifulSoup # Fixed Import
|
11 |
from tools.final_answer import FinalAnswerTool
|
12 |
from Gradio_UI import GradioUI
|
@@ -18,7 +19,7 @@ def get_box_score_links() -> list:
|
|
18 |
"""A tool that fetches the URLs to the boxscores for each of last night's NBA games."""
|
19 |
BASE_URL = "https://www.basketball-reference.com"
|
20 |
MAIN_URL = f"{BASE_URL}/boxscores/"
|
21 |
-
logging.debug("
|
22 |
try:
|
23 |
response = requests.get(MAIN_URL)
|
24 |
response.raise_for_status() # Raise exception for HTTP errors
|
@@ -32,22 +33,26 @@ def get_box_score_links() -> list:
|
|
32 |
if '/boxscores/' in href and href.endswith('.html') and 's/202' in href:
|
33 |
box_score_links.append(BASE_URL + href)
|
34 |
|
|
|
35 |
# Return unique links while preserving order
|
36 |
return list(dict.fromkeys(box_score_links))
|
37 |
|
38 |
except requests.exceptions.RequestException as e:
|
|
|
39 |
# Return error message as a list to maintain consistent return type
|
40 |
return [f"Error fetching boxScore links: {str(e)}"]
|
41 |
|
42 |
-
def get_box_score_data(url:
|
43 |
"""A tool that fetches the boxscores data from a provided URL.
|
44 |
Args:
|
45 |
url: A string representing the URL to a box score of an nba game from last night.
|
46 |
"""
|
|
|
47 |
try:
|
48 |
box_scores = {}
|
49 |
response = requests.get(url)
|
50 |
response.raise_for_status() # Raise exception for HTTP errors
|
|
|
51 |
soup = BeautifulSoup(response.text, 'html.parser')
|
52 |
pattern = r"<h1>(.*?) at (.*?) Box Score"
|
53 |
match = re.search(pattern, str(soup.find('div', id="content").find('h1')))
|
@@ -55,6 +60,7 @@ def get_box_score_data(url: list) -> dict:
|
|
55 |
if match:
|
56 |
team1 = match.group(1)
|
57 |
team2 = match.group(2)
|
|
|
58 |
|
59 |
# Read HTML tables
|
60 |
tables = pd.read_html(url)
|
@@ -76,11 +82,13 @@ def get_box_score_data(url: list) -> dict:
|
|
76 |
|
77 |
else:
|
78 |
# If regex pattern did not match
|
|
|
79 |
box_scores[url] = [{"Error": "Team names not found in the page title"}]
|
80 |
|
81 |
return box_scores
|
82 |
|
83 |
except Exception as e:
|
|
|
84 |
return {"Error": f"Error fetching boxScore data: {str(e)}"}
|
85 |
|
86 |
@tool
|
@@ -92,47 +100,45 @@ def get_stats_from_boxScore_data(url: str, stat: str) -> dict:
|
|
92 |
Must be one of: 'MP', 'FG', 'FGA', 'FG%', '3P', '3PA', '3P%', 'FT', 'FTA', 'FT%',
|
93 |
'ORB', 'DRB', 'TRB', 'AST', 'STL', 'BLK', 'TOV', 'PF', 'PTS', 'GmSc', '+/-'
|
94 |
"""
|
95 |
-
# Define the allowed stats
|
96 |
allowed_stats = ['MP', 'FG', 'FGA', 'FG%', '3P', '3PA', '3P%', 'FT', 'FTA', 'FT%',
|
97 |
'ORB', 'DRB', 'TRB', 'AST', 'STL', 'BLK', 'TOV', 'PF', 'PTS',
|
98 |
'GmSc', '+/-']
|
|
|
99 |
# Check if stat is valid
|
100 |
if stat not in allowed_stats:
|
|
|
101 |
return {"Error": f"Invalid stat '{stat}'. Allowed values are: {', '.join(allowed_stats)}"}
|
|
|
102 |
try:
|
103 |
box_scores = get_box_score_data(url)
|
104 |
-
logging.debug(f"
|
105 |
stats = {}
|
106 |
stat_key = ('Basic Box Score Stats', stat)
|
107 |
for teams in box_scores.keys():
|
108 |
-
logging.debug(f"
|
109 |
for player in box_scores[teams]:
|
110 |
-
logging.debug(f"Reached Line 112 (player = {player}, stat_key = {stat_key}")
|
111 |
if stat_key in player:
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
if player[list(player.keys())[0]] != "Team Totals":
|
118 |
-
stats[player[list(player.keys())[0]]] = pd.to_numeric(player[stat_key], errors='coerce')
|
119 |
-
logging.debug(f"Reached BoxScores return, stats = {str(stats)}")
|
120 |
return stats
|
|
|
121 |
except Exception as e:
|
|
|
122 |
return {"Error": f"Error fetching boxScore data for given statistic: {str(e)}"}
|
123 |
|
|
|
124 |
final_answer = FinalAnswerTool()
|
125 |
search_tool = DuckDuckGoSearchTool()
|
126 |
visit_webpage_tool = VisitWebpageTool()
|
127 |
user_input_tool = UserInputTool()
|
128 |
|
129 |
-
# 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:
|
130 |
-
# model_id='https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud'
|
131 |
-
|
132 |
model = HfApiModel(
|
133 |
max_tokens=2096,
|
134 |
temperature=0.5,
|
135 |
-
model_id='Qwen/Qwen2.5-Coder-32B-Instruct',
|
136 |
custom_role_conversions=None,
|
137 |
)
|
138 |
|
@@ -154,11 +160,9 @@ agent = CodeAgent(
|
|
154 |
user_input_tool,
|
155 |
get_box_score_links,
|
156 |
get_stats_from_boxScore_data
|
157 |
-
],
|
158 |
max_steps=6,
|
159 |
verbosity_level=1,
|
160 |
-
grammar=None,
|
161 |
-
planning_interval=None,
|
162 |
name="NBA Box Scores Agent",
|
163 |
description="Fetches NBA box scores and player points from last night's games.",
|
164 |
prompt_templates=prompt_templates,
|
@@ -166,4 +170,4 @@ agent = CodeAgent(
|
|
166 |
)
|
167 |
|
168 |
# Launch Gradio UI
|
169 |
-
GradioUI(agent).launch()
|
|
|
7 |
import pandas as pd
|
8 |
import re
|
9 |
import logging
|
10 |
+
import inspect
|
11 |
from bs4 import BeautifulSoup # Fixed Import
|
12 |
from tools.final_answer import FinalAnswerTool
|
13 |
from Gradio_UI import GradioUI
|
|
|
19 |
"""A tool that fetches the URLs to the boxscores for each of last night's NBA games."""
|
20 |
BASE_URL = "https://www.basketball-reference.com"
|
21 |
MAIN_URL = f"{BASE_URL}/boxscores/"
|
22 |
+
logging.debug(f"[Line {inspect.currentframe().f_lineno}] Fetching box score links from: {MAIN_URL}")
|
23 |
try:
|
24 |
response = requests.get(MAIN_URL)
|
25 |
response.raise_for_status() # Raise exception for HTTP errors
|
|
|
33 |
if '/boxscores/' in href and href.endswith('.html') and 's/202' in href:
|
34 |
box_score_links.append(BASE_URL + href)
|
35 |
|
36 |
+
logging.info(f"[Line {inspect.currentframe().f_lineno}] Found {len(box_score_links)} box score links.")
|
37 |
# Return unique links while preserving order
|
38 |
return list(dict.fromkeys(box_score_links))
|
39 |
|
40 |
except requests.exceptions.RequestException as e:
|
41 |
+
logging.error(f"[Line {inspect.currentframe().f_lineno}] Error fetching boxScore links: {str(e)}")
|
42 |
# Return error message as a list to maintain consistent return type
|
43 |
return [f"Error fetching boxScore links: {str(e)}"]
|
44 |
|
45 |
+
def get_box_score_data(url: str) -> dict:
|
46 |
"""A tool that fetches the boxscores data from a provided URL.
|
47 |
Args:
|
48 |
url: A string representing the URL to a box score of an nba game from last night.
|
49 |
"""
|
50 |
+
logging.debug(f"[Line {inspect.currentframe().f_lineno}] Fetching box score data from URL: {url}")
|
51 |
try:
|
52 |
box_scores = {}
|
53 |
response = requests.get(url)
|
54 |
response.raise_for_status() # Raise exception for HTTP errors
|
55 |
+
|
56 |
soup = BeautifulSoup(response.text, 'html.parser')
|
57 |
pattern = r"<h1>(.*?) at (.*?) Box Score"
|
58 |
match = re.search(pattern, str(soup.find('div', id="content").find('h1')))
|
|
|
60 |
if match:
|
61 |
team1 = match.group(1)
|
62 |
team2 = match.group(2)
|
63 |
+
logging.info(f"[Line {inspect.currentframe().f_lineno}] Game found: {team1} vs {team2}")
|
64 |
|
65 |
# Read HTML tables
|
66 |
tables = pd.read_html(url)
|
|
|
82 |
|
83 |
else:
|
84 |
# If regex pattern did not match
|
85 |
+
logging.warning(f"[Line {inspect.currentframe().f_lineno}] Team names not found in the page title for URL: {url}")
|
86 |
box_scores[url] = [{"Error": "Team names not found in the page title"}]
|
87 |
|
88 |
return box_scores
|
89 |
|
90 |
except Exception as e:
|
91 |
+
logging.error(f"[Line {inspect.currentframe().f_lineno}] Error fetching boxScore data: {str(e)}")
|
92 |
return {"Error": f"Error fetching boxScore data: {str(e)}"}
|
93 |
|
94 |
@tool
|
|
|
100 |
Must be one of: 'MP', 'FG', 'FGA', 'FG%', '3P', '3PA', '3P%', 'FT', 'FTA', 'FT%',
|
101 |
'ORB', 'DRB', 'TRB', 'AST', 'STL', 'BLK', 'TOV', 'PF', 'PTS', 'GmSc', '+/-'
|
102 |
"""
|
|
|
103 |
allowed_stats = ['MP', 'FG', 'FGA', 'FG%', '3P', '3PA', '3P%', 'FT', 'FTA', 'FT%',
|
104 |
'ORB', 'DRB', 'TRB', 'AST', 'STL', 'BLK', 'TOV', 'PF', 'PTS',
|
105 |
'GmSc', '+/-']
|
106 |
+
|
107 |
# Check if stat is valid
|
108 |
if stat not in allowed_stats:
|
109 |
+
logging.error(f"[Line {inspect.currentframe().f_lineno}] Invalid stat requested: {stat}")
|
110 |
return {"Error": f"Invalid stat '{stat}'. Allowed values are: {', '.join(allowed_stats)}"}
|
111 |
+
|
112 |
try:
|
113 |
box_scores = get_box_score_data(url)
|
114 |
+
logging.debug(f"[Line {inspect.currentframe().f_lineno}] Box Scores: {box_scores}")
|
115 |
stats = {}
|
116 |
stat_key = ('Basic Box Score Stats', stat)
|
117 |
for teams in box_scores.keys():
|
118 |
+
logging.debug(f"[Line {inspect.currentframe().f_lineno}] Processing team: {teams}")
|
119 |
for player in box_scores[teams]:
|
|
|
120 |
if stat_key in player:
|
121 |
+
if player[stat_key] is not None and player[stat_key].replace('.', '').isdigit():
|
122 |
+
if player[list(player.keys())[0]] != "Team Totals":
|
123 |
+
stats[player[list(player.keys())[0]]] = pd.to_numeric(player[stat_key], errors='coerce')
|
124 |
+
|
125 |
+
logging.info(f"[Line {inspect.currentframe().f_lineno}] Stats for {stat}: {stats}")
|
|
|
|
|
|
|
126 |
return stats
|
127 |
+
|
128 |
except Exception as e:
|
129 |
+
logging.error(f"[Line {inspect.currentframe().f_lineno}] Error fetching boxScore data for given statistic: {str(e)}")
|
130 |
return {"Error": f"Error fetching boxScore data for given statistic: {str(e)}"}
|
131 |
|
132 |
+
# Instantiate Tools and Model
|
133 |
final_answer = FinalAnswerTool()
|
134 |
search_tool = DuckDuckGoSearchTool()
|
135 |
visit_webpage_tool = VisitWebpageTool()
|
136 |
user_input_tool = UserInputTool()
|
137 |
|
|
|
|
|
|
|
138 |
model = HfApiModel(
|
139 |
max_tokens=2096,
|
140 |
temperature=0.5,
|
141 |
+
model_id='Qwen/Qwen2.5-Coder-32B-Instruct',
|
142 |
custom_role_conversions=None,
|
143 |
)
|
144 |
|
|
|
160 |
user_input_tool,
|
161 |
get_box_score_links,
|
162 |
get_stats_from_boxScore_data
|
163 |
+
],
|
164 |
max_steps=6,
|
165 |
verbosity_level=1,
|
|
|
|
|
166 |
name="NBA Box Scores Agent",
|
167 |
description="Fetches NBA box scores and player points from last night's games.",
|
168 |
prompt_templates=prompt_templates,
|
|
|
170 |
)
|
171 |
|
172 |
# Launch Gradio UI
|
173 |
+
GradioUI(agent).launch()
|