City BudgetAI Assistant

How It Works

Back to Home

How We Built City Budget AI Assistant

City budgets are hundreds of pages long. We built a pipeline that parses them, indexes their meaning, and retrieves precise answers with page citations — so you never have to skim a PDF again.

The Pipeline

Step 1

Document Ingestion

Budget PDFs are parsed page-by-page using pdf-parse to extract raw text. Each page's content is preserved with its page number, so every answer can cite exactly where the information came from.

Step 2

Intelligent Chunking

Extracted text is split into overlapping ~1,000-character segments. The overlap ensures that context isn't lost at chunk boundaries — a sentence that spans two pages still gets captured in full.

Step 3

Vector Embeddings

Each chunk is converted into a high-dimensional numerical vector using BGE-M3. This model captures semantic meaning — so "public safety expenditure" and "police department funding" end up close together in vector space.

Step 4

Semantic Retrieval

When a user asks a question, it's also embedded into the same vector space. Upstash Vector finds the most relevant chunks by cosine similarity — no keyword matching, just meaning.

Step 5

Contextual Answer Generation

The retrieved excerpts are assembled into a prompt with instructions to stay grounded in the source material. The language model generates an answer with page citations, so users can verify every claim.

Architecture

┌─────────────┐
│  PDF Upload  │
└──────┬──────┘
       │ parse pages
       ▼
┌─────────────┐
│  Text Chunks │  ~1000 chars, overlapping
└──────┬──────┘
       │ embed (BGE-M3)
       ▼
┌─────────────┐
│ Vector Store │  Upstash Vector
└──────┬──────┘
       │
       │         ┌──────────────┐
       │         │ User Question │
       │         └──────┬───────┘
       │                │ embed
       │                ▼
       │         ┌──────────────┐
       └────────►│  Similarity  │
                 │    Search    │
                 └──────┬───────┘
                        │ top-k chunks
                        ▼
                 ┌──────────────┐
                 │   Prompt +   │
                 │   Context    │
                 └──────┬───────┘
                        │ generate
                        ▼
                 ┌──────────────┐
                 │    Answer    │
                 │ (with pages) │
                 └──────────────┘

Tech Stack

Next.js 16React 19TypeScriptUpstash VectorOpenRouterBGE-M3Tailwind CSSshadcn/ui