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:
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user