Spaces:
Sleeping
A newer version of the Gradio SDK is available: 6.20.0
title: Document RAG GPT
emoji: π
colorFrom: indigo
colorTo: purple
sdk: gradio
sdk_version: 6.16.0
app_file: app.py
pinned: false
license: mit
π RAG Document Chat
A Retrieval-Augmented Generation (RAG) chat application. Ask questions answered strictly from document content, with guardrails against prompt injection and out-of-scope queries. The app ships preloaded with the Constitution of India so it works immediately, and you can also upload your own PDF, DOCX, or TXT files.
Built-in dataset
On startup the app indexes a small corpus (in data/):
Fundamental-Rights.pdfβ Part III, Articles 12β35Directive-Principles.docxβ Part IV, Articles 36β51Preamble-and-Fundamental-Duties.txtβ Preamble and Article 51A
This exercises all three file loaders (PDF, DOCX, TXT). The bare text of the
Constitution is freely reproducible in India (Copyright Act, 1957, s. 52); it was
compiled from public sources via build_corpus.py and is provided for
demonstration (see indiacode.nic.in for the authoritative current text).
Sample questions: "What does Article 21 protect?", "What is the right against exploitation?", "List the Fundamental Duties", "What does the Preamble say?". An out-of-scope question like "What's the weather today?" is correctly refused.
Document scope (by design)
The assistant answers from one document set at a time:
- Default: the built-in Constitution of India corpus described above.
- After upload: once you upload and process your own files, the system uses only those documents for the rest of the session; the built-in corpus is no longer searched.
This single-source behaviour is an intentional design choice β when a user brings their own documents, answers should be grounded solely in those documents, with no blending from an unrelated default corpus. Starting a new session (or restarting the Space) reverts to the built-in corpus.
Features
- Multi-format upload β PDF, DOCX (paragraphs + tables), and TXT.
- RAG pipeline β chunking β embeddings β vector search β grounded generation.
- Guardrails
- Input validation (empty / too-short / too-long).
- Direct prompt-injection detection on the user's query.
- Indirect prompt-injection defence: retrieved text is passed to the model as clearly delimited, untrusted data that it is instructed never to obey.
- Out-of-scope handling: if retrieval similarity is below a threshold, the app answers "I couldn't find that in the uploaded documents" without calling the LLM.
- Session isolation β each user's index lives in their own session state.
- Provider-agnostic LLM β Groq (default, free tier), OpenAI, or Gemini, all via the OpenAI-compatible API.
- Conversation memory β the last few turns are sent to the model, so follow-up questions that refer back are understood in the context of the conversation.
How it works
- Load documents and extract text (
pypdf,python-docx). - Chunk text into ~900-character, paragraph-aware pieces with overlap.
- Embed chunks with
all-MiniLM-L6-v2(Sentence-Transformers), normalized. - Store vectors in an in-memory FAISS index (
IndexFlatIP= cosine similarity). - Answer: validate β injection check β retrieve top-k β scope check β generate a grounded answer from the retrieved excerpts only.
Project structure
app.py # Gradio UI + orchestration (loads built-in corpus at startup)
build_corpus.py # (dev) regenerates the data/ files from public sources
data/ # built-in corpus: Constitution of India (PDF, DOCX, TXT)
rag/
document_loader.py # PDF / DOCX / TXT extraction + validation
chunker.py # paragraph-aware chunking with overlap
embeddings.py # Sentence-Transformers wrapper (lazy singleton)
vector_store.py # FAISS in-memory store
llm.py # OpenAI-compatible client (Groq/OpenAI/Gemini)
guardrails.py # input validation + injection detection
pipeline.py # build_index() and answer()
requirements.txt
.env.example
Local setup
git clone <your-repo-url>
cd rag-document-chat
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # then edit .env and add your API key
python app.py # opens at http://127.0.0.1:7860
Getting a free API key (Groq)
Create one at https://console.groq.com/keys (free tier, no credit card), then set
GROQ_API_KEY in .env. To use a different provider, set LLM_PROVIDER to
openai or gemini and provide the matching key.
Environment variables
| Variable | Default | Description |
|---|---|---|
LLM_PROVIDER |
groq |
groq, openai, or gemini |
GROQ_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY |
β | key for the chosen provider |
LLM_MODEL |
provider default | override the model name |
EMBEDDING_MODEL |
sentence-transformers/all-MiniLM-L6-v2 |
embedding model |
RELEVANCE_THRESHOLD |
0.25 |
min cosine score to treat a match as in-scope |
Deploy to Hugging Face Spaces
- Create a new Space at https://huggingface.co/new-space β choose Gradio as the SDK.
- Push this repository to the Space (or upload the files). The included README
front matter sets
sdk: gradioandapp_file: app.py. If the build reports the SDK version is unavailable, changesdk_versionto the latest 6.x shown in the Space settings and updategradio==inrequirements.txtto match. - In Settings β Variables and secrets, add a secret named
GROQ_API_KEY(andLLM_PROVIDERif not using Groq). - The Space builds automatically and serves the app.
Notes & limitations
- The index is in memory and resets when the Space restarts or the session ends.
- Scanned/image-only PDFs yield no text (no OCR); the app reports this clearly.
- The injection filter uses high-signal heuristics; the model-side instruction is the primary defence against instructions hidden inside documents.
- Conversation memory is applied at the generation step only: recent turns help the model interpret a follow-up, but retrieval still embeds the raw question. For follow-ups whose meaning depends entirely on earlier turns, conversational query rewriting β rephrasing the follow-up into a standalone question before retrieval β would be the more robust approach.