rairo commited on
Commit
aa281d3
·
verified ·
1 Parent(s): a2e14dd

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +299 -203
src/streamlit_app.py CHANGED
@@ -6,7 +6,7 @@ import plotly.graph_objects as go
6
  from plotly.subplots import make_subplots
7
  import requests
8
  from nba_api.stats.endpoints import (
9
- playercareerstats, playercompare, teamdetails, teamgamelog,
10
  leaguegamelog, playergamelog, commonplayerinfo, teamplayerdashboard,
11
  leagueleaders, playerestimatedmetrics, teamestimatedmetrics
12
  )
@@ -15,6 +15,25 @@ import time
15
  from datetime import datetime
16
  import json
17
  import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  # Page configuration
19
  st.set_page_config(
20
  page_title="NBA Analytics Hub",
@@ -54,31 +73,49 @@ if 'chat_history' not in st.session_state:
54
 
55
  # Perplexity API configuration
56
  PERPLEXITY_API_KEY = os.getenv("PERPLEXITY_API_KEY")
 
 
 
 
 
 
 
 
 
 
57
 
58
- def query_perplexity(prompt, max_tokens=500):
59
- """Query Perplexity Sonar API"""
60
- if not PERPLEXITY_API_KEY:
61
- return "Please configure your Perplexity API key in Streamlit secrets."
62
-
63
- url = "https://api.perplexity.ai/chat/completions"
64
  headers = {
65
- "Authorization": f"Bearer {PERPLEXITY_API_KEY}",
66
- "Content-Type": "application/json"
67
  }
68
-
69
- data = {
70
- "model": "sonar-medium-online",
71
- "messages": [{"role": "user", "content": prompt}],
 
 
72
  "max_tokens": max_tokens,
73
- "temperature": 0.2
74
  }
75
-
76
  try:
77
- response = requests.post(url, json=data, headers=headers)
78
- response.raise_for_status()
79
- return response.json()["choices"][0]["message"]["content"]
 
 
 
 
 
 
 
 
 
 
 
 
80
  except Exception as e:
81
- return f"Error querying Perplexity API: {str(e)}"
 
82
 
83
  @st.cache_data(ttl=3600)
84
  def get_all_players():
@@ -113,7 +150,7 @@ def get_team_stats(team_id, season="2023-24"):
113
  def create_comparison_chart(data, players_names, metric):
114
  """Create comparison chart for players"""
115
  fig = go.Figure()
116
-
117
  for i, player in enumerate(players_names):
118
  if player in data['PLAYER_NAME'].values:
119
  player_data = data[data['PLAYER_NAME'] == player]
@@ -124,7 +161,7 @@ def create_comparison_chart(data, players_names, metric):
124
  name=player,
125
  line=dict(width=3)
126
  ))
127
-
128
  fig.update_layout(
129
  title=f"{metric} Comparison",
130
  xaxis_title="Season",
@@ -132,38 +169,42 @@ def create_comparison_chart(data, players_names, metric):
132
  hovermode='x unified',
133
  height=500
134
  )
135
-
136
  return fig
137
 
138
  def create_radar_chart(player_stats, categories):
139
  """Create radar chart for player comparison"""
140
  fig = go.Figure()
141
-
142
  for player_name, stats in player_stats.items():
 
 
 
143
  fig.add_trace(go.Scatterpolar(
144
- r=[stats.get(cat, 0) for cat in categories],
145
  theta=categories,
146
  fill='toself',
147
  name=player_name,
148
  opacity=0.7
149
  ))
150
-
151
  fig.update_layout(
152
  polar=dict(
153
  radialaxis=dict(
154
  visible=True,
 
155
  range=[0, 100]
156
  )),
157
  showlegend=True,
158
  title="Player Comparison Radar Chart"
159
  )
160
-
161
  return fig
162
 
163
  # Main app
164
  def main():
165
  st.markdown('<h1 class="main-header">🏀 NBA Analytics Hub</h1>', unsafe_allow_html=True)
166
-
167
  # Sidebar navigation
168
  st.sidebar.title("Navigation")
169
  page = st.sidebar.selectbox(
@@ -178,7 +219,7 @@ def main():
178
  "Roster Builder"
179
  ]
180
  )
181
-
182
  if page == "Player vs Player Comparison":
183
  player_comparison_page()
184
  elif page == "Team vs Team Analysis":
@@ -196,42 +237,47 @@ def main():
196
 
197
  def player_comparison_page():
198
  st.markdown('<h2 class="section-header">Player vs Player Comparison</h2>', unsafe_allow_html=True)
199
-
200
  # Get all players
201
  all_players = get_all_players()
202
  player_names = [player['full_name'] for player in all_players]
203
-
204
  col1, col2 = st.columns(2)
205
-
206
  with col1:
207
  selected_players = st.multiselect(
208
  "Select Players to Compare (up to 4)",
209
  player_names,
210
  max_selections=4
211
  )
212
-
213
  with col2:
214
  seasons = st.multiselect(
215
  "Select Seasons",
216
  ["2023-24", "2022-23", "2021-22", "2020-21", "2019-20"],
217
  default=["2023-24"]
218
  )
219
-
220
- if selected_players:
 
 
 
 
 
221
  # Get player IDs
222
  player_ids = []
223
  for name in selected_players:
224
  player_id = next((p['id'] for p in all_players if p['full_name'] == name), None)
225
  if player_id:
226
  player_ids.append(player_id)
227
-
228
  # Fetch and display stats
229
  stats_tabs = st.tabs(["Basic Stats", "Advanced Stats", "Visualizations"])
230
-
231
  with stats_tabs[0]:
232
  st.subheader("Basic Statistics")
233
  basic_stats_data = []
234
-
235
  for i, player_id in enumerate(player_ids):
236
  stats_df = get_player_stats(player_id)
237
  if not stats_df.empty:
@@ -241,84 +287,119 @@ def player_comparison_page():
241
  avg_stats = filtered_stats.mean(numeric_only=True)
242
  avg_stats['PLAYER_NAME'] = selected_players[i]
243
  basic_stats_data.append(avg_stats)
244
-
245
  if basic_stats_data:
246
  comparison_df = pd.DataFrame(basic_stats_data)
247
  basic_cols = ['PLAYER_NAME', 'GP', 'MIN', 'PTS', 'REB', 'AST', 'STL', 'BLK', 'FG_PCT', 'FT_PCT', 'FG3_PCT']
248
  display_cols = [col for col in basic_cols if col in comparison_df.columns]
249
  st.dataframe(comparison_df[display_cols].round(2), use_container_width=True)
250
-
 
 
251
  with stats_tabs[1]:
252
  st.subheader("Advanced Statistics")
