Spaces:
No application file
No application file
Liss, Alex (NYC-HUG)
commited on
Commit
·
bb4fc9d
1
Parent(s):
ef3bbde
preparing to execute sprint 1 feature work log
Browse files
data/april_11_multimedia_data_collect/nfl_team_logos.csv
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
team_name,logo_url,local_path
|
2 |
+
"Arizona Cardinals News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/ARI,"team_logos/arizona_cardinals_news,_scores,_stats,_schedule.png"
|
3 |
+
"Atlanta Falcons News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/ATL,"team_logos/atlanta_falcons_news,_scores,_stats,_schedule.png"
|
4 |
+
"Carolina Panthers News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/CAR,"team_logos/carolina_panthers_news,_scores,_stats,_schedule.png"
|
5 |
+
"Chicago Bears News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/CHI,"team_logos/chicago_bears_news,_scores,_stats,_schedule.png"
|
6 |
+
"Dallas Cowboys News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/DAL,"team_logos/dallas_cowboys_news,_scores,_stats,_schedule.png"
|
7 |
+
"Detroit Lions News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/DET,"team_logos/detroit_lions_news,_scores,_stats,_schedule.png"
|
8 |
+
"Green Bay Packers News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/GB,"team_logos/green_bay_packers_news,_scores,_stats,_schedule.png"
|
9 |
+
"Los Angeles Rams News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/LA,"team_logos/los_angeles_rams_news,_scores,_stats,_schedule.png"
|
10 |
+
"Minnesota Vikings News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/MIN,"team_logos/minnesota_vikings_news,_scores,_stats,_schedule.png"
|
11 |
+
"New Orleans Saints News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/NO,"team_logos/new_orleans_saints_news,_scores,_stats,_schedule.png"
|
12 |
+
"New York Giants News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/NYG,"team_logos/new_york_giants_news,_scores,_stats,_schedule.png"
|
13 |
+
"Philadelphia Eagles News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/PHI,"team_logos/philadelphia_eagles_news,_scores,_stats,_schedule.png"
|
14 |
+
"San Francisco 49ers News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/SF,"team_logos/san_francisco_49ers_news,_scores,_stats,_schedule.png"
|
15 |
+
"Seattle Seahawks News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/SEA,"team_logos/seattle_seahawks_news,_scores,_stats,_schedule.png"
|
16 |
+
"Tampa Bay Buccaneers News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/TB,"team_logos/tampa_bay_buccaneers_news,_scores,_stats,_schedule.png"
|
17 |
+
"Washington Commanders News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/WAS,"team_logos/washington_commanders_news,_scores,_stats,_schedule.png"
|
18 |
+
"Baltimore Ravens News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/BAL,"team_logos/baltimore_ravens_news,_scores,_stats,_schedule.png"
|
19 |
+
"Buffalo Bills News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/BUF,"team_logos/buffalo_bills_news,_scores,_stats,_schedule.png"
|
20 |
+
"Cincinnati Bengals News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/CIN,"team_logos/cincinnati_bengals_news,_scores,_stats,_schedule.png"
|
21 |
+
"Cleveland Browns News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/CLE,"team_logos/cleveland_browns_news,_scores,_stats,_schedule.png"
|
22 |
+
"Denver Broncos News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/DEN,"team_logos/denver_broncos_news,_scores,_stats,_schedule.png"
|
23 |
+
"Jacksonville Jaguars News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/JAX,"team_logos/jacksonville_jaguars_news,_scores,_stats,_schedule.png"
|
24 |
+
"Kansas City Chiefs News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/KC,"team_logos/kansas_city_chiefs_news,_scores,_stats,_schedule.png"
|
25 |
+
"Las Vegas Raiders News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/LV,"team_logos/las_vegas_raiders_news,_scores,_stats,_schedule.png"
|
26 |
+
"Los Angeles Chargers News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/LAC,"team_logos/los_angeles_chargers_news,_scores,_stats,_schedule.png"
|
27 |
+
"Miami Dolphins News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/MIA,"team_logos/miami_dolphins_news,_scores,_stats,_schedule.png"
|
28 |
+
"New England Patriots News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/NE,"team_logos/new_england_patriots_news,_scores,_stats,_schedule.png"
|
29 |
+
"New York Jets News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/NYJ,"team_logos/new_york_jets_news,_scores,_stats,_schedule.png"
|
30 |
+
"Pittsburgh Steelers News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/PIT,"team_logos/pittsburgh_steelers_news,_scores,_stats,_schedule.png"
|
31 |
+
"Tennessee Titans News, Scores, Stats, Schedule",https://static.www.nfl.com/t_headshot_desktop/league/api/clubs/logos/TEN,"team_logos/tennessee_titans_news,_scores,_stats,_schedule.png"
|
32 |
+
Arizona Cardinals,https://a.espncdn.com/i/teamlogos/nfl/500/ari.png,team_logos/arizona_cardinals.png
|
33 |
+
Atlanta Falcons,https://a.espncdn.com/i/teamlogos/nfl/500/atl.png,team_logos/atlanta_falcons.png
|
34 |
+
Baltimore Ravens,https://a.espncdn.com/i/teamlogos/nfl/500/bal.png,team_logos/baltimore_ravens.png
|
35 |
+
Buffalo Bills,https://a.espncdn.com/i/teamlogos/nfl/500/buf.png,team_logos/buffalo_bills.png
|
36 |
+
Carolina Panthers,https://a.espncdn.com/i/teamlogos/nfl/500/car.png,team_logos/carolina_panthers.png
|
37 |
+
Chicago Bears,https://a.espncdn.com/i/teamlogos/nfl/500/chi.png,team_logos/chicago_bears.png
|
38 |
+
Cincinnati Bengals,https://a.espncdn.com/i/teamlogos/nfl/500/cin.png,team_logos/cincinnati_bengals.png
|
39 |
+
Cleveland Browns,https://a.espncdn.com/i/teamlogos/nfl/500/cle.png,team_logos/cleveland_browns.png
|
40 |
+
Dallas Cowboys,https://a.espncdn.com/i/teamlogos/nfl/500/dal.png,team_logos/dallas_cowboys.png
|
41 |
+
Denver Broncos,https://a.espncdn.com/i/teamlogos/nfl/500/den.png,team_logos/denver_broncos.png
|
42 |
+
Detroit Lions,https://a.espncdn.com/i/teamlogos/nfl/500/det.png,team_logos/detroit_lions.png
|
43 |
+
Green Bay Packers,https://a.espncdn.com/i/teamlogos/nfl/500/gb.png,team_logos/green_bay_packers.png
|
44 |
+
Houston Texans,https://a.espncdn.com/i/teamlogos/nfl/500/hou.png,team_logos/houston_texans.png
|
45 |
+
Indianapolis Colts,https://a.espncdn.com/i/teamlogos/nfl/500/ind.png,team_logos/indianapolis_colts.png
|
46 |
+
Jacksonville Jaguars,https://a.espncdn.com/i/teamlogos/nfl/500/jax.png,team_logos/jacksonville_jaguars.png
|
47 |
+
Kansas City Chiefs,https://a.espncdn.com/i/teamlogos/nfl/500/kc.png,team_logos/kansas_city_chiefs.png
|
48 |
+
Las Vegas Raiders,https://a.espncdn.com/i/teamlogos/nfl/500/lv.png,team_logos/las_vegas_raiders.png
|
49 |
+
Los Angeles Chargers,https://a.espncdn.com/i/teamlogos/nfl/500/lac.png,team_logos/los_angeles_chargers.png
|
50 |
+
Los Angeles Rams,https://a.espncdn.com/i/teamlogos/nfl/500/lar.png,team_logos/los_angeles_rams.png
|
51 |
+
Miami Dolphins,https://a.espncdn.com/i/teamlogos/nfl/500/mia.png,team_logos/miami_dolphins.png
|
52 |
+
Minnesota Vikings,https://a.espncdn.com/i/teamlogos/nfl/500/min.png,team_logos/minnesota_vikings.png
|
53 |
+
New England Patriots,https://a.espncdn.com/i/teamlogos/nfl/500/ne.png,team_logos/new_england_patriots.png
|
54 |
+
New Orleans Saints,https://a.espncdn.com/i/teamlogos/nfl/500/no.png,team_logos/new_orleans_saints.png
|
55 |
+
New York Giants,https://a.espncdn.com/i/teamlogos/nfl/500/nyg.png,team_logos/new_york_giants.png
|
56 |
+
New York Jets,https://a.espncdn.com/i/teamlogos/nfl/500/nyj.png,team_logos/new_york_jets.png
|
57 |
+
Philadelphia Eagles,https://a.espncdn.com/i/teamlogos/nfl/500/phi.png,team_logos/philadelphia_eagles.png
|
58 |
+
Pittsburgh Steelers,https://a.espncdn.com/i/teamlogos/nfl/500/pit.png,team_logos/pittsburgh_steelers.png
|
59 |
+
San Francisco 49ers,https://a.espncdn.com/i/teamlogos/nfl/500/sf.png,team_logos/san_francisco_49ers.png
|
60 |
+
Seattle Seahawks,https://a.espncdn.com/i/teamlogos/nfl/500/sea.png,team_logos/seattle_seahawks.png
|
61 |
+
Tampa Bay Buccaneers,https://a.espncdn.com/i/teamlogos/nfl/500/tb.png,team_logos/tampa_bay_buccaneers.png
|
62 |
+
Tennessee Titans,https://a.espncdn.com/i/teamlogos/nfl/500/ten.png,team_logos/tennessee_titans.png
|
63 |
+
Washington Commanders,https://a.espncdn.com/i/teamlogos/nfl/500/wsh.png,team_logos/washington_commanders.png
|
data/april_11_multimedia_data_collect/nfl_team_logos_revised.csv
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
team_name,logo_url,local_path
|
2 |
+
Arizona Cardinals,https://a.espncdn.com/i/teamlogos/nfl/500/ari.png,team_logos/arizona_cardinals.png
|
3 |
+
Atlanta Falcons,https://a.espncdn.com/i/teamlogos/nfl/500/atl.png,team_logos/atlanta_falcons.png
|
4 |
+
Baltimore Ravens,https://a.espncdn.com/i/teamlogos/nfl/500/bal.png,team_logos/baltimore_ravens.png
|
5 |
+
Buffalo Bills,https://a.espncdn.com/i/teamlogos/nfl/500/buf.png,team_logos/buffalo_bills.png
|
6 |
+
Carolina Panthers,https://a.espncdn.com/i/teamlogos/nfl/500/car.png,team_logos/carolina_panthers.png
|
7 |
+
Chicago Bears,https://a.espncdn.com/i/teamlogos/nfl/500/chi.png,team_logos/chicago_bears.png
|
8 |
+
Cincinnati Bengals,https://a.espncdn.com/i/teamlogos/nfl/500/cin.png,team_logos/cincinnati_bengals.png
|
9 |
+
Cleveland Browns,https://a.espncdn.com/i/teamlogos/nfl/500/cle.png,team_logos/cleveland_browns.png
|
10 |
+
Dallas Cowboys,https://a.espncdn.com/i/teamlogos/nfl/500/dal.png,team_logos/dallas_cowboys.png
|
11 |
+
Denver Broncos,https://a.espncdn.com/i/teamlogos/nfl/500/den.png,team_logos/denver_broncos.png
|
12 |
+
Detroit Lions,https://a.espncdn.com/i/teamlogos/nfl/500/det.png,team_logos/detroit_lions.png
|
13 |
+
Green Bay Packers,https://a.espncdn.com/i/teamlogos/nfl/500/gb.png,team_logos/green_bay_packers.png
|
14 |
+
Houston Texans,https://a.espncdn.com/i/teamlogos/nfl/500/hou.png,team_logos/houston_texans.png
|
15 |
+
Indianapolis Colts,https://a.espncdn.com/i/teamlogos/nfl/500/ind.png,team_logos/indianapolis_colts.png
|
16 |
+
Jacksonville Jaguars,https://a.espncdn.com/i/teamlogos/nfl/500/jax.png,team_logos/jacksonville_jaguars.png
|
17 |
+
Kansas City Chiefs,https://a.espncdn.com/i/teamlogos/nfl/500/kc.png,team_logos/kansas_city_chiefs.png
|
18 |
+
Las Vegas Raiders,https://a.espncdn.com/i/teamlogos/nfl/500/lv.png,team_logos/las_vegas_raiders.png
|
19 |
+
Los Angeles Chargers,https://a.espncdn.com/i/teamlogos/nfl/500/lac.png,team_logos/los_angeles_chargers.png
|
20 |
+
Los Angeles Rams,https://a.espncdn.com/i/teamlogos/nfl/500/lar.png,team_logos/los_angeles_rams.png
|
21 |
+
Miami Dolphins,https://a.espncdn.com/i/teamlogos/nfl/500/mia.png,team_logos/miami_dolphins.png
|
22 |
+
Minnesota Vikings,https://a.espncdn.com/i/teamlogos/nfl/500/min.png,team_logos/minnesota_vikings.png
|
23 |
+
New England Patriots,https://a.espncdn.com/i/teamlogos/nfl/500/ne.png,team_logos/new_england_patriots.png
|
24 |
+
New Orleans Saints,https://a.espncdn.com/i/teamlogos/nfl/500/no.png,team_logos/new_orleans_saints.png
|
25 |
+
New York Giants,https://a.espncdn.com/i/teamlogos/nfl/500/nyg.png,team_logos/new_york_giants.png
|
26 |
+
New York Jets,https://a.espncdn.com/i/teamlogos/nfl/500/nyj.png,team_logos/new_york_jets.png
|
27 |
+
Philadelphia Eagles,https://a.espncdn.com/i/teamlogos/nfl/500/phi.png,team_logos/philadelphia_eagles.png
|
28 |
+
Pittsburgh Steelers,https://a.espncdn.com/i/teamlogos/nfl/500/pit.png,team_logos/pittsburgh_steelers.png
|
29 |
+
San Francisco 49ers,https://a.espncdn.com/i/teamlogos/nfl/500/sf.png,team_logos/san_francisco_49ers.png
|
30 |
+
Seattle Seahawks,https://a.espncdn.com/i/teamlogos/nfl/500/sea.png,team_logos/seattle_seahawks.png
|
31 |
+
Tampa Bay Buccaneers,https://a.espncdn.com/i/teamlogos/nfl/500/tb.png,team_logos/tampa_bay_buccaneers.png
|
32 |
+
Tennessee Titans,https://a.espncdn.com/i/teamlogos/nfl/500/ten.png,team_logos/tennessee_titans.png
|
33 |
+
Washington Commanders,https://a.espncdn.com/i/teamlogos/nfl/500/wsh.png,team_logos/washington_commanders.png
|
data/april_11_multimedia_data_collect/team_logos.py
ADDED
@@ -0,0 +1,298 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
from bs4 import BeautifulSoup
|
3 |
+
import csv
|
4 |
+
import os
|
5 |
+
import time
|
6 |
+
import re
|
7 |
+
import json
|
8 |
+
import logging
|
9 |
+
|
10 |
+
# Set up logging
|
11 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
12 |
+
logger = logging.getLogger(__name__)
|
13 |
+
|
14 |
+
# Constants
|
15 |
+
NFL_TEAMS_URL = "https://www.nfl.com/teams/"
|
16 |
+
OUTPUT_DIR = "team_logos"
|
17 |
+
CSV_OUTPUT = "nfl_team_logos.csv"
|
18 |
+
EXPECTED_TEAM_COUNT = 32
|
19 |
+
|
20 |
+
def ensure_output_dir(dir_path):
|
21 |
+
"""Ensure output directory exists"""
|
22 |
+
if not os.path.exists(dir_path):
|
23 |
+
os.makedirs(dir_path)
|
24 |
+
logger.info(f"Created directory: {dir_path}")
|
25 |
+
|
26 |
+
def download_image(url, file_path):
|
27 |
+
"""Download image from URL and save to file_path"""
|
28 |
+
try:
|
29 |
+
headers = {
|
30 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
31 |
+
}
|
32 |
+
response = requests.get(url, headers=headers, stream=True)
|
33 |
+
response.raise_for_status()
|
34 |
+
|
35 |
+
with open(file_path, 'wb') as f:
|
36 |
+
for chunk in response.iter_content(chunk_size=8192):
|
37 |
+
f.write(chunk)
|
38 |
+
|
39 |
+
return True
|
40 |
+
except Exception as e:
|
41 |
+
logger.error(f"Failed to download image from {url}: {e}")
|
42 |
+
return False
|
43 |
+
|
44 |
+
def get_team_logo_urls():
|
45 |
+
"""
|
46 |
+
Get team logo URLs directly from team pages.
|
47 |
+
Returns a dictionary mapping team names to their logo URLs.
|
48 |
+
"""
|
49 |
+
logger.info(f"Fetching team information from {NFL_TEAMS_URL}")
|
50 |
+
|
51 |
+
headers = {
|
52 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
53 |
+
}
|
54 |
+
|
55 |
+
try:
|
56 |
+
response = requests.get(NFL_TEAMS_URL, headers=headers)
|
57 |
+
response.raise_for_status()
|
58 |
+
except Exception as e:
|
59 |
+
logger.error(f"Failed to fetch NFL teams page: {e}")
|
60 |
+
return {}
|
61 |
+
|
62 |
+
soup = BeautifulSoup(response.text, 'html.parser')
|
63 |
+
|
64 |
+
# Find all team links
|
65 |
+
team_links = []
|
66 |
+
for a_tag in soup.find_all('a', href=True):
|
67 |
+
if '/teams/' in a_tag['href'] and a_tag['href'].count('/') >= 3:
|
68 |
+
# This looks like a team-specific link
|
69 |
+
team_links.append(a_tag['href'])
|
70 |
+
|
71 |
+
# Get unique team URLs
|
72 |
+
team_urls = {}
|
73 |
+
for link in team_links:
|
74 |
+
# Extract team slug (e.g., 'cardinals', '49ers')
|
75 |
+
match = re.search(r'/teams/([a-z0-9-]+)/?$', link)
|
76 |
+
if match:
|
77 |
+
team_slug = match.group(1)
|
78 |
+
if team_slug not in team_urls:
|
79 |
+
full_url = f"https://www.nfl.com{link}" if not link.startswith('http') else link
|
80 |
+
team_urls[team_slug] = full_url
|
81 |
+
|
82 |
+
logger.info(f"Found {len(team_urls)} unique team URLs")
|
83 |
+
|
84 |
+
# Visit each team page to get the official logo
|
85 |
+
team_logos = {}
|
86 |
+
for slug, url in team_urls.items():
|
87 |
+
try:
|
88 |
+
logger.info(f"Visiting team page: {url}")
|
89 |
+
team_response = requests.get(url, headers=headers)
|
90 |
+
team_response.raise_for_status()
|
91 |
+
|
92 |
+
team_soup = BeautifulSoup(team_response.text, 'html.parser')
|
93 |
+
|
94 |
+
# Get team name from title
|
95 |
+
title_tag = team_soup.find('title')
|
96 |
+
if title_tag:
|
97 |
+
title_text = title_tag.text
|
98 |
+
team_name = title_text.split('|')[0].strip()
|
99 |
+
if not team_name:
|
100 |
+
team_name = slug.replace('-', ' ').title() # Fallback to slug
|
101 |
+
else:
|
102 |
+
team_name = slug.replace('-', ' ').title() # Fallback to slug
|
103 |
+
|
104 |
+
# Look for team logo in various places
|
105 |
+
logo_url = None
|
106 |
+
|
107 |
+
# Method 1: Look for logo in meta tags (most reliable)
|
108 |
+
og_image = team_soup.find('meta', property='og:image')
|
109 |
+
if og_image and og_image.get('content'):
|
110 |
+
logo_url = og_image.get('content')
|
111 |
+
|
112 |
+
# Method 2: Look for team logos in certain image tags or SVGs
|
113 |
+
if not logo_url:
|
114 |
+
team_header = team_soup.find('div', class_=lambda c: c and ('team-header' in c or 'logo' in c))
|
115 |
+
if team_header:
|
116 |
+
img = team_header.find('img')
|
117 |
+
if img and img.get('src'):
|
118 |
+
logo_url = img.get('src')
|
119 |
+
|
120 |
+
# Method 3: JavaScript data
|
121 |
+
if not logo_url:
|
122 |
+
scripts = team_soup.find_all('script')
|
123 |
+
for script in scripts:
|
124 |
+
if script.string and ('logo' in script.string.lower() or 'image' in script.string.lower()):
|
125 |
+
# Try to extract JSON data with logo information
|
126 |
+
json_matches = re.findall(r'({.*?"logo".*?})', script.string)
|
127 |
+
for match in json_matches:
|
128 |
+
try:
|
129 |
+
data = json.loads(match)
|
130 |
+
if 'logo' in data and isinstance(data['logo'], str):
|
131 |
+
logo_url = data['logo']
|
132 |
+
break
|
133 |
+
except:
|
134 |
+
continue
|
135 |
+
|
136 |
+
# Method 4: Fallback to a known pattern based on team abbreviation
|
137 |
+
if not logo_url and len(slug) > 2:
|
138 |
+
# Some teams have standardized logo URLs with abbreviations
|
139 |
+
team_abbr = slug[:2].upper() # Get first 2 chars as abbreviation
|
140 |
+
logo_url = f"https://static.www.nfl.com/t_headshot_desktop/f_auto/league/api/clubs/logos/{team_abbr}"
|
141 |
+
|
142 |
+
# If we found a logo, add it to our dictionary
|
143 |
+
if logo_url:
|
144 |
+
# If necessary, make the URL absolute
|
145 |
+
if not logo_url.startswith('http'):
|
146 |
+
logo_url = f"https://www.nfl.com{logo_url}" if logo_url.startswith('/') else f"https://www.nfl.com/{logo_url}"
|
147 |
+
|
148 |
+
team_logos[team_name] = logo_url
|
149 |
+
logger.info(f"Found logo for {team_name}: {logo_url}")
|
150 |
+
else:
|
151 |
+
logger.warning(f"Could not find logo URL for {team_name}")
|
152 |
+
|
153 |
+
# Be polite with rate limiting
|
154 |
+
time.sleep(1)
|
155 |
+
|
156 |
+
except Exception as e:
|
157 |
+
logger.error(f"Error processing team page {url}: {e}")
|
158 |
+
|
159 |
+
logger.info(f"Found logos for {len(team_logos)} teams")
|
160 |
+
return team_logos
|
161 |
+
|
162 |
+
def download_team_logos():
|
163 |
+
"""Download NFL team logos and save to CSV"""
|
164 |
+
logger.info("Starting NFL team logo download")
|
165 |
+
|
166 |
+
# Ensure output directory exists
|
167 |
+
ensure_output_dir(OUTPUT_DIR)
|
168 |
+
|
169 |
+
# Get team logo URLs from team pages
|
170 |
+
team_logos = get_team_logo_urls()
|
171 |
+
|
172 |
+
# Use a backup approach for any missing teams
|
173 |
+
if len(team_logos) < EXPECTED_TEAM_COUNT:
|
174 |
+
logger.warning(f"Only found {len(team_logos)} team logos from web scraping. Using ESPN API as backup.")
|
175 |
+
# We'll use ESPN's API to get team data including logos
|
176 |
+
try:
|
177 |
+
espn_url = "https://site.api.espn.com/apis/site/v2/sports/football/nfl/teams"
|
178 |
+
response = requests.get(espn_url)
|
179 |
+
response.raise_for_status()
|
180 |
+
|
181 |
+
espn_data = response.json()
|
182 |
+
if 'sports' in espn_data and len(espn_data['sports']) > 0:
|
183 |
+
if 'leagues' in espn_data['sports'][0] and len(espn_data['sports'][0]['leagues']) > 0:
|
184 |
+
if 'teams' in espn_data['sports'][0]['leagues'][0]:
|
185 |
+
for team_data in espn_data['sports'][0]['leagues'][0]['teams']:
|
186 |
+
team = team_data.get('team', {})
|
187 |
+
team_name = team.get('displayName')
|
188 |
+
if team_name and team_name not in team_logos:
|
189 |
+
logo_url = team.get('logos', [{}])[0].get('href')
|
190 |
+
if logo_url:
|
191 |
+
team_logos[team_name] = logo_url
|
192 |
+
logger.info(f"Added {team_name} logo from ESPN API: {logo_url}")
|
193 |
+
except Exception as e:
|
194 |
+
logger.error(f"Error fetching from ESPN API: {e}")
|
195 |
+
|
196 |
+
# If we still don't have enough teams, use a manually defined dictionary
|
197 |
+
if len(team_logos) < EXPECTED_TEAM_COUNT:
|
198 |
+
logger.warning(f"Still only have {len(team_logos)} teams. Adding manual definitions for missing teams.")
|
199 |
+
|
200 |
+
# Standard team names that should be present
|
201 |
+
standard_teams = [
|
202 |
+
"Arizona Cardinals", "Atlanta Falcons", "Baltimore Ravens", "Buffalo Bills",
|
203 |
+
"Carolina Panthers", "Chicago Bears", "Cincinnati Bengals", "Cleveland Browns",
|
204 |
+
"Dallas Cowboys", "Denver Broncos", "Detroit Lions", "Green Bay Packers",
|
205 |
+
"Houston Texans", "Indianapolis Colts", "Jacksonville Jaguars", "Kansas City Chiefs",
|
206 |
+
"Las Vegas Raiders", "Los Angeles Chargers", "Los Angeles Rams", "Miami Dolphins",
|
207 |
+
"Minnesota Vikings", "New England Patriots", "New Orleans Saints", "New York Giants",
|
208 |
+
"New York Jets", "Philadelphia Eagles", "Pittsburgh Steelers", "San Francisco 49ers",
|
209 |
+
"Seattle Seahawks", "Tampa Bay Buccaneers", "Tennessee Titans", "Washington Commanders"
|
210 |
+
]
|
211 |
+
|
212 |
+
# Manual dictionary of team logos (use correct ones from NFL's CDN)
|
213 |
+
manual_logos = {
|
214 |
+
"Arizona Cardinals": "https://static.www.nfl.com/image/private/f_auto/league/u9fltoslqdsyao8cpm0k",
|
215 |
+
"Atlanta Falcons": "https://static.www.nfl.com/image/private/f_auto/league/d8m7hzwsyzgg0smz7ifyj",
|
216 |
+
"Baltimore Ravens": "https://static.www.nfl.com/image/private/f_auto/league/ucsdijmddsqcj1i9tddd",
|
217 |
+
"Buffalo Bills": "https://static.www.nfl.com/image/private/f_auto/league/giphcy6ie9mxbnldntsf",
|
218 |
+
"Carolina Panthers": "https://static.www.nfl.com/image/private/f_auto/league/ervfzgrqdpnc7lh5gqwq",
|
219 |
+
"Chicago Bears": "https://static.www.nfl.com/image/private/f_auto/league/ra0poq2ivwyahbaq86d2",
|
220 |
+
"Cincinnati Bengals": "https://static.www.nfl.com/image/private/f_auto/league/bpx88i8nw4nnabuq0oob",
|
221 |
+
"Cleveland Browns": "https://static.www.nfl.com/image/private/f_auto/league/omlzo6n7dpxzbpwrqaak",
|
222 |
+
"Dallas Cowboys": "https://static.www.nfl.com/image/private/f_auto/league/dxibuyxbk0b9ua5ih9hn",
|
223 |
+
"Denver Broncos": "https://static.www.nfl.com/image/private/f_auto/league/t0p7m5cjdjy18rnzzqbx",
|
224 |
+
"Detroit Lions": "https://static.www.nfl.com/image/private/f_auto/league/dhfidtn8jrumakbawoxz",
|
225 |
+
"Green Bay Packers": "https://static.www.nfl.com/image/private/f_auto/league/q1l7xmkuuyrpdmnutkzf",
|
226 |
+
"Houston Texans": "https://static.www.nfl.com/image/private/f_auto/league/bpx88i8nw4nnabuq0oob",
|
227 |
+
"Indianapolis Colts": "https://static.www.nfl.com/image/private/f_auto/league/ketwqeuschqzjsllbid5",
|
228 |
+
"Jacksonville Jaguars": "https://static.www.nfl.com/image/private/f_auto/league/bwl1nuab0n2bhi8nxiar",
|
229 |
+
"Kansas City Chiefs": "https://static.www.nfl.com/image/private/f_auto/league/ujshjqvmnxce8m4obmvs",
|
230 |
+
"Las Vegas Raiders": "https://static.www.nfl.com/image/private/f_auto/league/gzcojbzcyjgubgyb6xf2",
|
231 |
+
"Los Angeles Chargers": "https://static.www.nfl.com/image/private/f_auto/league/dhfidtn8jrumakbawoxz",
|
232 |
+
"Los Angeles Rams": "https://static.www.nfl.com/image/private/f_auto/league/rjxoqpjirhjvvitffvwh",
|
233 |
+
"Miami Dolphins": "https://static.www.nfl.com/image/private/f_auto/league/lits6p8ycthy9to70bnt",
|
234 |
+
"Minnesota Vikings": "https://static.www.nfl.com/image/private/f_auto/league/teguylrnqqmfcwxvcmmz",
|
235 |
+
"New England Patriots": "https://static.www.nfl.com/image/private/f_auto/league/moyfxx3dq5pio4aiftnc",
|
236 |
+
"New Orleans Saints": "https://static.www.nfl.com/image/private/f_auto/league/grhjkahghuebpwzo6kxn",
|
237 |
+
"New York Giants": "https://static.www.nfl.com/image/private/f_auto/league/t6mhdmgizi6qhndh8b9p",
|
238 |
+
"New York Jets": "https://static.www.nfl.com/image/private/f_auto/league/ekijosiae96gektbo1lj",
|
239 |
+
"Philadelphia Eagles": "https://static.www.nfl.com/image/private/f_auto/league/puhrqgj71gobgmwb5g3p",
|
240 |
+
"Pittsburgh Steelers": "https://static.www.nfl.com/image/private/f_auto/league/xujik9a3j8hl6jjumu25",
|
241 |
+
"San Francisco 49ers": "https://static.www.nfl.com/image/private/f_auto/league/dxibuyxbk0b9ua5ih9hn",
|
242 |
+
"Seattle Seahawks": "https://static.www.nfl.com/image/private/f_auto/league/gcytzwpjdzbpwnwxincg",
|
243 |
+
"Tampa Bay Buccaneers": "https://static.www.nfl.com/image/private/f_auto/league/v8uqiualryypwqgvwcih",
|
244 |
+
"Tennessee Titans": "https://static.www.nfl.com/image/private/f_auto/league/pln44vuzugjgipyidsre",
|
245 |
+
"Washington Commanders": "https://static.www.nfl.com/image/private/f_auto/league/xymxwrxtyj9fhaegfwof"
|
246 |
+
}
|
247 |
+
|
248 |
+
# Fill in any missing teams with manual data
|
249 |
+
for team_name in standard_teams:
|
250 |
+
if team_name not in team_logos and team_name in manual_logos:
|
251 |
+
team_logos[team_name] = manual_logos[team_name]
|
252 |
+
logger.info(f"Added {team_name} logo from manual dictionary")
|
253 |
+
|
254 |
+
# Process and download team logos
|
255 |
+
results = []
|
256 |
+
for team_name, logo_url in team_logos.items():
|
257 |
+
# Create safe filename
|
258 |
+
safe_name = team_name.replace(' ', '_').lower()
|
259 |
+
file_extension = '.png' # Default to PNG
|
260 |
+
filename = f"{safe_name}{file_extension}"
|
261 |
+
local_path = os.path.join(OUTPUT_DIR, filename)
|
262 |
+
|
263 |
+
# Download the logo
|
264 |
+
logger.info(f"Downloading logo for {team_name} from {logo_url}")
|
265 |
+
download_success = download_image(logo_url, local_path)
|
266 |
+
|
267 |
+
if download_success:
|
268 |
+
results.append({
|
269 |
+
'team_name': team_name,
|
270 |
+
'logo_url': logo_url,
|
271 |
+
'local_path': local_path
|
272 |
+
})
|
273 |
+
logger.info(f"Successfully downloaded logo for {team_name}")
|
274 |
+
else:
|
275 |
+
logger.error(f"Failed to download logo for {team_name}")
|
276 |
+
|
277 |
+
# Add a small delay
|
278 |
+
time.sleep(0.5)
|
279 |
+
|
280 |
+
# Save to CSV
|
281 |
+
with open(CSV_OUTPUT, 'w', newline='', encoding='utf-8') as f:
|
282 |
+
fieldnames = ['team_name', 'logo_url', 'local_path']
|
283 |
+
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
284 |
+
writer.writeheader()
|
285 |
+
writer.writerows(results)
|
286 |
+
|
287 |
+
logger.info(f"Successfully saved {len(results)} team logos out of {len(team_logos)} teams.")
|
288 |
+
logger.info(f"CSV data saved to '{CSV_OUTPUT}'")
|
289 |
+
|
290 |
+
if len(results) < EXPECTED_TEAM_COUNT:
|
291 |
+
logger.warning(f"Only downloaded {len(results)} team logos, expected {EXPECTED_TEAM_COUNT}.")
|
292 |
+
else:
|
293 |
+
logger.info(f"SUCCESS! Downloaded all {EXPECTED_TEAM_COUNT} NFL team logos!")
|
294 |
+
|
295 |
+
return results
|
296 |
+
|
297 |
+
if __name__ == "__main__":
|
298 |
+
download_team_logos()
|
docs/requirements.md
ADDED
@@ -0,0 +1,447 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# IFX Companion – Product & Technical Requirements (WIP)
|
2 |
+
|
3 |
+
## 1. App at a Glance
|
4 |
+
|
5 |
+
**Name:** IFX Companion
|
6 |
+
|
7 |
+
**Summary:**
|
8 |
+
An AI-powered sports fan assistant that creates immersive, multimodal, and personalized experiences around NFL teams, players, games, rules, and fan communities. The app delivers conversational responses enhanced with visuals and session memory.
|
9 |
+
|
10 |
+
**Primary Users:**
|
11 |
+
- **Novice Fans:** Curious about the sport
|
12 |
+
- **Intermediate Fans:** Seeking updates and highlights
|
13 |
+
- **Super Fans:** Wanting in-depth stats, analysis, and community connection
|
14 |
+
|
15 |
+
**Key Value Proposition:**
|
16 |
+
IFX Companion makes fans feel seen, informed, and connected — through natural language, visual storytelling, and personalized interactions tailored to their fandom level.
|
17 |
+
|
18 |
+
## 2. Experience Principles
|
19 |
+
|
20 |
+
### Natural Language Question and Answers
|
21 |
+
Give the user a search interface to immediately find the focus of their intention, improving on existing league and teams apps (NFL, SF 49ers) that don't provide similar functionality.
|
22 |
+
|
23 |
+
### Dynamic UI Outputs Tailored to User's Query
|
24 |
+
Dynamic layout and content of AI responses, based on the user's query (player / game / team) give the user an engaging and contextually relevant experience.
|
25 |
+
|
26 |
+
### Personalization Based on User Profile
|
27 |
+
Pre-created fan profiles allow the user to select archetypes (casual fan, consistent fan, superfan) and experience different content and recommendations.
|
28 |
+
|
29 |
+
### Connection with Communities of Like-Minded Fans
|
30 |
+
Recommendations for how to engage and participate with real-world fan communities allows the fan to join a bigger movement.
|
31 |
+
|
32 |
+
## 3. Feature Overview
|
33 |
+
|
34 |
+
### 0. Persona Selection
|
35 |
+
- **Description:**
|
36 |
+
User chooses a predefined persona that represents their level of engagement (novice, intermediate, super fan). This sets a `persona_id` and initializes a memory object in Zep.
|
37 |
+
- **Inputs:**
|
38 |
+
Button click (Gradio)
|
39 |
+
- **Outputs:**
|
40 |
+
Persona object passed into session memory for use in future context
|
41 |
+
- **Priority:**
|
42 |
+
**High**
|
43 |
+
|
44 |
+
**Persona Memory Structure (Zep)**
|
45 |
+
```json
|
46 |
+
{
|
47 |
+
"persona_id": "superfan",
|
48 |
+
"name": "The Strategist",
|
49 |
+
"fan_level": "advanced",
|
50 |
+
"favorite_team": "49ers",
|
51 |
+
"preferred_channels": ["YouTube", "Twitter"]
|
52 |
+
}
|
53 |
+
```
|
54 |
+
|
55 |
+
### 1. Team Search
|
56 |
+
- **Description:** Natural language queries about team history, season recaps, outlooks, and trending stories.
|
57 |
+
- **Data Source:** Preloaded Neo4j graph database (no external SERP/API)
|
58 |
+
- **Display:** Dynamic Gradio widget layout with text + media (image, video preview)
|
59 |
+
- **Examples:**
|
60 |
+
- "Tell me about the 49ers"
|
61 |
+
- "How did they do in the offseason?"
|
62 |
+
- "Are they going to be good this year?"
|
63 |
+
- **Priority:** High
|
64 |
+
|
65 |
+
### 2. Player Search
|
66 |
+
- **Description:** Player-specific queries, from basic info to advanced game-by-game stat breakdowns.
|
67 |
+
- **Data Source:** Preloaded Neo4j
|
68 |
+
- **Display:** Profile image + stat preview components
|
69 |
+
- **Examples:**
|
70 |
+
- "Who is the starting QB?"
|
71 |
+
- "What was Deebo Samuel's best game?"
|
72 |
+
- "How accurate is Brock Purdy's deep ball?"
|
73 |
+
- **Priority:** High
|
74 |
+
|
75 |
+
### 3. Game Search
|
76 |
+
- **Description:** Game-level summaries and key moments/highlights.
|
77 |
+
- **Data Source:** Preloaded Neo4j
|
78 |
+
- **Display:** Recap text block + embedded image or video preview
|
79 |
+
- **Examples:**
|
80 |
+
- "How did the 49ers do vs Dolphins?"
|
81 |
+
- "What was the key play in the Seahawks loss?"
|
82 |
+
- **Priority:** High
|
83 |
+
|
84 |
+
### 4. Fan Community Search
|
85 |
+
- **Description:** Allows users to find fan communities in a given location.
|
86 |
+
- **Data Source:** Neo4j (chapter name, location, contact info)
|
87 |
+
- **Input:** Location (e.g. city/state)
|
88 |
+
- **Output:** Community info cards
|
89 |
+
- **Examples:**
|
90 |
+
- "Are there any 49ers fan groups in Iowa?"
|
91 |
+
- **Priority:** Medium
|
92 |
+
|
93 |
+
### 5. Rule Search (Deferred)
|
94 |
+
- **Description:** Future use of RAG or LLMs to answer football rules queries.
|
95 |
+
- **Status:** Deferred from MVP
|
96 |
+
|
97 |
+
## 4. Technical Stack & Constraints
|
98 |
+
|
99 |
+
### Frontend:
|
100 |
+
- Gradio (Python)
|
101 |
+
- Responsive, widget-based layout for chat and dynamic components
|
102 |
+
- Designed to be portable to other frameworks after POC
|
103 |
+
|
104 |
+
### Backend:
|
105 |
+
- Modular microservices using MCP (Model Context Protocol)
|
106 |
+
- Each feature (team, player, game, fan) is its own callable service module
|
107 |
+
- Stateless with Zep memory injected as needed
|
108 |
+
|
109 |
+
### Memory:
|
110 |
+
- Zep memory management using persona_id
|
111 |
+
- Memory updates per session stored but without historical user data in MVP
|
112 |
+
|
113 |
+
### Database:
|
114 |
+
- Neo4j for all structured data:
|
115 |
+
- Teams
|
116 |
+
- Players
|
117 |
+
- Games
|
118 |
+
- Fan communities
|
119 |
+
|
120 |
+
### Hosting:
|
121 |
+
- Hugging Face Spaces (initial deployment)
|
122 |
+
|
123 |
+
### Constraints:
|
124 |
+
- No social logins or dynamic user accounts (MVP only)
|
125 |
+
- All personalization is based on preselected personas
|
126 |
+
- AI must not hallucinate or create false summaries — must stick to data in graph or defined assets
|
127 |
+
|
128 |
+
## 5. App Architecture & Workflow
|
129 |
+
|
130 |
+
```mermaid
|
131 |
+
flowchart TD
|
132 |
+
A[Select Persona] --> B[Load Zep Persona Memory]
|
133 |
+
B --> C[User Query (Text Input)]
|
134 |
+
C --> D[Classify Intent (Team/Player/Game/Fan)]
|
135 |
+
D --> E[Call MCP Service]
|
136 |
+
E --> F[Retrieve from Neo4j]
|
137 |
+
F --> G[Render Output in Gradio]
|
138 |
+
G --> H[Update Zep Memory]
|
139 |
+
```
|
140 |
+
|
141 |
+
## 6. Deployment & Testing
|
142 |
+
|
143 |
+
### Deployment:
|
144 |
+
- Code managed via GitHub
|
145 |
+
- Hugging Face Spaces deployment using standard YAML metadata
|
146 |
+
- All assets and dependencies pinned in requirements.txt
|
147 |
+
|
148 |
+
### Testing Strategy:
|
149 |
+
|
150 |
+
| Layer | Tool / Approach | Goal |
|
151 |
+
|-------|----------------|------|
|
152 |
+
| Service Layer | pytest unit tests | Validate correct behavior of each MCP service (team_service, player_service, etc.) |
|
153 |
+
| Graph Queries | Neo4j test container or schema mocks | Ensure Cypher queries return structured data as expected |
|
154 |
+
| Gradio UI | Manual session testing per persona | Simulate key user journeys across personas |
|
155 |
+
| Memory System | Mocked Zep client in pytest | Ensure persona selection creates correct memory structure |
|
156 |
+
| Integration | Persona-based E2E tests (manual) | Confirm chat-to-output loop works as designed for each use case |
|
157 |
+
|
158 |
+
## 7. Design System (49ers Themed)
|
159 |
+
|
160 |
+
### Color Palette:
|
161 |
+
- Primary Red: #AA0000
|
162 |
+
- Gold Accent: #B3995D
|
163 |
+
- Shadow Black: #111111
|
164 |
+
- Cool Gray: #E6E6E6
|
165 |
+
- White: #FFFFFF
|
166 |
+
|
167 |
+
### Typography:
|
168 |
+
- Headlines: "Impact," sans-serif (or similar bold typeface)
|
169 |
+
- Body: "Open Sans," sans-serif
|
170 |
+
|
171 |
+
### Sample CSS (for embedding in Gradio app):
|
172 |
+
|
173 |
+
```css
|
174 |
+
body {
|
175 |
+
font-family: 'Open Sans', sans-serif;
|
176 |
+
background-color: #111111;
|
177 |
+
color: #E6E6E6;
|
178 |
+
}
|
179 |
+
|
180 |
+
h1, h2 {
|
181 |
+
font-family: 'Impact', sans-serif;
|
182 |
+
color: #AA0000;
|
183 |
+
}
|
184 |
+
|
185 |
+
button {
|
186 |
+
background-color: #B3995D;
|
187 |
+
color: #111111;
|
188 |
+
border-radius: 8px;
|
189 |
+
padding: 8px 16px;
|
190 |
+
border: none;
|
191 |
+
}
|
192 |
+
```
|
193 |
+
|
194 |
+
## 8. Component Library – Gradio Components for Reuse
|
195 |
+
|
196 |
+
| Component Name | Description | Gradio Element(s) |
|
197 |
+
|----------------|-------------|-------------------|
|
198 |
+
| Persona Selector | Three fan-type buttons (novice/intermediate/super fan). | gr.Row, gr.Button |
|
199 |
+
| Chat Window | Textbox for user query + LLM response. | gr.Textbox, gr.Markdown |
|
200 |
+
| Team Summary Card | Team logo, summary, record, etc. | gr.Image, gr.Markdown, gr.Row |
|
201 |
+
| Player Stat Card | Player image, name, key stats. | gr.Column, gr.Image, gr.Text |
|
202 |
+
| Game Recap Card | Score, highlight clip, key play. | gr.Row, gr.Image or gr.Video |
|
203 |
+
| Fan Group Finder | Location input + search results. | gr.Textbox, gr.Dataframe or gr.Accordion |
|
204 |
+
|
205 |
+
All components:
|
206 |
+
- Must be responsive
|
207 |
+
- Use the 49ers-themed CSS above
|
208 |
+
- Allow easy import from a components/ folder in the codebase
|
209 |
+
|
210 |
+
## 9. Open Items / Next Steps
|
211 |
+
|
212 |
+
| Topic | Action |
|
213 |
+
|-------|--------|
|
214 |
+
| Personas | Finalize attributes for each of the 3 fan levels |
|
215 |
+
| Graph Schema | Reupload graph schema including links to media |
|
216 |
+
| Data Ingestion | Download team logo files + download game recaps |
|
217 |
+
| Component Dev | Build/test each Gradio component independently |
|
218 |
+
| Deployment | Set up GitHub+HF Spaces config for clean deployment cycle |
|
219 |
+
| CSS | Embed or reference the custom stylesheet for theme |
|
220 |
+
|
221 |
+
## 10. Detailed Work Plan
|
222 |
+
|
223 |
+
Based on a review of the existing codebase and requirements, here's a structured implementation plan:
|
224 |
+
|
225 |
+
### Phase 1: Foundation (April 14 - 25)
|
226 |
+
|
227 |
+
| Task | Description | Dependencies |
|
228 |
+
|------|-------------|--------------|
|
229 |
+
| **1.1 Complete data ingestion of team thumbnail images** | Download and integrate team logo files into the database | None |
|
230 |
+
| **1.1 data extracted on 4.13 ✅** |
|
231 |
+
| **1.2 Build and test gradio components locally** | Create components using CSV files instead of Neo4j, including multimedia integration | 1.1 |
|
232 |
+
| **1.3 Develop memory system and UI integration with Zep** | Implement persona-based memory system with Zep | None |
|
233 |
+
|
234 |
+
**Demo 1 Milestone:** April 22
|
235 |
+
|
236 |
+
### Phase 2: Core Integration (April 28 - May 9)
|
237 |
+
|
238 |
+
| Task | Description | Dependencies |
|
239 |
+
|------|-------------|--------------|
|
240 |
+
| **2.1 Rebuild graph with full asset integration** | Develop and test low-latency approach for media assets | 1.1 |
|
241 |
+
| **2.2 Refactor ALL OF THE SERVICES** | Update services using updated graph and gradio UI integration | 1.2, 2.1 |
|
242 |
+
|
243 |
+
**Demo 2 Milestone:** May 6
|
244 |
+
|
245 |
+
### Phase 3: Enhancement & Refinement (May 12 - May 23)
|
246 |
+
|
247 |
+
| Task | Description | Dependencies |
|
248 |
+
|------|-------------|--------------|
|
249 |
+
| **3.1 Cloud deployment to Hugging Face spaces** | Set up and configure deployment environment | 2.1, 2.2 |
|
250 |
+
| **3.2 Testing the tuning through FreePlay.AI** | Validate AI responses and performance | 3.1 |
|
251 |
+
| **3.3 Fine tuning responses between personality types and fan skill levels** | Customize responses based on persona | 1.3, 3.1 |
|
252 |
+
| **3.4 Refining precision of game recap search** | Improve search accuracy and relevance | 2.1, 2.2 |
|
253 |
+
|
254 |
+
**Demo 3 Milestone:** May 20
|
255 |
+
|
256 |
+
### Phase 4: Final Launch (May 26 - 29)
|
257 |
+
|
258 |
+
| Task | Description | Dependencies |
|
259 |
+
|------|-------------|--------------|
|
260 |
+
| **4.1 Final testing and adjustments** | Address any remaining issues | 3.1, 3.2, 3.3, 3.4 |
|
261 |
+
| **4.2 Documentation and handoff** | Complete all documentation | 4.1 |
|
262 |
+
|
263 |
+
**FINAL GO LIVE:** May 29
|
264 |
+
|
265 |
+
## Implementation Details
|
266 |
+
|
267 |
+
### Technical Implementation Notes
|
268 |
+
|
269 |
+
1. **Gradio Migration**
|
270 |
+
- Update existing `gradio_app.py` to support all required components
|
271 |
+
- Refactor `gradio_utils.py` to handle persona-based memory
|
272 |
+
|
273 |
+
2. **Neo4j Schema Enhancements**
|
274 |
+
- Add media links to Player nodes (images, videos)
|
275 |
+
- Ensure Game nodes have highlight video links
|
276 |
+
- Add team-level properties for team info/history
|
277 |
+
- Reupload graph schema including links to media
|
278 |
+
|
279 |
+
3. **Persona System**
|
280 |
+
- Create `persona.py` module with persona definitions and selection logic
|
281 |
+
- Enhance Zep integration to store persona context
|
282 |
+
- Develop memory system and UI integration with Zep (Phase 1)
|
283 |
+
|
284 |
+
4. **MCP Services**
|
285 |
+
- Create `services/` directory with modules for each domain:
|
286 |
+
- `team_service.py`
|
287 |
+
- `player_service.py`
|
288 |
+
- `game_service.py`
|
289 |
+
- `community_service.py`
|
290 |
+
- Implement service registry and routing in `service_router.py`
|
291 |
+
- Refactor all services using updated graph and gradio UI integration (Phase 2)
|
292 |
+
|
293 |
+
5. **UI Components**
|
294 |
+
- Create `components/` directory with reusable components:
|
295 |
+
- `persona_selector.py`
|
296 |
+
- `team_card.py`
|
297 |
+
- `player_card.py`
|
298 |
+
- `game_recap.py`
|
299 |
+
- `community_finder.py`
|
300 |
+
- Build and test gradio components locally using CSV files (Phase 1)
|
301 |
+
|
302 |
+
6. **CSS Implementation**
|
303 |
+
- Create `static/styles.css` with 49ers theming
|
304 |
+
- Integrate with Gradio using custom CSS parameter
|
305 |
+
|
306 |
+
7. **Data Integration**
|
307 |
+
- Complete data ingestion of team thumbnail images (Phase 1)
|
308 |
+
- Download game recaps (Phase 1)
|
309 |
+
- Rebuild graph with full asset integration (Phase 2)
|
310 |
+
|
311 |
+
8. **Deployment & Testing**
|
312 |
+
- Cloud deployment to Hugging Face spaces (Phase 3)
|
313 |
+
- Testing the tuning through FreePlay.AI (Phase 3)
|
314 |
+
- Fine tuning responses between personality types and fan skill levels (Phase 3)
|
315 |
+
- Refining precision of game recap search (Phase 3)
|
316 |
+
- Final testing and adjustments (Phase 4)
|
317 |
+
- FINAL GO LIVE on May 29
|
318 |
+
|
319 |
+
### Feature Gap Analysis
|
320 |
+
|
321 |
+
| Feature | Current Status | Work Needed |
|
322 |
+
|---------|---------------|-------------|
|
323 |
+
| Basic Chat | Implemented | Enhance with persona awareness |
|
324 |
+
| Neo4j Integration | Implemented | Add media fields to schema |
|
325 |
+
| Zep Memory | Basic implementation | Add persona structure |
|
326 |
+
| Gradio UI | Basic implementation | Add themed components |
|
327 |
+
| Persona Selection | Not implemented | Create from scratch |
|
328 |
+
| Media Components | Not implemented | Create from scratch |
|
329 |
+
| Service Architecture | Not implemented | Refactor into MCP services |
|
330 |
+
| Intent Classification | Basic implementation | Enhance with persona context |
|
331 |
+
|
332 |
+
### Resource Requirements
|
333 |
+
|
334 |
+
1. **Development Environment**
|
335 |
+
- Python 3.9+
|
336 |
+
- Neo4j database (access to update schema)
|
337 |
+
- OpenAI API key
|
338 |
+
- Zep account for memory management
|
339 |
+
|
340 |
+
2. **Assets Needed**
|
341 |
+
- 49ers team imagery
|
342 |
+
- Player headshots
|
343 |
+
- Game highlight clips/thumbnails
|
344 |
+
- Custom CSS for theming
|
345 |
+
|
346 |
+
3. **External Services**
|
347 |
+
- Hugging Face Spaces for deployment
|
348 |
+
- (Optional) Content hosting for media assets
|
349 |
+
|
350 |
+
### Risk Management
|
351 |
+
|
352 |
+
| Risk | Mitigation Strategy |
|
353 |
+
|------|---------------------|
|
354 |
+
| Neo4j data completeness | Conduct audit of required fields before implementation |
|
355 |
+
| Media asset availability | Create fallback text-only components if media is unavailable |
|
356 |
+
| Persona complexity | Start with simplified personas, then enhance |
|
357 |
+
| Deployment constraints | Test with Hugging Face resource limits early |
|
358 |
+
| Memory persistence | Implement simple local fallback if Zep has issues |
|
359 |
+
|
360 |
+
## 11. Feature Work Log
|
361 |
+
|
362 |
+
### Step 1.2: Team Search Feature Implementation
|
363 |
+
|
364 |
+
#### Objective
|
365 |
+
Implement the Team Search feature (Feature 1 from Feature Overview) with focus on game recap display functionality.
|
366 |
+
|
367 |
+
#### Prerequisites
|
368 |
+
- Access to `schedule_with_result_april_11.csv`
|
369 |
+
- Access to `nfl_team_logos_revised.csv`
|
370 |
+
- Reference to `game recap layout example.png`
|
371 |
+
- Gradio app instance
|
372 |
+
- Neo4j database instance
|
373 |
+
|
374 |
+
#### Implementation Steps
|
375 |
+
|
376 |
+
1. **CSS Integration**
|
377 |
+
- Add required CSS styles to the Gradio app
|
378 |
+
- Ensure styles support responsive layout
|
379 |
+
- Implement 49ers theme colors from Design System section
|
380 |
+
|
381 |
+
2. **Data Requirements Enhancement**
|
382 |
+
- Review existing game score & result data
|
383 |
+
- Identify home team name and logo source
|
384 |
+
- Identify away team name and logo source
|
385 |
+
- Document data structure requirements
|
386 |
+
|
387 |
+
3. **CSV File Update**
|
388 |
+
- Open `schedule_with_result_april_11.csv`
|
389 |
+
- Add columns for home team logo
|
390 |
+
- Add columns for away team logo
|
391 |
+
- Merge data from `nfl_team_logos_revised.csv`
|
392 |
+
- Validate data integrity
|
393 |
+
- Save as new version
|
394 |
+
|
395 |
+
4. **Static Gradio Component Development**
|
396 |
+
- Create new component file
|
397 |
+
- Implement layout matching `game recap layout example.png`:
|
398 |
+
- Top row: away team elements
|
399 |
+
- Bottom row: home team elements
|
400 |
+
- Score display with winning team highlight
|
401 |
+
- Video preview box
|
402 |
+
- Use static assets for 49ers first game
|
403 |
+
- Implement responsive design
|
404 |
+
|
405 |
+
5. **Component Testing**
|
406 |
+
- Add component as first element in Gradio app
|
407 |
+
- Test CSV data integration
|
408 |
+
- Verify static display
|
409 |
+
- Document any display issues
|
410 |
+
|
411 |
+
6. **Function-Calling Implementation**
|
412 |
+
- Prepare Neo4j merge operations
|
413 |
+
- Update graph with new game data
|
414 |
+
- Preserve existing nodes
|
415 |
+
- Add new attributes
|
416 |
+
- Test data integrity
|
417 |
+
|
418 |
+
7. **LangChain Integration**
|
419 |
+
- Adapt graph search function
|
420 |
+
- Implement game-specific search
|
421 |
+
- Test attribute retrieval
|
422 |
+
- Verify data flow to Gradio component
|
423 |
+
|
424 |
+
8. **Final Deployment**
|
425 |
+
- Deploy to Gradio
|
426 |
+
- Perform final UI checks
|
427 |
+
- Verify data accuracy
|
428 |
+
- Document any issues
|
429 |
+
|
430 |
+
#### Failure Conditions
|
431 |
+
- Halt process if any step fails after 3 attempts
|
432 |
+
- Document failure point and reason
|
433 |
+
- Consult with user for guidance
|
434 |
+
- Do not proceed without resolution
|
435 |
+
|
436 |
+
#### Success Criteria
|
437 |
+
- Component displays correctly in Gradio
|
438 |
+
- Data flows accurately from CSV to display
|
439 |
+
- Graph integration works without data loss
|
440 |
+
- LangChain search returns correct game data
|
441 |
+
- UI matches design specifications
|
442 |
+
|
443 |
+
#### Notes
|
444 |
+
- Maintain existing Neo4j node structure
|
445 |
+
- Preserve all current functionality
|
446 |
+
- Document all changes for future reference
|
447 |
+
- Test thoroughly before proceeding to next phase
|
requirements.txt
CHANGED
@@ -6,7 +6,6 @@ langchain-neo4j>=0.1.1
|
|
6 |
openai>=1.2.0
|
7 |
neo4j>=5.14.0
|
8 |
python-dotenv>=1.0.0
|
9 |
-
uuid>=1.30
|
10 |
zep-cloud>=0.1.0
|
11 |
asyncio>=3.4.3
|
12 |
pandas>=2.0.0
|
|
|
6 |
openai>=1.2.0
|
7 |
neo4j>=5.14.0
|
8 |
python-dotenv>=1.0.0
|
|
|
9 |
zep-cloud>=0.1.0
|
10 |
asyncio>=3.4.3
|
11 |
pandas>=2.0.0
|