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

76 lines
3.7 KiB
Python

from __future__ import annotations
import re
from typing import Any
try:
from .krea_cast import natural_label_text
except ImportError: # Allows local smoke tests with `python -c`.
from krea_cast import natural_label_text
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 clothing_access_phrase(action_text: Any) -> str:
text = _clean(action_text).lower()
if any(term in text for term in ("cumshot", "ejaculat", "semen", "cum on", "cum across", "post-orgasm", "aftermath")):
return "leaving the body exposed for visible semen and aftermath"
if any(term in text for term in ("boobjob", "titjob", "breast sex", "handjob", "hand job", "footjob", "testicle", "balls", "penis licking", "non-penetrative")):
return "leaving the contact point unobstructed"
if any(term in text for term in ("oral", "blowjob", "fellatio", "mouth", "tongue")):
return "leaving the oral contact unobstructed"
if any(term in text for term in ("penetrat", "thrust", "penis entering", "vaginal", "anal")):
return "leaving the penetration point unobstructed"
return "leaving skin and body contact readable"
def natural_clothing_state(text: Any, action_text: Any = "") -> str:
text = _clean(text)
if not text:
return ""
text = re.sub(r"^Clothing state:\s*", "", text, flags=re.IGNORECASE)
if re.search(r";\s*(?=(?:Woman|Man) [A-Z]\b)", text):
parts = [
natural_clothing_state(part, action_text).rstrip(".")
for part in re.split(r";\s*(?=(?:Woman|Man) [A-Z]\b)", text)
if _clean(part)
]
return ". ".join(part for part in parts if part)
body_exposure = re.match(r"^Body exposure:\s*(.*?)\.?$", text, flags=re.IGNORECASE)
if body_exposure:
return _clean(body_exposure.group(1)).rstrip(".")
if re.search(r"\bfully nude\b|\bbody is fully exposed\b|\bno clothing covering\b", text, flags=re.IGNORECASE):
owner = "the woman"
owner_match = re.match(r"^\s*((?:Woman|Man) [A-Z])\b", text)
if owner_match:
owner = natural_label_text(owner_match.group(1), ["Woman A", "Man A"]) or owner
return f"{owner.capitalize()}'s body is fully exposed, bare skin unobstructed"
match = re.match(
r"^(.*?)\b(?:softcore|teaser) outfit is (.*?)(?: for the (?:hardcore|sex) scene)?;\s*(?:softcore visual reference|teaser outfit detail):\s*(.*?)\.?$",
text,
flags=re.IGNORECASE,
)
if match:
owner = natural_label_text(match.group(1).strip(" 's"), ["Woman A", "Man A"]).strip() or "the woman"
state = _clean(match.group(2)).lower()
outfit = _clean(match.group(3)).rstrip(".")
if "fully nude" in state or "fully exposed" in state or "no clothing covering" in state:
return f"{owner.capitalize()}'s body is fully exposed, bare skin unobstructed"
if "nude-adjacent" in state:
return f"{owner.capitalize()}'s body is partly exposed"
if "partially removed" in state or "pushed aside" in state:
return f"{owner.capitalize()}'s {outfit} is pushed aside or partly removed where needed, {clothing_access_phrase(action_text)}"
if "keeps" in state:
return f"{owner.capitalize()} keeps the {outfit} on while {clothing_access_phrase(action_text)}"
text = re.sub(r";\s*(?:softcore visual reference|teaser outfit detail):\s*", ". Visual clothing state: ", text, flags=re.IGNORECASE)
text = text.replace("softcore outfit", "outfit")
text = text.replace("teaser outfit", "outfit")
text = text.replace("hardcore scene", "sex scene")
return text