253
- # Display advanced metrics like PER, TS%, etc.
254
  if basic_stats_data:
255
  advanced_df = comparison_df.copy()
256
- # Calculate some advanced stats
257
  if all(col in advanced_df.columns for col in ['PTS', 'FGA', 'FTA']):
258
- advanced_df['TS%'] = advanced_df['PTS'] / (2 * (advanced_df['FGA'] + 0.44 * advanced_df['FTA']))
259
-
 
 
 
260
  advanced_cols = ['PLAYER_NAME', 'PTS', 'REB', 'AST', 'FG_PCT', 'TS%'] if 'TS%' in advanced_df.columns else ['PLAYER_NAME', 'PTS', 'REB', 'AST', 'FG_PCT']
261
  display_cols = [col for col in advanced_cols if col in advanced_df.columns]
262
  st.dataframe(advanced_df[display_cols].round(3), use_container_width=True)
263
-
 
 
264
  with stats_tabs[2]:
265
  st.subheader("Player Comparison Charts")
266
-
267
  if basic_stats_data:
268
- # Create comparison charts
269
  metrics = ['PTS', 'REB', 'AST', 'FG_PCT']
270
  available_metrics = [m for m in metrics if m in comparison_df.columns]
271
-
272
- selected_metric = st.selectbox("Select Metric to Visualize", available_metrics)
273
-
274
- if selected_metric:
275
- # Bar chart comparison
276
- fig = px.bar(
277
- comparison_df,
278
- x='PLAYER_NAME',
279
- y=selected_metric,
280
- title=f"{selected_metric} Comparison",
281
- color='PLAYER_NAME'
282
- )
283
- st.plotly_chart(fig, use_container_width=True)
284
-
285
- # Radar chart for multi-metric comparison
286
- if len(available_metrics) >= 3:
287
- radar_data = {}
288
- for _, row in comparison_df.iterrows():
289
- radar_data[row['PLAYER_NAME']] = {
290
- metric: row[metric] for metric in available_metrics[:5]
291
- }
292
-
293
- if radar_data:
294
- radar_fig = create_radar_chart(radar_data, available_metrics[:5])
295
- st.plotly_chart(radar_fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
 
297
  def team_comparison_page():
298
  st.markdown('<h2 class="section-header">Team vs Team Analysis</h2>', unsafe_allow_html=True)
299
-
300
  all_teams = get_all_teams()
301
  team_names = [team['full_name'] for team in all_teams]
302
-
303
  col1, col2 = st.columns(2)
304
-
305
  with col1:
306
  selected_teams = st.multiselect(
307
  "Select Teams to Compare",
308
  team_names,
309
  max_selections=4
310
  )
311
-
312
  with col2:
313
  seasons = st.multiselect(
314
  "Select Seasons",
315
  ["2023-24", "2022-23", "2021-22", "2020-21"],
316
  default=["2023-24"]
317
  )
318
-
319
- if selected_teams:
 
 
 
 
 
320
  team_stats_data = []
321
-
322
  for team_name in selected_teams:
323
  team_id = next((t['id'] for t in all_teams if t['full_name'] == team_name), None)
324
  if team_id:
@@ -329,24 +410,24 @@ def team_comparison_page():
329
  team_avg['TEAM_NAME'] = team_name
330
  team_avg['SEASON'] = season
331
  team_stats_data.append(team_avg)
332
-
333
  if team_stats_data:
334
  team_df = pd.DataFrame(team_stats_data)
335
-
336
  # Display team comparison
337
  st.subheader("Team Statistics Comparison")
338
  team_cols = ['TEAM_NAME', 'SEASON', 'PTS', 'REB', 'AST', 'FG_PCT', 'FG3_PCT', 'FT_PCT']
339
  display_cols = [col for col in team_cols if col in team_df.columns]
340
  st.dataframe(team_df[display_cols].round(2), use_container_width=True)
341
-
342
  # Visualization
343
  st.subheader("Team Performance Visualization")
344
  metric_options = ['PTS', 'REB', 'AST', 'FG_PCT']
345
  available_metrics = [m for m in metric_options if m in team_df.columns]
346
-
347
  if available_metrics:
348
  selected_metric = st.selectbox("Select Metric", available_metrics)
349
-
350
  fig = px.bar(
351
  team_df,
352
  x='TEAM_NAME',
@@ -356,18 +437,24 @@ def team_comparison_page():
356
  barmode='group'
357
  )
358
  st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
359
 
360
  def awards_predictor_page():
361
  st.markdown('<h2 class="section-header">NBA Awards Predictor</h2>', unsafe_allow_html=True)
362
-
363
  award_type = st.selectbox(
364
  "Select Award Type",
365
  ["MVP", "Defensive Player of the Year", "Rookie of the Year", "6th Man of the Year", "All-NBA First Team"]
366
  )
367
-
368
  st.subheader(f"{award_type} Prediction Criteria")
369
-
370
  # Define criteria for different awards
 
371
  if award_type == "MVP":
372
  criteria = {
373
  "Points Per Game": st.slider("Minimum PPG", 15.0, 35.0, 25.0),
@@ -382,150 +469,154 @@ def awards_predictor_page():
382
  "Defensive Rating": st.slider("Maximum Defensive Rating", 90.0, 120.0, 105.0),
383
  "Team Defensive Ranking": st.slider("Maximum Team Def Rank", 1, 30, 10)
384
  }
385
- else:
386
  criteria = {
387
  "Points Per Game": st.slider("Minimum PPG", 10.0, 30.0, 15.0),
388
  "Games Played": st.slider("Minimum Games", 50, 82, 65),
389
  "Shooting Efficiency": st.slider("Minimum FG%", 0.35, 0.65, 0.45)
390
  }
391
-
392
  if st.button("Generate Predictions"):
393
- # Use AI to analyze and predict
394
  prompt = f"""
395
  Based on the following criteria for {award_type}, analyze current NBA players and provide predictions:
396
-
397
  Criteria: {criteria}
398
-
399
  Please provide:
400
  1. Top 5 candidates with their stats
401
  2. Analysis of why each candidate fits the criteria
402
  3. Your prediction for the winner with reasoning
403
-
404
  Focus on current 2023-24 season performance and recent trends.
405
  """
406
-
407
- with st.spinner("Analyzing candidates..."):
408
- prediction = query_perplexity(prompt, max_tokens=800)
409
  st.markdown("### AI Prediction Analysis")
410
  st.write(prediction)
411
 
412
  def ai_chat_page():
413
  st.markdown('<h2 class="section-header">AI NBA Chat & Insights</h2>', unsafe_allow_html=True)
414
-
415
  # Chat interface
416
  st.subheader("Ask AI About NBA Stats and Insights")
417
-
418
  # Display chat history
419
  for message in st.session_state.chat_history:
420
  with st.chat_message(message["role"]):
421
  st.write(message["content"])
422
-
423
  # Chat input
424
  if prompt := st.chat_input("Ask about NBA players, teams, stats, or strategies..."):
425
  # Add user message to chat history
426
  st.session_state.chat_history.append({"role": "user", "content": prompt})
427
-
428
  # Display user message
429
  with st.chat_message("user"):
430
  st.write(prompt)
431
-
432
  # Generate AI response
433
  with st.chat_message("assistant"):
434
- with st.spinner("Thinking..."):
435
- # Enhance prompt with NBA context
436
- enhanced_prompt = f"""
437
- As an NBA expert analyst, please answer this question about basketball:
438
-
439
- {prompt}
440
-
441
- Please provide detailed analysis with current stats, trends, and insights when relevant.
442
- If specific player or team stats are mentioned, include recent performance data.
443
- """
444
-
445
- response = query_perplexity(enhanced_prompt, max_tokens=700)
446
  st.write(response)
447
-
448
  # Add assistant response to chat history
449
  st.session_state.chat_history.append({"role": "assistant", "content": response})
450
-
 
 
 
451
  # Quick action buttons
452
  st.subheader("Quick Insights")
453
  col1, col2, col3 = st.columns(3)
454
-
455
  with col1:
456
  if st.button("🏆 Championship Contenders"):
457
  prompt = "Analyze the current NBA championship contenders for 2024. Who are the top 5 teams and why?"
458
- response = query_perplexity(prompt)
459
- st.write(response)
460
-
 
461
  with col2:
462
  if st.button("⭐ Rising Stars"):
463
  prompt = "Who are the most promising young NBA players to watch in 2024? Focus on players 23 and under."
464
- response = query_perplexity(prompt)
465
- st.write(response)
466
-
 
467
  with col3:
468
  if st.button("📊 Trade Analysis"):
469
  prompt = "What are some potential NBA trades that could happen this season? Analyze team needs and available players."
470
- response = query_perplexity(prompt)
471
- st.write(response)
 
472
 
473
  def young_player_projections_page():
474
  st.markdown('<h2 class="section-header">Young Player Projections</h2>', unsafe_allow_html=True)
475
-
476
  # Player selection
477
  all_players = get_all_players()
478
  player_names = [player['full_name'] for player in all_players]
479
-
480
  selected_player = st.selectbox("Select Young Player (or enter manually)", [""] + player_names)
481
-
482
  if not selected_player:
483
  manual_player = st.text_input("Enter Player Name Manually")
484
  if manual_player:
485
  selected_player = manual_player
486
-
487
  if selected_player:
488
  col1, col2 = st.columns(2)
489
-
490
  with col1:
491
  current_age = st.number_input("Current Age", min_value=18, max_value=25, value=21)
492
  years_in_league = st.number_input("Years in NBA", min_value=0, max_value=7, value=2)
493
-
494
  with col2:
495
  current_ppg = st.number_input("Current PPG", min_value=0.0, max_value=40.0, value=15.0)
496
  current_rpg = st.number_input("Current RPG", min_value=0.0, max_value=20.0, value=5.0)
497
  current_apg = st.number_input("Current APG", min_value=0.0, max_value=15.0, value=3.0)
498
-
499
  if st.button("Generate AI Projection"):
500
  prompt = f"""
501
  Analyze and project the future potential of NBA player {selected_player}:
502
-
503
  Current Stats:
504
  - Age: {current_age}
505
  - Years in NBA: {years_in_league}
506
  - PPG: {current_ppg}
507
  - RPG: {current_rpg}
508
  - APG: {current_apg}
509
-
510
  Please provide:
511
  1. 3-year projection of their stats
512
  2. Peak potential analysis
513
  3. Areas for improvement
514
  4. Comparison to similar players at the same age
515
  5. Career trajectory prediction
516
-
517
  Base your analysis on historical player development patterns and current NBA trends.
518
  """
519
-
520
- with st.spinner("Generating projection..."):
521
- projection = query_perplexity(prompt, max_tokens=800)
522
  st.markdown("### AI Player Projection")
523
  st.write(projection)
524
-
525
  # Create a simple projection visualization
526
  years = [f"Year {i+1}" for i in range(5)]
527
  projected_ppg = [current_ppg * (1 + 0.1 * i) for i in range(5)] # Simple growth model
528
-
529
  fig = go.Figure()
530
  fig.add_trace(go.Scatter(
531
  x=years,
@@ -534,162 +625,166 @@ def young_player_projections_page():
534
  name='Projected PPG',
535
  line=dict(width=3, color='blue')
536
  ))
537
-
538
  fig.update_layout(
539
  title=f"{selected_player} - PPG Projection",
540
  xaxis_title="Years",
541
  yaxis_title="Points Per Game",
542
  height=400
543
  )
544
-
545
  st.plotly_chart(fig, use_container_width=True)
546
 
547
  def similar_players_page():
548
  st.markdown('<h2 class="section-header">Find Similar Players</h2>', unsafe_allow_html=True)
549
-
550
  all_players = get_all_players()
551
  player_names = [player['full_name'] for player in all_players]
552
-
553
  target_player = st.selectbox("Select Target Player", player_names)
554
-
555
  similarity_criteria = st.multiselect(
556
  "Select Similarity Criteria",
557
  ["Position", "Height/Weight", "Playing Style", "Statistical Profile", "Age/Experience"],
558
  default=["Playing Style", "Statistical Profile"]
559
  )
560
-
561
  if target_player and similarity_criteria:
562
  if st.button("Find Similar Players"):
563
  prompt = f"""
564
  Find NBA players similar to {target_player} based on the following criteria:
565
  {', '.join(similarity_criteria)}
566
-
567
  Please provide:
568
  1. Top 5 most similar current NBA players
569
  2. Top 3 historical comparisons
570
  3. Explanation of similarities for each player
571
  4. Key differences that distinguish them
572
  5. Playing style analysis
573
-
574
  Focus on both statistical similarities and playing style/role similarities.
575
  """
576
-
577
- with st.spinner("Finding similar players..."):
578
- similar_players = query_perplexity(prompt, max_tokens=800)
579
  st.markdown("### Similar Players Analysis")
580
  st.write(similar_players)
581
-
582
  # Alternative: Manual similarity finder
583
  st.subheader("Manual Player Comparison Tool")
584
-
585
  col1, col2 = st.columns(2)
586
-
587
  with col1:
588
  player1 = st.selectbox("Player 1", player_names, key="sim1")
589
-
590
  with col2:
591
  player2 = st.selectbox("Player 2", player_names, key="sim2")
592
-
593
  if player1 and player2 and player1 != player2:
594
  if st.button("Compare Players"):
595
  prompt = f"""
596
  Compare {player1} and {player2} in detail:
597
-
598
  Please analyze:
599
  1. Statistical comparison (current season)
600
  2. Playing style similarities and differences
601
  3. Strengths and weaknesses of each
602
  4. Team impact and role
603
  5. Overall similarity score (1-10)
604
-
605
  Provide a comprehensive comparison with specific examples.
606
  """
607
-
608
- comparison = query_perplexity(prompt, max_tokens=700)
609
- st.markdown("### Player Comparison Analysis")
610
- st.write(comparison)
 
611
 
612
  def roster_builder_page():
613
  st.markdown('<h2 class="section-header">NBA Roster Builder</h2>', unsafe_allow_html=True)
614
-
615
  st.subheader("Build Your Ideal NBA Roster")
616
-
617
  # Roster building parameters
618
  col1, col2 = st.columns(2)
619
-
620
  with col1:
621
  salary_cap = st.number_input("Salary Cap (Millions)", min_value=100, max_value=200, value=136)
622
  team_strategy = st.selectbox(
623
  "Team Strategy",
624
  ["Championship Contender", "Young Core Development", "Balanced Veteran Mix", "Small Ball", "Defense First"]
625
  )
626
-
627
  with col2:
628
  key_positions = st.multiselect(
629
  "Priority Positions",
630
  ["Point Guard", "Shooting Guard", "Small Forward", "Power Forward", "Center"],
631
  default=["Point Guard", "Center"]
632
  )
633
-
634
  # Player budget allocation
635
  st.subheader("Budget Allocation")
636
  position_budgets = {}
637
-
638
  positions = ["PG", "SG", "SF", "PF", "C"]
639
  cols = st.columns(5)
640
-
641
  total_allocated = 0
642
  for i, pos in enumerate(positions):
643
  with cols[i]:
644
  budget = st.number_input(f"{pos} Budget ($M)", min_value=0, max_value=50, value=20, key=f"budget_{pos}")
645
  position_budgets[pos] = budget
646
  total_allocated += budget
647
-
648
  st.write(f"Total Allocated: ${total_allocated}M / ${salary_cap}M")
649
-
650
  if total_allocated > salary_cap:
651
  st.error("Budget exceeds salary cap!")
652
-
653
  # Generate roster suggestions
654
  if st.button("Generate Roster Suggestions"):
655
- prompt = f"""
656
- Build an NBA roster with the following constraints:
657
-
658
- - Salary Cap: ${salary_cap} million
659
- - Team Strategy: {team_strategy}
660
- - Priority Positions: {', '.join(key_positions)}
661
- - Position Budgets: {position_budgets}
662
-
663
- Please provide:
664
- 1. Starting lineup with specific player recommendations
665
- 2. Key bench players (6th man, backup center, etc.)
666
- 3. Total estimated salary breakdown
667
- 4. Rationale for each major signing
668
- 5. How this roster fits the chosen strategy
669
- 6. Potential weaknesses and how to address them
670
-
671
- Focus on realistic player availability and current market values.
672
- """
673
-
674
- with st.spinner("Building your roster..."):
675
- roster_suggestions = query_perplexity(prompt, max_tokens=900)
676
- st.markdown("### AI Roster Recommendations")
677
- st.write(roster_suggestions)
678
-
 
 
 
679
  # Trade scenario analyzer
680
  st.subheader("Trade Scenario Analyzer")
681
-
682
  trade_team1 = st.text_input("Team 1 Trading:")
683
  trade_team2 = st.text_input("Team 2 Trading:")
684
-
685
  if trade_team1 and trade_team2:
686
  if st.button("Analyze Trade"):
687
  prompt = f"""
688
  Analyze this potential NBA trade:
689
-
690
  Team 1 trades: {trade_team1}
691
  Team 2 trades: {trade_team2}
692
-
693
  Please evaluate:
694
  1. Fair value assessment
695
  2. How this trade helps each team
@@ -697,13 +792,14 @@ def roster_builder_page():
697
  4. Impact on team chemistry and performance
698
  5. Likelihood of this trade happening
699
  6. Alternative trade suggestions
700
-
701
  Consider current team needs and player contracts.
702
  """
703
-
704
- trade_analysis = query_perplexity(prompt, max_tokens=700)
705
- st.markdown("### Trade Analysis")
706
- st.write(trade_analysis)
 
707
 
708
  if __name__ == "__main__":
709
  main()
 
6
  from plotly.subplots import make_subplots
7
  import requests
8
  from nba_api.stats.endpoints import (
9
+ playercareerstats, teamdetails, teamgamelog,
10
  leaguegamelog, playergamelog, commonplayerinfo, teamplayerdashboard,
11
  leagueleaders, playerestimatedmetrics, teamestimatedmetrics
12
  )
 
15
  from datetime import datetime
16
  import json
17
  import os
18
+
19
+ # --- IMPORTANT: Addressing PermissionError in Containerized Environments ---
20
+ # The error "PermissionError: [Errno 13] Permission denied: '/.streamlit'"
21
+ # occurs because Streamlit tries to write to a non-writable directory.
22
+ # To fix this in your Dockerfile or when running your Docker container,
23
+ # you should set one of the following environment variables:
24
+ #
25
+ # Option 1 (Recommended): Set the HOME environment variable to a writable path.
26
+ # In your Dockerfile: ENV HOME /tmp
27
+ # Or when running: docker run -e HOME=/tmp your_image_name
28
+ #
29
+ # Option 2: Disable Streamlit's usage statistics gathering.
30
+ # In your Dockerfile: ENV STREAMLIT_BROWSER_GATHER_USAGE_STATS=False
31
+ # Or when running: docker run -e STREAMLIT_BROWSER_GATHER_USAGE_STATS=False your_image_name
32
+ #
33
+ # Option 1 is generally more robust as it provides a writable home directory
34
+ # for any application that might need it.
35
+ # -----------------------------------------------------------------------
36
+
37
  # Page configuration
38
  st.set_page_config(
39
  page_title="NBA Analytics Hub",
 
73
 
74
  # Perplexity API configuration
75
  PERPLEXITY_API_KEY = os.getenv("PERPLEXITY_API_KEY")
76
+ PERPLEXITY_API_URL = "https://api.perplexity.ai/chat/completions"
77
+
78
+ # ---------- Perplexity API Functions ----------
79
+ def get_perplexity_response(api_key, prompt, system_message="You are a helpful NBA analyst AI.", max_tokens=500, temperature=0.2):
80
+ """
81
+ Queries the Perplexity AI API with a given prompt and system message.
82
+ """
83
+ if not api_key:
84
+ st.error("Perplexity API Key is not set. Please configure it as an environment variable (PERPLEXITY_API_KEY).")
85
+ return None
86
 
 
 
 
 
 
 
87
  headers = {
88
+ 'Authorization': f'Bearer {api_key}',
89
+ 'Content-Type': 'application/json'
90
  }
91
+ payload = {
92
+ 'model': 'sonar-medium-online', # Or 'sonar-pro-online' for more advanced capabilities
93
+ 'messages': [
94
+ {'role': 'system', 'content': system_message},
95
+ {'role': 'user', 'content': prompt}
96
+ ],
97
  "max_tokens": max_tokens,
98
+ "temperature": temperature
99
  }
 
100
  try:
101
+ with st.spinner("Querying Perplexity AI..."):
102
+ response = requests.post(PERPLEXITY_API_URL, headers=headers, json=payload, timeout=45)
103
+ response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
104
+ data = response.json()
105
+ return data.get('choices', [{}])[0].get('message', {}).get('content', '')
106
+ except requests.exceptions.RequestException as e:
107
+ error_message = f"Error communicating with Perplexity API: {e}"
108
+ if e.response is not None:
109
+ try:
110
+ error_detail = e.response.json().get("error", {}).get("message", e.response.text)
111
+ error_message = f"Perplexity API error: {error_detail}"
112
+ except ValueError: # If response is not valid JSON
113
+ error_message = f"Perplexity API error: {e.response.status_code} - {e.response.reason}"
114
+ st.error(error_message)
115
+ return None
116
  except Exception as e:
117
+ st.error(f"An unexpected error occurred with Perplexity API: {e}")
118
+ return None
119
 
120
  @st.cache_data(ttl=3600)
121
  def get_all_players():
 
150
  def create_comparison_chart(data, players_names, metric):
151
  """Create comparison chart for players"""
152
  fig = go.Figure()
153
+
154
  for i, player in enumerate(players_names):
155
  if player in data['PLAYER_NAME'].values:
156
  player_data = data[data['PLAYER_NAME'] == player]
 
161
  name=player,
162
  line=dict(width=3)
163
  ))
