Add hardcore action family metadata

This commit is contained in:
2026-06-26 16:38:25 +02:00
parent 0e49aed8ac
commit 8668dfec9d
8 changed files with 237 additions and 60 deletions
+101
View File
@@ -0,0 +1,101 @@
from __future__ import annotations
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,
)
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,
)
ACTION_CLIMAX = "climax"
ACTION_FOREPLAY = "foreplay"
ACTION_OUTERCOURSE = "outercourse"
ACTION_ORAL = "oral"
ACTION_PENETRATION = "penetration"
ACTION_TOY_DOUBLE = "toy_double"
ACTION_DEFAULT = "default"
HARDCORE_ACTION_FAMILY_CHOICES = {
ACTION_CLIMAX,
ACTION_FOREPLAY,
ACTION_OUTERCOURSE,
ACTION_ORAL,
ACTION_PENETRATION,
ACTION_TOY_DOUBLE,
ACTION_DEFAULT,
}
def normalize_hardcore_action_family(value: Any, default: str = "") -> str:
text = str(value or "").strip().lower()
if text == "penetrative":
text = ACTION_PENETRATION
return text if text in HARDCORE_ACTION_FAMILY_CHOICES else default
def infer_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 source_hardcore_action_family(
source_family: Any,
role_graph: str,
hard_item: str,
composition: str = "",
axis_values: Any = None,
) -> str:
inferred = infer_hardcore_action_family(role_graph, hard_item, composition, axis_values)
if inferred in (ACTION_CLIMAX, ACTION_TOY_DOUBLE):
return inferred
family = str(source_family or "").strip().lower()
source_mapping = {
"penetrative": ACTION_PENETRATION,
"foreplay": ACTION_FOREPLAY,
"interaction": ACTION_FOREPLAY,
"manual": ACTION_FOREPLAY,
"oral": ACTION_ORAL,
"outercourse": ACTION_OUTERCOURSE,
"climax": ACTION_CLIMAX,
}
if family == "anal":
return ACTION_DEFAULT
return source_mapping.get(family, inferred)