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
+74
View File
@@ -15,6 +15,7 @@ try:
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors,
)
from .hardcore_action_metadata import source_hardcore_action_family
from .prompt_hygiene import (
sanitize_caption_text,
sanitize_negative_text,
@@ -27,6 +28,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors,
)
from hardcore_action_metadata import source_hardcore_action_family
from prompt_hygiene import (
sanitize_caption_text,
sanitize_negative_text,
@@ -490,6 +492,49 @@ HARDCORE_POSITION_AXIS_KEYS = {
"aftercare_act",
"cleanup_detail",
}
HARDCORE_SOURCE_FAMILY_BY_SUBCATEGORY = {
"penetrative_sex": "penetrative",
"foreplay_teasing": "foreplay",
"body_worship_touching": "interaction",
"clothing_position_transitions": "interaction",
"dominant_guidance": "interaction",
"camera_performance": "interaction",
"manual_stimulation": "manual",
"oral_sex": "oral",
"outercourse_sex": "outercourse",
"anal_double_penetration": "anal",
"threesomes": "threesome",
"group_coordination": "interaction",
"group_sex_orgy": "group",
"cumshot_climax": "climax",
"aftercare_cleanup": "interaction",
}
def _hardcore_source_position_family(subcategory: dict[str, Any], config: dict[str, Any] | None = None) -> str:
slug = str(subcategory.get("slug") or subcategory.get("name") or "").strip().lower()
family = HARDCORE_SOURCE_FAMILY_BY_SUBCATEGORY.get(slug, "")
if family:
return family
config_family = _normalize_hardcore_position_family((config or {}).get("family"), "")
return "" if config_family == "any" else config_family
def _hardcore_position_keys(*parts: Any, axis_values: dict[str, Any] | None = None) -> list[str]:
text_parts = [str(part or "") for part in parts if str(part or "").strip()]
if isinstance(axis_values, dict):
text_parts.extend(str(value or "") for value in axis_values.values() if str(value or "").strip())
text = " ".join(text_parts).lower()
if not text:
return []
keys: list[str] = []
for key, tokens in HARDCORE_POSITION_KEY_MATCHES.items():
if any(token in text for token in tokens):
keys.append(key)
return keys
CAMERA_ORBIT_FRAMING_CHOICES = [
"from_zoom",
"wide",
@@ -7055,6 +7100,27 @@ def _build_custom_row(
if is_pose_category:
source_composition = _sanitize_hardcore_environment_anchors(source_composition)
composition = _pov_composition_prompt(source_composition, pov_character_labels)
position_family = ""
position_keys: list[str] = []
position_key = ""
action_family = ""
if is_pose_category:
position_family = _hardcore_source_position_family(subcategory, parsed_hardcore_position_config)
position_keys = _hardcore_position_keys(
item_text,
source_role_graph,
source_composition,
pose,
axis_values=item_axis_values,
)
position_key = position_keys[0] if position_keys else ""
action_family = source_hardcore_action_family(
position_family,
source_role_graph,
item_text,
source_composition,
item_axis_values,
)
negative_prompt = str(_merged_field(category, subcategory, item, "negative_prompt", g.NEGATIVE_PROMPT))
positive_suffix = str(_merged_field(category, subcategory, item, "positive_suffix", GENERIC_POSITIVE_SUFFIX))
@@ -7096,6 +7162,10 @@ def _build_custom_row(
"composition_config": parsed_composition_config if _composition_config_active(parsed_composition_config) else {},
"role_graph": role_graph,
"source_role_graph": source_role_graph,
"action_family": action_family,
"position_family": position_family,
"position_key": position_key,
"position_keys": position_keys,
"pov_character_labels": pov_character_labels,
"pov_prompt_directive": _pov_prompt_directive(pov_character_labels),
"cast_descriptors": cast_descriptor_text,
@@ -7170,6 +7240,10 @@ def _build_custom_row(
"content_seed_axis": content_axis,
"role_graph": role_graph,
"source_role_graph": source_role_graph,
"action_family": action_family,
"position_family": position_family,
"position_key": position_key,
"position_keys": position_keys,
"source_composition": source_composition,
"pov_character_labels": pov_character_labels,
"pov_prompt_directive": _pov_prompt_directive(pov_character_labels),