⚑ Sangsakala Proxy 🏠 Home
Skip to content

About

1st place, GDG Raipur Agentic Premier League hackathon 2026. Real-time IPL backend: Redis pub/sub, three AI agents, WebSocket broadcast.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

⚑ CricketPulse

Real-time multi-agent IPL AI backend

Every ball. Three AI agents. One live broadcast.

Python FastAPI XGBoost Groq Redis License

πŸ† 1st place at GDG Raipur β€” Agentic Premier League Hackathon, May 24 2026


What is this?

CricketPulse turns a Cricsheet ball-by-ball JSON into a live AI broadcast. The moment an event arrives off the Redis wire, three agents fire in parallel:

Agent Type What it does
Win Probability XGBoost ML Predicts P(batting team wins) from 12 match-state features
Commentary Groq LLM Writes one Harsha Bhogle-style sentence per delivery
Alerts Rules + LLM Fires on wickets, fifties, centuries, sixes β€” LLM called only when needed

All three results are fused into a single JSON payload and broadcast to every WebSocket client in real time. PostgreSQL gets a background log. The frontend updates without a page refresh.


Architecture

Cricsheet JSON
      β”‚
      β–Ό
emitter.py ──publish──▢ Redis: match:events
                                β”‚
                         [FastAPI subscriber]
                                β”‚
                      event_processor.py
                                β”‚
               β”Œβ”€β”€β”€β”€asyncio.gather()────┐
               β”‚                        β”‚
        to_thread(XGBoost)        check_and_alert()
        Win Probability           Rules + Groq LLM
               β”‚                        β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                   generate_commentary()
                        Groq LLM
                            β”‚
                   WebSocketPayload
                            β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚             β”‚             β”‚
       WS broadcast      Next.js UI   create_task(Postgres)
       (all clients)     React app    (fire-and-forget)

Critical design decisions:

  • asyncio.gather() β€” ML inference and alert check run concurrently, not sequentially
  • asyncio.to_thread() β€” XGBoost inference offloaded to thread pool, event loop stays unblocked
  • Per-client try/except in broadcast() β€” one dead WebSocket never kills others
  • LLM fallback "Great delivery!" β€” Groq rate limits or timeouts never crash the pipeline
  • DB logging is always create_task() β€” never adds to broadcast latency

Project structure

CricketPulse/
β”œβ”€β”€ Backend/
β”‚   β”œβ”€β”€ main.py                  # FastAPI app, lifespan, router registration
β”‚   β”œβ”€β”€ config.py                # pydantic-settings, reads .env
β”‚   β”œβ”€β”€ database.py              # async SQLModel engine + session factory
β”‚   β”œβ”€β”€ agents/
β”‚   β”‚   β”œβ”€β”€ win_probability.py   # XGBoost inference, 12-feature match state
β”‚   β”‚   β”œβ”€β”€ commentary.py        # Groq LLM, one sentence per ball
β”‚   β”‚   └── alerts.py            # Rule engine + conditional Groq call
β”‚   β”œβ”€β”€ core/
β”‚   β”‚   β”œβ”€β”€ event_processor.py   # Orchestrator β€” gather, broadcast, log
β”‚   β”‚   β”œβ”€β”€ redis.py             # Async pub/sub singleton
β”‚   β”‚   β”œβ”€β”€ ws_manager.py        # WebSocket fan-out with fault isolation
β”‚   β”‚   └── llm.py               # Groq async wrapper + fallback
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ health.py            # GET /health
β”‚   β”‚   β”œβ”€β”€ match.py             # state, history, inject, demo/wicket
β”‚   β”‚   └── websocket.py         # WS /ws
β”‚   β”œβ”€β”€ schemas/
β”‚   β”‚   β”œβ”€β”€ event.py             # BallEvent (Pydantic v2)
β”‚   β”‚   β”œβ”€β”€ payload.py           # WinProbResult, WebSocketPayload
β”‚   β”‚   └── response.py          # HealthResponse, MatchStateResponse, etc.
β”‚   β”œβ”€β”€ db/
β”‚   β”‚   └── models.py            # BallEventLog, LLMResponseLog (SQLModel)
β”‚   └── emitter/
β”‚       └── emitter.py           # Cricsheet parser + Redis publisher
β”‚
β”œβ”€β”€ Frontend/cricketpulse-frontend/
β”‚   β”œβ”€β”€ app/                     # Next.js 16 App Router (React Server Components)
β”‚   β”‚   β”œβ”€β”€ layout.tsx           # Root layout with metadata
β”‚   β”‚   β”œβ”€β”€ page.tsx             # Home page
β”‚   β”‚   β”œβ”€β”€ globals.css          # Global styles
β”‚   β”‚   └── docs/                # Documentation pages
β”‚   β”œβ”€β”€ components/              # React components
β”‚   β”‚   β”œβ”€β”€ animations/          # Framer Motion animations (six, wicket, boundary, milestone)
β”‚   β”‚   β”œβ”€β”€ dashboard/           # Dashboard widgets (ScoreBoard, CommentaryFeed, WinProbBar, etc.)
β”‚   β”‚   β”œβ”€β”€ docs/                # Documentation components (API reference, architecture, etc.)
β”‚   β”‚   └── ui/                  # Reusable UI components (Badge, CodeBlock, StatCard, etc.)
β”‚   β”œβ”€β”€ hooks/                   # Custom React hooks (useWebSocket, useMatchState, useAnimationTrigger)
β”‚   β”œβ”€β”€ lib/                     # Utilities (API examples, constants, utils)
β”‚   β”œβ”€β”€ public/                  # Static assets
β”‚   β”œβ”€β”€ types/                   # TypeScript type definitions (cricket.ts)
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ tsconfig.json
β”‚   β”œβ”€β”€ next.config.ts
β”‚   β”œβ”€β”€ postcss.config.mjs
β”‚   β”œβ”€β”€ tailwind.config.js
β”‚   β”œβ”€β”€ eslint.config.mjs
β”‚   └── next-env.d.ts
β”‚
β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ win_prob.pkl
β”‚   β”œβ”€β”€ team_encoder.pkl
β”‚   └── features.pkl
β”‚
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ requirements.txt
└── PRD.md

