Files
ComfyUI-Ethanfel-Prompt-Bui…/krea_action_dispatch.py
T

210 lines
7.1 KiB
Python

from __future__ import annotations
import re
from dataclasses import dataclass
from typing import Any
try:
from .krea_action_context import (
axis_values_text,
is_climax_text,
is_toy_assisted_double_text,
normalize_hardcore_detail_density,
)
from .hardcore_action_metadata import (
ACTION_CLIMAX,
ACTION_FOREPLAY,
ACTION_ORAL,
ACTION_OUTERCOURSE,
ACTION_PENETRATION,
ACTION_TOY_DOUBLE,
infer_hardcore_action_family,
normalize_hardcore_action_family,
)
from .krea_detail import limit_detail_for_density
from .krea_action_positions import hardcore_pose_anchor
from .krea_action_details import (
dedupe_anchor_detail,
dedupe_oral_detail,
dedupe_outercourse_detail,
dedupe_penetration_detail,
dedupe_toy_double_detail,
hardcore_item_detail,
sanitize_foreplay_detail,
)
from .krea_action_climax import climax_role_graph, dedupe_climax_detail
except ImportError: # Allows local smoke tests with `python -c`.
from krea_action_context import (
axis_values_text,
is_climax_text,
is_toy_assisted_double_text,
normalize_hardcore_detail_density,
)
from hardcore_action_metadata import (
ACTION_CLIMAX,
ACTION_FOREPLAY,
ACTION_ORAL,
ACTION_OUTERCOURSE,
ACTION_PENETRATION,
ACTION_TOY_DOUBLE,
infer_hardcore_action_family,
normalize_hardcore_action_family,
)
from krea_detail import limit_detail_for_density
from krea_action_positions import hardcore_pose_anchor
from krea_action_details import (
dedupe_anchor_detail,
dedupe_oral_detail,
dedupe_outercourse_detail,
dedupe_penetration_detail,
dedupe_toy_double_detail,
hardcore_item_detail,
sanitize_foreplay_detail,
)
from krea_action_climax import climax_role_graph, dedupe_climax_detail
@dataclass(frozen=True)
class HardcoreActionParts:
family: str
role_graph: str
hard_item: str
detail: str
anchor: str
detail_density: str
def _clean(value: Any) -> str:
text = "" if value is None else str(value)
text = text.replace("\n", " ")
text = re.sub(r"\s+", " ", text).strip()
text = re.sub(r"\s+([,.;:])", r"\1", text)
return text
def normalize_hardcore_role_graph(role_graph: str) -> str:
role_graph = _clean(role_graph).rstrip(".")
replacements = (
(
r"\bthe man penetrates the woman while a toy adds a second point of contact\b",
"the man's penis thrusts into the woman while a toy is positioned at the second penetration point",
),
(
r"\bthe man thrusts his penis into the woman while a toy adds a second penetration point\b",
"the man's penis thrusts into the woman while a toy is positioned at the second penetration point",
),
(
r"\bthe man thrusts his penis into the woman\b",
"the man's penis thrusts into the woman",
),
(
r"\bthe man penetrates the woman anally\b",
"the man's penis thrusts into the woman's ass",
),
(
r"\bthe man thrusts his penis into the woman's ass\b",
"the man's penis thrusts into the woman's ass",
),
(
r"\bthe man penetrates the woman\b",
"the man's penis thrusts into the woman",
),
(
r"\bthe woman and the man are in mutual oral contact with mouth-to-genital contact visible\b",
"the woman has the man's penis in her mouth while the man uses his mouth on her pussy",
),
(
r"\bthe woman gives oral to the man\b",
"the woman takes the man's penis in her mouth",
),
)
for pattern, replacement in replacements:
role_graph = re.sub(pattern, replacement, role_graph, flags=re.IGNORECASE)
return role_graph
def normalize_toy_double_role_graph(role_graph: str) -> str:
return re.sub(
r"\s+while a toy adds (?:the|a) second penetration point\b",
" while a toy is positioned at the second penetration point",
role_graph,
flags=re.IGNORECASE,
)
def action_detail_for_family(
family: str,
detail: str,
role_graph: str,
hard_item: str,
composition: str = "",
axis_values: Any = None,
*,
anchor: str = "",
detail_density: str = "balanced",
) -> tuple[str, str]:
if family == ACTION_CLIMAX:
return "", dedupe_climax_detail(detail, role_graph, detail_density)
if family == ACTION_FOREPLAY:
detail = sanitize_foreplay_detail(detail, role_graph, composition)
return "", limit_detail_for_density(detail, detail_density, False)
if family == ACTION_OUTERCOURSE:
detail = dedupe_outercourse_detail(detail, role_graph, hard_item, axis_values)
return "", limit_detail_for_density(detail, detail_density, False)
if family == ACTION_ORAL and role_graph:
detail = dedupe_oral_detail(detail, role_graph, hard_item, axis_values)
return "", limit_detail_for_density(detail, detail_density, False)
if family == ACTION_PENETRATION and role_graph:
detail = dedupe_penetration_detail(detail, role_graph, hard_item, axis_values)
return "", limit_detail_for_density(detail, detail_density, False)
if anchor:
detail = dedupe_anchor_detail(detail, anchor)
if family == ACTION_TOY_DOUBLE:
detail = dedupe_toy_double_detail(detail)
return anchor, limit_detail_for_density(detail, detail_density, False)
def resolve_hardcore_action_parts(
role_graph: str,
hard_item: str,
composition: str = "",
axis_values: Any = None,
detail_density: str = "balanced",
action_family: Any = "",
) -> HardcoreActionParts:
detail_density = normalize_hardcore_detail_density(detail_density)
role_graph = normalize_hardcore_role_graph(role_graph)
hard_item = _clean(hard_item).rstrip(".")
axis_text = axis_values_text(axis_values)
forced_family = normalize_hardcore_action_family(action_family)
is_climax = forced_family == ACTION_CLIMAX or is_climax_text(role_graph, hard_item, composition, axis_text)
if is_climax:
role_graph = climax_role_graph(role_graph, hard_item, axis_values)
detail = hardcore_item_detail(hard_item)
anchor = hardcore_pose_anchor(role_graph, hard_item, composition, axis_values)
family = forced_family or infer_hardcore_action_family(role_graph, hard_item, composition, axis_values, is_climax=is_climax)
if is_toy_assisted_double_text(role_graph, hard_item, composition, axis_text):
role_graph = normalize_toy_double_role_graph(role_graph)
anchor, detail = action_detail_for_family(
family,
detail,
role_graph,
hard_item,
composition,
axis_values,
anchor=anchor,
detail_density=detail_density,
)
return HardcoreActionParts(
family=family,
role_graph=role_graph,
hard_item=hard_item,
detail=detail,
anchor=anchor,
detail_density=detail_density,
)