nba-buzz / app.py
cdechoch's picture
Update app.py
3e718bc verified
"""NBA Buzz - FastAPI Backend"""
from fastapi import FastAPI, BackgroundTasks
from fastapi.responses import HTMLResponse
import threading
import time
from datetime import datetime, timezone
from bluesky_fetcher import BlueskyFetcher, load_handles_from_csv
import player_matcher
import database
from nba_teams import get_player_team, get_team_abbreviation, get_team_players, get_all_teams, PLAYER_TEAMS
app = FastAPI(title="NBA Buzz API")
is_fetching = False
fetch_status = "Ready"
def do_fetch():
global is_fetching, fetch_status
if is_fetching:
return
is_fetching = True
try:
handles = load_handles_from_csv("bluesky_handles.csv")
if handles:
fetch_status = f"Fetching {len(handles)} accounts..."
bsky = BlueskyFetcher()
posts = bsky.fetch_multiple_accounts(handles, posts_per_account=25, delay=0.15)
print(f"Fetched {len(posts)} posts")
added, mentions = database.process_and_store_posts(posts, player_matcher, get_player_team)
print(f"Stored {added} posts, {mentions} mentions")
database.set_last_update()
database.cleanup_old_data(days=3)
fetch_status = f"Updated {datetime.now(timezone.utc).strftime('%H:%M UTC')}"
except Exception as e:
fetch_status = f"Error: {str(e)[:50]}"
print(f"Fetch error: {e}")
finally:
is_fetching = False
def auto_refresh_loop():
"""Background thread that refreshes data every 15 minutes."""
while True:
time.sleep(900) # 15 minutes
print("Auto-refresh triggered")
do_fetch()
# Auto-fetch on startup
thread = threading.Thread(target=do_fetch, daemon=True)
thread.start()
# Start auto-refresh loop
refresh_thread = threading.Thread(target=auto_refresh_loop, daemon=True)
refresh_thread.start()
@app.get("/api/status")
def get_status():
stats = database.get_database_stats()
return {
"total_posts": stats['total_posts'],
"total_mentions": stats['total_mentions'],
"unique_players": stats['unique_players'],
"last_update": database.get_last_update(),
"is_fetching": is_fetching,
"fetch_status": fetch_status
}
@app.get("/api/players")
def get_players(hours: int = 24, limit: int = 50):
counts = database.get_player_mention_counts(hours=hours, limit=limit)
result = []
for i, item in enumerate(counts, 1):
team = item.get("team_name") or ""
entry = {
"rank": i,
"player": item["player_name"],
"team": team,
"team_abbrev": get_team_abbreviation(team),
"mentions": item["mention_count"]
}
# Add latest mention for top 5
if i <= 5:
latest = database.get_latest_mention_for_player(item["player_name"], hours=hours)
if latest:
entry["latest_mention"] = latest
result.append(entry)
return result
@app.get("/api/teams")
def get_teams(hours: int = 24, limit: int = 30):
counts = database.get_team_mention_counts(hours=hours, limit=limit)
result = []
for i, item in enumerate(counts, 1):
entry = {
"rank": i,
"team": item["team_name"],
"team_abbrev": get_team_abbreviation(item["team_name"]),
"mentions": item["mention_count"]
}
# Add latest mention for top 5
if i <= 5:
latest = database.get_latest_mention_for_team(item["team_name"], hours=hours)
if latest:
entry["latest_mention"] = latest
result.append(entry)
return result
@app.get("/api/search")
def search(q: str):
q_lower = q.lower()
players = [p for p in PLAYER_TEAMS.keys() if q_lower in p.lower()][:10]
teams = [t for t in get_all_teams() if q_lower in t.lower()][:5]
return {"players": players, "teams": teams}
@app.get("/api/player/{player_name}")
def get_player_info(player_name: str):
team = get_player_team(player_name)
teammates = get_team_players(team)[:10] if team else []
teammates = [t for t in teammates if t != player_name][:5]
# Get period stats
period_stats = []
for hours, label in [(6, "6h"), (12, "12h"), (24, "24h"), (48, "48h"), (168, "7d")]:
counts = database.get_player_mention_counts(hours=hours, limit=100)
mentions = 0
rank = None
for i, item in enumerate(counts, 1):
if item["player_name"] == player_name:
mentions = item["mention_count"]
rank = i
break
period_stats.append({"hours": hours, "label": label, "mentions": mentions, "rank": rank})
return {
"player": player_name,
"team": team,
"team_abbrev": get_team_abbreviation(team),
"teammates": teammates,
"period_stats": period_stats
}
@app.get("/api/team/{team_name}")
def get_team_info(team_name: str):
players = get_team_players(team_name)[:15]
# Get period stats
period_stats = []
for hours, label in [(6, "6h"), (12, "12h"), (24, "24h"), (48, "48h"), (168, "7d")]:
counts = database.get_team_mention_counts(hours=hours, limit=30)
mentions = 0
rank = None
for i, item in enumerate(counts, 1):
if item["team_name"] == team_name:
mentions = item["mention_count"]
rank = i
break
period_stats.append({"hours": hours, "label": label, "mentions": mentions, "rank": rank})
return {
"team": team_name,
"team_abbrev": get_team_abbreviation(team_name),
"players": players,
"period_stats": period_stats
}
@app.get("/api/mentions/{player_name}")
def get_player_mentions(player_name: str, limit: int = 50):
return database.get_player_recent_mentions(player_name, limit=limit)
@app.get("/api/team-mentions/{team_name}")
def get_team_mentions(team_name: str, limit: int = 50):
return database.get_team_recent_mentions(team_name, limit=limit)
@app.post("/api/refresh")
def trigger_refresh(background_tasks: BackgroundTasks):
if is_fetching:
return {"status": "already_fetching"}
background_tasks.add_task(do_fetch)
return {"status": "started"}
@app.get("/", response_class=HTMLResponse)
def serve_index():
return open("index.html", "r").read()
@app.get("/player/{player_name}", response_class=HTMLResponse)
def serve_player_page(player_name: str):
return open("player.html", "r").read()
@app.get("/team/{team_name}", response_class=HTMLResponse)
def serve_team_page(team_name: str):
return open("team.html", "r").read()
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)