Extract Insta pair row creation
This commit is contained in:
@@ -144,17 +144,18 @@ Owner today: `build_insta_of_pair`.
|
||||
|
||||
Keep here:
|
||||
|
||||
- soft/hard row creation;
|
||||
- continuity policy;
|
||||
- softcore cast policy;
|
||||
|
||||
Improve later:
|
||||
|
||||
- split pair assembly into small functions by phase:
|
||||
`build_soft_row`, `build_hard_row`.
|
||||
- split remaining pair cast/descriptor policy out of `build_insta_of_pair`.
|
||||
|
||||
Already isolated:
|
||||
|
||||
- soft/hard row creation lives in `pair_rows.py`, including softcore expression
|
||||
override resolution, Woman A slot context application, soft outfit/pose
|
||||
overrides, POV row fields, and hardcore row creation.
|
||||
- pair-level camera routing lives in `pair_camera.py`, including soft/hard
|
||||
camera config selection, same-as-softcore mode, camera-detail override,
|
||||
same-room hard scene continuity, camera-aware composition mutation, POV camera
|
||||
|
||||
@@ -65,6 +65,7 @@ Core helper ownership:
|
||||
| Python module | What it owns |
|
||||
| --- | --- |
|
||||
| `category_library.py` | JSON category loading, subcategory normalization, named scene/expression/composition pool loading, cast compatibility filtering, exact subcategory lookup, and inheritance-based pool merging. |
|
||||
| `pair_rows.py` | Insta/OF soft/hard row creation, softcore expression override resolution, Woman A slot context application, soft outfit/pose overrides, and POV row fields. |
|
||||
| `pair_camera.py` | Insta/OF soft/hard camera route resolution, same-as-softcore camera mode, camera-detail override, camera-aware composition mutation, POV camera suppression, and synchronized row/root camera metadata. |
|
||||
| `pair_clothing.py` | Insta/OF hardcore clothing continuity, action-aware body-access flags, conflicting outfit-piece cleanup, default visible-men clothing, and final root clothing-state assembly. |
|
||||
| `pair_output.py` | Insta/OF final pair prompts, trigger preservation, negative prompts, captions, and root pair metadata assembly. |
|
||||
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable
|
||||
|
||||
|
||||
BuildPrompt = Callable[..., dict[str, Any]]
|
||||
AxisRng = Callable[[dict[str, int], str, int, int], Any]
|
||||
|
||||
|
||||
def build_insta_pair_rows(
|
||||
*,
|
||||
row_number: int,
|
||||
start_index: int,
|
||||
seed: int,
|
||||
active_trigger: str,
|
||||
parsed_seed_config: dict[str, int],
|
||||
options: dict[str, Any],
|
||||
ethnicity: str,
|
||||
figure: str,
|
||||
no_plus_women: bool,
|
||||
no_black: bool,
|
||||
character_profile: str | dict[str, Any] | None,
|
||||
character_cast: str | dict[str, Any] | list[Any] | None,
|
||||
character_slot_map: dict[str, dict[str, Any]],
|
||||
pov_character_labels: list[str],
|
||||
hard_women_count: int,
|
||||
hard_men_count: int,
|
||||
soft_category: str,
|
||||
soft_subcategory: str,
|
||||
softcore_level_key: str,
|
||||
hardcore_random_subcategory: str,
|
||||
hardcore_position_config: str | dict[str, Any] | None,
|
||||
location_config: str | dict[str, Any] | None,
|
||||
composition_config: str | dict[str, Any] | None,
|
||||
build_prompt: BuildPrompt,
|
||||
axis_rng: AxisRng,
|
||||
cast_expression_intensity_override: Callable[
|
||||
[float, dict[str, dict[str, Any]], int, int, str],
|
||||
tuple[float | None, str],
|
||||
],
|
||||
context_from_character_slot: Callable[[Any, dict[str, Any], str, str, str, bool, bool], dict[str, Any]],
|
||||
apply_character_context_to_row: Callable[[dict[str, Any], dict[str, Any]], dict[str, Any]],
|
||||
disable_row_expression: Callable[[dict[str, Any], str], dict[str, Any]],
|
||||
slot_softcore_outfit: Callable[[dict[str, Any] | None, Any], str],
|
||||
softcore_outfit: Callable[[Any, str], str],
|
||||
softcore_pose: Callable[[Any, str], str],
|
||||
softcore_item_prompt_label: Callable[[str], str],
|
||||
body_exposure_scene_text: Callable[[Any], str],
|
||||
pov_prompt_directive: Callable[[list[str]], str],
|
||||
pov_composition_prompt: Callable[[Any, list[str]], str],
|
||||
) -> dict[str, Any]:
|
||||
soft_content_rng = axis_rng(parsed_seed_config, "content", seed, row_number + 311)
|
||||
hard_content_rng = axis_rng(parsed_seed_config, "content", seed, row_number + 317)
|
||||
soft_person_rng = axis_rng(parsed_seed_config, "person", seed, row_number)
|
||||
|
||||
soft_expression_women_count = hard_women_count if options["softcore_cast"] == "same_as_hardcore" else 1
|
||||
soft_expression_men_count = hard_men_count if options["softcore_cast"] == "same_as_hardcore" else 0
|
||||
soft_expression_enabled = bool(options["softcore_expression_enabled"])
|
||||
soft_expression_intensity = options["softcore_expression_intensity"]
|
||||
soft_expression_intensity_source = "input"
|
||||
if soft_expression_enabled:
|
||||
soft_expression_intensity, soft_expression_intensity_source = cast_expression_intensity_override(
|
||||
options["softcore_expression_intensity"],
|
||||
character_slot_map,
|
||||
soft_expression_women_count,
|
||||
soft_expression_men_count,
|
||||
"softcore",
|
||||
)
|
||||
if soft_expression_intensity is None:
|
||||
soft_expression_enabled = False
|
||||
else:
|
||||
soft_expression_intensity_source = "disabled"
|
||||
|
||||
primary_slot = character_slot_map.get("Woman A")
|
||||
primary_slot_context = None
|
||||
if primary_slot:
|
||||
primary_slot_context = context_from_character_slot(
|
||||
soft_person_rng,
|
||||
primary_slot,
|
||||
"woman",
|
||||
ethnicity,
|
||||
figure,
|
||||
no_plus_women,
|
||||
no_black,
|
||||
)
|
||||
|
||||
soft_row = build_prompt(
|
||||
category=soft_category,
|
||||
subcategory=soft_subcategory,
|
||||
row_number=row_number,
|
||||
start_index=start_index,
|
||||
seed=seed,
|
||||
clothing="minimal",
|
||||
ethnicity=ethnicity,
|
||||
poses="evocative",
|
||||
backside_bias=0.0,
|
||||
figure=figure,
|
||||
no_plus_women=no_plus_women,
|
||||
no_black=no_black,
|
||||
minimal_clothing_ratio=-1,
|
||||
standard_pose_ratio=-1,
|
||||
trigger=active_trigger,
|
||||
prepend_trigger_to_prompt=False,
|
||||
extra_positive="",
|
||||
extra_negative="",
|
||||
seed_config=parsed_seed_config,
|
||||
women_count=1,
|
||||
men_count=0,
|
||||
expression_enabled=soft_expression_enabled,
|
||||
expression_intensity=soft_expression_intensity,
|
||||
character_profile="" if primary_slot else character_profile or "",
|
||||
character_cast="",
|
||||
location_config=location_config or "",
|
||||
composition_config=composition_config or "",
|
||||
)
|
||||
soft_row["expression_intensity_source"] = soft_expression_intensity_source
|
||||
if primary_slot_context:
|
||||
soft_row = apply_character_context_to_row(soft_row, primary_slot_context)
|
||||
soft_row["character_slot"] = primary_slot
|
||||
soft_row["character_slot_status"] = "applied:Woman A"
|
||||
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)
|
||||
soft_row["pose"] = softcore_pose(soft_content_rng, softcore_level_key)
|
||||
soft_row["item_label"] = (
|
||||
"Insta/OF softcore body exposure"
|
||||
if softcore_level_key == "explicit_nude"
|
||||
else "Insta/OF softcore outfit"
|
||||
)
|
||||
soft_row["softcore_item_prompt_label"] = softcore_item_prompt_label(softcore_level_key)
|
||||
soft_row["custom_item"] = "insta_of_softcore_outfit"
|
||||
soft_row["softcore_outfit_policy"] = "character_slot:Woman A" if primary_softcore_outfit else "insta_of_safe_softcore"
|
||||
if softcore_level_key == "explicit_nude":
|
||||
soft_row["source_scene_text"] = soft_row.get("source_scene_text") or soft_row.get("scene_text", "")
|
||||
soft_row["scene_text"] = body_exposure_scene_text(soft_row.get("scene_text", ""))
|
||||
soft_row["pov_character_labels"] = (
|
||||
pov_character_labels
|
||||
if options["softcore_cast"] == "same_as_hardcore"
|
||||
else []
|
||||
)
|
||||
soft_row["pov_prompt_directive"] = pov_prompt_directive(soft_row["pov_character_labels"])
|
||||
if soft_row["pov_character_labels"]:
|
||||
soft_row["source_composition"] = soft_row.get("source_composition") or soft_row.get("composition", "")
|
||||
soft_row["composition"] = pov_composition_prompt(
|
||||
soft_row["source_composition"],
|
||||
soft_row["pov_character_labels"],
|
||||
)
|
||||
|
||||
hard_row = build_prompt(
|
||||
category="Hardcore sexual poses",
|
||||
subcategory=hardcore_random_subcategory,
|
||||
row_number=row_number,
|
||||
start_index=start_index,
|
||||
seed=seed,
|
||||
clothing="minimal",
|
||||
ethnicity=ethnicity,
|
||||
poses="evocative",
|
||||
backside_bias=0.0,
|
||||
figure=figure,
|
||||
no_plus_women=no_plus_women,
|
||||
no_black=no_black,
|
||||
minimal_clothing_ratio=-1,
|
||||
standard_pose_ratio=-1,
|
||||
trigger=active_trigger,
|
||||
prepend_trigger_to_prompt=False,
|
||||
extra_positive="",
|
||||
extra_negative="",
|
||||
seed_config=parsed_seed_config,
|
||||
women_count=hard_women_count,
|
||||
men_count=hard_men_count,
|
||||
expression_enabled=options["hardcore_expression_enabled"],
|
||||
expression_intensity=options["hardcore_expression_intensity"],
|
||||
character_cast=character_cast or "",
|
||||
expression_phase="hardcore",
|
||||
hardcore_position_config=hardcore_position_config or "",
|
||||
location_config=location_config or "",
|
||||
composition_config=composition_config or "",
|
||||
)
|
||||
hard_row["hardcore_detail_density"] = options["hardcore_detail_density"]
|
||||
hard_row["pov_character_labels"] = pov_character_labels
|
||||
hard_row["pov_prompt_directive"] = pov_prompt_directive(pov_character_labels)
|
||||
|
||||
return {
|
||||
"soft_row": soft_row,
|
||||
"hard_row": hard_row,
|
||||
"hard_content_rng": hard_content_rng,
|
||||
}
|
||||
+32
-113
@@ -28,6 +28,7 @@ try:
|
||||
from . import pair_clothing
|
||||
from . import pair_camera
|
||||
from . import pair_output
|
||||
from . import pair_rows
|
||||
from . import scene_camera_adapters
|
||||
from .hardcore_text_cleanup import (
|
||||
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
|
||||
@@ -60,6 +61,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
||||
import pair_clothing
|
||||
import pair_camera
|
||||
import pair_output
|
||||
import pair_rows
|
||||
import scene_camera_adapters
|
||||
from hardcore_text_cleanup import (
|
||||
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
|
||||
@@ -6993,130 +6995,47 @@ def build_insta_of_pair(
|
||||
pov_character_labels = _pov_character_labels(character_slot_map, hard_men_count)
|
||||
softcore_level_key = str(options["softcore_level"])
|
||||
soft_category, soft_subcategory = _insta_of_softcore_category(softcore_level_key)
|
||||
soft_content_rng = _axis_rng(parsed_seed_config, "content", seed, row_number + 311)
|
||||
hard_content_rng = _axis_rng(parsed_seed_config, "content", seed, row_number + 317)
|
||||
soft_person_rng = _axis_rng(parsed_seed_config, "person", seed, row_number)
|
||||
soft_expression_women_count = hard_women_count if options["softcore_cast"] == "same_as_hardcore" else 1
|
||||
soft_expression_men_count = hard_men_count if options["softcore_cast"] == "same_as_hardcore" else 0
|
||||
soft_expression_enabled = bool(options["softcore_expression_enabled"])
|
||||
soft_expression_intensity = options["softcore_expression_intensity"]
|
||||
soft_expression_intensity_source = "input"
|
||||
if soft_expression_enabled:
|
||||
soft_expression_intensity, soft_expression_intensity_source = _cast_expression_intensity_override(
|
||||
options["softcore_expression_intensity"],
|
||||
character_slot_map,
|
||||
soft_expression_women_count,
|
||||
soft_expression_men_count,
|
||||
"softcore",
|
||||
)
|
||||
if soft_expression_intensity is None:
|
||||
soft_expression_enabled = False
|
||||
else:
|
||||
soft_expression_intensity_source = "disabled"
|
||||
primary_slot_context = None
|
||||
primary_slot = character_slot_map.get("Woman A")
|
||||
if primary_slot:
|
||||
primary_slot_context = _context_from_character_slot(
|
||||
soft_person_rng,
|
||||
primary_slot,
|
||||
"woman",
|
||||
ethnicity,
|
||||
figure,
|
||||
no_plus_women,
|
||||
no_black,
|
||||
)
|
||||
|
||||
soft_row = build_prompt(
|
||||
category=soft_category,
|
||||
subcategory=soft_subcategory,
|
||||
row_route = pair_rows.build_insta_pair_rows(
|
||||
row_number=row_number,
|
||||
start_index=start_index,
|
||||
seed=seed,
|
||||
clothing="minimal",
|
||||
active_trigger=active_trigger,
|
||||
parsed_seed_config=parsed_seed_config,
|
||||
options=options,
|
||||
ethnicity=ethnicity,
|
||||
poses="evocative",
|
||||
backside_bias=0.0,
|
||||
figure=figure,
|
||||
no_plus_women=no_plus_women,
|
||||
no_black=no_black,
|
||||
minimal_clothing_ratio=-1,
|
||||
standard_pose_ratio=-1,
|
||||
trigger=active_trigger,
|
||||
prepend_trigger_to_prompt=False,
|
||||
extra_positive="",
|
||||
extra_negative="",
|
||||
seed_config=parsed_seed_config,
|
||||
women_count=1,
|
||||
men_count=0,
|
||||
expression_enabled=soft_expression_enabled,
|
||||
expression_intensity=soft_expression_intensity,
|
||||
character_profile="" if primary_slot else character_profile or "",
|
||||
character_cast="",
|
||||
location_config=location_config or "",
|
||||
composition_config=composition_config or "",
|
||||
)
|
||||
soft_row["expression_intensity_source"] = soft_expression_intensity_source
|
||||
if primary_slot_context:
|
||||
soft_row = _apply_character_context_to_row(soft_row, primary_slot_context)
|
||||
soft_row["character_slot"] = primary_slot
|
||||
soft_row["character_slot_status"] = "applied:Woman A"
|
||||
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 _insta_of_softcore_outfit(soft_content_rng, softcore_level_key)
|
||||
soft_row["pose"] = _insta_of_softcore_pose(soft_content_rng, softcore_level_key)
|
||||
soft_row["item_label"] = "Insta/OF softcore body exposure" if softcore_level_key == "explicit_nude" else "Insta/OF softcore outfit"
|
||||
soft_row["softcore_item_prompt_label"] = _insta_of_softcore_item_prompt_label(softcore_level_key)
|
||||
soft_row["custom_item"] = "insta_of_softcore_outfit"
|
||||
soft_row["softcore_outfit_policy"] = "character_slot:Woman A" if primary_softcore_outfit else "insta_of_safe_softcore"
|
||||
if softcore_level_key == "explicit_nude":
|
||||
soft_row["source_scene_text"] = soft_row.get("source_scene_text") or soft_row.get("scene_text", "")
|
||||
soft_row["scene_text"] = _body_exposure_scene_text(soft_row.get("scene_text", ""))
|
||||
soft_row["pov_character_labels"] = (
|
||||
pov_character_labels
|
||||
if options["softcore_cast"] == "same_as_hardcore"
|
||||
else []
|
||||
)
|
||||
soft_row["pov_prompt_directive"] = _pov_prompt_directive(soft_row["pov_character_labels"])
|
||||
if soft_row["pov_character_labels"]:
|
||||
soft_row["source_composition"] = soft_row.get("source_composition") or soft_row.get("composition", "")
|
||||
soft_row["composition"] = _pov_composition_prompt(
|
||||
soft_row["source_composition"],
|
||||
soft_row["pov_character_labels"],
|
||||
)
|
||||
hard_row = build_prompt(
|
||||
category="Hardcore sexual poses",
|
||||
subcategory=RANDOM_SUBCATEGORY,
|
||||
row_number=row_number,
|
||||
start_index=start_index,
|
||||
seed=seed,
|
||||
clothing="minimal",
|
||||
ethnicity=ethnicity,
|
||||
poses="evocative",
|
||||
backside_bias=0.0,
|
||||
figure=figure,
|
||||
no_plus_women=no_plus_women,
|
||||
no_black=no_black,
|
||||
minimal_clothing_ratio=-1,
|
||||
standard_pose_ratio=-1,
|
||||
trigger=active_trigger,
|
||||
prepend_trigger_to_prompt=False,
|
||||
extra_positive="",
|
||||
extra_negative="",
|
||||
seed_config=parsed_seed_config,
|
||||
women_count=hard_women_count,
|
||||
men_count=hard_men_count,
|
||||
expression_enabled=options["hardcore_expression_enabled"],
|
||||
expression_intensity=options["hardcore_expression_intensity"],
|
||||
character_profile=character_profile,
|
||||
character_cast=character_cast or "",
|
||||
expression_phase="hardcore",
|
||||
hardcore_position_config=hardcore_position_config or "",
|
||||
character_slot_map=character_slot_map,
|
||||
pov_character_labels=pov_character_labels,
|
||||
hard_women_count=hard_women_count,
|
||||
hard_men_count=hard_men_count,
|
||||
soft_category=soft_category,
|
||||
soft_subcategory=soft_subcategory,
|
||||
softcore_level_key=softcore_level_key,
|
||||
hardcore_random_subcategory=RANDOM_SUBCATEGORY,
|
||||
hardcore_position_config=hardcore_position_config,
|
||||
location_config=location_config or "",
|
||||
composition_config=composition_config or "",
|
||||
build_prompt=build_prompt,
|
||||
axis_rng=_axis_rng,
|
||||
cast_expression_intensity_override=_cast_expression_intensity_override,
|
||||
context_from_character_slot=_context_from_character_slot,
|
||||
apply_character_context_to_row=_apply_character_context_to_row,
|
||||
disable_row_expression=_disable_row_expression,
|
||||
slot_softcore_outfit=_slot_softcore_outfit,
|
||||
softcore_outfit=_insta_of_softcore_outfit,
|
||||
softcore_pose=_insta_of_softcore_pose,
|
||||
softcore_item_prompt_label=_insta_of_softcore_item_prompt_label,
|
||||
body_exposure_scene_text=_body_exposure_scene_text,
|
||||
pov_prompt_directive=_pov_prompt_directive,
|
||||
pov_composition_prompt=_pov_composition_prompt,
|
||||
)
|
||||
hard_row["hardcore_detail_density"] = options["hardcore_detail_density"]
|
||||
hard_row["pov_character_labels"] = pov_character_labels
|
||||
hard_row["pov_prompt_directive"] = _pov_prompt_directive(pov_character_labels)
|
||||
soft_row = row_route["soft_row"]
|
||||
hard_row = row_route["hard_row"]
|
||||
hard_content_rng = row_route["hard_content_rng"]
|
||||
|
||||
descriptor = _insta_of_descriptor(soft_row)
|
||||
cast_descriptors = _insta_of_cast_descriptors(
|
||||
|
||||
Reference in New Issue
Block a user