Ask questions about your PDF using Retrieval-Augmented Generation (RAG)
An academic AI project: upload a PDF, and the app indexes it into a vector database, then answers your questions strictly from the document's content using Google's Gemini API β with sources shown for every answer.
Large language models (LLMs) are powerful, but they hallucinate and their knowledge is frozen at training time. This project builds a complete Retrieval-Augmented Generation (RAG) pipeline that solves both problems: before the model answers, the app retrieves the most relevant passages of your document and gives them to the model as context. The result is an answer grounded in the document, with visible sources.
The application is built with Streamlit, processes PDFs with PyPDF, chunks text with a simple custom splitter, embeds chunks locally with sentence-transformers, stores vectors in ChromaDB, and generates answers with Google's Gemini API.
- Users need accurate answers about the contents of their own documents (manuals, research papers, lecture notes, reports).
- General-purpose chatbots cannot see these private documents and may fabricate answers.
- There is a need for a simple, verifiable Q&A system over uploaded PDFs.
- Accept a PDF upload and extract its text page by page.
- Chunk the text and embed each chunk into a vector space.
- Store the vectors in a persistent local vector database (ChromaDB).
- Retrieve the most relevant chunks for a user's question (semantic search).
- Generate an answer with Gemini using only the retrieved context.
- Display the answer together with sources (page numbers + retrieved chunks).
- Handle errors gracefully and keep the code simple enough to explain.
- π PDF upload (PDF-only, validated)
- π Semantic search over the document (cosine similarity)
- π¬ Chat interface with session-based history
- π Sources for every answer + expandable retrieved context
- βοΈ Configurable number of retrieved chunks (K = 3β8)
- π§Ή Friendly error handling (missing key, invalid PDF, scanned PDF, empty question, API failures, ...)
- π§ͺ Offline unit tests (no API key required)
- π³ Docker support
PDF Upload β Text Extraction (pypdf) β Cleaning β Chunking
β Embeddings (all-MiniLM-L6-v2) β ChromaDB Vector Storage
β User Question β Question Embedding β Similarity Search
β Top K Chunks β Prompt Construction β Gemini LLM
β Answer + Sources
Two phases:
- Ingestion (offline): process the PDF, embed the chunks, store them.
- Question answering (online): embed the question, retrieve top-K chunks, build a grounded prompt, generate the answer, show sources.
| Layer | Technology |
|---|---|
| UI | Streamlit |
| PDF processing | PyPDF (pypdf) |
| Text chunking | Custom recursive splitter (simple) |
| Embeddings | sentence-transformers / all-MiniLM-L6-v2 (384-dim, local) |
| Vector database | ChromaDB (persistent, local) |
| LLM | Google Gemini (google-genai SDK) |
| Config / secrets | python-dotenv + .env |
| Language | Python 3.10+ |
RAG-model/
β
βββ app.py # Streamlit UI (entry point)
βββ src/
β βββ __init__.py
β βββ config.py # All settings from env vars
β βββ pdf_processor.py # PDF extraction, cleaning, chunking
β βββ embeddings.py # SentenceTransformer wrapper
β βββ vector_store.py # ChromaDB operations
β βββ llm.py # Gemini client + friendly errors
β βββ rag_pipeline.py # Retrieval + prompt + answer generation
βββ data/
β βββ .gitkeep
β βββ sample_document.pdf # Sample PDF for the demo
βββ chroma_db/ # Vector DB storage (gitignored)
βββ reports/
β βββ RAG_Research_Report.md # Part 1 report
β βββ Problem_Solving_Answers.md # Part 3 answers
βββ screenshots/README.md # Which screenshots to take
βββ tests/
β βββ __init__.py
β βββ utils.py # PDF generator + fake models
β βββ test_pdf_processor.py # 10 tests
β βββ test_rag_components.py # 11 tests
βββ .env.example
βββ .gitignore
βββ requirements.txt
βββ Dockerfile
βββ demo_script.md # 3β5 minute demo script
Requirements: Python 3.10+ and pip.
# 1. Clone or copy the project, then enter the folder
cd RAG-model
# 2. Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# 3. Install dependencies
pip install -r requirements.txt
β οΈ Note for the original development Mac: this project folder was originally inside an iCloud-synced Desktop, and iCloud kept corrupting the venv and evicting source files. On that machine the project was moved to~/RAG-model(outside iCloud) and a pre-built venv exists at~/rag-model-venv. On any normal computer the standard steps above work perfectly.
- Get a free Gemini API key: https://aistudio.google.com/apikey
- Copy the template and fill it in:
cp .env.example .envGEMINI_API_KEY=your_real_key_here
GEMINI_MODEL=gemini-3.7-flash- The key is never hardcoded β it is read from the environment.
.envis in.gitignore, so it is never committed.GEMINI_MODELis configurable;gemini-3.7-flashis the current stable Flash model (2.5 Flash still works but is being deprecated).
streamlit run app.pyOpen http://localhost:8501, then:
- Upload
data/sample_document.pdf(or any text PDF). - Click βοΈ Process Document.
- Ask a question, e.g. "What should cats eat?"
- Read the answer + Sources + "View retrieved context".
- Upload β the PDF bytes are read.
- Extract β
pypdfreads text page by page; whitespace is cleaned. - Chunk β text is split into ~500-character chunks with overlap; each chunk remembers its page number.
- Embed β
all-MiniLM-L6-v2converts every chunk into a 384-dimensional vector (semantically similar texts β similar vectors). - Store β vectors + metadata (source, page, chunk id) go into a fresh ChromaDB collection (old documents never mix with new ones).
- Ask β the question is embedded with the same model.
- Retrieve β ChromaDB returns the K most similar chunks.
- Prompt β a system instruction ("answer only from the context, never invent facts") + the retrieved chunks + the question are combined.
- Generate β Gemini answers with
temperature=0.2(factual). - Show β answer + page sources + expandable retrieved context.
User: What should cats eat?
Assistant: According to the document (Page 2), cats need protein-rich
food to stay healthy. Provide fresh water every day, and feed
adult cats twice a day following the portions on the package.
Sources: Page 2
[View retrieved context βΈ]
If the document does not contain the answer, the app responds: "I couldn't find this information in the uploaded document."
See screenshots/README.md for the exact list.
Save your own screenshots into the screenshots/ folder.
| Situation | Behaviour |
|---|---|
| Missing Gemini API key | Friendly message with setup instructions |
| Invalid / corrupted PDF | Friendly "not a valid PDF" message |
| Empty PDF | Friendly "empty file" message |
| Scanned / image-only PDF | "No text could be extracted ... OCR not supported" |
| Extraction failure | Friendly message; details logged |
| Gemini API / rate limit / quota | Friendly retry message; details logged |
| Embedding model load failure | Friendly message with troubleshooting hints |
| ChromaDB failure | Friendly message |
| Empty question | Warning "Please type a question first." |
| Question before upload/processing | Chat input is disabled |
Errors are logged (for developers) and shown as friendly st.error messages
to users β no raw tracebacks.
- Scanned PDFs need OCR (not included).
- Retrieval quality depends on the chunking and the embedding model.
- Requires an internet connection + Gemini API key for answers.
- Embedding model downloads on first use (a few tens of MB).
- OCR support for scanned PDFs (e.g. Tesseract).
- Hybrid search (BM25 + embeddings) and re-ranking.
- Multiple document uploads with per-document collections.
- Chat history persisted to disk (e.g. SQLite) instead of session-only.
- Model selection dropdown (Gemini models, temperature).
Option A β Docker (local or any server):
docker build -t rag-qa .
docker run -p 8501:8501 -e GEMINI_API_KEY=your_key_here rag-qa
# open http://localhost:8501Option B β Streamlit Community Cloud (free):
- Push the project to GitHub (add your
.envvalues as Secrets in the Streamlit Cloud dashboard instead of committing them). - Import the repository at https://streamlit.io/cloud.
- Set the secret
GEMINI_API_KEYin Settings β Secrets. - Deploy β the app is served automatically.
TODO: Student must complete this step β add your live deployment URL here:
Live deployment URL: [Add your deployment link here]
git init
git add .
git commit -m "AI Document Q&A (RAG) β Intelligent Document Q&A Assistant"
git branch -M main
git remote add origin https://github.com/<your-username>/<your-repo>.git
git push -u origin mainGitHub Repository: [Add your repository link here]
TODO: Student must complete this step.
See demo_script.md β a 3β5 minute spoken script covering
introduction, the problem, the stack, upload, processing, asking, sources,
chat history, the RAG architecture, error handling, and conclusion.
Run the unit tests (fully offline β no API key needed):
python -m pytest tests/ -vAll 21 tests pass. They cover PDF extraction, empty/invalid/scanned PDF handling, chunk creation, overlap, embedding generation, vector store creation/search, collection isolation, prompt building, and the full pipeline with mocked LLM calls.
| Field | Value |
|---|---|
| Name | TODO: Student must complete this step. |
| College | TODO: Student must complete this step. |
| Roll No. | TODO: Student must complete this step. |
| Course | TODO: Student must complete this step. |
| Submission | TODO: Student must complete this step. |
Built with Streamlit, PyPDF, sentence-transformers, ChromaDB, and Google Gemini. Part of an academic assignment on Retrieval-Augmented Generation.