NAI Character Prompt Select
The node that stops NAI from smearing two characters together
- CharacterPrompt
Single-prompt image generation has a structural problem: prompt adherence is global, so a prompt describing two people reliably smears their attributes together. The girl on the left ends up wearing the girl on the right's outfit, or worse, they merge into one person. Local ComfyUI solved this years ago with regional prompting (Latent Couple, Forge Couple, the whole family). NovelAI's answer, baked into its V4+ models, is per-character prompting with spatial coordinates - and CharacterPromptSelect is how you drive that from ComfyUI.
This node defines up to five character slots, each with its own positive prompt, its own negative prompt, and an x/y position on a 0–10 grid. The output is a single LIST that plugs into the characterPrompts input on NovelAIGenerator, NAIImg2ImgNode, or NAIInpaintNode. When NovelAI V4/V4.5/V5 was new, the multi-character prompt plus positioning was the feature people actually got excited about - and it's still the cleanest way to get two or three distinct characters into one frame on a closed model.
How it works
Under the hood the node is a packager, not a model. It collects your enabled slots, normalizes the 0–10 coordinates down to 0–1, and hands each slot's text plus a center to the generator node. There, the generator builds NovelAI's v4_prompt.caption.char_captions array - the exact structure the V4 API expects. So the real work happens server-side: NAI's captioning understands char_captions with centers and treats each as a regional prompt over the canvas.
The catch hiding in that sentence: only V4 and V5 model ids get the character structure (apply_v4_parameters gates on nai-diffusion-4 / nai-diffusion-5). Wire characterPrompts into a V3 or Furry V3 model and the list is silently ignored. Not a crash, just nothing - so if you're on the old models, this node is dead weight.
The inputs
character1 (the prompt), character1_uc (its negative), and character1_x/character1_y are required, defaulting to position (3,3). Characters 2 through 5 are optional and each has an _enable toggle - character2 defaults to on, 3–5 to off. Each enabled slot contributes its own prompt, negative, and center.
A practical note on coordinates: they're a 10×10 grid, and the values map straight to image position - (0,0) is top-left, (10,10) bottom-right. Start with your main character somewhere central and secondary characters offset to a side. Expect to tune positions; NAI's regional behavior is good but it's not a hard mask, and a character's prompt still bleeds into its neighbors at the boundaries. If one character dominates, check whether its _uc (negative) is fighting the others, and keep per-slot prompts short and tag-heavy rather than prose.
The output is the CharacterPrompt list. That's it - it has no image output and does nothing on its own; it's a prompt-construction node you feed into the pack's generators.
Install
Same pack as the rest of these nodes. ComfyUI Manager → Custom Nodes Manager → search ComfyUI_RS_NAI_API_Request → Install, restart, done. Manual, if you prefer:
cd ComfyUI/custom_nodes
git clone https://github.com/raspie10032/ComfyUI_RS_NAI_API_Request.git
pip install -r requirements.txt
No token needed here - this node never calls the API. You'll need the token configured before the generator it feeds will run, though (a .env in the node directory with NAI_ACCESS_TOKEN=...).
Gotchas
The obvious one is the V3 blind spot above. The subtler one is expectation: this is a helper for the generator's character structure, not a masking tool. NovelAI's regional prompting is learned, not geometric, so treat the coordinates as guidance and be ready to iterate. If you're after hard, pixel-accurate regions, you're on the wrong node - but for "two characters who stay distinct and roughly where I put them," this is the least fiddly option this pack offers.
Inputs (24)
| Name | Type | Default | Description |
|---|---|---|---|
| character1 | STRING | Input Character 1 | — |
| character1_uc | STRING | negative_prompt | — |
| character1_x | FLOAT | 0.30–1 | — |
| character1_y | FLOAT | 0.30–1 | — |
| character2_enableopt | BOOLEAN | true | — |
| character2opt | STRING | Input Character 2 | — |
| character2_ucopt | STRING | negative_prompt | — |
| character2_xopt | FLOAT | 0.10–1 | — |
| character2_yopt | FLOAT | 0.30–1 | — |
| character3_enableopt | BOOLEAN | false | — |
| character3opt | STRING | — | |
| character3_ucopt | STRING | negative_prompt | — |
| character3_xopt | FLOAT | 0.10–1 | — |
| character3_yopt | FLOAT | 0.30–1 | — |
| character4_enableopt | BOOLEAN | false | — |
| character4opt | STRING | — | |
| character4_ucopt | STRING | negative_prompt | — |
| character4_xopt | FLOAT | 0.10–1 | — |
| character4_yopt | FLOAT | 0.30–1 | — |
| character5_enableopt | BOOLEAN | false | — |
| character5opt | STRING | — | |
| character5_ucopt | STRING | negative_prompt | — |
| character5_xopt | FLOAT | 0.10–1 | — |
| character5_yopt | FLOAT | 0.30–1 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| CharacterPrompt | LIST | — |