164
+
165
  fig.update_layout(
166
  title=f"{metric} Comparison",
167
  xaxis_title="Season",
 
169
  hovermode='x unified',
170
  height=500
171
  )
172
+
173
  return fig
174
 
175
  def create_radar_chart(player_stats, categories):
176
  """Create radar chart for player comparison"""
177
  fig = go.Figure()
178
+
179
  for player_name, stats in player_stats.items():
180
+ # Ensure all categories are present, default to 0 if not
181
+ r_values = [stats.get(cat, 0) for cat in categories]
182
+
183
  fig.add_trace(go.Scatterpolar(
184
+ r=r_values,
185
  theta=categories,
186
  fill='toself',
187
  name=player_name,
188
  opacity=0.7
189
  ))
190
+
191
  fig.update_layout(
192
  polar=dict(
193
  radialaxis=dict(
194
  visible=True,
195
+ # The range should be adjusted based on the scaled data (0-100)
196
  range=[0, 100]
197
  )),
198
  showlegend=True,
199
  title="Player Comparison Radar Chart"
200
  )
201
+
202
  return fig
203
 
204
  # Main app
205
  def main():
206
  st.markdown('<h1 class="main-header">🏀 NBA Analytics Hub</h1>', unsafe_allow_html=True)
207
+
208
  # Sidebar navigation