Quickstart

Prerequisites

  • Python 3.11+
  • Docker Desktop
  • A Groq API key (free tier works)

1. Clone and install

git clone https://github.com/BackStacked/CricketPulse.git
cd CricketPulse
pip install -r requirements.txt

2. Configure

# .env is already created β€” just add your key
GROQ_API_KEY=gsk_your_key_here
REDIS_URL=redis://localhost:6379
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/cricketpulse
REDIS_CHANNEL=match:events

3. Start infrastructure

docker compose up -d

4. Run the backend

# Terminal 1
uvicorn Backend.main:app --reload

Expected startup output:

[CricketPulse] Starting up...
[WinProbAgent] Loaded β€” 81.7% acc, 0.91 AUC
[CricketPulse] Redis connected
[CricketPulse] Subscribed to Redis channel: match:events
[CricketPulse] Ready β€” waiting for ball events...

5. Start the emitter

# Terminal 2
python -m Backend.emitter.emitter --file 1529309.json --speed demo

6. Open the dashboard

# Terminal 3
cd Frontend/cricketpulse-frontend
npm install
npm run dev

The Next.js dashboard will start on http://localhost:3000


Speed modes

Flag Delay per ball Use case
--speed slow 8s Watch carefully
--speed normal 4s Default
--speed demo 2s Hackathon demo
--speed fast 1s Quick integration test

API reference

Docs: http://localhost:8000/docs (Swagger UI auto-generated)

Method Path Description
GET /health Redis, DB, model status
GET /match/state Current in-memory match state
GET /match/history?limit=20 Last N balls from Postgres
POST /match/event Inject any BallEvent into the pipeline
POST /demo/wicket Force a Rohit Sharma caught dismissal
WS /ws Live WebSocketPayload stream

WebSocket payload shape

Every ball emits this JSON to all connected clients:

{
  "ball": {
    "match_id": "1529309",
    "inning": 1,
    "batting_team": "Gujarat Titans",
    "bowling_team": "Chennai Super Kings",
    "over": 7,
    "ball": 3,
    "batter": "Shubman Gill",
    "bowler": "Mukesh Choudhary",
    "non_striker": "B Sai Sudharsan",
    "batsman_runs": 1,
    "extra_runs": 0,
    "total_runs": 1,
    "is_wicket": false,
    "player_dismissed": null,
    "dismissal_kind": null,
    "is_powerplay": false
  },
  "win_prob": {
    "batting_team": "Gujarat Titans",
    "bowling_team": "Chennai Super Kings",
    "batting_prob": 64.2,
    "bowling_prob": 35.8
  },
  "commentary": "Shubman Gill clips it fine for a cheeky single as Gujarat continue to build steadily.",
  "alert": null,
  "timestamp": "2026-05-24T14:22:01.123456Z"
}

