Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ask London

A voice-enabled chat agent that answers cited questions about London's 33 boroughs, grounded in real open data, running on NVIDIA Nemotron. Every figure is computed from the data and traced to its source; the agent says so plainly when the data cannot answer.

It assembles a mosaic: it stitches the relevant facts for a borough across several fragmented open datasets - income, housing affordability, deprivation, health - into one answer, and points you to the source for every number.

What it does

  • Chat (ChatGPT-style) and voice (ElevenLabs, optional) over London open data.
  • Two reasoning lanes, the model picks per question:
    • Retrieval (RAG + graph) - cited facts, cross-source joins, exact rankings.
    • Computation (text-to-SQL via PydanticAI) - exact aggregates (averages, counts, totals).
  • Never invents a number - every figure is cited to its source chunk or its SQL query.
  • Self-contained and designed to run fully local on an NVIDIA DGX Spark.

Quickstart

git clone https://github.com/Krishna-kai/AskLondon
cd AskLondon
./bootstrap.sh                                   # venv + deps + index, one command
# add your NVIDIA_API_KEY to .env, then:
.venv/bin/python -m streamlit run chat_app.py    # http://localhost:8501

bootstrap.sh works offline too (builds a deterministic index with no key). Acceptance check: EMBED_MODE=hash LLM_MODE=test .venv/bin/python tests.py.

Where it runs

Built for NVIDIA. The agent runs on NVIDIA Nemotron, served via NIM, with NVIDIA NeMo Retriever for the embeddings:

Run target Set in .env What you get
Cloud NIM (laptop + NVIDIA API key) NVIDIA_API_KEY=nvapi-... the full two-lane agent on Nemotron (validated 2026-06-07)
NVIDIA DGX Spark (sovereign, fully local) nim_stack.sh up, NIM_BASE_URL=http://localhost:8000/v1 Nemotron LLM + NeMo Retriever + rerank + safety, co-resident on the box

On the Spark the whole Nemotron stack stays in the room; only the optional ElevenLabs voice leaves it. Full bring-up: DEPLOY_SPARK.md.

git clone https://github.com/Krishna-kai/AskLondon && cd AskLondon
./bootstrap.sh                                    # venv + deps + index
# put NVIDIA_API_KEY=nvapi-... in .env   (free key at build.nvidia.com), then:
.venv/bin/python -m streamlit run chat_app.py     # http://localhost:8501

Data resilience: the bundled health data always loads, and the economy sources fall back to a bundled cache (data/economy_cache.json) if the London Datastore is down, so a demo never loses sources.

Portability beyond NVIDIA is a footnote, not the headline.1

The guards make a weaker local model fail safe, not wrong: if it cannot tool-call the SQL lane cleanly, the anti-fabrication guard returns "compute unavailable" instead of an invented number.

Deploy on an NVIDIA DGX Spark

From your laptop, with the project cloned:

ssh-copy-id nvidia@my-spark.local      # one-time passwordless SSH (use your box's host id)
./push_to_spark.sh my-spark            # rsync the project + bootstrap on the box

Then on the box: ./serve_model.sh (Nemotron on :8000) and ./deploy_spark.sh (ingest + app on :8501), with NIM_BASE_URL=http://localhost:8000/v1. Details: DEPLOY_SPARK.md.

Data

  • Income - HMRC taxpayer income by borough (London Datastore)
  • Housing affordability - house-price-to-earnings ratio (London Datastore)
  • Deprivation - Indices of Deprivation 2019 (London Datastore)
  • Health - life expectancy at birth (OHID Fingertips)

The economy datasets are fetched live from the London Datastore at ingest; the Fingertips extract is bundled in data/. New sources plug in as small adapters (see connector.py / economy.py).

How it works

chat_app.py ─► agent.py ─► retrieval.py (vector + graph + rank)  ─┐
                          └► sql_lane.py (PydanticAI text-to-SQL) ─┴─► Nemotron ─► cited answer
            data: connector.py + economy.py ─► store.py + graphstore.py + sql_db.py

Full write-up in ARCHITECTURE.md. Local deployment on a DGX Spark: DEPLOY_SPARK.md. Versions: VERSION.md.

Testing

Two layers, both offline (no key, no GPU):

EMBED_MODE=hash STORE_MODE=local python tests.py     # 22 checks, all offline
  • Plumbing - connector to embeddings to store + graph to retrieval to cited answer.
  • Guarantees (pinned so a refactor cannot silently break them): read-only SQL safety (rejects writes/DDL, including stacked SELECT 1; DROP ...), never-invent (no figure unless a real SELECT ran), exact ranking (the graph sorts real values), exact compute (DuckDB aggregates).

doctor.py healthchecks the index + model + embed endpoints; deploy_spark.sh runs tests.py on the box before the app goes live. Validated end to end on cloud NIM (2026-06-07): both lanes cited and correct, 22/22 in NIM mode.

Configuration

The same code runs on a laptop (cloud NIM) and on a Spark (local Nemotron) by env only: EMBED_MODE (hash | nim), STORE_MODE (local | milvus), LLM_MODE (test | nim), NIM_BASE_URL, EMBED_BASE_URL, NIM_MODEL, SQL_NIM_MODEL. See .env.example.

SQL_NIM_MODEL gives the SQL lane its own model knob - keep it on nvidia-nemotron-nano-9b-v2 even if NIM_MODEL is set to a bigger model; larger reasoning models can malform SQL tool-call JSON. Validated model for both lanes: Nano-9B-v2 (cloud NIM, re-confirmed 2026-06-07).

License

MIT - see LICENSE.

Footnotes

Footnotes

  1. NVIDIA is the target, not a lock-in. Because every inference call is OpenAI-compatible and routed through config.py, the same code also runs (a) offline with no key, in a deterministic test mode (used by the acceptance tests / CI), and (b) against a non-NVIDIA local endpoint such as Ollama, LM Studio, or MLX (Mac / Windows / Linux) by setting LLM_MODE=nim, NIM_BASE_URL, NIM_MODEL, SQL_NIM_MODEL, and EMBED_MODE=hash. Both paths are validated, but they are a portability fallback - the project is built for NVIDIA Nemotron on the DGX Spark.

About

Voice-enabled chat agent on NVIDIA Nemotron answering cited questions about London's boroughs, fully local on a DGX Spark.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages