🏷️ Voice Tag Editor
Make your TTS laugh, sigh, and hesitate on command
- clean_text
- tagged_text
Most TTS engines don't take direction. You type "he laughed," it reads "he laughed" in the same flat voice it reads everything else. A few engines - VoxCPM being the one this pack targets - understand inline tags: drop [laughing] into your script and the model actually emits a laugh. The catch is you're typing those tags by hand, maintaining two versions of every script (one tagged, one clean), and hoping you don't fat-finger a bracket. 🏷️ Voice Tag Editor is a small text-category node that turns that chore into a click.
It's a text-helper, not a TTS model. Nothing leaves your machine, no API is called, no weights download. It exists to make the script-writing part of a TTS workflow tolerable.
How it works
The clever part lives in the frontend. When you add the node you get a textarea with a palette of tag chips above it, grouped by category (laughter & sighs, pauses & thinking, question intonation, emotional expression). Click a chip and the tag code is inserted at your cursor position - not appended, not at a fixed spot. selectionStart/selectionEnd do the work, so it plays nice with mid-sentence edits. The 11 default tags come straight from the VoxCPM cookbook: [laughing], [sigh], [Uhm], [Shh], four [Question-*] variants, [Surprise-wa], [Surprise-yo], and [Dissatisfaction-hnn].
Under the hood the Python is almost insultingly simple. Run it and you get two strings:
clean_text- your text with every[...]tag regex-stripped. Feed this to a TTS that doesn't know tags, like Chatterbox or Kokoro, which would otherwise garble them.tagged_text- the raw text, tags intact. This is what VoxCPM wants.
So one node, two destinations: wire tagged_text to your tag-aware engine and clean_text to the fallback, and the same script works for both. The dual output is the whole point - it's why you'd reach for this instead of a plain text node.
The input and the configs
There's exactly one input, a multiline text STRING - type or paste your script, or wire a STRING in from another node. Nothing else matters for basic use.
Beyond that, the gear button opens a config manager: you can add, edit, delete, reorder, and recategorize tags, and save them as named config sets you switch between via a dropdown. Configs are plain JSON files in the pack's tags_configs/ folder, and there's a small REST API (/voice-tag-editor/config, /active-config, etc.) if you want to automate config swaps.
Installing it
cd ComfyUI/custom_nodes/
git clone https://github.com/mailzwj/ComfyUI-Voice-Tag-Editor
Then restart ComfyUI. Or just search ComfyUI-Voice-Tag-Editor in ComfyUI Manager and click install - same result. No pip dependencies, no model files, nothing heavy. It's the rare audio-adjacent node that can't break your environment, which is worth something in a corner of ComfyUI where dependency conflicts are the default failure mode.
Where people get burned
- Only
[...]tags are stripped. The regex is hardcoded to\[.*?\]. VoxCPM uses that format, but if you pick a different engine or invent your own syntax,clean_textwill cheerfully pass your junk tags through to the TTS. - Configs live inside the pack folder. Your custom tag sets are JSON files in
tags_configs/. A normalgit pullwon't touch them, but delete-and-reclone and they're gone. Back them up if you've built something elaborate. - The UI is Chinese-first. Tag aliases show as 😄 笑声, 🤔 迟疑嗯, and so on. The codes themselves are English and that's what actually goes in the text, so it's usable either way - just don't expect English labels.
- Keep tags lowercase and sparse. VoxCPM is more reliable with
[laughing]than[Laughter], and stacking six tags in one sentence is how you get audio that sounds like a malfunctioning soundboard.
For a 0-dependency utility that makes VoxCPM scripting dramatically less fiddly, this is a good grab - as long as you know it's a script editor with an opinionated default format, not a general-purpose TTS toolbox.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| clean_text | STRING | — |
| tagged_text | STRING | — |