Skip to content

Instantly share code, notes, and snippets.

@jeremylongshore
Last active March 6, 2026 03:09
Show Gist options
  • Select an option

  • Save jeremylongshore/07e15be57e39b73c0b6f486bbfad1b8a to your computer and use it in GitHub Desktop.

Select an option

Save jeremylongshore/07e15be57e39b73c0b6f486bbfad1b8a to your computer and use it in GitHub Desktop.
Braves Booth Intelligence Dashboard — Architecture Reference Card

Braves Booth Intelligence Dashboard

Real-time AI-powered broadcast intelligence for Atlanta Braves radio. Surfaces AI-generated narratives, player analytics, matchup history, and situational intelligence to announcers and producers during live games — with sub-6-second data latency from MLB's live feed to the broadcast booth.


Architecture

Three-service monorepo deployed on Google Cloud Platform, designed around a core constraint: zero network dependencies during live broadcast for all cached data.

                        ┌──────────────────────────┐
                        │     Firebase Hosting      │
                        │     (CDN + SPA)           │
                        └────────┬───┬─────────────┘
                                 │   ▲
                        API      │   │  Static Assets
                        Proxy    │   │
                                 ▼   │
┌──────────────┐      ┌─────────────────────────┐      ┌───────────────────┐
│ MLB Stats API│◄────►│    Backend Service       │◄────►│  Python Service   │
│ (GUMBO Feed) │      │    Fastify + TypeScript  │      │  FastAPI + Statcast│
└──────────────┘      └──────┬────────┬──────────┘      └───────────────────┘
                             │        │
                   ┌─────────┘        └─────────┐
                   ▼                            ▼
            ┌──────────────┐          ┌──────────────────┐
            │    SQLite    │          │   Vertex AI      │
            │   (WAL mode) │          │   Gemini 2.5 Pro │
            └──────────────┘          └──────────────────┘
Service Stack Deploy Target
Backend Fastify 5, TypeScript, SQLite, Pino Cloud Run
Frontend React 18, Vite 6, Tailwind CSS v4 Firebase Hosting
Python FastAPI, pybaseball, Statcast Cloud Run

Key Features

  • Live Game Tracking — 5-second polling of MLB's GUMBO feed with Server-Sent Events pushing state changes to connected clients in real time
  • AI Broadcast Narratives — Gemini 2.5 Pro generates context-aware talking points for each at-bat, combining player stats, matchup history, game situation, and broadcaster personality profiles
  • Predictive Prefetching — System anticipates data needs at boot, on batter changes (on-deck + in-hole), and on pitcher substitutions, pre-warming caches before announcers need the data
  • Statcast Analytics — Deep statistical pipeline via pybaseball: exit velocity, barrel rates, pitch spin rates, platoon splits, and historical batter-vs-pitcher matchups
  • Multi-Source Matchup Intelligence — Parallel queries to MLB Stats API and Statcast with graceful partial-failure handling via Promise.allSettled()
  • Broadcaster Co-Host Profiles — AI narratives adapt tone and content based on which co-host is on air
  • Live Ticker — Real-time MLB scores and NL standings alongside the broadcast dashboard
  • Venue-Aware Weather — Dynamic weather data using stadium coordinates, with intelligent fallback for API outages
  • Free-Form AI Q&A — Natural language queries about the current game state answered from live context

Real-Time Data Pipeline

The system consumes MLB's GUMBO v1.1 live feed, a comprehensive JSON stream updated pitch-by-pitch during games.

MLB GUMBO Feed (5s poll)
    │
    ▼
GUMBO Poller ─── detects state transitions ──┐
    │                                         │
    ├─► game-state (every poll cycle)         │
    ├─► batter-change (plate appearance)      │
    ├─► pitcher-change (substitution)         │
    └─► score-change (run scored)             │
                                              ▼
                                    Event Bus (pub/sub)
                                              │
                                              ▼
                                    SSE Stream (/api/events)
                                              │
                                              ▼
                                    Browser EventSource
                                              │
                                              ▼
                                    React Context → UI Panels

End-to-end latency: ~5.5 seconds from MLB feed update to browser render.


AI Intelligence Engine

Narrative Generation

Each at-bat, the system assembles a rich context window for Gemini 2.5 Pro:

  1. Batter profile — current + prior season stats, splits, tendencies
  2. Pitcher profile — current + prior season stats, pitch arsenal
  3. Matchup history — historical at-bats between the two players (MLB Stats + Statcast)
  4. Game situation — inning, count, runners, score differential
  5. Broadcaster profile — personality, preferred angles, storytelling style

The AI generates a structured response: a lead talking point and supporting angles, giving announcers a quick-glance narrative they can riff on live.

Query Engine

Announcers can ask free-form questions about the game ("How has Acuna done with runners in scoring position this series?") and get factual answers synthesized from the live context window — no hallucination, sourced only from available data.


