Skip to content

Repository files navigation

electiondata-chatbot-api

An unofficial, community-run chatbot for ElectionData.MY — an Agno agent that answers questions about Malaysian election data, backed by the public ElectionData.MY REST API and its data lake (candidate demographics, polling-station level results, voter rolls, and full historical trends going back to GE-01).

This is not maintained or endorsed by the ElectionData.MY team — it's a separate project built on their public API and data, kept here so anyone can self-host it. Bring your own API keys.

Try it live at http://localhost:8001/ after running it (see below) — a single-page chat widget is included, no separate frontend needed.

Shape

  • FastAPI backend, one Agno Agent, no external database (in-process session history only — history lives as long as the server process runs)
  • POST /chat — AG-UI-compatible streaming endpoint (text/event-stream)
  • GET / — a self-contained, dependency-free HTML/JS chat widget that talks to /chat
  • Async tools against the public ElectionData.MY REST API (candidates, seats, parties, elections, by-elections, results)
  • query_data_lake — a read-only DuckDB SQL tool against the public Parquet data lake (lake.electiondata.my), for anything the REST API alone can't answer: candidate age/sex/ ethnicity, saluran (polling station) level results, voter rolls, cross-election analysis
  • Optional controlled UI components (show_ui): cards, tables, alerts, and a candidate profile card colour-coded by coalition

Setup

Requires uv and Python 3.12.

make setup      # uv sync + creates .env from .env.example if missing

Then fill in .env:

  • OPENAI_API_KEY — your own OpenAI key (any account with API access; the agent defaults to gpt-4o-mini, configurable via OPENAI_MODEL)
  • ELECTIONDATA_API_KEY — get one free at electiondata.my (an API key is required for the REST endpoints; the data lake itself needs no key)
make dev        # runs at http://localhost:8001

Open http://localhost:8001/ in a browser to chat. No separate frontend, no CORS setup needed — the widget is served by this same app.

Docker

make docker-up

Runs on port 8001 by default (see docker-compose.yml). Environment variables come from .env.

Test

make test
make lint

Embedding your own frontend

If you'd rather build your own UI instead of using the bundled widget, POST /chat accepts a minimal AG-UI-style body and streams AG-UI events back:

{
  "threadId": "local-thread",
  "messages": [{ "role": "user", "content": "Who won P.001 Padang Besar in GE-15?" }]
}

Any AG-UI compatible client (e.g. @ag-ui/client's HttpAgent) works directly against this endpoint.

Notes on safety

query_data_lake runs whatever read-only SQL the agent writes. It's gated to SELECT/WITH statements only (no DDL, no raw URLs — only the documented dataset names), voter-roll queries are forced to LIMIT 10000 or less, and results are hard-capped at 200 rows server-side regardless of the query. See src/electiondata_chatbot_api/services/datalake.py for the exact rules.

About

Unofficial, self-hostable Agno chatbot for ElectionData.MY — bring your own API keys

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages