Broaden seed axis simulation checks
This commit is contained in:
@@ -93,6 +93,30 @@ def _character_cast(*, pov_man: bool = False) -> str:
|
||||
)["character_cast"]
|
||||
|
||||
|
||||
def _random_character_cast() -> str:
|
||||
cast = pb.build_character_slot_json(
|
||||
subject_type="woman",
|
||||
label="A",
|
||||
age="random",
|
||||
ethnicity="random",
|
||||
figure="random",
|
||||
body="random",
|
||||
hair_color="random",
|
||||
hair_length="random",
|
||||
hair_style="random",
|
||||
descriptor_detail="full",
|
||||
)["character_cast"]
|
||||
return pb.build_character_slot_json(
|
||||
subject_type="man",
|
||||
label="A",
|
||||
age="random",
|
||||
ethnicity="random",
|
||||
body="random",
|
||||
descriptor_detail="compact",
|
||||
character_cast=cast,
|
||||
)["character_cast"]
|
||||
|
||||
|
||||
def _coworking_location_config() -> str:
|
||||
return pb.build_location_pool_json(
|
||||
enabled=True,
|
||||
@@ -106,6 +130,32 @@ def _coworking_location_config() -> str:
|
||||
)
|
||||
|
||||
|
||||
def _seed_probe_location_config() -> str:
|
||||
return pb.build_location_pool_json(
|
||||
enabled=True,
|
||||
combine_mode="replace",
|
||||
preset="custom_only",
|
||||
custom_locations=(
|
||||
"seed_coworking_desk: coworking desk row with warm lamps and laptops\n"
|
||||
"seed_coworking_glass: coworking glass office with plants and partition seams\n"
|
||||
"seed_coworking_windows: coworking window lounge with repeated desks and city light"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _seed_probe_composition_config() -> str:
|
||||
return pb.build_composition_pool_json(
|
||||
enabled=True,
|
||||
combine_mode="replace",
|
||||
preset="custom_only",
|
||||
custom_compositions=(
|
||||
"seed composition near a desk edge\n"
|
||||
"seed composition through a glass partition\n"
|
||||
"seed composition down repeating desk rows"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _orbit_camera(horizontal_angle: int = 45, vertical_angle: int = 0, zoom: float = 6.0) -> str:
|
||||
return pb.build_camera_orbit_config_json(
|
||||
enabled=True,
|
||||
@@ -602,8 +652,8 @@ def _insta_pair_case(seed: int, *, pov: bool, position: str, focus: str, family:
|
||||
)
|
||||
|
||||
|
||||
def _seed_axis_check(seed: int) -> dict[str, Any]:
|
||||
base = pb.build_prompt(
|
||||
def _seed_probe_row(seed: int, *, reroll_axis: str = "none", reroll_seed: int = -1) -> dict[str, Any]:
|
||||
return pb.build_prompt(
|
||||
category="Hardcore sexual poses",
|
||||
subcategory="Penetrative sex",
|
||||
row_number=1,
|
||||
@@ -622,64 +672,146 @@ def _seed_axis_check(seed: int) -> dict[str, Any]:
|
||||
prepend_trigger_to_prompt=True,
|
||||
extra_positive="",
|
||||
extra_negative="",
|
||||
seed_config=pb.build_seed_lock_config_json(base_seed=seed),
|
||||
seed_config=pb.build_seed_lock_config_json(base_seed=seed, reroll_axis=reroll_axis, reroll_seed=reroll_seed),
|
||||
women_count=1,
|
||||
men_count=1,
|
||||
character_cast=_character_cast(),
|
||||
character_cast=_random_character_cast(),
|
||||
hardcore_position_config=_position_filter("penetration_only", "penetration", ["missionary", "doggy", "cowgirl"]),
|
||||
location_config=_coworking_location_config(),
|
||||
location_config=_seed_probe_location_config(),
|
||||
composition_config=_seed_probe_composition_config(),
|
||||
expression_intensity=0.75,
|
||||
)
|
||||
changed = False
|
||||
mismatches: list[str] = []
|
||||
for reroll_seed in range(seed + 1, seed + 10):
|
||||
rerolled = pb.build_prompt(
|
||||
category="Hardcore sexual poses",
|
||||
subcategory="Penetrative sex",
|
||||
row_number=1,
|
||||
start_index=1,
|
||||
seed=seed,
|
||||
clothing="random",
|
||||
ethnicity="any",
|
||||
poses="random",
|
||||
backside_bias=0.0,
|
||||
figure="random",
|
||||
no_plus_women=False,
|
||||
no_black=False,
|
||||
minimal_clothing_ratio=-1,
|
||||
standard_pose_ratio=-1,
|
||||
trigger=TRIGGER,
|
||||
prepend_trigger_to_prompt=True,
|
||||
extra_positive="",
|
||||
extra_negative="",
|
||||
seed_config=pb.build_seed_lock_config_json(base_seed=seed, reroll_axis="pose", reroll_seed=reroll_seed),
|
||||
women_count=1,
|
||||
men_count=1,
|
||||
character_cast=_character_cast(),
|
||||
hardcore_position_config=_position_filter("penetration_only", "penetration", ["missionary", "doggy", "cowgirl"]),
|
||||
location_config=_coworking_location_config(),
|
||||
)
|
||||
if rerolled.get("cast_descriptor_text") != base.get("cast_descriptor_text"):
|
||||
mismatches.append(f"cast changed on pose reroll {reroll_seed}")
|
||||
if rerolled.get("scene_text") != base.get("scene_text"):
|
||||
mismatches.append(f"scene changed on pose reroll {reroll_seed}")
|
||||
if (
|
||||
rerolled.get("position_key") != base.get("position_key")
|
||||
or rerolled.get("source_role_graph") != base.get("source_role_graph")
|
||||
or rerolled.get("item") != base.get("item")
|
||||
):
|
||||
changed = True
|
||||
break
|
||||
issues = list(mismatches)
|
||||
if not changed:
|
||||
issues.append("pose reroll did not change pose/action metadata within 9 attempts")
|
||||
|
||||
|
||||
def _seed_probe_snapshot(row: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
"name": "seed_axis.pose_reroll",
|
||||
"base": _row_summary(base),
|
||||
"changed": changed,
|
||||
"cast_descriptor_text": row.get("cast_descriptor_text"),
|
||||
"scene": row.get("scene"),
|
||||
"scene_text": row.get("scene_text"),
|
||||
"position_key": row.get("position_key"),
|
||||
"position_keys": row.get("position_keys") or [],
|
||||
"item": row.get("item"),
|
||||
"source_role_graph": row.get("source_role_graph"),
|
||||
"character_expression_text": row.get("character_expression_text"),
|
||||
"composition": row.get("composition"),
|
||||
}
|
||||
|
||||
|
||||
def _same_fields_issues(
|
||||
name: str,
|
||||
base: dict[str, Any],
|
||||
rerolled: dict[str, Any],
|
||||
fields: tuple[str, ...],
|
||||
reroll_seed: int,
|
||||
) -> list[str]:
|
||||
return [
|
||||
f"{name}: stable_field_changed:{field}:reroll_seed={reroll_seed}"
|
||||
for field in fields
|
||||
if base.get(field) != rerolled.get(field)
|
||||
]
|
||||
|
||||
|
||||
def _formatter_output_texts(row: dict[str, Any]) -> dict[str, str]:
|
||||
formatted = _format_metadata(row, "single")
|
||||
return {
|
||||
"krea": str(formatted["krea"].get("krea_prompt") or ""),
|
||||
"sdxl": str(formatted["sdxl"].get("sdxl_prompt") or ""),
|
||||
"caption": str(formatted["caption"].get("natural_caption") or ""),
|
||||
}
|
||||
|
||||
|
||||
def _seed_determinism_check(seed: int) -> dict[str, Any]:
|
||||
first = _seed_probe_row(seed)
|
||||
second = _seed_probe_row(seed)
|
||||
issues: list[str] = []
|
||||
if first != second:
|
||||
issues.append("locked seed config did not reproduce identical row metadata")
|
||||
if _formatter_output_texts(first) != _formatter_output_texts(second):
|
||||
issues.append("locked seed config did not reproduce identical formatter outputs")
|
||||
return {
|
||||
"name": "seed_axis.locked_determinism",
|
||||
"base": _row_summary(first),
|
||||
"changed": False,
|
||||
"issues": issues,
|
||||
}
|
||||
|
||||
|
||||
def _seed_reroll_check(
|
||||
seed: int,
|
||||
*,
|
||||
reroll_axis: str,
|
||||
changed_fields: tuple[str, ...],
|
||||
stable_fields: tuple[str, ...],
|
||||
) -> dict[str, Any]:
|
||||
name = f"seed_axis.{reroll_axis}_reroll"
|
||||
base = _seed_probe_row(seed)
|
||||
base_snapshot = _seed_probe_snapshot(base)
|
||||
changed = False
|
||||
changed_seed = None
|
||||
changed_field_names: list[str] = []
|
||||
issues: list[str] = []
|
||||
for reroll_seed in range(seed + 1, seed + 16):
|
||||
rerolled = _seed_probe_row(seed, reroll_axis=reroll_axis, reroll_seed=reroll_seed)
|
||||
rerolled_snapshot = _seed_probe_snapshot(rerolled)
|
||||
field_issues = _same_fields_issues(name, base_snapshot, rerolled_snapshot, stable_fields, reroll_seed)
|
||||
if field_issues:
|
||||
issues.extend(field_issues)
|
||||
break
|
||||
changed_field_names = [
|
||||
field for field in changed_fields if base_snapshot.get(field) != rerolled_snapshot.get(field)
|
||||
]
|
||||
if changed_field_names:
|
||||
changed = True
|
||||
changed_seed = reroll_seed
|
||||
break
|
||||
if not changed:
|
||||
issues.append(f"{reroll_axis} reroll did not change {', '.join(changed_fields)} within 15 attempts")
|
||||
return {
|
||||
"name": name,
|
||||
"base": _row_summary(base),
|
||||
"changed": changed,
|
||||
"changed_seed": changed_seed,
|
||||
"changed_fields": changed_field_names,
|
||||
"issues": issues,
|
||||
}
|
||||
|
||||
|
||||
def _seed_axis_checks(seed: int) -> list[dict[str, Any]]:
|
||||
return [
|
||||
_seed_determinism_check(seed),
|
||||
_seed_reroll_check(
|
||||
seed,
|
||||
reroll_axis="person",
|
||||
changed_fields=("cast_descriptor_text",),
|
||||
stable_fields=("scene_text", "position_key", "item", "source_role_graph", "character_expression_text", "composition"),
|
||||
),
|
||||
_seed_reroll_check(
|
||||
seed,
|
||||
reroll_axis="scene",
|
||||
changed_fields=("scene", "scene_text"),
|
||||
stable_fields=("cast_descriptor_text", "position_key", "item", "source_role_graph", "character_expression_text", "composition"),
|
||||
),
|
||||
_seed_reroll_check(
|
||||
seed,
|
||||
reroll_axis="pose",
|
||||
changed_fields=("position_key", "item", "source_role_graph"),
|
||||
stable_fields=("cast_descriptor_text", "scene_text", "character_expression_text", "composition"),
|
||||
),
|
||||
_seed_reroll_check(
|
||||
seed,
|
||||
reroll_axis="expression",
|
||||
changed_fields=("character_expression_text",),
|
||||
stable_fields=("cast_descriptor_text", "scene_text", "position_key", "item", "source_role_graph", "composition"),
|
||||
),
|
||||
_seed_reroll_check(
|
||||
seed,
|
||||
reroll_axis="composition",
|
||||
changed_fields=("composition",),
|
||||
stable_fields=("cast_descriptor_text", "scene_text", "position_key", "item", "source_role_graph", "character_expression_text"),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def run_simulation(seed: int = 3901, *, include_prompts: bool = False) -> dict[str, Any]:
|
||||
cases: list[dict[str, Any]] = []
|
||||
regular = _regular_single_case(seed)
|
||||
@@ -705,7 +837,7 @@ def run_simulation(seed: int = 3901, *, include_prompts: bool = False) -> dict[s
|
||||
cases.extend(_pair_reports("insta_pair.penetration", penetration_pair, include_prompts=include_prompts))
|
||||
pov_pair = _insta_pair_case(seed + 2, pov=True, position="penis_licking", focus="outercourse_only", family="outercourse")
|
||||
cases.extend(_pair_reports("insta_pair.pov_outercourse", pov_pair, include_prompts=include_prompts))
|
||||
axis_checks = [_seed_axis_check(seed + 3)]
|
||||
axis_checks = _seed_axis_checks(seed + 3)
|
||||
issues = [
|
||||
{"case": case["name"], "issue": issue}
|
||||
for case in cases
|
||||
|
||||
+22
-1
@@ -7834,7 +7834,7 @@ def smoke_prompt_route_simulation_policy() -> None:
|
||||
report = prompt_route_simulation.run_simulation(seed=3901, include_prompts=False)
|
||||
summary = report.get("summary") or {}
|
||||
_expect(summary.get("cases") == 11, "Prompt route simulation case count changed unexpectedly")
|
||||
_expect(summary.get("axis_checks") == 1, "Prompt route simulation lost axis check coverage")
|
||||
_expect(summary.get("axis_checks") == 6, "Prompt route simulation lost axis check coverage")
|
||||
_expect(summary.get("issues") == 0, f"Prompt route simulation reported issues: {report.get('issues')}")
|
||||
cases = {case.get("name"): case for case in report.get("cases") or []}
|
||||
for route_name in (
|
||||
@@ -7856,6 +7856,27 @@ def smoke_prompt_route_simulation_policy() -> None:
|
||||
"penis_licking" in (pov_summary.get("position_keys") or []),
|
||||
"Prompt route simulation lost selected outercourse key from position_keys",
|
||||
)
|
||||
axis_checks = {check.get("name"): check for check in report.get("axis_checks") or []}
|
||||
for check_name in (
|
||||
"seed_axis.locked_determinism",
|
||||
"seed_axis.person_reroll",
|
||||
"seed_axis.scene_reroll",
|
||||
"seed_axis.pose_reroll",
|
||||
"seed_axis.expression_reroll",
|
||||
"seed_axis.composition_reroll",
|
||||
):
|
||||
check = axis_checks.get(check_name) or {}
|
||||
_expect(check, f"Prompt route simulation lost seed-axis check {check_name}")
|
||||
_expect(not check.get("issues"), f"Prompt route simulation seed-axis check reported issues: {check_name}")
|
||||
_expect(axis_checks["seed_axis.locked_determinism"].get("changed") is False, "Locked determinism check should not be a reroll")
|
||||
for check_name in (
|
||||
"seed_axis.person_reroll",
|
||||
"seed_axis.scene_reroll",
|
||||
"seed_axis.pose_reroll",
|
||||
"seed_axis.expression_reroll",
|
||||
"seed_axis.composition_reroll",
|
||||
):
|
||||
_expect(axis_checks[check_name].get("changed") is True, f"{check_name} should prove its axis can reroll")
|
||||
|
||||
|
||||
def smoke_node_camera_registration() -> None:
|
||||
|
||||
Reference in New Issue
Block a user