Probabilistic Tag Sampler (Text)
A tag sampler where every pick remembers the last one
- tags
Wildcards and {a|b|c} brackets give you prompt variety, but they're blind: every pick is independent, and nothing you choose affects what comes next. Probabilistic Tag Sampler is the version that treats your prompt like a system instead. Pick rain and the odds of night or wet clothes climb while sunny falls off a cliff. It's a small stochastic tag generator for the Danbooru-style tag models (Illustrious, NoobAI, Pony derivatives) where comma-separated vocabulary is the prompting language - batch a scene and get variations that stay coherent with each other, the same job people use LLM prompt nodes or the bracket trick for, done locally with zero API calls and no key.
The name isn't lying about anything. It's pure Python, no dependencies, no model files to download.
How it works
Every tag in the model carries a base score in [-1, 1], which a logistic S-curve maps to a probability (-1 = hard 0%, +1 = hard 100%, 0 = coin flip). The node then runs a selection loop: for each remaining candidate it rolls the RNG (averaged rng_avg_count times for stability), computes probability − roll_avg, and picks the tag with the best positive margin. If nothing clears the bar and min_tags forces more picks, it reluctantly takes the least-bad negative candidate. No margins and the minimum's met? It stops - a tag at 3% doesn't get dragged in for fun.
The interesting part is the influence matrix. Every time a tag gets chosen, its row is applied to the scores of everyone still standing, so night can push moon up and daylight down. That's the dependency model wildcards don't have. Chosen tags also apply their influence to any tags you passed in via input_text, which is how chaining works.
Tags are grouped, and each of the 10 groups gets three toggles: Exclude hard-locks the group's tags to -1 (never pick them), while Boost and Suppress nudge their scores by boost_amount / suppress_amount. The group assignments themselves live in the model data as bitmasks - you define them.
The inputs that matter
Most of the schema is defaults you'll leave alone. The ones you'll actually touch:
- seed - reproducibility. ComfyUI gives you the control-after-generate widget for free here, so re-rolls are one click.
- input_text - pass in a base prompt or another sampler's output; its tags get pre-selected and their influence applied, so samplers can chain.
- min_tags / max_tags - floor and ceiling.
max_tagsdefaults to-1, which means "no cap" (all non-excluded tags);min_tagsbackfills the lowest-probability winners if the loop undershoots. - separator -
comma_space,comma,space, ornewline; you're feeding a booru model, socomma_spaceis where you'll live. - output_strengths - flip this on to emit weighted
(tag:1.35)syntax instead of bare tags; normalise_strengths then rescales so the weights average 1.0.
Output: a single tags STRING. Wire it straight into a CLIP Text Encode (or a prompt-concat node if you're merging with fixed tags).
Installing it
ComfyUI Manager is easiest - search "Probabilistic Tag Sampler" (the pack is comfyUI_probabilistic_tag_sampler) and install. Or do it by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/Travers5/comfyUI_probabilistic_tag_sampler
Restart ComfyUI and the node shows up under text/tags. No requirements.txt, no pip step, nothing heavy - just random, math, csv, and json from the stdlib.
The catch nobody in the README underlines
First run auto-creates tag_data.json and tag_data.csv in the node's folder, and out of the box they're placeholder city: six tags named tag_01 through tag_06, every base score 0.0, an all-zeros influence matrix, no group memberships. Until you edit that data, the node is literally rolling dice among six dummy labels. This is a framework more than a finished tool - the model is the product, and there's no GUI for authoring it. You edit the CSV in a spreadsheet (better for the matrix) or the JSON by hand, and if the CSV is newer than the JSON, the loader rebuilds from the CSV automatically. Budget the data-entry time before you build a workflow on it.
Troubleshooting
- Edits not showing up: the loader only rebuilds JSON from CSV when the CSV is newer. Touch the CSV again after an edit, or the older JSON wins.
- Zero community signal: it's brand new - one commit, no Reddit presence, no impressions to speak of. You're an early adopter, so the repo's own docs (
INTENDED_BEHAVIOR.md,PROGRAM_STRUCTURE_AND_IO.md) are your best map; there's nobody to ask yet. - Want to see what it's doing: the source has code-only debug settings (
DEBUG_LOG_TO_FILEand friends) that writeprob_tag_sampler_debug.logwith the full per-iteration margin math. Handy when your influence matrix produces nonsense.
Inputs (40)
| Name | Type | Default | Description |
|---|---|---|---|
| seed | INT | 00–18446744073709550000 | — |
| input_text | STRING | — | |
| min_tags | INT | 00–9999 | — |
| max_tags | INT | -1-1–9999 | — |
| separator | COMBO | comma_space | 4 options: comma_space, comma, space, newline |
| boost_amount | FLOAT | 0.250–1 | — |
| suppress_amount | FLOAT | 0.250–1 | — |
| output_strengths | BOOLEAN | false | — |
| rng_avg_count | INT | 21–32 | — |
| normalise_strengths | BOOLEAN | true | — |
| Group 01 (Exclude) | BOOLEAN | false | — |
| Group 01 (Boost) | BOOLEAN | false | — |
| Group 01 (Suppress) | BOOLEAN | false | — |
| Group 02 (Exclude) | BOOLEAN | false | — |
| Group 02 (Boost) | BOOLEAN | false | — |
| Group 02 (Suppress) | BOOLEAN | false | — |
| Group 03 (Exclude) | BOOLEAN | false | — |
| Group 03 (Boost) | BOOLEAN | false | — |
| Group 03 (Suppress) | BOOLEAN | false | — |
| Group 04 (Exclude) | BOOLEAN | false | — |
| Group 04 (Boost) | BOOLEAN | false | — |
| Group 04 (Suppress) | BOOLEAN | false | — |
| Group 05 (Exclude) | BOOLEAN | false | — |
| Group 05 (Boost) | BOOLEAN | false | — |
| Group 05 (Suppress) | BOOLEAN | false | — |
| Group 06 (Exclude) | BOOLEAN | false | — |
| Group 06 (Boost) | BOOLEAN | false | — |
| Group 06 (Suppress) | BOOLEAN | false | — |
| Group 07 (Exclude) | BOOLEAN | false | — |
| Group 07 (Boost) | BOOLEAN | false | — |
| Group 07 (Suppress) | BOOLEAN | false | — |
| Group 08 (Exclude) | BOOLEAN | false | — |
| Group 08 (Boost) | BOOLEAN | false | — |
| Group 08 (Suppress) | BOOLEAN | false | — |
| Group 09 (Exclude) | BOOLEAN | false | — |
| Group 09 (Boost) | BOOLEAN | false | — |
| Group 09 (Suppress) | BOOLEAN | false | — |
| Group 10 (Exclude) | BOOLEAN | false | — |
| Group 10 (Boost) | BOOLEAN | false | — |
| Group 10 (Suppress) | BOOLEAN | false | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| tags | STRING | — |