ComfyUI Node

DHan-API-Image-gen

Nano Banana and GPT Image Without Leaving ComfyUI

By DHan315·Created 2 days ago·Updated a day ago· 0
DHan-API-Image-gen
  • image
  • references
  • ref_image_1
  • ref_image_2
  • ref_image_3
  • ref_image_4
  • ref_image_5
  • ref_image_6
  • ref_image_7
  • ref_image_8
  • ref_image_9
  • ref_image_10
  • ref_image_11
  • ref_image_12
  • ref_image_13
  • ref_image_14
  • images
  • log
◄provider▾►
◄model▾►
◄api_key►
◄promptProfessional photo edit►
◄negative_prompt►
◄seed0►
◄aspect_ratio▾►
◄resolution▾►
◄num_images1►
◄quality▾►
◄background▾►
◄output_format▾►
◄output_compression90►
◄thinking_mode▾►
◄search_grounding▾►
◄debug_mode▾►

Here's what the name hides: DHan-API-Image-gen doesn't generate anything on your GPU. It's a wrapper. You hand it a prompt and some images, it fires an HTTP request at Google or OpenAI, and the picture that comes back is a normal IMAGE tensor you can wire into your graph like any sampler's output. No checkpoint, no download, no VRAM - just a key and a network call.

Why this instead of Comfy's own official API Nodes? You bill Google or OpenAI directly with your own key rather than buying prepaid Comfy credits, both providers sit behind one node with one prompt field, and the match_input sizing exists to hand your exact dimensions back for downstream compositing.

The caveat up front: API-wrapper nodes are the category that already shipped credential-stealing malware once (ComfyUI_LLMVISION), and a node whose job is to hold your key and phone home is exactly where a malicious phone-home looks normal. This pack is tiny - four Python files, one commit - so read it before you give it a key, and never save a workflow with a key in the node field.

How it works

Pick a provider and the request splits two ways. Gemini models post to generativelanguage.googleapis.com/v1beta/interactions with the key in an x-goog-api-key header. OpenAI goes to api.openai.com/v1/images/edits as a multipart upload when any image is connected, or /v1/images/generations as JSON when you're doing plain text-to-image.

The Gemini path is the interesting one. It builds a deliberately ordered request: each reference gets a text block labelling it REFERENCE IMAGE n - DONOR REFERENCE ONLY, the primary image goes in last as PRIMARY IMAGE - EDIT TARGET / CANVAS, and your instruction follows. That ordering is why the model edits your canvas instead of redrawing a donor. Shorthand like "ref 2" gets normalised to "Reference Image 2", so referring to donors by number works.

The inputs that matter

provider, model, api_key and prompt are the required ones. Then the optional image - your canvas, the thing being edited - plus fourteen ref_image_N sockets, or a single references input if you're using the pack's RefStacker. Donors go in refs, the edit target goes in image.

Past that, the settings you'll actually touch:

  • aspect_ratio / resolution - match_input is the default and the one worth understanding. On Gemini, the node edge-pads the primary image out to the nearest ratio the model supports (pixel replication, no scaling), requests that ratio explicitly, then strips the padding on the way back. On OpenAI it computes a custom GPT size near your aspect ratio - clamped to 3:1 and 3840 px on the long edge - then LANCZOS-resizes the result to your exact input dimensions. Compositing-friendly, but it is a resample.
  • quality, background, output_format, output_compression - GPT Image only; the front-end hides them on Gemini. xhigh and max belong to the 2.5 models, so pair them with gpt-image-2.5-sunburst or -flare.
  • num_images (1–10) and seed - the seed is real on Gemini. GPT Image has no seed parameter at all, so there it only exists to make ComfyUI re-run the node.
  • thinking_mode and search_grounding - thinking is transmitted only for gemini-3.1-flash-image; grounding adds Google's web/image search tool to the request. debug_mode writes a sanitised report of what was actually sent, so reach for it before filing a bug.

Outputs are images (an IMAGE batch, one frame per returned image) and log (a STRING). Wire the log into a Show Text node; it names the model that ran and the size requested.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/DHan315/Comfyui-DHan-API-Image-gen
# restart ComfyUI

ComfyUI Manager finds it under "Comfyui-DHan-API-Image-gen". No models, no build step. Then paste a key into the node, or export GOOGLE_API_KEY / OPENAI_API_KEY before launching ComfyUI - a process that's already running won't see a new export.

Where people get burned

Wrong provider, wrong model, silent fallback. If the front-end JS hasn't loaded (stale browser cache) or you reopen a workflow saved on the other provider, the node doesn't error - it swaps in the first model of the selected provider and runs. Check the Model: line in the log.

negative_prompt isn't a negative prompt. There's no CFG here, so the text gets glued onto your prompt as Avoid: … (OpenAI) or AVOID: … (Gemini). A thirty-word negative stack steals attention from the real instruction.

Only the first frame of a batch is used. Primary and references alike are converted with tensor[0]. Wiring a 4-frame batch in sends one image, quietly.

Small sizing surprises. 0.5K silently becomes 1K on gemini-3-pro-image and gemini-2.5-flash-image, the panoramic ratios (4:1, 8:1 and friends) only exist on gemini-3.1-flash-image, and transparent plus jpeg gets you no alpha.

The key field clears itself. Switch provider and the node drops the key the first time you move to one with no saved value. Environment variables skip that dance entirely.

You can't loosen the filter. Whatever Google or OpenAI refuses stays refused - no weights to abliterate, no safety knob on the node.

And cost: ten images is ten billed images. The log reports usage when the endpoint returns it, but keeps no running total.

CategoryImage API

Inputs (32)

NameTypeDefaultDescription
providerCOMBO2 options: Nano Banana (Gemini), GPT Image (OpenAI)
modelCOMBO6 options: gemini-3.1-flash-image, gemini-3-pro-image, gemini-2.5-flash-image, gpt-image-2.5-sunburst, gpt-image-2.5-flare, gpt-image-2
api_keySTRING—
promptSTRINGProfessional photo edit—
negative_promptSTRING—
seedINT00–18446744073709550000—
aspect_ratioCOMBO16 options: match_input, auto, 1:1, 16:9, 9:16, 4:3, +10
resolutionCOMBO4 options: 0.5K, 1K, 2K, 4K
num_imagesINT11–10—
qualityCOMBO6 options: auto, low, medium, high, xhigh, max
backgroundCOMBO3 options: auto, opaque, transparent
output_formatCOMBO3 options: png, jpeg, webp
output_compressionINT900–100—
thinking_modeCOMBO2 options: Minimal, High
search_groundingCOMBO2 options: Disabled, Enabled
debug_modeCOMBO3 options: Off, Summary, Full Request
imageoptIMAGE—
referencesoptAPI_IMAGE_REFS—
ref_image_1optIMAGE—
ref_image_2optIMAGE—
ref_image_3optIMAGE—
ref_image_4optIMAGE—
ref_image_5optIMAGE—
ref_image_6optIMAGE—
ref_image_7optIMAGE—
ref_image_8optIMAGE—
ref_image_9optIMAGE—
ref_image_10optIMAGE—
ref_image_11optIMAGE—
ref_image_12optIMAGE—
ref_image_13optIMAGE—
ref_image_14optIMAGE—

Outputs (2)

NameTypeDescription
imagesIMAGE—
logSTRING—