130 lines
4.5 KiB
Python
130 lines
4.5 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Callable
|
|
|
|
try:
|
|
from . import character_config as character_policy
|
|
except ImportError: # Allows local smoke tests with top-level imports.
|
|
import character_config as character_policy
|
|
|
|
|
|
Choose = Callable[[Any, list[tuple[str, str, str]]], tuple[str, str, str]]
|
|
|
|
|
|
def count_phrase(count: int, singular: str, plural: str) -> str:
|
|
words = {
|
|
0: "no",
|
|
1: "one",
|
|
2: "two",
|
|
3: "three",
|
|
4: "four",
|
|
5: "five",
|
|
6: "six",
|
|
7: "seven",
|
|
8: "eight",
|
|
9: "nine",
|
|
10: "ten",
|
|
11: "eleven",
|
|
12: "twelve",
|
|
}
|
|
label = singular if count == 1 else plural
|
|
return f"{words.get(count, str(count))} {label}"
|
|
|
|
|
|
def cast_summary_phrase(women_count: int, men_count: int) -> str:
|
|
women_count = max(0, int(women_count))
|
|
men_count = max(0, int(men_count))
|
|
if women_count + men_count == 0:
|
|
women_count = 1
|
|
person_count = women_count + men_count
|
|
women_label = "woman" if women_count == 1 else "women"
|
|
men_label = "man" if men_count == 1 else "men"
|
|
return f"{women_count} {women_label}, {men_count} {men_label}, {person_count} total adults"
|
|
|
|
|
|
def explicit_character_slot_label(slot: dict[str, Any]) -> str:
|
|
label = str(slot.get("label") or "").strip().upper()
|
|
if label in character_policy.CHARACTER_LABEL_CHOICES and label != "AUTO_CHAIN":
|
|
return label
|
|
return ""
|
|
|
|
|
|
def character_slot_label_map(slots: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
|
|
label_map: dict[str, dict[str, Any]] = {}
|
|
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
for subject_type, prefix in (("woman", "Woman"), ("man", "Man")):
|
|
subject_slots = [slot for slot in slots if slot.get("subject_type") == subject_type]
|
|
auto_slots = [slot for slot in subject_slots if not explicit_character_slot_label(slot)]
|
|
for index, slot in enumerate(reversed(auto_slots)):
|
|
if index >= len(letters):
|
|
break
|
|
label_map[f"{prefix} {letters[index]}"] = slot
|
|
for slot in subject_slots:
|
|
explicit = explicit_character_slot_label(slot)
|
|
if explicit:
|
|
label_map[f"{prefix} {explicit}"] = slot
|
|
return label_map
|
|
|
|
|
|
def configured_cast_context(women_count: int, men_count: int) -> dict[str, str]:
|
|
women_count = max(0, int(women_count))
|
|
men_count = max(0, int(men_count))
|
|
if women_count + men_count == 0:
|
|
women_count = 1
|
|
parts = []
|
|
if women_count:
|
|
parts.append(count_phrase(women_count, "adult woman", "adult women"))
|
|
if men_count:
|
|
parts.append(count_phrase(men_count, "adult man", "adult men"))
|
|
subject_phrase = parts[0] if len(parts) == 1 else f"{parts[0]} and {parts[1]}"
|
|
person_count = women_count + men_count
|
|
if person_count == 1:
|
|
scene_kind = "solo adult sexual pose"
|
|
elif person_count == 2:
|
|
scene_kind = "adult couple sex scene"
|
|
elif person_count == 3:
|
|
scene_kind = "adult threesome sex scene"
|
|
else:
|
|
scene_kind = "adult group sex scene"
|
|
return {
|
|
"subject_type": "configured_cast",
|
|
"subject": f"{women_count}w_{men_count}m_sex_scene",
|
|
"subject_phrase": subject_phrase,
|
|
"age": "21+ adults",
|
|
"body": "varied",
|
|
"skin": "",
|
|
"hair": "",
|
|
"eyes": "",
|
|
"body_phrase": "varied adult bodies",
|
|
"women_count": str(women_count),
|
|
"men_count": str(men_count),
|
|
"person_count": str(person_count),
|
|
"cast_summary": cast_summary_phrase(women_count, men_count),
|
|
"scene_kind": scene_kind,
|
|
}
|
|
|
|
|
|
def couple_type_from_counts(
|
|
rng: Any,
|
|
women_count: int,
|
|
men_count: int,
|
|
*,
|
|
choose: Choose,
|
|
couple_types: list[tuple[str, str, str]],
|
|
) -> tuple[str, str, str, int, int]:
|
|
women_count = max(0, int(women_count))
|
|
men_count = max(0, int(men_count))
|
|
if women_count >= 2 and men_count == 0:
|
|
return "two women", "two women", "close affectionate couple pose", 2, 0
|
|
if men_count >= 2 and women_count == 0:
|
|
return "two men", "two men", "relaxed romantic couple pose", 0, 2
|
|
if women_count >= 1 and men_count >= 1:
|
|
return "woman and man", "a woman and a man", "playful date-night pose", 1, 1
|
|
|
|
primary_subject, subject_phrase, pose = choose(rng, couple_types)
|
|
if primary_subject == "two women":
|
|
return primary_subject, subject_phrase, pose, 2, 0
|
|
if primary_subject == "two men":
|
|
return primary_subject, subject_phrase, pose, 0, 2
|
|
return primary_subject, subject_phrase, pose, 1, 1
|