Add seeded random character slots
This commit is contained in:
+63
-4
@@ -178,6 +178,7 @@ CHARACTER_MAN_BODY_CHOICES = [
|
||||
CHARACTER_DESCRIPTOR_DETAIL_CHOICES = ["auto", "full", "medium", "compact", "minimal"]
|
||||
CHARACTER_PRESENCE_CHOICES = ["visible", "pov"]
|
||||
CHARACTER_RANDOM_TOKENS = {"", "random", "auto", "global", "from_global", "default"}
|
||||
CHARACTER_SLOT_SEED_MAX = 0xFFFFFFFF
|
||||
|
||||
CAMERA_DETAIL_CHOICES = ["off", "compact", "full"]
|
||||
HARDCORE_DETAIL_DENSITY_CHOICES = ["compact", "balanced", "dense"]
|
||||
@@ -2307,6 +2308,47 @@ def _slot_expression_intensity_for_phase(slot: dict[str, Any] | None, phase: str
|
||||
return _slot_expression_intensity(slot)
|
||||
|
||||
|
||||
def _normalize_slot_seed(value: Any) -> int:
|
||||
try:
|
||||
seed = int(value)
|
||||
except (TypeError, ValueError):
|
||||
return -1
|
||||
if seed < 0:
|
||||
return -1
|
||||
return min(seed, CHARACTER_SLOT_SEED_MAX)
|
||||
|
||||
|
||||
def _slot_seed(slot: dict[str, Any] | None) -> int:
|
||||
if not slot:
|
||||
return -1
|
||||
return _normalize_slot_seed(slot.get("slot_seed"))
|
||||
|
||||
|
||||
def _slot_seeded_rng(slot: dict[str, Any] | None, salt: int) -> random.Random | None:
|
||||
seed = _slot_seed(slot)
|
||||
if seed < 0:
|
||||
return None
|
||||
return random.Random(_row_seed(seed, 1, salt))
|
||||
|
||||
|
||||
def _slot_context_rng(slot: dict[str, Any], fallback_rng: random.Random) -> random.Random:
|
||||
return _slot_seeded_rng(slot, 701) or fallback_rng
|
||||
|
||||
|
||||
def _slot_effective_figure(
|
||||
slot: dict[str, Any],
|
||||
subject_type: str,
|
||||
fallback_figure: str,
|
||||
) -> str:
|
||||
raw_figure = str(slot.get("figure") or "random").strip()
|
||||
if raw_figure in ("curvy", "balanced", "bombshell"):
|
||||
return raw_figure
|
||||
seeded_rng = _slot_seeded_rng(slot, 709)
|
||||
if subject_type == "woman" and seeded_rng is not None:
|
||||
return g.choose(seeded_rng, ["curvy", "balanced", "bombshell"])
|
||||
return fallback_figure
|
||||
|
||||
|
||||
def _mean(values: list[float]) -> float:
|
||||
return sum(values) / len(values)
|
||||
|
||||
@@ -2468,6 +2510,7 @@ def _normalize_character_slot(slot: dict[str, Any]) -> dict[str, Any]:
|
||||
"profile_type": "character_slot",
|
||||
"subject_type": subject_type,
|
||||
"label": label,
|
||||
"slot_seed": _normalize_slot_seed(slot.get("slot_seed")),
|
||||
"age": age,
|
||||
"ethnicity": _normalize_slot_ethnicity(slot.get("ethnicity")),
|
||||
"figure": figure,
|
||||
@@ -2522,12 +2565,14 @@ def _character_slot_summary(slot: dict[str, Any]) -> str:
|
||||
parts = [
|
||||
subject,
|
||||
label_text,
|
||||
f"seed={slot.get('slot_seed')}" if _slot_seed(slot) >= 0 else "",
|
||||
f"age={slot.get('age', 'random')}",
|
||||
f"ethnicity={slot.get('ethnicity', 'random')}",
|
||||
f"figure={slot.get('figure', 'random')}",
|
||||
f"body={slot.get('body', 'random')}",
|
||||
f"detail={slot.get('descriptor_detail', 'auto')}",
|
||||
]
|
||||
parts = [part for part in parts if part]
|
||||
if _slot_is_pov(slot):
|
||||
parts.append("presence=pov")
|
||||
if not _slot_expression_enabled(slot):
|
||||
@@ -2556,6 +2601,7 @@ def _character_slot_summary(slot: dict[str, Any]) -> str:
|
||||
def build_character_slot_json(
|
||||
subject_type: str = "woman",
|
||||
label: str = "auto_chain",
|
||||
slot_seed: int = -1,
|
||||
age: str = "random",
|
||||
manual_age: str = "",
|
||||
ethnicity: str = "random",
|
||||
@@ -2582,6 +2628,7 @@ def build_character_slot_json(
|
||||
{
|
||||
"subject_type": subject_type,
|
||||
"label": label,
|
||||
"slot_seed": slot_seed,
|
||||
"age": age,
|
||||
"manual_age": manual_age,
|
||||
"ethnicity": ethnicity,
|
||||
@@ -2786,14 +2833,14 @@ def _context_from_character_slot(
|
||||
no_black: bool,
|
||||
) -> dict[str, str]:
|
||||
slot_ethnicity = _slot_value(slot.get("ethnicity"))
|
||||
slot_figure = _slot_value(slot.get("figure"))
|
||||
slot_body = _slot_value(slot.get("body"))
|
||||
effective_ethnicity = slot_ethnicity or ethnicity
|
||||
effective_figure = slot_figure if slot_figure in ("curvy", "balanced", "bombshell") else figure
|
||||
effective_figure = _slot_effective_figure(slot, subject_type, figure)
|
||||
effective_no_plus = bool(no_plus_women) and not slot_body
|
||||
effective_no_black = bool(no_black) and not slot_ethnicity
|
||||
appearance_rng = _slot_context_rng(slot, rng)
|
||||
context = _appearance_for_subject(
|
||||
rng,
|
||||
appearance_rng,
|
||||
subject_type,
|
||||
effective_ethnicity,
|
||||
effective_figure,
|
||||
@@ -2914,7 +2961,19 @@ def _row_from_character_slot(character_slot: str | dict[str, Any] | None) -> dic
|
||||
slots = _parse_character_cast(character_slot)
|
||||
if not slots:
|
||||
return {}
|
||||
return slots[-1]
|
||||
slot = slots[-1]
|
||||
if _slot_seed(slot) >= 0:
|
||||
subject_type = str(slot.get("subject_type") or "woman")
|
||||
return _context_from_character_slot(
|
||||
random.Random(_row_seed(_slot_seed(slot), 1, 719)),
|
||||
slot,
|
||||
subject_type,
|
||||
"any",
|
||||
"curvy",
|
||||
False,
|
||||
False,
|
||||
)
|
||||
return slot
|
||||
|
||||
|
||||
def _character_profile_descriptor(profile: dict[str, Any]) -> str:
|
||||
|
||||
Reference in New Issue
Block a user