Spaces:
Running
Running
rdmlx commited on
Commit ·
b3dfc35
1
Parent(s): 7817fe3
Add API test script and remove deployment guide
Browse files- Add test_api.sh: Comprehensive test suite for API validation
- Tests health check endpoint
- Validates semantic search with query 'what did jesus say about eternal life'
- Asserts top result is John 17 with similarity >= 0.77
- Tests testament filter functionality
- Checks interactive documentation accessibility
- All 8 tests passing ✓
- Remove DEPLOYMENT_GUIDE.md (no longer needed post-deployment)
Test results: Book jhn, Chapter 17, Similarity 0.789 (> 0.77 threshold)
- DEPLOYMENT_GUIDE.md +0 -326
- test_api.sh +146 -0
DEPLOYMENT_GUIDE.md
DELETED
|
@@ -1,326 +0,0 @@
|
|
| 1 |
-
# Deployment Guide: Biblos API to Hugging Face Spaces
|
| 2 |
-
|
| 3 |
-
This guide walks you through deploying the Biblos Semantic Search API to Hugging Face Spaces.
|
| 4 |
-
|
| 5 |
-
## Prerequisites
|
| 6 |
-
|
| 7 |
-
1. **Hugging Face Account** - Sign up at [huggingface.co](https://huggingface.co)
|
| 8 |
-
2. **Git** - Installed on your machine
|
| 9 |
-
3. **Python 3.10+** - For running the data preparation script
|
| 10 |
-
|
| 11 |
-
---
|
| 12 |
-
|
| 13 |
-
## Step 1: Prepare the Data
|
| 14 |
-
|
| 15 |
-
First, extract the Bible embeddings from your existing ZIP files:
|
| 16 |
-
|
| 17 |
-
```bash
|
| 18 |
-
# Navigate to the hf-spaces directory
|
| 19 |
-
cd hf-spaces
|
| 20 |
-
|
| 21 |
-
# Run the data preparation script (uses desktop embeddings by default)
|
| 22 |
-
python prepare_data.py
|
| 23 |
-
|
| 24 |
-
# OR, use iOS embeddings (smaller, quantized):
|
| 25 |
-
python prepare_data.py --ios
|
| 26 |
-
|
| 27 |
-
# OR, specify custom paths:
|
| 28 |
-
python prepare_data.py --source ../public/data --output ./data
|
| 29 |
-
```
|
| 30 |
-
|
| 31 |
-
This will:
|
| 32 |
-
- Extract JSON files from ZIP archives
|
| 33 |
-
- Validate embeddings
|
| 34 |
-
- Create a `data/` directory with 66 JSON files (one per book)
|
| 35 |
-
- Total size: ~200-250MB
|
| 36 |
-
|
| 37 |
-
**Verify the extraction:**
|
| 38 |
-
```bash
|
| 39 |
-
ls -lh data/
|
| 40 |
-
# Should show 66 .json files
|
| 41 |
-
```
|
| 42 |
-
|
| 43 |
-
---
|
| 44 |
-
|
| 45 |
-
## Step 2: Test Locally (Optional but Recommended)
|
| 46 |
-
|
| 47 |
-
Before deploying, test the API locally:
|
| 48 |
-
|
| 49 |
-
```bash
|
| 50 |
-
# Install dependencies
|
| 51 |
-
pip install -r requirements.txt
|
| 52 |
-
|
| 53 |
-
# Run the server
|
| 54 |
-
python -m uvicorn app:app --host 0.0.0.0 --port 7860
|
| 55 |
-
|
| 56 |
-
# In another terminal, test the API
|
| 57 |
-
curl -X POST http://localhost:7860/search \
|
| 58 |
-
-H "Content-Type: application/json" \
|
| 59 |
-
-d '{"query": "love one another", "limit": 3}'
|
| 60 |
-
```
|
| 61 |
-
|
| 62 |
-
Visit http://localhost:7860/docs for interactive API documentation.
|
| 63 |
-
|
| 64 |
-
---
|
| 65 |
-
|
| 66 |
-
## Step 3: Create a Hugging Face Space
|
| 67 |
-
|
| 68 |
-
1. **Go to Hugging Face** - Visit [huggingface.co/spaces](https://huggingface.co/spaces)
|
| 69 |
-
|
| 70 |
-
2. **Click "Create new Space"**
|
| 71 |
-
|
| 72 |
-
3. **Configure the Space:**
|
| 73 |
-
- **Space name**: Choose a name (e.g., `biblos-api`)
|
| 74 |
-
- **License**: MIT
|
| 75 |
-
- **SDK**: Select **Docker**
|
| 76 |
-
- **Space hardware**: CPU basic (free)
|
| 77 |
-
- **Visibility**: Public or Private (your choice)
|
| 78 |
-
|
| 79 |
-
4. **Click "Create Space"**
|
| 80 |
-
|
| 81 |
-
---
|
| 82 |
-
|
| 83 |
-
## Step 4: Upload Files to Your Space
|
| 84 |
-
|
| 85 |
-
### Option A: Using Git (Recommended)
|
| 86 |
-
|
| 87 |
-
```bash
|
| 88 |
-
# Clone your Space repository (replace YOUR-USERNAME and YOUR-SPACE-NAME)
|
| 89 |
-
git clone https://huggingface.co/spaces/YOUR-USERNAME/YOUR-SPACE-NAME
|
| 90 |
-
cd YOUR-SPACE-NAME
|
| 91 |
-
|
| 92 |
-
# Copy all files from hf-spaces directory
|
| 93 |
-
cp -r ../hf-spaces/* .
|
| 94 |
-
|
| 95 |
-
# Add all files to git
|
| 96 |
-
git add .
|
| 97 |
-
|
| 98 |
-
# Commit
|
| 99 |
-
git commit -m "Initial deployment of Biblos API"
|
| 100 |
-
|
| 101 |
-
# Push to Hugging Face (this triggers deployment)
|
| 102 |
-
git push
|
| 103 |
-
```
|
| 104 |
-
|
| 105 |
-
### Option B: Using Web Interface
|
| 106 |
-
|
| 107 |
-
1. Click "Files and versions" tab in your Space
|
| 108 |
-
2. Click "Add file" → "Upload files"
|
| 109 |
-
3. Upload these files from the `hf-spaces/` directory:
|
| 110 |
-
- `app.py`
|
| 111 |
-
- `requirements.txt`
|
| 112 |
-
- `Dockerfile`
|
| 113 |
-
- `README.md`
|
| 114 |
-
- The entire `data/` directory (66 JSON files)
|
| 115 |
-
4. Commit the changes
|
| 116 |
-
|
| 117 |
-
**Important:** Make sure to upload the `data/` directory with all 66 JSON files!
|
| 118 |
-
|
| 119 |
-
---
|
| 120 |
-
|
| 121 |
-
## Step 5: Wait for Deployment
|
| 122 |
-
|
| 123 |
-
After pushing/uploading:
|
| 124 |
-
|
| 125 |
-
1. **HF Spaces will automatically build** your Docker container
|
| 126 |
-
2. You'll see logs in the "Logs" tab
|
| 127 |
-
3. Initial build takes **5-10 minutes**
|
| 128 |
-
4. Once complete, you'll see: `Application startup complete`
|
| 129 |
-
|
| 130 |
-
**Build process:**
|
| 131 |
-
- Install Python dependencies
|
| 132 |
-
- Download the BGE-large model (~639MB)
|
| 133 |
-
- Load all Bible embeddings into memory
|
| 134 |
-
- Start the FastAPI server
|
| 135 |
-
|
| 136 |
-
---
|
| 137 |
-
|
| 138 |
-
## Step 6: Test Your Deployed API
|
| 139 |
-
|
| 140 |
-
Once deployment is complete, your API is live!
|
| 141 |
-
|
| 142 |
-
**Your API URL:**
|
| 143 |
-
```
|
| 144 |
-
https://YOUR-USERNAME-YOUR-SPACE-NAME.hf.space
|
| 145 |
-
```
|
| 146 |
-
|
| 147 |
-
### Test Endpoints
|
| 148 |
-
|
| 149 |
-
**Health Check:**
|
| 150 |
-
```bash
|
| 151 |
-
curl https://YOUR-USERNAME-YOUR-SPACE-NAME.hf.space/
|
| 152 |
-
```
|
| 153 |
-
|
| 154 |
-
**Search:**
|
| 155 |
-
```bash
|
| 156 |
-
curl -X POST https://YOUR-USERNAME-YOUR-SPACE-NAME.hf.space/search \
|
| 157 |
-
-H "Content-Type: application/json" \
|
| 158 |
-
-d '{
|
| 159 |
-
"query": "faith without works",
|
| 160 |
-
"testament": "new",
|
| 161 |
-
"limit": 5
|
| 162 |
-
}'
|
| 163 |
-
```
|
| 164 |
-
|
| 165 |
-
**Interactive Docs:**
|
| 166 |
-
Visit: `https://YOUR-USERNAME-YOUR-SPACE-NAME.hf.space/docs`
|
| 167 |
-
|
| 168 |
-
---
|
| 169 |
-
|
| 170 |
-
## Step 7: Update Your Frontend
|
| 171 |
-
|
| 172 |
-
Update your Biblos frontend to use the new API:
|
| 173 |
-
|
| 174 |
-
**In your frontend code:**
|
| 175 |
-
```javascript
|
| 176 |
-
// Instead of client-side search, call your API
|
| 177 |
-
const API_URL = 'https://YOUR-USERNAME-YOUR-SPACE-NAME.hf.space'
|
| 178 |
-
|
| 179 |
-
async function searchBible(query, options = {}) {
|
| 180 |
-
const response = await fetch(`${API_URL}/search`, {
|
| 181 |
-
method: 'POST',
|
| 182 |
-
headers: { 'Content-Type': 'application/json' },
|
| 183 |
-
body: JSON.stringify({ query, ...options })
|
| 184 |
-
})
|
| 185 |
-
|
| 186 |
-
const data = await response.json()
|
| 187 |
-
return data.results
|
| 188 |
-
}
|
| 189 |
-
```
|
| 190 |
-
|
| 191 |
-
---
|
| 192 |
-
|
| 193 |
-
## Troubleshooting
|
| 194 |
-
|
| 195 |
-
### Build Fails
|
| 196 |
-
|
| 197 |
-
**Check logs** in the "Logs" tab. Common issues:
|
| 198 |
-
|
| 199 |
-
1. **Missing data files**
|
| 200 |
-
- Ensure all 66 JSON files are in `data/` directory
|
| 201 |
-
- Re-run `prepare_data.py` if needed
|
| 202 |
-
|
| 203 |
-
2. **Out of memory**
|
| 204 |
-
- Reduce model size (use iOS embeddings)
|
| 205 |
-
- Upgrade to larger Space hardware (paid)
|
| 206 |
-
|
| 207 |
-
3. **Import errors**
|
| 208 |
-
- Check `requirements.txt` versions
|
| 209 |
-
- Ensure all dependencies are listed
|
| 210 |
-
|
| 211 |
-
### API Returns 503 Error
|
| 212 |
-
|
| 213 |
-
This means the model hasn't loaded yet:
|
| 214 |
-
- Wait a few more seconds
|
| 215 |
-
- Check logs for model loading progress
|
| 216 |
-
- First request after cold start takes 2-3 seconds
|
| 217 |
-
|
| 218 |
-
### Slow Response Times
|
| 219 |
-
|
| 220 |
-
- First request: Expected (~2-3s for model loading)
|
| 221 |
-
- Subsequent requests: Should be 50-100ms
|
| 222 |
-
- If consistently slow:
|
| 223 |
-
- Check Space hardware in settings
|
| 224 |
-
- Consider upgrading to GPU (faster inference)
|
| 225 |
-
|
| 226 |
-
---
|
| 227 |
-
|
| 228 |
-
## Monitoring & Maintenance
|
| 229 |
-
|
| 230 |
-
### View Logs
|
| 231 |
-
1. Go to your Space page
|
| 232 |
-
2. Click "Logs" tab
|
| 233 |
-
3. See real-time logs of API requests and responses
|
| 234 |
-
|
| 235 |
-
### Update the API
|
| 236 |
-
1. Make changes locally
|
| 237 |
-
2. Commit and push:
|
| 238 |
-
```bash
|
| 239 |
-
git add .
|
| 240 |
-
git commit -m "Update API"
|
| 241 |
-
git push
|
| 242 |
-
```
|
| 243 |
-
3. HF Spaces automatically rebuilds
|
| 244 |
-
|
| 245 |
-
### Space Sleep
|
| 246 |
-
- Free CPU Spaces may sleep after 48h of inactivity
|
| 247 |
-
- First request after sleep has ~30s cold start
|
| 248 |
-
- To prevent: Upgrade to persistent hardware (paid)
|
| 249 |
-
|
| 250 |
-
---
|
| 251 |
-
|
| 252 |
-
## Cost & Limits
|
| 253 |
-
|
| 254 |
-
### Free Tier (CPU Basic)
|
| 255 |
-
- ✅ Perfect for moderate traffic
|
| 256 |
-
- ✅ No time limit
|
| 257 |
-
- ✅ No request limit
|
| 258 |
-
- ⚠️ May sleep after 48h inactivity
|
| 259 |
-
- ⚠️ Slower inference (CPU only)
|
| 260 |
-
|
| 261 |
-
### Paid Tiers
|
| 262 |
-
If you need more performance:
|
| 263 |
-
- **CPU Upgrade** ($0.04/hour) - Faster CPU, no sleep
|
| 264 |
-
- **GPU T4** ($0.60/hour) - 10x faster inference
|
| 265 |
-
- **GPU A10G** ($3.15/hour) - Best performance
|
| 266 |
-
|
| 267 |
-
Upgrade in Space Settings → "Change hardware"
|
| 268 |
-
|
| 269 |
-
---
|
| 270 |
-
|
| 271 |
-
## Security Considerations
|
| 272 |
-
|
| 273 |
-
1. **CORS** - Currently allows all origins. To restrict:
|
| 274 |
-
```python
|
| 275 |
-
# In app.py, change:
|
| 276 |
-
allow_origins=["https://yourdomain.com"]
|
| 277 |
-
```
|
| 278 |
-
|
| 279 |
-
2. **Rate Limiting** - Consider adding:
|
| 280 |
-
```bash
|
| 281 |
-
pip install slowapi
|
| 282 |
-
```
|
| 283 |
-
See [slowapi docs](https://slowapi.readthedocs.io/)
|
| 284 |
-
|
| 285 |
-
3. **API Keys** - For private use, add authentication:
|
| 286 |
-
```python
|
| 287 |
-
from fastapi.security import HTTPBearer
|
| 288 |
-
```
|
| 289 |
-
|
| 290 |
-
---
|
| 291 |
-
|
| 292 |
-
## Next Steps
|
| 293 |
-
|
| 294 |
-
1. ✅ Deploy your API
|
| 295 |
-
2. ✅ Test all endpoints
|
| 296 |
-
3. ✅ Update frontend to use API
|
| 297 |
-
4. ✅ Share API URL with other developers
|
| 298 |
-
5. ✅ Monitor usage and performance
|
| 299 |
-
6. Consider: Add caching, rate limiting, analytics
|
| 300 |
-
|
| 301 |
-
---
|
| 302 |
-
|
| 303 |
-
## Support
|
| 304 |
-
|
| 305 |
-
- **HF Spaces Docs**: [huggingface.co/docs/hub/spaces](https://huggingface.co/docs/hub/spaces)
|
| 306 |
-
- **FastAPI Docs**: [fastapi.tiangolo.com](https://fastapi.tiangolo.com)
|
| 307 |
-
- **Community Forum**: [discuss.huggingface.co](https://discuss.huggingface.co)
|
| 308 |
-
|
| 309 |
-
---
|
| 310 |
-
|
| 311 |
-
## Summary
|
| 312 |
-
|
| 313 |
-
```bash
|
| 314 |
-
# Quick deployment checklist:
|
| 315 |
-
☐ Run prepare_data.py to extract embeddings
|
| 316 |
-
☐ Create new Space on Hugging Face (Docker SDK)
|
| 317 |
-
☐ Upload all files (app.py, requirements.txt, Dockerfile, README.md, data/)
|
| 318 |
-
☐ Wait for build to complete (~5-10 min)
|
| 319 |
-
☐ Test API endpoints
|
| 320 |
-
☐ Update frontend to use new API URL
|
| 321 |
-
☐ 🎉 Your API is live!
|
| 322 |
-
```
|
| 323 |
-
|
| 324 |
-
**Estimated total time:** 15-30 minutes
|
| 325 |
-
|
| 326 |
-
Good luck! 🚀
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
test_api.sh
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Biblos API Test Script
|
| 4 |
+
# Tests the semantic search API with expected results
|
| 5 |
+
|
| 6 |
+
API_URL="https://dssjon-biblos-api.hf.space"
|
| 7 |
+
QUERY="what did jesus say about eternal life"
|
| 8 |
+
EXPECTED_BOOK="jhn"
|
| 9 |
+
EXPECTED_CHAPTER=17
|
| 10 |
+
MIN_SIMILARITY=0.77
|
| 11 |
+
|
| 12 |
+
echo "======================================"
|
| 13 |
+
echo "Biblos API Test Suite"
|
| 14 |
+
echo "======================================"
|
| 15 |
+
echo ""
|
| 16 |
+
|
| 17 |
+
# Colors for output
|
| 18 |
+
GREEN='\033[0;32m'
|
| 19 |
+
RED='\033[0;31m'
|
| 20 |
+
NC='\033[0m'
|
| 21 |
+
|
| 22 |
+
pass_count=0
|
| 23 |
+
fail_count=0
|
| 24 |
+
|
| 25 |
+
print_pass() {
|
| 26 |
+
echo -e "${GREEN}✓ PASS${NC}: $1"
|
| 27 |
+
((pass_count++))
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
print_fail() {
|
| 31 |
+
echo -e "${RED}✗ FAIL${NC}: $1"
|
| 32 |
+
((fail_count++))
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
# Test 1: Health Check
|
| 36 |
+
echo "Test 1: Health Check (GET /)"
|
| 37 |
+
health=$(curl -s "$API_URL/")
|
| 38 |
+
status=$(echo "$health" | jq -r '.status' 2>/dev/null)
|
| 39 |
+
|
| 40 |
+
if [ "$status" = "online" ]; then
|
| 41 |
+
print_pass "API is online and responding"
|
| 42 |
+
else
|
| 43 |
+
print_fail "API health check failed"
|
| 44 |
+
fi
|
| 45 |
+
|
| 46 |
+
books=$(echo "$health" | jq -r '.books_loaded' 2>/dev/null)
|
| 47 |
+
if [ "$books" = "66" ]; then
|
| 48 |
+
print_pass "All 66 books loaded"
|
| 49 |
+
else
|
| 50 |
+
print_fail "Expected 66 books, got $books"
|
| 51 |
+
fi
|
| 52 |
+
echo ""
|
| 53 |
+
|
| 54 |
+
# Test 2: Semantic Search
|
| 55 |
+
echo "Test 2: Semantic Search"
|
| 56 |
+
echo "Query: \"$QUERY\""
|
| 57 |
+
search=$(curl -s -X POST "$API_URL/search" \
|
| 58 |
+
-H "Content-Type: application/json" \
|
| 59 |
+
-d "{\"query\":\"$QUERY\",\"limit\":3}")
|
| 60 |
+
|
| 61 |
+
# Check if we got results
|
| 62 |
+
results_count=$(echo "$search" | jq -r '.results | length' 2>/dev/null)
|
| 63 |
+
if [ "$results_count" -gt 0 ]; then
|
| 64 |
+
print_pass "Search returned $results_count results"
|
| 65 |
+
else
|
| 66 |
+
print_fail "No search results returned"
|
| 67 |
+
exit 1
|
| 68 |
+
fi
|
| 69 |
+
echo ""
|
| 70 |
+
|
| 71 |
+
# Test 3: Validate Top Result
|
| 72 |
+
echo "Test 3: Validate Top Result"
|
| 73 |
+
book=$(echo "$search" | jq -r '.results[0].book')
|
| 74 |
+
chapter=$(echo "$search" | jq -r '.results[0].chapter')
|
| 75 |
+
similarity=$(echo "$search" | jq -r '.results[0].similarity')
|
| 76 |
+
content=$(echo "$search" | jq -r '.results[0].content' | head -c 80)
|
| 77 |
+
|
| 78 |
+
echo "Top Result:"
|
| 79 |
+
echo " Book: $book"
|
| 80 |
+
echo " Chapter: $chapter"
|
| 81 |
+
echo " Similarity: $similarity"
|
| 82 |
+
echo " Content: ${content}..."
|
| 83 |
+
echo ""
|
| 84 |
+
|
| 85 |
+
if [ "$book" = "$EXPECTED_BOOK" ]; then
|
| 86 |
+
print_pass "Book matches expected: $EXPECTED_BOOK"
|
| 87 |
+
else
|
| 88 |
+
print_fail "Expected book '$EXPECTED_BOOK', got '$book'"
|
| 89 |
+
fi
|
| 90 |
+
|
| 91 |
+
if [ "$chapter" = "$EXPECTED_CHAPTER" ]; then
|
| 92 |
+
print_pass "Chapter matches expected: $EXPECTED_CHAPTER"
|
| 93 |
+
else
|
| 94 |
+
print_fail "Expected chapter $EXPECTED_CHAPTER, got $chapter"
|
| 95 |
+
fi
|
| 96 |
+
|
| 97 |
+
# Check similarity threshold
|
| 98 |
+
if (( $(echo "$similarity >= $MIN_SIMILARITY" | bc -l) )); then
|
| 99 |
+
print_pass "Similarity score $similarity >= $MIN_SIMILARITY"
|
| 100 |
+
else
|
| 101 |
+
print_fail "Similarity score $similarity < $MIN_SIMILARITY"
|
| 102 |
+
fi
|
| 103 |
+
echo ""
|
| 104 |
+
|
| 105 |
+
# Test 4: Testament Filter
|
| 106 |
+
echo "Test 4: Testament Filter"
|
| 107 |
+
nt_search=$(curl -s -X POST "$API_URL/search" \
|
| 108 |
+
-H "Content-Type: application/json" \
|
| 109 |
+
-d '{"query":"love","testament":"new","limit":1}')
|
| 110 |
+
testament=$(echo "$nt_search" | jq -r '.results[0].testament')
|
| 111 |
+
|
| 112 |
+
if [ "$testament" = "NT" ]; then
|
| 113 |
+
print_pass "Testament filter working correctly"
|
| 114 |
+
else
|
| 115 |
+
print_fail "Testament filter returned: $testament"
|
| 116 |
+
fi
|
| 117 |
+
echo ""
|
| 118 |
+
|
| 119 |
+
# Test 5: Interactive Docs
|
| 120 |
+
echo "Test 5: Interactive Documentation"
|
| 121 |
+
docs_code=$(curl -s -o /dev/null -w "%{http_code}" "$API_URL/docs")
|
| 122 |
+
|
| 123 |
+
if [ "$docs_code" = "200" ]; then
|
| 124 |
+
print_pass "Interactive docs accessible at /docs"
|
| 125 |
+
else
|
| 126 |
+
print_fail "Docs endpoint returned HTTP $docs_code"
|
| 127 |
+
fi
|
| 128 |
+
echo ""
|
| 129 |
+
|
| 130 |
+
# Summary
|
| 131 |
+
echo "======================================"
|
| 132 |
+
echo "Test Summary"
|
| 133 |
+
echo "======================================"
|
| 134 |
+
total=$((pass_count + fail_count))
|
| 135 |
+
echo -e "${GREEN}Passed: $pass_count/$total${NC}"
|
| 136 |
+
|
| 137 |
+
if [ $fail_count -gt 0 ]; then
|
| 138 |
+
echo -e "${RED}Failed: $fail_count/$total${NC}"
|
| 139 |
+
echo ""
|
| 140 |
+
echo -e "${RED}Some tests failed!${NC}"
|
| 141 |
+
exit 1
|
| 142 |
+
else
|
| 143 |
+
echo ""
|
| 144 |
+
echo -e "${GREEN}All tests passed! ✓${NC}"
|
| 145 |
+
exit 0
|
| 146 |
+
fi
|