209
  st.sidebar.title("Navigation")
210
  page = st.sidebar.selectbox(
 
219
  "Roster Builder"
220
  ]
221
  )
222
+
223
  if page == "Player vs Player Comparison":
224
  player_comparison_page()
225
  elif page == "Team vs Team Analysis":
 
237
 
238
  def player_comparison_page():
239
  st.markdown('<h2 class="section-header">Player vs Player Comparison</h2>', unsafe_allow_html=True)
240
+
241
  # Get all players
242
  all_players = get_all_players()
243
  player_names = [player['full_name'] for player in all_players]
244
+
245
  col1, col2 = st.columns(2)
246
+
247
  with col1:
248
  selected_players = st.multiselect(
249
  "Select Players to Compare (up to 4)",
250
  player_names,
251
  max_selections=4
252
  )
253
+
254
  with col2:
255
  seasons = st.multiselect(
256
  "Select Seasons",
257
  ["2023-24", "2022-23", "2021-22", "2020-21", "2019-20"],
258
  default=["2023-24"]
259
  )
260
+
261
+ # Add a button to trigger the comparison
262
+ if st.button("Run Player Comparison"):
263
+ if not selected_players:
264
+ st.warning("Please select at least one player to compare.")
265
+ return
266
+
267
  # Get player IDs
