Nodes/TrainyThing/TrainyThing Review
ComfyUI Node

TrainyThing Review

Swipe your batch on your phone, then let the graph carry on

By ryanrinkel·Created 21 days ago·Updated 21 days ago· 0
TrainyThing Review
  • images
  • latent
  • images_b
  • accepted
  • rejected
  • accepted_latent
  • images
  • labels
  • summary
  • notes
  • accepted_meta
  • accepted_indices
  • link
  • slug
◄titleComfyUI batch►
◄promptKeep this one?►
◄modesingle►
◄publicfalse►
◄slug►
◄intro►
◄options►
◄feedbackon_reject►
◄identityname_email►
◄ordercoverage►
◄min_reviews1►
◄projectcomfyui►
◄timeout_minutes45.0►
◄on_timeoutpartial►
◄labels►
◄meta►

What it is

TrainyThing Review is the flagship of this pack: wire it after VAE Decode, press Queue, and the batch becomes a review queue on your phone. A link and QR appear on the node, the run waits, you swipe each image keep-or-reject with a note on why, and the graph carries on - keepers on one socket, rejects on another, reasons attached as text.

Why use it instead of clicking keepers on the canvas? Because you'd rather review away from the desk; because a note on why you rejected something beats "meh"; or because someone else is picking and you want names on the verdicts. If none of that applies, an on-canvas chooser like cg-image-picker is simpler.

It's an output node, so it runs with nothing wired downstream. The pack is brand new (v0.2.0, barely a Reddit thread to its name), so everything below comes from the source, not folklore.

How it works

Review is TrainyThing Send and TrainyThing Wait welded together: each image becomes a card, the PNGs go to a local daemon, the node polls /status while the reviewer works, then splits the batch you still have in memory. That's the point of the combined node - the batch and its latent stay resident across the wait, so accepted_latent needs no re-encoding.

The uploaded PNGs carry the prompt and workflow chunks Save Image would have written, unless ComfyUI runs with --disable-metadata. The node also walks your graph backwards from images - VAE Decode, sampler, text encoders, LoRA loaders, checkpoint - and attaches what it found to each card. That's how a keeper's seed and prompt come back to you.

Connection details are deliberately not widgets - TRAINYTHING_URL/TRAINYTHING_TOKEN, then ~/.trainything/config.json, then 127.0.0.1:4747. No token field, on purpose: ComfyUI writes widget values into every PNG and shared workflow, so a token in a node leaks with the first image.

The inputs that matter

A fresh node shows five - images, title, prompt, mode, public. The rest is folded behind a more settings switch, which unfolds itself if a loaded workflow changed one of them.

  • images - any batch size, one card per image.
  • mode - single (keep or reject), pair (A vs B, wire images_b), choose (pick one of your options), select (tick any).
  • public - off, the link only works on that machine. On, the daemon opens a tunnel (fetching cloudflared on first use) so your phone off the home Wi-Fi can reach it; if it fails you get a console line and the local link.
  • min_reviews - how many people must judge each card before the queue is done. Set 2+ and ties become contested, which is in neither set - that's what Filter's rule is for.
  • feedback / identity - when a reason is demanded (on_reject, optional, required, off), and whether reviewers leave a name and email.
  • timeout_minutes (45) and on_timeout - partial goes on with what got judged, block stops the run. The queue stays open either way.

Optional: latent (needed for accepted_latent), images_b (pair mode), labels (a caption per card), meta (your own JSON, which overrides the graph walk), and slug - empty derives one from the title, random makes an unguessable one.

The outputs

accepted and rejected are the obvious two. images plus labels is the pair you wire into TrainyThing Filter when you need a rule more interesting than keep/reject. summary into any preview-text node is the fastest way to read the reasons, and notes is the bare list of them. accepted_meta is JSON with each keeper's seed, position, prompt, checkpoint, LoRAs and sampler settings; accepted_indices is an INT list, so a downstream node runs once per keeper. link and slug are for you and for Load.

Installing it

cd ComfyUI/custom_nodes
git clone https://github.com/ryanrinkel/comfyui-trainything
cd comfyui-trainything
python -m pip install -r requirements.txt   # ComfyUI's own python, or python_embeded\python.exe
# restart ComfyUI, then once:
npx -y trainything dashboard

