ComfyUI-API-DockerCPU
Unified ComfyUI nodes for external API integration (Replicate, Fal.ai, HuggingFace)
Nodes (39)
FLUX.2 Klein image editing, hosted — your GPU bills nothing
SeedVR-class upscaling on fal.ai's servers — no GPU, and some oddly named inputs
Take up to five LoRA URLs and hand them to the API as one clean list
Type a repo and a filename, get a working HuggingFace URL
Pick a safetensor from HuggingFace without typing a URL
The Load Image that stops throwing your metadata away
The LoadImage That Reads the Recipe and Passes You the Scissors
Got a Replicate prediction ID? Re-download the result without re-running it
Point at a ZIP of PNGs — get them all back as one image batch
Point it at LM Studio (or any OpenAI-compatible server) and get text back in your graph
FLUX.2 Klein, no VRAM required — Replicate does the lifting
Klein 9B, the LoRA-ready base — fast inference aimed at fine-tunes
FLUX.2 Max, the flagship, on someone else's GPUs
FLUX.2 Pro — the professional tier, minus the professional hardware
The one with Google Search wired in
The flagship Gemini image model, parked inside your graph
Ask a vision model what's in your image — then feed the answer back into your workflow
Segment anything with a prompt — SAM3, served up on Replicate
GPT-5 as your caption writer, no OpenAI account required
SeedVR2 for video, via Replicate — the 7B model without the data-center GPU
The 'Clarity' upscaler lineage, as a Replicate API call
Z-Image Turbo with LoRAs, and no VRAM budget at all
The 'Restore Faces' toggle, but you pay Replicate instead of loading a model
The granddaddy of face restoration, now over the wire
Topaz-grade upscaling on Replicate, with the model picker exposed
RVC song covers in ComfyUI
SeedVR2 upscaling, without the datacenter GPU
Save video with the AMD audio bug already fixed
Text to a file, named after the source image
ComfyUI-API-DockerCPU
Unified ComfyUI custom nodes for external API integration (Replicate, Fal.ai, HuggingFace).
Overview
This package combines multiple external API integrations into a single ComfyUI extension:
- Replicate API (
🎨 DockerCPU API/🎨 Replicate) - Run models from Replicate - Fal.ai API (
🎨 DockerCPU API/🎨 FalAi) - Run models from Fal.ai - HuggingFace Hub (
🎨 DockerCPU API/🤗 HuggingFace) - Browse and select models from HuggingFace
Docker Deployment
This custom node is designed to be used in conjunction with ComfyUI_API-DockerContainer — a Docker build that runs ComfyUI on systems without a dedicated GPU, such as virtual machines or CPU-only servers.
All inference is offloaded to cloud APIs (Replicate, Fal.ai, HuggingFace), so no local GPU is required.
Key Features
- DockerCPU Design: No local model downloads. All inference runs externally via APIs.
- Debug/Dry-Run Mode: Test workflows without API costs by enabling debug mode on any node
- Unified Structure: Single extension for all API integrations
- Comprehensive Tests: Test outside ComfyUI to validate inputs, outputs, and parameters
Installation
Prerequisites
- ComfyUI installed
- Python 3.10+
Steps
-
Clone or copy this folder to your ComfyUI custom_nodes directory:
ComfyUI/custom_nodes/ComfyUI-API-DockerCPU/ -
Install dependencies:
pip install -r requirements.txt -
Set required environment variables:
export REPLICATE_API_TOKEN="your_token_here" # Required for Replicate export FAL_KEY="your_fal_key_here" # Required for Fal.ai export HF_TOKEN="your_hf_token_here" # Optional (for private repos)
Usage
Schema-Based Nodes (Replicate & Fal.ai)
Nodes are automatically generated from API schemas. Each model has its own node with:
- Dynamic INPUT_TYPES based on the model's parameters
- IMAGE, AUDIO, and STRING inputs
- IMAGE, AUDIO, and STRING outputs
- JSON payload output for debugging
Replicate Nodes
Example: Replicate black-forest-labs/flux-2-klein-9b
Available in category: 🎨 DockerCPU API/Replicate
Fal.ai Nodes
Example: Fal AI fal-ai/seedvr/upscale/image
Available in category: 🎨 DockerCPU API/FalAi
HuggingFace Nodes
HF Model Selector
Browse and select safetensor models from configured HuggingFace repositories.
HF Lora Combiner
Combine multiple Lora URLs into an array for use with other nodes.
HF Lora URL Builder
Build HuggingFace URLs from repository ID and filename.
Available in category: 🤗 HuggingFace
Debug/Dry-Run Mode
All schema-based nodes support debug mode:
- Add a
debugboolean input to your workflow - Set it to
True - The node will:
- Skip the actual API call
- Return the first input image as a mock output
- Output the JSON payload that would have been sent
This is useful for:
- Testing workflows without API costs
- Debugging parameter configurations
- Validating workflow connections
Schema Management
Updating Schemas
Fetch latest schemas from APIs:
# Update all schemas
python import_schemas.py --update
# Update specific API
python import_schemas.py --api replicate
python import_schemas.py --api falai
Configuration
The node generation/config stack is YAML-based.
supported_models.yaml: Provider/model/repo allowlist and per-model overridesglobal_inputs.yaml: Global media input pattern mappingglobal_parameters.yaml: Global non-media parameter mapping and orderingglobal_outputs.yaml: Global output inference/exposure rules
Example (supported_models.yaml):
replicate:
models:
black-forest-labs/flux-2-klein-9b:
display_name: "FLUX.2 [klein] 9B"
falai:
models:
fal-ai/seedvr/upscale/image:
display_name: "SeedVR Upscale Image"
huggingface:
repos:
renderartist/Technically-Color-Z-Image-Turbo:
display_name: "Color Z Image Turbo"
Testing
Run tests outside of ComfyUI:
# Run all tests
python -m pytest tests/
# Or run the schema test script directly
python tests/test_schemas.py
Environment Variables
| Variable | Description | Required |
|----------|-------------|----------|
| REPLICATE_API_TOKEN | Replicate API token | Yes |
| FAL_KEY | Fal.ai API key | Yes |
| HF_TOKEN | HuggingFace token | No (required for private repos) |
| LOCAL_LLM_API_KEY | API key for the Local LLM node when its api_key widget is empty. LocalLLM is also accepted | No (LM Studio needs none) |
| LOCAL_LLM_ENDPOINT | Endpoint for the Local LLM node when its endpoint_url widget is empty (default http://localhost:1234) | No |
| DEBUG_API_TRUSTYPANGOLIN | Enable debug output | No |
Prefer the environment variables over typing a key into the Local LLM widget: widget values are saved in the workflow JSON and embedded in every output image's metadata. If a Local LLM variable isn't set in the environment, the node reads it from .env at this repo's root (gitignored). Only the Local LLM keys are read from that file.
Utility Nodes
Available in category: 🎨 DockerCPU API/Utilities
- Load Image With Metadata - Loads an image from the input folder and extracts embedded prompt, workflow, and EXIF metadata
- Outputs:
IMAGE,MASK,prompt(JSON),Metadata RAW,BASE_FILENAME,BASE_DIR,height,width,megapixels,REL_DIR(folder relative to input, e.g.originals/1990),STEM(name without extension),SHA256(file hash),ORIGINAL,ORIGINAL_SHA256(see Provenance below) - The Crop variant has the same optional
library_rootand the same two trailing outputs
- Outputs:
- Load Images From Folder With Metadata - Loads every image in an input subfolder in natural order (
img2beforeimg10), as lists at native size- Inputs:
folder,pattern(case-insensitive glob),recursive,strip_prefix(defaultoriginals/),start_index,limit(0 = all) - Outputs (lists):
image,mask,BASE_FILENAME,STEM,REL_DIR,MIRROR_DIR(REL_DIRminusstrip_prefix),SHA256,width,height,ORIGINAL,ORIGINAL_SHA256 - Provenance (all three loaders):
ORIGINALis the PrimaryLibrary file the image derives from ("1992 Feb/img0018.jpg"),ORIGINAL_SHA256that library file's hash; both""when unknown. Resolved from the input PNG'srestorechunk (carriedoriginal+original_sha256, checked against the library; orsource, followed recursively up to 8 hops), else frominput/originals/<album>/<file>when the library twin has the same SHA-256, else by searching the library for the same SHA-256 (exactly one match wins; none or several →""and a warning listing them). For asourcechain the search uses the file the chain ends at. Optionallibrary_rootwidget, else envPRIMARY_LIBRARY, elseC:/Users/luton/OneDrive/Pictures/PrimaryLibrary; when that folder is missing (Docker) only carried values are used, unchecked. The search only hashes library images whose byte size equals the input's (os.statdoesn't download OneDrive cloud-only files; reading does); the size index is cached for 5 minutes
- Inputs:
- Load Prompt From File - Pick a
.txtfile underinput/prompts/(subfolders included, alphabetical) from a dropdown; outputs itstextreload:if file changed(default) re-reads after you edit the file;if value changedonly when another file is picked. Press R in ComfyUI to refresh the list- Subfolders show as
📁submenus at every depth (web/prompt_loader.js, classic canvas only)
- Save Image With Filename - Writes
output/<stage>/<mirror_dir>/<stem><suffix>.pngwith no counter (_00,_01, ... for batches > 1)if_exists:error(default) /overwrite/skip. Embeds prompt and workflow like Save Image- Always writes the PNG text key
restore:extra_metadata(a JSON object, or{}) plus"schema": 1,"original","original_sha256"from the optionaloriginal/original_sha256inputs (wire the loader'sORIGINAL/ORIGINAL_SHA256; empty or unconnected →null, and they override the same keys inextra_metadata) require_original(default off): whenoriginalororiginal_sha256is empty, raiserestore provenance: no library original for …and save nothing, instead of writingnull- Refuses paths outside the output folder and anything under the input folder
- Load ZIP Archive - Load PNG images from a ZIP file URL or path
- Load Replicate Prediction - Load output from a Replicate prediction by ID
- Save AMD Video - Save video with AMD GPU audio fix patch
- Save Text With Filename - Save text content to a file named after the source image
- Inputs:
text,base_dir,base_filename,replace_extension(BOOLEAN),extension(STRING) output_mode:base_dir(write intobase_dir) oroutput_stage(samestage/mirror_dir/stem/suffixpath rule as Save Image With Filename)- Refuses to write under the input folder unless
allow_input_diris on;if_existsdefaults tooverwrite
- Inputs:
Face Nodes
Available in category: 🎨 DockerCPU API/Face. All run on CPU; a GPU is used when available.
- Face Analyze (InsightFace ONNX) - SCRFD detection + 512-d ArcFace embeddings via
onnxruntime(noinsightfacepackage). Models frommodels/insightface(e.g.buffalo_l/det_10g.onnx,buffalo_l/w600k_r50.onnx); add aninsightface:key toextra_model_paths.yamlif your models live elsewheresort:left_to_right(default, box centre-x) orscore; applied to every output, so face k is the same face everywhere- Outputs:
bboxes(nativeBOUNDING_BOX),face_analysis,face_count,scores,faces_json({frame, index, x, y, width, height, score}, index 1-based)
- Draw Numbered BBoxes - Draws boxes with legible number labels (PIL only); accepts the same
BOUNDING_BOXshapes as native Draw BBoxes- Inputs:
image,bboxes,sort(as_given/left_to_right),start_index,line_width(0 = auto),font_scale(label height as a fraction of the short edge, 0 = auto),color,show_score - Outputs:
image,bboxes(in drawn order),labels_json
- Inputs:
- Face Similarity (ArcFace) - Cosine similarity of one face against a
reference_analysisand/or areference_folderof images and.npyembeddings (subfolder names become labels)- Outputs:
best_score,best_match,ranking(JSON)
- Outputs:
- Face Identify (ArcFace) - Every face in one image vs a reference folder (
<folder>/<Label>/*.png|jpg|npy, relative to the input folder or absolute). Per-label scores combine bymaxormean_top3; a label is assigned when the best score reachesthresholdand beats the best other label bymargin, elseunknown_label- List outputs, one per face:
face_crop(square,crop_pad× bbox, native resolution),label,score,runner_up,runner_up_score,suffix(_p01…),subfolder,crop_box_json,restore_json(wire into Save Image With Filenameextra_metadata); plussummary_json; thenmirror_dir,stem(the optional inputs repeated per face) andsave_dir(<label>/<mirror_dir>), so batch runs pair each face with its own image when saving. Optionalsuffix_extrais appended to each suffix (_p01_head)
- List outputs, one per face:
- Face Cluster (ArcFace) - Batch node: groups all faces from a folder (average-linkage, cosine distance ≤
distance_threshold) intocluster_01(largest) … andsingles, to bootstrap reference folders - Collect Labelled Faces - Reads a review done by moving crops between
<review_root>/<Label>/<folder>/folders into a CSV (changed= moved from the original label). Optionally copies confirmed crops into<references_root>/<Label>/under the input folder (needsallow_input_dir; neveroriginals/; honoursexclude_listandskip_labels) - Face crops saved with
restore_jsoncarry their face keypoints, so they work as references without re-detection - Load Face Detection Model (MediaPipe, device) - Native MediaPipe face landmarker loaded on
cpuor thedefaultdevice; works with the native MediaPipe detect / mask nodes
Install onnxruntime (CPU) or onnxruntime-gpu for the InsightFace nodes; cpu-requirements.txt includes the CPU build.
Touch/Pencil Usability
On touch devices (e.g. iPad, detected via navigator.maxTouchPoints), this extension enlarges LiteGraph's context menu and combo-widget value-list rows (.litemenu-entry), which ship at a 12px font with 2px padding - too small to reliably tap with a finger or Apple Pencil. It also turns an Apple Pencil tap on a menu/list entry into a click, because Safari often doesn't send one for pen taps (e.g. with Scribble enabled), so the pencil selects entries the way a finger does. While the pencil is down on the graph canvas, it also hides tiny pencil movements (within LiteGraph's 6px click drift) from the canvas, so a pencil tap counts as a click rather than a drag. This makes widget arrows and combo dropdowns respond to the pencil.
Palm rejection: Settings → DockerCPU → Pencil → Ignore finger touches blocks all finger input, so you can rest your hand on the screen while using the pencil. After the first pencil tap, a floating ✏️ toggle appears in the bottom-right corner to switch this on and off. A finger can always tap the toggle, so you can't lock yourself out. Hide the toggle with Show pencil toggle when a pencil is used. Apple Pencil double-tap and squeeze aren't supported: Safari doesn't make them available to web pages. Desktop mouse/trackpad usage is unaffected. See web/touch_usability.js.
Link Chain Highlight
Tap or click the body of any link (not its centre dot, which keeps its menu) to animate the whole chain that link belongs to: a pulsing glow in the link's colour with white dashes running from source to destination, along reroutes, plus outlines on every node in the chain (SOURCE and END labelled). The chain follows the link's type through nodes: upstream through inputs of the same type, downstream through outputs of the same type, so Load Image → Upscale → Sharpen → VAE Encode lights up end to end and stops at VAE Encode (IMAGE in, LATENT out). * slots such as legacy Reroute nodes pass the type through; Set/Get-style virtual links aren't followed. Tap the same link again, tap empty canvas or press Esc to clear; Shift/Alt drags on links work as before. Turn it off in Settings → DockerCPU → Links. Classic canvas; with Nodes 2.0 the links animate but node outlines are skipped. See web/link_chain.js.
Supported Models
Replicate Models
| Model ID | Display Name | Category | Description |
|----------|-------------|----------|-------------|
| black-forest-labs/flux-2-klein-9b | FLUX.2 [klein] 9B | image-generation | Fast, high-quality text-to-image generation |
| black-forest-labs/flux-2-klein-9b-base-lora | FLUX.2 [klein] 9B Base LoRA | image-generation | Fast fine-tuned LoRA inference |
| black-forest-labs/flux-2-max | FLUX.2 [max] | image-generation | Highest fidelity image model |
| black-forest-labs/flux-2-pro | FLUX.2 [pro] | image-generation | Professional image generation |
| google/nano-banana | Google Nano Banana | image-generation | Fast, high-quality text-to-image |
| google/nano-banana-pro | Google Nano Banana Pro | image-generation | Pro version with more images |
| google/nano-banana-2 | Google Nano Banana 2 | image-generation | Extended version |
| openai/gpt-5 | OpenAI GPT-5 | image-understanding | Image-to-text generation for captions |
| lucataco/qwen3-vl-8b-instruct | Qwen3-VL-8B Instruct | image-understanding | Multimodal vision-language model |
| mattsays/sam3-image | SAM3 Image | image-segmentation | Prompt-based segmentation |
| papina/seedvr2 | SeedVR 2 | image-upscaling | Realistic vision enhancement |
| philz1337x/crystal-upscaler | Crystal Upscaler | image-upscaling | High-quality image upscaler |
| topazlabs/image-upscale | TopazLabs Image Upscale | image-upscaling | Professional image upscaling |
| sczhou/codeformer | CodeFormer | face-restoration | Face restoration and enhancement |
| zsxkib/seedvr2 | SeedVR 2 Video | video-upscaling | Video upscaling |
| zsxkib/realistic-voice-cloning | Realistic Voice Cloning | audio-processing | AI song covers with RVC voice models |
| prunaai/z-image-turbo-lora | Z-Image Turbo LoRA | image-generation | Fast generation with LoRA support |
| tencentarc/gfpgan | GFPGAN | face-restoration | Face restoration |
Fal.ai Models
| Model ID | Display Name | Category | Description |
|----------|-------------|----------|-------------|
| fal-ai/flux-2/klein/9b/edit | FLUX.2 [klein] 9B Edit | image-editing | Image editing with FLUX.2 Klein |
| fal-ai/seedvr/upscale/image | SeedVR Upscale Image | image-upscaling | Image upscaling with SeedVR |
HuggingFace Repos
| Repo ID | Display Name | Category | Description |
|---------|-------------|----------|-------------|
| renderartist/Technically-Color-Z-Image-Turbo | Color Z Image Turbo | image-processing | Colorization with style transfer |
| starsfriday/FLUX.2-klein-AC-Style-LORA | AC Style LORA | image-generation | Anime/Comic style LoRA for FLUX |
| Papina/Lora-Characters | LORA Characters | image-generation | Character style LoRA |
Directory Structure
ComfyUI-API-DockerCPU/
├── __init__.py # Main entry point
├── pyproject.toml # ComfyUI Registry config
├── requirements.txt # Dependencies
├── README.md # This file
│
├── API/ # API-specific implementations
│ ├── Replicate/
│ │ ├── node.py # Dynamic node creation
│ │ └── schema_to_node.py # Schema parsing
│ ├── FalAi/
│ │ ├── node.py # Dynamic node creation
│ │ └── schema_to_node.py # Schema parsing
│ └── HuggingFace/
│ └── node.py # Model selector & utilities
│
├── common/ # Shared utilities
│ ├── utils.py # Image/audio conversion
│ ├── logger.py # Logging utilities
│ ├── zip_utils.py # ZIP archive loading
│ ├── amd_tools.py # AMD GPU patch
│ ├── image_utils.py # Load Image With Metadata
│ ├── provenance.py # ORIGINAL / ORIGINAL_SHA256 resolution
│ ├── prompt_loader.py # Load Prompt From File
│ └── text_saver.py # Save Text With Filename
│
├── schemas/ # API schema definitions
│ ├── Replicate/*.json
│ ├── FalAi/*.json
│ └── HuggingFace/*.json
│
└── tests/ # Test suite
└── test_schemas.py # Schema validation tests
License
MIT
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
python -m pytest tests/ - Submit a pull request
Support
- GitHub Issues: https://github.com/trustypangolin/ComfyUI-API-DockerCPU/issues
- Wiki: https://github.com/trustypangolin/ComfyUI-API-DockerCPU/wiki