268
  player_ids = []
269
  for name in selected_players:
270
  player_id = next((p['id'] for p in all_players if p['full_name'] == name), None)
271
  if player_id:
272
  player_ids.append(player_id)
273
+
274
  # Fetch and display stats
275
  stats_tabs = st.tabs(["Basic Stats", "Advanced Stats", "Visualizations"])
276
+
277
  with stats_tabs[0]:
278
  st.subheader("Basic Statistics")
279
  basic_stats_data = []
280
+
281
  for i, player_id in enumerate(player_ids):
282
  stats_df = get_player_stats(player_id)
283
  if not stats_df.empty:
 
287
  avg_stats = filtered_stats.mean(numeric_only=True)
288
  avg_stats['PLAYER_NAME'] = selected_players[i]
289
  basic_stats_data.append(avg_stats)
290
+
291
  if basic_stats_data:
292
  comparison_df = pd.DataFrame(basic_stats_data)
293
  basic_cols = ['PLAYER_NAME', 'GP', 'MIN', 'PTS', 'REB', 'AST', 'STL', 'BLK', 'FG_PCT', 'FT_PCT', 'FG3_PCT']
294
  display_cols = [col for col in basic_cols if col in comparison_df.columns]
295
  st.dataframe(comparison_df[display_cols].round(2), use_container_width=True)
296
+ else:
297
+ st.info("No data available for the selected players and seasons.")
298
+
299
  with stats_tabs[1]:
300
  st.subheader("Advanced Statistics")
 
301
  if basic_stats_data:
302
  advanced_df = comparison_df.copy()
303
+ # Calculate TS% (True Shooting Percentage)
304
  if all(col in advanced_df.columns for col in ['PTS', 'FGA', 'FTA']):
305
+ advanced_df['TS%'] = advanced_df.apply(
306
+ lambda row: row['PTS'] / (2 * (row['FGA'] + 0.44 * row['FTA'])) if (row['FGA'] + 0.44 * row['FTA']) != 0 else 0,
307
+ axis=1
308
+ )
309
+
310
  advanced_cols = ['PLAYER_NAME', 'PTS', 'REB', 'AST', 'FG_PCT', 'TS%'] if 'TS%' in advanced_df.columns else ['PLAYER_NAME', 'PTS', 'REB', 'AST', 'FG_PCT']
