Update main.py
Browse files
main.py
CHANGED
|
@@ -677,13 +677,6 @@ def get_player_career_stats_brscraper(player_name, seasons_to_check=10, playoffs
|
|
| 677 |
return pd.DataFrame()
|
| 678 |
all_rows = []
|
| 679 |
|
| 680 |
-
# This function should only try to fetch data for the specific seasons requested,
|
| 681 |
-
# not all available seasons, to avoid unnecessary calls and "invalid season" warnings.
|
| 682 |
-
# However, the current design of `getPlayerStats` endpoint passes `selected_seasons`
|
| 683 |
-
# as a list of seasons for *all* players.
|
| 684 |
-
# So, this function still needs to iterate through `get_available_seasons_util`
|
| 685 |
-
# and then the calling endpoint will filter.
|
| 686 |
-
# The warnings are expected if BRScraper doesn't have data for a given year.
|
| 687 |
|
| 688 |
seasons_to_try = get_available_seasons_util(seasons_to_check) # Get all potentially available seasons
|
| 689 |
|
|
@@ -822,7 +815,19 @@ def _scrape_dashboard_info_brscraper():
|
|
| 822 |
PERP_KEY = os.getenv("PERPLEXITY_API_KEY")
|
| 823 |
PERP_URL = "https://api.perplexity.ai/chat/completions"
|
| 824 |
|
| 825 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 826 |
if not PERP_KEY:
|
| 827 |
logging.error("PERPLEXITY_API_KEY env var not set.")
|
| 828 |
return "Perplexity API key is not configured."
|
|
@@ -830,7 +835,7 @@ def ask_perp(prompt, system="You are a helpful NBA analyst AI.", max_tokens=500,
|
|
| 830 |
payload = {
|
| 831 |
"model":"sonar-pro",
|
| 832 |
"messages":[{"role":"system","content":system},{"role":"user","content":prompt}],
|
| 833 |
-
"max_tokens":max_tokens, "temperature":temp
|
| 834 |
}
|
| 835 |
try:
|
| 836 |
r = requests.post(PERP_URL, json=payload, headers=hdr, timeout=45)
|
|
@@ -1112,7 +1117,7 @@ def perplexity_explain():
|
|
| 1112 |
if not prompt:
|
| 1113 |
return jsonify({'error': 'Prompt is required'}), 400
|
| 1114 |
|
| 1115 |
-
explanation = ask_perp(prompt
|
| 1116 |
if "Error from AI" in explanation:
|
| 1117 |
return jsonify({'error': explanation}), 500
|
| 1118 |
|
|
@@ -1210,7 +1215,7 @@ def perplexity_chat():
|
|
| 1210 |
token = auth_header.split(' ')[1]
|
| 1211 |
uid = verify_token(token)
|
| 1212 |
|
| 1213 |
-
response_content = ask_perp(prompt
|
| 1214 |
if "Error from AI" in response_content:
|
| 1215 |
return jsonify({'error': response_content}), 500
|
| 1216 |
|
|
@@ -1248,7 +1253,7 @@ def awards_predictor():
|
|
| 1248 |
return jsonify({'error': 'Award type and criteria are required'}), 400
|
| 1249 |
|
| 1250 |
prompt = f"Predict top 5 {award_type} candidates based on {criteria}. Focus on 2024-25 season."
|
| 1251 |
-
prediction = ask_perp(prompt,
|
| 1252 |
if "Error from AI" in prediction:
|
| 1253 |
return jsonify({'error': prediction}), 500
|
| 1254 |
|
|
@@ -1302,58 +1307,37 @@ def similar_players():
|
|
| 1302 |
if not target_player or not criteria:
|
| 1303 |
return jsonify({'error': 'Target player and criteria are required'}), 400
|
| 1304 |
|
| 1305 |
-
prompt = f"Find top
|
| 1306 |
-
similar_players_analysis = ask_perp(prompt
|
| 1307 |
if "Error from AI" in similar_players_analysis:
|
| 1308 |
return jsonify({'error': similar_players_analysis}), 500
|
| 1309 |
|
| 1310 |
-
|
| 1311 |
-
|
| 1312 |
-
|
| 1313 |
-
|
| 1314 |
|
| 1315 |
-
|
| 1316 |
-
|
| 1317 |
-
|
| 1318 |
-
|
| 1319 |
-
|
| 1320 |
-
|
| 1321 |
-
|
| 1322 |
-
|
| 1323 |
-
|
| 1324 |
-
|
| 1325 |
-
|
| 1326 |
-
|
| 1327 |
-
|
| 1328 |
-
|
| 1329 |
-
player1_str = f"{player1_name} ({player1_season} season)" if player1_season else player1_name
|
| 1330 |
-
player2_str = f"{player2_name} ({player2_season} season)" if player2_season else player2_name
|
| 1331 |
-
|
| 1332 |
-
comparison_context = "Statistical comparison"
|
| 1333 |
-
if player1_season and player2_season:
|
| 1334 |
-
comparison_context += f" (specifically {player1_season} vs {player2_season} seasons)"
|
| 1335 |
-
elif player1_season:
|
| 1336 |
-
comparison_context += f" (specifically {player1_season} season for {player1_name} vs {player2_name}'s career/prime)"
|
| 1337 |
-
elif player2_season:
|
| 1338 |
-
comparison_context += f" (specifically {player1_name}'s career/prime vs {player2_season} season for {player2_name})"
|
| 1339 |
else:
|
| 1340 |
-
|
| 1341 |
|
| 1342 |
-
|
| 1343 |
-
|
| 1344 |
-
f"1. {comparison_context}. "
|
| 1345 |
-
"2. Playing style similarities and differences. 3. Strengths and weaknesses of each. "
|
| 1346 |
-
"4. Team impact and role. 5. Overall similarity score (1-10). "
|
| 1347 |
-
"Provide a comprehensive comparison with specific examples."
|
| 1348 |
-
)
|
| 1349 |
-
|
| 1350 |
-
comparison = ask_perp(prompt, system="You are a comparison expert AI.")
|
| 1351 |
-
if "Error from AI" in comparison:
|
| 1352 |
-
return jsonify({'error': comparison}), 500
|
| 1353 |
-
|
| 1354 |
-
return jsonify({'comparison': comparison})
|
| 1355 |
except Exception as e:
|
| 1356 |
-
logging.error(f"Error in /api/nba/
|
| 1357 |
return jsonify({'error': str(e)}), 500
|
| 1358 |
|
| 1359 |
|
|
|
|
| 677 |
return pd.DataFrame()
|
| 678 |
all_rows = []
|
| 679 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 680 |
|
| 681 |
seasons_to_try = get_available_seasons_util(seasons_to_check) # Get all potentially available seasons
|
| 682 |
|
|
|
|
| 815 |
PERP_KEY = os.getenv("PERPLEXITY_API_KEY")
|
| 816 |
PERP_URL = "https://api.perplexity.ai/chat/completions"
|
| 817 |
|
| 818 |
+
NBA_ANALYST_SYSTEM_PROMPT = (
|
| 819 |
+
"You are a sharp, insightful NBA analyst AI with the tone and knowledge of a seasoned sports commentator. "
|
| 820 |
+
"Your expertise spans the entire history of the league—from hardwood legends to rising stars, tactical evolutions, "
|
| 821 |
+
"advanced stats, trades, rivalries, and playoff lore. Speak with authority, depth, and the occasional flair of broadcast commentary. "
|
| 822 |
+
"Your job is to help users explore the NBA with analytical rigor and passion. You draw on statistics, game film analysis, "
|
| 823 |
+
"player tendencies, team dynamics, historical context, and front-office strategy. You may reference key metrics like PER, TS%, "
|
| 824 |
+
"on-off splits, or synergy data when relevant. You provide takes that are well-reasoned, never vague, and always rooted in basketball-specific insight. "
|
| 825 |
+
"Do not respond to questions outside the world of basketball. If asked, steer the conversation back to the NBA with finesse, "
|
| 826 |
+
"perhaps by connecting a topic metaphorically to hoops. Your personality is that of a knowledgeable but approachable analyst—"
|
| 827 |
+
"a cross between a basketball scout, play-by-play commentator, and sportswriter. You love the game, and it shows."
|
| 828 |
+
)
|
| 829 |
+
|
| 830 |
+
def ask_perp(prompt, system=NBA_ANALYST_SYSTEM_PROMPT , max_tokens=1000, temp=0.2):
|
| 831 |
if not PERP_KEY:
|
| 832 |
logging.error("PERPLEXITY_API_KEY env var not set.")
|
| 833 |
return "Perplexity API key is not configured."
|
|
|
|
| 835 |
payload = {
|
| 836 |
"model":"sonar-pro",
|
| 837 |
"messages":[{"role":"system","content":system},{"role":"user","content":prompt}],
|
| 838 |
+
"max_tokens":max_tokens, "temperature":temp, "search_context_size": "high"
|
| 839 |
}
|
| 840 |
try:
|
| 841 |
r = requests.post(PERP_URL, json=payload, headers=hdr, timeout=45)
|
|
|
|
| 1117 |
if not prompt:
|
| 1118 |
return jsonify({'error': 'Prompt is required'}), 400
|
| 1119 |
|
| 1120 |
+
explanation = ask_perp(prompt)
|
| 1121 |
if "Error from AI" in explanation:
|
| 1122 |
return jsonify({'error': explanation}), 500
|
| 1123 |
|
|
|
|
| 1215 |
token = auth_header.split(' ')[1]
|
| 1216 |
uid = verify_token(token)
|
| 1217 |
|
| 1218 |
+
response_content = ask_perp(prompt)
|
| 1219 |
if "Error from AI" in response_content:
|
| 1220 |
return jsonify({'error': response_content}), 500
|
| 1221 |
|
|
|
|
| 1253 |
return jsonify({'error': 'Award type and criteria are required'}), 400
|
| 1254 |
|
| 1255 |
prompt = f"Predict top 5 {award_type} candidates based on {criteria}. Focus on 2024-25 season."
|
| 1256 |
+
prediction = ask_perp(prompt,)
|
| 1257 |
if "Error from AI" in prediction:
|
| 1258 |
return jsonify({'error': prediction}), 500
|
| 1259 |
|
|
|
|
| 1307 |
if not target_player or not criteria:
|
| 1308 |
return jsonify({'error': 'Target player and criteria are required'}), 400
|
| 1309 |
|
| 1310 |
+
prompt = f"Find top 3 current and top 3 historical players similar to {target_player} based on the following criteria: {', '.join(criteria)}. Provide detailed reasoning."
|
| 1311 |
+
similar_players_analysis = ask_perp(prompt)
|
| 1312 |
if "Error from AI" in similar_players_analysis:
|
| 1313 |
return jsonify({'error': similar_players_analysis}), 500
|
| 1314 |
|
| 1315 |
+
# Extract user ID from auth header
|
| 1316 |
+
auth_header = request.headers.get('Authorization', '')
|
| 1317 |
+
token = auth_header.split(' ')[1]
|
| 1318 |
+
uid = verify_token(token)
|
| 1319 |
|
| 1320 |
+
analysis_id = str(uuid.uuid4()) # Unique ID for this analysis
|
| 1321 |
+
|
| 1322 |
+
if FIREBASE_INITIALIZED:
|
| 1323 |
+
user_analyses_ref = db.reference(f'user_analyses/{uid}')
|
| 1324 |
+
analysis_data = {
|
| 1325 |
+
'type': 'similar_players',
|
| 1326 |
+
'target_player': target_player,
|
| 1327 |
+
'criteria': criteria,
|
| 1328 |
+
'prompt': prompt,
|
| 1329 |
+
'explanation': similar_players_analysis,
|
| 1330 |
+
'created_at': datetime.utcnow().isoformat()
|
| 1331 |
+
}
|
| 1332 |
+
user_analyses_ref.child(analysis_id).set(analysis_data)
|
| 1333 |
+
logging.info(f"Similar players analysis stored for user {uid} with ID: {analysis_id}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1334 |
else:
|
| 1335 |
+
logging.warning("Firebase not initialized. Similar players analysis will not be saved.")
|
| 1336 |
|
| 1337 |
+
return jsonify({'similar_players': similar_players_analysis, 'analysis_id': analysis_id})
|
| 1338 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1339 |
except Exception as e:
|
| 1340 |
+
logging.error(f"Error in /api/nba/similar_players: {e}")
|
| 1341 |
return jsonify({'error': str(e)}), 500
|
| 1342 |
|
| 1343 |
|