A production-ready RAG (Retrieval-Augmented Generation) chatbot built with FastAPI, Qdrant Cloud, and Google Gemini 2.5 Flash. This system allows you to upload documents, index them in a vector database, and query them using natural language.
- Document Upload & Indexing: Upload PDF, TXT, and Markdown files
- Vector Search: Powered by Qdrant Cloud for fast similarity search
- AI-Powered Responses: Using Google Gemini 2.5 Flash for intelligent answers
- RESTful API: Clean FastAPI endpoints for easy integration
- Scalable Architecture: Modular design ready for multimodal expansion (images, audio)
- Production Ready: Proper error handling, logging, and configuration management
┌─────────────┐
│ Client │
└──────┬──────┘
│
▼
┌─────────────────────────────────────┐
│ FastAPI Server │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Documents │ │ Chat │ │
│ │ Routes │ │ Routes │ │
│ └──────┬──────┘ └──────┬───────┘ │
│ │ │ │
│ ┌──────┴────────────────┴───────┐ │
│ │ Service Layer │ │
│ │ • Document Processor │ │
│ │ • Embeddings Service │ │
│ │ • Vector Store │ │
│ │ • Chatbot Service │ │
│ └───────┬──────────────┬─────────┘ │
└──────────┼──────────────┼───────────┘
│ │
┌──────┴────┐ ┌────┴─────────┐
│ Qdrant │ │ Gemini │
│ Cloud │ │ API (2.5) │
└───────────┘ └──────────────┘
Tutor_chatbot/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI application entry point
│ ├── config.py # Configuration loader
│ ├── models/
│ │ ├── __init__.py
│ │ └── schemas.py # Pydantic request/response models
│ ├── services/
│ │ ├── __init__.py
│ │ ├── document_processor.py # Text/PDF extraction
│ │ ├── embeddings.py # Gemini embedding generation
│ │ ├── vector_store.py # Qdrant operations
│ │ └── chatbot.py # RAG query logic
│ ├── routes/
│ │ ├── __init__.py
│ │ ├── documents.py # Document upload/management endpoints
│ │ └── chat.py # Chat query endpoint
│ └── utils/
│ ├── __init__.py
│ └── chunking.py # Text chunking utilities
├── config/
│ └── config.yaml # App configuration
├── .env.example # Example environment variables
├── .gitignore
├── requirements.txt
└── README.md
- Python 3.8 or higher
- Qdrant Cloud account (sign up here)
- Google Gemini API key (get it here)
-
Clone the repository:
cd Tutor_chatbot -
Create a virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Configure environment variables:
cp .env.example .env
Edit
.envand add your credentials:GEMINI_API_KEY=your_gemini_api_key_here QDRANT_URL=your_qdrant_cloud_url_here QDRANT_API_KEY=your_qdrant_api_key_here ENVIRONMENT=development LOG_LEVEL=INFO
-
Configure application settings (optional):
Edit
config/config.yamlto adjust:- Chunk size and overlap
- Model parameters
- Collection name
- RAG settings
Start the development server:
python -m app.mainOr using uvicorn directly:
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000The API will be available at:
- API: http://localhost:8000
- Interactive Docs: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
Welcome endpoint with API information.
Response:
{
"message": "Welcome to RAG Tutor Chatbot API",
"version": "1.0.0",
"docs": "/docs",
"redoc": "/redoc"
}Health check endpoint.
Response:
{
"status": "healthy",
"version": "1.0.0",
"services": {
"qdrant": "healthy",
"gemini": "healthy"
}
}Upload and index a document.
Request:
- Method:
POST - Content-Type:
multipart/form-data - Body: File upload (PDF, TXT, or MD)
cURL Example:
curl -X POST "http://localhost:8000/documents/upload" \
-H "accept: application/json" \
-H "Content-Type: multipart/form-data" \
-F "file=@/path/to/your/document.pdf"Response:
{
"document_id": "doc_123abc",
"filename": "python_tutorial.pdf",
"chunks_created": 25,
"status": "success",
"message": "Document uploaded and indexed successfully",
"content_type": "text"
}List all indexed documents.
cURL Example:
curl -X GET "http://localhost:8000/documents/list"Response:
{
"documents": [
{
"document_id": "doc_123abc",
"filename": "python_tutorial.pdf",
"chunks_count": 25,
"upload_timestamp": "2025-10-13T10:30:00",
"content_type": "text"
}
],
"total_count": 1
}Delete a document from the vector database.
cURL Example:
curl -X DELETE "http://localhost:8000/documents/doc_123abc"Response:
{
"status": "success",
"message": "Document 'doc_123abc' deleted successfully"
}Query the chatbot with a question.
Request Body:
{
"query": "What are the main features of Python?",
"top_k": 5,
"filters": null,
"content_type": "text"
}cURL Example:
curl -X POST "http://localhost:8000/chat/query" \
-H "Content-Type: application/json" \
-d '{
"query": "What are the main features of Python?",
"top_k": 5
}'Response:
{
"answer": "Python is a high-level, interpreted programming language known for its simplicity and readability. Based on the provided context, the main features include...",
"sources": [
{
"document_id": "doc_123abc",
"filename": "python_tutorial.pdf",
"chunk_index": 5,
"content": "Python is a high-level programming language...",
"score": 0.92
}
],
"query": "What are the main features of Python?",
"processing_time": 1.23
}import requests
# Base URL
BASE_URL = "http://localhost:8000"
# 1. Upload a document
with open("python_tutorial.pdf", "rb") as f:
response = requests.post(
f"{BASE_URL}/documents/upload",
files={"file": f}
)
result = response.json()
print(f"Document ID: {result['document_id']}")
# 2. Query the chatbot
query_data = {
"query": "What are Python's main features?",
"top_k": 5
}
response = requests.post(
f"{BASE_URL}/chat/query",
json=query_data
)
result = response.json()
print(f"Answer: {result['answer']}")
print(f"Sources: {len(result['sources'])} documents")
# 3. List all documents
response = requests.get(f"{BASE_URL}/documents/list")
documents = response.json()
print(f"Total documents: {documents['total_count']}")
# 4. Delete a document
doc_id = "doc_123abc"
response = requests.delete(f"{BASE_URL}/documents/{doc_id}")
print(response.json())const BASE_URL = "http://localhost:8000";
// Upload a document
async function uploadDocument(file) {
const formData = new FormData();
formData.append('file', file);
const response = await fetch(`${BASE_URL}/documents/upload`, {
method: 'POST',
body: formData
});
return await response.json();
}
// Query the chatbot
async function queryChat(question) {
const response = await fetch(`${BASE_URL}/chat/query`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: question,
top_k: 5
})
});
return await response.json();
}
// Usage
const result = await queryChat("What are Python's main features?");
console.log(result.answer);| Variable | Description | Required |
|---|---|---|
GEMINI_API_KEY |
Google Gemini API key | Yes |
QDRANT_URL |
Qdrant Cloud URL | Yes |
QDRANT_API_KEY |
Qdrant Cloud API key | Yes |
ENVIRONMENT |
Environment (development/production) | No |
LOG_LEVEL |
Logging level (DEBUG/INFO/WARNING/ERROR) | No |
document_processing:
chunk_size: 1000 # Characters per chunk
chunk_overlap: 200 # Overlap between chunks
max_file_size_mb: 50 # Maximum file size
qdrant:
collection_name: "tutor_documents"
vector_size: 768
distance_metric: "Cosine"
gemini:
embedding_model: "models/embedding-001"
chat_model: "gemini-2.0-flash-exp"
temperature: 0.7
max_output_tokens: 2048
top_k_retrieval: 5
rag:
similarity_threshold: 0.7 # Minimum similarity score# Install test dependencies
pip install pytest pytest-asyncio httpx
# Run tests
pytest# Install formatting tools
pip install black flake8 mypy
# Format code
black app/
# Check style
flake8 app/
# Type checking
mypy app/The architecture is designed to support multimodal inputs:
-
Image Processing:
- OCR for text extraction
- Visual question answering
- Image similarity search
-
Audio Processing:
- Speech-to-text transcription
- Audio indexing and search
- Voice queries
-
Video Processing:
- Frame extraction and analysis
- Transcript generation
- Multimodal search
- Streaming responses for real-time answers
- Document versioning and updates
- Advanced filtering and metadata search
- Multi-language support
- Conversation history and context
- User authentication and authorization
- Rate limiting and quotas
- Caching for improved performance
- Batch document upload
- Export conversation history
Issue: "Connection to Qdrant failed"
- Solution: Verify your Qdrant Cloud URL and API key in
.env
Issue: "Gemini API authentication failed"
- Solution: Check your Gemini API key and ensure it's valid
Issue: "No relevant context found"
- Solution: Ensure documents are uploaded and indexed before querying
Issue: "File size too large"
- Solution: Adjust
max_file_size_mbinconfig.yamlor compress the file
Enable debug logging for troubleshooting:
# In .env file
LOG_LEVEL=DEBUGCheck logs for detailed error messages and processing information.
-
Chunk Size: Adjust
chunk_sizebased on your document type- Smaller chunks (500-800): Better for FAQ-style content
- Larger chunks (1000-1500): Better for detailed explanations
-
Embedding Batch Size: Process documents in batches to avoid rate limits
-
Top-K Retrieval: Use lower values (3-5) for faster responses
-
Similarity Threshold: Increase threshold to filter out irrelevant results
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
This project is licensed under the MIT License.
For issues, questions, or contributions, please open an issue on GitHub.
- FastAPI: Modern Python web framework
- Qdrant: High-performance vector database
- Google Gemini: Advanced AI language model
- pypdf: PDF text extraction
Built with ❤️ for educational purposes