311
  display_cols = [col for col in advanced_cols if col in advanced_df.columns]
312
  st.dataframe(advanced_df[display_cols].round(3), use_container_width=True)
313
+ else:
314
+ st.info("No data available for advanced statistics.")
315
+
316
  with stats_tabs[2]:
317
  st.subheader("Player Comparison Charts")
318
+
319
  if basic_stats_data:
 
320
  metrics = ['PTS', 'REB', 'AST', 'FG_PCT']
321
  available_metrics = [m for m in metrics if m in comparison_df.columns]
322
+
323
+ if available_metrics:
324
+ selected_metric = st.selectbox("Select Metric to Visualize", available_metrics)
325
+
326
+ if selected_metric:
327
+ # Bar chart comparison
328
+ fig = px.bar(
329
+ comparison_df,
330
+ x='PLAYER_NAME',
331
+ y=selected_metric,
332
+ title=f"{selected_metric} Comparison",
333
+ color='PLAYER_NAME'
334
+ )
335
+ st.plotly_chart(fig, use_container_width=True)
336
+
337
+ # Radar chart for multi-metric comparison
338
+ # It's crucial to normalize data for radar charts if metrics have vastly different scales.
339
+ radar_metrics_for_chart = ['PTS', 'REB', 'AST', 'STL', 'BLK']
340
+ radar_metrics_for_chart = [m for m in radar_metrics_for_chart if m in comparison_df.columns]
341
+
342
+ if len(radar_metrics_for_chart) >= 3:
343
+ radar_data = {}
344
+ scaled_comparison_df = comparison_df.copy()
345
+
346
+ # Simple min-max scaling for radar chart visualization (0-100)
347
+ for col in radar_metrics_for_chart:
348
+ min_val = scaled_comparison_df[col].min()
349
+ max_val = scaled_comparison_df[col].max()
350
+ if max_val > min_val:
351
+ scaled_comparison_df[col] = ((scaled_comparison_df[col] - min_val) / (max_val - min_val)) * 100
352
+ else:
353
+ scaled_comparison_df[col] = 0 # Default if all values are the same
354
+
355
+ for _, row in scaled_comparison_df.iterrows():
356
+ radar_data[row['PLAYER_NAME']] = {
357
+ metric: row[metric] for metric in radar_metrics_for_chart
358
+ }
359
+
360
+ if radar_data:
361
+ radar_fig = create_radar_chart(radar_data, radar_metrics_for_chart)
362
+ st.plotly_chart(radar_fig, use_container_width=True)
363
+ else:
364
+ st.info("Could not generate radar chart data.")
365
+ else:
366
+ st.info("Select at least 3 common metrics for a radar chart (e.g., PTS, REB, AST, STL, BLK).")
367
+ else:
368
+ st.info("No common metrics available for visualization.")
369
+ else:
370
+ st.info("No data available for visualizations.")
371
+
372
 
373
  def team_comparison_page():
374
  st.markdown('<h2 class="section-header">Team vs Team Analysis</h2>', unsafe_allow_html=True)
375
+
376
  all_teams = get_all_teams()
377
  team_names = [team['full_name'] for team in all_teams]
378
+
379
  col1, col2 = st.columns(2)
380
+
381
  with col1:
382
  selected_teams = st.multiselect(
383
  "Select Teams to Compare",
384
  team_names,
385
  max_selections=4
386
  )
387
+
388
  with col2:
389
  seasons = st.multiselect(
390
  "Select Seasons",
391
  ["2023-24", "2022-23", "2021-22", "2020-21"],
392
  default=["2023-24"]
393
  )
394
+
395
+ # Add a button to trigger the comparison
396
+ if st.button("Run Team Comparison"):
397
+ if not selected_teams:
398
+ st.warning("Please select at least one team to compare.")
399
+ return
400
+
401
  team_stats_data = []
402
+
403
  for team_name in selected_teams:
404
  team_id = next((t['id'] for t in all_teams if t['full_name'] == team_name), None)
405
  if team_id:
 
410
  team_avg['TEAM_NAME'] = team_name
411
  team_avg['SEASON'] = season
412
  team_stats_data.append(team_avg)
413
+
414
  if team_stats_data:
415
  team_df = pd.DataFrame(team_stats_data)
416
+
417
  # Display team comparison
418
  st.subheader("Team Statistics Comparison")
419
  team_cols = ['TEAM_NAME', 'SEASON', 'PTS', 'REB', 'AST', 'FG_PCT', 'FG3_PCT', 'FT_PCT']
420
  display_cols = [col for col in team_cols if col in team_df.columns]
421
  st.dataframe(team_df[display_cols].round(2), use_container_width=True)
422
+
423
  # Visualization
424
  st.subheader("Team Performance Visualization")
425
  metric_options = ['PTS', 'REB', 'AST', 'FG_PCT']
426
  available_metrics = [m for m in metric_options if m in team_df.columns]
427
+
428
  if available_metrics:
429
  selected_metric = st.selectbox("Select Metric", available_metrics)
430
+
431
  fig = px.bar(
432
  team_df,
433
  x='TEAM_NAME',
 
437
  barmode='group'
438
  )
439
  st.plotly_chart(fig, use_container_width=True)
440
+ else:
441
+ st.info("No common metrics available for visualization.")
442
+ else:
443
+ st.info("No data available for the selected teams and seasons.")
444
+
445
 
446
  def awards_predictor_page():
447
  st.markdown('<h2 class="section-header">NBA Awards Predictor</h2>', unsafe_allow_html=True)
448
+
449
  award_type = st.selectbox(
450
  "Select Award Type",
451
  ["MVP", "Defensive Player of the Year", "Rookie of the Year", "6th Man of the Year", "All-NBA First Team"]
452
  )
453
+
454
  st.subheader(f"{award_type} Prediction Criteria")
455
+
456
  # Define criteria for different awards
457
+ criteria = {}
458
  if award_type == "MVP":
459
  criteria = {
460
  "Points Per Game": st.slider("Minimum PPG", 15.0, 35.0, 25.0),
 
469
  "Defensive Rating": st.slider("Maximum Defensive Rating", 90.0, 120.0, 105.0),
470
  "Team Defensive Ranking": st.slider("Maximum Team Def Rank", 1, 30, 10)
471
  }
472
+ else: # Default for Rookie of the Year, 6th Man, All-NBA
473
  criteria = {
474
  "Points Per Game": st.slider("Minimum PPG", 10.0, 30.0, 15.0),
475
  "Games Played": st.slider("Minimum Games", 50, 82, 65),
476
  "Shooting Efficiency": st.slider("Minimum FG%", 0.35, 0.65, 0.45)
477
  }
