Use couple wording for same-cast softcore camera prompts

This commit is contained in:
2026-06-28 01:07:54 +02:00
parent 8d58bfdf6a
commit 14f984a629
3 changed files with 82 additions and 4 deletions
+18 -2
View File
@@ -24,6 +24,22 @@ def camera_config_with_detail(
return camera_config return camera_config
def softcore_subject_kind(softcore_cast: Any, hard_women_count: int, hard_men_count: int) -> str:
if str(softcore_cast) == "solo":
return "woman"
total = int(hard_women_count or 0) + int(hard_men_count or 0)
if total == 2:
return "couple"
return "subjects"
def hardcore_subject_kind(hard_women_count: int, hard_men_count: int) -> str:
total = int(hard_women_count or 0) + int(hard_men_count or 0)
if total == 2:
return "couple"
return "subjects"
@dataclass(frozen=True) @dataclass(frozen=True)
class InstaPairCameraRoute: class InstaPairCameraRoute:
soft_row: dict[str, Any] soft_row: dict[str, Any]
@@ -101,8 +117,8 @@ def resolve_insta_pair_camera_result(
soft_camera_directive, soft_camera_config_dict = camera_directive(soft_camera_config_dict) soft_camera_directive, soft_camera_config_dict = camera_directive(soft_camera_config_dict)
hard_camera_directive, hard_camera_config_dict = camera_directive(hard_camera_config_dict) hard_camera_directive, hard_camera_config_dict = camera_directive(hard_camera_config_dict)
soft_subject_kind = "woman" if options["softcore_cast"] == "solo" else "subjects" soft_subject_kind = softcore_subject_kind(options["softcore_cast"], hard_women_count, hard_men_count)
hard_subject_kind = "couple" if hard_women_count + hard_men_count == 2 else "subjects" hard_subject_kind = hardcore_subject_kind(hard_women_count, hard_men_count)
soft_row = apply_contextual_composition(soft_row, soft_subject_kind) soft_row = apply_contextual_composition(soft_row, soft_subject_kind)
hard_row = apply_contextual_composition(hard_row, hard_subject_kind) hard_row = apply_contextual_composition(hard_row, hard_subject_kind)
+22 -2
View File
@@ -1054,13 +1054,32 @@ def profile_composition_text(profile: dict[str, Any], subject_kind: str) -> str:
if subject_kind == "man" and composition.get("man"): if subject_kind == "man" and composition.get("man"):
return str(composition["man"]) return str(composition["man"])
text = str(composition.get("default") or f"{profile['place']} frame with the subjects clearly placed in the room") text = str(composition.get("default") or f"{profile['place']} frame with the subjects clearly placed in the room")
if subject_kind == "couple": text = composition_subject_text(text, subject_kind)
text = text.replace("the subjects", "the couple")
if "composition" not in text.lower(): if "composition" not in text.lower():
text = f"{text} composition" text = f"{text} composition"
return text return text
def composition_subject_text(text: str, subject_kind: str) -> str:
replacements: dict[str, str] = {}
if subject_kind == "woman":
replacements = {"The subjects": "The woman", "the subjects": "the woman"}
elif subject_kind == "man":
replacements = {"The subjects": "The man", "the subjects": "the man"}
elif subject_kind == "couple":
replacements = {
"The subjects": "The couple",
"the subjects": "the couple",
"The woman": "The couple",
"the woman": "the couple",
"The man": "The couple",
"the man": "the couple",
}
for old, new in replacements.items():
text = text.replace(old, new)
return text
def contextual_composition_prompt( def contextual_composition_prompt(
scene_text: Any, scene_text: Any,
composition: Any, composition: Any,
@@ -1073,6 +1092,7 @@ def contextual_composition_prompt(
text = str(composition or "").strip() text = str(composition or "").strip()
if not text: if not text:
return text return text
text = composition_subject_text(text, subject_kind)
profile = scene_camera_profile(scene_text, scene_entry=scene_entry, theme=theme, profile_key=profile_key) profile = scene_camera_profile(scene_text, scene_entry=scene_entry, theme=theme, profile_key=profile_key)
if not profile: if not profile:
return text return text
+42
View File
@@ -881,6 +881,46 @@ def smoke_row_camera_policy() -> None:
"coworking lounge frame with the couple near a desk edge" in updated.get("composition", ""), "coworking lounge frame with the couple near a desk edge" in updated.get("composition", ""),
"row camera policy did not adapt coworking composition for couple rows", "row camera policy did not adapt coworking composition for couple rows",
) )
already_matching_row = dict(row)
already_matching_row["pov_character_labels"] = []
already_matching_row["composition"] = "coworking lounge frame with the subjects near a desk edge and tall-window depth behind them"
already_matching_row["prompt"] = (
"A generated adult prompt. Framed as coworking lounge frame with the subjects near a desk edge and tall-window depth behind them. "
"Avoid: low quality."
)
updated_matching = row_camera.apply_camera_config(
already_matching_row,
_orbit_camera(horizontal_angle=45, vertical_angle=0, zoom=5.5),
compact_labels=pb.CAMERA_COMPACT_LABELS,
)
_expect(
"the couple near a desk edge" in str(updated_matching.get("composition", "")),
"row camera policy did not adapt generic matching composition subject wording",
)
_expect(
"the subjects near a desk edge" not in str(updated_matching.get("prompt", "")),
"row camera policy left generic matching composition subject wording in prompt",
)
pre_normalized_row = dict(row)
pre_normalized_row["pov_character_labels"] = []
pre_normalized_row["composition"] = "coworking lounge frame with the woman near a desk edge and tall-window depth behind them"
pre_normalized_row["prompt"] = (
"A generated adult prompt. Framed as coworking lounge frame with the woman near a desk edge and tall-window depth behind them. "
"Avoid: low quality."
)
updated_pre_normalized = row_camera.apply_camera_config(
pre_normalized_row,
_orbit_camera(horizontal_angle=45, vertical_angle=0, zoom=5.5),
compact_labels=pb.CAMERA_COMPACT_LABELS,
)
_expect(
"the couple near a desk edge" in str(updated_pre_normalized.get("composition", "")),
"row camera policy did not adapt pre-normalized woman composition for couple rows",
)
_expect(
"the woman near a desk edge" not in str(updated_pre_normalized.get("prompt", "")),
"row camera policy left pre-normalized woman composition wording in prompt",
)
stale_internal_row = dict(row) stale_internal_row = dict(row)
stale_internal_row["pov_character_labels"] = [] stale_internal_row["pov_character_labels"] = []
stale_internal_row["composition"] = "camera-aware coworking lounge frame with subjects near a desk edge" stale_internal_row["composition"] = "camera-aware coworking lounge frame with subjects near a desk edge"
@@ -6203,6 +6243,8 @@ def smoke_pair_route_policy() -> None:
_expect(camera_route.as_dict() == camera_legacy, "Typed pair camera route should match legacy dict route") _expect(camera_route.as_dict() == camera_legacy, "Typed pair camera route should match legacy dict route")
_expect(camera_route.hard_scene == "soft room", "Typed pair camera route lost same-room continuity") _expect(camera_route.hard_scene == "soft room", "Typed pair camera route lost same-room continuity")
_expect(camera_route.hard_camera_sentence.startswith("Camera control:"), "Typed pair camera route lost hard camera sentence") _expect(camera_route.hard_camera_sentence.startswith("Camera control:"), "Typed pair camera route lost hard camera sentence")
_expect(camera_route.soft_row.get("subject_kind") == "couple", "Same-cast softcore camera route should use couple subject kind")
_expect("couple scene directive" in camera_route.soft_camera_scene_directive, "Same-cast softcore camera directive should use couple wording")
clothing_common = { clothing_common = {
"hard_row": { "hard_row": {