Or Manager → search "TrainyThing" (comfy node install trainything). The Python side is tiny - segno, pillow, numpy, no models - but the daemon needs Node ≥ 22.5 and the pack wants ComfyUI ≥ 0.39.0 for its V3 node API. You can test it with no checkpoint: copy tests/fixtures/sprites/*.png into ComfyUI's input/, drag examples/gate.json onto the canvas, press Run.

Where people get burned

It holds ComfyUI's whole queue - nothing else runs while you're swiping. Inherent to any on-canvas chooser, and the reason Send-then-Load exists.

ComfyUI caches an unchanged Review. The same graph with the same inputs is skipped - those images are already on the phone. Change a seed if you want a fresh send.

accepted_latent is always blocked in pair mode - the wired latent is the A side's, and a winning B has none. VAE Encode accepted.

In choose and select, accepted and rejected are empty on purpose - those modes produce a tally, not a binary. Get the images with TrainyThing Filter, rule option.

CategoryTrainyThing

Inputs (19)

NameTypeDefaultDescription
imagesIMAGEThe pictures to review. Each one becomes a card on the phone.
titleSTRINGComfyUI batchA name for this batch. Shown at the top of the phone page and on the dashboard.
promptSTRINGKeep this one?The question written on every card, e.g. Keep this one?
modeCOMBOsingleHow the reviewer answers. single: keep or reject each picture. pair: pick A or B (wire the B pictures into images_b). choose: pick one of your options per picture. select: tick any of your options per picture.
publicBOOLEANfalseOn: make a link that works away from this computer (your phone off the home Wi-Fi), through a tunnel. Off: the link only works on this machine.
slugSTRINGThe short name in the link, like a folder name. Leave empty to make one from the title. Use the name of a batch that is still open to add these pictures to it. Type random for a name nobody can guess.
introSTRINGA short message the reviewer reads before the first card. Leave empty for an automatic one that quotes your positive prompt and says what to do.
optionsSTRINGOnly for choose and select: the buttons the reviewer sees, as id:Label pairs separated by commas, e.g. hair:Hair colour, hands:Hands, ok:Fine. An id is lowercase letters, digits, - or _. Ignored in single and pair.
feedbackCOMBOon_rejectWhen the reviewer is asked to type a reason. on_reject: only when they reject (single mode; a note box on every card in the other modes). optional: a note box on every card. required: they must write something. off: never.
identityCOMBOname_emailname_email: the phone asks for a name and email before the first card, so you know who said what. anonymous: it asks nothing.
orderCOMBOcoverageThe order the cards are shown in. coverage: the pictures with the fewest reviews first, so several reviewers spread out. fixed: the batch order.
min_reviewsINT11–50How many people must judge each picture before the batch counts as done. 1 when it is just you.
projectSTRINGcomfyuiA tag that groups batches on the dashboard.
timeout_minutesFLOAT45.00.1–10080How long to wait for the phone before the run moves on. The batch stays open on the dashboard either way.
on_timeoutCOMBOpartialWhat happens when the time runs out. partial: carry on with what was judged, the rest counts as unjudged. block: stop here; nothing after this node runs.
latentoptLATENTOptional: the latent from the KSampler that made these pictures. accepted_latent then carries the keepers' latents to a next step.
images_boptIMAGEpair mode only: the B pictures, one for each A picture, same count.
labelsoptSTRINGOptional: a caption above each card. One line per picture, in batch order.
metaoptSTRINGOptional: extra details to attach to every card as JSON, e.g. {"lora": "witch-v2"}. One object for all pictures, or one per line. It comes back with the verdicts and overrides what the node reads from the graph.

Outputs (11)

NameTypeDescription
acceptedIMAGEThe pictures the reviewer kept.
rejectedIMAGEThe pictures the reviewer rejected.
accepted_latentLATENTThe keepers' latents, cut from the latent you wired in. Nothing flows here if no latent was wired.
imagesIMAGEAll the pictures, unchanged, in batch order. Wire with labels into TrainyThing Filter.
labelsSTRINGOne line per picture: its verdict, the votes and the notes. Made for TrainyThing Filter.
summarySTRINGA short readable report: how many were kept, rejected or contested, and the notes. Wire to a Preview Any node.
notesSTRINGThe reasons the reviewer typed, one per line, with the picture each one was about.
accepted_metaSTRINGFor each keeper: its seed, batch position, prompt, checkpoint, LoRAs and sampler settings, as JSON. For reproducing or refining.
accepted_indicesINTThe batch positions of the keepers, counting from 0.
linkSTRINGThe review link the phone was sent to.
slugSTRINGThis batch's short name, for TrainyThing Load in a later run.