From a70ba1f75a085b4535e63f6ef42c3fd38788d63e Mon Sep 17 00:00:00 2001 From: Taddeus <8607097+taddeusb90@users.noreply.github.com> Date: Mon, 23 Jun 2025 20:04:34 +0300 Subject: [PATCH] Phase 1: LightRAG Minimal Helm chart and documentation indexing using url references (#2) * Partial implementation of phase-0 * Partial implementation of phase-1 * add report * add postgress * Revert "add postgress" This reverts commit 27778dc6bb3906b5220dd386e47fe32ca7415332. * remove junk * Cleaned up annd setup docs * update docs * moved report * Updated load_markdown_files function: Now returns tuples with (content, title, relative_path) instead of just (content, title) * fixes to load docs script and more env variables for llm configuration * update prod values * update docs * apolo docs support with linking * update docs to reflect url conventions and mapping with docs * Adds ingress and forwardAuth configurations Adds ingress configuration to expose the application. Adds forwardAuth configuration to enable user authentication. Includes middleware to strip headers. * Adds ingress and forward authentication middleware support --- .gitignore | 4 + README_load_docs.md | 174 ++++++ blueprints/KUBERNETES_DEPLOYMENT.md | 506 ++++++++++++++++++ blueprints/REPORT.md | 438 +++++++++++++++ deploy-stacks.sh | 217 ++++++++ docker-compose.all-in-one.yml | 148 +++++ docker-compose.balanced.yml | 122 +++++ docker-compose.development.yml | 81 +++ docker-compose.high-performance.yml | 199 +++++++ docker-compose.minimal.yml | 55 ++ k8s-deploy/lightrag-minimal/Chart.lock | 6 + k8s-deploy/lightrag-minimal/Chart.yaml | 13 + k8s-deploy/lightrag-minimal/README.md | 379 +++++++++++++ .../lightrag-minimal/templates/NOTES.txt | 54 ++ .../lightrag-minimal/templates/_helpers.tpl | 80 +++ .../templates/deployment.yaml | 157 ++++++ .../templates/forwardauth-middleware.yaml | 28 + .../lightrag-minimal/templates/hpa.yaml | 32 ++ .../lightrag-minimal/templates/ingress.yaml | 44 ++ .../lightrag-minimal/templates/pvc.yaml | 35 ++ .../lightrag-minimal/templates/secret.yaml | 10 + .../lightrag-minimal/templates/service.yaml | 15 + .../templates/serviceaccount.yaml | 12 + .../templates/strip-headers-middleware.yaml | 15 + k8s-deploy/lightrag-minimal/values-dev.yaml | 75 +++ k8s-deploy/lightrag-minimal/values-prod.yaml | 120 +++++ k8s-deploy/lightrag-minimal/values.yaml | 162 ++++++ k8s-deploy/lightrag/templates/deployment.yaml | 2 +- .../templates/forwardauth-middleware.yaml | 28 + k8s-deploy/lightrag/templates/ingress.yaml | 54 ++ .../templates/strip-headers-middleware.yaml | 15 + k8s-deploy/lightrag/values.yaml | 24 + load_docs.py | 319 +++++++++++ 33 files changed, 3622 insertions(+), 1 deletion(-) create mode 100644 README_load_docs.md create mode 100644 blueprints/KUBERNETES_DEPLOYMENT.md create mode 100644 blueprints/REPORT.md create mode 100755 deploy-stacks.sh create mode 100644 docker-compose.all-in-one.yml create mode 100644 docker-compose.balanced.yml create mode 100644 docker-compose.development.yml create mode 100644 docker-compose.high-performance.yml create mode 100644 docker-compose.minimal.yml create mode 100644 k8s-deploy/lightrag-minimal/Chart.lock create mode 100644 k8s-deploy/lightrag-minimal/Chart.yaml create mode 100644 k8s-deploy/lightrag-minimal/README.md create mode 100644 k8s-deploy/lightrag-minimal/templates/NOTES.txt create mode 100644 k8s-deploy/lightrag-minimal/templates/_helpers.tpl create mode 100644 k8s-deploy/lightrag-minimal/templates/deployment.yaml create mode 100644 k8s-deploy/lightrag-minimal/templates/forwardauth-middleware.yaml create mode 100644 k8s-deploy/lightrag-minimal/templates/hpa.yaml create mode 100644 k8s-deploy/lightrag-minimal/templates/ingress.yaml create mode 100644 k8s-deploy/lightrag-minimal/templates/pvc.yaml create mode 100644 k8s-deploy/lightrag-minimal/templates/secret.yaml create mode 100644 k8s-deploy/lightrag-minimal/templates/service.yaml create mode 100644 k8s-deploy/lightrag-minimal/templates/serviceaccount.yaml create mode 100644 k8s-deploy/lightrag-minimal/templates/strip-headers-middleware.yaml create mode 100644 k8s-deploy/lightrag-minimal/values-dev.yaml create mode 100644 k8s-deploy/lightrag-minimal/values-prod.yaml create mode 100644 k8s-deploy/lightrag-minimal/values.yaml create mode 100644 k8s-deploy/lightrag/templates/forwardauth-middleware.yaml create mode 100644 k8s-deploy/lightrag/templates/ingress.yaml create mode 100644 k8s-deploy/lightrag/templates/strip-headers-middleware.yaml create mode 100755 load_docs.py diff --git a/.gitignore b/.gitignore index a1b10a90..a498b0f6 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,10 @@ __pycache__/ *.tar.gz *.ini +apolo-documentation/ +init-scripts/ +mongo-init/ +rag_storage_test/ # Virtual Environment .venv/ env/ diff --git a/README_load_docs.md b/README_load_docs.md new file mode 100644 index 00000000..1d5d846f --- /dev/null +++ b/README_load_docs.md @@ -0,0 +1,174 @@ +# LightRAG Documentation Loader + +Advanced script to load markdown documentation into LightRAG with flexible reference modes. + +## Quick Start + +```bash +# Default mode (file path references) +python load_docs.py /path/to/your/docs + +# URL mode (website link references) +python load_docs.py /path/to/docs --mode urls --base-url https://docs.example.com/ +``` + +## Reference Modes + +### Files Mode (Default) +Uses local file paths in query response citations: +```bash +python load_docs.py docs/ +python load_docs.py docs/ --mode files +``` + +**Query Response Example:** +``` +### References +- [DC] getting-started/installation.md +- [KG] administration/setup.md +``` + +### URLs Mode +Uses website URLs in query response citations: +```bash +python load_docs.py docs/ --mode urls --base-url https://docs.apolo.us/index/ +python load_docs.py docs/ --mode urls --base-url https://my-docs.com/v1/ +``` + +**Query Response Example:** +``` +### References +- [DC] https://docs.apolo.us/index/getting-started/installation +- [KG] https://docs.apolo.us/index/administration/setup +``` + +**⚠️ Important for URLs Mode**: Your local file structure must match your documentation site's URL structure for proper link generation. + +**File Structure Requirements:** +``` +docs/ +├── getting-started/ +│ ├── installation.md → https://docs.example.com/getting-started/installation +│ └── first-steps.md → https://docs.example.com/getting-started/first-steps +├── administration/ +│ ├── README.md → https://docs.example.com/administration +│ └── setup.md → https://docs.example.com/administration/setup +└── README.md → https://docs.example.com/ +``` + +**URL Mapping Rules:** +- `.md` extension is removed from URLs +- `README.md` files map to their directory URL +- Subdirectories become URL path segments +- Hyphens and underscores in filenames are preserved + +### Organizing Docs for URL Mode + +**Step 1: Analyze Your Documentation Site Structure** +```bash +# Visit your docs site and note the URL patterns: +# https://docs.example.com/getting-started/installation +# https://docs.example.com/api/authentication +# https://docs.example.com/guides/deployment +``` + +**Step 2: Create Matching Directory Structure** +```bash +mkdir -p docs/{getting-started,api,guides} +``` + +**Step 3: Organize Your Markdown Files** +```bash +# Match each URL to a file path: +docs/getting-started/installation.md # → /getting-started/installation +docs/api/authentication.md # → /api/authentication +docs/guides/deployment.md # → /guides/deployment +docs/guides/README.md # → /guides (overview page) +``` + +**Step 4: Verify URL Mapping** +```bash +# Test a few URLs manually to ensure they work: +curl -I https://docs.example.com/getting-started/installation +curl -I https://docs.example.com/api/authentication +``` + +**Common Documentation Site Patterns:** + +| Site Type | File Structure | URL Structure | +|-----------|---------------|---------------| +| **GitBook** | `docs/section/page.md` | `/section/page` | +| **Docusaurus** | `docs/section/page.md` | `/docs/section/page` | +| **MkDocs** | `docs/section/page.md` | `/section/page/` | +| **Custom** | Varies | Match your site's pattern | + +**Real Example: Apolo Documentation** +```bash +# Apolo docs site: https://docs.apolo.us/index/ +# Your local structure should match: +apolo-docs/ +├── getting-started/ +│ ├── first-steps/ +│ │ ├── getting-started.md → /index/getting-started/first-steps/getting-started +│ │ └── README.md → /index/getting-started/first-steps +│ ├── apolo-base-docker-image.md → /index/getting-started/apolo-base-docker-image +│ └── faq.md → /index/getting-started/faq +├── apolo-console/ +│ └── getting-started/ +│ └── sign-up-login.md → /index/apolo-console/getting-started/sign-up-login +└── README.md → /index/ + +# Load with correct base URL: +python load_docs.py apolo-docs/ --mode urls --base-url https://docs.apolo.us/index/ +``` + +## Complete Usage Examples + +```bash +# Load Apolo documentation with URL references +python load_docs.py ../apolo-copilot/docs/official-apolo-documentation/docs \ + --mode urls --base-url https://docs.apolo.us/index/ + +# Load with custom LightRAG endpoint +python load_docs.py docs/ --endpoint https://lightrag.example.com + +# Load to local instance, skip test query +python load_docs.py docs/ --no-test + +# Files mode with custom endpoint +python load_docs.py docs/ --mode files --endpoint http://localhost:9621 +``` + +## Features + +- **Dual Reference Modes**: File paths or live website URLs in citations +- **Flexible Base URL**: Works with any documentation site structure +- **Simple dependency**: Only requires `httpx` and Python standard library +- **Automatic discovery**: Finds all `.md` files recursively +- **Smart metadata**: Adds appropriate title, path/URL, and source information +- **Progress tracking**: Shows loading progress with success/failure counts +- **Health checks**: Verifies LightRAG connectivity before loading +- **Test queries**: Validates functionality after loading +- **Error handling**: Clear validation and error messages + +## Requirements + +```bash +pip install httpx +``` + +## Use Cases + +This loader is perfect for: +- **Kubernetes deployments**: Self-contained with minimal dependencies +- **Quick testing**: Immediate setup without complex environments +- **Documentation loading**: Any markdown-based documentation +- **Development workflows**: Fast iteration and testing + +## Requirements + +```bash +pip install httpx +``` + +**Note**: This script is included with LightRAG deployments and provides a simple way to load any markdown documentation into your LightRAG instance. \ No newline at end of file diff --git a/blueprints/KUBERNETES_DEPLOYMENT.md b/blueprints/KUBERNETES_DEPLOYMENT.md new file mode 100644 index 00000000..9fbc8190 --- /dev/null +++ b/blueprints/KUBERNETES_DEPLOYMENT.md @@ -0,0 +1,506 @@ +# LightRAG Kubernetes Deployment Guide + +**Complete guide for deploying LightRAG minimal stack to Kubernetes clusters** + +## 📋 Overview + +This guide provides a production-ready approach to deploying LightRAG to Kubernetes using only Helm charts. This method has been validated and tested for reliability. + +**Key Features:** +- **Pure Helm deployment** - Everything managed through Helm charts, no kubectl apply needed +- **Embedded PostgreSQL with pgvector** - Automatic setup using Bitnami PostgreSQL chart with pgvector image +- **Multiple environments** - Development and production configurations +- **Auto-scaling ready** - Built-in HPA configuration for production +- **Validated process** - Tested teardown/rebuild cycle confirms reliability + +## 🏗️ Architecture + +```mermaid +graph TD + subgraph "Kubernetes Cluster" + subgraph "lightrag Namespace" + A[LightRAG Deployment
gpt-4o model] + B[PostgreSQL StatefulSet
pgvector/pgvector:pg16] + C[Services & ConfigMaps] + D[PersistentVolumes] + E[Secrets & API Keys] + end + end + + F[Helm Chart Management] + G[External Access] + H[OpenAI API] + + F --> A + F --> B + A --> B + A --> H + C --> G + + style A fill:#e1f5fe + style B fill:#f3e5f5 + style F fill:#e8f5e8 +``` + +## 📦 Prerequisites + +### Required Components +- **Kubernetes cluster** (1.19+) - Minikube, EKS, GKE, AKS, or on-premises +- **Helm** (3.0+) with Bitnami repository added +- **kubectl** configured for your target cluster +- **OpenAI API key** for LLM and embedding services + +### Cluster Requirements +- **Minimum resources**: 2 CPU cores, 4Gi memory available +- **Storage class** supporting ReadWriteOnce volumes (standard class works) +- **Container registry access** to ghcr.io and docker.io + +### Local Development Setup (Minikube) +```bash +# Start Minikube with sufficient resources +minikube start --cpus=4 --memory=8192 --disk-size=20g + +# Verify cluster +kubectl cluster-info +kubectl get nodes +``` + +## 🚀 Deployment Process + +### Step 1: Environment Preparation + +```bash +# Navigate to deployment directory +cd LightRAG/k8s-deploy/lightrag-minimal + +# Verify Helm repositories +helm repo add bitnami https://charts.bitnami.com/bitnami +helm repo update + +# Update chart dependencies +helm dependency update + +# Set your OpenAI API key +export OPENAI_API_KEY="your-api-key-here" +``` + +### Step 2: Deploy for Development (Minikube/Local) + +```bash +# Substitute environment variables in values file +envsubst < values-dev.yaml > values-dev-final.yaml + +# Deploy the complete stack +helm install lightrag-minimal . \ + -f values-dev-final.yaml \ + --namespace lightrag \ + --create-namespace + +# Wait for PostgreSQL to be ready +kubectl wait --namespace lightrag \ + --for=condition=ready pod \ + -l app.kubernetes.io/name=postgresql \ + --timeout=120s + +# Wait for LightRAG to be ready +kubectl wait --namespace lightrag \ + --for=condition=ready pod \ + -l app.kubernetes.io/name=lightrag-minimal \ + --timeout=120s + +# Clean up temporary file +rm values-dev-final.yaml + +# Start port forwarding for access +kubectl port-forward --namespace lightrag svc/lightrag-minimal 9621:9621 & +``` + +**Access Methods:** +- **Web UI**: http://localhost:9621/webui +- **API Docs**: http://localhost:9621/docs +- **Health Check**: http://localhost:9621/health + +### Step 3: Deploy for Production + +```bash +# First, customize production values +# Edit values-prod.yaml to set: +# - Your domain name (lightrag.yourdomain.com) +# - Storage classes (fast-ssd) +# - Secure passwords +# - Resource limits based on your needs + +# Substitute environment variables +envsubst < values-prod.yaml > values-prod-final.yaml + +# Deploy with production configuration +helm install lightrag-minimal . \ + -f values-prod-final.yaml \ + --namespace lightrag \ + --create-namespace + +# Wait for deployment completion +kubectl wait --namespace lightrag \ + --for=condition=ready pod \ + -l app.kubernetes.io/name=lightrag-minimal \ + --timeout=300s + +# Clean up temporary file +rm values-prod-final.yaml +``` + +**Access:** Via ingress at your configured domain (e.g., https://lightrag.yourdomain.com/webui) + +## 🔧 Configuration Files + +### Available Values Files + +| File | Purpose | Resources | Use Case | +|------|---------|-----------|----------| +| `values.yaml` | Default base | Medium | Testing | +| `values-dev.yaml` | Development | Small (1 CPU, 2Gi) | Local/Minikube | +| `values-prod.yaml` | Production | Large (4 CPU, 8Gi) | Production clusters | + +### Key Configuration Options + +#### Development (values-dev.yaml) +```yaml +# Small resources for local development +resources: + limits: + cpu: 1000m + memory: 2Gi + +# Smaller storage +persistence: + ragStorage: + size: 5Gi + +# Embedded PostgreSQL with pgvector +postgresql: + image: + repository: pgvector/pgvector + tag: pg16 + +# No ingress (use port-forward) +ingress: + enabled: false +``` + +#### Production (values-prod.yaml) +```yaml +# Production resources +resources: + limits: + cpu: 4000m + memory: 8Gi + +# Large storage with fast storage class +persistence: + ragStorage: + size: 100Gi + storageClass: "fast-ssd" + +# Ingress with TLS +ingress: + enabled: true + hosts: + - host: lightrag.yourdomain.com + +# Auto-scaling +autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 10 +``` + +## 📊 Deployment Verification + +### Check Deployment Status +```bash +# Check all deployed resources +kubectl get all --namespace lightrag + +# Verify persistent volumes are bound +kubectl get pvc --namespace lightrag + +# Check pod logs for any issues +kubectl logs --namespace lightrag -l app.kubernetes.io/name=lightrag-minimal +``` + +### Test System Health +```bash +# Start port forwarding (for development) +kubectl port-forward --namespace lightrag svc/lightrag-minimal 9621:9621 & + +# Test health endpoint +curl http://localhost:9621/health + +# Expected healthy response: +{ + "status": "healthy", + "configuration": { + "llm_model": "gpt-4o", + "kv_storage": "PGKVStorage", + "vector_storage": "PGVectorStorage", + "graph_storage": "NetworkXStorage" + } +} + +# Test document upload endpoint +curl http://localhost:9621/documents + +# Expected response: +{ + "documents": 0, + "message": "Ready for document upload" +} +``` + +### View Logs +```bash +# LightRAG logs +kubectl logs --namespace lightrag -l app.kubernetes.io/name=lightrag-minimal -f + +# PostgreSQL logs +kubectl logs --namespace lightrag -l app.kubernetes.io/name=postgresql -f +``` + +## 📚 Load Documentation + +After successful deployment, load your documentation into LightRAG using the advanced documentation loader with dual reference modes: + +### Using the Enhanced Documentation Loader + +LightRAG includes an advanced documentation loader with flexible reference modes: + +```bash +# Ensure port forwarding is active +kubectl port-forward --namespace lightrag svc/lightrag-minimal 9621:9621 & + +# Files Mode (Default) - Uses file paths in citations +python load_docs.py /path/to/your/docs + +# URLs Mode - Uses website URLs in citations (recommended for public docs) +python load_docs.py /path/to/docs --mode urls --base-url https://docs.example.com/ + +# Load Apolo documentation with URL references +python load_docs.py /path/to/apolo-docs --mode urls --base-url https://docs.apolo.us/index/ + +# Load with custom endpoint +python load_docs.py /path/to/docs --endpoint https://lightrag.yourdomain.com + +# Skip test query after loading +python load_docs.py /path/to/docs --no-test +``` + +### Reference Mode Benefits + +**Files Mode (Default):** +- Uses local file paths in query response references +- Good for internal documentation or development +- Example: `[DC] getting-started/installation.md` + +**URLs Mode:** +- Uses live website URLs in query response references +- Provides clickable links in responses +- Better user experience with direct access to source material +- Example: `[DC] https://docs.apolo.us/index/getting-started/installation` + +### ⚠️ File Structure Requirements for URL Mode + +**Critical**: Your local file structure must exactly match your documentation site's URL structure. + +**Example Mapping:** +``` +# Local file structure → Website URLs +docs/getting-started/installation.md → https://docs.example.com/getting-started/installation +docs/api/README.md → https://docs.example.com/api +docs/guides/deployment.md → https://docs.example.com/guides/deployment +``` + +**Setup Instructions:** +1. **Analyze your docs site URLs** - Note the exact path structure +2. **Create matching directories** - Mirror the URL structure locally +3. **Place files correctly** - Remove `.md` from URL paths to match filenames +4. **Test URLs** - Verify a few links work before loading documents + +This ensures generated URLs in query responses are valid and clickable. + +### Loader Features + +- **Simple dependencies**: Only requires `httpx` +- **Automatic discovery**: Finds all `.md` files recursively +- **Basic metadata**: Adds title, path, and source information +- **Progress tracking**: Shows loading progress with success/failure counts +- **Health checks**: Verifies LightRAG connectivity before loading +- **Test queries**: Validates functionality after loading + +### Expected Output +``` +🚀 Loading Documentation into LightRAG +============================================================ +📁 Documentation path: /path/to/docs +🌐 LightRAG endpoint: http://localhost:9621 + +✅ LightRAG is healthy: healthy +📚 Found 25 markdown files +📊 Total content: 150,000 characters +📊 Average length: 6,000 characters + +🔄 Starting to load documents... +✅ Loaded: Getting Started +✅ Loaded: Installation Guide +✅ Loaded: API Reference +... (25 documents total) +📈 Progress: 20/25 (20 success, 0 failed) + +✅ Loading complete! +📊 Successful: 25 +📊 Failed: 0 + +🧪 Testing query... +✅ Query successful! +Response: This documentation covers... +``` + +### Verify Documentation Loading +```bash +# Check document count +curl http://localhost:9621/documents | jq '.documents | length' + +# Test a sample query +curl -X POST http://localhost:9621/query \ + -H "Content-Type: application/json" \ + -d '{"query": "How do I get started?", "mode": "hybrid"}' +``` + +## 🔄 Management Commands + +### Scaling +```bash +# Manual scaling +kubectl scale deployment lightrag-minimal --replicas=3 --namespace lightrag + +# Update resources +helm upgrade lightrag-minimal . \ + -f values-dev-final.yaml \ + --set resources.limits.cpu=2000m \ + --namespace lightrag +``` + +### Updates +```bash +# Update to latest image +helm upgrade lightrag-minimal . \ + -f values-dev-final.yaml \ + --set image.tag=latest \ + --namespace lightrag + +# Rolling restart +kubectl rollout restart deployment/lightrag-minimal --namespace lightrag +``` + +### Cleanup +```bash +# Uninstall release +helm uninstall lightrag-minimal --namespace lightrag + +# Remove namespace +kubectl delete namespace lightrag +``` + +## 🚨 Troubleshooting + +### Common Issues + +**Issue: Pod CrashLoopBackOff** +```bash +# Check logs +kubectl logs --namespace lightrag -l app.kubernetes.io/name=lightrag-minimal + +# Check PostgreSQL +kubectl logs --namespace lightrag -l app.kubernetes.io/name=postgresql +``` + +**Issue: pgvector extension missing** +```bash +# Check if extension was created automatically +kubectl exec --namespace lightrag \ + $(kubectl get pod -l app.kubernetes.io/name=postgresql -o jsonpath='{.items[0].metadata.name}') \ + -- psql -U lightrag_user -d lightrag -c "SELECT * FROM pg_extension WHERE extname='vector';" +``` + +**Issue: Storage issues** +```bash +# Check PVCs +kubectl get pvc --namespace lightrag + +# Check storage class +kubectl get storageclass +``` + +### Support Commands +```bash +# Describe problematic pod +kubectl describe pod --namespace lightrag -l app.kubernetes.io/name=lightrag-minimal + +# Check events +kubectl get events --namespace lightrag --sort-by='.lastTimestamp' + +# Port forward for debugging +kubectl port-forward --namespace lightrag svc/lightrag-minimal 9621:9621 +``` + +## 🎯 Advantages of This Approach + +✅ **Pure Helm** - No manual kubectl apply commands +✅ **Integrated PostgreSQL** - Bitnami chart handles all PostgreSQL complexity +✅ **pgvector Support** - Automatic extension creation via initdb scripts +✅ **Environment Flexibility** - Separate values files for dev/prod +✅ **Production Ready** - Built-in scaling, security, monitoring hooks +✅ **Clean Management** - Easy updates, rollbacks, and cleanup +✅ **Persistent Storage** - Data survives pod restarts and cluster updates + +## 📁 Final Directory Structure + +``` +lightrag-minimal/ +├── Chart.yaml # Helm chart metadata +├── Chart.lock # Dependency lock file +├── charts/ # Downloaded dependencies (PostgreSQL) +├── templates/ # Kubernetes manifests templates +├── values.yaml # Default configuration +├── values-dev.yaml # Development settings +├── values-prod.yaml # Production settings +└── README.md # Chart documentation +``` + +## ✅ Deployment Validation + +This deployment process has been thoroughly validated through complete teardown and rebuild cycles: + +### Validation Process +1. **Complete Teardown**: `helm uninstall` + `kubectl delete namespace` +2. **Clean Rebuild**: Fresh deployment from scratch using only Helm +3. **Functionality Testing**: Health checks, API endpoints, document loading +4. **Resource Verification**: All pods running, PVCs bound, services accessible + +### Validated Components +- ✅ **Pure Helm Deployment** - No manual kubectl apply commands needed +- ✅ **PostgreSQL with pgvector** - Automatic extension creation via initdb scripts +- ✅ **Resource Management** - Proper CPU/memory limits and persistent storage +- ✅ **API Functionality** - Health, document upload, and query endpoints working +- ✅ **Documentation Loading** - Successful loading of markdown documentation files + +### Test Results +```bash +# Deployment Status: ✅ SUCCESS +📊 LightRAG: healthy, gpt-4o model configured +📊 PostgreSQL: running with pgvector extension +📊 Storage: 3 PVCs bound (12Gi total) +📊 API: All endpoints responding correctly +📊 Documentation: Ready for loading with included loader script +``` + +This approach provides a production-ready, maintainable solution for deploying LightRAG to any Kubernetes cluster with confidence in its reliability and repeatability. \ No newline at end of file diff --git a/blueprints/REPORT.md b/blueprints/REPORT.md new file mode 100644 index 00000000..502b85e5 --- /dev/null +++ b/blueprints/REPORT.md @@ -0,0 +1,438 @@ +# LightRAG Storage Stack Configurations Report + +## Executive Summary + +LightRAG supports a modular storage architecture with 4 distinct storage types that can be mixed and matched: +- **Graph Storage**: Knowledge graph relationships +- **Vector Storage**: Document embeddings +- **KV Storage**: Key-value pairs and metadata +- **Document Status Storage**: Document processing status + +This report analyzes 25+ storage implementations across 8 database technologies to provide recommendations for different use cases. + +## Storage Architecture Overview + +### Storage Types & Available Implementations + +| Storage Type | Implementations | Count | +|--------------|----------------|-------| +| **Graph Storage** | NetworkXStorage, Neo4JStorage, PGGraphStorage, AGEStorage¹, MongoGraphStorage¹ | 5 | +| **Vector Storage** | NanoVectorDBStorage, MilvusVectorDBStorage, ChromaVectorDBStorage, PGVectorStorage, FaissVectorDBStorage, QdrantVectorDBStorage, MongoVectorDBStorage | 7 | +| **KV Storage** | JsonKVStorage, RedisKVStorage, PGKVStorage, MongoKVStorage | 4 | +| **Doc Status Storage** | JsonDocStatusStorage, PGDocStatusStorage, MongoDocStatusStorage | 3 | + +¹ *Currently commented out in production* + +## Database Technology Analysis + +### 1. PostgreSQL + pgvector +**Implementations**: PGVectorStorage, PGKVStorage, PGGraphStorage, PGDocStatusStorage + +**Strengths:** +- ✅ **Unified Database**: Single database for all storage types +- ✅ **ACID Compliance**: Full transactional support +- ✅ **Mature Ecosystem**: Well-established, enterprise-ready +- ✅ **Minimal**: Single database to maintain +- ✅ **pgvector Extension**: Native vector operations with good performance +- ✅ **SQL Familiarity**: Easy to query and debug + +**Weaknesses:** +- ❌ **Graph Limitations**: Requires AGE extension for advanced graph operations +- ❌ **Vector Performance**: Good but not specialized vector database performance +- ❌ **Single Point of Failure**: All data in one database + +**Configuration:** +```yaml +LIGHTRAG_KV_STORAGE: PGKVStorage +LIGHTRAG_VECTOR_STORAGE: PGVectorStorage +LIGHTRAG_DOC_STATUS_STORAGE: PGDocStatusStorage +LIGHTRAG_GRAPH_STORAGE: PGGraphStorage # Requires AGE extension +``` + +### 2. Neo4j (Graph Specialist) +**Implementations**: Neo4JStorage + +**Strengths:** +- ✅ **Graph Optimization**: Purpose-built for graph operations +- ✅ **Advanced Graph Analytics**: Complex graph algorithms built-in +- ✅ **Cypher Query Language**: Powerful graph query capabilities +- ✅ **Scalability**: Excellent for large, complex graphs +- ✅ **Visualization**: Rich graph visualization tools + +**Weaknesses:** +- ❌ **Graph Only**: Requires additional databases for vectors/KV +- ❌ **Complexity**: More complex setup and maintenance +- ❌ **Cost**: Enterprise features require licensing +- ❌ **Memory Usage**: Can be memory-intensive + +**Typical Configuration:** +```yaml +LIGHTRAG_GRAPH_STORAGE: Neo4JStorage +LIGHTRAG_VECTOR_STORAGE: MilvusVectorDBStorage # Or Qdrant +LIGHTRAG_KV_STORAGE: RedisKVStorage +LIGHTRAG_DOC_STATUS_STORAGE: PGDocStatusStorage +``` + +### 3. Milvus (Vector Specialist) +**Implementations**: MilvusVectorDBStorage + +**Strengths:** +- ✅ **Vector Performance**: Optimized for high-performance vector search +- ✅ **Scalability**: Designed for billion-scale vector collections +- ✅ **Multiple Indexes**: Various indexing algorithms (IVF, HNSW, etc.) +- ✅ **GPU Support**: CUDA acceleration for vector operations +- ✅ **Cloud Native**: Kubernetes-ready architecture + +**Weaknesses:** +- ❌ **Complexity**: Complex distributed architecture +- ❌ **Resource Usage**: High memory and compute requirements +- ❌ **Overkill**: May be excessive for smaller datasets +- ❌ **Dependencies**: Requires etcd and MinIO for full deployment + +**Typical Configuration:** +```yaml +LIGHTRAG_VECTOR_STORAGE: MilvusVectorDBStorage +LIGHTRAG_GRAPH_STORAGE: Neo4JStorage +LIGHTRAG_KV_STORAGE: RedisKVStorage +LIGHTRAG_DOC_STATUS_STORAGE: MongoDocStatusStorage +``` + +### 4. Qdrant (Vector Specialist) +**Implementations**: QdrantVectorDBStorage + +**Strengths:** +- ✅ **Performance**: High-performance vector search with Rust backend +- ✅ **Simplicity**: Easier deployment than Milvus +- ✅ **Filtering**: Advanced payload filtering capabilities +- ✅ **API**: Rich REST and gRPC APIs +- ✅ **Memory Efficiency**: Lower memory footprint than Milvus + +**Weaknesses:** +- ❌ **Ecosystem**: Smaller ecosystem compared to alternatives +- ❌ **Vector Only**: Requires additional databases for other storage types + +### 5. MongoDB (Multi-Purpose) +**Implementations**: MongoKVStorage, MongoVectorDBStorage, MongoDocStatusStorage + +**Strengths:** +- ✅ **Flexibility**: Schema-less document storage +- ✅ **Vector Search**: Native vector search capabilities (Atlas Search) +- ✅ **Multi-Purpose**: Can handle KV, vectors, and document status +- ✅ **Scalability**: Horizontal scaling with sharding +- ✅ **Developer Friendly**: Easy to work with JSON documents + +**Weaknesses:** +- ❌ **Graph Limitations**: Not optimized for graph operations +- ❌ **Vector Performance**: Vector search not as optimized as specialists +- ❌ **Memory Usage**: Can be memory-intensive for large datasets + +### 6. Redis (KV Specialist) +**Implementations**: RedisKVStorage + +**Strengths:** +- ✅ **Speed**: In-memory performance for KV operations +- ✅ **Simplicity**: Simple key-value operations +- ✅ **Data Structures**: Rich data structures (lists, sets, hashes) +- ✅ **Caching**: Excellent for caching and session storage + +**Weaknesses:** +- ❌ **Memory Bound**: Limited by available RAM +- ❌ **KV Only**: Only suitable for key-value storage +- ❌ **Persistence**: Data persistence requires configuration + +### 7. Local File Storage +**Implementations**: NetworkXStorage, JsonKVStorage, JsonDocStatusStorage, NanoVectorDBStorage, FaissVectorDBStorage + +**Strengths:** +- ✅ **Simplicity**: No external dependencies +- ✅ **Development**: Perfect for development and testing +- ✅ **Portability**: Easy to backup and move +- ✅ **Cost**: No infrastructure costs + +**Weaknesses:** +- ❌ **Scalability**: Limited by single machine resources +- ❌ **Concurrency**: No built-in concurrent access +- ❌ **Performance**: Limited performance for large datasets +- ❌ **Reliability**: Single point of failure + +### 8. ChromaDB (Vector Specialist) +**Implementations**: ChromaVectorDBStorage + +**Strengths:** +- ✅ **Simplicity**: Easy to deploy and use +- ✅ **Python Native**: Built for Python ML workflows +- ✅ **Metadata**: Rich metadata filtering capabilities +- ✅ **Local/Distributed**: Can run locally or distributed + +**Weaknesses:** +- ❌ **Performance**: Slower than Milvus/Qdrant for large scales +- ❌ **Maturity**: Newer project with evolving feature set + +## Recommended Stack Configurations + +### 1. 🏆 **Production High-Performance Stack** +**Best for**: Large-scale production deployments, complex graph analytics + +```yaml +LIGHTRAG_GRAPH_STORAGE: Neo4JStorage +LIGHTRAG_VECTOR_STORAGE: MilvusVectorDBStorage +LIGHTRAG_KV_STORAGE: RedisKVStorage +LIGHTRAG_DOC_STATUS_STORAGE: PGDocStatusStorage +``` + +**Services Required:** +- Neo4j (Graph operations) +- Milvus + etcd + MinIO (Vector search) +- Redis (KV cache) +- PostgreSQL (Document status) + +**Pros**: Maximum performance, specialized for each data type +**Cons**: High complexity, resource intensive, expensive + +```mermaid +graph LR + LightRAG_App["LightRAG Application"] + Neo4j_Service["Neo4j Service"] + Milvus_Cluster["Milvus Cluster (Milvus, etcd, MinIO)"] + Redis_Service["Redis Service"] + PostgreSQL_Service["PostgreSQL Service"] + + LightRAG_App --> |Graph Storage| Neo4j_Service + LightRAG_App --> |Vector Storage| Milvus_Cluster + LightRAG_App --> |KV Storage| Redis_Service + LightRAG_App --> |Doc Status Storage| PostgreSQL_Service +``` + +### 2. 🎯 **Production Balanced Stack** +**Best for**: Production deployments prioritizing simplicity + +```yaml +LIGHTRAG_GRAPH_STORAGE: NetworkXStorage +LIGHTRAG_VECTOR_STORAGE: QdrantVectorDBStorage +LIGHTRAG_KV_STORAGE: RedisKVStorage +LIGHTRAG_DOC_STATUS_STORAGE: PGDocStatusStorage +``` + +**Services Required:** +- Qdrant (Vector search) +- Redis (KV cache) +- PostgreSQL (Document status) +- File system (Graph storage) + +**Pros**: Good performance, simpler than full specialist stack +**Cons**: Graph operations limited by file-based storage + +```mermaid +graph LR + subgraph "LightRAG Application Environment" + LightRAG_App["LightRAG Application"] + NetworkX["NetworkX Graph Storage (Local FS)"] + LightRAG_App -.-> NetworkX + end + Qdrant_Service["Qdrant Service"] + Redis_Service["Redis Service"] + PostgreSQL_Service["PostgreSQL Service"] + + LightRAG_App --> |Vector Storage| Qdrant_Service + LightRAG_App --> |KV Storage| Redis_Service + LightRAG_App --> |Doc Status Storage| PostgreSQL_Service +``` + +### 3. 💰 **Production Minimal Stack** +**Best for**: Budget-conscious production deployments + +```yaml +LIGHTRAG_GRAPH_STORAGE: NetworkXStorage +LIGHTRAG_VECTOR_STORAGE: PGVectorStorage +LIGHTRAG_KV_STORAGE: PGKVStorage +LIGHTRAG_DOC_STATUS_STORAGE: PGDocStatusStorage +``` + +**Services Required:** +- PostgreSQL + pgvector (All storage except graph) +- File system (Graph storage) + +**Pros**: Single database, low cost, good for medium scale +**Cons**: Not optimized for very large datasets or complex graphs + +```mermaid +graph LR + subgraph "LightRAG Application Environment" + LightRAG_App["LightRAG Application"] + NetworkX["NetworkX Graph Storage (Local FS)"] + LightRAG_App -.-> NetworkX + end + PostgreSQL_Service["PostgreSQL Service (+pgvector)"] + + LightRAG_App --> |Vector Storage| PostgreSQL_Service + LightRAG_App --> |KV Storage| PostgreSQL_Service + LightRAG_App --> |Doc Status Storage| PostgreSQL_Service +``` + +### 4. 🚀 **Development & Testing Stack** +**Best for**: Local development, testing, small deployments + +```yaml +LIGHTRAG_GRAPH_STORAGE: NetworkXStorage +LIGHTRAG_VECTOR_STORAGE: NanoVectorDBStorage +LIGHTRAG_KV_STORAGE: JsonKVStorage +LIGHTRAG_DOC_STATUS_STORAGE: JsonDocStatusStorage +``` + +**Services Required:** +- None (all file-based) + +**Pros**: Zero infrastructure, fast setup, portable +**Cons**: Limited scalability and performance + +```mermaid +graph LR + subgraph "LightRAG Application (Local Process)" + LightRAG_App["LightRAG App"] + NetworkX["NetworkX (File System)"] + NanoVectorDB["NanoVectorDB (File System)"] + JsonKV["JsonKVStorage (File System)"] + JsonDocStatus["JsonDocStatusStorage (File System)"] + + LightRAG_App -.-> |Graph| NetworkX + LightRAG_App -.-> |Vector| NanoVectorDB + LightRAG_App -.-> |KV| JsonKV + LightRAG_App -.-> |Doc Status| JsonDocStatus + end +``` + +### 5. 🐳 **Docker All-in-One Stack** +**Best for**: Containerized deployments, cloud environments + +```yaml +LIGHTRAG_GRAPH_STORAGE: Neo4JStorage +LIGHTRAG_VECTOR_STORAGE: QdrantVectorDBStorage +LIGHTRAG_KV_STORAGE: RedisKVStorage +LIGHTRAG_DOC_STATUS_STORAGE: MongoDocStatusStorage +``` + +**Services Required:** +- Neo4j (Graph) +- Qdrant (Vector) +- Redis (KV) +- MongoDB (Document status) + +**Pros**: Cloud-native, each service containerized +**Cons**: More services to manage + +```mermaid +graph LR + subgraph "Docker Environment (e.g., Docker Compose)" + LightRAG_Container["LightRAG App (Container)"] + Neo4j_Container["Neo4j (Container)"] + Qdrant_Container["Qdrant (Container)"] + Redis_Container["Redis (Container)"] + MongoDB_Container["MongoDB (Container)"] + end + LightRAG_Container --> |Graph Storage| Neo4j_Container + LightRAG_Container --> |Vector Storage| Qdrant_Container + LightRAG_Container --> |KV Storage| Redis_Container + LightRAG_Container --> |Doc Status Storage| MongoDB_Container +``` + +## Performance Comparison + +### Vector Search Performance (Approximate) +| Implementation | Small (1K docs) | Medium (100K docs) | Large (1M+ docs) | Memory Usage | +|---------------|-----------------|--------------------|-----------------|--------------| +| MilvusVectorDB | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | High | +| QdrantVectorDB | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | Medium | +| PGVectorStorage | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | Medium | +| ChromaVectorDB | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | Medium | +| FaissVectorDB | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | Low | +| NanoVectorDB | ⭐⭐⭐ | ⭐⭐ | ⭐ | Low | + +### Graph Operations Performance +| Implementation | Node Queries | Edge Traversal | Complex Analytics | Scalability | +|---------------|--------------|----------------|------------------|-------------| +| Neo4JStorage | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| PGGraphStorage | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | +| NetworkXStorage | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ | + +### KV Operations Performance +| Implementation | Read Speed | Write Speed | Concurrency | Persistence | +|---------------|------------|-------------|-------------|-------------| +| RedisKVStorage | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | +| PGKVStorage | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| MongoKVStorage | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| JsonKVStorage | ⭐⭐ | ⭐⭐ | ⭐ | ⭐⭐⭐⭐⭐ | + +## Deployment Considerations + +### Resource Requirements + +| Configuration | CPU | Memory | Storage | Network | +|--------------|-----|--------|---------|---------| +| Development Stack | 2 cores | 4GB | 10GB | Minimal | +| Minimal Stack | 4 cores | 8GB | 50GB | Medium | +| Balanced Stack | 8 cores | 16GB | 100GB | High | +| High-Performance Stack | 16+ cores | 32GB+ | 500GB+ | Very High | + +### Maintenance Complexity + +| Stack Type | Setup Complexity | Operational Overhead | Monitoring | Backup Strategy | +|-----------|------------------|---------------------|------------|-----------------| +| Development | ⭐ | ⭐ | ⭐ | Simple | +| Minimal | ⭐⭐ | ⭐⭐ | ⭐⭐ | Medium | +| Balanced | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | Complex | +| High-Performance | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | Very Complex | + +## Migration Paths + +### Development → Production +1. Start with Development Stack (all file-based) +2. Migrate to Minimal Stack (PostgreSQL-based) +3. Scale to Balanced Stack (add specialized vector DB) +4. Optimize with High-Performance Stack (full specialization) + +### Data Migration Tools +- **Database-specific**: Use native tools (pg_dump, neo4j-admin, etc.) +- **LightRAG native**: Built-in export/import capabilities +- **Cross-platform**: JSON export for universal compatibility + +## Recommendations by Use Case + +### 📚 **Documentation/Knowledge Base** +- **Small (<10K docs)**: Development Stack +- **Medium (<100K docs)**: Minimal Stack +- **Large (>100K docs)**: Balanced Stack + +### 🔬 **Research/Analytics** +- **Graph-heavy**: High-Performance Stack with Neo4j +- **Vector-heavy**: Balanced Stack with Milvus +- **Mixed workload**: Balanced Stack + +### 💼 **Enterprise** +- **High Availability**: High-Performance Stack with clustering +- **Budget Conscious**: Minimal Stack with PostgreSQL +- **Regulatory**: On-premises with full control + +### 🚀 **Startups/SMBs** +- **MVP**: Development Stack +- **Growing**: Minimal Stack +- **Scaling**: Balanced Stack + +## Conclusion + +The **Minimal Stack** (PostgreSQL + NetworkX) provides the best balance of performance, complexity, and cost for most use cases. It offers: + +- ✅ Production-ready reliability +- ✅ Reasonable performance for medium-scale deployments +- ✅ Low operational overhead +- ✅ Clear upgrade path to specialized components + +For specialized needs: +- **High graph complexity** → Add Neo4j +- **High vector performance** → Add Qdrant/Milvus +- **High concurrency KV** → Add Redis + +The modular architecture allows gradual optimization based on actual performance bottlenecks rather than premature optimization. + +--- + +*Report generated based on LightRAG v1.3.7 implementation analysis* \ No newline at end of file diff --git a/deploy-stacks.sh b/deploy-stacks.sh new file mode 100755 index 00000000..4c6fc3b5 --- /dev/null +++ b/deploy-stacks.sh @@ -0,0 +1,217 @@ +#!/bin/bash +# Deployment script for LightRAG stack configurations + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if .env file exists +check_env_file() { + if [ ! -f .env ]; then + print_warning ".env file not found. Creating from env.example..." + if [ -f env.example ]; then + cp env.example .env + print_warning "Please update .env with your API keys before deployment!" + else + print_error "env.example file not found!" + exit 1 + fi + fi +} + +# Create necessary directories +create_directories() { + print_status "Creating necessary directories..." + mkdir -p data/inputs + mkdir -p data/rag_storage + mkdir -p data/dev-storage + print_success "Directories created" +} + +# Deploy specific stack +deploy_stack() { + local stack=$1 + local compose_file="docker-compose.${stack}.yml" + + if [ ! -f "$compose_file" ]; then + print_error "Compose file $compose_file not found!" + return 1 + fi + + print_status "Deploying $stack stack..." + + # Stop any existing containers + docker-compose -f "$compose_file" down 2>/dev/null || true + + # Start the stack + docker-compose -f "$compose_file" up -d + + if [ $? -eq 0 ]; then + print_success "$stack stack deployed successfully!" + + # Show running services + echo "" + print_status "Running services:" + docker-compose -f "$compose_file" ps + + # Wait a bit for services to start + sleep 5 + + # Check LightRAG health + print_status "Checking LightRAG health..." + for i in {1..30}; do + if curl -s http://localhost:9621/health > /dev/null 2>&1; then + print_success "LightRAG is healthy and ready!" + echo "" + echo "🌐 Web UI: http://localhost:9621/webui" + echo "📖 API Docs: http://localhost:9621/docs" + echo "💚 Health Check: http://localhost:9621/health" + return 0 + fi + echo -n "." + sleep 2 + done + + print_warning "LightRAG health check timed out. Check logs with:" + echo "docker-compose -f $compose_file logs lightrag" + else + print_error "Failed to deploy $stack stack!" + return 1 + fi +} + +# Stop stack +stop_stack() { + local stack=$1 + local compose_file="docker-compose.${stack}.yml" + + if [ ! -f "$compose_file" ]; then + print_error "Compose file $compose_file not found!" + return 1 + fi + + print_status "Stopping $stack stack..." + docker-compose -f "$compose_file" down + print_success "$stack stack stopped" +} + +# Clean up stack (stop and remove volumes) +cleanup_stack() { + local stack=$1 + local compose_file="docker-compose.${stack}.yml" + + if [ ! -f "$compose_file" ]; then + print_error "Compose file $compose_file not found!" + return 1 + fi + + print_warning "This will remove all data for $stack stack. Are you sure? (y/N)" + read -r response + if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then + print_status "Cleaning up $stack stack..." + docker-compose -f "$compose_file" down -v --remove-orphans + print_success "$stack stack cleaned up" + else + print_status "Cleanup cancelled" + fi +} + +# Show usage +show_usage() { + echo "Usage: $0 [stack]" + echo "" + echo "Commands:" + echo " deploy Deploy a specific stack" + echo " stop Stop a specific stack" + echo " cleanup Stop and remove all data for a stack" + echo " list List available stacks" + echo "" + echo "Available stacks:" + echo " development File-based storage (NetworkX + NanoVector + JSON)" + echo " minimal File-based storage (NetworkX + PostgreSQL)" + echo " balanced Mixed storage (NetworkX + Qdrant + Redis + PostgreSQL)" + echo " high-performance Specialized storage (Neo4j + Milvus + Redis + PostgreSQL)" + echo " all-in-one Cloud-native (Neo4j + Qdrant + Redis + MongoDB)" + echo "" + echo "Examples:" + echo " $0 deploy development" + echo " $0 stop Minimal" + echo " $0 cleanup high-performance" +} + +# List available stacks +list_stacks() { + print_status "Available LightRAG stack configurations:" + echo "" + echo "📚 development - File-based storage, perfect for development" + echo "💰 minimal - PostgreSQL-based, single database" + echo "🎯 balanced - Mixed storage, good performance/complexity balance" + echo "🏆 high-performance - Specialized databases, maximum performance" + echo "🐳 all-in-one - Cloud-native, containerized services" + echo "" + echo "Use '$0 deploy ' to deploy a configuration" +} + +# Main script logic +main() { + case "$1" in + deploy) + if [ -z "$2" ]; then + print_error "Please specify a stack to deploy" + show_usage + exit 1 + fi + check_env_file + create_directories + deploy_stack "$2" + ;; + stop) + if [ -z "$2" ]; then + print_error "Please specify a stack to stop" + show_usage + exit 1 + fi + stop_stack "$2" + ;; + cleanup) + if [ -z "$2" ]; then + print_error "Please specify a stack to cleanup" + show_usage + exit 1 + fi + cleanup_stack "$2" + ;; + list) + list_stacks + ;; + *) + show_usage + exit 1 + ;; + esac +} + +# Run main function with all arguments +main "$@" \ No newline at end of file diff --git a/docker-compose.all-in-one.yml b/docker-compose.all-in-one.yml new file mode 100644 index 00000000..506aacaa --- /dev/null +++ b/docker-compose.all-in-one.yml @@ -0,0 +1,148 @@ +version: '3.8' + +# Docker All-in-One Stack +# Neo4j + Qdrant + Redis + MongoDB +# Best for: Containerized deployments, cloud environments + +services: + # LightRAG Application + lightrag: + image: ghcr.io/hkuds/lightrag:latest + container_name: lightrag-aio + env_file: + - .env + environment: + # All-in-One Storage Configuration + LIGHTRAG_GRAPH_STORAGE: Neo4JStorage + LIGHTRAG_VECTOR_STORAGE: QdrantVectorDBStorage + LIGHTRAG_KV_STORAGE: RedisKVStorage + LIGHTRAG_DOC_STATUS_STORAGE: MongoDocStatusStorage + + # Service Connection Details + NEO4J_URI: bolt://neo4j:7687 + NEO4J_USERNAME: neo4j + NEO4J_PASSWORD: lightrag_neo4j_pass + + QDRANT_URL: http://qdrant:6333 + + REDIS_URI: redis://redis:6379 + + MONGO_URI: mongodb://lightrag_user:lightrag_pass@mongodb:27017/lightrag?authSource=admin + MONGO_DATABASE: lightrag + + # Performance settings + MAX_ASYNC: 6 + MAX_TOKENS: 32768 + ENABLE_LLM_CACHE: true + ENABLE_LLM_CACHE_FOR_EXTRACT: true + ports: + - "9621:9621" + depends_on: + mongodb: + condition: service_healthy + redis: + condition: service_healthy + neo4j: + condition: service_started + qdrant: + condition: service_healthy + volumes: + - ./data/inputs:/app/inputs + - ./data/rag_storage:/app/rag_storage + networks: + - lightrag-aio-network + restart: unless-stopped + + # MongoDB for Document Status Storage + mongodb: + image: mongo:7 + container_name: lightrag-aio-mongodb + environment: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: admin_pass + MONGO_INITDB_DATABASE: lightrag + ports: + - "27017:27017" + volumes: + - mongodb_data:/data/db + - ./mongo-init-aio:/docker-entrypoint-initdb.d + healthcheck: + test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok", "--quiet"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - lightrag-aio-network + restart: unless-stopped + + # Redis for KV Storage + redis: + image: redis:7-alpine + container_name: lightrag-aio-redis + command: redis-server --appendonly yes --maxmemory 1gb --maxmemory-policy allkeys-lru + ports: + - "6379:6379" + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - lightrag-aio-network + restart: unless-stopped + + # Neo4j for Graph Storage + neo4j: + image: neo4j:5.15 + container_name: lightrag-aio-neo4j + environment: + NEO4J_AUTH: neo4j/lightrag_neo4j_pass + NEO4J_PLUGINS: '["apoc"]' + NEO4J_dbms_security_procedures_unrestricted: apoc.* + NEO4J_dbms_memory_heap_initial__size: 512M + NEO4J_dbms_memory_heap_max__size: 1G + NEO4J_dbms_memory_pagecache_size: 512M + ports: + - "7474:7474" + - "7687:7687" + volumes: + - neo4j_data:/data + - neo4j_logs:/logs + networks: + - lightrag-aio-network + restart: unless-stopped + + # Qdrant Vector Database + qdrant: + image: qdrant/qdrant:latest + container_name: lightrag-aio-qdrant + environment: + QDRANT__SERVICE__HTTP_PORT: 6333 + QDRANT__SERVICE__GRPC_PORT: 6334 + QDRANT__LOG_LEVEL: INFO + ports: + - "6333:6333" + - "6334:6334" + volumes: + - qdrant_data:/qdrant/storage + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:6333/health"] + interval: 30s + timeout: 20s + retries: 3 + networks: + - lightrag-aio-network + restart: unless-stopped + +volumes: + mongodb_data: + redis_data: + neo4j_data: + neo4j_logs: + qdrant_data: + +networks: + lightrag-aio-network: + driver: bridge \ No newline at end of file diff --git a/docker-compose.balanced.yml b/docker-compose.balanced.yml new file mode 100644 index 00000000..579331ab --- /dev/null +++ b/docker-compose.balanced.yml @@ -0,0 +1,122 @@ +version: '3.8' + +# Production Balanced Stack +# NetworkX + Qdrant + Redis + PostgreSQL +# Best for: Production deployments prioritizing simplicity + +services: + # LightRAG Application + lightrag: + image: ghcr.io/hkuds/lightrag:latest + container_name: lightrag-balanced + env_file: + - .env + environment: + # Balanced Storage Configuration + LIGHTRAG_GRAPH_STORAGE: NetworkXStorage + LIGHTRAG_VECTOR_STORAGE: QdrantVectorDBStorage + LIGHTRAG_KV_STORAGE: RedisKVStorage + LIGHTRAG_DOC_STATUS_STORAGE: PGDocStatusStorage + + # Service Connection Details + QDRANT_URL: http://qdrant:6333 + + REDIS_URI: redis://redis:6379 + + POSTGRES_HOST: postgres + POSTGRES_PORT: 5432 + POSTGRES_USER: lightrag_user + POSTGRES_PASSWORD: lightrag_pass + POSTGRES_DATABASE: lightrag + + # Performance settings + MAX_ASYNC: 6 + MAX_TOKENS: 32768 + ENABLE_LLM_CACHE: true + ENABLE_LLM_CACHE_FOR_EXTRACT: true + ports: + - "9621:9621" + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + qdrant: + condition: service_healthy + volumes: + - ./data/inputs:/app/inputs + - ./data/rag_storage:/app/rag_storage + networks: + - lightrag-balanced-network + restart: unless-stopped + + # PostgreSQL for Document Status Storage + postgres: + image: postgres:16 + container_name: lightrag-balanced-postgres + environment: + POSTGRES_DB: lightrag + POSTGRES_USER: lightrag_user + POSTGRES_PASSWORD: lightrag_pass + POSTGRES_INITDB_ARGS: "--encoding=UTF-8" + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U lightrag_user -d lightrag"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - lightrag-balanced-network + restart: unless-stopped + + # Redis for KV Storage + redis: + image: redis:7-alpine + container_name: lightrag-balanced-redis + command: redis-server --appendonly yes --maxmemory 1gb --maxmemory-policy allkeys-lru + ports: + - "6379:6379" + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - lightrag-balanced-network + restart: unless-stopped + + # Qdrant Vector Database + qdrant: + image: qdrant/qdrant:latest + container_name: lightrag-balanced-qdrant + environment: + QDRANT__SERVICE__HTTP_PORT: 6333 + QDRANT__SERVICE__GRPC_PORT: 6334 + QDRANT__LOG_LEVEL: INFO + ports: + - "6333:6333" + - "6334:6334" + volumes: + - qdrant_data:/qdrant/storage + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:6333/health"] + interval: 30s + timeout: 20s + retries: 3 + networks: + - lightrag-balanced-network + restart: unless-stopped + +volumes: + postgres_data: + redis_data: + qdrant_data: + +networks: + lightrag-balanced-network: + driver: bridge \ No newline at end of file diff --git a/docker-compose.development.yml b/docker-compose.development.yml new file mode 100644 index 00000000..c2246d97 --- /dev/null +++ b/docker-compose.development.yml @@ -0,0 +1,81 @@ +version: '3.8' + +# Development & Testing Stack +# All file-based storage (NetworkX + NanoVector + JSON) +# Best for: Local development, testing, small deployments + +services: + # LightRAG Application (File-based storage only) + lightrag: + image: ghcr.io/hkuds/lightrag:latest + container_name: lightrag-dev + env_file: + - .env + environment: + # Development Storage Configuration (All file-based) + LIGHTRAG_GRAPH_STORAGE: NetworkXStorage + LIGHTRAG_VECTOR_STORAGE: NanoVectorDBStorage + LIGHTRAG_KV_STORAGE: JsonKVStorage + LIGHTRAG_DOC_STATUS_STORAGE: JsonDocStatusStorage + + # Development settings + MAX_ASYNC: 2 + MAX_TOKENS: 16384 + ENABLE_LLM_CACHE: true + ENABLE_LLM_CACHE_FOR_EXTRACT: false + LOG_LEVEL: DEBUG + + # No external database connections needed + ports: + - "9621:9621" + volumes: + - ./data/inputs:/app/inputs + - ./data/rag_storage:/app/rag_storage + # Mount additional volumes for file-based storage persistence + - ./data/dev-storage:/app/dev-storage + networks: + - lightrag-dev-network + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9621/health"] + interval: 30s + timeout: 10s + retries: 3 + + # Optional: Lightweight file browser for development + filebrowser: + image: filebrowser/filebrowser:latest + container_name: lightrag-dev-filebrowser + environment: + - FB_BASEURL=/files + ports: + - "8080:80" + volumes: + - ./data:/srv/data + networks: + - lightrag-dev-network + restart: unless-stopped + profiles: + - tools + + # Optional: Lightweight monitoring for development + portainer: + image: portainer/portainer-ce:latest + container_name: lightrag-dev-portainer + ports: + - "9000:9000" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - portainer_data:/data + networks: + - lightrag-dev-network + restart: unless-stopped + profiles: + - tools + +volumes: + portainer_data: + +networks: + lightrag-dev-network: + driver: bridge \ No newline at end of file diff --git a/docker-compose.high-performance.yml b/docker-compose.high-performance.yml new file mode 100644 index 00000000..ae7465cb --- /dev/null +++ b/docker-compose.high-performance.yml @@ -0,0 +1,199 @@ +version: '3.8' + +# Production High-Performance Stack +# Neo4j + Milvus + Redis + PostgreSQL +# Best for: Large-scale production, complex graph analytics + +services: + # LightRAG Application + lightrag: + image: ghcr.io/hkuds/lightrag:latest + container_name: lightrag-hp + env_file: + - .env + environment: + # High-Performance Storage Configuration + LIGHTRAG_GRAPH_STORAGE: Neo4JStorage + LIGHTRAG_VECTOR_STORAGE: MilvusVectorDBStorage + LIGHTRAG_KV_STORAGE: RedisKVStorage + LIGHTRAG_DOC_STATUS_STORAGE: PGDocStatusStorage + + # Service Connection Details + NEO4J_URI: bolt://neo4j:7687 + NEO4J_USERNAME: neo4j + NEO4J_PASSWORD: lightrag_neo4j_pass + + MILVUS_URI: http://milvus-standalone:19530 + MILVUS_DB_NAME: lightrag + + REDIS_URI: redis://redis:6379 + + POSTGRES_HOST: postgres + POSTGRES_PORT: 5432 + POSTGRES_USER: lightrag_user + POSTGRES_PASSWORD: lightrag_pass + POSTGRES_DATABASE: lightrag + + # Performance optimizations + MAX_ASYNC: 8 + MAX_TOKENS: 32768 + ENABLE_LLM_CACHE: true + ENABLE_LLM_CACHE_FOR_EXTRACT: true + ports: + - "9621:9621" + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + neo4j: + condition: service_started + milvus-standalone: + condition: service_healthy + volumes: + - ./data/inputs:/app/inputs + - ./data/rag_storage:/app/rag_storage + networks: + - lightrag-hp-network + restart: unless-stopped + + # PostgreSQL for Document Status Storage + postgres: + image: postgres:16 + container_name: lightrag-hp-postgres + environment: + POSTGRES_DB: lightrag + POSTGRES_USER: lightrag_user + POSTGRES_PASSWORD: lightrag_pass + POSTGRES_INITDB_ARGS: "--encoding=UTF-8" + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U lightrag_user -d lightrag"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - lightrag-hp-network + restart: unless-stopped + + # Redis for KV Storage + redis: + image: redis:7-alpine + container_name: lightrag-hp-redis + command: redis-server --appendonly yes --maxmemory 2gb --maxmemory-policy allkeys-lru + ports: + - "6379:6379" + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - lightrag-hp-network + restart: unless-stopped + + # Neo4j for Graph Storage + neo4j: + image: neo4j:5.15 + container_name: lightrag-hp-neo4j + environment: + NEO4J_AUTH: neo4j/lightrag_neo4j_pass + NEO4J_PLUGINS: '["apoc"]' + NEO4J_dbms_security_procedures_unrestricted: apoc.* + NEO4J_dbms_memory_heap_initial__size: 1G + NEO4J_dbms_memory_heap_max__size: 2G + NEO4J_dbms_memory_pagecache_size: 1G + ports: + - "7474:7474" + - "7687:7687" + volumes: + - neo4j_data:/data + - neo4j_logs:/logs + networks: + - lightrag-hp-network + restart: unless-stopped + + # Milvus Dependencies + etcd: + image: quay.io/coreos/etcd:v3.5.5 + container_name: lightrag-hp-milvus-etcd + environment: + - ETCD_AUTO_COMPACTION_MODE=revision + - ETCD_AUTO_COMPACTION_RETENTION=1000 + - ETCD_QUOTA_BACKEND_BYTES=4294967296 + - ETCD_SNAPSHOT_COUNT=50000 + command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd + volumes: + - etcd_data:/etcd + healthcheck: + test: ["CMD", "etcdctl", "endpoint", "health"] + interval: 30s + timeout: 20s + retries: 3 + networks: + - lightrag-hp-network + restart: unless-stopped + + minio: + image: minio/minio:RELEASE.2023-03-20T20-16-18Z + container_name: lightrag-hp-milvus-minio + environment: + MINIO_ACCESS_KEY: minioadmin + MINIO_SECRET_KEY: minioadmin + command: minio server /minio_data --console-address ":9001" + volumes: + - minio_data:/minio_data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + networks: + - lightrag-hp-network + restart: unless-stopped + + # Milvus Vector Database + milvus-standalone: + image: milvusdb/milvus:v2.3.10 + container_name: lightrag-hp-milvus + command: ["milvus", "run", "standalone"] + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + volumes: + - milvus_data:/var/lib/milvus + ports: + - "19530:19530" + - "9091:9091" + depends_on: + etcd: + condition: service_healthy + minio: + condition: service_healthy + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"] + interval: 30s + start_period: 90s + timeout: 20s + retries: 3 + networks: + - lightrag-hp-network + restart: unless-stopped + +volumes: + postgres_data: + redis_data: + neo4j_data: + neo4j_logs: + etcd_data: + minio_data: + milvus_data: + +networks: + lightrag-hp-network: + driver: bridge \ No newline at end of file diff --git a/docker-compose.minimal.yml b/docker-compose.minimal.yml new file mode 100644 index 00000000..c040ef89 --- /dev/null +++ b/docker-compose.minimal.yml @@ -0,0 +1,55 @@ +version: '3.8' + +services: + postgres: + image: pgvector/pgvector:pg16 + container_name: lightrag-postgres-minimal + environment: + POSTGRES_DB: lightrag + POSTGRES_USER: lightrag_user + POSTGRES_PASSWORD: lightrag_pass + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U lightrag_user -d lightrag"] + interval: 10s + timeout: 5s + retries: 5 + + lightrag: + image: ghcr.io/hkuds/lightrag:latest + container_name: lightrag-minimal + env_file: + - .env + environment: + # Pass API key from host + OPENAI_API_KEY: ${OPENAI_API_KEY} + LLM_BINDING_API_KEY: ${OPENAI_API_KEY} + EMBEDDING_BINDING_API_KEY: ${OPENAI_API_KEY} + # Use mixed storage - PostgreSQL for vectors and KV, NetworkX for graph + LIGHTRAG_KV_STORAGE: PGKVStorage + LIGHTRAG_VECTOR_STORAGE: PGVectorStorage + LIGHTRAG_DOC_STATUS_STORAGE: PGDocStatusStorage + LIGHTRAG_GRAPH_STORAGE: NetworkXStorage + POSTGRES_HOST: postgres + POSTGRES_PORT: 5432 + POSTGRES_USER: lightrag_user + POSTGRES_PASSWORD: lightrag_pass + POSTGRES_DATABASE: lightrag + ports: + - "9621:9621" + depends_on: + postgres: + condition: service_healthy + volumes: + - ./data/inputs:/app/inputs + - ./data/rag_storage:/app/rag_storage + +volumes: + postgres_data: + +networks: + default: + name: lightrag-minimal-network \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/Chart.lock b/k8s-deploy/lightrag-minimal/Chart.lock new file mode 100644 index 00000000..eb94fc44 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 12.0.1 +digest: sha256:2f6a5e813010d3cccac288a6f5a0544fdc55adcc474b7ba0bc8fe0cdf1f8f440 +generated: "2025-06-18T10:39:04.357456+03:00" diff --git a/k8s-deploy/lightrag-minimal/Chart.yaml b/k8s-deploy/lightrag-minimal/Chart.yaml new file mode 100644 index 00000000..c7b95c45 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +name: lightrag-minimal +description: A minimal Helm chart for LightRAG with PostgreSQL and NetworkX storage +type: application +version: 0.1.0 +appVersion: "1.0.0" +maintainers: + - name: Apolo Copilot Team +dependencies: + - name: postgresql + version: "~12.0.0" + repository: "https://charts.bitnami.com/bitnami" + condition: postgresql.enabled \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/README.md b/k8s-deploy/lightrag-minimal/README.md new file mode 100644 index 00000000..6d15aeb2 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/README.md @@ -0,0 +1,379 @@ +# LightRAG Minimal Helm Chart + +This Helm chart deploys a production-ready LightRAG setup with PostgreSQL and pgvector support for Kubernetes environments. It has been tested and validated with complete teardown/rebuild cycles. + +## Configuration + +This chart provides a comprehensive LightRAG deployment with: +- **PostgreSQL with pgvector**: For vector storage, KV storage, and document status using `pgvector/pgvector:pg16` image +- **NetworkX**: For graph storage (local, no external database required) +- **Persistent Storage**: For data persistence across pod restarts +- **Health Checks**: Automated health monitoring +- **API Endpoints**: Document upload, query, and management +- **Conservative Concurrency**: Optimized OpenAI API usage to prevent rate limiting + +## Prerequisites + +- Kubernetes 1.19+ (tested with Minikube) +- Helm 3.0+ with Bitnami repository +- OpenAI API key +- Storage class that supports ReadWriteOnce (standard storage class works) +- Minimum resources: 2 CPU cores, 4Gi memory available + +## Validated Installation Steps + +### Development/Local Setup (Minikube) + +1. **Prepare Helm repositories**: +```bash +cd lightrag-minimal +helm repo add bitnami https://charts.bitnami.com/bitnami +helm repo update +helm dependency update +``` + +2. **Set your OpenAI API key**: +```bash +export OPENAI_API_KEY="your-openai-api-key-here" +``` + +3. **Deploy for development**: +```bash +# Substitute environment variables and deploy +envsubst < values-dev.yaml > values-dev-final.yaml +helm install lightrag-minimal . \ + -f values-dev-final.yaml \ + --namespace lightrag \ + --create-namespace + +# Wait for deployment +kubectl wait --namespace lightrag \ + --for=condition=ready pod \ + -l app.kubernetes.io/name=postgresql \ + --timeout=120s + +kubectl wait --namespace lightrag \ + --for=condition=ready pod \ + -l app.kubernetes.io/name=lightrag-minimal \ + --timeout=120s + +# Clean up temporary file +rm values-dev-final.yaml + +# Start port forwarding +kubectl port-forward --namespace lightrag svc/lightrag-minimal 9621:9621 & +``` + +### Production Setup + +```bash +# Customize values-prod.yaml first (domain, storage classes, etc.) +envsubst < values-prod.yaml > values-prod-final.yaml +helm install lightrag-minimal . \ + -f values-prod-final.yaml \ + --namespace lightrag \ + --create-namespace +rm values-prod-final.yaml +``` + +## Configuration Options + +### Validated Environment Configuration + +Both `values-dev.yaml` and `values-prod.yaml` include these critical settings: + +```yaml +env: + # OpenAI API Configuration (REQUIRED) + LLM_BINDING: "openai" + LLM_BINDING_HOST: "https://api.openai.com/v1" + EMBEDDING_BINDING: "openai" + EMBEDDING_BINDING_HOST: "https://api.openai.com/v1" + EMBEDDING_MODEL: "text-embedding-ada-002" + EMBEDDING_DIM: "1536" + + # Conservative concurrency (prevents API errors) + MAX_ASYNC: "4" + MAX_PARALLEL_INSERT: "2" + + # LLM Configuration + ENABLE_LLM_CACHE: "true" + ENABLE_LLM_CACHE_FOR_EXTRACT: "true" + TIMEOUT: "240" + TEMPERATURE: "0" + MAX_TOKENS: "32768" +``` + +### PostgreSQL Configuration + +```yaml +postgresql: + # CRITICAL: Use pgvector image for vector support + image: + registry: docker.io + repository: pgvector/pgvector + tag: pg16 + auth: + password: "your-secure-password" +``` + +### Development vs Production + +| Setting | Development | Production | +|---------|-------------|------------| +| Resources | 1 CPU, 2Gi RAM | 4 CPU, 8Gi RAM | +| Storage | 5Gi | 100Gi | +| Replicas | 1 | 2-10 (autoscaling) | +| Ingress | Disabled | Enabled with TLS | +| Storage Class | Default | `fast-ssd` | + +## Accessing LightRAG + +### Development Access +```bash +# Port forward (included in installation steps above) +kubectl port-forward --namespace lightrag svc/lightrag-minimal 9621:9621 & + +# Access URLs +echo "Web UI: http://localhost:9621/webui" +echo "API Docs: http://localhost:9621/docs" +echo "Health Check: http://localhost:9621/health" +``` + +### Verify Deployment +```bash +# Check health +curl http://localhost:9621/health + +# Expected response: +{ + "status": "healthy", + "configuration": { + "llm_model": "gpt-4o", + "kv_storage": "PGKVStorage", + "vector_storage": "PGVectorStorage", + "graph_storage": "NetworkXStorage" + } +} +``` + +### Production (Ingress) +Production uses ingress with TLS (see `values-prod.yaml`): +```yaml +ingress: + enabled: true + className: "nginx" + hosts: + - host: lightrag.yourdomain.com +``` + +## Monitoring + +### Check Deployment Status +```bash +kubectl get pods -l app.kubernetes.io/name=lightrag-minimal +kubectl get services -l app.kubernetes.io/name=lightrag-minimal +``` + +### View Logs +```bash +kubectl logs -l app.kubernetes.io/name=lightrag-minimal -f +``` + +### Health Checks +The deployment includes health checks on `/health` endpoint. + +## Scaling + +For production workloads, consider enabling autoscaling: +```yaml +autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 10 + targetCPUUtilizationPercentage: 70 +``` + +## Upgrading + +```bash +helm upgrade lightrag-minimal ./lightrag-minimal -f values-prod.yaml +``` + +## Uninstalling + +```bash +helm uninstall lightrag-minimal +``` + +**Note**: This will delete all data unless you have persistent volumes with a retain policy. + +## Document Loading + +After successful deployment, load your documentation using the included loader. The loader supports two reference modes: + +### Reference Modes + +**Files Mode (Default)**: Uses file paths in citations +```bash +# Install dependencies (if needed) +pip install httpx + +# Load documents with file path references +python ../../../load_docs.py /path/to/your/docs --endpoint http://localhost:9621 + +# Example with relative path +python ../../../load_docs.py ../docs --endpoint http://localhost:9621 +``` + +**URLs Mode**: Uses website URLs in citations (recommended for public documentation) +```bash +# Load Apolo documentation with URL references +python ../../../load_docs.py ../apolo-copilot/docs/official-apolo-documentation/docs \ + --mode urls --base-url https://docs.apolo.us/index/ --endpoint http://localhost:9621 + +# Load custom documentation with URL references +python ../../../load_docs.py /path/to/docs \ + --mode urls --base-url https://your-docs.example.com/docs/ --endpoint http://localhost:9621 +``` + +### Benefits of URL Mode +- **Clickable References**: Query responses include direct links to source documentation +- **Better User Experience**: Users can easily navigate to original content +- **Professional Citations**: References point to live documentation sites + +### ⚠️ Important: File Structure Requirements for URL Mode + +**Your local file structure must match your documentation site's URL structure:** + +``` +# Example: GitBook documentation site +docs/ +├── getting-started/ +│ ├── installation.md → https://docs.example.com/getting-started/installation +│ └── first-steps.md → https://docs.example.com/getting-started/first-steps +├── administration/ +│ ├── README.md → https://docs.example.com/administration +│ └── setup.md → https://docs.example.com/administration/setup +└── README.md → https://docs.example.com/ +``` + +**Quick Setup Guide:** +1. **Analyze your docs site**: Visit URLs and note the path structure +2. **Create matching directories**: `mkdir -p docs/{section1,section2,section3}` +3. **Organize markdown files**: Place files to match URL paths (remove `.md` from URLs) +4. **Verify mapping**: Test a few URLs manually before loading + +**URL Mapping Rules:** +- `.md` extension is removed from URLs +- `README.md` files map to their directory URL +- Subdirectories become URL path segments +- File and folder names should match URL slugs exactly + +### Expected Output + +Both modes produce similar output with different reference formats: + +```bash +🚀 Loading Documentation into LightRAG +============================================================ +📁 Documentation path: /path/to/docs +🔧 Reference mode: urls +🌐 Base URL: https://docs.apolo.us/index/ +🌐 LightRAG endpoint: http://localhost:9621 + +✅ LightRAG is healthy: healthy +📚 Found 58 markdown files +🔧 Mode: urls +🌐 Base URL: https://docs.apolo.us/index/ +📊 Total content: 244,400 characters +📊 Average length: 4,287 characters + +🔄 Starting to load documents... +✅ Loaded: Document Title +📈 Progress: 10/58 (10 success, 0 failed) +... +✅ Loading complete! +📊 Successful: 58 +📊 Failed: 0 +✅ Query successful! +``` + +### Query Response Examples + +**Files Mode References:** +``` +### References +- [DC] getting-started/installation.md +- [KG] administration/cluster-setup.md +``` + +**URLs Mode References:** +``` +### References +- [DC] https://docs.apolo.us/index/getting-started/installation +- [KG] https://docs.apolo.us/index/administration/cluster-setup +``` + +## Troubleshooting + +### Common Issues + +**Issue: `UnsupportedProtocol: Request URL is missing protocol`** +- **Solution**: Ensure `LLM_BINDING_HOST` and `EMBEDDING_BINDING_HOST` are set to `https://api.openai.com/v1` + +**Issue: Document processing failures with API connection errors** +- **Solution**: Reduce concurrency with `MAX_ASYNC: "4"` and `MAX_PARALLEL_INSERT: "2"` + +**Issue: pgvector extension missing** +- **Solution**: Ensure using `pgvector/pgvector:pg16` image, not standard PostgreSQL + +### Validation Commands +```bash +# Check all pods are running +kubectl get pods --namespace lightrag + +# Verify API connectivity +kubectl exec --namespace lightrag \ + $(kubectl get pod -l app.kubernetes.io/name=lightrag-minimal --namespace lightrag -o jsonpath='{.items[0].metadata.name}') \ + -- python -c "import requests; print(requests.get('https://api.openai.com/v1/models', headers={'Authorization': 'Bearer ' + open('/dev/null').read()}, timeout=5).status_code)" + +# Check document processing status +curl http://localhost:9621/documents | jq '.statuses | to_entries | map({status: .key, count: (.value | length)})' +``` + +## Clean Teardown and Rebuild + +For testing or redeployment: + +```bash +# Complete teardown +helm uninstall lightrag-minimal --namespace lightrag +kubectl delete namespace lightrag + +# Rebuild (repeat installation steps above) +# This process has been validated multiple times +``` + +## Validated Features + +✅ **Pure Helm Deployment** - No manual kubectl apply commands needed +✅ **PostgreSQL with pgvector** - Automatic extension creation via proper image +✅ **Environment Flexibility** - Separate dev/prod configurations +✅ **Document Loading** - Working API with `file_source` parameter +✅ **Conservative Concurrency** - Prevents OpenAI API rate limiting +✅ **Health Monitoring** - Comprehensive health checks and status endpoints +✅ **Persistent Storage** - Data survives pod restarts and cluster updates + +## Comparison with Docker Compose + +| Feature | Docker Compose | Helm Chart | +|---------|----------------|------------| +| PostgreSQL | pgvector/pgvector:pg16 | Same image via subchart | +| Concurrency | MAX_ASYNC=4 | Same settings | +| API Configuration | .env file | Environment variables | +| Scaling | Single container | Kubernetes autoscaling | +| Persistence | Local volumes | PersistentVolumeClaims | +| Monitoring | Manual | Kubernetes native | + +This chart maintains the same conservative, working configuration as the Docker Compose setup while adding Kubernetes-native features for production deployment. \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/NOTES.txt b/k8s-deploy/lightrag-minimal/templates/NOTES.txt new file mode 100644 index 00000000..ae2c1148 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/NOTES.txt @@ -0,0 +1,54 @@ +✅ LightRAG deployment successful! + +1. Wait for all pods to be ready: + kubectl wait --namespace {{ .Release.Namespace }} --for=condition=ready pod -l app.kubernetes.io/name=postgresql --timeout=120s + kubectl wait --namespace {{ .Release.Namespace }} --for=condition=ready pod -l app.kubernetes.io/name={{ include "lightrag-minimal.name" . }} --timeout=120s + +2. Access your application: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + 🌐 Web UI: http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}webui + 📚 API Docs: http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}docs + {{- end }} +{{- end }} +{{- else }} + # Start port forwarding (run in background): + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ include "lightrag-minimal.fullname" . }} 9621:9621 & + + 🌐 Web UI: http://localhost:9621/webui + 📚 API Docs: http://localhost:9621/docs + 🔍 Health Check: http://localhost:9621/health +{{- end }} + +3. Verify deployment health: + curl http://localhost:9621/health + # Expected: {"status": "healthy", "configuration": {...}} + +4. Load your documents: + # Install httpx if needed: pip install httpx + + # Files mode (file path references) - Default + python ../../../load_docs.py /path/to/your/docs --endpoint http://localhost:9621 + + # URLs mode (website URL references) - Recommended for public docs + # Note: Local file structure must match your docs site URL structure + python ../../../load_docs.py /path/to/docs --mode urls \ + --base-url https://docs.example.com/ --endpoint http://localhost:9621 + +5. Monitor your deployment: + # Check pods status + kubectl get pods --namespace {{ .Release.Namespace }} + + # View logs + kubectl logs --namespace {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "lightrag-minimal.name" . }} -f + +Configuration Summary: +🗄️ Storage: PostgreSQL with pgvector + NetworkX graph storage +🔒 Persistence: {{ if .Values.persistence.ragStorage.enabled }}Enabled{{ else }}Disabled{{ end }} ({{ .Values.persistence.ragStorage.size }} storage) +💻 Resources: {{ .Values.resources.limits.cpu }} CPU, {{ .Values.resources.limits.memory }} memory +🐘 PostgreSQL: pgvector/pgvector:pg16 with {{ .Values.postgresql.primary.persistence.size }} storage +🤖 LLM Model: {{ .Values.env.LLM_MODEL }} +📊 Concurrency: MAX_ASYNC={{ .Values.env.MAX_ASYNC }}, MAX_PARALLEL_INSERT={{ .Values.env.MAX_PARALLEL_INSERT }} + +📖 For detailed usage instructions, see the README.md in the chart directory. \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/_helpers.tpl b/k8s-deploy/lightrag-minimal/templates/_helpers.tpl new file mode 100644 index 00000000..711cb911 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/_helpers.tpl @@ -0,0 +1,80 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "lightrag-minimal.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "lightrag-minimal.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "lightrag-minimal.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "lightrag-minimal.labels" -}} +helm.sh/chart: {{ include "lightrag-minimal.chart" . }} +{{ include "lightrag-minimal.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "lightrag-minimal.selectorLabels" -}} +app.kubernetes.io/name: {{ include "lightrag-minimal.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "lightrag-minimal.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "lightrag-minimal.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create the name of the secret +*/}} +{{- define "lightrag-minimal.secretName" -}} +{{- printf "%s-secrets" (include "lightrag-minimal.fullname" .) }} +{{- end }} + +{{/* +PostgreSQL connection string +*/}} +{{- define "lightrag-minimal.postgresqlHost" -}} +{{- if .Values.postgresql.enabled }} +{{- printf "%s-postgresql" (include "lightrag-minimal.fullname" .) }} +{{- else }} +{{- .Values.env.POSTGRES_HOST }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/deployment.yaml b/k8s-deploy/lightrag-minimal/templates/deployment.yaml new file mode 100644 index 00000000..25efb089 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/deployment.yaml @@ -0,0 +1,157 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "lightrag-minimal.fullname" . }} + labels: + {{- include "lightrag-minimal.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "lightrag-minimal.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "lightrag-minimal.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "lightrag-minimal.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.targetPort }} + protocol: TCP + env: + # Basic server configuration + - name: HOST + value: {{ .Values.env.HOST | quote }} + - name: PORT + value: {{ .Values.env.PORT | quote }} + + # Web UI configuration + - name: WEBUI_TITLE + value: {{ .Values.env.WEBUI_TITLE | quote }} + - name: WEBUI_DESCRIPTION + value: {{ .Values.env.WEBUI_DESCRIPTION | quote }} + + # LLM configuration + - name: LLM_BINDING + value: {{ .Values.env.LLM_BINDING | quote }} + - name: LLM_MODEL + value: {{ .Values.env.LLM_MODEL | quote }} + - name: LLM_BINDING_HOST + value: {{ .Values.env.LLM_BINDING_HOST | quote }} + - name: LLM_BINDING_API_KEY + valueFrom: + secretKeyRef: + name: {{ include "lightrag-minimal.secretName" . }} + key: openai-api-key + + # Embedding configuration + - name: EMBEDDING_BINDING + value: {{ .Values.env.EMBEDDING_BINDING | quote }} + - name: EMBEDDING_MODEL + value: {{ .Values.env.EMBEDDING_MODEL | quote }} + - name: EMBEDDING_DIM + value: {{ .Values.env.EMBEDDING_DIM | quote }} + - name: EMBEDDING_BINDING_API_KEY + valueFrom: + secretKeyRef: + name: {{ include "lightrag-minimal.secretName" . }} + key: openai-api-key + + # Storage configuration + - name: LIGHTRAG_KV_STORAGE + value: {{ .Values.env.LIGHTRAG_KV_STORAGE | quote }} + - name: LIGHTRAG_VECTOR_STORAGE + value: {{ .Values.env.LIGHTRAG_VECTOR_STORAGE | quote }} + - name: LIGHTRAG_DOC_STATUS_STORAGE + value: {{ .Values.env.LIGHTRAG_DOC_STATUS_STORAGE | quote }} + - name: LIGHTRAG_GRAPH_STORAGE + value: {{ .Values.env.LIGHTRAG_GRAPH_STORAGE | quote }} + + # PostgreSQL configuration + - name: POSTGRES_HOST + value: {{ include "lightrag-minimal.postgresqlHost" . | quote }} + - name: POSTGRES_PORT + value: {{ .Values.env.POSTGRES_PORT | quote }} + - name: POSTGRES_USER + value: {{ .Values.env.POSTGRES_USER | quote }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "lightrag-minimal.secretName" . }} + key: postgres-password + - name: POSTGRES_DATABASE + value: {{ .Values.env.POSTGRES_DATABASE | quote }} + - name: POSTGRES_WORKSPACE + value: {{ .Values.env.POSTGRES_WORKSPACE | quote }} + + {{- if .Values.healthCheck.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.healthCheck.path }} + port: http + initialDelaySeconds: {{ .Values.healthCheck.initialDelaySeconds }} + periodSeconds: {{ .Values.healthCheck.periodSeconds }} + timeoutSeconds: {{ .Values.healthCheck.timeoutSeconds }} + failureThreshold: {{ .Values.healthCheck.failureThreshold }} + readinessProbe: + httpGet: + path: {{ .Values.healthCheck.path }} + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + {{- end }} + + resources: + {{- toYaml .Values.resources | nindent 12 }} + + {{- if .Values.persistence.enabled }} + volumeMounts: + - name: rag-storage + mountPath: /app/rag_storage + - name: inputs + mountPath: /app/inputs + {{- end }} + + {{- if .Values.persistence.enabled }} + volumes: + - name: rag-storage + persistentVolumeClaim: + claimName: {{ include "lightrag-minimal.fullname" . }}-rag-storage + - name: inputs + persistentVolumeClaim: + claimName: {{ include "lightrag-minimal.fullname" . }}-inputs + {{- end }} + + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/forwardauth-middleware.yaml b/k8s-deploy/lightrag-minimal/templates/forwardauth-middleware.yaml new file mode 100644 index 00000000..ca69da59 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/forwardauth-middleware.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.ingress.enabled .Values.ingress.forwardAuth.enabled }} +apiVersion: traefik.io/v1alpha1 # Use traefik.containo.us/v1alpha1 if using older Traefik +kind: Middleware +metadata: + # Use the helper for the Middleware resource name + name: {{ .Values.ingress.forwardAuth.name | quote }} + # Middleware MUST be in the same namespace as the Ingress that uses it + namespace: {{ .Release.Namespace }} + labels: + {{- include "lightrag-minimal.labels" . | nindent 4 }} +spec: + forwardAuth: + # Required fields from values.yaml + address: {{ .Values.ingress.forwardAuth.address | quote }} + trustForwardHeader: {{ .Values.ingress.forwardAuth.trustForwardHeader | default true }} + + # Optional headers to send to the authentication service + {{- if .Values.ingress.forwardAuth.authRequestHeaders }} + authRequestHeaders: + {{- toYaml .Values.ingress.forwardAuth.authRequestHeaders | nindent 6 }} + {{- end }} + + # Optional headers to copy from the authentication service's response + {{- if .Values.ingress.forwardAuth.authResponseHeaders }} + authResponseHeaders: + {{- toYaml .Values.ingress.forwardAuth.authResponseHeaders | nindent 6 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/hpa.yaml b/k8s-deploy/lightrag-minimal/templates/hpa.yaml new file mode 100644 index 00000000..8313e20b --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "lightrag-minimal.fullname" . }} + labels: + {{- include "lightrag-minimal.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "lightrag-minimal.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/ingress.yaml b/k8s-deploy/lightrag-minimal/templates/ingress.yaml new file mode 100644 index 00000000..43d8c47c --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/ingress.yaml @@ -0,0 +1,44 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "lightrag-minimal.fullname" . }} + labels: + {{- include "lightrag-minimal.labels" $ | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + rules: + {{- if .Values.ingress.hosts }} + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "lightrag-minimal.fullname" $ }} + port: + name: http + {{- end }} + {{- end }} + {{- else }} + - host: {{ .Release.Namespace }}.apps.{{ .Values.ingress.clusterName }}.org.neu.ro + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "lightrag-minimal.fullname" $ }} + port: + name: http + {{- end }} +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/pvc.yaml b/k8s-deploy/lightrag-minimal/templates/pvc.yaml new file mode 100644 index 00000000..a8f63bb8 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/pvc.yaml @@ -0,0 +1,35 @@ +{{- if .Values.persistence.enabled }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "lightrag-minimal.fullname" . }}-rag-storage + labels: + {{- include "lightrag-minimal.labels" . | nindent 4 }} +spec: + accessModes: + - {{ .Values.persistence.ragStorage.accessMode }} + resources: + requests: + storage: {{ .Values.persistence.ragStorage.size }} + {{- if .Values.persistence.ragStorage.storageClass }} + storageClassName: {{ .Values.persistence.ragStorage.storageClass }} + {{- end }} + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "lightrag-minimal.fullname" . }}-inputs + labels: + {{- include "lightrag-minimal.labels" . | nindent 4 }} +spec: + accessModes: + - {{ .Values.persistence.inputs.accessMode }} + resources: + requests: + storage: {{ .Values.persistence.inputs.size }} + {{- if .Values.persistence.inputs.storageClass }} + storageClassName: {{ .Values.persistence.inputs.storageClass }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/secret.yaml b/k8s-deploy/lightrag-minimal/templates/secret.yaml new file mode 100644 index 00000000..f86c5eb8 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/secret.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "lightrag-minimal.secretName" . }} + labels: + {{- include "lightrag-minimal.labels" . | nindent 4 }} +type: Opaque +data: + openai-api-key: {{ .Values.secrets.openaiApiKey | b64enc | quote }} + postgres-password: {{ .Values.postgresql.auth.password | b64enc | quote }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/service.yaml b/k8s-deploy/lightrag-minimal/templates/service.yaml new file mode 100644 index 00000000..cd6f0278 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "lightrag-minimal.fullname" . }} + labels: + {{- include "lightrag-minimal.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.targetPort }} + protocol: TCP + name: http + selector: + {{- include "lightrag-minimal.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/serviceaccount.yaml b/k8s-deploy/lightrag-minimal/templates/serviceaccount.yaml new file mode 100644 index 00000000..ffc678ae --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "lightrag-minimal.serviceAccountName" . }} + labels: + {{- include "lightrag-minimal.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/templates/strip-headers-middleware.yaml b/k8s-deploy/lightrag-minimal/templates/strip-headers-middleware.yaml new file mode 100644 index 00000000..1818e1db --- /dev/null +++ b/k8s-deploy/lightrag-minimal/templates/strip-headers-middleware.yaml @@ -0,0 +1,15 @@ +{{- /* Create strip-headers Middleware only if ingress is enabled */}} +{{- if and .Values.ingress.enabled .Values.ingress.forwardAuth.enabled }} +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: strip-headers + namespace: {{ .Release.Namespace }} + labels: + {{- include "lightrag-minimal.labels" . | nindent 4 }} +spec: + headers: + customRequestHeaders: + Authorization: "" # Empty value removes header + Cookie: "" +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/values-dev.yaml b/k8s-deploy/lightrag-minimal/values-dev.yaml new file mode 100644 index 00000000..a5e5f7bd --- /dev/null +++ b/k8s-deploy/lightrag-minimal/values-dev.yaml @@ -0,0 +1,75 @@ +# Development/Minikube Values +# Optimized for local development with reduced resource requirements + +# Environment configuration +env: + LLM_MODEL: "gpt-4o" + WEBUI_TITLE: "Apolo Copilot - LightRAG (Development)" + WEBUI_DESCRIPTION: "Development LightRAG for Apolo Documentation" + + # OpenAI API Configuration + LLM_BINDING: "openai" + LLM_BINDING_HOST: "https://api.openai.com/v1" + EMBEDDING_BINDING: "openai" + EMBEDDING_BINDING_HOST: "https://api.openai.com/v1" + EMBEDDING_MODEL: "text-embedding-ada-002" + EMBEDDING_DIM: "1536" + + # Concurrency settings (conservative for API stability) + MAX_ASYNC: "4" + MAX_PARALLEL_INSERT: "2" + + # LLM Configuration + ENABLE_LLM_CACHE: "true" + ENABLE_LLM_CACHE_FOR_EXTRACT: "true" + TIMEOUT: "240" + TEMPERATURE: "0" + MAX_TOKENS: "32768" + +# Reduced resources for local development +resources: + limits: + cpu: 1000m + memory: 2Gi + requests: + cpu: 250m + memory: 512Mi + +# Smaller storage for development +persistence: + ragStorage: + size: 5Gi + inputs: + size: 2Gi + +# PostgreSQL with reduced resources +postgresql: + # Use pgvector image for vector support + image: + registry: docker.io + repository: pgvector/pgvector + tag: pg16 + auth: + password: "dev-lightrag-pass" + primary: + persistence: + size: 5Gi + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + +# OpenAI API key (set via environment variable) +secrets: + openaiApiKey: "${OPENAI_API_KEY}" + +# Disable ingress for local development (use port-forward) +ingress: + enabled: false + +# Disable autoscaling for development +autoscaling: + enabled: false \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/values-prod.yaml b/k8s-deploy/lightrag-minimal/values-prod.yaml new file mode 100644 index 00000000..92c9eb3f --- /dev/null +++ b/k8s-deploy/lightrag-minimal/values-prod.yaml @@ -0,0 +1,120 @@ +# Production Values +# Optimized for production with HA, scaling, and monitoring + +# Environment configuration +env: + LLM_MODEL: "gpt-4o" + WEBUI_TITLE: "Apolo Copilot - LightRAG" + WEBUI_DESCRIPTION: "Production LightRAG for Apolo Documentation" + + # OpenAI API Configuration + LLM_BINDING: "openai" + LLM_BINDING_HOST: "https://api.openai.com/v1" + EMBEDDING_BINDING: "openai" + EMBEDDING_BINDING_HOST: "https://api.openai.com/v1" + EMBEDDING_MODEL: "text-embedding-ada-002" + EMBEDDING_DIM: "1536" + + # Concurrency settings (conservative for API stability) + MAX_ASYNC: "4" + MAX_PARALLEL_INSERT: "2" + + # LLM Configuration + ENABLE_LLM_CACHE: "true" + ENABLE_LLM_CACHE_FOR_EXTRACT: "true" + TIMEOUT: "240" + TEMPERATURE: "0" + MAX_TOKENS: "32768" + +# Production resources +resources: + limits: + cpu: 4000m + memory: 8Gi + requests: + cpu: 1000m + memory: 2Gi + +# Production storage with fast storage class +persistence: + ragStorage: + size: 100Gi + storageClass: "fast-ssd" # Adjust for your cluster + inputs: + size: 50Gi + storageClass: "fast-ssd" + +# PostgreSQL with production resources +postgresql: + # Use pgvector image for vector support + image: + registry: docker.io + repository: pgvector/pgvector + tag: pg16 + auth: + password: "secure-production-password" # Use external secret in real production + primary: + persistence: + size: 200Gi + storageClass: "fast-ssd" + resources: + limits: + cpu: 2000m + memory: 4Gi + requests: + cpu: 500m + memory: 1Gi + +# OpenAI API key (use external secret manager in production) +secrets: + openaiApiKey: "${OPENAI_API_KEY}" + +# Enable ingress for production +ingress: + enabled: true + className: "nginx" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/proxy-body-size: "100m" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + hosts: + - host: lightrag.yourdomain.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: lightrag-tls + hosts: + - lightrag.yourdomain.com + +# Enable autoscaling for production +autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 10 + targetCPUUtilizationPercentage: 70 + targetMemoryUtilizationPercentage: 80 + +# Production security context +securityContext: + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 1000 + +podSecurityContext: + seccompProfile: + type: RuntimeDefault + +# Node affinity for production workloads +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - lightrag-minimal + topologyKey: kubernetes.io/hostname \ No newline at end of file diff --git a/k8s-deploy/lightrag-minimal/values.yaml b/k8s-deploy/lightrag-minimal/values.yaml new file mode 100644 index 00000000..2bc66662 --- /dev/null +++ b/k8s-deploy/lightrag-minimal/values.yaml @@ -0,0 +1,162 @@ +# LightRAG Minimal Configuration +# Matches docker-compose.minimal.yml setup + +replicaCount: 1 + +image: + repository: ghcr.io/hkuds/lightrag + tag: latest + pullPolicy: IfNotPresent + +nameOverride: "" +fullnameOverride: "" + +service: + type: ClusterIP + port: 9621 + targetPort: 9621 + +ingress: + enabled: false + className: "" + clusterName: "" + annotations: {} + hosts: + - host: lightrag-minimal.local + paths: + - path: / + pathType: Prefix + tls: [] + forwardAuth: + enabled: false + # name: forwardauth + # address: http://forwardauth:8080 + # trustForwardHeader: true + # authRequestHeaders: + # - "Cookie" + # - "Authorization" + +# Resource limits and requests +resources: + limits: + cpu: 2000m + memory: 4Gi + requests: + cpu: 500m + memory: 1Gi + +# Persistence for data volumes +persistence: + enabled: true + ragStorage: + accessMode: ReadWriteOnce + size: 20Gi + storageClass: "" + inputs: + accessMode: ReadWriteOnce + size: 10Gi + storageClass: "" + +# PostgreSQL configuration (embedded chart with pgvector) +postgresql: + enabled: true + # Use pgvector image instead of standard PostgreSQL + image: + registry: docker.io + repository: pgvector/pgvector + tag: pg16 + auth: + database: lightrag + username: lightrag_user + password: lightrag_pass + primary: + persistence: + enabled: true + size: 20Gi + resources: + limits: + cpu: 1000m + memory: 2Gi + requests: + cpu: 250m + memory: 512Mi + initdb: + scripts: + 00-pgvector.sql: | + CREATE EXTENSION IF NOT EXISTS vector; + +# LightRAG Environment Configuration +# This matches the minimal docker-compose setup +env: + # Server configuration + HOST: "0.0.0.0" + PORT: "9621" + + # Web UI configuration + WEBUI_TITLE: "Apolo Copilot - LightRAG" + WEBUI_DESCRIPTION: "Simple and Fast Graph Based RAG System for Apolo Documentation" + + # LLM configuration + LLM_BINDING: "openai" + LLM_MODEL: "gpt-4o-mini" + LLM_BINDING_HOST: "" + # LLM_BINDING_API_KEY: Set via secret + + # Embedding configuration + EMBEDDING_BINDING: "openai" + EMBEDDING_MODEL: "text-embedding-ada-002" + EMBEDDING_DIM: "1536" + # EMBEDDING_BINDING_API_KEY: Set via secret + + # Storage configuration - Minimal setup + LIGHTRAG_KV_STORAGE: "PGKVStorage" + LIGHTRAG_VECTOR_STORAGE: "PGVectorStorage" + LIGHTRAG_DOC_STATUS_STORAGE: "PGDocStatusStorage" + LIGHTRAG_GRAPH_STORAGE: "NetworkXStorage" # Local storage, no external DB needed + + # PostgreSQL connection (internal service) + POSTGRES_HOST: "{{ include \"lightrag-minimal.fullname\" . }}-postgresql" + POSTGRES_PORT: "5432" + POSTGRES_USER: "lightrag_user" + POSTGRES_DATABASE: "lightrag" + POSTGRES_WORKSPACE: "default" + +# Secret configuration for API keys +secrets: + # Create a secret with your OpenAI API key + openaiApiKey: "" # Set this or create manually + +# Node selector and affinity +nodeSelector: {} +tolerations: [] +affinity: {} + +# Security context +securityContext: {} +podSecurityContext: {} + +# Service account +serviceAccount: + create: true + annotations: {} + name: "" + +# Pod annotations +podAnnotations: {} + +# Auto scaling (disabled by default for minimal setup) +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 3 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + +# Health checks +healthCheck: + enabled: true + path: "/health" + initialDelaySeconds: 60 + periodSeconds: 30 + timeoutSeconds: 10 + failureThreshold: 5 \ No newline at end of file diff --git a/k8s-deploy/lightrag/templates/deployment.yaml b/k8s-deploy/lightrag/templates/deployment.yaml index fe63c1ac..d804b79c 100644 --- a/k8s-deploy/lightrag/templates/deployment.yaml +++ b/k8s-deploy/lightrag/templates/deployment.yaml @@ -19,7 +19,7 @@ spec: containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: IfNotPresent + imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: http containerPort: {{ .Values.env.PORT }} diff --git a/k8s-deploy/lightrag/templates/forwardauth-middleware.yaml b/k8s-deploy/lightrag/templates/forwardauth-middleware.yaml new file mode 100644 index 00000000..6632850b --- /dev/null +++ b/k8s-deploy/lightrag/templates/forwardauth-middleware.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.ingress.enabled .Values.ingress.forwardAuth.enabled }} +apiVersion: traefik.io/v1alpha1 # Use traefik.containo.us/v1alpha1 if using older Traefik +kind: Middleware +metadata: + # Use the helper for the Middleware resource name + name: {{ .Values.ingress.forwardAuth.name | quote }} + # Middleware MUST be in the same namespace as the Ingress that uses it + namespace: {{ .Release.Namespace }} + labels: + {{- include "lightrag.labels" . | nindent 4 }} +spec: + forwardAuth: + # Required fields from values.yaml + address: {{ .Values.ingress.forwardAuth.address | quote }} + trustForwardHeader: {{ .Values.ingress.forwardAuth.trustForwardHeader | default true }} + + # Optional headers to send to the authentication service + {{- if .Values.ingress.forwardAuth.authRequestHeaders }} + authRequestHeaders: + {{- toYaml .Values.ingress.forwardAuth.authRequestHeaders | nindent 6 }} + {{- end }} + + # Optional headers to copy from the authentication service's response + {{- if .Values.ingress.forwardAuth.authResponseHeaders }} + authResponseHeaders: + {{- toYaml .Values.ingress.forwardAuth.authResponseHeaders | nindent 6 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag/templates/ingress.yaml b/k8s-deploy/lightrag/templates/ingress.yaml new file mode 100644 index 00000000..ec6e9117 --- /dev/null +++ b/k8s-deploy/lightrag/templates/ingress.yaml @@ -0,0 +1,54 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "lightrag.fullname" . }} + labels: + {{- include "lightrag.labels" $ | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + rules: + {{- if .Values.ingress.hosts }} + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "lightrag.fullname" $ }} + port: + name: http + {{- end }} + {{- end }} + {{- else }} + - host: {{ .Release.Namespace }}.apps.{{ .Values.ingress.clusterName }}.org.neu.ro + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "lightrag.fullname" $ }} + port: + name: http + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag/templates/strip-headers-middleware.yaml b/k8s-deploy/lightrag/templates/strip-headers-middleware.yaml new file mode 100644 index 00000000..f3c56b96 --- /dev/null +++ b/k8s-deploy/lightrag/templates/strip-headers-middleware.yaml @@ -0,0 +1,15 @@ +{{- /* Create strip-headers Middleware only if ingress is enabled */}} +{{- if and .Values.ingress.enabled .Values.ingress.forwardAuth.enabled }} +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: strip-headers + namespace: {{ .Release.Namespace }} + labels: + {{- include "lightrag.labels" . | nindent 4 }} +spec: + headers: + customRequestHeaders: + Authorization: "" # Empty value removes header + Cookie: "" +{{- end }} \ No newline at end of file diff --git a/k8s-deploy/lightrag/values.yaml b/k8s-deploy/lightrag/values.yaml index fb1bbe31..6cf013e2 100644 --- a/k8s-deploy/lightrag/values.yaml +++ b/k8s-deploy/lightrag/values.yaml @@ -3,11 +3,35 @@ replicaCount: 1 image: repository: ghcr.io/hkuds/lightrag tag: latest + pullPolicy: IfNotPresent + +nameOverride: "" +fullnameOverride: "" service: type: ClusterIP port: 9621 +ingress: + enabled: false + className: "" + clusterName: "" + annotations: {} + hosts: + - host: lightrag.local + paths: + - path: / + pathType: Prefix + tls: [] + forwardAuth: + enabled: false + # name: forwardauth + # address: http://forwardauth:8080 + # trustForwardHeader: true + # authRequestHeaders: + # - "Cookie" + # - "Authorization" + resources: limits: cpu: 1000m diff --git a/load_docs.py b/load_docs.py new file mode 100755 index 00000000..dfc6601e --- /dev/null +++ b/load_docs.py @@ -0,0 +1,319 @@ +#!/usr/bin/env python3 +""" +Simplified script to load documentation into LightRAG +Loads all markdown files from a directory structure +""" + +import asyncio +import httpx +import argparse +import sys +from pathlib import Path +from typing import List, Optional + + +async def load_document_to_lightrag( + content: str, + title: str, + doc_url: str, + endpoint: str = "http://localhost:9621" +) -> bool: + """Load a single document to LightRAG with URL reference""" + try: + async with httpx.AsyncClient(timeout=30.0) as client: + response = await client.post( + f"{endpoint}/documents/text", + headers={"Content-Type": "application/json"}, + json={ + "text": content, + "file_source": doc_url + } + ) + + if response.status_code == 200: + print(f"✅ Loaded: {title}") + return True + else: + print(f"❌ Failed to load {title}: {response.status_code}") + if response.status_code == 500: + try: + error_detail = response.json() + print(f" Error details: {error_detail}") + except: + print(f" Response: {response.text}") + return False + + except Exception as e: + print(f"❌ Error loading {title}: {e}") + return False + + +def convert_file_path_to_url(relative_path: str, base_url: str) -> str: + """Convert file path to documentation URL""" + # Ensure base URL ends with / + if not base_url.endswith('/'): + base_url += '/' + + # Handle special cases + if relative_path in ["README.md", "SUMMARY.md"]: + return base_url.rstrip('/') + + # Remove .md extension and convert path + url_path = relative_path.replace(".md", "") + + # Handle README files in subdirectories - they map to the directory URL + if url_path.endswith("/README"): + url_path = url_path[:-7] # Remove "/README" + + # Clean up any double slashes + url_path = url_path.strip("/") + + return f"{base_url}{url_path}" + + +def load_markdown_files(docs_path: Path, mode: str = "files", base_url: str = None) -> List[tuple]: + """Load all markdown files from directory structure + + Args: + docs_path: Path to documentation directory + mode: 'files' for file paths, 'urls' for URL references + base_url: Base URL for documentation site (required for 'urls' mode) + """ + if not docs_path.exists(): + raise FileNotFoundError(f"Documentation directory not found: {docs_path}") + + if mode == "urls" and not base_url: + raise ValueError("base_url is required when mode is 'urls'") + + # Find all markdown files, excluding SUMMARY.md as it's just the table of contents + md_files = [f for f in docs_path.rglob("*.md") if f.name != "SUMMARY.md"] + print(f"📚 Found {len(md_files)} markdown files") + print(f"🔧 Mode: {mode}") + if mode == "urls": + print(f"🌐 Base URL: {base_url}") + + documents = [] + + for file_path in md_files: + try: + # Load content + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read().strip() + + if not content: + continue + + # Generate title from filename + title = file_path.stem.replace("-", " ").replace("_", " ").title() + if title.lower() == "readme": + # Use parent directory name for README files + title = f"{file_path.parent.name.replace('-', ' ').replace('_', ' ').title()} Overview" + + # Get relative path for metadata + relative_path = str(file_path.relative_to(docs_path)) + + if mode == "files": + # Use file path as reference + reference = relative_path + source_info = f"File: {file_path.name}" + + # Prepare content with file metadata + content_with_metadata = f""" +Title: {title} +Path: {relative_path} +Source: {source_info} + +{content} +""" + else: # urls mode + # Convert file path to documentation URL + reference = convert_file_path_to_url(relative_path, base_url) + source_info = f"Documentation Site" + + # Prepare content with URL metadata + content_with_metadata = f""" +Title: {title} +URL: {reference} +Source: {source_info} + +{content} +""" + + documents.append((content_with_metadata, title, reference)) + + except Exception as e: + print(f"⚠️ Error processing {file_path}: {e}") + continue + + return documents + + +async def test_lightrag_health(endpoint: str = "http://localhost:9621") -> bool: + """Test if LightRAG is accessible""" + try: + async with httpx.AsyncClient(timeout=10.0) as client: + response = await client.get(f"{endpoint}/health") + if response.status_code == 200: + health_data = response.json() + print(f"✅ LightRAG is healthy: {health_data.get('status')}") + return True + else: + print(f"❌ LightRAG health check failed: {response.status_code}") + return False + except Exception as e: + print(f"❌ Cannot connect to LightRAG: {e}") + return False + + +async def test_query(endpoint: str = "http://localhost:9621") -> None: + """Test a sample query""" + print(f"\n🧪 Testing query...") + try: + async with httpx.AsyncClient(timeout=30.0) as client: + response = await client.post( + f"{endpoint}/query", + headers={"Content-Type": "application/json"}, + json={"query": "What is this documentation about?", "mode": "local"} + ) + + if response.status_code == 200: + result = response.json() + print(f"✅ Query successful!") + print(f"Response: {result['response'][:200]}...") + else: + print(f"❌ Query failed: {response.status_code}") + if response.status_code == 500: + try: + error_detail = response.json() + print(f" Error details: {error_detail}") + except: + print(f" Response: {response.text}") + + except Exception as e: + print(f"❌ Query error: {e}") + + +async def main(): + """Main loading function""" + parser = argparse.ArgumentParser( + description="Load documentation into LightRAG with file paths or URL references", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Load with file path references (default mode) + python load_docs.py ../apolo-copilot/docs/official-apolo-documentation/docs + + # Load with URL references + python load_docs.py docs/ --mode urls --base-url https://docs.apolo.us/index/ + + # Load Apolo docs with URL references (common use case) + python load_docs.py ../apolo-copilot/docs/official-apolo-documentation/docs \\ + --mode urls --base-url https://docs.apolo.us/index/ + + # Use custom endpoint + python load_docs.py docs/ --endpoint https://lightrag.example.com + + # Load with different documentation base URL + python load_docs.py docs/ --mode urls --base-url https://my-docs.example.com/docs/ +""" + ) + + parser.add_argument( + "docs_path", + nargs="?", + default="../apolo-copilot/docs/official-apolo-documentation/docs", + help="Path to documentation directory (default: ../apolo-copilot/docs/official-apolo-documentation/docs)" + ) + parser.add_argument( + "--mode", + choices=["files", "urls"], + default="files", + help="Reference mode: 'files' for file paths, 'urls' for URL references (default: files)" + ) + parser.add_argument( + "--base-url", + dest="base_url", + help="Base URL for documentation site (required when mode=urls). Example: https://docs.apolo.us/index/" + ) + parser.add_argument( + "--endpoint", + default="http://localhost:9621", + help="LightRAG endpoint URL (default: http://localhost:9621)" + ) + parser.add_argument( + "--no-test", + action="store_true", + help="Skip test query after loading" + ) + + args = parser.parse_args() + + print("🚀 Loading Documentation into LightRAG") + print("=" * 60) + print(f"📁 Documentation path: {args.docs_path}") + print(f"🔧 Reference mode: {args.mode}") + if args.mode == "urls": + if args.base_url: + print(f"🌐 Base URL: {args.base_url}") + else: + print("❌ Error: --base-url is required when mode is 'urls'") + sys.exit(1) + print(f"🌐 LightRAG endpoint: {args.endpoint}") + print() + + # Test LightRAG connectivity + if not await test_lightrag_health(args.endpoint): + print("❌ Cannot connect to LightRAG. Please ensure it's running and accessible.") + sys.exit(1) + + # Load documents + docs_path = Path(args.docs_path).resolve() + try: + documents = load_markdown_files(docs_path, args.mode, args.base_url) + except (FileNotFoundError, ValueError) as e: + print(f"❌ {e}") + sys.exit(1) + + if not documents: + print("❌ No markdown files found to load") + sys.exit(1) + + # Calculate statistics + total_content = sum(len(content) for content, _, _ in documents) + avg_content = total_content // len(documents) if documents else 0 + + print(f"📊 Total content: {total_content:,} characters") + print(f"📊 Average length: {avg_content:,} characters") + + # Load documents + successful = 0 + failed = 0 + + print(f"\n🔄 Starting to load documents...") + + for i, (content, title, doc_url) in enumerate(documents): + success = await load_document_to_lightrag(content, title, doc_url, args.endpoint) + + if success: + successful += 1 + else: + failed += 1 + + # Progress update + if (i + 1) % 10 == 0: + print(f"📈 Progress: {i + 1}/{len(documents)} ({successful} success, {failed} failed)") + + # Small delay to avoid overwhelming the service + await asyncio.sleep(0.3) + + print(f"\n✅ Loading complete!") + print(f"📊 Successful: {successful}") + print(f"📊 Failed: {failed}") + + # Test query unless disabled + if not args.no_test and successful > 0: + await test_query(args.endpoint) + + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file