303 lines
12 KiB
Python
303 lines
12 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any, Callable
|
|
|
|
try:
|
|
from . import pair_clothing
|
|
except ImportError: # Allows local smoke tests with top-level imports.
|
|
import pair_clothing
|
|
|
|
|
|
BuildPrompt = Callable[..., dict[str, Any]]
|
|
AxisRng = Callable[[dict[str, int], str, int, int], Any]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class InstaPairRowsRoute:
|
|
soft_row: dict[str, Any]
|
|
hard_row: dict[str, Any]
|
|
hard_content_rng: Any
|
|
|
|
def as_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"soft_row": self.soft_row,
|
|
"hard_row": self.hard_row,
|
|
"hard_content_rng": self.hard_content_rng,
|
|
}
|
|
|
|
|
|
def build_insta_pair_rows_result(
|
|
*,
|
|
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],
|
|
pov_prompt_directive: Callable[[list[str]], str],
|
|
pov_composition_prompt: Callable[[Any, list[str]], str],
|
|
parsed_softcore_seed_config: dict[str, int] | None = None,
|
|
parsed_hardcore_seed_config: dict[str, int] | None = None,
|
|
style_config: str | dict[str, Any] | None = "",
|
|
) -> InstaPairRowsRoute:
|
|
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_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)
|
|
|
|
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=soft_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 "",
|
|
style_config=style_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_pose_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"] = pair_clothing.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=hard_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 "",
|
|
style_config=style_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 InstaPairRowsRoute(
|
|
soft_row=soft_row,
|
|
hard_row=hard_row,
|
|
hard_content_rng=hard_content_rng,
|
|
)
|
|
|
|
|
|
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],
|
|
pov_prompt_directive: Callable[[list[str]], str],
|
|
pov_composition_prompt: Callable[[Any, list[str]], str],
|
|
parsed_softcore_seed_config: dict[str, int] | None = None,
|
|
parsed_hardcore_seed_config: dict[str, int] | None = None,
|
|
style_config: str | dict[str, Any] | None = "",
|
|
) -> dict[str, Any]:
|
|
return build_insta_pair_rows_result(
|
|
row_number=row_number,
|
|
start_index=start_index,
|
|
seed=seed,
|
|
active_trigger=active_trigger,
|
|
parsed_seed_config=parsed_seed_config,
|
|
parsed_softcore_seed_config=parsed_softcore_seed_config,
|
|
parsed_hardcore_seed_config=parsed_hardcore_seed_config,
|
|
options=options,
|
|
ethnicity=ethnicity,
|
|
figure=figure,
|
|
no_plus_women=no_plus_women,
|
|
no_black=no_black,
|
|
character_profile=character_profile,
|
|
character_cast=character_cast,
|
|
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=hardcore_random_subcategory,
|
|
hardcore_position_config=hardcore_position_config,
|
|
location_config=location_config,
|
|
composition_config=composition_config,
|
|
style_config=style_config,
|
|
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=softcore_outfit,
|
|
softcore_pose=softcore_pose,
|
|
softcore_item_prompt_label=softcore_item_prompt_label,
|
|
pov_prompt_directive=pov_prompt_directive,
|
|
pov_composition_prompt=pov_composition_prompt,
|
|
).as_dict()
|