hmd-comfy-client
v1.0.0
Published
ComfyUI HTTP API client library with one-shot workflow and file upload
Maintainers
Readme
hmd-comfy-client
A Node.js client library for ComfyUI's HTTP API with one-shot workflow execution and intelligent file upload handling.
Features
- ✅ One-shot execution - Workflow + file uploads in a single operation
- ✅ Smart file handling - Automatic upload from local files, URLs, or base64
- ✅ $map-based I/O - Predictable input/output mapping using workflow annotations
- ✅ HTTP polling - No WebSocket complexity
- ✅ Multiple output formats - File, base64, or URL
- ✅ TypeScript support - Full type definitions included
- ✅ Error handling - Comprehensive custom error types
Installation
npm install hmd-comfy-clientQuick Start
import { ComfyClient } from 'hmd-comfy-client';
const client = new ComfyClient('http://127.0.0.1:8188');
const result = await client.generateImage({
workflow: './workflow.json',
inputs: {
prompt: 'A beautiful sunset over mountains',
seed: 123456
}
});
console.log('Generated:', result.images[0].url);Usage
Basic Generation
import { ComfyClient } from 'hmd-comfy-client';
const client = new ComfyClient('http://127.0.0.1:8188');
const result = await client.generateImage({
workflow: './my-workflow.json',
inputs: {
prompt: 'A serene mountain landscape at sunset',
negative_prompt: 'blurry, low quality',
seed: 123456,
steps: 30,
cfg: 7.5
}
});
console.log(result.images);With File Upload
const result = await client.generateImage({
workflow: './workflow.json',
inputs: {
prompt: 'Transform into an oil painting',
image: 'file:./input.png', // Local file
seed: 123456
}
});Using URLs for Input Images
const result = await client.generateImage({
workflow: './workflow.json',
inputs: {
prompt: 'Cyberpunk style transformation',
image: 'file:https://example.com/image.jpg', // URL
seed: 123456
}
});Using Base64 Images
const result = await client.generateImage({
workflow: './workflow.json',
inputs: {
prompt: 'Enhance this image',
image: 'file:data:image/png;base64,iVBORw0KGg...', // Base64
seed: 123456
}
});Output Handling
Get URLs Only (Default)
const result = await client.generateImage({
workflow: './workflow.json',
inputs: { prompt: 'A cat' }
});
// Access URLs
result.images.forEach(img => {
console.log(img.url);
});Save to File
const result = await client.generateImage({
workflow: './workflow.json',
inputs: { prompt: 'A cat' },
output: {
type: 'file',
destination: './outputs'
}
});
console.log('Saved to:', result.images[0].savedPath);Get as Base64
const result = await client.generateImage({
workflow: './workflow.json',
inputs: { prompt: 'A cat' },
output: {
type: 'base64'
}
});
console.log('Base64:', result.images[0].base64);Multiple Outputs with Mapping
const result = await client.generateImage({
workflow: './workflow.json',
inputs: { prompt: 'A cat' },
output: {
type: 'file',
destination: './outputs',
mapping: {
'output': 'main-image.png',
'output2': 'preview.png'
}
}
});$map-Based Workflows
For complex workflows with multiple nodes of the same type, use the $map annotation pattern in node titles.
Workflow Setup
Add $map to node titles in your ComfyUI workflow:
For single input (string value):
{
"6": {
"class_type": "CLIPTextEncode",
"_meta": {
"title": "CLIP Text Encode {\"$map\": \"prompt\"}"
},
"inputs": {
"text": "default text"
}
}
}For multiple inputs (object value):
{
"27": {
"class_type": "EmptySD3LatentImage",
"_meta": {
"title": "Latent Image {\"$map\": {\"width\": \"width\", \"height\": \"height\"}}"
},
"inputs": {
"width": 512,
"height": 512
}
}
}For outputs:
{
"9": {
"class_type": "SaveImage",
"_meta": {
"title": "Save Image {\"$map\": \"output\"}"
}
}
}Using $map Workflows
const result = await client.generateImage({
workflow: './map-workflow.json',
inputs: {
prompt: 'A beautiful landscape', // Maps to node with $map: "prompt"
width: 768, // Maps to node input
height: 512 // Maps to node input
},
output: {
type: 'file',
destination: './outputs',
mapping: {
'output': 'main.png', // Maps to node with $map: "output"
'output2': 'secondary.png'
}
}
});
// Result includes mapKey
result.images.forEach(img => {
console.log(`${img.mapKey}: ${img.savedPath}`);
});API Reference
ComfyClient
Constructor
const client = new ComfyClient(baseUrl);baseUrl(string, optional): ComfyUI server URL. Default:'http://127.0.0.1:8188'
Methods
generateImage(options)
Generate images using a workflow.
await client.generateImage({
workflow: string | object,
inputs?: object,
output?: {
type?: 'file' | 'base64' | 'url',
destination?: string,
mapping?: object,
format?: string
}
});Parameters:
workflow: Path to workflow file, URL, JSON string, or workflow objectinputs: Input values for the workflow. Prefix file inputs withfile:output.type: Output format ('url','file', or'base64')output.destination: Directory path for file outputoutput.mapping: Map output names to filenamesoutput.format: File extension (default:'png')
Returns: Promise
downloadImage(imageInfo, outputPath)
Download a generated image to disk.
await client.downloadImage(result.images[0], './output.png');getImageAsBase64(imageInfo)
Get image as base64 string.
const base64 = await client.getImageAsBase64(result.images[0]);getQueue()
Get current queue status.
const queue = await client.getQueue();interrupt()
Interrupt current generation.
await client.interrupt();getSystemStats()
Get ComfyUI system statistics.
const stats = await client.getSystemStats();Constants
import { SAMPLERS, SCHEDULERS, NODE_TYPES } from 'hmd-comfy-client';
console.log(SAMPLERS.EULER); // 'euler'
console.log(SCHEDULERS.KARRAS); // 'karras'
console.log(NODE_TYPES.KSAMPLER); // 'KSampler'Error Handling
import {
ComfyError,
ComfyWorkflowError,
ComfyUploadError,
ComfyPromptError,
ComfyTimeoutError,
ComfyConnectionError,
handleComfyError
} from 'hmd-comfy-client';
try {
const result = await client.generateImage({...});
} catch (error) {
if (error instanceof ComfyTimeoutError) {
console.error('Generation timed out');
} else if (error instanceof ComfyUploadError) {
console.error('File upload failed:', error.message);
} else {
handleComfyError(error);
}
}Advanced Examples
Batch Generation
const prompts = [
'A serene lake at dawn',
'A bustling city at night',
'A peaceful forest in autumn'
];
for (const prompt of prompts) {
const result = await client.generateImage({
workflow: './workflow.json',
inputs: {
prompt,
seed: Math.floor(Math.random() * 1000000)
},
output: {
type: 'file',
destination: './batch-output'
}
});
console.log(`Generated: ${prompt}`);
}Custom Workflow Modifications
import fs from 'fs';
// Load and modify workflow
const workflow = JSON.parse(fs.readFileSync('./workflow.json', 'utf-8'));
// Modify specific nodes
workflow["3"].inputs.seed = 123456;
workflow["3"].inputs.steps = 40;
workflow["6"].inputs.text = 'My custom prompt';
const result = await client.generateImage({
workflow,
inputs: {}
});Working with Multiple File Inputs
const result = await client.generateImage({
workflow: './multi-input-workflow.json',
inputs: {
image1: 'file:./input1.png',
image2: 'file:https://example.com/input2.jpg',
image3: 'file:data:image/png;base64,...',
prompt: 'Blend these images',
seed: 123456
}
});TypeScript Support
Full TypeScript definitions are included:
import {
ComfyClient,
GenerateImageOptions,
GenerateImageResult,
ImageInfo
} from 'hmd-comfy-client';
const client: ComfyClient = new ComfyClient();
const options: GenerateImageOptions = {
workflow: './workflow.json',
inputs: {
prompt: 'A landscape'
}
};
const result: GenerateImageResult = await client.generateImage(options);Requirements
- Node.js >= 18.0.0
- ComfyUI server running and accessible
License
MIT
