Extract character appearance policy
This commit is contained in:
+31
-190
@@ -26,6 +26,7 @@ try:
|
||||
from . import camera_config as camera_policy
|
||||
from . import cast_context as cast_context_policy
|
||||
from . import category_template_metadata as item_template_policy
|
||||
from . import character_appearance as character_appearance_policy
|
||||
from . import character_config as character_policy
|
||||
from . import character_profile as character_profile_policy
|
||||
from . import character_slot as character_slot_policy
|
||||
@@ -71,6 +72,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
||||
import camera_config as camera_policy
|
||||
import cast_context as cast_context_policy
|
||||
import category_template_metadata as item_template_policy
|
||||
import character_appearance as character_appearance_policy
|
||||
import character_config as character_policy
|
||||
import character_profile as character_profile_policy
|
||||
import character_slot as character_slot_policy
|
||||
@@ -2117,51 +2119,7 @@ def _hair_phrase_from_parts(color_key: str, length_key: str, style_key: str) ->
|
||||
|
||||
|
||||
def _hair_descriptor_from_slot(base_hair: Any, slot: dict[str, Any], rng: random.Random) -> str:
|
||||
hair_config = _parse_hair_config(slot.get("hair_config"))
|
||||
color_choice = _normalize_hair_choice(slot.get("hair_color"), CHARACTER_HAIR_COLOR_CHOICES)
|
||||
length_choice = _normalize_hair_choice(slot.get("hair_length"), CHARACTER_HAIR_LENGTH_CHOICES)
|
||||
style_choice = _normalize_hair_choice(slot.get("hair_style"), CHARACTER_HAIR_STYLE_CHOICES)
|
||||
color_options = hair_config.get("colors") or []
|
||||
length_options = hair_config.get("lengths") or []
|
||||
style_options = hair_config.get("styles") or []
|
||||
if (
|
||||
color_choice == "random"
|
||||
and length_choice == "random"
|
||||
and style_choice == "random"
|
||||
and not color_options
|
||||
and not length_options
|
||||
and not style_options
|
||||
):
|
||||
return ""
|
||||
if color_choice != "random":
|
||||
color_key = color_choice
|
||||
elif color_options:
|
||||
color_key = g.choose(rng, color_options)
|
||||
else:
|
||||
color_key = _infer_hair_color_key(base_hair)
|
||||
|
||||
if length_choice != "random":
|
||||
length_key = length_choice
|
||||
elif length_options:
|
||||
length_key = g.choose(rng, length_options)
|
||||
else:
|
||||
length_key = _infer_hair_length_key(base_hair)
|
||||
|
||||
if style_choice != "random":
|
||||
style_key = style_choice
|
||||
elif style_options:
|
||||
style_key = g.choose(rng, style_options)
|
||||
else:
|
||||
style_key = _infer_hair_style_key(base_hair)
|
||||
if color_key == "random":
|
||||
color_key = _choose_hair_key(rng, CHARACTER_HAIR_COLOR_CHOICES)
|
||||
if length_key == "random":
|
||||
length_key = _choose_hair_key(rng, CHARACTER_HAIR_LENGTH_CHOICES)
|
||||
if style_key == "random":
|
||||
style_key = _choose_hair_key(rng, CHARACTER_HAIR_STYLE_CHOICES)
|
||||
if length_key == "updo" and style_key not in ("ponytail", "braid", "braids", "bun", "messy_bun", "locs", "twists"):
|
||||
style_key = g.choose(rng, ["ponytail", "braid", "bun", "messy_bun"])
|
||||
return _hair_phrase_from_parts(color_key, length_key, style_key)
|
||||
return character_appearance_policy.hair_descriptor_from_slot(base_hair, slot, rng)
|
||||
|
||||
|
||||
def _normalize_character_slot(slot: dict[str, Any]) -> dict[str, Any]:
|
||||
@@ -2272,25 +2230,11 @@ def _pov_composition_prompt(composition: Any, pov_labels: list[str]) -> str:
|
||||
|
||||
|
||||
def _slot_softcore_outfit(slot: dict[str, Any] | None, rng: random.Random | None = None) -> str:
|
||||
if not slot:
|
||||
return ""
|
||||
outfit = _slot_value(slot.get("softcore_outfit"))
|
||||
if outfit:
|
||||
return outfit
|
||||
if rng is None:
|
||||
return ""
|
||||
return _characteristic_choice(_parse_characteristics_config(slot.get("characteristics")), "softcore_outfits", rng)
|
||||
return character_appearance_policy.slot_softcore_outfit(slot, rng)
|
||||
|
||||
|
||||
def _slot_hardcore_clothing(slot: dict[str, Any] | None, rng: random.Random | None = None) -> str:
|
||||
if not slot:
|
||||
return ""
|
||||
clothing = _slot_value(slot.get("hardcore_clothing"))
|
||||
if clothing:
|
||||
return clothing
|
||||
if rng is None:
|
||||
return ""
|
||||
return _characteristic_choice(_parse_characteristics_config(slot.get("characteristics")), "hardcore_clothing", rng)
|
||||
return character_appearance_policy.slot_hardcore_clothing(slot, rng)
|
||||
|
||||
|
||||
def _context_from_character_slot(
|
||||
@@ -2302,63 +2246,16 @@ def _context_from_character_slot(
|
||||
no_plus_women: bool,
|
||||
no_black: bool,
|
||||
) -> dict[str, str]:
|
||||
slot_ethnicity = _slot_value(slot.get("ethnicity"))
|
||||
slot_body = _slot_value(slot.get("body"))
|
||||
effective_ethnicity = slot_ethnicity or ethnicity
|
||||
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(
|
||||
appearance_rng,
|
||||
return character_appearance_policy.context_from_character_slot(
|
||||
rng,
|
||||
slot,
|
||||
subject_type,
|
||||
effective_ethnicity,
|
||||
effective_figure,
|
||||
effective_no_plus,
|
||||
effective_no_black,
|
||||
ethnicity,
|
||||
figure,
|
||||
no_plus_women,
|
||||
no_black,
|
||||
)
|
||||
|
||||
characteristics = _parse_characteristics_config(slot.get("characteristics"))
|
||||
age = _slot_value(slot.get("age")) or _characteristic_choice(characteristics, "ages", appearance_rng)
|
||||
body_phrase = _slot_value(slot.get("body_phrase"))
|
||||
if not slot_body:
|
||||
slot_body = _characteristic_choice(characteristics, "bodies", appearance_rng)
|
||||
if age:
|
||||
context["age"] = age
|
||||
if slot_body:
|
||||
context["body"] = slot_body
|
||||
if subject_type == "woman":
|
||||
context["body_phrase"] = _body_phrase(slot_body, context.get("figure", ""))
|
||||
else:
|
||||
context["body_phrase"] = f"{slot_body} figure"
|
||||
if body_phrase:
|
||||
context["body_phrase"] = body_phrase
|
||||
skin_value = _slot_value(slot.get("skin"))
|
||||
if skin_value:
|
||||
context["skin"] = skin_value
|
||||
eyes_value = _slot_value(slot.get("eyes"))
|
||||
if not eyes_value:
|
||||
eyes_value = _eye_phrase_from_key(_characteristic_choice(characteristics, "eyes", appearance_rng))
|
||||
if eyes_value:
|
||||
context["eyes"] = eyes_value
|
||||
hair_value = _slot_value(slot.get("hair"))
|
||||
if hair_value:
|
||||
context["hair"] = hair_value
|
||||
else:
|
||||
hair_descriptor = _hair_descriptor_from_slot(context.get("hair"), slot, appearance_rng)
|
||||
if hair_descriptor:
|
||||
context["hair"] = hair_descriptor
|
||||
context["descriptor_detail"] = _normalize_descriptor_detail(slot.get("descriptor_detail"))
|
||||
context["presence_mode"] = _normalize_presence_mode(slot.get("presence_mode"), subject_type)
|
||||
context["expression_enabled"] = _slot_expression_enabled(slot)
|
||||
expression_intensity = _slot_expression_intensity(slot)
|
||||
if expression_intensity is not None:
|
||||
context["expression_intensity"] = expression_intensity
|
||||
context["subject_type"] = subject_type
|
||||
context["subject"] = subject_type
|
||||
context["subject_phrase"] = subject_type
|
||||
return context
|
||||
|
||||
|
||||
def _character_context_for_label(
|
||||
label: str,
|
||||
@@ -2369,36 +2266,19 @@ def _character_context_for_label(
|
||||
no_plus_women: bool,
|
||||
no_black: bool,
|
||||
) -> tuple[dict[str, str], dict[str, Any] | None]:
|
||||
subject_type = "man" if label.startswith("Man ") else "woman"
|
||||
slot = label_map.get(label)
|
||||
if slot:
|
||||
return _context_from_character_slot(rng, slot, subject_type, ethnicity, figure, no_plus_women, no_black), slot
|
||||
return _appearance_for_subject(rng, subject_type, ethnicity, figure, no_plus_women, no_black), None
|
||||
return character_appearance_policy.character_context_for_label(
|
||||
label,
|
||||
label_map,
|
||||
rng,
|
||||
ethnicity,
|
||||
figure,
|
||||
no_plus_women,
|
||||
no_black,
|
||||
)
|
||||
|
||||
|
||||
def _apply_character_context_to_row(row: dict[str, Any], context: dict[str, Any]) -> dict[str, Any]:
|
||||
for key in (
|
||||
"subject_type",
|
||||
"subject",
|
||||
"subject_phrase",
|
||||
"age",
|
||||
"body",
|
||||
"body_phrase",
|
||||
"skin",
|
||||
"hair",
|
||||
"eyes",
|
||||
"figure",
|
||||
"descriptor_detail",
|
||||
"presence_mode",
|
||||
"expression_enabled",
|
||||
"expression_intensity",
|
||||
):
|
||||
value = context.get(key)
|
||||
if value is not None and value != "":
|
||||
row[key] = value
|
||||
if context.get("age"):
|
||||
row["age_band"] = context["age"]
|
||||
return row
|
||||
return character_appearance_policy.apply_character_context_to_row(row, context)
|
||||
|
||||
|
||||
def _cast_descriptor_entries(
|
||||
@@ -2439,22 +2319,7 @@ def _row_from_profile_metadata(metadata_json: str | dict[str, Any] | None) -> di
|
||||
|
||||
|
||||
def _row_from_character_slot(character_slot: str | dict[str, Any] | None) -> dict[str, Any]:
|
||||
slots = _parse_character_cast(character_slot)
|
||||
if not slots:
|
||||
return {}
|
||||
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
|
||||
return character_appearance_policy.row_from_character_slot(character_slot)
|
||||
|
||||
|
||||
def _character_profile_descriptor(profile: dict[str, Any]) -> str:
|
||||
@@ -2591,38 +2456,14 @@ def _appearance_for_subject(
|
||||
no_plus_women: bool,
|
||||
no_black: bool,
|
||||
) -> dict[str, str]:
|
||||
if subject_type == "single_any":
|
||||
subject_type = "woman" if rng.random() < 0.82 else "man"
|
||||
|
||||
if subject_type == "man":
|
||||
men_ethnicity = ethnicity if ethnicity else "any"
|
||||
subject, age, body, skin, hair, eyes = g.choose(rng, g.by_ethnicity(g.MEN, men_ethnicity))
|
||||
return {
|
||||
"subject_type": "man",
|
||||
"subject": subject,
|
||||
"subject_phrase": subject,
|
||||
"age": age,
|
||||
"body": body,
|
||||
"skin": skin,
|
||||
"hair": hair,
|
||||
"eyes": eyes,
|
||||
"body_phrase": f"{body} figure",
|
||||
}
|
||||
|
||||
subject, age, body, skin, hair, eyes = g.choose_woman(rng, ethnicity, no_plus_women, no_black)
|
||||
figure_note = g.choose(rng, g.figure_pool(figure))
|
||||
return {
|
||||
"subject_type": "woman",
|
||||
"subject": subject,
|
||||
"subject_phrase": subject,
|
||||
"age": age,
|
||||
"body": body,
|
||||
"skin": skin,
|
||||
"hair": hair,
|
||||
"eyes": eyes,
|
||||
"body_phrase": _body_phrase(body, figure_note),
|
||||
"figure": figure_note,
|
||||
}
|
||||
return character_appearance_policy.appearance_for_subject(
|
||||
rng,
|
||||
subject_type,
|
||||
ethnicity,
|
||||
figure,
|
||||
no_plus_women,
|
||||
no_black,
|
||||
)
|
||||
|
||||
|
||||
def _count_phrase(count: int, singular: str, plural: str) -> str:
|
||||
|
||||
Reference in New Issue
Block a user