Tag Frequency Weighter
Let Danbooru's tag counts set your prompt weights
- output_prompt
If you generate anime with an Illustrious or NoobAI checkpoint, you know the drill: hand-wrap the niche tag in (tag:1.4) because the model barely registers it at plain weight, while 1girl sits at 1.0 doing all the heavy lifting. Tag Frequency Weighter is the "stop hand-tuning that" node. It looks up every tag in your prompt in a real Danbooru post-count table - 719,000 tags, shipped right in the repo - and rewrites the prompt so rare tags get a boost and absurdly common ones get dialed down. Single prompt string out, no API, no key.
Why the idea works: Danbooru-trained models learned 1girl from 6.8 million images; it doesn't need your help. A tag that only shows up a few thousand times has a weaker grip on cross-attention, and a couple tenths of emphasis is often the difference between it appearing and getting ignored. Weighting by rarity is as old as tag prompting itself; this node just makes it automatic instead of a per-prompt judgment call.
How it works
The pack ships a ~13 MB CSV (danbooru_tags_post_count.csv) mapping each tag to its post count. On first use, the node loads it into memory and computes global stats - average count, min/max, and the mean of log10 counts - then writes them to tag_stats_cache.json next to the node so later runs are cheap. For each plain tag it:
- looks up the post count and takes log10 (so the
1girl-scale giants don't flatten the whole range), - finds the rarest and most common tag in your current prompt and scales against those,
- maps each tag onto your
min_value–max_valuerange around a pivot: common tags trend towardmin_value, rare tags towardmax_value, - and if the result rounds to 1.00, leaves the tag completely alone.
Output is standard weighted-paren syntax - (tag:1.3), or the weight-after-comma (tag, :1.3) form inside a comma list - so it plugs straight into a CLIPTextEncode positive. Existing (...) groups and any tag not in the table pass through untouched.
The inputs that matter
input_prompt- the tags to reweight, comma-separated.min_value/max_value- the low and high end of the output range. Defaults of 1.0 / 1.5 are a sane starting point.ignore_below_tag_count/ignore_above_tag_count- count thresholds; tags outside the band are left unchanged.pivot-log10(avg)(default) orx_avg; the "neutral" point everything is measured against.debug- prints each tag's count to the console when you're wondering why one didn't move.
The gotcha most people hit first: the default ignore_above_tag_count is 2000, and min_value defaults to 1.0. That means the shipped demo prompt - 2girls, megumin, from above - comes back byte-for-byte, because all three tags clear 2000 posts (megumin alone has 9,174). Out of the box this is really a "boost the rare stuff" node: tags above ~2000 posts get skipped, and between the pivot and min_value, only tags rarer than roughly 500 posts actually get pushed past 1.25. To get the full behavior - common tags actively downweighted - set ignore_above_tag_count to 0 and drop min_value below 1.0 (0.8-ish is a reasonable floor).
Install
ComfyUI Manager (search "Tag Frequency Weighter") or the one-liner:
cd ComfyUI/custom_nodes
git clone https://github.com/L33chKing/comfyui-tag-frequency-weighter
Then restart ComfyUI. No model download, no Python dependencies - the CSV is committed to the repo, which is exactly why install is painless. The node shows up under the "prompt" category.
Troubleshooting & when to skip it
- It only makes sense on Danbooru-tag models - Illustrious, NoobAI, WAI, Pony. On Flux or any LLM-encoded model,
(tag:1.3)gets discarded by the text encoder, so this node is busywork. Check what your checkpoint is actually built on first. - The table is Danbooru, not e621, so Pony's furry and
score_vocabulary won't resolve - those tags just pass through unchanged, which is harmless. - The default
preserve_underscores_in_outputis off, solong_hairbecomeslong hair- and that's the right call, since Danbooru-trained models are prompted with spaces, not underscores. - If the node dir is read-only, the cache write fails silently and it just recomputes; the only cost is startup time.
- Flip
calculate_averageon once (or runprint_csv_stats.pyin the node folder) to regenerate or eyeball the stats. First load of a session parses the whole CSV - a second or two, then it's cached in memory.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| input_prompt | STRING | 2girls, megumin, from above | Prompt to reweight; commas/spacing preserved. |
| min_value | FLOAT | 1.00–5 | Lower bound for output weights; popular tags trend toward this. |
| max_value | FLOAT | 1.50–5 | Upper bound for output weights; rare tags trend toward this. |
| calculate_average | BOOLEAN | false | Recompute averages from CSV now and update cache. |
| preserve_underscores_in_output | BOOLEAN | false | Keep underscores in wrapped tags (do not replace with spaces). |
| pivot | COMBO | log10(avg) | Neutral pivot (1.0): log10(avg) or mean of log10 counts (x_avg). |
| ignore_below_tag_count | INT | 00–7000000 | Leave tags with counts below this unchanged. |
| ignore_above_tag_count | INT | 20000–7000000 | Leave tags with counts above this unchanged. |
| debug | BOOLEAN | false | Print per-tag counts while processing (verbose). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| output_prompt | STRING | — |