Skip to content
AzineZPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

MacroMind

An AI coach for League of Legends. Turns a player's ranked match history into specific, actionable coaching — not another stats dashboard. It reads the match timeline (per-minute state + kill/objective/ward events), extracts the signals that explain why games are lost, and uses an LLM to deliver plain-English feedback like:

Overextending after kills — 3 of your 5 deaths came within 60s of getting a kill, all in the 10–15 min window. You're chasing tempo instead of resetting.


Demo

demo

(Local, single-user tool — run against any Riot ID. See Running it.)


Why this exists (the core idea)

Most "stats" tools stop at end-of-game numbers (KDA, CS, gold) — which only ever produce generic advice: "your KDA is low, die less." The interesting signal lives in the timeline: when deaths happen, where on the map, and what preceded them. That's what lets the coach say why and when, not just what.

So the engineering focus isn't the API calls — it's the feature-extraction layer that turns thousands of raw timeline events into ~15 meaningful signals the LLM can reason over.


Architecture

flowchart LR
    A[Riot API<br/>match + timeline] --> B[Ingestion<br/>Python]
    B --> C[(PostgreSQL<br/>normalized schema)]
    C --> D[Feature extraction<br/>SQL → compact JSON]
    D --> E[LLM coach<br/>Gemini, structured output]
    E --> F[Coaching insights]
Loading

Two coaching modes, both fed by derived features (never raw timeline JSON):

Mode Input Example output
Per-match one match's timeline features "Your deaths spike 10–15 min after kills."
Trend aggregates over last N matches (GROUP BY) "This death-timing pattern shows up in 7 of your last 10 losses."

What I built / learned

  • Relational schema design from scratch — normalized players / matches / participants / participant_frames / timeline_events, foreign keys, and partial indexes tuned for the hot death-timing query. (My prior projects used Firestore; this was deliberate first-time relational modeling.)
  • Time-series feature engineering in SQL — width_bucket death-window bucketing, self-joins for "deaths within 60s of a kill," lane-opponent gold diff at 10/15 min via correlated subqueries.
  • LLM integration — structured prompting + typed/validated output (no fragile text parsing), a frozen cacheable system prompt, and a feature layer that keeps token cost and noise down instead of dumping raw JSON at the model.
  • Ingestion pipeline — rate-limited Riot API client, idempotent upserts, batch parsing of match + timeline payloads.

Tech stack

Layer Choice
Language Python 3.11
Database PostgreSQL 16 (Docker)
DB driver psycopg 3 (connection pool)
API client httpx
LLM Gemini API (structured outputs)
Data source Riot Games API (account-v1, match-v5 + timeline)

Key design decisions

Why the timeline, not just end-game stats?

Summary stats can tell you a death count; only the timeline knows those deaths clustered at 12–14 min in the enemy jungle right after a kill. The whole product thesis is that timing and context are what make coaching non-generic, so the timeline endpoint is the backbone, not an add-on.

Why compute features in SQL instead of sending raw JSON to the LLM?

A single timeline is tens of thousands of tokens of mostly-noise. LLMs reason poorly (and expensively) over raw event dumps. So SQL does the measurement (~15 signals) and the model does the interpretation — the split that keeps the output sharp and the cost low.

Why store all 10 participants, not just the tracked player?

Comparisons ("gold diff vs your lane opponent at 15") are impossible without the opponent's frames. Storing the full lobby is what makes benchmark-relative features work.


Running it

Local, single-user tool. Needs a Riot API key and a Gemini API key.

# 1. Postgres
docker compose up -d

# 2. Install
python3 -m venv .venv && source .venv/bin/activate
pip install -e .

# 3. Configure — copy and fill in keys
cp .env.example .env      # RIOT_API_KEY, GEMINI_API_KEY

# 4. Create the schema
python -m scripts.init_db

# 5. Analyze a player (Riot ID = gameName#tagLine)
python -m scripts.run_pipeline "Faker" "KR1" --count 10

Get a Riot key at https://developer.riotgames.com (a Personal API Key — the Development key expires every 24h).


Project layout

migrations/001_init.sql        # normalized schema
src/game_analyzer/
  riot/client.py               # rate-limited Riot API client
  riot/ingest.py               # match + timeline → Postgres
  features.py                  # timeline → compact feature dict  ← the core
  llm/prompt.py                # frozen, cacheable coaching prompt
  llm/coach.py                 # Gemini call, structured output
scripts/
  init_db.py                   # apply migrations
  run_pipeline.py              # end-to-end demo

Roadmap

  • Seed real role/rank benchmarks (currently a small reference table)
  • Per-champion trend breakdowns
  • Map-zone death classification (river / enemy jungle overextension)
  • Web frontend with trend charts (Recharts) + per-match insight cards
  • "Coach chat" — ask follow-up questions about a specific game

Notes

Personal, non-commercial learning project. Not affiliated with or endorsed by Riot Games. Secrets live in .env (gitignored) — no keys are committed.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages