# Z-Image-Turbo API Wrapper **Simple REST API wrapper for the Z-Image-Turbo Gradio space that returns direct image URLs** ## What is this? This project wraps the Gradio-based Z-Image-Turbo API and provides: - ✅ Simple REST endpoints - ✅ Automatic polling for async results - ✅ Direct image URL response - ✅ Both Python (Flask) and Node.js (Express) implementations - ✅ Production-ready with Docker support - ✅ Easy deployment (systemd, PM2, Docker Compose, etc.) ## Features - **Simple API**: Single endpoint - POST `/api/generate` with a prompt - **Direct URLs**: Returns the image URL directly (no base64, no polling needed from client) - **Async Handling**: Handles the Gradio async polling internally - **Error Handling**: Graceful error responses with helpful messages - **CORS Support**: Ready for web frontend integration - **Configurable**: Adjustable timeout, polling intervals, parameters - **Logging**: Detailed logging for debugging - **Health Checks**: Built-in health endpoint - **Scalable**: Multi-worker support (Gunicorn, PM2, Docker) ## Quick Start ### Option 1: Python (Recommended) ```bash # Setup bash setup.sh # Run source venv/bin/activate python app.py # Test curl -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "A beautiful sunset"}' ``` ### Option 2: Node.js ```bash # Setup bash setup-node.sh # Run npm start # Test curl -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "A beautiful sunset"}' ``` ### Option 3: Docker ```bash # Python docker build -t z-image-api -f Dockerfile.python . docker run -p 5000:5000 z-image-api # Node.js docker build -t z-image-api -f Dockerfile.nodejs . docker run -p 5000:5000 z-image-api ``` ## API Endpoints ### GET `/health` Health check endpoint ```bash curl http://localhost:5000/health ``` Response: ```json {"status": "ok"} ``` ### GET `/api/info` Get API information and available parameters ```bash curl http://localhost:5000/api/info ``` ### POST `/api/generate` Generate an image **Request:** ```bash curl -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{ "prompt": "A beautiful sunset over mountains", "steps": 20, "height": 512, "width": 512 }' ``` **Parameters:** | Parameter | Type | Default | Required | Description | |-----------|------|---------|----------|-------------| | prompt | string | - | ✓ Yes | Text description of the image | | steps | integer | 20 | No | Inference steps (1-50) | | height | integer | 512 | No | Image height in pixels | | width | integer | 512 | No | Image width in pixels | **Response:** ```json { "success": true, "prompt": "A beautiful sunset over mountains", "steps": 20, "height": 512, "width": 512, "image_url": "https://example.com/path/to/image.png", "image_path": "/path/to/local/image", "size": 123456, "mime_type": "image/png", "filename": "image.png" } ``` **Error Response:** ```json { "success": false, "error": "Error message describing what went wrong" } ``` ## Usage Examples ### Curl **Simple generation:** ```bash curl -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "A cat sitting on a window sill"}' ``` **Extract and download image:** ```bash RESPONSE=$(curl -s -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "A sunset over the ocean"}') IMAGE_URL=$(echo $RESPONSE | jq -r '.image_url') curl -o my_image.png "$IMAGE_URL" ``` ### Python ```python import requests response = requests.post( 'http://localhost:5000/api/generate', json={ 'prompt': 'A magical forest', 'steps': 25, 'height': 768, 'width': 768 } ) result = response.json() if result['success']: print(f"Image URL: {result['image_url']}") # Download it img = requests.get(result['image_url']) with open('image.png', 'wb') as f: f.write(img.content) ``` ### JavaScript ```javascript async function generateImage(prompt) { const response = await fetch('http://localhost:5000/api/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: prompt, steps: 20, height: 512, width: 512 }) }); const result = await response.json(); if (result.success) { console.log('Image URL:', result.image_url); // Use the image URL document.getElementById('image').src = result.image_url; } } generateImage('A beautiful landscape'); ``` ### cURL with timeout handling ```bash #!/bin/bash TIMEOUT=600 # 10 minutes PROMPT="A futuristic city with neon lights" echo "Generating image..." RESPONSE=$(curl -s -X POST http://localhost:5000/api/generate \ --max-time $TIMEOUT \ -H "Content-Type: application/json" \ -d "{\"prompt\": \"$PROMPT\", \"steps\": 25}") if [ $? -eq 0 ]; then SUCCESS=$(echo $RESPONSE | jq -r '.success') if [ "$SUCCESS" == "true" ]; then IMAGE_URL=$(echo $RESPONSE | jq -r '.image_url') echo "✓ Generated: $IMAGE_URL" else ERROR=$(echo $RESPONSE | jq -r '.error') echo "✗ Error: $ERROR" fi else echo "✗ Request failed or timed out" fi ``` ## Files Included ``` ├── app.py # Flask implementation (Python) ├── server.js # Express implementation (Node.js) ├── requirements.txt # Python dependencies ├── package.json # Node.js dependencies ├── setup.sh # Python quick setup script ├── setup-node.sh # Node.js quick setup script ├── README.md # This file ├── SETUP_GUIDE.md # Detailed setup and deployment guide ├── USAGE_EXAMPLES.md # More detailed usage examples └── Dockerfile # Docker build file ``` ## Configuration ### Environment Variables Create a `.env` file: ```bash # API Settings GRADIO_API_URL=https://mohamedislegend4-z-image-turbo-api.hf.space PORT=5000 # Server Settings WORKERS=4 TIMEOUT=300 DEBUG=False # Polling Settings MAX_POLL_ATTEMPTS=120 POLL_INTERVAL=1 ``` ### Python Configuration Edit the constants in `app.py`: ```python GRADIO_API_URL = "https://mohamedislegend4-z-image-turbo-api.hf.space" MAX_POLL_ATTEMPTS = 120 # 2 minutes POLL_INTERVAL = 1 # seconds ``` ### Node.js Configuration Edit the constants in `server.js`: ```javascript const PORT = process.env.PORT || 5000; const GRADIO_API_URL = 'https://mohamedislegend4-z-image-turbo-api.hf.space'; const MAX_POLL_ATTEMPTS = 120; const POLL_INTERVAL = 1000; // ms ``` ## Performance Tips ### Image Generation Parameters | Parameter | Fast | Balanced | High Quality | |-----------|------|----------|--------------| | steps | 8-12 | 20-25 | 40-50 | | height | 256 | 512 | 768-1024 | | width | 256 | 512 | 768-1024 | | time | 10-20s | 30-60s | 60-120s | ### Server Optimization **Python (Gunicorn):** ```bash gunicorn -w 8 -b 0.0.0.0:5000 \ --timeout 300 \ --max-requests 1000 \ --worker-class sync \ app:app ``` **Node.js (PM2):** ```bash pm2 start server.js -i 4 --name z-image-api pm2 save ``` ## Deployment ### Systemd (Python) ```bash sudo cat > /etc/systemd/system/z-image-api.service << EOF [Unit] Description=Z-Image-Turbo API After=network.target [Service] Type=simple User=www-data WorkingDirectory=/opt/z-image-api ExecStart=/opt/z-image-api/venv/bin/gunicorn -w 4 -b 0.0.0.0:5000 --timeout 300 app:app Restart=always [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable z-image-api sudo systemctl start z-image-api ``` ### Docker Compose See `SETUP_GUIDE.md` for complete Docker Compose configuration. ## Troubleshooting ### "Connection refused" - Ensure the server is running - Check if port 5000 is in use: `lsof -i :5000` ### "Timeout waiting for result" - The Gradio API is slow or overloaded - Try reducing `steps` or image size - Check if `mohamedislegend4-z-image-turbo-api.hf.space` is accessible ### "Empty image_url" - The Gradio API didn't return image data - Check server logs for details - Try again with simpler parameters ### Slow responses - First request initializes the model (slow) - Subsequent requests are faster - Network latency to Gradio API affects speed See `SETUP_GUIDE.md` for more troubleshooting tips. ## How It Works ``` Client Request ↓ Flask/Express Server (this wrapper) ↓ Call Gradio Endpoint: /gradio_api/call/v2/generate ↓ Get event_id ↓ Poll Result: /gradio_api/call/generate/{event_id} (every 1 second) ↓ Wait for result (up to 2 minutes) ↓ Extract image data ↓ Return image_url to client ↓ Client Response with image_url ``` ## What's Next? 1. **Start the server** (see Quick Start) 2. **Test with curl** (see API Endpoints) 3. **Integrate into your app** (see Usage Examples) 4. **Deploy to production** (see SETUP_GUIDE.md) 5. **Monitor and optimize** (see SETUP_GUIDE.md) ## Requirements **Python:** - Python 3.8+ - Flask 3.0+ - Requests 2.31+ **Node.js:** - Node.js 14+ - Express 4.18+ - Axios 1.6+ **Both:** - Internet connection (to reach Gradio API) - Reasonable timeout (images can take 30-120 seconds) ## License MIT ## Support For issues or questions: 1. Check `SETUP_GUIDE.md` troubleshooting section 2. Check server logs 3. Ensure Gradio API is accessible 4. Review `USAGE_EXAMPLES.md` for code samples ## Credits - Built for: Z-Image-Turbo by Tongyi-MAI - Gradio Space: mohamedislegend4/Z-Image-Turbo-API - Wrapper created: 2024 --- **Ready to generate images? Start with:** ```bash # Python bash setup.sh && source venv/bin/activate && python app.py # Node.js bash setup-node.sh && npm start ``` Then test with: ```bash curl -X POST http://localhost:5000/api/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "Your image description here"}' ```