# Z-Image-Turbo API Wrapper - Complete Setup Guide ## Overview This wrapper provides a simple REST API endpoint that handles: 1. Calling the Gradio Z-Image-Turbo API 2. Polling for results (async handling) 3. Returning the direct image URL **Two implementations provided:** - Python (Flask) - Node.js (Express) --- ## Python Setup (Recommended) ### Prerequisites - Python 3.8+ - pip ### Installation 1. **Clone/Download files** ```bash # Get app.py, requirements.txt, USAGE_EXAMPLES.md ls -la # Should see: app.py, requirements.txt, USAGE_EXAMPLES.md ``` 2. **Install dependencies** ```bash pip install -r requirements.txt ``` 3. **Run the server** ```bash python app.py ``` Expected output: ``` ============================================================ Z-Image-Turbo API Wrapper ============================================================ Gradio API URL: https://mohamedislegend4-z-image-turbo-api.hf.space Starting Flask server... ============================================================ * Running on http://0.0.0.0:5000 ``` 4. **Test the API** ```bash # Health check curl http://localhost:5000/health # Generate image curl -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "A beautiful sunset"}' ``` ### Production Deployment (Python) Using Gunicorn: ```bash pip install gunicorn # Run with 4 workers gunicorn -w 4 -b 0.0.0.0:5000 --timeout 300 app:app ``` Using systemd service: ```bash sudo cat > /etc/systemd/system/z-image-api.service << EOF [Unit] Description=Z-Image-Turbo API Wrapper After=network.target [Service] Type=notify User=www-data WorkingDirectory=/home/www-data/z-image-api ExecStart=/usr/bin/gunicorn -w 4 -b 0.0.0.0:5000 --timeout 300 app:app Restart=always [Install] WantedBy=multi-user.target EOF sudo systemctl enable z-image-api sudo systemctl start z-image-api ``` --- ## Node.js Setup ### Prerequisites - Node.js 14+ - npm ### Installation 1. **Download files** ```bash # Get server.js and package.json ls -la # Should see: server.js, package.json ``` 2. **Install dependencies** ```bash npm install ``` 3. **Run the server** ```bash npm start ``` Or with auto-reload during development: ```bash npm install --save-dev nodemon npm run dev ``` Expected output: ``` [2024-01-15T10:30:45.123Z] INFO: ============================================================ [2024-01-15T10:30:45.124Z] INFO: Z-Image-Turbo API Wrapper (Node.js) [2024-01-15T10:30:45.125Z] INFO: ============================================================ [2024-01-15T10:30:45.126Z] INFO: Gradio API URL: https://... [2024-01-15T10:30:45.127Z] INFO: Server running on: http://localhost:5000 ``` 4. **Test the API** ```bash # Health check curl http://localhost:5000/health # Generate image curl -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "A beautiful sunset"}' ``` ### Production Deployment (Node.js) Using PM2: ```bash npm install -g pm2 # Start pm2 start server.js --name "z-image-api" -i 4 # Make it restart on boot pm2 startup pm2 save ``` Using Docker: ```bash cat > Dockerfile << 'EOF' FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY server.js . EXPOSE 5000 CMD ["node", "server.js"] EOF docker build -t z-image-api . docker run -d -p 5000:5000 --name z-image-api z-image-api ``` --- ## Docker Deployment (Both) ### Python Version ```bash cat > Dockerfile << 'EOF' FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app.py . EXPOSE 5000 CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "--timeout", "300", "app:app"] EOF # Build docker build -t z-image-api-python . # Run docker run -d -p 5000:5000 --name z-image-api z-image-api-python ``` ### Docker Compose (Both) ```yaml version: '3.8' services: # Python version z-image-python: image: z-image-api-python ports: - "5000:5000" environment: - FLASK_ENV=production restart: unless-stopped # Node.js version (use one or the other) z-image-node: image: z-image-api-node ports: - "5001:5000" environment: - NODE_ENV=production restart: unless-stopped # Nginx reverse proxy nginx: image: nginx:latest ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - z-image-python - z-image-node restart: unless-stopped ``` --- ## API Usage Quick Start ### Basic Request ```bash curl -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{ "prompt": "A serene forest landscape at dawn", "steps": 20, "height": 512, "width": 512 }' ``` ### Response Format ```json { "success": true, "prompt": "A serene forest landscape at dawn", "steps": 20, "height": 512, "width": 512, "image_url": "https://example.com/path/to/image.png", "image_path": "/tmp/path/to/image", "size": 234567, "mime_type": "image/png", "filename": "image.png" } ``` ### Download Generated Image ```bash RESPONSE=$(curl -s -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "A beautiful sunset"}') IMAGE_URL=$(echo $RESPONSE | jq -r '.image_url') if [ "$IMAGE_URL" != "null" ]; then curl -o my_image.png "$IMAGE_URL" echo "Downloaded to my_image.png" fi ``` --- ## Configuration ### Environment Variables Create a `.env` file: ```bash # API Configuration GRADIO_API_URL=https://mohamedislegend4-z-image-turbo-api.hf.space PORT=5000 # Server Configuration WORKERS=4 TIMEOUT=300 DEBUG=False # Polling Configuration MAX_POLL_ATTEMPTS=120 POLL_INTERVAL=1 ``` ### Python: Load Environment Variables Modify `app.py`: ```python from dotenv import load_dotenv import os load_dotenv() GRADIO_API_URL = os.getenv("GRADIO_API_URL", "https://...") MAX_POLL_ATTEMPTS = int(os.getenv("MAX_POLL_ATTEMPTS", 120)) ``` ### Node.js: Load Environment Variables Modify `server.js`: ```javascript require('dotenv').config(); const PORT = process.env.PORT || 5000; const GRADIO_API_URL = process.env.GRADIO_API_URL || 'https://...'; const MAX_POLL_ATTEMPTS = parseInt(process.env.MAX_POLL_ATTEMPTS) || 120; ``` --- ## Troubleshooting ### Issue: "Connection refused" **Solution:** Make sure the server is running ```bash # Python python app.py # Node.js npm start ``` ### Issue: "Timeout waiting for image" **Cause:** The Gradio API is slow or overloaded **Solutions:** - Reduce `steps` parameter (default 20, try 8-15) - Use smaller image dimensions (try 256x256 or 512x512) - Try again later ### Issue: "Empty image_url in response" **Cause:** The Gradio API didn't return image data **Debug:** Check server logs for error messages ### Issue: High latency/slow responses **Cause:** - First request needs model initialization - Network latency to Gradio API **Solutions:** - Use a server closer to the Gradio API - Consider running Z-Image-Turbo locally ### Issue: "Port already in use" **Solution:** Change port or kill existing process ```bash # Find process on port 5000 lsof -i :5000 # Kill it kill -9 # Or use different port python app.py --port 5001 ``` --- ## Performance Tuning ### For Python (Gunicorn) ```bash # Adjust workers based on CPU cores # Rule: workers = (2 × cores) + 1 gunicorn -w 8 -b 0.0.0.0:5000 \ --timeout 300 \ --max-requests 1000 \ --max-requests-jitter 100 \ app:app ``` ### For Node.js (Cluster) ```javascript const cluster = require('cluster'); const os = require('os'); if (cluster.isMaster) { const numWorkers = os.cpus().length; for (let i = 0; i < numWorkers; i++) { cluster.fork(); } } else { app.listen(PORT); } ``` ### Caching Responses ```python from functools import lru_cache @app.route('/api/generate', methods=['POST']) @lru_cache(maxsize=100) def generate(): # ... implementation ``` --- ## Reverse Proxy Setup (Nginx) ```nginx upstream z_image_api { server localhost:5000 max_fails=3 fail_timeout=30s; } server { listen 80; server_name api.example.com; location /api/ { proxy_pass http://z_image_api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Increase timeout for image generation proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s; # Buffering proxy_buffering on; proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; } location /health { proxy_pass http://z_image_api; } } ``` --- ## Monitoring & Logging ### Python Logs ```bash # Real-time tail -f app.log # With Flask's built-in logging # Logs appear in console by default ``` ### Node.js Logs ```bash # PM2 logs pm2 logs z-image-api # Docker logs docker logs -f z-image-api ``` ### Health Check Script ```bash #!/bin/bash while true; do HEALTH=$(curl -s http://localhost:5000/health | jq -r '.status') if [ "$HEALTH" == "ok" ]; then echo "✓ API is healthy" else echo "✗ API is down!" # Restart if needed fi sleep 60 done ``` --- ## API Rate Limiting ### Python with Flask-Limiter ```bash pip install Flask-Limiter ``` ```python from flask_limiter import Limiter from flask_limiter.util import get_remote_address limiter = Limiter( app=app, key_func=get_remote_address, default_limits=["200 per day", "50 per hour"] ) @app.route('/api/generate', methods=['POST']) @limiter.limit("5 per minute") def generate(): # ... implementation ``` ### Node.js with express-rate-limit ```bash npm install express-rate-limit ``` ```javascript const rateLimit = require('express-rate-limit'); const limiter = rateLimit({ windowMs: 1 * 60 * 1000, // 1 minute max: 5 // 5 requests per minute }); app.post('/api/generate', limiter, (req, res) => { // ... implementation }); ``` --- ## Next Steps 1. **Start the server** (Python or Node.js) 2. **Test with curl** (see examples above) 3. **Integrate into your application** 4. **Deploy to production** (Docker, systemd, PM2, etc.) 5. **Monitor performance** (logs, metrics, health checks) See `USAGE_EXAMPLES.md` for more detailed code examples!