HTTP API for ComfyUI workflow submission with: - POST /api/webhook endpoint for workflow submission - Real-time progress events via callback URL - Automatic output collection (no re-encoding) - Input/Output nodes for webhook data access
203 lines
6.3 KiB
Markdown
203 lines
6.3 KiB
Markdown
# ComfyUI Workflow API
|
|
|
|
HTTP API for ComfyUI with webhook-based workflow execution. Submit workflows via HTTP, receive real-time progress updates and outputs at your callback URL.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
cd /path/to/ComfyUI/custom_nodes
|
|
git clone https://github.com/isala404/comfy-workflow-api.git
|
|
pip install -r comfy-workflow-api/requirements.txt
|
|
```
|
|
|
|
## Use Cases
|
|
|
|
- **Backend Integration**: Run ComfyUI as a headless service behind your application
|
|
- **Batch Processing**: Submit multiple workflows and receive results asynchronously
|
|
- **Distributed Systems**: Decouple workflow submission from result handling
|
|
- **Mobile/Web Apps**: Trigger image generation from any HTTP client
|
|
|
|
## How It Works
|
|
|
|
```
|
|
Client ComfyUI Your Server
|
|
│ │ │
|
|
├─── POST /api/webhook ─────────►│ │
|
|
│ (workflow + callback_url) │ │
|
|
│ │ │
|
|
│◄── {request_id, prompt_id} ────┤ │
|
|
│ │ │
|
|
│ ├── workflow.progress ──────────►│
|
|
│ ├── workflow.progress ──────────►│
|
|
│ ├── ... │
|
|
│ │ │
|
|
│ ├── multipart (files) ──────────►│
|
|
│ │ │
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### 1. Create a workflow using webhook nodes
|
|
|
|
Use **WebhookReceiver** → **WebhookTransformer** → **WebhookSend** to read inputs from HTTP and send outputs back:
|
|
|
|
```
|
|
┌─► WebhookTransformer ──► CLIPTextEncode ──┐
|
|
WebhookReceiver ────┤ (extracts "prompt") ├──► KSampler ──► WebhookSend
|
|
└─► WebhookTransformer ──► VAEEncode ───────┘
|
|
(extracts "image")
|
|
```
|
|
|
|
### 2. Submit via HTTP
|
|
|
|
```bash
|
|
# Image-to-image example
|
|
curl -X POST http://localhost:8188/api/webhook \
|
|
-F "workflow=@workflow.json" \
|
|
-F "callback_url=http://your-server.com/webhook" \
|
|
-F "prompt=turn it into a watercolor painting" \
|
|
-F "image=@input.png"
|
|
```
|
|
|
|
### 3. Receive at your callback
|
|
|
|
Your server receives:
|
|
- **Progress events** (JSON): `{"event": "workflow.progress", "progress": {"value": 5, "max": 20}}`
|
|
- **Output files** (gzip multipart): Images, audio, video, etc.
|
|
|
|
## Nodes
|
|
|
|
### WebhookReceiver
|
|
|
|
Entry point for webhook workflows. Reads request configuration from the HTTP call.
|
|
|
|
| Output | Type | Description |
|
|
|--------|------|-------------|
|
|
| webhook_context | WEBHOOK_CONTEXT | Context for other webhook nodes |
|
|
|
|
### WebhookTransformer
|
|
|
|
Extracts a field from the HTTP request. Connects to any input type.
|
|
|
|
| Input | Description |
|
|
|-------|-------------|
|
|
| webhook_context | From WebhookReceiver |
|
|
| field | Field name to extract (e.g., "prompt") |
|
|
| default_value | Optional fallback if field missing |
|
|
|
|
| Output | Type | Description |
|
|
|--------|------|-------------|
|
|
| value | * (wildcard) | Extracted value, auto-typed |
|
|
|
|
**Type inference**: Strings are converted to INT, FLOAT, BOOLEAN when applicable. File uploads become IMAGE, AUDIO, VIDEO, MESH, or LATENT based on content type.
|
|
|
|
### WebhookSend
|
|
|
|
Sends outputs to the callback URL. Supports 5 output fields.
|
|
|
|
| Input | Description |
|
|
|-------|-------------|
|
|
| webhook_context | From WebhookReceiver |
|
|
| field_1..5 | Any ComfyUI type (IMAGE, AUDIO, STRING, etc.) |
|
|
| field_1..5_name | Names for each output |
|
|
|
|
**Encoding**: IMAGE→PNG, AUDIO→FLAC, VIDEO→MP4, MESH→GLB, LATENT→safetensors
|
|
|
|
## API Reference
|
|
|
|
### POST /api/webhook
|
|
|
|
| Field | Required | Description |
|
|
|-------|----------|-------------|
|
|
| workflow | Yes | Workflow JSON |
|
|
| callback_url | Yes | URL to receive events/outputs |
|
|
| auth_header | No | Auth header name |
|
|
| auth_value | No | Auth header value |
|
|
| timeout | No | HTTP timeout (default: 60s) |
|
|
| max_retries | No | Retry attempts (default: 3) |
|
|
| *custom fields* | No | Any field accessible via WebhookTransformer |
|
|
|
|
**Response:**
|
|
```json
|
|
{"request_id": "...", "prompt_id": "...", "status": "queued"}
|
|
```
|
|
|
|
### GET /api/webhook/status/{request_id}
|
|
|
|
Check request status.
|
|
|
|
### DELETE /api/webhook/{request_id}
|
|
|
|
Cancel a queued/running workflow.
|
|
|
|
## Webhook Events
|
|
|
|
| Event | Content-Type | Description |
|
|
|-------|--------------|-------------|
|
|
| workflow.started | application/json | Execution began |
|
|
| workflow.progress | application/json | Step progress (throttled 500ms) |
|
|
| workflow.completed | multipart/form-data (gzip) | Output files + metadata |
|
|
| workflow.error | application/json | Execution failed |
|
|
|
|
**Note**: Completion payload is gzip compressed. Decompress before parsing.
|
|
|
|
## Example
|
|
|
|
**workflow.json** (see `example_workflow.json`):
|
|
```json
|
|
{
|
|
"10": {
|
|
"class_type": "WebhookReceiver",
|
|
"inputs": {"debug": true}
|
|
},
|
|
"11": {
|
|
"class_type": "WebhookTransformer",
|
|
"inputs": {"field": "prompt", "webhook_context": ["10", 0]}
|
|
},
|
|
"6": {
|
|
"class_type": "CLIPTextEncode",
|
|
"inputs": {"text": ["11", 0], "clip": ["4", 1]}
|
|
},
|
|
"...": "... rest of workflow ...",
|
|
"12": {
|
|
"class_type": "WebhookSend",
|
|
"inputs": {"webhook_context": ["10", 0], "field_1": ["8", 0]}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Python client** (see `example_client.py`):
|
|
```python
|
|
import requests, json
|
|
|
|
# Load image for img2img
|
|
image_data = open("input.png", "rb").read()
|
|
|
|
response = requests.post(
|
|
"http://localhost:8188/api/webhook",
|
|
files={
|
|
"workflow": (None, json.dumps(workflow), "application/json"),
|
|
"callback_url": (None, "http://localhost:5001/webhook"),
|
|
"prompt": (None, "make it look like a painting"),
|
|
"image": ("input.png", image_data, "image/png"),
|
|
}
|
|
)
|
|
```
|
|
|
|
## Testing
|
|
|
|
```bash
|
|
# Terminal 1: Start ComfyUI
|
|
python main.py
|
|
|
|
# Terminal 2: Run example client (image-to-image)
|
|
cd custom_nodes/comfy-workflow-api
|
|
python example_client.py sample_input.png "turn it into a watercolor painting"
|
|
```
|
|
|
|
A sample image (`sample_input.png`) is included in the repo for testing.
|
|
|
|
## License
|
|
|
|
MIT
|