478
+
479
  if st.button("Generate Predictions"):
 
480
  prompt = f"""
481
  Based on the following criteria for {award_type}, analyze current NBA players and provide predictions:
482
+
483
  Criteria: {criteria}
484
+
485
  Please provide:
486
  1. Top 5 candidates with their stats
487
  2. Analysis of why each candidate fits the criteria
488
  3. Your prediction for the winner with reasoning
489
+
490
  Focus on current 2023-24 season performance and recent trends.
491
  """
492
+
493
+ prediction = get_perplexity_response(PERPLEXITY_API_KEY, prompt, max_tokens=800, system_message="You are an NBA awards prediction expert AI.")
494
+ if prediction:
495
  st.markdown("### AI Prediction Analysis")
496
  st.write(prediction)
497
 
498
  def ai_chat_page():
499
  st.markdown('<h2 class="section-header">AI NBA Chat & Insights</h2>', unsafe_allow_html=True)
500
+
501
  # Chat interface
502
  st.subheader("Ask AI About NBA Stats and Insights")
503
+
504
  # Display chat history
505
  for message in st.session_state.chat_history:
506
  with st.chat_message(message["role"]):
507
  st.write(message["content"])
508
+
509
  # Chat input
510
  if prompt := st.chat_input("Ask about NBA players, teams, stats, or strategies..."):
511
  # Add user message to chat history
512
  st.session_state.chat_history.append({"role": "user", "content": prompt})
513
+
514
  # Display user message
515
  with st.chat_message("user"):
516
  st.write(prompt)
517
+
518
  # Generate AI response
519
  with st.chat_message("assistant"):
520
+ # Enhance prompt with NBA context
521
+ enhanced_prompt = f"""
522
+ As an NBA expert analyst, please answer this question about basketball:
523
+
524
+ {prompt}
525
+
526
+ Please provide detailed analysis with current stats, trends, and insights when relevant.
527
+ If specific player or team stats are mentioned, include recent performance data.
528
+ """
529
+
530
+ response = get_perplexity_response(PERPLEXITY_API_KEY, enhanced_prompt, max_tokens=700, system_message="You are an NBA expert analyst AI.")
531
+ if response:
532
  st.write(response)
 
533
  # Add assistant response to chat history
534
  st.session_state.chat_history.append({"role": "assistant", "content": response})
535
+ else:
536
+ st.session_state.chat_history.append({"role": "assistant", "content": "Sorry, I couldn't get a response from the AI."})
537
+
538
+
539
  # Quick action buttons
540
  st.subheader("Quick Insights")
541
  col1, col2, col3 = st.columns(3)
542
+
543
  with col1:
544
  if st.button("🏆 Championship Contenders"):
545
  prompt = "Analyze the current NBA championship contenders for 2024. Who are the top 5 teams and why?"
546
+ response = get_perplexity_response(PERPLEXITY_API_KEY, prompt, system_message="You are an NBA expert analyst AI.")
547
+ if response:
548
+ st.write(response)
549
+
550
  with col2:
551
  if st.button("⭐ Rising Stars"):
552
  prompt = "Who are the most promising young NBA players to watch in 2024? Focus on players 23 and under."
553
+ response = get_perplexity_response(PERPLEXITY_API_KEY, prompt, system_message="You are an NBA expert analyst AI.")
554
+ if response:
555
+ st.write(response)
556
+
557
  with col3:
558
  if st.button("📊 Trade Analysis"):
559
  prompt = "What are some potential NBA trades that could happen this season? Analyze team needs and available players."
560
+ response = get_perplexity_response(PERPLEXITY_API_KEY, prompt, system_message="You are an NBA expert analyst AI.")
561
+ if response:
562
+ st.write(response)
563
 
564
  def young_player_projections_page():
565
  st.markdown('<h2 class="section-header">Young Player Projections</h2>', unsafe_allow_html=True)
566
+
567
  # Player selection
568
  all_players = get_all_players()
569
  player_names = [player['full_name'] for player in all_players]
570
+
571
  selected_player = st.selectbox("Select Young Player (or enter manually)", [""] + player_names)
572
+
573
  if not selected_player:
574
  manual_player = st.text_input("Enter Player Name Manually")
575
  if manual_player:
576
  selected_player = manual_player
577
+
578
  if selected_player:
579
  col1, col2 = st.columns(2)
580
+
581
  with col1:
582
  current_age = st.number_input("Current Age", min_value=18, max_value=25, value=21)
583
  years_in_league = st.number_input("Years in NBA", min_value=0, max_value=7, value=2)
584
+
585
  with col2:
586
  current_ppg = st.number_input("Current PPG", min_value=0.0, max_value=40.0, value=15.0)
587
  current_rpg = st.number_input("Current RPG", min_value=0.0, max_value=20.0, value=5.0)
588
  current_apg = st.number_input("Current APG", min_value=0.0, max_value=15.0, value=3.0)
589
+
590
  if st.button("Generate AI Projection"):
591
  prompt = f"""
592
  Analyze and project the future potential of NBA player {selected_player}:
593
+
594
  Current Stats:
595
  - Age: {current_age}
596
  - Years in NBA: {years_in_league}
597
  - PPG: {current_ppg}
598
  - RPG: {current_rpg}
599
  - APG: {current_apg}
600
+
601
  Please provide:
602
  1. 3-year projection of their stats
603
  2. Peak potential analysis
604
  3. Areas for improvement
605
  4. Comparison to similar players at the same age
606
  5. Career trajectory prediction
607
+
608
  Base your analysis on historical player development patterns and current NBA trends.
609
  """
610
+
611
+ projection = get_perplexity_response(PERPLEXITY_API_KEY, prompt, max_tokens=800, system_message="You are an NBA player projection expert AI.")
612
+ if projection:
613
  st.markdown("### AI Player Projection")
614
  st.write(projection)
615
+
616
  # Create a simple projection visualization
617
  years = [f"Year {i+1}" for i in range(5)]
618
  projected_ppg = [current_ppg * (1 + 0.1 * i) for i in range(5)] # Simple growth model
619
+
620
  fig = go.Figure()
621
  fig.add_trace(go.Scatter(
622
  x=years,
 
625
  name='Projected PPG',
626
  line=dict(width=3, color='blue')
627
  ))
628
+
629
  fig.update_layout(
630
  title=f"{selected_player} - PPG Projection",
631
  xaxis_title="Years",
632
  yaxis_title="Points Per Game",
633
  height=400
634
  )
635
+
636
  st.plotly_chart(fig, use_container_width=True)
637
 
638
  def similar_players_page():
