feat: migrate from RapidAPI to TheSportsDB with SvelteKit dashboard
- Replace free-api-live-football-data (RapidAPI) backend with TheSportsDB - Add PostgreSQL cache layer for permanent data (teams, players, leagues, events) - Replace Bootstrap dashboard with SvelteKit-based interactive dashboard - Restructure MCP tools around TheSportsDB capabilities (get_team_info, get_roster, get_fixtures, get_standings, etc.) - Expose tool registry via GET /api/tools so dashboard stays in sync - Remove legacy modules and references (api_football, sync, RapidAPI env vars)
This commit is contained in:
115
README.md
115
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
MCP server and web dashboard for football (soccer) data, with full MLS support.
|
||||
|
||||
Queries live data from [free-api-live-football-data](https://rapidapi.com/Creativesdev/api/free-api-live-football-data) (RapidAPI) and exposes it via MCP tools for conversational analysis and a Bootstrap status dashboard.
|
||||
Queries live data from [TheSportsDB](https://www.thesportsdb.com/) and exposes it via MCP tools for conversational analysis, with a SvelteKit dashboard for status and interactive testing. A PostgreSQL cache stores permanent data (teams, players, leagues, events) to minimise API calls.
|
||||
|
||||
Project #205
|
||||
---
|
||||
@@ -13,61 +13,53 @@ Project #205
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ nike/server.py — single process on 0.0.0.0:{PORT} │
|
||||
│ │
|
||||
│ GET / → Bootstrap dashboard (dashboard.html)│
|
||||
│ GET / → SvelteKit dashboard (dashboard/build)│
|
||||
│ GET /api/* → Dashboard JSON API │
|
||||
│ /mcp/ → FastMCP HTTP (streamable) │
|
||||
└──────────┬──────────────────────────────────────────────┘
|
||||
│
|
||||
nike/rapidapi.py
|
||||
(free-api-live-football-data client)
|
||||
nike/sportsdb.py ←→ nike/db.py (PostgreSQL cache)
|
||||
(TheSportsDB client)
|
||||
│
|
||||
RapidAPI
|
||||
(free-api-live-football-data.p.rapidapi.com)
|
||||
TheSportsDB API
|
||||
```
|
||||
|
||||
### Module responsibilities
|
||||
|
||||
| Module | Role |
|
||||
|--------|------|
|
||||
| `nike/config.py` | Centralised settings from `.env` (API keys, constants) |
|
||||
| `nike/rapidapi.py` | RapidAPI client with TTL cache (live data backend) |
|
||||
| `nike/config.py` | Centralised settings from `.env` (API key, DB, server) |
|
||||
| `nike/sportsdb.py` | TheSportsDB client with in-memory TTL cache (live backend) |
|
||||
| `nike/db.py` | PostgreSQL connection pool + active cache layer for permanent data |
|
||||
| `nike/server.py` | FastAPI app: MCP tools, dashboard routes, mounts MCP ASGI |
|
||||
| `nike/templates/dashboard.html` | Live status dashboard (Bootstrap 5, dark theme) |
|
||||
|
||||
### Legacy modules (preserved, not active)
|
||||
|
||||
| Module | Role |
|
||||
|--------|------|
|
||||
| `nike/api_football.py` | API-Football v3 client (original backend) |
|
||||
| `nike/db.py` | PostgreSQL connection pool and query helpers |
|
||||
| `nike/sync.py` | API → DB sync pipeline |
|
||||
| `schema.sql` | Database DDL |
|
||||
| `schema.sql` | Cache database DDL |
|
||||
|
||||
### MCP Tools
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `search(query)` | Universal search across teams, players, leagues, matches |
|
||||
| `live_scores()` | All currently live matches worldwide |
|
||||
| `fixtures(league, date)` | Matches by league and/or date |
|
||||
| `standings(league)` | Full league table |
|
||||
| `team_info(team)` | Team profile + squad roster |
|
||||
| `player_info(player)` | Player profile and details |
|
||||
| `match_detail(event_id)` | Full match: score, stats, lineups, venue, referee |
|
||||
| `head_to_head(event_id)` | H2H history for a matchup |
|
||||
| `top_players(league, stat)` | Top scorers / assists / rated |
|
||||
| `transfers(league_or_team, scope)` | Transfer activity |
|
||||
| `news(scope, name)` | Trending, league, or team news |
|
||||
| `get_team_info(team_name)` | Team profile: stadium, capacity, location, founded year, colors |
|
||||
| `get_roster(team_name)` | Current squad grouped by position |
|
||||
| `get_player_info(player_name)` | Player profile: position, nationality, DOB, team, status |
|
||||
| `get_fixtures(team_name, status)` | Recent results and upcoming matches (`status`: all/upcoming/past) |
|
||||
| `get_standings(league, season)` | Full league table with points, goal difference, and form |
|
||||
| `get_match_result(team_name, match_date)` | Match result for a team on a specific date |
|
||||
| `get_match_detail(event_id)` ★ | Deep match stats, lineup, and timeline |
|
||||
| `get_livescores()` ★ | Current live soccer scores worldwide |
|
||||
|
||||
★ Requires a premium TheSportsDB key.
|
||||
|
||||
The dashboard derives its tool list from these registrations via `GET /api/tools`, so it stays in sync automatically.
|
||||
|
||||
---
|
||||
|
||||
## Dashboard
|
||||
|
||||
The web dashboard is a SvelteKit 2 / Svelte 5 / Tailwind CSS 4 app in `dashboard/`.
|
||||
The web dashboard is a SvelteKit 2 / Svelte 5 / Tailwind CSS 4 + DaisyUI 5 app in `dashboard/`.
|
||||
|
||||
| Route | Description |
|
||||
|-------|-------------|
|
||||
| `/` | System status: DB, API, MCP health cards; followed teams; tools list; request log |
|
||||
| `/` | System status: cache, API, and MCP health cards; followed teams; tools list; request log |
|
||||
| `/tools` | Interactive tool runner — pick a tool, fill in parameters, inspect raw output |
|
||||
|
||||
### Build (required before serving via FastAPI)
|
||||
@@ -101,12 +93,12 @@ The dev dashboard is at `http://localhost:5173`.
|
||||
### Prerequisites
|
||||
|
||||
- Python >= 3.11
|
||||
- A RapidAPI key for [free-api-live-football-data](https://rapidapi.com/Creativesdev/api/free-api-live-football-data)
|
||||
- PostgreSQL (for the cache; see `schema.sql`)
|
||||
- A TheSportsDB key (`3` is the free test key; premium tools require a paid key)
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
cd ~/gitea/nike
|
||||
python3 -m venv ~/env/nike
|
||||
source ~/env/nike/bin/activate
|
||||
pip install -e .
|
||||
@@ -114,19 +106,15 @@ pip install -e .
|
||||
|
||||
### Configure
|
||||
|
||||
Create (or edit) `.env` in the project root:
|
||||
Copy `.env.example` to `.env` and fill in your values (TheSportsDB key, database connection, server host/port). See `.env.example` for the full list of `NIKE_*` variables.
|
||||
|
||||
```env
|
||||
RAPIDAPI_KEY=<your-rapidapi-key>
|
||||
```
|
||||
|
||||
### Verify API connectivity
|
||||
### Provision the cache database
|
||||
|
||||
```bash
|
||||
python scripts/test_rapidapi.py
|
||||
python scripts/apply_schema.py
|
||||
```
|
||||
|
||||
This searches for MLS, fetches standings, finds Toronto FC, and pulls the squad roster.
|
||||
This applies `schema.sql` to the PostgreSQL database configured in `.env`.
|
||||
|
||||
---
|
||||
|
||||
@@ -171,8 +159,6 @@ Once connected, you can ask questions like:
|
||||
- *"What matches are live right now?"*
|
||||
- *"Show the MLS standings"*
|
||||
- *"Who plays for Toronto FC?"*
|
||||
- *"Who's the MLS top scorer?"*
|
||||
- *"Any transfer news for Inter Miami?"*
|
||||
- *"Tell me about Federico Bernardeschi"*
|
||||
|
||||
---
|
||||
@@ -181,12 +167,8 @@ Once connected, you can ask questions like:
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `scripts/test_rapidapi.py` | Verify RapidAPI connectivity and fetch sample data |
|
||||
| `scripts/test_db.py` | Verify PostgreSQL connectivity (legacy) |
|
||||
| `scripts/test_api.py` | Verify API-Football connectivity (legacy) |
|
||||
| `scripts/apply_schema.py` | Apply database schema (legacy) |
|
||||
| `scripts/pull_tfc.py` | Full TFC data sync via API-Football (legacy) |
|
||||
| `scripts/verify_db.py` | Print DB row counts (legacy) |
|
||||
| `scripts/apply_schema.py` | Apply `schema.sql` to provision the cache database |
|
||||
| `scripts/discover_sportsdb.py` | Explore TheSportsDB API responses |
|
||||
|
||||
---
|
||||
|
||||
@@ -197,41 +179,26 @@ nike/
|
||||
├── .env # Secrets (not committed)
|
||||
├── pyproject.toml # Package metadata & dependencies
|
||||
├── run.py # Entrypoint: python run.py
|
||||
├── schema.sql # Database DDL (legacy)
|
||||
├── schema.sql # Cache database DDL
|
||||
├── nike.service # systemd unit file
|
||||
├── nike/
|
||||
│ ├── __init__.py
|
||||
│ ├── config.py # Settings from .env
|
||||
│ ├── rapidapi.py # RapidAPI client (active backend)
|
||||
│ ├── api_football.py # API-Football v3 client (legacy)
|
||||
│ ├── db.py # DB pool + queries (legacy)
|
||||
│ ├── sync.py # API → DB sync logic (legacy)
|
||||
│ ├── server.py # FastAPI + MCP server
|
||||
│ └── templates/
|
||||
│ └── dashboard.html # Status dashboard
|
||||
│ ├── sportsdb.py # TheSportsDB client (live backend)
|
||||
│ ├── db.py # PostgreSQL pool + active cache
|
||||
│ ├── logging_config.py # Structured logging setup
|
||||
│ └── server.py # FastAPI + MCP server
|
||||
├── dashboard/ # SvelteKit + DaisyUI dashboard
|
||||
└── scripts/
|
||||
├── test_rapidapi.py # RapidAPI smoke test
|
||||
├── apply_schema.py # (legacy)
|
||||
├── pull_tfc.py # (legacy)
|
||||
├── test_api.py # (legacy)
|
||||
├── test_db.py # (legacy)
|
||||
└── verify_db.py # (legacy)
|
||||
├── apply_schema.py # Provision the cache database
|
||||
└── discover_sportsdb.py # API exploration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Quota
|
||||
## Caching
|
||||
|
||||
The free-api-live-football-data RapidAPI pricing:
|
||||
|
||||
| Plan | Price | Requests/Month |
|
||||
|------|-------|----------------|
|
||||
| Basic (Free) | $0 | 100 |
|
||||
| Pro | $9.99/mo | 20,000 |
|
||||
| Ultra | $19.99/mo | 200,000 |
|
||||
| Mega | $49.99/mo | 500,000 |
|
||||
|
||||
Nike uses a 5-minute in-memory TTL cache to minimize API calls during conversations.
|
||||
Nike caches in two layers to minimise TheSportsDB calls: a short-lived in-memory TTL cache in `nike/sportsdb.py`, and a PostgreSQL cache (`nike/db.py`) for permanent data such as teams, players, leagues, and events. The dashboard's **Clear Cache** button (and `POST /api/cache/invalidate`) flushes both.
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user