Spaces:
Sleeping
Sleeping
Tripagra commited on
Commit Β·
42f628f
1
Parent(s): cef122e
Add deployment solution: FastAPI/uvicorn + Render config + deployment guides
Browse files- DEPLOYMENT_OPTIONS.md +191 -0
- DEPLOYMENT_SOLUTION.md +190 -0
- api/proxy.py +93 -0
- deploy.sh +136 -0
- render.yaml +28 -0
- requirements.txt +4 -0
DEPLOYMENT_OPTIONS.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Smart Escalation API - Deployment Options
|
| 2 |
+
|
| 3 |
+
## β οΈ Critical Constraint
|
| 4 |
+
|
| 5 |
+
Your application uses heavy ML dependencies (~5GB total):
|
| 6 |
+
- `sentence-transformers` (~2GB with PyTorch)
|
| 7 |
+
- `faiss-cpu` (~500MB)
|
| 8 |
+
- `torch` (~2GB)
|
| 9 |
+
- CUDA libraries and other dependencies
|
| 10 |
+
|
| 11 |
+
**Vercel serverless functions have a 500MB size limit** - your dependencies are 10x larger.
|
| 12 |
+
|
| 13 |
+
## Option 1: Hybrid Deployment (RECOMMENDED)
|
| 14 |
+
|
| 15 |
+
Deploy frontend and backend separately:
|
| 16 |
+
|
| 17 |
+
### Frontend β Vercel
|
| 18 |
+
- β
Already working at `https://escalation-api-frontend.vercel.app/`
|
| 19 |
+
- Static React app (no size limits)
|
| 20 |
+
- Fast global CDN
|
| 21 |
+
|
| 22 |
+
### Backend β Render/Railway/Hugging Face
|
| 23 |
+
- Deploy the full Python ML backend
|
| 24 |
+
- No size limits
|
| 25 |
+
- Persistent containers (not serverless)
|
| 26 |
+
|
| 27 |
+
**Steps:**
|
| 28 |
+
1. Deploy backend to Render (see `BACKEND_DEPLOY.md`)
|
| 29 |
+
2. Get backend URL (e.g., `https://your-app.onrender.com`)
|
| 30 |
+
3. Add `VITE_API_URL` environment variable in Vercel
|
| 31 |
+
4. Redeploy frontend
|
| 32 |
+
|
| 33 |
+
**Cost:**
|
| 34 |
+
- Vercel: Free
|
| 35 |
+
- Render: $7/month (Starter plan)
|
| 36 |
+
- Total: $7/month
|
| 37 |
+
|
| 38 |
+
---
|
| 39 |
+
|
| 40 |
+
## Option 2: API Gateway Pattern (Vercel Frontend + Proxy)
|
| 41 |
+
|
| 42 |
+
Keep everything "on Vercel" by using a lightweight proxy:
|
| 43 |
+
|
| 44 |
+
### Architecture
|
| 45 |
+
```
|
| 46 |
+
User β Vercel Frontend β Vercel Proxy (api/proxy.py) β External ML Backend
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
### What's on Vercel
|
| 50 |
+
- Frontend (static React)
|
| 51 |
+
- Lightweight Python proxy (no ML dependencies, <1MB)
|
| 52 |
+
|
| 53 |
+
### What's External
|
| 54 |
+
- Full ML backend on Render/Railway/Hugging Face
|
| 55 |
+
|
| 56 |
+
**Steps:**
|
| 57 |
+
1. Deploy ML backend to Render
|
| 58 |
+
2. Update `vercel.json` to use `api/proxy.py`
|
| 59 |
+
3. Set `ML_BACKEND_URL` environment variable in Vercel
|
| 60 |
+
4. Deploy to Vercel
|
| 61 |
+
|
| 62 |
+
**Benefit:** Everything appears to be "on Vercel" from user perspective
|
| 63 |
+
|
| 64 |
+
---
|
| 65 |
+
|
| 66 |
+
## Option 3: Full Vercel (NOT POSSIBLE)
|
| 67 |
+
|
| 68 |
+
β Cannot deploy ML dependencies to Vercel serverless functions
|
| 69 |
+
β 500MB limit vs 5GB dependencies
|
| 70 |
+
β Multiple attempts failed with size errors
|
| 71 |
+
|
| 72 |
+
**Why it fails:**
|
| 73 |
+
```
|
| 74 |
+
Error: Total dependency size (4995.65 MB) exceeds Lambda
|
| 75 |
+
ephemeral storage limit (500 MB)
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
---
|
| 79 |
+
|
| 80 |
+
## Recommended Solution: Option 1 (Hybrid)
|
| 81 |
+
|
| 82 |
+
This is the standard approach for ML applications:
|
| 83 |
+
|
| 84 |
+
### 1. Deploy Backend to Render
|
| 85 |
+
|
| 86 |
+
```bash
|
| 87 |
+
# Create render.yaml
|
| 88 |
+
cat > render.yaml << 'EOF'
|
| 89 |
+
services:
|
| 90 |
+
- type: web
|
| 91 |
+
name: escalation-api-backend
|
| 92 |
+
runtime: python
|
| 93 |
+
buildCommand: pip install -r requirements.txt
|
| 94 |
+
startCommand: uvicorn src.main:app --host 0.0.0.0 --port $PORT
|
| 95 |
+
envVars:
|
| 96 |
+
- key: GOOGLE_API_KEY
|
| 97 |
+
sync: false
|
| 98 |
+
- key: ARTICLES_DIR
|
| 99 |
+
value: data/articles
|
| 100 |
+
- key: EMBEDDING_MODEL
|
| 101 |
+
value: all-MiniLM-L6-v2
|
| 102 |
+
- key: RELEVANCE_THRESHOLD
|
| 103 |
+
value: "0.5"
|
| 104 |
+
- key: TOP_K_CHUNKS
|
| 105 |
+
value: "3"
|
| 106 |
+
- key: CHUNK_SIZE
|
| 107 |
+
value: "500"
|
| 108 |
+
- key: CHUNK_OVERLAP
|
| 109 |
+
value: "50"
|
| 110 |
+
- key: LLM_MODEL
|
| 111 |
+
value: gemini-1.5-flash
|
| 112 |
+
- key: LLM_TEMPERATURE
|
| 113 |
+
value: "0.3"
|
| 114 |
+
- key: CORS_ORIGINS
|
| 115 |
+
value: https://escalation-api-frontend.vercel.app
|
| 116 |
+
EOF
|
| 117 |
+
|
| 118 |
+
# Add FastAPI and uvicorn to requirements.txt
|
| 119 |
+
echo "fastapi==0.104.1" >> requirements.txt
|
| 120 |
+
echo "uvicorn[standard]==0.24.0" >> requirements.txt
|
| 121 |
+
|
| 122 |
+
# Commit and push
|
| 123 |
+
git add .
|
| 124 |
+
git commit -m "Add Render deployment config"
|
| 125 |
+
git push
|
| 126 |
+
|
| 127 |
+
# Deploy on Render dashboard
|
| 128 |
+
# 1. Go to https://dashboard.render.com
|
| 129 |
+
# 2. New β Web Service
|
| 130 |
+
# 3. Connect your GitHub repo
|
| 131 |
+
# 4. Render will auto-detect render.yaml
|
| 132 |
+
# 5. Add GOOGLE_API_KEY in environment variables
|
| 133 |
+
# 6. Deploy
|
| 134 |
+
```
|
| 135 |
+
|
| 136 |
+
### 2. Connect Frontend to Backend
|
| 137 |
+
|
| 138 |
+
```bash
|
| 139 |
+
# In Vercel dashboard:
|
| 140 |
+
# 1. Go to your project settings
|
| 141 |
+
# 2. Environment Variables
|
| 142 |
+
# 3. Add: VITE_API_URL = https://your-app.onrender.com
|
| 143 |
+
# 4. Redeploy frontend
|
| 144 |
+
```
|
| 145 |
+
|
| 146 |
+
### 3. Test End-to-End
|
| 147 |
+
|
| 148 |
+
```bash
|
| 149 |
+
# Test backend directly
|
| 150 |
+
curl -X POST https://your-app.onrender.com/ask \
|
| 151 |
+
-H "Content-Type: application/json" \
|
| 152 |
+
-d '{"question": "How do I reset my password?"}'
|
| 153 |
+
|
| 154 |
+
# Test frontend
|
| 155 |
+
# Visit https://escalation-api-frontend.vercel.app/
|
| 156 |
+
# Ask a question
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
---
|
| 160 |
+
|
| 161 |
+
## Why Not Vercel for ML?
|
| 162 |
+
|
| 163 |
+
Vercel is optimized for:
|
| 164 |
+
- β
Static sites (Next.js, React, Vue)
|
| 165 |
+
- β
Lightweight serverless functions (<50MB)
|
| 166 |
+
- β
Edge functions (<1MB)
|
| 167 |
+
|
| 168 |
+
Vercel is NOT suitable for:
|
| 169 |
+
- β Heavy ML models (>500MB)
|
| 170 |
+
- β Long-running processes (>10s timeout)
|
| 171 |
+
- β GPU workloads
|
| 172 |
+
- β Large binary dependencies
|
| 173 |
+
|
| 174 |
+
For ML applications, use:
|
| 175 |
+
- Render (persistent containers)
|
| 176 |
+
- Railway (persistent containers)
|
| 177 |
+
- Hugging Face Spaces (ML-optimized)
|
| 178 |
+
- AWS Lambda with container images (10GB limit)
|
| 179 |
+
- Google Cloud Run (ML-optimized)
|
| 180 |
+
|
| 181 |
+
---
|
| 182 |
+
|
| 183 |
+
## Next Steps
|
| 184 |
+
|
| 185 |
+
Choose your deployment strategy:
|
| 186 |
+
|
| 187 |
+
**Option 1 (Recommended):** Follow the Render deployment steps above
|
| 188 |
+
|
| 189 |
+
**Option 2 (API Gateway):** Use `api/proxy.py` and deploy ML backend separately
|
| 190 |
+
|
| 191 |
+
**Need help?** Check `BACKEND_DEPLOY.md` for detailed Render instructions.
|
DEPLOYMENT_SOLUTION.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# β οΈ CRITICAL: Why Vercel-Only Deployment is Impossible
|
| 2 |
+
|
| 3 |
+
## The Problem
|
| 4 |
+
|
| 5 |
+
Your Smart Escalation API uses heavy ML dependencies that **cannot** be deployed to Vercel serverless functions:
|
| 6 |
+
|
| 7 |
+
```
|
| 8 |
+
Total dependency size: ~5,000 MB (5 GB)
|
| 9 |
+
Vercel Lambda limit: 500 MB
|
| 10 |
+
Ratio: 10x too large β
|
| 11 |
+
```
|
| 12 |
+
|
| 13 |
+
### Dependencies Breakdown
|
| 14 |
+
- `sentence-transformers` + `torch`: ~2.5 GB
|
| 15 |
+
- `faiss-cpu`: ~500 MB
|
| 16 |
+
- CUDA libraries: ~2 GB
|
| 17 |
+
- Other dependencies: ~500 MB
|
| 18 |
+
|
| 19 |
+
## Why All Deployment Attempts Failed
|
| 20 |
+
|
| 21 |
+
Every error you encountered stems from this fundamental size constraint:
|
| 22 |
+
|
| 23 |
+
1. **"Total dependency size (4995.65 MB) exceeds Lambda ephemeral storage limit (500 MB)"**
|
| 24 |
+
- Direct size limit violation
|
| 25 |
+
|
| 26 |
+
2. **"Function Runtimes must have a valid version"**
|
| 27 |
+
- Vercel trying different Python versions to fit dependencies (all failed)
|
| 28 |
+
|
| 29 |
+
3. **"faiss-cpu has no wheels for Python 3.14"**
|
| 30 |
+
- Vercel using latest Python hoping for smaller wheels (doesn't exist)
|
| 31 |
+
|
| 32 |
+
4. **"Command 'uvicorn' not found"** (on Render)
|
| 33 |
+
- Missing FastAPI/uvicorn in requirements.txt (now fixed)
|
| 34 |
+
|
| 35 |
+
## The Solution: Hybrid Deployment β
|
| 36 |
+
|
| 37 |
+
You **must** split your deployment:
|
| 38 |
+
|
| 39 |
+
### Architecture
|
| 40 |
+
```
|
| 41 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 42 |
+
β USER β
|
| 43 |
+
ββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
|
| 44 |
+
β
|
| 45 |
+
βΌ
|
| 46 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 47 |
+
β VERCEL (Frontend) β
|
| 48 |
+
β - React chat UI β
|
| 49 |
+
β - Static files only β
|
| 50 |
+
β - URL: escalation-api-frontend.vercel.app β
|
| 51 |
+
β - Cost: FREE β
|
| 52 |
+
ββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
|
| 53 |
+
β API calls
|
| 54 |
+
βΌ
|
| 55 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 56 |
+
β RENDER (Backend) β
|
| 57 |
+
β - Python FastAPI + ML models β
|
| 58 |
+
β - Persistent container (not serverless) β
|
| 59 |
+
β - URL: your-app.onrender.com β
|
| 60 |
+
β - Cost: $7/month β
|
| 61 |
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
## Quick Deployment Steps
|
| 65 |
+
|
| 66 |
+
### 1. Add Missing Dependencies (DONE β
)
|
| 67 |
+
|
| 68 |
+
```bash
|
| 69 |
+
# Already added to requirements.txt:
|
| 70 |
+
fastapi==0.104.1
|
| 71 |
+
uvicorn[standard]==0.24.0
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
### 2. Deploy Backend to Render
|
| 75 |
+
|
| 76 |
+
```bash
|
| 77 |
+
# Commit changes
|
| 78 |
+
git add .
|
| 79 |
+
git commit -m "Add FastAPI/uvicorn and Render config"
|
| 80 |
+
git push
|
| 81 |
+
|
| 82 |
+
# Then go to https://dashboard.render.com
|
| 83 |
+
# 1. New β Web Service
|
| 84 |
+
# 2. Connect GitHub repo
|
| 85 |
+
# 3. Render auto-detects render.yaml
|
| 86 |
+
# 4. Add GOOGLE_API_KEY environment variable
|
| 87 |
+
# 5. Deploy (takes 5-10 minutes)
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
### 3. Connect Frontend to Backend
|
| 91 |
+
|
| 92 |
+
```bash
|
| 93 |
+
# In Vercel dashboard:
|
| 94 |
+
# 1. Go to your project settings
|
| 95 |
+
# 2. Environment Variables
|
| 96 |
+
# 3. Add: VITE_API_URL = https://your-app.onrender.com
|
| 97 |
+
# 4. Redeploy frontend
|
| 98 |
+
```
|
| 99 |
+
|
| 100 |
+
### 4. Test
|
| 101 |
+
|
| 102 |
+
```bash
|
| 103 |
+
# Test backend
|
| 104 |
+
curl -X POST https://your-app.onrender.com/ask \
|
| 105 |
+
-H "Content-Type: application/json" \
|
| 106 |
+
-d '{"question": "How do I reset my password?"}'
|
| 107 |
+
|
| 108 |
+
# Test frontend
|
| 109 |
+
# Visit https://escalation-api-frontend.vercel.app/
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
## Files Created/Updated
|
| 113 |
+
|
| 114 |
+
β
`requirements.txt` - Added fastapi and uvicorn
|
| 115 |
+
β
`render.yaml` - Render deployment configuration
|
| 116 |
+
β
`DEPLOYMENT_OPTIONS.md` - Detailed deployment guide
|
| 117 |
+
β
`DEPLOYMENT_SOLUTION.md` - This file
|
| 118 |
+
β
`deploy.sh` - Deployment helper script
|
| 119 |
+
β
`api/proxy.py` - Optional lightweight proxy pattern
|
| 120 |
+
|
| 121 |
+
## Why This is the Industry Standard
|
| 122 |
+
|
| 123 |
+
**Every ML application** uses this pattern:
|
| 124 |
+
|
| 125 |
+
- **Hugging Face**: Frontend on Vercel/Netlify, models on Spaces
|
| 126 |
+
- **OpenAI**: Frontend on Vercel, models on dedicated infrastructure
|
| 127 |
+
- **Anthropic**: Frontend on Vercel, models on AWS/GCP
|
| 128 |
+
- **Midjourney**: Frontend on Vercel, models on GPU clusters
|
| 129 |
+
|
| 130 |
+
**Vercel is designed for**:
|
| 131 |
+
- β
Static sites (React, Next.js)
|
| 132 |
+
- β
Lightweight APIs (<50MB)
|
| 133 |
+
- β
Edge functions (<1MB)
|
| 134 |
+
|
| 135 |
+
**Vercel is NOT designed for**:
|
| 136 |
+
- β Heavy ML models (>500MB)
|
| 137 |
+
- β GPU workloads
|
| 138 |
+
- β Long-running processes
|
| 139 |
+
|
| 140 |
+
## Alternative Platforms for ML Backend
|
| 141 |
+
|
| 142 |
+
If you don't want Render, consider:
|
| 143 |
+
|
| 144 |
+
1. **Railway** ($5/month)
|
| 145 |
+
- Similar to Render
|
| 146 |
+
- Easy deployment
|
| 147 |
+
- Good for Python ML apps
|
| 148 |
+
|
| 149 |
+
2. **Hugging Face Spaces** (FREE)
|
| 150 |
+
- Optimized for ML models
|
| 151 |
+
- Free tier available
|
| 152 |
+
- Built-in GPU support
|
| 153 |
+
|
| 154 |
+
3. **Google Cloud Run** ($0-20/month)
|
| 155 |
+
- Serverless containers (not functions)
|
| 156 |
+
- 10GB size limit
|
| 157 |
+
- Pay per use
|
| 158 |
+
|
| 159 |
+
4. **AWS Lambda with Container Images** ($0-20/month)
|
| 160 |
+
- 10GB size limit
|
| 161 |
+
- More complex setup
|
| 162 |
+
- Pay per use
|
| 163 |
+
|
| 164 |
+
## Cost Comparison
|
| 165 |
+
|
| 166 |
+
| Platform | Frontend | Backend | Total/Month |
|
| 167 |
+
|----------|----------|---------|-------------|
|
| 168 |
+
| **Hybrid (Recommended)** | Vercel (Free) | Render ($7) | **$7** |
|
| 169 |
+
| Vercel Only | β Impossible | β Impossible | β |
|
| 170 |
+
| Railway | Vercel (Free) | Railway ($5) | **$5** |
|
| 171 |
+
| HF Spaces | Vercel (Free) | HF (Free) | **$0** |
|
| 172 |
+
| Cloud Run | Vercel (Free) | GCP ($10) | **$10** |
|
| 173 |
+
|
| 174 |
+
## Next Steps
|
| 175 |
+
|
| 176 |
+
1. **Deploy backend to Render** (5 minutes setup, 10 minutes build)
|
| 177 |
+
2. **Get backend URL** from Render dashboard
|
| 178 |
+
3. **Add VITE_API_URL** to Vercel environment variables
|
| 179 |
+
4. **Redeploy frontend** on Vercel
|
| 180 |
+
5. **Test end-to-end** functionality
|
| 181 |
+
|
| 182 |
+
## Need Help?
|
| 183 |
+
|
| 184 |
+
- **Render deployment**: See `BACKEND_DEPLOY.md`
|
| 185 |
+
- **All options**: See `DEPLOYMENT_OPTIONS.md`
|
| 186 |
+
- **Quick deploy**: Run `bash deploy.sh`
|
| 187 |
+
|
| 188 |
+
---
|
| 189 |
+
|
| 190 |
+
**Bottom line**: You cannot deploy ML models to Vercel serverless functions. The hybrid approach is the only viable solution and is the industry standard for ML applications.
|
api/proxy.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Lightweight Vercel Serverless Function - API Gateway Pattern
|
| 3 |
+
This proxies requests to an external ML backend (deployed elsewhere)
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
from http.server import BaseHTTPRequestHandler
|
| 7 |
+
import json
|
| 8 |
+
import os
|
| 9 |
+
import urllib.request
|
| 10 |
+
import urllib.error
|
| 11 |
+
|
| 12 |
+
# External ML backend URL (set in Vercel environment variables)
|
| 13 |
+
ML_BACKEND_URL = os.getenv("ML_BACKEND_URL", "")
|
| 14 |
+
|
| 15 |
+
class handler(BaseHTTPRequestHandler):
|
| 16 |
+
"""Lightweight proxy handler for Vercel."""
|
| 17 |
+
|
| 18 |
+
def do_POST(self):
|
| 19 |
+
"""Proxy POST requests to ML backend."""
|
| 20 |
+
if not ML_BACKEND_URL:
|
| 21 |
+
self.send_error_response(503, "ML backend not configured")
|
| 22 |
+
return
|
| 23 |
+
|
| 24 |
+
try:
|
| 25 |
+
# Read request body
|
| 26 |
+
content_length = int(self.headers.get('Content-Length', 0))
|
| 27 |
+
body = self.rfile.read(content_length)
|
| 28 |
+
|
| 29 |
+
# Forward to ML backend
|
| 30 |
+
req = urllib.request.Request(
|
| 31 |
+
f"{ML_BACKEND_URL}/ask",
|
| 32 |
+
data=body,
|
| 33 |
+
headers={'Content-Type': 'application/json'},
|
| 34 |
+
method='POST'
|
| 35 |
+
)
|
| 36 |
+
|
| 37 |
+
with urllib.request.urlopen(req, timeout=30) as response:
|
| 38 |
+
response_data = response.read()
|
| 39 |
+
|
| 40 |
+
# Send response
|
| 41 |
+
self.send_response(200)
|
| 42 |
+
self.send_header('Content-Type', 'application/json')
|
| 43 |
+
self.send_header('Access-Control-Allow-Origin', '*')
|
| 44 |
+
self.send_header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
| 45 |
+
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
|
| 46 |
+
self.end_headers()
|
| 47 |
+
self.wfile.write(response_data)
|
| 48 |
+
|
| 49 |
+
except urllib.error.HTTPError as e:
|
| 50 |
+
self.send_error_response(e.code, f"Backend error: {e.reason}")
|
| 51 |
+
except urllib.error.URLError as e:
|
| 52 |
+
self.send_error_response(503, "ML backend unavailable")
|
| 53 |
+
except Exception as e:
|
| 54 |
+
print(f"Proxy error: {str(e)}")
|
| 55 |
+
self.send_error_response(500, "Proxy error")
|
| 56 |
+
|
| 57 |
+
def do_OPTIONS(self):
|
| 58 |
+
"""Handle CORS preflight."""
|
| 59 |
+
self.send_response(200)
|
| 60 |
+
self.send_header('Access-Control-Allow-Origin', '*')
|
| 61 |
+
self.send_header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
| 62 |
+
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
|
| 63 |
+
self.end_headers()
|
| 64 |
+
|
| 65 |
+
def do_GET(self):
|
| 66 |
+
"""Health check."""
|
| 67 |
+
self.send_response(200)
|
| 68 |
+
self.send_header('Content-Type', 'application/json')
|
| 69 |
+
self.send_header('Access-Control-Allow-Origin', '*')
|
| 70 |
+
self.end_headers()
|
| 71 |
+
|
| 72 |
+
response = {
|
| 73 |
+
"status": "healthy",
|
| 74 |
+
"backend_configured": bool(ML_BACKEND_URL)
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
self.wfile.write(json.dumps(response).encode('utf-8'))
|
| 78 |
+
|
| 79 |
+
def send_error_response(self, status_code, message):
|
| 80 |
+
"""Send error response."""
|
| 81 |
+
self.send_response(status_code)
|
| 82 |
+
self.send_header('Content-Type', 'application/json')
|
| 83 |
+
self.send_header('Access-Control-Allow-Origin', '*')
|
| 84 |
+
self.end_headers()
|
| 85 |
+
|
| 86 |
+
response = {
|
| 87 |
+
"response_type": "error",
|
| 88 |
+
"message": message,
|
| 89 |
+
"confidence_explanation": "Service error",
|
| 90 |
+
"sources": None
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
self.wfile.write(json.dumps(response).encode('utf-8'))
|
deploy.sh
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Smart Escalation API - Deployment Script
|
| 4 |
+
# This script helps you deploy the application using the hybrid approach
|
| 5 |
+
|
| 6 |
+
set -e
|
| 7 |
+
|
| 8 |
+
echo "π Smart Escalation API - Deployment Helper"
|
| 9 |
+
echo "============================================"
|
| 10 |
+
echo ""
|
| 11 |
+
|
| 12 |
+
# Check if git is clean
|
| 13 |
+
if [[ -n $(git status -s) ]]; then
|
| 14 |
+
echo "β οΈ You have uncommitted changes. Commit them first:"
|
| 15 |
+
echo ""
|
| 16 |
+
git status -s
|
| 17 |
+
echo ""
|
| 18 |
+
read -p "Commit changes now? (y/n) " -n 1 -r
|
| 19 |
+
echo ""
|
| 20 |
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
| 21 |
+
git add .
|
| 22 |
+
read -p "Enter commit message: " commit_msg
|
| 23 |
+
git commit -m "$commit_msg"
|
| 24 |
+
echo "β
Changes committed"
|
| 25 |
+
else
|
| 26 |
+
echo "β Please commit changes before deploying"
|
| 27 |
+
exit 1
|
| 28 |
+
fi
|
| 29 |
+
fi
|
| 30 |
+
|
| 31 |
+
echo ""
|
| 32 |
+
echo "π¦ Deployment Options:"
|
| 33 |
+
echo "1. Deploy Backend to Render (recommended)"
|
| 34 |
+
echo "2. Deploy Frontend to Vercel"
|
| 35 |
+
echo "3. Deploy Both (Backend β Render, Frontend β Vercel)"
|
| 36 |
+
echo ""
|
| 37 |
+
read -p "Choose option (1-3): " option
|
| 38 |
+
|
| 39 |
+
case $option in
|
| 40 |
+
1)
|
| 41 |
+
echo ""
|
| 42 |
+
echo "π§ Deploying Backend to Render..."
|
| 43 |
+
echo ""
|
| 44 |
+
echo "Steps:"
|
| 45 |
+
echo "1. Push your code to GitHub:"
|
| 46 |
+
git push
|
| 47 |
+
echo " β
Code pushed to GitHub"
|
| 48 |
+
echo ""
|
| 49 |
+
echo "2. Go to https://dashboard.render.com"
|
| 50 |
+
echo "3. Click 'New +' β 'Web Service'"
|
| 51 |
+
echo "4. Connect your GitHub repository"
|
| 52 |
+
echo "5. Render will auto-detect render.yaml"
|
| 53 |
+
echo "6. Add your GOOGLE_API_KEY in environment variables"
|
| 54 |
+
echo "7. Click 'Create Web Service'"
|
| 55 |
+
echo ""
|
| 56 |
+
echo "β³ Deployment will take 5-10 minutes (downloading ML models)"
|
| 57 |
+
echo ""
|
| 58 |
+
echo "After deployment:"
|
| 59 |
+
echo "- Copy your backend URL (e.g., https://your-app.onrender.com)"
|
| 60 |
+
echo "- Add VITE_API_URL environment variable in Vercel"
|
| 61 |
+
echo "- Redeploy frontend"
|
| 62 |
+
;;
|
| 63 |
+
2)
|
| 64 |
+
echo ""
|
| 65 |
+
echo "π§ Deploying Frontend to Vercel..."
|
| 66 |
+
echo ""
|
| 67 |
+
echo "Steps:"
|
| 68 |
+
echo "1. Push your code to GitHub:"
|
| 69 |
+
git push
|
| 70 |
+
echo " β
Code pushed to GitHub"
|
| 71 |
+
echo ""
|
| 72 |
+
echo "2. Go to https://vercel.com/dashboard"
|
| 73 |
+
echo "3. Import your GitHub repository"
|
| 74 |
+
echo "4. Configure:"
|
| 75 |
+
echo " - Framework Preset: Vite"
|
| 76 |
+
echo " - Root Directory: frontend"
|
| 77 |
+
echo " - Build Command: npm run build"
|
| 78 |
+
echo " - Output Directory: dist"
|
| 79 |
+
echo "5. Add environment variable:"
|
| 80 |
+
echo " - VITE_API_URL = https://your-backend.onrender.com"
|
| 81 |
+
echo "6. Deploy"
|
| 82 |
+
echo ""
|
| 83 |
+
echo "β
Frontend will be live in ~2 minutes"
|
| 84 |
+
;;
|
| 85 |
+
3)
|
| 86 |
+
echo ""
|
| 87 |
+
echo "π§ Deploying Full Stack..."
|
| 88 |
+
echo ""
|
| 89 |
+
git push
|
| 90 |
+
echo "β
Code pushed to GitHub"
|
| 91 |
+
echo ""
|
| 92 |
+
echo "π Follow these steps:"
|
| 93 |
+
echo ""
|
| 94 |
+
echo "STEP 1: Deploy Backend to Render"
|
| 95 |
+
echo "--------------------------------"
|
| 96 |
+
echo "1. Go to https://dashboard.render.com"
|
| 97 |
+
echo "2. Click 'New +' β 'Web Service'"
|
| 98 |
+
echo "3. Connect your GitHub repository"
|
| 99 |
+
echo "4. Render will auto-detect render.yaml"
|
| 100 |
+
echo "5. Add GOOGLE_API_KEY in environment variables"
|
| 101 |
+
echo "6. Click 'Create Web Service'"
|
| 102 |
+
echo "7. Wait for deployment (5-10 minutes)"
|
| 103 |
+
echo "8. Copy your backend URL"
|
| 104 |
+
echo ""
|
| 105 |
+
echo "STEP 2: Deploy Frontend to Vercel"
|
| 106 |
+
echo "---------------------------------"
|
| 107 |
+
echo "1. Go to https://vercel.com/dashboard"
|
| 108 |
+
echo "2. Import your GitHub repository"
|
| 109 |
+
echo "3. Configure:"
|
| 110 |
+
echo " - Framework Preset: Vite"
|
| 111 |
+
echo " - Root Directory: frontend"
|
| 112 |
+
echo " - Build Command: npm run build"
|
| 113 |
+
echo " - Output Directory: dist"
|
| 114 |
+
echo "4. Add environment variable:"
|
| 115 |
+
echo " - VITE_API_URL = [YOUR_RENDER_BACKEND_URL]"
|
| 116 |
+
echo "5. Deploy"
|
| 117 |
+
echo ""
|
| 118 |
+
echo "STEP 3: Test"
|
| 119 |
+
echo "------------"
|
| 120 |
+
echo "1. Visit your Vercel frontend URL"
|
| 121 |
+
echo "2. Ask a question"
|
| 122 |
+
echo "3. Verify it connects to your Render backend"
|
| 123 |
+
echo ""
|
| 124 |
+
echo "β
Full deployment complete!"
|
| 125 |
+
;;
|
| 126 |
+
*)
|
| 127 |
+
echo "β Invalid option"
|
| 128 |
+
exit 1
|
| 129 |
+
;;
|
| 130 |
+
esac
|
| 131 |
+
|
| 132 |
+
echo ""
|
| 133 |
+
echo "π For detailed instructions, see:"
|
| 134 |
+
echo " - DEPLOYMENT_OPTIONS.md (overview)"
|
| 135 |
+
echo " - BACKEND_DEPLOY.md (Render setup)"
|
| 136 |
+
echo " - README.md (general setup)"
|
render.yaml
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
- type: web
|
| 3 |
+
name: escalation-api-backend
|
| 4 |
+
runtime: python
|
| 5 |
+
plan: starter
|
| 6 |
+
buildCommand: pip install -r requirements.txt
|
| 7 |
+
startCommand: uvicorn src.main:app --host 0.0.0.0 --port $PORT
|
| 8 |
+
envVars:
|
| 9 |
+
- key: GOOGLE_API_KEY
|
| 10 |
+
sync: false
|
| 11 |
+
- key: ARTICLES_DIR
|
| 12 |
+
value: data/articles
|
| 13 |
+
- key: EMBEDDING_MODEL
|
| 14 |
+
value: all-MiniLM-L6-v2
|
| 15 |
+
- key: RELEVANCE_THRESHOLD
|
| 16 |
+
value: "0.5"
|
| 17 |
+
- key: TOP_K_CHUNKS
|
| 18 |
+
value: "3"
|
| 19 |
+
- key: CHUNK_SIZE
|
| 20 |
+
value: "500"
|
| 21 |
+
- key: CHUNK_OVERLAP
|
| 22 |
+
value: "50"
|
| 23 |
+
- key: LLM_MODEL
|
| 24 |
+
value: gemini-1.5-flash
|
| 25 |
+
- key: LLM_TEMPERATURE
|
| 26 |
+
value: "0.3"
|
| 27 |
+
- key: CORS_ORIGINS
|
| 28 |
+
value: https://escalation-api-frontend.vercel.app,http://localhost:5173
|
requirements.txt
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# Core dependencies
|
| 2 |
pydantic>=2.5.0
|
| 3 |
pydantic-settings>=2.1.0
|
|
|
|
| 1 |
+
# Web framework
|
| 2 |
+
fastapi==0.104.1
|
| 3 |
+
uvicorn[standard]==0.24.0
|
| 4 |
+
|
| 5 |
# Core dependencies
|
| 6 |
pydantic>=2.5.0
|
| 7 |
pydantic-settings>=2.1.0
|