Extract Krea action family dispatch
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
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_foreplay_text,
|
||||
is_oral_text,
|
||||
is_outercourse_text,
|
||||
is_toy_assisted_double_text,
|
||||
is_vaginal_penetration_text,
|
||||
normalize_hardcore_detail_density,
|
||||
)
|
||||
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_foreplay_text,
|
||||
is_oral_text,
|
||||
is_outercourse_text,
|
||||
is_toy_assisted_double_text,
|
||||
is_vaginal_penetration_text,
|
||||
normalize_hardcore_detail_density,
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
ACTION_CLIMAX = "climax"
|
||||
ACTION_FOREPLAY = "foreplay"
|
||||
ACTION_OUTERCOURSE = "outercourse"
|
||||
ACTION_ORAL = "oral"
|
||||
ACTION_PENETRATION = "penetration"
|
||||
ACTION_TOY_DOUBLE = "toy_double"
|
||||
ACTION_DEFAULT = "default"
|
||||
|
||||
|
||||
@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 hardcore_action_family(
|
||||
role_graph: str,
|
||||
hard_item: str,
|
||||
composition: str = "",
|
||||
axis_values: Any = None,
|
||||
*,
|
||||
is_climax: bool | None = None,
|
||||
) -> str:
|
||||
axis_text = axis_values_text(axis_values)
|
||||
if is_climax is None:
|
||||
is_climax = is_climax_text(role_graph, hard_item, composition, axis_text)
|
||||
if is_climax:
|
||||
return ACTION_CLIMAX
|
||||
if is_foreplay_text(role_graph, hard_item, composition, axis_text):
|
||||
return ACTION_FOREPLAY
|
||||
if is_outercourse_text(role_graph, hard_item, composition, axis_text):
|
||||
return ACTION_OUTERCOURSE
|
||||
if is_oral_text(role_graph, hard_item, composition, axis_text):
|
||||
return ACTION_ORAL
|
||||
if is_vaginal_penetration_text(role_graph, hard_item, composition, axis_text):
|
||||
return ACTION_PENETRATION
|
||||
if is_toy_assisted_double_text(role_graph, hard_item, composition, axis_text):
|
||||
return ACTION_TOY_DOUBLE
|
||||
return ACTION_DEFAULT
|
||||
|
||||
|
||||
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",
|
||||
) -> 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)
|
||||
is_climax = 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 = 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,
|
||||
)
|
||||
Reference in New Issue
Block a user