Skip to content

Latest commit

 

History

155 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Table Lens

An AI-native conversational BI tool. Ask a question about your data in plain English, and a system of specialized agents finds the relevant schema, writes and validates SQL, answers in plain English, and can turn any result into a chart or a saved dashboard — all without you writing a query or picking a chart type yourself.

Full product vision, architecture, schemas, and API surface live in docs/ — this file is just enough to understand the shape of the project and get it running locally. docs/PRD.md is the canonical description of what this is and where it's going.

The data

The demo instance runs against a property & casualty insurance database — customers, policies, agents, claims, underwriting, fraud flags, call-center interactions, audit trails. 50 tables, 2,215 columns, over 5 million rows, generated to be messy the way real operational data is: null rates and column types vary wildly table to table, denormalized snapshots sit next to raw transactional logs, timestamps are stored without timezone, and some table names are ambiguous enough to need real disambiguation. It's built to be a genuinely hard target.

Architecture, briefly

Table Lens isn't one model trying to do everything — it's a small set of specialized agents, each responsible for one part of the problem, closer to how a real data team would split the work. One agent is responsible for understanding the database. A separate agent turns a question into SQL.Another takes a finished result and decides how to visualize it, including its own chart title.

A real, deliberate part of the design is how the system works with a schema at enterprise scale — hundreds of tables and thousands of columns, far more than could ever fit in a single prompt.

Nothing generated by a model is trusted blindly: SQL is validated before it's ever executed, and generated chart specs are validated before they reach the browser. Failures get retried with the actual error fed back in. The database connection is read-only and every query is restricted to SELECT; every endpoint is rate-limited.

Backed by 80+ automated tests — structural validation of every generate-then-validate guard, API route coverage, and real database round-trips, not just mocked-out happy paths. The default suite is pure/mocked and fast; tests that hit a live database or LLM are opt-in only. See docs/TESTING.md for the full layout and how to run each tier.

Stack

  • Backend: Python (FastAPI), uv for packages, one shared venv for the API, discovery/query/visualize agents, and the synthetic data generator
  • Agents: LangChain, routed through OpenRouter (model is a config swap)
  • Database: Supabase (Postgres + pgvector)
  • Frontend: Next.js 14 (App Router), bun for packages, ECharts for charts

Repo layout

table-lens/
├── backend/    # FastAPI app + agents (Python, uv) — see backend/Dockerfile
├── frontend/   # Next.js 14 app (bun) — see frontend/Dockerfile
├── scripts/    # start/stop scripts for local dev (see below)
├── docs/       # canon: PRD, architecture, schemas, API surface, progress
└── specs/      # per-increment design specs

Quick start

The fastest way to run everything locally:

./scripts/start.sh     # or scripts\start.ps1 on Windows PowerShell

Starts the backend on :8001 and frontend on :3000, killing anything already on those ports first. ./scripts/stop.sh (or stop.ps1) tears both down. Logs land in .run/.

That script assumes both projects already have their dependencies installed and a .env in place — see below for a from-scratch setup.

Environment

One .env for the whole project — create it at the repo root (a backend/.env also works, since load_dotenv() searches upward, but the root is the convention scripts/start.sh/start.ps1 rely on):

OPENROUTER_API_KEY=        # LLM + embeddings
SUPABASE_DB_URL=           # Supabase connection string (pooler, session mode)
SUPABASE_DB_URL_READONLY=  # a read-only Postgres role — falls back to SUPABASE_DB_URL if unset
ALLOWED_ORIGINS=           # comma-separated frontend origin(s); defaults to localhost in dev
NEXT_PUBLIC_API_BASE_URL=  # frontend's base URL for the backend; defaults to localhost:8000 if unset

Backend

cd backend
uv sync
uv run pytest              # fast suite; RUN_LIVE_TESTS=1 for real DB/LLM tests, -m slow for full end-to-end
uv run uvicorn app.main:app --reload --port 8001

Swagger UI is auto-generated at /docs (ReDoc at /redoc, raw spec at /openapi.json).

Frontend

cd frontend
bun install
bun run dev                 # http://localhost:3000

Set NEXT_PUBLIC_API_BASE_URL in the root .env if the backend isn't on http://localhost:8001 — one env file for the whole project, exported into both dev servers' process environment by scripts/start.sh/start.ps1.

Generator (populate the demo database)

Only needed once, or after resetting the demo schema:

cd backend/app/generator
uv run generate.py               # writes parquet locally
uv run connector/loader.py       # loads into Supabase's `demo` schema

Deploying

Both backend/ and frontend/ have production-ready multi-stage Dockerfiles. Recommended stack: any Docker host for the backend (Render, Fly, etc.) and Vercel for the frontend (which builds Next.js natively — the Dockerfile there is for portability to other platforms). Set NEXT_PUBLIC_API_BASE_URL at frontend build time and ALLOWED_ORIGINS on the backend to your real frontend domain.

About

Highly-efficient AI-native BI tool — query your database in plain English, visualize results instantly.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages