DocuChat is a fully local Retrieval-Augmented Generation (RAG) app that lets you chat with your own PDF documents. It chunks and embeds your files with sentence-transformers, stores the vectors in a local ChromaDB collection, retrieves the most relevant chunks for a given question, and passes them as context to a locally-running llama3.2:3b model via Ollama — so your documents and questions never leave your machine. A Streamlit UI talks to a FastAPI backend that wraps the whole retrieval + generation pipeline behind a single /chat endpoint.
Your PDFs shouldn't have to leave your laptop just to get asked a question. DocuChat runs the entire RAG pipeline — embeddings, vector search, and generation — on your own machine. Drop some PDFs in a folder, index them, and start asking. Zero third-party API calls, zero data leaving your machine.
| 🔒 Fully local | Embeddings, vector storage, and LLM inference all run on your machine; nothing is sent to a third-party API. |
| 📥 PDF ingestion | ingest.py reads every .pdf in data/, splits the extracted text into overlapping chunks (1200 chars, 150-char overlap), and embeds them with the all-MiniLM-L6-v2 sentence-transformer model. |
| 🗃️ Persistent vector store | Chunks and embeddings are stored in a local, persistent ChromaDB collection (chroma_db/), so you only need to re-run ingestion when your documents change. |
| 🎯 Source-grounded answers | rag.py retrieves the top-5 most similar chunks for a question and prompts the LLM to answer using only that context, citing the source filename in brackets. |
| ⚡ FastAPI backend | A minimal POST /chat endpoint (app.py) wraps the retrieval + generation pipeline. |
| 💬 Streamlit chat UI | ui.py provides a simple browser chat interface backed by the FastAPI API. |
| 🖥️ CLI mode | Run python3 rag.py for a REPL-style loop that answers questions directly in the terminal, no API/UI needed. |
| 🐳 Docker support | Dockerfile and docker-compose.yml build and run the FastAPI service in a container, persisting chroma_db/ via a bind-mounted volume and reaching the host's Ollama server through host.docker.internal. |
📸 More screenshots
CLI mode (python3 rag.py), answering a question grounded in an ingested PDF, with retrieval done in under a second:
Pipeline architecture:
- Backend: FastAPI
- UI: Streamlit
- Vector store: ChromaDB (persistent, local)
- Embeddings:
sentence-transformers(all-MiniLM-L6-v2) - LLM:
llama3.2:3bserved locally via Ollama - Containerization: Docker + Docker Compose
The flow, end to end:
ingest.pyreads PDFs fromdata/, splits them into overlapping text chunks, embeds them withall-MiniLM-L6-v2, and stores them in a persistent ChromaDB collection (chroma_db/).rag.pyembeds the incoming question, retrieves the top-5 most similar chunks from ChromaDB, and builds a prompt that instructs the model to answer using only that context (with source citations).app.pyexposes this as a FastAPIPOST /chatendpoint.ui.pyis a Streamlit chat interface that calls the FastAPI backend and renders the conversation.- The actual text generation happens through a local Ollama server running
llama3.2:3b.
- Python 3.13 (matches the version used in
Dockerfile; other recent 3.x versions will likely work too). - Ollama installed and running locally, with the
llama3.2:3bmodel pulled (see setup below).rag.pyandchat_test.pytalk to Ollama's/api/chatendpoint onlocalhost:11434; when running the API in Docker, it's reached athost.docker.internal:11434instead. - Enough disk space/RAM to run
llama3.2:3band to download theall-MiniLM-L6-v2embedding model (fetched automatically bysentence-transformerson first run).
# 1. Clone the repo
git clone https://github.com/destivano/docuchat.git
cd docuchat
# 2. Create a virtual environment and install dependencies
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# 3. Pull the local LLM
ollama pull llama3.2:3b
# 4. Add your PDFs to data/, then build the vector index
python3 ingest.py
# 5. Run the API
fastapi run app.py --port 8000
# or with Docker: docker compose up --build
# 6. In a separate terminal, run the UI
streamlit run ui.pyOpen the Streamlit URL printed in the terminal (usually http://localhost:8501) and start asking questions about your documents.
You can skip FastAPI and Streamlit entirely and just chat from the terminal once the vector index has been built:
python3 rag.pyThis starts a simple REPL: type a question at the Ask: prompt and it prints the model's answer.
.
├── app.py # FastAPI app exposing POST /chat
├── ingest.py # Reads PDFs from data/, chunks + embeds them, writes to ChromaDB
├── rag.py # Embeds a question, retrieves context from ChromaDB, queries Ollama, and offers a CLI REPL
├── ui.py # Streamlit chat UI that calls the FastAPI /chat endpoint
├── chat_test.py # Standalone example of streaming a chat request to Ollama
├── embed_test.py # Standalone example of embedding a sentence with sentence-transformers
├── Dockerfile # Builds the FastAPI service (python:3.13-slim base)
├── docker-compose.yml # Runs the API container, mounting chroma_db/ and reaching host Ollama
├── requirements.txt # Pinned Python dependencies
├── data/ # Put your source PDFs here (created by you, git-ignored)
└── chroma_db/ # Persistent ChromaDB store (created by ingest.py, git-ignored)
data/andchroma_db/are git-ignored — you need to createdata/yourself and populate it with PDFs before runningingest.py.- The embedding model and Ollama model are currently hard-coded (
all-MiniLM-L6-v2andllama3.2:3brespectively); there are no environment variables or config files to change them — editingest.py/rag.pydirectly if you want a different model. chat_test.pyandembed_test.pyare small standalone scripts used to sanity-check the Ollama chat endpoint and the embedding model in isolation; they aren't part of the app's runtime path.
This project is licensed under the MIT License.


