Bill's LoRA Detail Captioner (Gemma 4)
Caption Your LoRA Dataset in Bulk with a Local Gemma 4 — No API Key Required
- image
- STRING
If you've ever assembled a LoRA dataset by hand, you know the grind: twenty images, each one needs a caption, and the quality of those captions decides whether your LoRA is a likeness or a lump. This node - Bill's LoRA Detail Captioner (Gemma 4), class BillLoRACaptionNode - automates the chore with a vision LLM running entirely on your own machine. The name is not a lie: it doesn't call any API and needs no key. It talks to a local Ollama server and writes the captions out as .txt files, ready for ai-toolkit, kohya, or whatever trainer you use.
What it actually does
The interesting part is the trick the author calls Concept Isolation, and it's smarter than "describe this picture." You tell it two things: the subject's physical traits (excluded_details, default "a vintage red sports car") and a single token to stand in for that subject (trigger_word, default "MyCar"). The node then builds a prompt that tells the LLM to describe the scene in high detail - lighting, composition, pose, texture - but to substitute every physical description of that subject with the trigger word. So you get MyCar parked on a rainy street, warm window light bouncing off wet asphalt instead of A red car parked on a rainy street....
That's exactly the captioning rule that actually works for LoRA training, straight out of the playbook: caption what you want to remain variable (scene, pose, lighting), and leave the fixed identity out of the general description so it binds to the trigger token. The LLM runs at temperature 0.1 in a single pass - deliberately boring, on purpose, so you don't get token drift between iterations.
Under the hood
The node is a thin wrapper over Ollama's local HTTP API. Your image gets converted to a JPEG, base64-encoded, and POSTed to http://localhost:11434/api/generate alongside the prompt. The model dropdown is populated live from whatever vision models you have installed in Ollama (it reads /api/tags), falling back to gemma4 if Ollama wasn't running when ComfyUI loaded. The heavy lifting - and the VRAM - all happens in the LLM, not in the node.
The inputs that matter:
- image - any IMAGE tensor, e.g. from
LoadImage. Note it only captions the first frame of a batch, so feed one image per run or loop it. - excluded_details - the subject's inherent traits, described so the model knows what to hide.
- trigger_word - what the model substitutes for those traits.
- model - which installed Ollama vision model to use.
Optional filename and save_folder control the .txt export (default comfyui/output/captions). The output is a single STRING - the caption - which wires straight into PreviewAny or a text display, exactly like the pack's sample workflows.
Installing it
Two steps, and only the second one is heavy:
cd ComfyUI/custom_nodes
git clone https://github.com/0-bill-0/ComfyUI-BILL-Concept_Isolator-Captioner
Or use ComfyUI Manager and search "ComfyUI-BILL-Concept_Isolator-Captioner", then restart. The requirements.txt is just torch, numpy, Pillow, and requests - all of which ComfyUI already has, so the pack itself adds essentially nothing. The real dependency is Ollama:
# install Ollama first, then pull a vision model
ollama run gemma4
Keep in mind the hardware table in the README: it's honest enough to list "potato" as the minimum and 24–32GB VRAM as recommended. Gemma 4 is a big model. On a smaller card, pull a smaller vision model and pick it in the dropdown - that's the beauty of the live model list.
Where people get burned
- The dropdown shows only
gemma4. That means Ollama wasn't running when ComfyUI loaded, so the live model list came back empty. Start Ollama, confirm your model withollama list, then reload ComfyUI. - The caption output literally reads "Could not connect to Ollama. Is it running?" Errors come back as the output string rather than crashing the graph, so skim a caption or two before you trust a full dataset run - a dead server will happily write error text into all your
.txtfiles. - The default
filenameis "caption_output" and the folder is relative to your ComfyUI working directory. Running the batch without setting a per-image filename overwrites the same file every time. - "MyCar" is a weak trigger. The community rule of thumb is a rare alphanumeric token (
ohwx,ch9ractername) so it can't collide with a real word. The mechanic is fine; the example is just not the best one.
It's a niche, one-node pack from a single author, and there are mainstream captioners with bigger followings - JoyCaption and Florence 2 for natural language, WD14 for taggers. This one earns its place if you want the trigger-word isolation workflow, local privacy, and a .txt pipeline that lands captions directly where your trainer expects them.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| model | COMBO | 1 options: gemma4 | |
| excluded_details | STRING | a vintage red sports car | — |
| trigger_word | STRING | MyCar | — |
| filenameopt | STRING | caption_output | — |
| save_folderopt | STRING | comfyui/output/captions | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| STRING | STRING | — |