639
  st.markdown('<h2 class="section-header">Find Similar Players</h2>', unsafe_allow_html=True)
640
+
641
  all_players = get_all_players()
642
  player_names = [player['full_name'] for player in all_players]
643
+
644
  target_player = st.selectbox("Select Target Player", player_names)
645
+
646
  similarity_criteria = st.multiselect(
647
  "Select Similarity Criteria",
648
  ["Position", "Height/Weight", "Playing Style", "Statistical Profile", "Age/Experience"],
649
  default=["Playing Style", "Statistical Profile"]
650
  )
651
+
652
  if target_player and similarity_criteria:
653
  if st.button("Find Similar Players"):
654
  prompt = f"""
655
  Find NBA players similar to {target_player} based on the following criteria:
656
  {', '.join(similarity_criteria)}
657
+
658
  Please provide:
659
  1. Top 5 most similar current NBA players
660
  2. Top 3 historical comparisons
661
  3. Explanation of similarities for each player
662
  4. Key differences that distinguish them
663
  5. Playing style analysis
664
+
665
  Focus on both statistical similarities and playing style/role similarities.
666
  """
667
+
668
+ similar_players = get_perplexity_response(PERPLEXITY_API_KEY, prompt, max_tokens=800, system_message="You are an NBA player similarity expert AI.")
669
+ if similar_players:
670
  st.markdown("### Similar Players Analysis")
671
  st.write(similar_players)
672
+
673
  # Alternative: Manual similarity finder
674
  st.subheader("Manual Player Comparison Tool")
675
+
676
  col1, col2 = st.columns(2)
677
+
678
  with col1:
679
  player1 = st.selectbox("Player 1", player_names, key="sim1")
680
+
681
  with col2:
682
  player2 = st.selectbox("Player 2", player_names, key="sim2")
683
+
684
  if player1 and player2 and player1 != player2:
685
  if st.button("Compare Players"):
686
  prompt = f"""
687
  Compare {player1} and {player2} in detail:
688
+
689
  Please analyze:
690
  1. Statistical comparison (current season)
691
  2. Playing style similarities and differences
692
  3. Strengths and weaknesses of each
693
  4. Team impact and role
694
  5. Overall similarity score (1-10)
695
+
696
  Provide a comprehensive comparison with specific examples.
697
  """
698
+
699
+ comparison = get_perplexity_response(PERPLEXITY_API_KEY, prompt, max_tokens=700, system_message="You are an NBA player comparison expert AI.")
700
+ if comparison:
701
+ st.markdown("### Player Comparison Analysis")
702
+ st.write(comparison)
703
 
704
  def roster_builder_page():
705
  st.markdown('<h2 class="section-header">NBA Roster Builder</h2>', unsafe_allow_html=True)
706
+
707
  st.subheader("Build Your Ideal NBA Roster")
708
+
709
  # Roster building parameters
710
  col1, col2 = st.columns(2)
711
+
712
  with col1:
713
  salary_cap = st.number_input("Salary Cap (Millions)", min_value=100, max_value=200, value=136)
714
  team_strategy = st.selectbox(
715
  "Team Strategy",
716
  ["Championship Contender", "Young Core Development", "Balanced Veteran Mix", "Small Ball", "Defense First"]
717
  )
718
+
719
  with col2:
720
  key_positions = st.multiselect(
721
  "Priority Positions",
722
  ["Point Guard", "Shooting Guard", "Small Forward", "Power Forward", "Center"],
723
  default=["Point Guard", "Center"]
724
  )
725
+
726
  # Player budget allocation
727
  st.subheader("Budget Allocation")
728
  position_budgets = {}
729
+
730
  positions = ["PG", "SG", "SF", "PF", "C"]
731
  cols = st.columns(5)
732
+
733
  total_allocated = 0
734
  for i, pos in enumerate(positions):
735
  with cols[i]:
736
  budget = st.number_input(f"{pos} Budget ($M)", min_value=0, max_value=50, value=20, key=f"budget_{pos}")
737
  position_budgets[pos] = budget
738
  total_allocated += budget
739
+
740
  st.write(f"Total Allocated: ${total_allocated}M / ${salary_cap}M")
741
+
742
  if total_allocated > salary_cap:
743
  st.error("Budget exceeds salary cap!")
744
+
745
  # Generate roster suggestions
746
  if st.button("Generate Roster Suggestions"):
747
+ if total_allocated <= salary_cap:
748
+ prompt = f"""
749
+ Build an NBA roster with the following constraints:
750
+
751
+ - Salary Cap: ${salary_cap} million
752
+ - Team Strategy: {team_strategy}
753
+ - Priority Positions: {', '.join(key_positions)}
754
+ - Position Budgets: {position_budgets}
755
+
756
+ Please provide:
757
+ 1. Starting lineup with specific player recommendations
758
+ 2. Key bench players (6th man, backup center, etc.)
759
+ 3. Total estimated salary breakdown
760
+ 4. Rationale for each major signing
761
+ 5. How this roster fits the chosen strategy
762
+ 6. Potential weaknesses and how to address them
763
+
764
+ Focus on realistic player availability and current market values.
765
+ """
766
+
767
+ roster_suggestions = get_perplexity_response(PERPLEXITY_API_KEY, prompt, max_tokens=900, system_message="You are an NBA roster building expert AI.")
768
+ if roster_suggestions:
769
+ st.markdown("### AI Roster Recommendations")
770
+ st.write(roster_suggestions)
771
+ else:
772
+ st.warning("Please adjust your budget to be within the salary cap before generating suggestions.")
773
+
774
  # Trade scenario analyzer
775
  st.subheader("Trade Scenario Analyzer")
776
+
777
  trade_team1 = st.text_input("Team 1 Trading:")
778
  trade_team2 = st.text_input("Team 2 Trading:")
779
+
780
  if trade_team1 and trade_team2:
781
  if st.button("Analyze Trade"):
782
  prompt = f"""
783
  Analyze this potential NBA trade:
784
+
785
  Team 1 trades: {trade_team1}
786
  Team 2 trades: {trade_team2}
787
+
788
  Please evaluate:
789
  1. Fair value assessment
790
  2. How this trade helps each team
 
792
  4. Impact on team chemistry and performance
793
  5. Likelihood of this trade happening
794
  6. Alternative trade suggestions
795
+
796
  Consider current team needs and player contracts.
797
  """
798
+
799
+ trade_analysis = get_perplexity_response(PERPLEXITY_API_KEY, prompt, max_tokens=700, system_message="You are an NBA trade analysis expert AI.")
800
+ if trade_analysis:
801
+ st.markdown("### Trade Analysis")
802
+ st.write(trade_analysis)
803
 
804
  if __name__ == "__main__":
805
  main()