A lightweight, single-user Retrieval-Augmented Generation (RAG) chatbot. Upload a PDF or text document and ask questions about it — answers are generated using only the content of the uploaded file, with a WhatsApp-style chat interface built in Streamlit.
- Upload PDF or TXT documents directly from the browser
- Automatic chunking of documents for better retrieval accuracy
- Semantic search powered by ChromaDB (vector similarity, not keyword matching)
- Answers generated by Google Gemini, grounded strictly in the uploaded document
- Custom chat UI with left/right message bubbles and an animated "typing" indicator
- Expandable "View sources" section showing which chunks the answer came from
- Persisted vector store — re-uploading the same document skips re-embedding
| Layer | Tool |
|---|---|
| UI | Streamlit |
| Orchestration | LangChain |
| LLM | Google Gemini (gemini-flash-latest) |
| Embeddings | Google Generative AI Embeddings |
| Vector Store | ChromaDB (local, persisted to disk) |
| Document Loading | PyPDFLoader, TextLoader |
personal-rag-bot/
├── app.py # Streamlit UI entry point
├── config/
│ └── settings.py # Paths, chunk size/overlap, constants
├── ingestion/
│ ├── loaders.py # Loads PDF/TXT into LangChain Documents
│ └── chunking.py # Splits documents into overlapping chunks
├── embedding/
│ └── factory.py # Embeddings model factory (Google GenAI)
├── retrieval/
│ └── base.py # Builds/loads Chroma vectorstore + retriever
├── chains/
│ ├── prompts.py # RAG prompt template
│ └── rag_chain.py # RetrievalQA chain (LLM + retriever)
├── ui/
│ └── state.py # Streamlit session_state initialization
├── data/
│ ├── tmp/ # Uploaded files land here
│ └── vector_stores/ # Persisted Chroma DBs (per document)
└── requirements.txt
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # macOS/Linuxpip install -r requirements.txtCreate a .env file in the project root:
GOOGLE_API_KEY=your_api_key_here
Get a free key from Google AI Studio.
streamlit run app.pyThis opens the app in your browser at http://localhost:8501.
- Upload a
.pdfor.txtfile using the uploader. - Wait for the "ready — ask away!" confirmation (this step embeds the document — only happens once per file).
- Type a question in the chat box.
- The assistant answers using only the content of your document, with sources available via the expander below each reply.
Upload → Load → Chunk → Embed → Store (Chroma) → Retrieve (top-k similar chunks) → LLM generates answer
- Load: The document is parsed into LangChain
Documentobjects (page_content+metadata). - Chunk: Long documents are split into overlapping segments (
CHUNK_SIZE/CHUNK_OVERLAPinconfig/settings.py) so retrieval stays precise. - Embed: Each chunk is converted into a vector using Google's embedding model.
- Store: Vectors + text + metadata are saved in a local ChromaDB instance, persisted to
data/vector_stores/<filename>/. - Retrieve: On each question, the query is embedded and compared against stored vectors to find the most relevant chunks.
- Generate: Retrieved chunks are inserted into a prompt template and sent to Gemini, which answers using only that context.
- No authentication or multi-user support — everything runs against one local vector store at a time.
- Re-uploading a file with the same name reuses the existing vectorstore rather than detecting content changes — delete the corresponding folder in
data/vector_stores/to force re-embedding. - Subject to Gemini's free-tier rate limits (RPM/RPD) — occasional
503/429errors under heavy use are expected and not a bug. - Single-turn Q&A — no conversational memory across questions yet.
- Add conversational memory (multi-turn context)
- Support more file types (
.docx,.csv,.md) - Add a "clear document" / "delete vectorstore" button in the UI
- Content-hash based deduplication for re-uploads
- Swap in a local embedding/LLM model (e.g. via Ollama) for a fully offline version