A financial chatbot that answers tax-related questions using hybrid retrieval — combining vector search (ChromaDB) with a knowledge graph (Neo4j). It processes tax records, IRS forms, the US Tax Code, and educational materials to provide grounded, context-aware responses via OpenAI's GPT models.
- Hybrid retrieval — semantic vector search for unstructured documents + graph queries for structured data (comparisons, aggregations, trends)
- Multi-source ingestion — CSV tax records, PDF documents, and PowerPoint presentations
- Knowledge graph — automatically built from CSV data with pre-computed aggregates across states, taxpayer types, income sources, and deduction types
- Streamlit UI — interactive chat interface with conversation history and system status sidebar
| Layer | Technology |
|---|---|
| UI | Streamlit |
| LLM | OpenAI GPT-4o-mini |
| Embeddings | OpenAI text-embedding-3-small |
| Vector store | ChromaDB |
| Knowledge graph | Neo4j (Community) |
| Data processing | Pandas, PyMuPDF, python-pptx |
| Package manager | uv |
flowchart LR
subgraph Sources["Data Sources"]
CSV[("tax_data.csv<br/>5,000 records")]
PDF[("IRS 1040<br/>USC Title 26")]
PPT[("Microeconomics<br/>presentation")]
end
subgraph Ingestion["Ingestion Pipeline"]
CSVP["csv_processor<br/>row chunks + aggregates"]
PDFP["pdf_processor<br/>extract + chunk"]
PPTP["ppt_processor<br/>slide extraction"]
end
subgraph Storage["Storage Layer"]
Chroma[("ChromaDB<br/>vector store")]
Neo4j[("Neo4j<br/>knowledge graph")]
end
subgraph Retrieval["Retrieval Layer"]
Router{{"Query Router<br/>structured vs semantic"}}
Hybrid["Hybrid Retriever<br/>merge + rank"]
end
subgraph Generation["Generation Layer"]
Embed["OpenAI Embeddings<br/>text-embedding-3-small"]
LLM["OpenAI Chat<br/>gpt-4o-mini"]
end
UI["Streamlit UI"]
User(["User"])
CSV --> CSVP
PDF --> PDFP
PPT --> PPTP
CSVP -->|text + metadata| Chroma
PDFP -->|text + metadata| Chroma
PPTP -->|text + metadata| Chroma
CSVP -->|nodes + edges + aggregates| Neo4j
Embed -.->|embed chunks| Chroma
User <--> UI
UI --> Router
Router -->|structured query| Neo4j
Router -->|semantic query| Chroma
Embed -.->|embed query| Chroma
Neo4j --> Hybrid
Chroma --> Hybrid
Hybrid -->|context| LLM
LLM -->|answer| UI
The pipeline is Ingestion → Storage → Retrieval → Generation.
Ingestion converts raw data (CSV, PDF, PPT) into text chunks with metadata. CSV data is also aggregated into summary statistics and loaded into a Neo4j knowledge graph with nodes for states, taxpayer types, income sources, deduction types, and tax years.
Retrieval is hybrid. A query router inspects the user's question for patterns that suggest structured data (e.g., state names, "compare", "trend") and queries Neo4j when appropriate. All queries also hit ChromaDB for semantic matches. Results from both sources are merged and passed to the LLM.
Generation uses GPT-4o-mini (temperature 0.1) with a system prompt that instructs it to act as a tax assistant. The last 6 conversation turns are included for context continuity.
If Neo4j is unavailable, the chatbot degrades gracefully to vector-only retrieval.
- Python 3.14+
- uv (recommended) or pip
- Docker & Docker Compose (for Neo4j)
- An OpenAI API key
- LibreOffice (optional — only needed if ingesting
.pptfiles)
-
Install dependencies
uv sync
Or with pip:
pip install -e ".[dev]" -
Configure environment variables
cp .env.example .env
Edit
.envand set your OpenAI API key:OPENAI_API_KEY=sk-... NEO4J_URI=bolt://localhost:7687 NEO4J_USER=neo4j NEO4J_PASSWORD=taxbuddy123 -
Start Neo4j
docker compose up -d
-
Ingest data
uv run python scripts/ingest.py
This processes all files in
data/, populates the vector store, and builds the knowledge graph. Pass--resetto clear and rebuild from scratch. -
Launch the app
streamlit run src/app.py
Open
http://localhost:8501in your browser.
The chatbot can answer questions like:
- "What is the average tax owed by corporations in California?"
- "Compare total tax collected across states in 2023."
- "What deductions do individual taxpayers commonly use?"
- "What is the standard deduction for 2024 according to the 1040 instructions?"
- "What does the tax code say about charitable contributions?"
Structured queries (state comparisons, aggregations, trends) are automatically routed to the knowledge graph. Everything else uses semantic vector search over the ingested documents.
# Run all tests
uv run pytest
# Verbose output
uv run pytest -v
# Specific test file
uv run pytest tests/test_ingestion.pyTests use mock embeddings and temporary directories — no API calls or running services required.
Unlicense — public domain.