Route clothing choices through clothing seed
This commit is contained in:
@@ -146,13 +146,14 @@ def build_prompt_result(request: PromptBuildRequest, deps: PromptBuildDependenci
|
||||
parsed_location_config = deps.parse_location_config(request.location_config)
|
||||
parsed_composition_config = deps.parse_composition_config(request.composition_config)
|
||||
content_rng = deps.axis_rng(parsed_seed_config, "content", seed, row_number)
|
||||
clothing_rng = deps.axis_rng(parsed_seed_config, "clothing", seed, row_number)
|
||||
pose_axis_rng = deps.axis_rng(parsed_seed_config, "pose", seed, row_number)
|
||||
person_rng = deps.axis_rng(parsed_seed_config, "person", seed, row_number)
|
||||
expression_rng = deps.axis_rng(parsed_seed_config, "expression", seed, row_number)
|
||||
clothing = request.clothing if request.clothing in ("full", "minimal", "random") else "full"
|
||||
poses = request.poses if request.poses in ("standard", "evocative", "random") else "standard"
|
||||
figure = request.figure if request.figure in ("curvy", "balanced", "bombshell", "random") else "curvy"
|
||||
clothing = deps.pick_clothing_mode(content_rng, clothing, minimal_ratio)
|
||||
clothing = deps.pick_clothing_mode(clothing_rng, clothing, minimal_ratio)
|
||||
poses = deps.pick_pose_mode(pose_axis_rng, poses, pose_ratio)
|
||||
figure = deps.pick_figure_bias(person_rng, figure)
|
||||
minimal_ratio = None
|
||||
@@ -185,6 +186,7 @@ def build_prompt_result(request: PromptBuildRequest, deps: PromptBuildDependenci
|
||||
minimal_ratio,
|
||||
pose_ratio,
|
||||
seed,
|
||||
seed_config=parsed_seed_config,
|
||||
)
|
||||
elif category in ("woman", "man", "couple", "group_or_layout") and not exact_custom_subcategory:
|
||||
branch = "built_in"
|
||||
|
||||
@@ -3059,16 +3059,17 @@ def row_base(index: int, batch: int, subject: str, age: str, body: str, scene_sl
|
||||
}
|
||||
|
||||
|
||||
def make_single(index: int, batch: int, rng: random.Random, gender: str, expr_deck: ExpressionDeck, clothing: str = "full", ethnicity: str = "any", poses: str = "standard", backside_bias: float = 0.0, figure: str = "curvy", no_plus: bool = False, no_black: bool = False) -> dict:
|
||||
def make_single(index: int, batch: int, rng: random.Random, gender: str, expr_deck: ExpressionDeck, clothing: str = "full", ethnicity: str = "any", poses: str = "standard", backside_bias: float = 0.0, figure: str = "curvy", no_plus: bool = False, no_black: bool = False, clothing_rng: random.Random | None = None) -> dict:
|
||||
minimal = clothing == "minimal"
|
||||
wardrobe_rng = clothing_rng or rng
|
||||
if gender == "woman":
|
||||
subject, age, body, skin, hair, eyes = choose_woman(rng, ethnicity, no_plus, no_black)
|
||||
clothes = choose(rng, WOMEN_CLOTHES_MINIMAL if minimal else WOMEN_CLOTHES)
|
||||
clothes = choose(wardrobe_rng, WOMEN_CLOTHES_MINIMAL if minimal else WOMEN_CLOTHES)
|
||||
figure_note = choose(rng, figure_pool(figure))
|
||||
else:
|
||||
men_pool = by_ethnicity(MEN, ethnicity)
|
||||
subject, age, body, skin, hair, eyes = choose(rng, men_pool)
|
||||
clothes = choose(rng, MEN_CLOTHES_MINIMAL if minimal else MEN_CLOTHES)
|
||||
clothes = choose(wardrobe_rng, MEN_CLOTHES_MINIMAL if minimal else MEN_CLOTHES)
|
||||
figure_note = ""
|
||||
body_phrase = make_body_phrase(body, figure_note)
|
||||
|
||||
@@ -3119,7 +3120,7 @@ def make_single(index: int, batch: int, rng: random.Random, gender: str, expr_de
|
||||
return row
|
||||
|
||||
|
||||
def make_couple(index: int, batch: int, rng: random.Random, expr_deck: ExpressionDeck, clothing: str = "full", ethnicity: str = "any", no_plus: bool = False) -> dict:
|
||||
def make_couple(index: int, batch: int, rng: random.Random, expr_deck: ExpressionDeck, clothing: str = "full", ethnicity: str = "any", no_plus: bool = False, clothing_rng: random.Random | None = None) -> dict:
|
||||
primary_subject, subject_phrase, pose = choose(rng, COUPLE_TYPES)
|
||||
if ethnicity == "asian":
|
||||
subject_phrase = {
|
||||
@@ -3140,7 +3141,7 @@ def make_couple(index: int, batch: int, rng: random.Random, expr_deck: Expressio
|
||||
if no_plus:
|
||||
body_options = [b for b in body_options if "plus" not in b and "fat" not in b]
|
||||
body = choose(rng, body_options)
|
||||
outfits = choose(rng, COUPLE_OUTFITS_MINIMAL if clothing == "minimal" else COUPLE_OUTFITS)
|
||||
outfits = choose(clothing_rng or rng, COUPLE_OUTFITS_MINIMAL if clothing == "minimal" else COUPLE_OUTFITS)
|
||||
expr_a, expr_b = expr_deck.draw_two()
|
||||
|
||||
row = row_base(index, batch, primary_subject, ages, body, scene_slug, composition)
|
||||
@@ -3164,7 +3165,7 @@ def make_couple(index: int, batch: int, rng: random.Random, expr_deck: Expressio
|
||||
return row
|
||||
|
||||
|
||||
def make_group_or_layout(index: int, batch: int, rng: random.Random, expr_deck: ExpressionDeck, clothing: str = "full", ethnicity: str = "any", no_plus: bool = False) -> dict:
|
||||
def make_group_or_layout(index: int, batch: int, rng: random.Random, expr_deck: ExpressionDeck, clothing: str = "full", ethnicity: str = "any", no_plus: bool = False, clothing_rng: random.Random | None = None) -> dict:
|
||||
minimal = clothing == "minimal"
|
||||
group_outfits = "minimal beachwear and lingerie-inspired outfits" if minimal else "stylish revealing party outfits"
|
||||
if ethnicity == "asian":
|
||||
@@ -3203,7 +3204,7 @@ def make_group_or_layout(index: int, batch: int, rng: random.Random, expr_deck:
|
||||
)
|
||||
return row
|
||||
|
||||
layout_slug, layout_desc = choose(rng, LAYOUTS_MINIMAL if minimal else LAYOUTS_FULL)
|
||||
layout_slug, layout_desc = choose(clothing_rng or rng, LAYOUTS_MINIMAL if minimal else LAYOUTS_FULL)
|
||||
if ethnicity == "asian":
|
||||
layout_desc = layout_desc.replace("adult", "Asian adult")
|
||||
elif ethnicity == "white_asian":
|
||||
|
||||
+5
-5
@@ -166,15 +166,15 @@ def softcore_partner_styling(
|
||||
choose: Choose,
|
||||
slot_softcore_outfit: SlotSoftcoreOutfit,
|
||||
) -> dict[str, Any]:
|
||||
content_rng = axis_rng(seed_config, "content", seed, row_number + 421)
|
||||
clothing_rng = axis_rng(seed_config, "clothing", seed, row_number + 421)
|
||||
pose_rng = axis_rng(seed_config, "pose", seed, row_number + 421)
|
||||
pov_set = set(pov_labels or [])
|
||||
outfits: list[str] = []
|
||||
for index in range(max(0, women_count - 1)):
|
||||
label = chr(ord("B") + index)
|
||||
full_label = f"Woman {label}"
|
||||
outfit = slot_softcore_outfit((label_map or {}).get(full_label), content_rng) or choose(
|
||||
content_rng,
|
||||
outfit = slot_softcore_outfit((label_map or {}).get(full_label), clothing_rng) or choose(
|
||||
clothing_rng,
|
||||
pair_options.INSTA_OF_SOFTCORE_PARTNER_WOMEN_OUTFITS,
|
||||
)
|
||||
sentence = pair_clothing.softcore_outfit_sentence(full_label, outfit)
|
||||
@@ -185,8 +185,8 @@ def softcore_partner_styling(
|
||||
full_label = f"Man {label}"
|
||||
if full_label in pov_set:
|
||||
continue
|
||||
outfit = slot_softcore_outfit((label_map or {}).get(full_label), content_rng) or choose(
|
||||
content_rng,
|
||||
outfit = slot_softcore_outfit((label_map or {}).get(full_label), clothing_rng) or choose(
|
||||
clothing_rng,
|
||||
pair_options.INSTA_OF_SOFTCORE_PARTNER_MEN_OUTFITS,
|
||||
)
|
||||
sentence = pair_clothing.softcore_outfit_sentence(full_label, outfit)
|
||||
|
||||
+3
-2
@@ -74,6 +74,7 @@ def build_insta_pair_rows_result(
|
||||
soft_seed_config = parsed_softcore_seed_config or parsed_seed_config
|
||||
hard_seed_config = parsed_hardcore_seed_config or parsed_seed_config
|
||||
soft_content_rng = axis_rng(soft_seed_config, "content", seed, row_number + 311)
|
||||
soft_clothing_rng = axis_rng(soft_seed_config, "clothing", seed, row_number + 311)
|
||||
soft_pose_rng = axis_rng(soft_seed_config, "pose", seed, row_number + 313)
|
||||
hard_content_rng = axis_rng(hard_seed_config, "content", seed, row_number + 317)
|
||||
soft_person_rng = axis_rng(soft_seed_config, "person", seed, row_number)
|
||||
@@ -147,8 +148,8 @@ def build_insta_pair_rows_result(
|
||||
if not soft_expression_enabled:
|
||||
soft_row = disable_row_expression(soft_row, soft_expression_intensity_source)
|
||||
|
||||
primary_softcore_outfit = slot_softcore_outfit(primary_slot, soft_content_rng)
|
||||
soft_row["item"] = primary_softcore_outfit or softcore_outfit(soft_content_rng, softcore_level_key)
|
||||
primary_softcore_outfit = slot_softcore_outfit(primary_slot, soft_clothing_rng)
|
||||
soft_row["item"] = primary_softcore_outfit or softcore_outfit(soft_clothing_rng, softcore_level_key)
|
||||
soft_row["pose"] = softcore_pose(soft_pose_rng, softcore_level_key)
|
||||
soft_row["item_label"] = (
|
||||
"Insta/OF softcore body exposure"
|
||||
|
||||
@@ -1441,6 +1441,7 @@ def _build_direct_builtin_row(
|
||||
minimal_clothing_ratio: float | None,
|
||||
standard_pose_ratio: float | None,
|
||||
seed: int,
|
||||
seed_config: dict[str, int] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
return row_generation_policy.build_direct_builtin_row(
|
||||
category,
|
||||
@@ -1456,6 +1457,7 @@ def _build_direct_builtin_row(
|
||||
minimal_clothing_ratio,
|
||||
standard_pose_ratio,
|
||||
seed,
|
||||
seed_config=seed_config,
|
||||
)
|
||||
|
||||
|
||||
|
||||
+28
-1
@@ -50,6 +50,32 @@ def is_pose_content_category(category: dict[str, Any], subcategory: dict[str, An
|
||||
return bool(tokens.intersection({"pose", "poses", "sex", "sexual"}))
|
||||
|
||||
|
||||
def is_clothing_content_category(category: dict[str, Any], subcategory: dict[str, Any]) -> bool:
|
||||
haystack = " ".join(
|
||||
str(value)
|
||||
for value in (
|
||||
category.get("name", ""),
|
||||
category.get("slug", ""),
|
||||
category.get("item_label", ""),
|
||||
subcategory.get("name", ""),
|
||||
subcategory.get("slug", ""),
|
||||
subcategory.get("item_label", ""),
|
||||
)
|
||||
).lower()
|
||||
tokens = set(re.findall(r"[a-z0-9]+", haystack))
|
||||
if tokens.intersection({"clothes", "clothing", "outfit", "outfits", "streetwear", "menswear", "daywear", "activewear", "lingerie", "wardrobe"}):
|
||||
return True
|
||||
return any(
|
||||
phrase in haystack
|
||||
for phrase in (
|
||||
"casual clothes",
|
||||
"men casual clothes",
|
||||
"couple casual clothes",
|
||||
"provocative erotic clothes",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def cast_count_adjustment(
|
||||
requested_women_count: int,
|
||||
requested_men_count: int,
|
||||
@@ -266,7 +292,8 @@ def select_category_item_route_result(
|
||||
)
|
||||
|
||||
is_pose_category = is_pose_content_category(category, subcategory)
|
||||
content_axis = "pose" if is_pose_category else "content"
|
||||
is_clothing_category = is_clothing_content_category(category, subcategory)
|
||||
content_axis = "pose" if is_pose_category else ("clothing" if is_clothing_category else "content")
|
||||
content_rng = seed_policy.axis_rng(seed_config, content_axis, seed, row_number)
|
||||
item = row_item_policy.weighted_choice(content_rng, _list_from(subcategory.get("items", [subcategory["name"]])))
|
||||
item_text, item_name, item_axis_values, item_template_metadata = row_item_policy.compose_item(
|
||||
|
||||
+21
-4
@@ -116,15 +116,19 @@ def build_direct_builtin_row(
|
||||
minimal_clothing_ratio: float | None,
|
||||
standard_pose_ratio: float | None,
|
||||
seed: int,
|
||||
seed_config: dict[str, int] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
rng = random.Random(seed_policy.row_seed(seed, row_number))
|
||||
clothing_rng = None
|
||||
if seed_config is not None:
|
||||
clothing_rng = seed_policy.axis_rng(seed_config, "clothing", seed, row_number)
|
||||
expr_deck = g.ExpressionDeck(
|
||||
g.EXPRESSIONS,
|
||||
random.Random(seed_policy.row_seed(g.EXPRESSION_SEED + seed, row_number)),
|
||||
)
|
||||
batch = max(1, ((row_number - 1) // g.BATCH_SIZE) + 1)
|
||||
index = start_index + row_number - 1
|
||||
row_clothing = pick_clothing_mode(rng, clothing, minimal_clothing_ratio)
|
||||
row_clothing = pick_clothing_mode(clothing_rng or rng, clothing, minimal_clothing_ratio)
|
||||
row_poses = pick_pose_mode(rng, poses, standard_pose_ratio)
|
||||
|
||||
if category == "woman":
|
||||
@@ -141,13 +145,26 @@ def build_direct_builtin_row(
|
||||
figure,
|
||||
no_plus_women,
|
||||
no_black,
|
||||
clothing_rng=clothing_rng,
|
||||
)
|
||||
elif category == "man":
|
||||
row = g.make_single(index, batch, rng, "man", expr_deck, row_clothing, ethnicity, row_poses, backside_bias, figure)
|
||||
row = g.make_single(
|
||||
index,
|
||||
batch,
|
||||
rng,
|
||||
"man",
|
||||
expr_deck,
|
||||
row_clothing,
|
||||
ethnicity,
|
||||
row_poses,
|
||||
backside_bias,
|
||||
figure,
|
||||
clothing_rng=clothing_rng,
|
||||
)
|
||||
elif category == "couple":
|
||||
row = g.make_couple(index, batch, rng, expr_deck, row_clothing, ethnicity, no_plus_women)
|
||||
row = g.make_couple(index, batch, rng, expr_deck, row_clothing, ethnicity, no_plus_women, clothing_rng=clothing_rng)
|
||||
elif category == "group_or_layout":
|
||||
row = g.make_group_or_layout(index, batch, rng, expr_deck, row_clothing, ethnicity, no_plus_women)
|
||||
row = g.make_group_or_layout(index, batch, rng, expr_deck, row_clothing, ethnicity, no_plus_women, clothing_rng=clothing_rng)
|
||||
else:
|
||||
raise ValueError(f"Unknown built-in category: {category}")
|
||||
|
||||
|
||||
+261
-2
@@ -2493,7 +2493,7 @@ def smoke_row_category_route_policy() -> None:
|
||||
hardcore_position_config={},
|
||||
)
|
||||
_expect(casual_route["category"]["slug"] == "casual_clothes", "Row category route selected wrong casual category")
|
||||
_expect(casual_route["content_axis"] == "content", "Non-pose category should use content seed axis")
|
||||
_expect(casual_route["content_axis"] == "clothing", "Casual clothes category should use clothing seed axis")
|
||||
_expect(casual_route["is_pose_category"] is False, "Non-pose category should not be marked as pose content")
|
||||
|
||||
exposed_route = row_category_route.select_category_item_route(
|
||||
@@ -2507,9 +2507,35 @@ def smoke_row_category_route_policy() -> None:
|
||||
hardcore_position_config={},
|
||||
)
|
||||
_expect(exposed_route["subcategory"]["slug"] == "sheer_exposed", "Row category route selected wrong exposed category")
|
||||
_expect(exposed_route["content_axis"] == "content", "Exposed clothing slug should not be treated as pose content")
|
||||
_expect(exposed_route["content_axis"] == "clothing", "Exposed clothing slug should use clothing seed axis")
|
||||
_expect(exposed_route["is_pose_category"] is False, "Exposed clothing slug should not be marked as pose content")
|
||||
|
||||
generic_categories = [
|
||||
{
|
||||
"name": "Lighting mood",
|
||||
"slug": "lighting_mood",
|
||||
"subcategories": [
|
||||
{
|
||||
"name": "Window light",
|
||||
"slug": "window_light",
|
||||
"items": ["soft window glow", "warm rim light"],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
generic_route = row_category_route.select_category_item_route(
|
||||
category_choice="Lighting mood",
|
||||
subcategory_choice="Window light",
|
||||
seed_config=seed_cfg,
|
||||
seed=2303,
|
||||
row_number=1,
|
||||
women_count=1,
|
||||
men_count=0,
|
||||
hardcore_position_config={},
|
||||
categories=generic_categories,
|
||||
)
|
||||
_expect(generic_route["content_axis"] == "content", "Generic non-clothing category should keep content seed axis")
|
||||
|
||||
|
||||
def smoke_row_generation_policy() -> None:
|
||||
_expect(pb._ratio_or_none(-1) is None, "Prompt builder ratio helper should treat negative as unset")
|
||||
@@ -2557,6 +2583,36 @@ def smoke_row_generation_policy() -> None:
|
||||
pb._build_direct_builtin_row(**direct_args) == row_generation.build_direct_builtin_row(**direct_args),
|
||||
"Prompt builder direct built-in row should delegate to row_generation",
|
||||
)
|
||||
direct_random_args = {**direct_args, "clothing": "random", "minimal_clothing_ratio": 0.5}
|
||||
direct_locked = row_generation.build_direct_builtin_row(
|
||||
**direct_random_args,
|
||||
seed_config=seed_config.parse_seed_config(pb.build_seed_lock_config_json(base_seed=5050)),
|
||||
)
|
||||
direct_clothing_reroll = row_generation.build_direct_builtin_row(
|
||||
**direct_random_args,
|
||||
seed_config=seed_config.parse_seed_config(
|
||||
pb.build_seed_lock_config_json(base_seed=5050, reroll_axis="clothing", reroll_seed=5052)
|
||||
),
|
||||
)
|
||||
direct_stable_keys = ("primary_subject", "age_band", "body_type", "scene", "composition", "pose_mode")
|
||||
_expect(
|
||||
tuple(direct_locked.get(key) for key in direct_stable_keys)
|
||||
== tuple(direct_clothing_reroll.get(key) for key in direct_stable_keys),
|
||||
"Direct built-in clothing reroll should keep non-clothing row fields stable",
|
||||
)
|
||||
_expect(
|
||||
(
|
||||
direct_locked.get("clothing_mode"),
|
||||
direct_locked.get("prompt"),
|
||||
direct_locked.get("caption"),
|
||||
)
|
||||
!= (
|
||||
direct_clothing_reroll.get("clothing_mode"),
|
||||
direct_clothing_reroll.get("prompt"),
|
||||
direct_clothing_reroll.get("caption"),
|
||||
),
|
||||
"Direct built-in clothing reroll should change clothing mode or clothing text",
|
||||
)
|
||||
auto_args = dict(
|
||||
row_number=2,
|
||||
start_index=41,
|
||||
@@ -14336,6 +14392,209 @@ def smoke_seed_config_policy() -> None:
|
||||
break
|
||||
_expect(pose_changed, "pose reroll should change pose/action metadata while cast and scene stay locked")
|
||||
|
||||
clothing_axis_seed = 42001
|
||||
|
||||
def clothing_category_row(seed_config_value: str | dict[str, Any], *, name: str = "seed_config_policy_clothing_axis") -> dict[str, Any]:
|
||||
return pb.build_prompt(
|
||||
category="Casual clothes",
|
||||
subcategory="Casual clothes / Streetwear",
|
||||
row_number=1,
|
||||
start_index=1,
|
||||
seed=clothing_axis_seed,
|
||||
clothing="random",
|
||||
ethnicity="any",
|
||||
poses="standard",
|
||||
backside_bias=0.0,
|
||||
figure="curvy",
|
||||
no_plus_women=False,
|
||||
no_black=False,
|
||||
minimal_clothing_ratio=0.5,
|
||||
standard_pose_ratio=-1,
|
||||
trigger=Trigger,
|
||||
prepend_trigger_to_prompt=True,
|
||||
extra_positive="",
|
||||
extra_negative="",
|
||||
seed_config=seed_config_value,
|
||||
women_count=1,
|
||||
men_count=0,
|
||||
expression_enabled=True,
|
||||
expression_intensity=0.6,
|
||||
)
|
||||
|
||||
def clothing_trace(row: dict[str, Any]) -> str:
|
||||
trace = row.get("generation_trace") if isinstance(row.get("generation_trace"), dict) else {}
|
||||
return str(trace.get("clothing") or "")
|
||||
|
||||
clothing_locked_row = clothing_category_row(pb.build_seed_lock_config_json(base_seed=clothing_axis_seed))
|
||||
content_pose_row = clothing_category_row(
|
||||
pb.build_seed_lock_config_json(
|
||||
base_seed=clothing_axis_seed,
|
||||
reroll_axis="content_pose",
|
||||
reroll_seed=clothing_axis_seed + 2,
|
||||
),
|
||||
name="seed_config_policy_content_pose_locked_clothing",
|
||||
)
|
||||
clothing_stable_fields = ("item", "scene_text", "subject_phrase")
|
||||
_expect(
|
||||
tuple(clothing_locked_row.get(key) for key in clothing_stable_fields)
|
||||
== tuple(content_pose_row.get(key) for key in clothing_stable_fields),
|
||||
"content_pose reroll should keep clothing-category item, scene, and subject stable when clothing is locked",
|
||||
)
|
||||
_expect(
|
||||
clothing_trace(clothing_locked_row) == clothing_trace(content_pose_row),
|
||||
"content_pose reroll should not change prompt clothing mode when clothing seed is locked",
|
||||
)
|
||||
|
||||
clothing_reroll_row = clothing_category_row(
|
||||
pb.build_seed_lock_config_json(
|
||||
base_seed=clothing_axis_seed,
|
||||
reroll_axis="clothing",
|
||||
reroll_seed=clothing_axis_seed + 2,
|
||||
),
|
||||
name="seed_config_policy_clothing_reroll",
|
||||
)
|
||||
_expect(
|
||||
tuple(clothing_locked_row.get(key) for key in ("scene_text", "pose", "subject_phrase"))
|
||||
== tuple(clothing_reroll_row.get(key) for key in ("scene_text", "pose", "subject_phrase")),
|
||||
"clothing reroll should keep scene, pose, and subject stable",
|
||||
)
|
||||
_expect(
|
||||
(
|
||||
clothing_trace(clothing_locked_row),
|
||||
clothing_locked_row.get("item"),
|
||||
)
|
||||
!= (
|
||||
clothing_trace(clothing_reroll_row),
|
||||
clothing_reroll_row.get("item"),
|
||||
),
|
||||
"clothing reroll should change clothing mode or outfit text",
|
||||
)
|
||||
|
||||
content_clothing_row = clothing_category_row(
|
||||
pb.build_seed_lock_config_json(
|
||||
base_seed=clothing_axis_seed,
|
||||
reroll_axis="content_clothing",
|
||||
reroll_seed=clothing_axis_seed + 2,
|
||||
),
|
||||
name="seed_config_policy_content_clothing_reroll",
|
||||
)
|
||||
_expect(
|
||||
clothing_trace(clothing_locked_row) != clothing_trace(content_clothing_row),
|
||||
"content_clothing reroll should change prompt clothing mode for clothing categories",
|
||||
)
|
||||
_expect(
|
||||
clothing_locked_row.get("item") != content_clothing_row.get("item"),
|
||||
"content_clothing reroll should change outfit text for clothing categories",
|
||||
)
|
||||
|
||||
outfit_alias_config = seed_config.parse_seed_config(pb.build_seed_lock_config_json(base_seed=clothing_axis_seed))
|
||||
outfit_alias_config.pop("clothing_seed", None)
|
||||
outfit_alias_config["content_seed"] = clothing_axis_seed
|
||||
outfit_alias_config["outfit_seed"] = clothing_axis_seed + 2
|
||||
outfit_alias_row = clothing_category_row(outfit_alias_config, name="seed_config_policy_outfit_alias")
|
||||
_expect(
|
||||
clothing_trace(outfit_alias_row) == clothing_trace(clothing_reroll_row),
|
||||
"outfit_seed alias should drive prompt clothing mode ahead of content_seed",
|
||||
)
|
||||
_expect(
|
||||
outfit_alias_row.get("item") == clothing_reroll_row.get("item"),
|
||||
"outfit_seed alias should drive clothing-category outfit text ahead of content_seed",
|
||||
)
|
||||
|
||||
def pair_row_outfit(seed_config_value: dict[str, int]) -> str:
|
||||
route = pair_rows.build_insta_pair_rows_result(
|
||||
row_number=1,
|
||||
start_index=1,
|
||||
seed=clothing_axis_seed,
|
||||
active_trigger=Trigger,
|
||||
parsed_seed_config=seed_config_value,
|
||||
options={
|
||||
"softcore_cast": "solo",
|
||||
"softcore_expression_enabled": False,
|
||||
"softcore_expression_intensity": 0.5,
|
||||
"hardcore_expression_enabled": False,
|
||||
"hardcore_expression_intensity": 0.5,
|
||||
"hardcore_detail_density": "standard",
|
||||
},
|
||||
ethnicity="any",
|
||||
figure="curvy",
|
||||
no_plus_women=False,
|
||||
no_black=False,
|
||||
character_profile="",
|
||||
character_cast="",
|
||||
character_slot_map={},
|
||||
pov_character_labels=[],
|
||||
hard_women_count=1,
|
||||
hard_men_count=1,
|
||||
soft_category="Casual clothes",
|
||||
soft_subcategory="Casual clothes / Streetwear",
|
||||
softcore_level_key="suggestive",
|
||||
hardcore_random_subcategory="Penetrative sex",
|
||||
hardcore_position_config="",
|
||||
location_config="",
|
||||
composition_config="",
|
||||
build_prompt=lambda **kwargs: {"prompt": "", "negative_prompt": "", "caption": ""},
|
||||
axis_rng=seed_config.axis_rng,
|
||||
cast_expression_intensity_override=lambda *_args: (None, "disabled"),
|
||||
context_from_character_slot=lambda *_args: {},
|
||||
apply_character_context_to_row=lambda row, _context: row,
|
||||
disable_row_expression=lambda row, _source: row,
|
||||
slot_softcore_outfit=lambda _slot, _rng: "",
|
||||
softcore_outfit=lambda rng, _level: f"outfit-{rng.randint(1, 1000000)}",
|
||||
softcore_pose=lambda rng, _level: f"pose-{rng.randint(1, 1000000)}",
|
||||
softcore_item_prompt_label=lambda _level: "outfit",
|
||||
pov_prompt_directive=lambda _labels: "",
|
||||
pov_composition_prompt=lambda composition, _labels: str(composition),
|
||||
)
|
||||
return str(route.soft_row.get("item") or "")
|
||||
|
||||
pair_base_config = seed_config.parse_seed_config(pb.build_seed_lock_config_json(base_seed=clothing_axis_seed))
|
||||
pair_content_reroll_config = seed_config.parse_seed_config(
|
||||
pb.build_seed_lock_config_json(
|
||||
base_seed=clothing_axis_seed,
|
||||
reroll_axis="content",
|
||||
reroll_seed=clothing_axis_seed + 4,
|
||||
)
|
||||
)
|
||||
pair_clothing_reroll_config = seed_config.parse_seed_config(
|
||||
pb.build_seed_lock_config_json(
|
||||
base_seed=clothing_axis_seed,
|
||||
reroll_axis="clothing",
|
||||
reroll_seed=clothing_axis_seed + 4,
|
||||
)
|
||||
)
|
||||
_expect(
|
||||
pair_row_outfit(pair_base_config) == pair_row_outfit(pair_content_reroll_config),
|
||||
"Pair softcore primary outfit should stay stable across content reroll when clothing is locked",
|
||||
)
|
||||
_expect(
|
||||
pair_row_outfit(pair_base_config) != pair_row_outfit(pair_clothing_reroll_config),
|
||||
"Pair softcore primary outfit should follow clothing reroll",
|
||||
)
|
||||
|
||||
def partner_outfits(seed_config_value: dict[str, int]) -> list[str]:
|
||||
return pair_cast.softcore_partner_styling(
|
||||
seed_config=seed_config_value,
|
||||
seed=clothing_axis_seed,
|
||||
row_number=1,
|
||||
women_count=2,
|
||||
men_count=1,
|
||||
pov_labels=[],
|
||||
label_map={},
|
||||
axis_rng=seed_config.axis_rng,
|
||||
choose=lambda rng, values: values[rng.randrange(len(values))],
|
||||
slot_softcore_outfit=lambda _slot, _rng: "",
|
||||
)["outfits"]
|
||||
|
||||
_expect(
|
||||
partner_outfits(pair_base_config) == partner_outfits(pair_content_reroll_config),
|
||||
"Pair partner outfits should stay stable across content reroll when clothing is locked",
|
||||
)
|
||||
_expect(
|
||||
partner_outfits(pair_base_config) != partner_outfits(pair_clothing_reroll_config),
|
||||
"Pair partner outfits should follow clothing reroll",
|
||||
)
|
||||
|
||||
|
||||
def smoke_prompt_route_simulation_policy() -> None:
|
||||
report = prompt_route_simulation.run_simulation(seed=3901, include_prompts=False)
|
||||
|
||||
Reference in New Issue
Block a user