Intelligent Document Understanding with RAG (Retrieval-Augmented Generation)
Upload any document β’ Chat with your files β’ Get accurate, context-aware answers
Retrieval-Augmented Generation (RAG) bridges the gap between what AI models know and what your documents contain.
Think of a large language model like a brilliant scholar locked inside a vast library that closed five years ago. It remembers every page but hasn't read a single new book since. RAG hands that scholar a new ability β to walk out, fetch the latest data, and respond with current, evidence-backed information.
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
β QUERY β βββΆ β RETRIEVE β βββΆ β AUGMENT β βββΆ β GENERATE β
β β β Relevant β β Context β β Answer β
β "What's the β β Documents β β + Query β β with Facts β
β refund..." β β β β β β β
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
| Without RAG | With RAG |
|---|---|
| "Refunds are typically available within 30 days." (generic guess) | "Refunds can be requested within 14 days of purchase, provided the license hasn't been activated." (from your actual policy) |
Every retrieval system walks the same line: finding what's relevant. The trick lies in how relevance is defined.
# TF-IDF based search - matches words, not meaning
query = "renewable energy from the sun"
# Results:
# β "Solar panels convert sunlight into electricity" β 0.00 (no word overlap!)
# β
"Wind turbines generate renewable power" β 0.19 (matches "renewable")The curse: Literal loyalty, semantic blindness.
# Sentence embeddings - matches meaning
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2')
query = "renewable energy from the sun"
# Results:
# β
"Solar panels convert sunlight into electricity" β 0.87 (understands solar = sun)
# β
"Wind turbines generate renewable power" β 0.55The magic: No matching words, yet perfect understanding.
DocuMind combines both for optimal results:
def hybrid_score(bm25_score, vector_score, alpha=0.6):
return alpha * vector_score + (1 - alpha) * bm25_scoreA model doesn't think in words. It thinks in vectors β numerical representations of meaning.
# Text β Vector (384 dimensions)
"Solar panels convert sunlight" β [0.13, 0.72, -0.48, ..., 0.19]
"Renewable energy from sun" β [0.15, 0.69, -0.45, ..., 0.21]
# Similar meaning = Close vectors in 384-dimensional space-- Traditional SQL can't do this:
SELECT * FROM docs WHERE meaning SIMILAR TO 'vacation policy'
-- It can only do exact matches:
SELECT * FROM docs WHERE content LIKE '%vacation%'# Semantic search with Pinecone
query_embedding = model.encode("time off policy")
results = index.query(vector=query_embedding, top_k=5)
# Returns: vacation policy, leave guidelines, PTO rules... ββββββββββββββββββββββββββββββββββββ
β DocuMind Frontend β
β (Next.js 14) β
β β’ Google OAuth (NextAuth) β
β β’ File Upload UI β
β β’ Chat Interface β
βββββββββββββββ¬βββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DocuMind Backend (FastAPI) β
β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β /auth β β /files β β /chat β β /credits β β
β β Router β β Router β β Router β β Router β β
β ββββββββ¬βββββββ ββββββββ¬βββββββ ββββββββ¬βββββββ ββββββββ¬βββββββ β
β β β β β β
β βΌ βΌ βΌ βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Services Layer β β
β β β’ MongoDB Service (Users, Files, Chats, Credits) β β
β β β’ RAG Service (LangChain + Pinecone) β β
β β β’ Local Processor (PDF, DOCX, Images, Audio/Video) β β
β β β’ Payment Service (Razorpay) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β MongoDB β β Pinecone β β Cloudinary β
β Atlas β β Vector Store β β File Store β
β β β β β β
β β’ Users β β β’ Embeddings β β β’ PDFs β
β β’ Files β β β’ Semantic β β β’ Images β
β β’ Chats β β Search β β β’ Videos β
β β’ Credits β β β β β’ Audio β
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Pinecone
# 1. Load document
loader = PyPDFLoader("company_policy.pdf")
docs = loader.load()
# 2. Split into chunks (800 chars, 100 overlap)
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100)
chunks = splitter.split_documents(docs)
# 3. Generate embeddings (FREE with local model)
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
# 4. Store in Pinecone
vectorstore = Pinecone.from_documents(chunks, embeddings, index_name="documind")# User query
query = "What is the vacation policy?"
# Embed query
query_embedding = embeddings.embed_query(query)
# Semantic search (top 5 most relevant chunks)
results = vectorstore.similarity_search(query, k=5)# Build context-aware prompt
context = "\n\n".join([doc.page_content for doc in results])
prompt = f"""
You are a helpful assistant. Answer based ONLY on the context below.
If the information isn't in the context, say "I don't have that information."
Context:
{context}
Question: {query}
Answer:
"""import google.generativeai as genai
# Generate grounded response
response = genai.generate_text(prompt)
print(response.text)
# Output: "According to your company policy, employees are entitled
# to 21 days of paid leave annually. Leave requests should be
# submitted 2 weeks in advance..."| Layer | Technology | Purpose |
|---|---|---|
| Frontend | Next.js 14, TypeScript, Tailwind CSS | Modern React UI |
| Auth | NextAuth.js + Google OAuth | Secure authentication |
| Backend | FastAPI (Python 3.11+) | High-performance API |
| Database | MongoDB Atlas | Document storage |
| Vector DB | Pinecone | Semantic search |
| Embeddings | Sentence Transformers (all-MiniLM-L6-v2) | Local, FREE embeddings |
| LLM | Google Gemini Pro | AI responses |
| File Storage | Cloudinary | Scalable file CDN |
| Payments | Razorpay | Credit system |
| Deployment | Docker + Render | Production hosting |
- Python 3.11+
- Node.js 20+
- MongoDB Atlas account
- Pinecone account
- Google Cloud Console (OAuth + Gemini API)
- Cloudinary account
git clone https://github.com/yourusername/documind.git
cd documindcd backend
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Create .env file
cp .env.example .envConfigure backend/.env:
# App
APP_NAME=DocuMind API
API_PREFIX=/api
# MongoDB Atlas
MONGODB_URI=mongodb+srv://<user>:<pass>@cluster.mongodb.net
MONGODB_DB_NAME=documind
# Security
JWT_SECRET=your-super-secret-jwt-key
JWT_ALGORITHM=HS256
# Google OAuth (from Google Cloud Console)
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-google-client-secret
# Gemini AI
GEMINI_API_KEY=your-gemini-api-key
# Pinecone Vector DB
PINECONE_API_KEY=your-pinecone-api-key
PINECONE_ENVIRONMENT=your-environment
PINECONE_INDEX_NAME=documind
# Cloudinary File Storage
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret
# Razorpay Payments
RAZORPAY_KEY_ID=your-key-id
RAZORPAY_KEY_SECRET=your-key-secretRun backend:
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000cd frontend
# Install dependencies
npm install
# Create .env file
cp .env.example .env.localConfigure frontend/.env.local:
# API
NEXT_PUBLIC_API_URL=http://localhost:8000
# NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-nextauth-secret
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-google-client-secretRun frontend:
npm run devcd backend
python setup_mongodb.pyVisit http://localhost:3000 and sign in with Google!
# Build and run all services
docker-compose up --build
# Run in background
docker-compose up -d
# View logs
docker-compose logs -f
# Stop
docker-compose downThe Docker setup is optimized for Render's free tier (512MB RAM):
# Multi-stage build (minimal image)
FROM python:3.11-slim as builder
# ... build dependencies ...
FROM python:3.11-slim as production
# ... only runtime dependencies ...
# Gunicorn with memory-optimized settings
CMD ["gunicorn", "app.main:app",
"--workers", "2", # 2 workers for 512MB
"--worker-class", "uvicorn.workers.UvicornWorker",
"--max-requests", "1000", # Prevent memory leaks
"--max-requests-jitter", "50",
"--preload"] # Load models once in master-
Create Web Service for Backend:
- Root Directory:
backend - Environment: Docker
- Add all environment variables from
.env
- Root Directory:
-
Create Web Service for Frontend:
- Root Directory:
frontend - Build Command:
npm install && npm run build - Start Command:
npm start
- Root Directory:
documind/
βββ backend/
β βββ app/
β β βββ core/
β β β βββ config.py # Environment settings
β β β βββ security.py # JWT authentication
β β βββ models/
β β β βββ schemas.py # Pydantic models
β β βββ routers/
β β β βββ auth.py # Google OAuth endpoints
β β β βββ files.py # File upload/management
β β β βββ chat.py # RAG chat endpoints
β β β βββ credits.py # Credit system
β β βββ services/
β β β βββ mongodb_service.py # Database operations
β β β βββ langchain_rag.py # RAG pipeline β
β β β βββ local_processor.py # Document processing
β β β βββ credit_service.py # Credit management
β β β βββ payment_service.py # Razorpay integration
β β βββ main.py # FastAPI app
β βββ Dockerfile
β βββ requirements.txt
β βββ .env
βββ frontend/
β βββ src/
β β βββ app/ # Next.js App Router
β β βββ components/ # React components
β β βββ contexts/ # React contexts
β β βββ hooks/ # Custom hooks
β β βββ lib/ # Utilities
β β βββ types/ # TypeScript types
β βββ Dockerfile
β βββ package.json
β βββ .env.local
βββ docker-compose.yml
βββ README.md
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/auth/google |
Google OAuth login |
GET |
/api/auth/me |
Get current user |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/files/upload |
Upload document |
GET |
/api/files |
List user files |
GET |
/api/files/{id} |
Get file details |
DELETE |
/api/files/{id} |
Delete file |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/chat |
Send message (RAG query) |
GET |
/api/chat/history/{file_id} |
Get chat history |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/credits/balance |
Get credit balance |
GET |
/api/credits/packages |
List credit packages |
POST |
/api/credits/order |
Create payment order |
POST |
/api/credits/verify |
Verify payment |
curl -X POST "http://localhost:8000/api/files/upload" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@company_policy.pdf"curl -X POST "http://localhost:8000/api/chat" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"file_id": "abc123",
"message": "What is the vacation policy?"
}'{
"response": "According to your company policy, employees are entitled to 21 days of paid leave annually. Leave requests should be submitted at least 2 weeks in advance. Up to 5 days of unused leave can be carried forward to the next year.",
"sources": [
{"chunk": "Employees are entitled to 21 days...", "page": 12},
{"chunk": "Leave requests must be submitted...", "page": 13}
]
}| Action | Credits |
|---|---|
| Upload file | Free |
| Ask question | 1 credit |
| New users | 50 free credits |
Credit Packages (Razorpay):
| Package | Credits | Price |
|---|---|---|
| Starter | 100 | βΉ99 |
| Pro | 500 | βΉ399 |
| Enterprise | 2000 | βΉ999 |
| Variable | Description | Required |
|---|---|---|
MONGODB_URI |
MongoDB connection string | β |
MONGODB_DB_NAME |
Database name | β |
JWT_SECRET |
Secret for JWT tokens | β |
GOOGLE_CLIENT_ID |
OAuth client ID | β |
GOOGLE_CLIENT_SECRET |
OAuth secret | β |
GEMINI_API_KEY |
Google Gemini API key | β |
PINECONE_API_KEY |
Pinecone API key | β |
PINECONE_INDEX_NAME |
Pinecone index name | β |
CLOUDINARY_CLOUD_NAME |
Cloudinary cloud name | β |
CLOUDINARY_API_KEY |
Cloudinary API key | β |
CLOUDINARY_API_SECRET |
Cloudinary API secret | β |
RAZORPAY_KEY_ID |
Razorpay key ID | β |
RAZORPAY_KEY_SECRET |
Razorpay secret | β |
| Variable | Description | Required |
|---|---|---|
NEXT_PUBLIC_API_URL |
Backend API URL | β |
NEXTAUTH_URL |
Frontend URL | β |
NEXTAUTH_SECRET |
NextAuth secret | β |
GOOGLE_CLIENT_ID |
OAuth client ID | β |
GOOGLE_CLIENT_SECRET |
OAuth secret | β |
# Lazy load embedding model
class RAGService:
def __init__(self):
self._model = None
def _get_model(self):
if self._model is None:
self._model = SentenceTransformer('all-MiniLM-L6-v2')
return self._model# Optimal settings for most documents
splitter = RecursiveCharacterTextSplitter(
chunk_size=800, # Not too small (loses context)
chunk_overlap=100, # Preserves continuity
separators=["\n\n", "\n", ". ", " "] # Natural breaks
)# Start with k=5, adjust based on accuracy
results = vectorstore.similarity_search(query, k=5)
# For complex queries, try k=10
# For simple lookups, k=3 is enough- β JWT-based authentication
- β Google OAuth 2.0
- β User data isolation (files, chats)
- β Non-root Docker containers
- β Environment variable secrets
- β CORS configuration
- RAG Paper (Lewis et al., 2020)
- LangChain Documentation
- Pinecone Vector Database
- Sentence Transformers
- Fork the repository
- Create feature branch (
git checkout -b feature/amazing) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing) - Open Pull Request
MIT License - see LICENSE for details.
Built with β€οΈ using RAG technology