A privacy-first Retrieval-Augmented Generation (RAG) system that runs entirely on your local machine. Upload documents and ask questionsโget AI-powered answers with source attribution.A local Retrieval-Augmented Generation (RAG) system built using:
Built with:- ๐ง Ollama for text generation and embeddings
-
๐ง Ollama - Local LLM for generation & embeddings - ๐พ Qdrant as a local vector database
-
๐พ Qdrant - Vector database for semantic search - ๐จ Streamlit for a simple and interactive web UI
-
๐จ Streamlit - Interactive web interface
This project runs 100% offline โ no external API calls โ perfect for privacy-preserving AI assistants and local knowledge bases.
100% offline โ No cloud APIs, no data leaves your machine.
โ Upload and process PDF or TXT documents
-
๐ Document Processing - Upload PDF and TXT filesโ Split documents into text chunks
-
๐ Smart Chunking - Overlapping chunks for better context preservationโ Generate embeddings locally using
mxbai-embed-large -
๐ฏ Semantic Search - Vector similarity search with Qdrantโ Store and search vectors using Qdrant
-
๐ค Local LLM - Powered by Ollama (llama3.2)โ Answer questions contextually using
llama3.2 -
โก Streaming Responses - Real-time answer generationโ Simple Streamlit web interface
-
๐ Source Attribution - See which document chunks were used with similarity scoresโ Optional multi-file upload and database reset
-
๐ Enhanced Metadata - Track source files, timestamps, chunk indices
-
๐๏ธ Database Management - Clear and reset your vector database---
-
๐ณ Docker Support - One-command deployment with docker-compose
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Streamlit Web Interface โ
โ (Upload, Query, Display Results) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ Document โ โ Embedding โ โ Vector Store โ
โ Processor โ โ Service โ โ (Qdrant) โ
โ (PyPDF2) โ โ (Ollama) โ โ โ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโ
โ Generation โ
โ (Ollama) โ
โ llama3.2 โ
โโโโโโโโโโโโโโโโ
local-rag/
โโโ server/
โ โโโ app.py # Main Streamlit application
โ โโโ config.py # Configuration management (.env support)
โ โโโ embedding.py # Ollama embedding functions
โ โโโ vectorstore.py # Qdrant vector operations
โ โโโ document_processor.py # PDF/TXT processing & chunking
โ โโโ requirements.txt # Python dependencies
โ โโโ .env # Environment variables (you create this)
โ โโโ .env.example # Example environment configuration
โโโ docker-compose.yml # Docker orchestration
โโโ README.md # This file
Prerequisites: Docker and Docker Compose installed
-
Clone the repository
git clone https://github.com/NimanthaSupun/local-RAG-Application.git cd local-rag -
Create
.envfile (optional - uses defaults if omitted)cp server/.env.example server/.env # Edit server/.env to customize settings -
Start everything with Docker Compose
docker-compose up
-
Open your browser
http://localhost:8501
That's it! Ollama, Qdrant, and the Streamlit app will all start automatically.
Prerequisites:
ollama pull mxbai-embed-large
ollama pull llama3.2docker run -p 6333:6333 -p 6334:6334 -v ${PWD}/qdrant_storage:/qdrant/storage:z qdrant/qdrantOr use Qdrant Cloud/native installation.
cd server
python -m venv venv
venv\Scripts\Activate.ps1
pip install -r requirements.txtCreate server/.env file (or copy from .env.example):
OLLAMA_URL=http://localhost:11434
QDRANT_URL=http://localhost:6333
QDRANT_COLLECTION=docs
EMBED_MODEL=mxbai-embed-large
GEN_MODEL=llama3.2
EMBED_DIM=1024
CHUNK_SIZE=500
CHUNK_OVERLAP=50
TOP_K=3streamlit run app.pyOpen your browser to http://localhost:8501
- Click "Browse files" in the sidebar
- Select one or more PDF or TXT files
- Wait for processing (you'll see chunk count)
- Type your question in the text input
- Click "Ask" button
- View the AI-generated answer with streaming effect
- See source chunks with similarity scores
- Click "๐๏ธ Clear Qdrant Data" to reset the database
- Useful when starting a new project or removing old documents
All configuration is managed via environment variables in server/.env:
| Variable | Default | Description |
|---|---|---|
OLLAMA_URL |
http://localhost:11434 |
Ollama API endpoint |
QDRANT_URL |
http://localhost:6333 |
Qdrant API endpoint |
QDRANT_COLLECTION |
docs |
Collection name in Qdrant |
EMBED_MODEL |
mxbai-embed-large |
Embedding model name (Ollama) |
GEN_MODEL |
llama3.2 |
Generation model name (Ollama) |
EMBED_DIM |
1024 |
Embedding vector dimension |
CHUNK_SIZE |
500 |
Characters per chunk |
CHUNK_OVERLAP |
50 |
Overlap between chunks |
TOP_K |
3 |
Number of chunks to retrieve |
The docker-compose.yml includes three services:
- Ollama - LLM service with GPU support (optional)
- Qdrant - Vector database
- Streamlit App - Web interface
If you have an NVIDIA GPU, uncomment the GPU sections in docker-compose.yml:
# Uncomment for GPU support
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]Edit docker-compose.yml to change default ports:
- Streamlit:
8501 - Qdrant:
6333,6334 - Ollama:
11434
The system uses overlapping chunks to preserve context across boundaries:
# Example: 500 char chunks with 50 char overlap
"...end of chunk 1 overlap..."
"...overlap start of chunk 2..."This ensures important information isn't split awkwardly.
Each vector stores rich metadata:
{
"text": "chunk content...",
"source_file": "document.pdf",
"chunk_index": 0,
"total_chunks": 15,
"upload_timestamp": "2025-11-04T10:30:00",
"file_type": "application/pdf"
}Use this to:
- Filter results by source file
- Show document names in UI
- Debug chunking issues
- Track upload history
Answers are streamed token-by-token for a better user experience (like ChatGPT).
Error: Cannot connect to Ollama
Solution:
- Check Ollama is running:
ollama list - Start Ollama service:
ollama serve - Verify URL in
.envmatches your Ollama endpoint
Error: Cannot connect to Qdrant
Solution:
- Check Qdrant is running:
docker ps(if using Docker) - Test connection:
curl http://localhost:6333 - Verify URL in
.env
Error: Model 'llama3.2' not found
Solution:
ollama pull llama3.2
ollama pull mxbai-embed-largeIf you run out of memory:
- Use a smaller model (e.g.,
llama3.2:1b) - Reduce
CHUNK_SIZEandTOP_K - Process fewer documents at once
Error: WinError 10013 or port 8501 in use
Solution:
# Find process using port 8501
netstat -ano | findstr :8501
# Kill the process (replace <PID> with actual PID)
taskkill /PID <PID> /F
# Or use a different port
streamlit run app.py --server.port 8502The codebase is modular for easy maintenance:
config.py- Centralized configuration with environment variable loadingembedding.py- Ollama embedding generationvectorstore.py- Qdrant client and vector operationsdocument_processor.py- File reading, text extraction, chunkingapp.py- Streamlit UI and orchestration
- Custom Chunking Strategy - Edit
document_processor.py - Different Embedding Models - Change
EMBED_MODELin.env - Alternative LLMs - Change
GEN_MODELin.env - New Document Types - Add parsers to
document_processor.py
Run health checks:
from config import check_services
check_services() # Verifies Ollama and Qdrant connectivity- Use GPU - Enable GPU support in docker-compose for faster inference
- Adjust Chunk Size - Larger chunks = more context but slower search
- Tune TOP_K - More chunks = better context but slower generation
- Model Selection - Smaller models are faster but less capable
- Batch Processing - Upload multiple documents at once
Contributions welcome! Ideas:
- Support for more file types (DOCX, HTML, Markdown)
- Hybrid search (vector + keyword/BM25)
- Multi-language support
- Query history and session management
- Re-ranking with cross-encoder models
- Export chat history
- API endpoints for programmatic access
- Ollama - Easy local LLM deployment
- Qdrant - High-performance vector search
- Streamlit - Rapid UI development
- PyPDF2 - PDF text extraction