Retrieval-Augmented Generation service for the apowerb stack — document processing, vector search and conversational retrieval.
A production-ready Retrieval-Augmented Generation (RAG) system built with FastAPI, featuring document processing, vector search, and conversational AI capabilities.
- Features
- Tech Stack
- Prerequisites
- Installation
- Configuration
- Running the Application
- Testing
- Development Workflow
- Project Structure
- API Documentation
- ContrXuting
- 🔐 JWT-based authentication with refresh tokens
- 📄 PDF document processing and vectorization
- 🗃️ Vector similarity search using LanceDB
- 💬 Conversational AI with context retrieval
- 📊 Dataset management and metadata tracking
- ☁️ S3-compatXle storage integration
- 🐳 Full Docker support with health checks
- 🧪 Comprehensive test suite
- Language: Python 3.12+
- Framework: FastAPI
- Package Manager: UV (modern Python package manager)
- ORM: SQLAlchemy 2.0
- Database: PostgreSQL
- Vector Store: LanceDB
- Embeddings: Sentence Transformers (gtr-t5-large)
- LLM: Mistral AI
- Document Processing: Docling
- Storage: S3-compatXle (Scaleway, AWS, etc.)
- Containerization: Docker + Docker Compose
# 1. Install Chocolatey (Package Manager) - Run as Administrator
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# 2. Install Python 3.12
choco install python312 -y
# 3. Install PostgreSQL (for local development)
choco install postgresql15 -y
# 4. Install Visual C++ Build Tools (required for some Python packages)
choco install visualstudio2022buildtools -y
# 5. Restart your terminal# 1. Install Homebrew (if not installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 2. Install Python 3.12
brew install python@3.12
# 3. Install PostgreSQL (for local development)
brew install postgresql@15
# 4. Install OpenCV (required for document processing)
brew install opencv
# 5. Restart your terminal# Install UV using PowerShell (Run as Administrator)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# Close and reopen your terminal, then verify
uv --version# Install UV
curl -LsSf https://astral.sh/uv/install.sh | sh
# Reload shell configuration
source ~/.zshrc # or ~/.bashrc for bash users
# Verify installation
uv --version# Install Git
choco install git -y
# Configure Git (replace with your info)
git config --global user.name "Your Name"
git config --global user.email "your.email@company.com"# Install Git
brew install git
# Configure Git (replace with your info)
git config --global user.name "Your Name"
git config --global user.email "your.email@company.com"- Windows: Download Docker Desktop for Windows
- macOS: Download Docker Desktop for Mac
# Clone the repository
git clone <repository-url>
cd rag-backend-api
# Switch to development branch (if applicable)
git checkout develop# Create UV virtual environment with Python 3.12
uv venv --python 3.12
# Activate virtual environment
.venv\Scripts\activate
# Verify Python version
python --version # Should show Python 3.12.x# Create UV virtual environment with Python 3.12
uv venv --python 3.12
# Activate virtual environment
source .venv/bin/activate
# Verify Python version
python --version # Should show Python 3.12.x# Install all dependencies (including dev dependencies)
uv sync
# For production only (without dev dependencies)
uv sync --no-devWindows 🪟
# If psycopg2-binary fails
# Make sure PostgreSQL is installed, then:
$env:PATH += ";C:\Program Files\PostgreSQL\15\bin"
uv pip install psycopg2-binary
# If Visual C++ errors occur
# Install Visual Studio Build Tools from:
# https://visualstudio.microsoft.com/visual-cpp-build-tools/macOS ARM (M1/M2/M3) 🍎
# If PyTorch installation fails
uv pip install torch==2.6.0 torchvision==0.21.0
# If psycopg2 fails
brew install postgresql@15
export PATH="/opt/homebrew/opt/postgresql@15/bin:$PATH"
uv pip install psycopg2-binary# Copy example configuration
Copy-Item .env.example .env
# Edit with notepad
notepad .env# Copy example configuration
cp .env.example .env
# Edit with your preferred editor
nano .env # or vim, code, etc.Update the .env file with your actual values:
# Application Mode
WORKING_MODE=development
# Database Configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=rag_db
DB_USER=your_db_user
DB_PASSWORD=your_secure_password
DB_SCHEMA=public
# S3 Storage Configuration
S3_REGION=eu-west-3
S3_ACCESS_KEY=your_access_key
S3_ACCESS_KEY_SECRET=your_secret_key
S3_ENDPOINT=https://s3.eu-west-3.amazonaws.com
S3_BUCKET_NAME=your_bucket_name
# Mistral AI API
MISTRAL_API_KEY=your_mistral_api_key
MISTRAL_API_URL=https://api.mistral.ai/v1
# JWT Authentication
SECRET_KEY=your-super-secret-key-minimum-32-characters
ACCESS_TOKEN_EXPIRE_MINUTES=60
ALGORITHM=HS256
# Password Encryption
ENCRYPT_KEY=your-encryption-key
# Development Settings (optional)
ECHO_SQL=false
⚠️ Security Warning: Never commit.envfiles to version control!
# Run database migrations
alembic upgrade headThe PostgreSQL database is IP-whitelisted for security reasons.
➡️ Before running the application, you must ask the project owner/admin to add your public IP address to the database whitelist.
curl ifconfig.meor
curl https://api.ipify.orgcurl ifconfig.meor
(Invoke-WebRequest -uri "https://api.ipify.org").ContentSend the resulting IP address to the administrator so it can be approved and added to the whitelist.
⚠️ Note: If you are on a dynamic network (VPN, mobile hotspot, etc.), your IP may change and need to be re-approved.
# Activate virtual environment
.venv\Scripts\activate
# Start the API server with auto-reload
uv run uvicorn th2rag.main:app --reload --host 0.0.0.0 --port 8000# Activate virtual environment
source .venv/bin/activate
# Start the API server with auto-reload
uv run uvicorn th2rag.main:app --reload --host 0.0.0.0 --port 8000Access Points:
- 📚 Swagger UI: http://localhost:8000/docs
- 📖 ReDoc: http://localhost:8000/redoc
- ❤️ Health Check: http://localhost:8000/health
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f api
# Stop services
docker-compose down# Important: Restart does NOT reload .env!
# You must stop and recreate containers:
docker-compose down
docker-compose up -d
docker-compose logs -f api# Activate virtual environment
.venv\Scripts\activate
# Run all tests
uv run pytest
# Run with verbose output
uv run pytest -v
# Run specific test file
uv run pytest test\test_auth.py
# Run with coverage
uv run pytest --cov=src --cov-report=html
uv run pytest --cov=src --cov-report=term-missing
# Open coverage report
start htmlcov\index.html# Activate virtual environment
source .venv/bin/activate
# Run all tests
uv run pytest
# Run with verbose output
uv run pytest -v
# Run specific test file
uv run pytest test/test_auth.py
# Run with coverage
uv run pytest --cov=src --cov-report=html
uv run pytest --cov=src --cov-report=term-missing
# Open coverage report
open htmlcov/index.html# Ensure containers are running
docker-compose up -d
# Run tests inside container
docker-compose exec api pytest -vThis project follows a Git workflow with feature branches:
# 1. Create a new feature branch from main/develop
git checkout -b feature/your-feature-name
# 2. Make your changes and commit regularly
git add .
git commit -m "feat: description of your changes"
# 3. Push to remote
git push origin feature/your-feature-name
# 4. Create a Pull Request on GitHubPre-commit hooks automatically check your code before each commit.
Windows 🪟
uv pip install pre-commitmacOS/Linux 🍎🐧
uv pip install pre-commit# Install the pre-commit hooks
pre-commit install
# (Optional) Run against all files to test
pre-commit run --all-filesCreate .pre-commit-config.yaml in your project root:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
args: ['--maxkb=1000']
- id: check-json
- id: check-merge-conflict
- id: detect-private-key
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
language_version: python3.12
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.9
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
hooks:
- id: mypy
additional_dependencies: [types-all]
args: [--ignore-missing-imports]Follow conventional commits for clear history:
# Format: <type>(<scope>): <subject>
git commit -m "feat(auth): add refresh token endpoint"
git commit -m "fix(database): resolve connection pool issue"
git commit -m "docs(readme): update installation instructions"
git commit -m "test(auth): add JWT validation tests"
git commit -m "chore(deps): update dependencies"Commit Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
1. Check your current status
# See what files have changed
git status
# See the actual changes
git diff2. Stage your changes
# Stage specific files
git add pyproject.toml
git add .pre-commit-config.yaml
git add docker-compose.yml
git add README.md
git add .env.example
# OR stage all changes
git add .3. Commit your changes
# Commit with a descriptive message
git commit -m "feat(migration): migrate to UV package manager and update documentation"4. Create and push your branch
Windows 🪟
# Create and switch to X branch
git checkout -b X
# Push to remote repository
git push -u origin XmacOS/Linux 🍎🐧
# Create and switch to X branch
git checkout -b X
# Push to remote repository
git push -u origin X5. Create a Pull Request
- Go to your GitHub repository
- Click "Compare & pull request" button
- Select base branch (usually
mainordevelop) - Add description of your changes
- Assign reviewers from your team
- Submit the pull request
# 1. Start of day - update your branch
git checkout X
git pull origin X
# 2. Make changes to files
# ... edit code ...
# 3. Check what changed
git status
git diff
# 4. Run tests before committing
uv run pytest
# 5. Pre-commit will automatically run when you commit
git add .
git commit -m "feat(rag): improve document chunking algorithm"
# 6. Push changes
git push origin X
# 7. If you need to sync with main branch
git checkout main
git pull origin main
git checkout X
git merge main
# Resolve any conflicts if they occur
git push origin XIf pre-commit hooks fail:
# Pre-commit will show what failed
# Fix the issues, then:
git add .
git commit -m "your message"
# If automatic fixes were applied, stage them:
git add .
git commit --amend --no-edit.
├── .github/ # GitHub workflows and templates
├── alembic/ # Database migrations
│ ├── versions/ # Migration scripts
│ └── env.py # Alembic environment
├── data/ # LanceDB vector storage
├── src/ # Main application source
│ ├── auth/ # JWT authentication
│ ├── clients/ # S3 client integration
│ ├── conversations/ # Conversation management
│ ├── dataset/ # Dataset handling
│ ├── knowledge/ # Document management
│ ├── messages/ # Message operations
│ ├── rag/ # RAG pipeline
│ │ ├── chunkers/ # Document chunking
│ │ ├── converters/ # Format conversion
│ │ ├── embeddings/ # Vector embeddings
│ │ ├── generation/ # LLM generation
│ │ ├── retrieval/ # Vector search
│ │ ├── services/ # RAG orchestration
│ │ └── tasks/ # Background jobs
│ ├── users/ # User management
│ ├── utils/ # Utilities
│ └── main.py # Application entry
├── test/ # Test suite
├── .env.example # Environment template
├── .gitignore # Git ignore rules
├── .pre-commit-config.yaml # Pre-commit hooks
├── alembic.ini # Alembic config
├── docker-compose.yml # Docker services
├── Dockerfile # Container definition
├── pyproject.toml # Project dependencies
└── README.md # This file
POST /auth/login- Login and get tokensPOST /auth/refresh-token- Refresh access token
GET /users- List users (admin)POST /users- Create userGET /users/me- Get current userGET /users/{id}- Get user by IDDELETE /users/{id}- Delete user
GET /conversations- List conversationsPOST /conversations- Create conversationGET /conversations/{id}- Get conversation detailsDELETE /conversations/{id}- Delete conversation
GET /conversations/{id}/messages- List messagesPOST /conversations/{id}/messages- Send message and get AI responsePOST /conversations/{id}/messages/{message_id}/feedback- Add feedback
GET /knowledge- List documentsPOST /knowledge- Upload PDF documentGET /knowledge/{id}- Get document detailsDELETE /knowledge/{id}- Delete document and vectors
GET /datasets- List datasetsPOST /datasets- Create datasetPUT /datasets/{id}- Update datasetDELETE /datasets/{id}- Delete dataset
For detailed API schemas, visit: http://localhost:8000/docs
The rag/ module is responsible for the core Retrieval-Augmented Generation (RAG) pipeline. It orchestrates document conversion, chunking, embedding, retrieval, and final answer generation.
converters/pdf_converter.py: Converts PDF files (local or S3) to an internalDocumentformat usingdocling.
convert_pdf(source: str) -> dictchunkers/hybrid_chunker.py: Wrapsdocling'sHybridChunkerto split documents into semantic chunks.
HybridTextChunker.chunk_document(dl_doc) -> listembeddings/sentence_transformer.py: Usessentence-transformers/gtr-t5-largeto convert text chunks into dense vectors.
SentenceTransformerEmbedding.encode(text: str) -> List[float]retrieval/lancedb/lancedb_storage.py: Manages chunk storage/retrieval in LanceDB.retrieval/lancedb/schemas.py: Pydantic schema definitions for LanceDB.
LanceDBStorage.add_chunks(chunks)
LanceDBStorage.query(query_vector, doc_id, limit)retrieval/lancedb/lancedb_retriever.py: Retrieves similar document chunks using LanceDB + embeddings.
LanceDBRetriever.retrieve(query: str, doc_id: int, limit: int) -> List[Dict]generation/mistral_generator.py: Calls Mistral API to generate responses using retrieved context.
MistralGenerator.generate(question, retrieved_context, prompt, history) -> strservices/rag_service.py: Orchestrates the full RAG pipeline.services/rag_service_builder.py: Builds the RAG service with configurable components.
RAGService.answer_question(question, doc_id, limit, prompt, history)tasks/process_pdf.py: Asynchronously handles PDF-to-vector pipeline including download, convert, chunk, embed, and store.
process_pdf_background(doc_id, source)Before submitting a PR, ensure:
- ✅ All tests pass (
uv run pytest) - ✅ Pre-commit hooks pass
- ✅ Code is documented with docstrings
- ✅ New features have tests
- ✅ README updated if needed
- ✅ Commit messages follow convention
- ✅ No sensitive data in commits
1. Database Changes
# Edit src/models.py
# Generate migration
alembic revision --autogenerate -m "add new feature"
# Review and apply
alembic upgrade head2. New Embedding Model
# src/rag/embeddings/custom_embedding.py
from th2rag.rag.embeddings.base import BaseEmbedding
class CustomEmbedding(BaseEmbedding):
def encode(self, text: str) -> List[float]:
# Implementation
pass3. New LLM Generator
# src/rag/generation/custom_generator.py
from th2rag.rag.generation.base import BaseGenerator
class CustomGenerator(BaseGenerator):
def generate(self, question: str, context: str) -> str:
# Implementation
passPort already in use:
# Find process
netstat -ano | findstr :8000
# Kill process (replace PID)
taskkill /PID <PID> /FPython not found:
# Add Python to PATH
$env:Path += ";C:\Python312;C:\Python312\Scripts"Permission errors:
# Run PowerShell as Administrator
# Or adjust execution policy
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserPort already in use:
# Find and kill process
lsof -ti:8000 | xargs kill -9SSL certificate errors:
# Update certificates
pip install --upgrade certifiDatabase connection failed:
- Verify PostgreSQL is running
- Check credentials in
.env - Ensure database exists
Docker container won't start:
docker-compose logs api
docker-compose down -v
docker-compose up -d --buildPre-commit hooks fail:
# Update hooks
pre-commit autoupdate
pre-commit run --all-files- 📧 Email: your-team@company.com
- 💬 Slack: #rag-backend-support
- 🐛 Issues: GitHub Issues
- 📖 Wiki: Project Wiki
th2rag is distributed under the Apache License 2.0. Copyright 2025-2026 thaink².
"apowerb" and "thaink²" are trademarks of thaink². The licence covers the code, not the marks — see TRADEMARK.md.