ML model

The win probability model was trained on IPL historical ball-by-ball data from Cricsheet.

Attribute Value
Algorithm XGBoost (XGBClassifier)
Accuracy 81.7%
AUC-ROC 0.91
Features 12 (inning, over, ball, runs, wickets, balls_remaining, CRR, RRR, runs_remaining, target, batting_team_enc, bowling_team_enc)
Target winner == batting_team (binary)
Serialization joblib

Run ML Model/train_win_prob.ipynb to retrain on updated data.


Demo script (for judges)

# 1. Start infrastructure + backend (see Quickstart above)

# 2. Open Frontend/index.html in browser
#    β†’ dot shows "Live", dashboard is waiting

# 3. Start emitter
python -m Backend.emitter.emitter --file 1529309.json --speed demo

# 4. Watch win probability bar shift every 2 seconds
# 5. Watch commentary appear for every ball
# 6. Wait for a wicket β€” red alert banner fires

# 7. Force an instant wicket anytime (works mid-match):
curl -X POST http://localhost:8000/demo/wicket

# 8. Show persistent DB history:
curl http://localhost:8000/match/history

# 9. Show Swagger UI:
#    http://localhost:8000/docs

# 10. Use --demo-wicket flag to force wicket at specific ball:
python -m Backend.emitter.emitter --file 1529309.json --speed demo --demo-wicket 10

Frontend dashboard

Next.js 16 + React 19 full-stack TypeScript application

Built with modern React patterns, Server Components, and TypeScript for type safety.

Key UI features:

  • Win probability bar β€” animated two-sided bar, purple (batting) vs teal (bowling), transitions smoothly on every ball (Framer Motion)
  • Commentary feed β€” last 10 deliveries, newest on top, fade-in animation
  • Alert banner β€” flashes red for wickets/milestones, auto-dismisses after 4 seconds
  • Ball log chips β€” last 20 balls: gray dot, blue 1-3, green 4, amber 6, red W
  • Connection indicator β€” pulsing green when live, auto-reconnects on disconnect
  • Responsive design β€” Tailwind CSS v4 for mobile-first, accessible UI
  • Smooth animations β€” Framer Motion for card and boundary animations

Tech stack

Layer Technology
API framework FastAPI + uvicorn
Real-time transport WebSocket (native FastAPI)
Message bus Redis pub/sub
Database PostgreSQL 15 via asyncpg + SQLModel
ORM / validation SQLModel + Pydantic v2
ML model Next.js 16 + React 19 + TypeScript
Styling Tailwind CSS v4 + PostCSS
Animations Framer Motion
Icons Lucide React
Linting ESLint
LLM Groq Cloud β€” llama-3.1-8b-instant
Config pydantic-settings
Serialization joblib (model), json (Redis)
Infra Docker Compose
Frontend Vanilla JS + CSS custom properties

Fault tolerance guarantees

Failure scenario Behaviour
Groq API down / rate limited Returns "Great delivery!" β€” pipeline never crashes
PostgreSQL unreachable DB log silently skipped β€” broadcast continues
Dead WebSocket client Client pruned silently β€” other clients unaffected
Unknown team name in ML encoder Falls back to index 0 β€” no exception
Model file missing Returns 50/50 β€” /health reports model_loaded: false

Contributing

  1. Fork the repo
  2. Add your agent under Backend/agents/
  3. Wire it into event_processor.py inside asyncio.gather()
  4. Add its output field to WebSocketPayload in schemas/payload.py
  5. Open a PR

Agent pattern is deliberately isolated β€” adding a new agent does not touch routes, WebSocket, or DB layers.


License

MIT β€” see LICENSE


Built with Python, XGBoost, Groq, Redis, FastAPI, and a love for cricket.

GDG Raipur β€” Agentic Premier League, May 24 2026

About

1st place, GDG Raipur Agentic Premier League hackathon 2026. Real-time IPL backend: Redis pub/sub, three AI agents, WebSocket broadcast.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages