Prompt Cleaner (CLIP Text Encode)
Clean Your Prompt and Encode It
- clip
- extra_texts
- conditioning
- cleaned_text
Every Anima workflow has a CLIP Text Encode in it. This node is that node with the tag cleaning baked in - you paste raw Danbooru output, it fixes the underscores and the brackets, and it hands the sampler a CONDITIONING you can use immediately. One fewer wire, one fewer place to forget that sunna_(zenless_zone_zero) is not what the model wants to see.
What it is
It is the pack's cleaning engine followed by a normal encode, in a single node: same rules, same switches, same settings dialog as the standalone Prompt Cleaner, plus a clip input on the front and a conditioning output on the back. Anima's Qwen3-0.6B encoder reads real Danbooru tags far better than paraphrases, but it wants them with spaces instead of underscores and with the series brackets escaped so ComfyUI's token_weights doesn't eat (zenless zone zero) as attention syntax. That is the whole reason to install the pack.
Mechanically it does the obvious thing, which is worth saying because it means there are no surprises: it concatenates your text sources, cleans the result, calls clip.tokenize() on the cleaned string, and returns clip.encode_from_tokens_scheduled(tokens) as the conditioning. The escaping holds because the cleaned string is the thing that gets tokenized - escape_important in comfy/sd1_clip.py recognizes \( and \), and Anima's text encoder goes through that path, so a protected series name arrives at the model intact instead of being consumed as emphasis.
Inputs and outputs that matter
clip is the only input that makes this node different from its sibling, and it's the one to get right. Point it at the encoder output of whatever loaded your model - Anima's is the qwen_3_06b_base text encoder the tooltip names. If it arrives as None you wired a model instead of an encoder, and you'll get the familiar "your checkpoint does not contain a valid clip or text encoder model" error. Wiring mistake, not a bug in the node.
Then the text side, identical to the Prompt Cleaner: a permanent text_in socket, up to ten autogrowing extra sockets, and the multiline box - merged in the order text_in → extra sockets → box and cleaned as one prompt, so a masterpiece coming from both your character node and your style node collapses to one. That merge is the real workflow win: wire a tags node and a style node into one encode and stop hand-maintaining a mega-string.
The cleaning switches live behind the node's ⚙ settings dialog: bracket_policy (keep it on escaped parentheses only - "escape everything" writes \[/\{, which ComfyUI never un-escapes), keep_weights, underscore_to_space, dedupe, strip_blacklist, lowercase, separator, normalize_fullwidth, and the blacklist editor. They're hidden widgets, not deleted ones: the same names carry the same values into an API-format run.
Two outputs, and the second one is the reason to prefer this over a stock encode:
conditioning→ straight into your sampler's positive (or negative) input.cleaned_text→ the cleaned single-line prompt, for reuse or for double-checking.
That second output is worth wiring somewhere: feed it into a stock CLIP Text Encode for your negative, into a filename node, or into a text preview so you can see what actually got sent. The node paints the cleaned text on its own canvas too.
One behavioural difference from the text-only node, and it's deliberate: this one is not an output node, so it only executes when something downstream consumes one of its outputs. That's correct - you don't want a text encoding burned on every queue just to update a preview - but it means that if you queue and the preview text on the node looks stale, the node simply wasn't reached. Check the sampler is actually wired to conditioning.
Install
Nothing to download, nothing to pip install - no models, no wheels, standard library only. It ships in the same pack as the cleaning node, and it needs ComfyUI >= 0.3.60 because the pack is written against the V3 node API.
cd ComfyUI/custom_nodes
git clone https://github.com/L134283/comfyui-promote-cleaner
# restart ComfyUI, then hard-refresh the browser (Ctrl+F5)
ComfyUI Manager users can search Prompt Cleaner, or run comfy node install comfyui-promote-cleaner. The nodes land in the Prompt Cleaner category and in Essentials → Basics; the encode variant is the one with the clip socket.
Where people get burned
The ⚙ and + text input buttons don't show up. They're injected by the pack's frontend JS. Hard-refresh before you file anything - that extension file is cached by the browser. The node still cleans and encodes without them; you just can't open the settings dialog.
score_7 is now score 7. underscore_to_space is on by default, and score tags are the documented exception to the "replace underscores" rule. Turn that switch off if you use them.
Weights look preserved but do nothing. keep_weights protects (tag:1.2) from being escaped, which is the safe behaviour. On Anima the weighting itself is discarded by the LLM encoder path, so it's inert punctuation rather than emphasis - the pack keeps your syntax valid instead of pretending to make it work. The Anima convention is comma+space tags with no weights at all.
Nothing runs. Not a bug - see above. This node is demand-driven, unlike the text-only one.
An old ComfyUI. If the node doesn't appear at all, check your version before anything else.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| clip | CLIP | CLIP / text encoder used to encode the prompt (Anima uses qwen_3_06b_base). | |
| text | STRING | Paste raw tags here: comma separated, one tag per line, or a mix of both. When 'text in' is connected, this box is appended after it (and after any extra text sockets), so you can mix an upstream prompt with extra tags typed here. Leave it empty to use only the sockets. | |
| bracket_policy | COMBO | 仅转义圆括号(推荐) | Bracket escaping policy. - Escaped parentheses only (recommended): sunna (zenless zone zero) -> sunna \(zenless zone zero\). In ComfyUI only \( \) is a real escape sequence (see escape_important in comfy/sd1_clip.py). - Escape everything: also backslash-escape square and curly brackets. Note that [ ] { } are NOT syntax in ComfyUI, so \[ \] \{ \} is never unescaped and the backslash ends up as a literal character for the Qwen2 tokenizer. - Leave as is: no escaping at all. Explicit weights such as (tag:1.2) are handled by the separate 'keep_weights' toggle, not by this policy. |
| keep_weights | BOOLEAN | true | Preserve explicit weight syntax: masterpiece, (best_quality:1.3) -> masterpiece, (best quality:1.3) A bracket group ending in :number is treated as a weight and kept as is so ComfyUI can parse it normally; all other brackets (such as the character series in 'sunna (zenless zone zero)') are escaped as usual. Nested weights such as ((tag:1.2)) are preserved too. Turn this off to escape every parenthesis, which would degrade (masterpiece:1.2) into \(masterpiece:1.2\) and drop the weight. |
| underscore_to_space | BOOLEAN | true | Convert underscores to spaces: drawing_bow -> drawing bow; sunna_(zenless_zone_zero) -> sunna (zenless zone zero). |
| dedupe | BOOLEAN | true | Drop repeated tags (case-insensitive, leading and trailing whitespace ignored), keeping the first occurrence. |
| strip_blacklist | BOOLEAN | true | Drop dirty tags such as tagme / watermark / signature using the blacklist below. |
| lowercase | BOOLEAN | false | Lowercase every tag, matching the Anima community convention of lowercase multi-word tags. |
| separator | COMBO | 逗号 + 空格 | String used to join the tags. '逗号 + 空格' = comma followed by a space (default, recommended); '仅逗号' = bare comma. |
| normalize_fullwidth | BOOLEAN | true | Convert full-width punctuation and full-width spaces to their half-width equivalents, e.g. () -> () and _ -> _. |
| blacklist | STRING | # ===== Prompt Cleaner 默认黑名单 ===== # 每行一条规则;# 开头为注释;清空本框 = 关闭黑名单过滤。 # 普通标签:忽略大小写、忽略空格/下划线差异,做「整标签」匹配。 # 正则规则:以 re: 开头,做包含匹配(如需整标签匹配请用 ^...$ 锚点)。 # --- Danbooru meta / 水印 / 署名类 --- tagme watermark sample watermark signature username twitter username patreon username artist name web address bad id bad source dated logo # --- 纯文字 / 对话框 / 翻译标注类 --- english text translated check translation speech bubble commentary # --- 请求类站位标签(对出图无意义) --- artist request character request reference request # --- 年份标签,如 year 2024 --- re:^year\s+\d{4}$ | Blacklist rules, one per line: - blank lines, and lines starting with #, are comments; - plain text = whole-tag match (case-insensitive, spaces and underscores treated as equal), e.g. watermark; - re: prefix = regular expression, partial match, e.g. re:^year\s+\d{4}$. Clear this box to disable blacklist filtering entirely. |
| text_inopt | STRING | Optional STRING socket. Whatever arrives here is cleaned first, then the extra text sockets (if any) and the content of the 'prompt text' box below are appended right after it and cleaned together. Leave it unconnected to clean the other sources alone. | |
| extra_textsopt | COMFY_AUTOGROW_V3 | Extra text inputs. - Connect a socket to make the next one appear (up to 10 extra sockets); - or use the '+ text input' button on the node / the settings window to add or remove sockets by hand. Everything that is connected is concatenated in order (text in -> extra inputs -> prompt text box) and cleaned as one prompt, so dedupe and blacklist also work across sources. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| conditioning | CONDITIONING | Encoded conditioning of the cleaned prompt, ready for a sampler. |
| cleaned_text | STRING | Cleaned single-line prompt, for reuse or for double-checking. |