Caching & Performance

Three-Tier Cache Architecture

The system uses a tiered caching strategy designed to survive the worst-case scenario: an API outage during a live broadcast.

Tier Technology Scope Purpose
L1 In-memory TTL cache Per-instance, volatile Hot path — sub-millisecond reads for repeat queries within a game
L2 SQLite (WAL mode) Persistent across restarts Warm path — survives process crashes, ephemeral by design on Cloud Run
L3 External APIs Source of truth Cold path — MLB Stats, Statcast, Vertex AI

SQLite runs in WAL (Write-Ahead Logging) mode for concurrent read/write performance. The database is intentionally ephemeral on Cloud Run — an architectural decision that trades persistence for zero network database dependencies during live broadcasts.

Predictive Prefetch Lifecycle

BOOT TIME
  └─► Discover today's game → start poller → prefetch full rosters
      (both teams: stats, player info, opposing starter narratives)
      Concurrency-limited parallel fetches across all data sources

BATTER CHANGE
  └─► Prefetch on-deck + in-hole batter stats (current + prior season)
      Pre-generate narrative for on-deck batter vs current pitcher

PITCHER CHANGE
  └─► Re-generate narratives for current batter, on-deck, and in-hole
      vs the new pitcher (3 parallel AI generations)

SSE CLIENT CONNECT
  └─► Auto-recovery: if poller isn't running, discover game + start + prefetch

Prefetch operations are idempotent with in-flight guards preventing duplicate concurrent runs.


API Surface

REST Endpoints (22 total)

Category Endpoints Purpose
Game 4 Live state, today's game discovery, poller control
Player Stats 2 Batter and pitcher profiles with dual-season data
Analytics 5 Matchups, Statcast, splits, platoon data
AI 2 Narrative generation, free-form Q&A
Broadcast 3 Co-host profiles, umpire tendencies
Context 3 Weather, ticker (scores + standings), health
Real-time 1 SSE event stream
Batch 2 Roster prefetch orchestration

SSE Event Types

Event Trigger Purpose
game-state Every 5s poll Full game state sync
batter-change New plate appearance Current, on-deck, and in-hole batters
pitcher-change Substitution New pitcher entering the game
score-change Run scored Updated score with team names
heartbeat Every 15s Connection keepalive

Engineering Highlights

Resilience Patterns

  • Circuit Breaker — Python's pybaseball integration uses a full state-machine circuit breaker (CLOSED → OPEN → HALF_OPEN) that isolates external library failures from the broadcast
  • Graceful Degradation — Matchup queries fan out to MLB Stats API and Statcast simultaneously; partial failures return available data rather than erroring
  • Timeout Boundaries — Every external call wrapped with abort signals; AI generation has a hard 5-second ceiling
  • Weather Fallback — API failures gracefully degrade to venue-default conditions
  • SSE Auto-Recovery — Frontend automatically reconnects on stream interruption; backend auto-discovers games on client connect if poller isn't running
  • Prefetch Idempotency — In-flight guards prevent duplicate concurrent prefetch runs on rapid event bursts

Architectural Decisions

  • SQLite over cloud databases — Eliminates network latency and single points of failure for cached data during live broadcast. The tradeoff (cold cache on redeploy) is mitigated by aggressive boot-time prefetching
  • SSE over WebSockets — Simpler protocol, native browser support, automatic reconnection. The data flow is unidirectional (server → client), making SSE the right fit
  • Monorepo with service isolation — Three services share a repo for atomic deploys but maintain strict boundaries. Python service exists solely because pybaseball/Statcast require a Python runtime
  • Ephemeral by design — No persistent cloud database means no database ops, no connection pooling, no migration headaches. Each deploy starts clean and pre-warms within seconds

Quality & Testing

Service Test Files Tests Status
Backend 19 85 All passing
Frontend 4 10 All passing
Python 4 16 All passing
Total 27 111 109 passing, 2 skipped (integration)
  • CI/CD: Automated deploy pipeline on push to main — builds and deploys all three services in dependency order with health check verification
  • Workload Identity Federation: Keyless authentication from GitHub Actions to GCP via OIDC — no service account keys stored anywhere

Metrics

Metric Value
Services 3 (TypeScript backend, React frontend, Python analytics)
Application code ~6,600 lines (TypeScript + TSX + Python)
Source files 105+
API endpoints 22
SSE event types 5
External data sources 4 (MLB Stats, GUMBO, Statcast/pybaseball, Open-Meteo)
AI model Gemini 2.5 Pro (Vertex AI)
Cache tiers 3 (memory → SQLite → API)
Test suite 111 tests across 27 files
Poll frequency 5 seconds (live game state)
Target latency <6s end-to-end (feed → browser)

A real-time broadcast intelligence system built for the speed and reliability demands of live sports radio.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment