Update src/streamlit_app.py
Browse files- src/streamlit_app.py +44 -47
src/streamlit_app.py
CHANGED
|
@@ -283,60 +283,57 @@ def get_player_index_brscraper():
|
|
| 283 |
return pd.DataFrame({'name': fallback_players})
|
| 284 |
|
| 285 |
@st.cache_data(ttl=300)
|
| 286 |
-
def get_player_career_stats_brscraper(player_name):
|
| 287 |
"""
|
| 288 |
-
|
| 289 |
-
|
| 290 |
"""
|
| 291 |
if not BRSCRAPER_AVAILABLE:
|
| 292 |
return pd.DataFrame()
|
| 293 |
-
|
| 294 |
-
try:
|
| 295 |
-
# BRScraper's nba.get_player_stats returns a DataFrame with career stats
|
| 296 |
-
df = nba.get_player_stats(player_name)
|
| 297 |
-
|
| 298 |
-
if df.empty:
|
| 299 |
-
return pd.DataFrame()
|
| 300 |
-
|
| 301 |
-
# Standardize column names from BRScraper output to app's expected format
|
| 302 |
-
# BRScraper's nba.get_player_stats uses column names like 'FG%', 'TRB', 'Tm', 'Age'
|
| 303 |
-
column_mapping = {
|
| 304 |
-
'Season': 'Season', # BRScraper returns 'Season'
|
| 305 |
-
'G': 'GP', 'GS': 'GS', 'MP': 'MIN',
|
| 306 |
-
'FG%': 'FG_PCT', '3P%': 'FG3_PCT', 'FT%': 'FT_PCT',
|
| 307 |
-
'TRB': 'REB', 'AST': 'AST', 'STL': 'STL', 'BLK': 'BLK', 'TOV': 'TO',
|
| 308 |
-
'PF': 'PF', 'PTS': 'PTS',
|
| 309 |
-
'Age': 'AGE', 'Tm': 'TEAM_ABBREVIATION', 'Lg': 'LEAGUE_ID', 'Pos': 'POSITION',
|
| 310 |
-
'FG': 'FGM', 'FGA': 'FGA', '3P': 'FG3M', '3PA': 'FG3A',
|
| 311 |
-
'2P': 'FGM2', '2PA': 'FGA2', '2P%': 'FG2_PCT', 'eFG%': 'EFG_PCT',
|
| 312 |
-
'FT': 'FTM', 'FTA': 'FTA', 'ORB': 'OREB', 'DRB': 'DREB'
|
| 313 |
-
}
|
| 314 |
-
|
| 315 |
-
# Apply column mapping only for columns that exist
|
| 316 |
-
for old_col, new_col in column_mapping.items():
|
| 317 |
-
if old_col in df.columns:
|
| 318 |
-
df = df.rename(columns={old_col: new_col})
|
| 319 |
-
|
| 320 |
-
# Ensure 'Season' column is string and uses en-dash
|
| 321 |
-
if 'Season' in df.columns:
|
| 322 |
-
df['Season'] = df['Season'].astype(str).str.replace('-', 'β')
|
| 323 |
-
|
| 324 |
-
# Convert numeric columns
|
| 325 |
-
# Exclude 'Season', 'TEAM_ABBREVIATION', 'LEAGUE_ID', 'POSITION' as they are strings
|
| 326 |
-
non_numeric_cols = {'Season', 'TEAM_ABBREVIATION', 'LEAGUE_ID', 'POSITION'}
|
| 327 |
-
for col in df.columns:
|
| 328 |
-
if col not in non_numeric_cols:
|
| 329 |
-
df[col] = pd.to_numeric(df[col], errors="coerce")
|
| 330 |
-
|
| 331 |
-
# Add 'Player' column for consistency with app logic
|
| 332 |
-
df['Player'] = player_name
|
| 333 |
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 338 |
return pd.DataFrame()
|
| 339 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
# ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 341 |
# Perplexity API
|
| 342 |
PERP_KEY = os.getenv("PERPLEXITY_API_KEY")
|
|
|
|
| 283 |
return pd.DataFrame({'name': fallback_players})
|
| 284 |
|
| 285 |
@st.cache_data(ttl=300)
|
| 286 |
+
def get_player_career_stats_brscraper(player_name, seasons_to_check=10):
|
| 287 |
"""
|
| 288 |
+
Build a player's career stats by fetching per-game data season-by-season
|
| 289 |
+
via nba.get_stats, instead of nba.get_player_stats (which was returning empty).
|
| 290 |
"""
|
| 291 |
if not BRSCRAPER_AVAILABLE:
|
| 292 |
return pd.DataFrame()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
|
| 294 |
+
all_rows = []
|
| 295 |
+
seasons = get_available_seasons(seasons_to_check)
|
| 296 |
+
for season_str in seasons:
|
| 297 |
+
end_year = int(season_str.split('β')[1])
|
| 298 |
+
try:
|
| 299 |
+
df_season = nba.get_stats(end_year, info='per_game', playoffs=False, rename=False)
|
| 300 |
+
if 'Player' in df_season.columns:
|
| 301 |
+
row = df_season[df_season['Player'] == player_name]
|
| 302 |
+
if not row.empty:
|
| 303 |
+
row = row.copy()
|
| 304 |
+
# normalize the season label
|
| 305 |
+
row['Season'] = season_str
|
| 306 |
+
all_rows.append(row)
|
| 307 |
+
except Exception as e:
|
| 308 |
+
# skip any failures
|
| 309 |
+
st.warning(f"Could not fetch {season_str} for {player_name}: {e}")
|
| 310 |
+
|
| 311 |
+
if not all_rows:
|
| 312 |
return pd.DataFrame()
|
| 313 |
|
| 314 |
+
df = pd.concat(all_rows, ignore_index=True)
|
| 315 |
+
|
| 316 |
+
# Standardize columns
|
| 317 |
+
mapping = {
|
| 318 |
+
'G':'GP','GS':'GS','MP':'MIN',
|
| 319 |
+
'FG%':'FG_PCT','3P%':'FG3_PCT','FT%':'FT_PCT',
|
| 320 |
+
'TRB':'REB','AST':'AST','STL':'STL','BLK':'BLK','TOV':'TO',
|
| 321 |
+
'PF':'PF','PTS':'PTS','ORB':'OREB','DRB':'DREB',
|
| 322 |
+
'FG':'FGM','FGA':'FGA','3P':'FG3M','3PA':'FG3A',
|
| 323 |
+
'2P':'FGM2','2PA':'FGA2','2P%':'FG2_PCT','eFG%':'EFG_PCT',
|
| 324 |
+
'FT':'FTM','FTA':'FTA'
|
| 325 |
+
}
|
| 326 |
+
df = df.rename(columns={o:n for o,n in mapping.items() if o in df.columns})
|
| 327 |
+
|
| 328 |
+
# Convert numeric columns
|
| 329 |
+
non_num = {'Season','Player','Tm','Lg','Pos'}
|
| 330 |
+
for col in df.columns:
|
| 331 |
+
if col not in non_num:
|
| 332 |
+
df[col] = pd.to_numeric(df[col], errors='coerce')
|
| 333 |
+
|
| 334 |
+
df['Player'] = player_name
|
| 335 |
+
return df
|
| 336 |
+
|
| 337 |
# ββββββββββββββββββββββββββββββββββββββββββββββ
|
| 338 |
# Perplexity API
|
| 339 |
PERP_KEY = os.getenv("PERPLEXITY_API_KEY")
|