refactor: rename random_person_node.py to nodes.py; default optional flair categories (facial_hair, makeup, accessories, expression, face_feature, skin_texture) to off; bump 1.0.2

This commit is contained in:
BRADSEC
2026-06-20 19:20:02 +10:00
parent b4cb783261
commit eff7f57d77
5 changed files with 34 additions and 6 deletions
+8
View File
@@ -91,6 +91,14 @@ Every attribute category (nationality, complexion, skin texture, eyes, face shap
> **Tip: turning off attributes:** Set any category's mode to `off` to remove it from the output completely. For example, if you don't want a body type in the description, set `body_type_mode` to `off`.
#### Default modes
Core identity categories (nationality, complexion, eyes, face shape, nose shape, mouth shape, hair colour/style/length, body type, plus age and sex) default to `random`. The optional "flair" categories default to `off` so the base person stays clean and realistic, and you opt them in per category:
`skin_texture`, `face_feature`, `facial_hair`, `expression`, `accessories`, `makeup`
The example outputs above have several of these enabled to show the full range.
#### Allow List: Custom Values
The allow_list field accepts comma-separated values. These can be:
+2 -2
View File
@@ -5,14 +5,14 @@ comfy_entrypoint for builds whose loader prefers the V3 schema API. WEB_DIRECTOR
ships the sex-aware widget extension.
"""
from .random_person_node import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
from .nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
WEB_DIRECTORY = "./js"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
try:
from .random_person_node import comfy_entrypoint # noqa: F401
from .nodes import comfy_entrypoint # noqa: F401
__all__.append("comfy_entrypoint")
except ImportError:
pass
+13 -2
View File
@@ -121,6 +121,17 @@ CATEGORY_SPECS = [
SEX_GATED = {"hair_color", "hair_style", "hair_length", "body_type", "face_shape",
"nose_shape", "mouth_shape", "face_feature", "facial_hair", "makeup"}
# Optional "flair" categories default to mode "off" so the base description stays
# clean and realistic; the user opts them in per category. Core identity
# categories (nationality, complexion, eyes, face/nose/mouth shape, hair, body)
# default to "random".
DEFAULT_OFF = {"skin_texture", "face_feature", "facial_hair",
"expression", "accessories", "makeup"}
def _mode_default(key):
return "off" if key in DEFAULT_OFF else "random"
# Tooltips (shared by both APIs).
_SEED_TIP = "Seed for reproducibility. With randomize off, the same seed reproduces the same person."
_RAND_TIP = "On: pick a new random person every run, ignoring the seed widget. Off: use the seed."
@@ -399,7 +410,7 @@ class RandomPersonNode:
"sex": (SEX_MODES, {"default": "random", "tooltip": _SEX_TIP}),
}
for key, fixed_labels, placeholder in CATEGORY_SPECS:
required[f"{key}_mode"] = (MODES, {"default": "random", "tooltip": _MODE_TIP})
required[f"{key}_mode"] = (MODES, {"default": _mode_default(key), "tooltip": _MODE_TIP})
required[f"{key}_allow_list"] = ("STRING", {"default": "", "multiline": False,
"placeholder": placeholder, "tooltip": _ALLOW_TIP})
required[f"{key}_fixed"] = (fixed_labels, {"default": "(none)", "tooltip": _FIXED_TIP})
@@ -442,7 +453,7 @@ try:
]
for key, fixed_labels, placeholder in CATEGORY_SPECS:
inputs += [
io.Combo.Input(f"{key}_mode", options=MODES, default="random", tooltip=_MODE_TIP),
io.Combo.Input(f"{key}_mode", options=MODES, default=_mode_default(key), tooltip=_MODE_TIP),
io.String.Input(f"{key}_allow_list", default="", multiline=False,
placeholder=placeholder, tooltip=_ALLOW_TIP),
io.Combo.Input(f"{key}_fixed", options=fixed_labels, default="(none)", tooltip=_FIXED_TIP),
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui_randomperson"
description = "Generate randomised, structured physical person descriptions for image-generation prompts. Sex-aware traits, per-category random/allow_list/fixed/off modes, age ranges, and individual output pins. Located under Add Node > utils. Node name: Random Person Description."
version = "1.0.1"
version = "1.0.2"
license = { file = "LICENSE" }
requires-python = ">=3.10"
dependencies = []
+10 -1
View File
@@ -6,7 +6,7 @@ Run: python -m unittest test_random_person -v
import unittest
import random_person_node as core
import nodes as core
def cat_args(**overrides):
@@ -65,6 +65,15 @@ class TestSelection(unittest.TestCase):
def test_sex_resolved_from_random(self):
self.assertIn(run(sex="random")[1], ("male", "female"))
def test_flair_categories_default_off(self):
# Optional categories must ship with mode default "off"; identity
# categories must default "random".
req = core.RandomPersonNode.INPUT_TYPES()["required"]
for key in core.DEFAULT_OFF:
self.assertEqual(req[f"{key}_mode"][1]["default"], "off", key)
for key in ("nationality", "complexion", "eyes", "hair_color", "body_type"):
self.assertEqual(req[f"{key}_mode"][1]["default"], "random", key)
def test_female_never_grows_facial_hair(self):
for seed in range(40):
self.assertEqual(run(seed=seed, sex="female")[7], "") # facial_hair pin empty