A local-first RAG (Retrieval-Augmented Generation) assistant for government documents.
Upload dense policy PDFs, government orders, or circulars β ask questions in plain English, and get cited, page-accurate answers in seconds. No manual Ctrl+F through 200-page documents.
- Problem Statement
β οΈ Deployment Note (Read This First)- Features
- Architecture
- Tech Stack
- Getting Started
- Environment Variables
- API Endpoints
- Project Structure
- Known Limitations
- Roadmap
- License
Government offices, legal teams, and policy researchers deal with hundreds of dense, unstructured PDF documents β circulars, orders, notifications. Finding a single relevant clause today means manually searching page by page, with no way to verify an answer's source at a glance.
GovVault turns that pile of PDFs into a searchable, conversational knowledge base β with every answer traceable back to the exact page it came from.
Only the frontend of this project is publicly deployed.
The backend depends on sentence-transformers, which pulls in a full PyTorch installation. This pushes the deployed image size and RAM footprint well past what free-tier hosting (Render, Railway, etc.) can handle β repeated attempts resulted in out-of-memory crashes during deployment. Upgrading to a paid tier to accommodate this wasn't a viable option for this project.
As a result:
- The live frontend you may find deployed is a UI showcase only β it is not connected to a running backend.
- The full RAG pipeline (PDF upload β local embedding β pgvector search β Groq inference) only runs locally, exactly as described in Getting Started below.
- A video walkthrough of the complete, working pipeline is embedded on the landing page for anyone who wants to see it in action without setting it up themselves.
To actually run and test the full project β backend included β you must fork or clone this repository and run it locally using the setup instructions below. There is currently no hosted, end-to-end working version.
- π PDF Upload & Parsing β Text-selectable PDFs are parsed page-by-page using PyMuPDF
- π§ Local Embeddings β Documents are vectorized on-device with SentenceTransformers (
paraphrase-MiniLM-L3-v2, 384 dimensions) β zero embedding API cost - π Vector Search β Postgres +
pgvectorextension for cosine-similarity retrieval, capped at top-5 chunks with a relevance threshold - β‘ Fast Inference β Final answer generation via Groq (
openai/gpt-oss-20b) - π Page-Level Citations β Every answer links back to the exact source page; the in-app PDF viewer jumps there automatically
- ποΈ Multi-Session Chat β Collapsible sidebar with independent chat sessions, each scoped to its own uploaded documents (100% session isolation)
- βοΈ Async Processing β PDF vectorization runs as a background Celery task, so large uploads don't block the request thread
- π¨ ChatGPT-Style UI β React + Tailwind, with
react-markdownrendering for formatted AI responses
βββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββ
β React βββββββΆβ Django + DRF βββββββΆβ PostgreSQL β
β (Vite SPA) ββββββββ REST API ββββββββ + pgvector β
βββββββββββββββ ββββββββββ¬ββββββββββ ββββββββββββββββββ
β
ββββββββββββ΄βββββββββββ
β β
βββββββΌβββββββ βββββββββΌβββββββββ
β Celery β β Groq API β
β + Redis β β (LLM inference) β
β (async β ββββββββββββββββββ
β PDF jobs) β
βββββββ¬βββββββ
β
ββββββββΌββββββββ
β SentenceTransformers β
β (local embeddings) β
ββββββββββββββββ
Flow:
- User uploads a PDF β Django saves it, kicks off a Celery task, returns immediately
- Celery worker extracts text (PyMuPDF) β embeds each page locally β stores vectors in Postgres via pgvector
- Frontend polls a status endpoint until processing completes
- User asks a question β query is embedded the same way β cosine similarity search retrieves top-5 relevant chunks
- Chunks + question are sent to Groq β answer streams back with a link to the source page
| Layer | Technology |
|---|---|
| Frontend | React (Vite), Tailwind CSS v4, Axios, React Router, react-markdown |
| Backend | Django, Django REST Framework |
| Database | PostgreSQL + pgvector |
| Task Queue | Celery + Redis |
| Embeddings | SentenceTransformers (paraphrase-MiniLM-L3-v2, 384-dim) |
| LLM Inference | Groq API (openai/gpt-oss-20b) |
| PDF Parsing | PyMuPDF (fitz) |
| Containerization | Docker (Postgres + Redis) |
- Python 3.11+
- Node.js 18+
- Docker & Docker Compose
- A Groq API key (free tier works)
cd backend
# Create and activate a virtual environment
python -m venv .venv
.venv\Scripts\activate # Windows
source .venv/bin/activate # macOS/Linux
# Install dependencies
pip install -r requirements.txt
# Start Postgres + Redis containers
docker-compose up -d
# Run migrations
python manage.py makemigrations
python manage.py migrate
# Create a .env file (see Environment Variables section below)cd frontend
# Install dependencies
npm install
# Create a .env file
echo "VITE_API_URL=http://127.0.0.1:8000/api" > .envYou'll need three terminals running simultaneously:
# Terminal 1 β Docker containers (from backend/)
docker-compose up -d
# Terminal 2 β Celery worker (from backend/, with venv active)
celery -A core worker --loglevel=info --pool=solo
# Terminal 3 β Django server (from backend/, with venv active)
python manage.py runserver# Terminal 4 β Frontend (from frontend/)
npm run devVisit http://localhost:5173.
Note:
--pool=solois required for Celery on Windows. On macOS/Linux you can omit it and use the default prefork pool.
backend/.env
DEBUG=True
DATABASE_URL=postgres://admin:adminpassword@localhost:5432/govvault_db
GROQ_API_KEY=your_groq_api_key_here
CELERY_BROKER_URL=redis://localhost:6379/0frontend/.env
VITE_API_URL=http://127.0.0.1:8000/api| Method | Endpoint | Description |
|---|---|---|
POST |
/api/documents/upload/ |
Upload a PDF, triggers async vectorization |
GET |
/api/documents/<id>/status/ |
Poll processing status (pending / processing / completed / failed) |
POST |
/api/chat/ |
Ask a question, scoped to document_ids |
GovVault/
βββ backend/
β βββ core/ # Django project settings, Celery config
β βββ knowledge_base/ # Main app β models, views, services, tasks
β β βββ models.py # Document, DocumentChunk
β β βββ views.py # Upload, Status, Chatbot views
β β βββ services.py # PDF parsing + embedding logic
β β βββ tasks.py # Celery async task
β βββ docker-compose.yml # Postgres (pgvector) + Redis
βββ frontend/
βββ src/
βββ components/
β βββ layouts/ # Navbar
β βββ sections/ # Hero, Features, HowItWorks, TechStack, Footer, VideoShowcase
β βββ rag-demo/ # RagDemoSection β main chat UI
βββ pages/ # LandingPage, ChatPage
- Scanned/image-based PDFs are not supported β PyMuPDF only extracts text from text-selectable PDFs. OCR is not currently implemented.
- No authentication layer β this is a demo/showcase project, not production-hardened.
- Backend is local-only β see the Deployment Note above.
- OCR support for scanned documents
- User authentication and per-user document libraries
- Lighter-weight embedding model to make cloud deployment feasible
- Streaming LLM responses token-by-token instead of waiting for the full completion
This project was built as a hackathon/showcase project. Feel free to fork, learn from, or build on it.
- Groq for fast LLM inference
- pgvector for making Postgres a viable vector store
- SentenceTransformers for local, cost-free embeddings
