Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .github/workflows/ci-quick.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ env:
NODE_VERSION: '20.x'
PYTHON_VERSION: '3.10'

permissions:
contents: read
pull-requests: write
issues: write

jobs:
# ============================================
# Quick validation (lint, type check, fast tests)
Expand Down Expand Up @@ -106,8 +111,6 @@ jobs:
"RESILIENTDB_GRAPHQL_URI=https://cloud.resilientdb.com/graphql" \
"JWT_SECRET=test-secret-key-do-not-use-in-production" > .env

- name: Run backend unit tests only (fast)
# wait for mongodb to be ready on localhost:27017
- name: Wait for MongoDB
run: |
for i in {1..30}; do
Expand Down Expand Up @@ -136,12 +139,14 @@ jobs:
--ci

- name: Build check (frontend)
env:
CI: false
run: |
cd frontend
npm run build

- name: Comment PR with quick results
if: github.event_name == 'pull_request' && always()
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false && always()
uses: actions/github-script@v7
with:
script: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ coverage/
*.coverage
backend/.coverage
node_modules
backend/qdrant_storage/
frontend/build/

# Exclude all .env files
Expand Down
119 changes: 118 additions & 1 deletion README.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions backend/NEXT_STEPS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

66 changes: 66 additions & 0 deletions backend/SETUP_VECTOR_SEARCH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Vector Search Setup Guide

## Quick Start

### Option 1: Using Docker Compose (Recommended)

```bash
cd backend

# Start Qdrant and Redis
docker-compose up -d qdrant redis

# Verify Qdrant is running
curl http://localhost:6333/healthz
# Should return: {"title":"healthz","version":"1.x.x"}

# Install Python dependencies (if not already done)
pip install -r requirements.txt

# Run backend
python app.py

# Seperate terminal
python worker/embedding_service.py
```

### Option 2: Local Qdrant Installation

```bash
# macOS with Homebrew
brew install qdrant

# Or using Docker standalone
docker run -p 6333:6333 -p 6334:6334 \
-v $(pwd)/qdrant_storage:/qdrant/storage \
qdrant/qdrant

# Install Python dependencies
cd backend
pip install -r requirements.txt

# Run backend
python app.py

# Seperate terminal
python worker/embedding_service.py
```

---

## 🔧 Configuration

The following environment variables can be set in `config.py`:

```bash
# Qdrant Vector Database
QDRANT_HOST=localhost
QDRANT_PORT=6333
QDRANT_GRPC_PORT=6334
QDRANT_COLLECTION_NAME=rescanvas_embeddings

# These are already in your config:
# REDIS_HOST=localhost
# REDIS_PORT=6379
# MONGO_ATLAS_URI=...
```
9 changes: 9 additions & 0 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ def filter(self, record):

app = Flask(__name__)

# Allow large request bodies for thumbnail uploads (up to 20MB)
app.config['MAX_CONTENT_LENGTH'] = 20 * 1024 * 1024

# Initialize rate limiting BEFORE importing routes (routes use limiter decorators)
from middleware.rate_limit import init_limiter, rate_limit_error_handler
limiter = init_limiter(app)
Expand All @@ -56,6 +59,9 @@ def filter(self, record):
from routes.frontend import frontend_bp
from routes.analytics import analytics_bp
from routes.export import export_bp
from routes.ai_assistant import ai_assistant_bp
from routes.search_ai import search_ai_bp
from routes.chatbot import chatbot_bp
from services.db import redis_client
from services.canvas_counter import get_canvas_draw_count
from services.graphql_service import commit_transaction_via_graphql
Expand Down Expand Up @@ -215,6 +221,8 @@ def handle_all_exceptions(e):
app.register_blueprint(submit_room_line_bp)
app.register_blueprint(admin_bp)
app.register_blueprint(export_bp)
app.register_blueprint(ai_assistant_bp)
app.register_blueprint(chatbot_bp)

# Register versioned API v1 blueprints for external applications
from api_v1.auth import auth_v1_bp
Expand All @@ -232,6 +240,7 @@ def handle_all_exceptions(e):
app.register_blueprint(users_v1_bp)
app.register_blueprint(stamps_bp, url_prefix='/api')
app.register_blueprint(templates_v1_bp)
app.register_blueprint(search_ai_bp)

# Frontend serving must be last to avoid route conflicts
app.register_blueprint(frontend_bp)
Expand Down
7 changes: 7 additions & 0 deletions backend/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
REDIS_HOST = os.getenv("REDIS_HOST", "localhost")
REDIS_PORT = int(os.getenv("REDIS_PORT", "6379"))

# Qdrant Vector Database Configuration
QDRANT_HOST = os.getenv("QDRANT_HOST", "localhost")
QDRANT_PORT = int(os.getenv("QDRANT_PORT", "6333"))
QDRANT_COLLECTION_NAME = os.getenv("QDRANT_COLLECTION_NAME", "rescanvas_embeddings")
EMBEDDING_DIMENSION = 512 # OpenCLIP ViT-B-32 output dimension
QDRANT_GRPC_PORT = int(os.getenv("QDRANT_GRPC_PORT", "6334"))

# Rate Limiting Configuration
RATE_LIMIT_STORAGE_URI = f"redis://{REDIS_HOST}:{REDIS_PORT}"
RATE_LIMIT_ENABLED = os.getenv("RATE_LIMIT_ENABLED", "True") == "True"
Expand Down
26 changes: 26 additions & 0 deletions backend/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ services:
networks:
- rescanvas-network

qdrant:
image: qdrant/qdrant:latest
container_name: rescanvas-qdrant
ports:
- "6333:6333" # HTTP API
- "6334:6334" # gRPC API
volumes:
- qdrant_data:/qdrant/storage
environment:
- QDRANT__SERVICE__GRPC_PORT=6334
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:6333/healthz"]
interval: 10s
timeout: 5s
retries: 5
networks:
- rescanvas-network

backend:
build:
context: .
Expand All @@ -34,6 +53,9 @@ services:
- RATE_LIMIT_STORAGE_URI=redis://redis:6379
- REDIS_HOST=redis
- REDIS_PORT=6379
- QDRANT_HOST=qdrant
- QDRANT_PORT=6333
- QDRANT_GRPC_PORT=6334
- JWT_SECRET=${JWT_SECRET:-dev-insecure-change-me}
- OPENAI_API_KEY=${OPENAI_API_KEY}
- ANALYTICS_ENABLED=${ANALYTICS_ENABLED:-True}
Expand All @@ -46,6 +68,8 @@ services:
depends_on:
redis:
condition: service_healthy
qdrant:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:10010/api/analytics/health"]
Expand All @@ -59,6 +83,8 @@ services:
volumes:
redis_data:
driver: local
qdrant_data:
driver: local

networks:
rescanvas-network:
Expand Down
9 changes: 8 additions & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ python-engineio==4.12.3
python-socketio==5.14.1
redis==6.2.0
requests==2.32.4
resilient-python-cache==0.1.1
# resilient-python-cache==0.1.1
rich==13.9.4
openai>=1.0.0
simple-websocket==1.1.0
simplejson==3.19.3
six==1.17.0
Expand All @@ -64,3 +65,9 @@ websockets==10.4
Werkzeug==3.1.3
wrapt==2.0.0
wsproto==1.2.0
# AI/ML dependencies for semantic search
torch>=2.0.0
open_clip_torch>=2.20.0
pillow>=10.0.0
qdrant-client>=1.7.0
numpy>=1.24.0
Loading
Loading