A natural language interface for banking databases that translates user queries into validated predicate logic objects, ensuring safe database execution without ever generating or executing raw SQL strings.
Important
The Zero Raw SQL Security Guarantee: The LLM never generates or executes raw SQL code. Instead, natural language inputs are parsed into a strictly validated Pydantic PredicateExpression structure. The application layer translates these validated structures into parameterized database queries. This architecture completely eliminates the risk of SQL injection attacks.
The diagram below outlines the end-to-end request lifecycle, from natural language input to safe execution against the Entity-Attribute-Value (EAV) database and response generation:
graph TD
User([User / Client])
UI[Streamlit Demo UI / Terminal CLI]
API[FastAPI Router: /api/v1/chat]
NLP[NLP Parser: LangChain Structured Output]
Exec[Query Executor: Repository Dispatch]
DB[(SQLite EAV Datastore)]
Resp[Response Generator: Natural Language Answer]
User -->|Asks Question| UI
User -->|HTTP API / SSE| API
UI -->|API Calls / SSE Stream| API
API -->|LangGraph Workflow| NLP
subgraph Fallback [LLM Provider Fallback Chain]
Groq[Groq: llama-3.3-70b-versatile]
Gemini[Gemini: gemini-2.0-flash]
Ollama[Ollama: Local llama3.2]
Groq -.->|if unavailable| Gemini
Gemini -.->|if unavailable| Ollama
end
NLP -->|Queries| Fallback
Fallback -->|Returns PredicateExpression| NLP
NLP -->|Passes PredicateExpression| Exec
Exec -->|Safe Parameterized Filter| DB
DB -->|Returns QueryResult Rows| Exec
Exec -->|Passes QueryResult| Resp
Resp -->|Natural Language Answer| User
All domain data (customers, accounts, loans, bank info, interest rates, schema metadata) is stored flexibly using an EAV pattern across three primary tables:
entities: Unique entity instances (customer_id,account_id,loan_id, etc.).attributes: Attribute definitions (balance,interest_rate,swift_code,kyc_status).entity_values: Typed value mappings associating an entity with an attribute value.
- π‘οΈ SQL Injection Protection: Translates natural language strictly into validated Pydantic predicate structures instead of raw SQL code.
- π Multi-Provider LLM Fallback: Automatic Chain-of-Responsibility fallback across Groq, Google Gemini, and local Ollama instances.
- β‘ Real-Time SSE Streaming: Async FastAPI streaming endpoint (
/api/v1/chat/stream) sending live token updates and predicate metadata to clients. - π EAV Schema Introspection: Built-in REST route (
/api/v1/schema) for full dynamic database schema discovery with PII sensitivity flagging. - π¨ Modern Streamlit Demo UI: Dark glassmorphism interface with chat session switching, live execution timing, predicate inspector, and database browser.
- π οΈ Developer Tooling & Automation: Fully managed Makefile automation for installation, seeding, testing, and dev environment launching.
| Layer | Technology | Purpose |
|---|---|---|
| Language | Python >= 3.14 | Core execution runtime |
| API Framework | FastAPI + Uvicorn | High-performance REST APIs + SSE streaming |
| Web Interface | Streamlit | Dark-themed interactive web UI |
| Database | SQLite + aiosqlite | Asynchronous local relational datastore |
| ORM | SQLAlchemy 2.x (async) | Async database session and schema modeling |
| Workflow Engine | LangGraph | Stateful conversational graph orchestration |
| LLM Framework | LangChain | Structured output parsing & provider integrations |
| Validation | Pydantic v2 | Strict schema validation and settings |
| Logging | Structlog | Structured JSON developer logging |
| Package Manager | uv | Lightning-fast Python dependency management |
predicate-sql-chat/
βββ app/
β βββ main.py β FastAPI app entrypoint & lifespan management
β βββ api/
β β βββ v1/routes/
β β βββ chat.py β API routes for chat execution (standard + SSE streaming)
β β βββ chats.py β API routes for chat sessions and message history
β β βββ schema.py β API route for dynamic EAV schema introspection
β βββ core/
β β βββ config.py β App settings loaded from .env via Pydantic
β β βββ exceptions.py β Centralized custom error hierarchy
β β βββ logging.py β Structlog logging setup
β βββ db/
β β βββ base.py β Async SQLAlchemy engine and session factory
β β βββ seed.py β EAV database seeder with sample banking data
β β βββ models/
β β βββ eav.py β Entity, Attribute, and EntityValue ORM models
β β βββ chat_history.py β ChatSession and ChatMessage persistence models
β βββ domain/
β β βββ predicates.py β Pure domain models: PredicateExpression, FilterCondition
β β βββ specifications.py β Specification rules for table and field validation
β βββ infrastructure/
β β βββ llm/
β β β βββ base.py β LLMProvider Protocol interface definition
β β β βββ fallback_chain.py β Chain of Responsibility fallback implementation
β β β βββ groq_provider.py β Groq LLM integration
β β β βββ gemini_provider.py β Gemini LLM integration
β β β βββ ollama_provider.py β Local Ollama LLM integration
β β βββ repositories/
β β βββ base.py β Base repository helper methods
β β βββ chat_history_repository.py β Conversation history persistence
β β βββ eav_repository.py β EAV dataset query execution & schema fetching
β β βββ operator_dispatch.pyβ Dispatch map for execution comparison operators
β βββ schemas/
β β βββ chat.py β API request/response Pydantic models
β βββ application/
β βββ query_executor.py β Validates and executes PredicateExpressions
β βββ use_cases.py β ChatUseCase coordinating execution & persistence
β βββ workflow/
β βββ graph.py β LangGraph state machine configuration
β βββ nodes.py β Workflow node handlers (parse, query, reply)
β βββ state.py β Conversational state dictionary schema
βββ streamlit_app/
β βββ styles/
β β βββ theme.css β Dark glassmorphism stylesheet for Streamlit UI
β βββ api_client.py β API connection client for Streamlit UI
βββ tests/
β βββ unit/ β Unit tests for domain, use cases, and repositories
β βββ integration/ β Integration tests for full API pipelines
βββ chat.py β CLI terminal chat loop wrapper
βββ streamlit_ui.py β Streamlit web interface entry point
βββ pyproject.toml β Project dependencies and configuration
βββ Makefile β Automation targets (install, dev, seed, test)
βββ .env.example β Template environment configuration file
Follow these steps to clone the repository and run the application locally:
- Python 3.14+
- uv package manager (
curl -LsSf https://astral.sh/uv/install.sh | sh) - (Optional) Ollama running locally if using local offline LLM fallback:
ollama pull llama3.2
Clone the repository and install dependencies using uv:
git clone https://github.com/KESHABWI/predicate-sql-chat.git
cd predicate-sql-chat
make installCopy the example environment file to .env:
cp .env.example .envOpen .env and fill in your API keys:
APP_ENV=development
LOG_LEVEL=INFO
DATABASE_URL=sqlite+aiosqlite:///./banking.db
GROQ_API_KEY=your-groq-key-here
GROQ_MODEL=llama-3.3-70b-versatile
GEMINI_API_KEY=your-gemini-key-here
GEMINI_MODEL=gemini-2.0-flash
OLLAMA_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2
LLM_FALLBACK_ORDER=groq,gemini,ollama
LLM_PROVIDER_TIMEOUT=30.0Initialize and seed the SQLite database with mock banking records (customers, accounts, loans, interest rates, branches):
make db-resetLaunch both the FastAPI backend and the Streamlit UI simultaneously:
make devOnce running:
- FastAPI API Documentation: http://localhost:8000/docs
- Streamlit Demo UI: http://localhost:8501
Alternatively, run individual components:
make runβ Launch FastAPI backend server (http://localhost:8000)make uiβ Launch Streamlit UI (http://localhost:8501)make chatβ Launch interactive CLI terminal chat
| Endpoint | Method | Description |
|---|---|---|
/api/v1/chat |
POST |
Process a natural language question and return a structured response with parsed predicates. |
/api/v1/chat/stream |
POST |
Process a question and stream Server-Sent Events (SSE) token by token. |
/api/v1/chats |
GET |
List all active conversation sessions. |
/api/v1/chats/{session_id}/messages |
GET |
Retrieve the chat message history for a given session. |
/api/v1/schema |
GET |
Retrieve database tables, column metadata, and PII sensitivity indicators. |
- Natural Language Question: "Show all savings accounts"
- Parsed Predicate Expression:
PredicateExpression( table="accounts", conditions=[ FilterCondition(field="account_type", operator="eq", value="savings") ], select_fields=["account_number", "current_balance", "account_status"], limit=10 )
- Generated Answer: "You have 10 savings accounts. Account ACC-0001001 has a balance of NPR 580,000.00..."
- Natural Language Question: "Do I have any active mortgage loans?"
- Parsed Predicate Expression:
PredicateExpression( table="loans", conditions=[ FilterCondition(field="loan_type", operator="eq", value="mortgage"), FilterCondition(field="loan_status", operator="eq", value="active") ], select_fields=["loan_reference", "outstanding_balance", "loan_status"], limit=10 )
Every common developer task is accessible via short make targets:
make install # Install dependencies via uv sync
make dev # Run FastAPI backend + Streamlit UI concurrently
make run # Start FastAPI backend server with hot reload
make ui # Start Streamlit web UI
make chat # Start terminal CLI chat interface
make seed # Populate database with mock data
make db-reset # Recreate database tables and re-seed
make test # Run pytest test suite (24 tests)
make test-unit # Run unit tests only
make test-integration # Run integration tests only
make clean # Remove pycache, temp files, and caches
make help # Display Makefile command summaryDistributed under the MIT License. See LICENSE for more information.