AI-Powered Study Tutor Application with Retrieval-Augmented Generation (RAG) capabilities for document analysis and conversational learning.
# 1. Clone the repository
git clone <repo-url>
cd AI-Study-Tutor
# 2. Frontend (cognify-frontend)
cd cognify-frontend && npm install && npm run dev
# Runs on http://localhost:5173
# 3. Node.js Backend (node-backend)
cd ../node-backend && npm install
cp .env.example .env # Configure your .env
npm run dev
# Runs on http://localhost:4000
# 4. FastAPI Backend (ai-engine)
cd ../ai-engine
# Create virtual environment
python -m venv venv
source venv/bin/activate # macOS/Linux
# Windows: venv\Scripts\activate
# Install and run
pip install -r requirements.txt
cp .env.example .env # Configure your .env
uvicorn app.main:app --reload
# Runs on http://localhost:8000
Why MongoDB Atlas?
Setup Steps:
# Example connection string:
mongodb+srv://username:password@cluster0.xxxxx.mongodb.net/rag_app
# Add to node-backend/.env:
MONGO_URI=mongodb+srv://username:password@cluster0.xxxxx.mongodb.net/rag_app
node-backend/.env
MONGO_URI=mongodb+srv://...
JWT_SECRET=your-secret
GOOGLE_CLIENT_ID=xxx
EMAIL_USER=email@zoho.in
EMAIL_PASSWORD=xxx
ai-engine/.env
LLM_PROVIDER=gemini
GOOGLE_API_KEY=your-key
JWT_SECRET=your-secret
See Section 5 for complete environment variable reference.
cognify-frontend)| Technology | Purpose |
|---|---|
| React 19 | Modern UI framework with latest features |
| TypeScript | Type-safe JavaScript for scalable development |
| Vite | Lightning-fast build tool and dev server |
| TailwindCSS 4 | Utility-first CSS framework |
| Redux Toolkit | State management with redux-persist |
| React Router v7 | Client-side routing |
| Framer Motion | Smooth animations and transitions |
| Mermaid | Diagram rendering for concept maps |
| react-markdown | Markdown rendering with remark-gfm |
| Ant Design | UI component library |
Why these choices?
node-backend)| Technology | Purpose |
|---|---|
| Express.js | Fast, minimalist web framework |
| TypeScript | Type safety for backend code |
| MongoDB + Mongoose | NoSQL database for flexible schemas |
| JWT (jsonwebtoken) | Stateless authentication |
| AWS S3 SDK | Cloud file storage integration |
| Multer | File upload handling |
| bcryptjs | Password hashing |
| Nodemailer | Email services |
| Google Auth Library | OAuth2 social login |
Why these choices?
ai-engine)| Technology | Purpose |
|---|---|
| FastAPI | High-performance async Python framework |
| Uvicorn | ASGI server for async processing |
| ChromaDB | Vector database for embeddings |
| Sentence Transformers | Text embedding generation |
| PyMuPDF (fitz) | PDF text extraction |
| OpenAI/DeepInfra/Gemini | LLM provider integrations |
| BeautifulSoup4 | Web scraping for URLs |
| boto3 | AWS S3 integration |
| Pydantic Settings | Configuration management |
Why these choices?
all-MiniLM-L6-v2 model
The application supports dual storage providers with a unified abstraction layer:
Configuration:
STORAGE_PROVIDER=local
LOCAL_STORAGE_PATH=../application-data
How it works:
application-data/ folder at project root{BACKEND_URL}/storage/{key}File organization:
application-data/
βββ {userEmail}/
βββ workspaces/
βββ {workspaceId}/
βββ pdfs/
β βββ {timestamp}-{filename}.pdf
βββ texts/
βββ {timestamp}-{title}.txt
Configuration:
STORAGE_PROVIDER=s3
AWS_S3_BUCKET=your-bucket-name
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
How it works:
S3 URL format:
https://{bucket}.s3.{region}.amazonaws.com/{key}
Simply change the STORAGE_PROVIDER environment variable:
| Provider | Value | Use Case |
|---|---|---|
| Local | local |
Development, self-hosted deployments |
| AWS S3 | s3 |
Production, scalable deployments |
Both backends (Node.js and FastAPI) use the same abstraction, ensuring consistent file access across the stack.
Switching LLM providers requires only updating 2 environment variables in
ai-engine/.env:
# Just change these two lines to switch providers:
LLM_PROVIDER=gemini # Options: gemini, openai, deepinfra, ollama, bedrock
GOOGLE_API_KEY=your-api-key # Add the corresponding API key
Available Providers:
| Provider | LLM_PROVIDER Value | API Key Variable | Example Model |
|---|---|---|---|
| Google Gemini | gemini |
GOOGLE_API_KEY | gemini-2.0-flash |
| OpenAI | openai |
OPENAI_API_KEY | gpt-4-turbo |
| DeepInfra | deepinfra |
DEEPINFRA_API_KEY | Various OSS models |
| Ollama (Local) | ollama |
None (uses OLLAMA_HOST) | llama2, mistral |
| AWS Bedrock | bedrock |
AWS credentials | Claude, Titan |
Example Configurations:
# Use Google Gemini (default)
LLM_PROVIDER=gemini
GOOGLE_API_KEY=AIzaSy...
# Use OpenAI
LLM_PROVIDER=openai
OPENAI_API_KEY=sk-...
# Use local Ollama (no API key needed)
LLM_PROVIDER=ollama
OLLAMA_HOST=http://localhost:11434
.env and restart the backend.
Configuration:
CHROMA_PERSIST_DIR=./chroma_db
EMBEDDING_MODEL=all-MiniLM-L6-v2
CHUNK_SIZE=500
CHUNK_OVERLAP=100
Key Operations:
| Operation | Description |
|---|---|
add_documents |
Store document chunks with embeddings |
query |
Semantic similarity search with doc_id filtering |
delete_document |
Remove all chunks for a document |
embed_text |
Generate embedding for single text |
Semantic Chunking Strategy:
\n\n)localhost:4000)| Endpoint | Method | Purpose |
|---|---|---|
/api/auth/register |
POST | User registration |
/api/auth/login |
POST | JWT authentication |
/api/auth/google |
POST | Google OAuth login |
/api/workspaces |
CRUD | Workspace management |
/api/workspaces/:id/sources |
CRUD | Source (document) management |
/api/chat/sessions |
CRUD | Chat session storage |
/health |
GET | Health check |
localhost:8000)| Endpoint | Method | Purpose |
|---|---|---|
/api/process |
POST | Document processing + embedding |
/api/generate |
POST | Deep content generation (SSE) |
/api/chat |
POST | RAG query (non-streaming) |
/ws/rag_chat |
WebSocket | Real-time RAG chat |
/api/scrape |
POST | URL content scraping |
/docs |
GET | Swagger documentation |
/health |
GET | Health check |
# Server
NODE_ENV=development
PORT=4000
CORS_ORIGINS=http://localhost:5173
# Database
MONGODB_URI=mongodb://localhost:27017/rag_app
# JWT (shared with FastAPI)
JWT_SECRET=your-super-secret-key
JWT_EXPIRES_IN=7d
# Storage
STORAGE_PROVIDER=local
LOCAL_STORAGE_PATH=../application-data
AWS_S3_BUCKET=your-bucket
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=xxx
AWS_SECRET_ACCESS_KEY=xxx
# OAuth
GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
# LLM
LLM_PROVIDER=gemini
GOOGLE_API_KEY=your-api-key
DEEPINFRA_API_KEY=xxx
OPENAI_API_KEY=xxx
# Vector Store
CHROMA_PERSIST_DIR=./chroma_db
EMBEDDING_MODEL=all-MiniLM-L6-v2
# Storage (same as Node.js)
STORAGE_PROVIDER=local
LOCAL_STORAGE_PATH=../application-data
# JWT (shared)
JWT_SECRET=your-super-secret-key
The RAG system uses a sophisticated multi-stage retrieval pipeline for significantly improved accuracy:
| Technique | Description | Why It Helps |
|---|---|---|
| HyDE | LLM generates hypothetical answer, used for vector search | Better semantic alignment with document chunks |
| Hybrid Search | Combines vector similarity + BM25 keyword search | Catches both semantic and exact matches |
| RRF Fusion | Reciprocal Rank Fusion combines multiple result lists | Leverages strengths of different search methods |
| Cross-Encoder Re-Ranking | Neural model scores query-document pairs | More accurate relevance scoring than bi-encoder |
The system uses cross-encoder/ms-marco-MiniLM-L-6-v2:
# Graceful LLM failure handling
try:
response = await self.llm.generate(messages)
return response.content
except Exception as e:
print(f"[RAGAgent] Error: {e}")
return "I encountered an error. Please try again."
The DeepContentGenerator includes robust JSON parsing:
// Node.js: Graceful storage errors
async getFileBuffer(key: string): Promise<Buffer> {
try {
return await readFile(this.getFullPath(key));
} catch (error) {
logger.error(`Failed to read file: ${key}`, error);
throw new NotFoundError(`File not found: ${key}`);
}
}
The application uses Nodemailer for sending OTP verification emails during user registration.
Add these to your node-backend/.env file:
# Email Configuration (Zoho Mail - Default)
EMAIL_USER=your-email@zoho.in
EMAIL_PASSWORD=your-zoho-app-password
Default Setup (Zoho Mail India):
// services/emailService.ts
const transporter = nodemailer.createTransport({
host: "smtp.zoho.in", // Zoho India SMTP server
port: 465, // SSL port
secure: true, // Use TLS encryption
auth: {
user: config.emailUser, // EMAIL_USER from .env
pass: config.emailPassword // EMAIL_PASSWORD from .env
},
});
| Setting | Value |
|---|---|
| Host | smtp.zoho.in |
| Port | 465 (SSL) |
| Secure | true |
| Authentication | Email + App Password |
To switch providers, modify emailService.ts:
Gmail:
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 587,
secure: false,
auth: {
user: config.emailUser,
pass: config.emailPassword, // Use App Password (not regular password)
},
});
SendGrid (Recommended for Production):
const transporter = nodemailer.createTransport({
host: "smtp.sendgrid.net",
port: 587,
auth: {
user: "apikey",
pass: process.env.SENDGRID_API_KEY,
},
});
| Feature | Implementation |
|---|---|
| OTP Generation | 6-digit random code via Math.random() |
| HTML Templates | Professional styled emails with gradient design |
| Plain Text Fallback | For email clients without HTML support |
| Custom Headers | X-Priority and X-Mailer for deliverability |
| Branding | "Cognify" branded email templates |
EMAIL_USEREMAIL_PASSWORDThe OTP email includes:
| Issue | Solution |
|---|---|
| Authentication failed | Use App Password, not regular password |
| Connection timeout | Check firewall allows port 465/587 |
| Email not received | Check spam folder, verify sender domain |
| Rate limiting | Use production provider (SendGrid/SES) |