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

223 lines
10 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Callable
@dataclass(frozen=True)
class KreaPairFormatRequest:
row: dict[str, Any]
detail_level: str
style_mode: str
@dataclass(frozen=True)
class KreaPairPrompts:
soft_prompt: str
soft_negative: str
hard_prompt: str
hard_negative: str
def as_tuple(self) -> tuple[str, str, str, str]:
return self.soft_prompt, self.soft_negative, self.hard_prompt, self.hard_negative
@dataclass(frozen=True)
class KreaPairFormatDependencies:
clean: Callable[[Any], str]
prompt_cast_descriptors: Callable[[str], str]
pair_camera_phrase: Callable[[Any, Any, dict[str, Any]], str]
camera_scene_phrase: Callable[[dict[str, Any]], str]
style_phrase: Callable[[dict[str, Any], str], str]
sanitize_hardcore_environment_anchors: Callable[[Any], str]
sanitize_hardcore_axis_values: Callable[[Any], Any]
sanitize_scene_text_for_cast: Callable[[Any, list[str]], str]
normalize_hardcore_detail_density: Callable[[Any], str]
row_action_family: Callable[[Any], str]
hardcore_action_sentence: Callable[[str, str, str, Any, str, str], str]
pov_action_phrase: Callable[[str, list[str], str, str, str, Any, str], str]
pov_labels_from_value: Callable[[Any], list[str]]
merge_labels: Callable[..., list[str]]
cast_prose_omit: Callable[[str, list[str]], tuple[str, list[str]]]
label_join: Callable[[list[str]], str]
filter_pov_labeled_clauses: Callable[[Any, list[str]], str]
natural_label_text: Callable[[Any, list[str]], str]
expression_disabled: Callable[[dict[str, Any]], bool]
expression_phrase: Callable[[Any], str]
pov_camera_phrase: Callable[[list[str]], str]
pov_soft_camera_phrase: Callable[[list[str]], str]
pov_composition_text: Callable[[Any, list[str]], str]
softcore_cast_presence_phrase: Callable[..., str]
natural_clothing_state: Callable[[Any, str], str]
composition_phrase: Callable[..., str]
paragraph: Callable[[list[str]], str]
combine_negative: Callable[..., str]
def format_insta_pair_result(request: KreaPairFormatRequest, deps: KreaPairFormatDependencies) -> KreaPairPrompts:
row = request.row
detail_level = request.detail_level
style_mode = request.style_mode
descriptor = deps.clean(row.get("shared_descriptor"))
cast_descriptors = row.get("shared_cast_descriptors")
if isinstance(cast_descriptors, list):
cast_descriptor_text = "; ".join(deps.clean(item) for item in cast_descriptors if deps.clean(item))
else:
cast_descriptor_text = deps.clean(cast_descriptors)
cast_descriptor_text = deps.prompt_cast_descriptors(cast_descriptor_text)
soft = row.get("softcore_row") if isinstance(row.get("softcore_row"), dict) else {}
hard = row.get("hardcore_row") if isinstance(row.get("hardcore_row"), dict) else {}
soft_camera = deps.pair_camera_phrase(row.get("softcore_camera_directive"), row.get("softcore_camera_config"), soft)
hard_camera = deps.pair_camera_phrase(row.get("hardcore_camera_directive"), row.get("hardcore_camera_config"), hard)
soft_camera_scene = deps.camera_scene_phrase(soft) or deps.clean(row.get("softcore_camera_scene_directive"))
hard_camera_scene = deps.camera_scene_phrase(hard) or deps.clean(row.get("hardcore_camera_scene_directive"))
soft_style = deps.style_phrase(soft, style_mode)
hard_style = deps.style_phrase(hard, style_mode)
options = row.get("options") if isinstance(row.get("options"), dict) else {}
soft_level = deps.clean(options.get("softcore_level")).replace("_", " ")
hard_level = deps.clean(options.get("hardcore_level")).replace("_", " ")
same_room = options.get("continuity") == "same_creator_same_room"
hard_scene = hard.get("scene_text") or (soft.get("scene_text") if same_room else "")
hard_composition = deps.sanitize_hardcore_environment_anchors(hard.get("composition"))
hard_source_composition = deps.sanitize_hardcore_environment_anchors(hard.get("source_composition") or hard_composition)
pov_labels = deps.merge_labels(
deps.pov_labels_from_value(row.get("pov_character_labels")),
deps.pov_labels_from_value(soft.get("pov_character_labels")),
deps.pov_labels_from_value(hard.get("pov_character_labels")),
)
if pov_labels:
hard_camera = ""
if options.get("softcore_cast") == "same_as_hardcore":
soft_camera = ""
soft_cast_descriptor_text = (
cast_descriptor_text
if options.get("softcore_cast") == "same_as_hardcore"
else f"Woman A: {descriptor}"
)
soft_cast_prose, soft_labels = deps.cast_prose_omit(
soft_cast_descriptor_text,
pov_labels if options.get("softcore_cast") == "same_as_hardcore" else [],
)
hard_cast_prose, hard_labels = deps.cast_prose_omit(cast_descriptor_text, pov_labels)
soft_labels = deps.merge_labels(soft_labels, pov_labels if options.get("softcore_cast") == "same_as_hardcore" else [])
hard_labels = deps.merge_labels(hard_labels, pov_labels)
hard_item = deps.sanitize_scene_text_for_cast(
deps.sanitize_hardcore_environment_anchors(hard.get("item")),
hard_labels,
)
hard_role_graph = deps.sanitize_scene_text_for_cast(
deps.sanitize_hardcore_environment_anchors(hard.get("source_role_graph") or hard.get("role_graph")),
hard_labels,
)
hard_item = deps.natural_label_text(hard_item, hard_labels)
hard_role_graph = deps.natural_label_text(hard_role_graph, hard_labels)
hard_axis_values = deps.sanitize_hardcore_axis_values(hard.get("item_axis_values"))
hard_detail_density = deps.normalize_hardcore_detail_density(
hard.get("hardcore_detail_density") or row.get("hardcore_detail_density") or options.get("hardcore_detail_density")
)
hard_action = deps.hardcore_action_sentence(
hard_role_graph,
hard_item,
hard_source_composition,
hard_axis_values,
hard_detail_density,
deps.row_action_family(hard) or deps.row_action_family(row),
)
hard_action = deps.pov_action_phrase(
hard_action,
pov_labels,
hard_role_graph,
hard_item,
hard_source_composition,
hard_axis_values,
hard_detail_density,
)
hard_output_composition = deps.pov_composition_text(hard_composition, pov_labels)
same_soft_cast = options.get("softcore_cast") == "same_as_hardcore"
soft_output_composition = deps.pov_composition_text(soft.get("composition"), pov_labels if same_soft_cast else [])
soft_cast_presence = deps.softcore_cast_presence_phrase(
same_cast=same_soft_cast,
pov_labels=pov_labels if same_soft_cast else [],
cast_label=deps.label_join(soft_labels),
woman_label="the woman",
)
partner_styling = row.get("softcore_partner_styling")
if isinstance(partner_styling, dict):
outfits = partner_styling.get("outfits")
partner_outfit_text = "; ".join(deps.clean(item) for item in outfits if deps.clean(item)) if isinstance(outfits, list) else ""
partner_pose = deps.clean(partner_styling.get("pose"))
else:
partner_outfit_text = ""
partner_pose = ""
partner_outfit_text = deps.filter_pov_labeled_clauses(partner_outfit_text, pov_labels)
if pov_labels:
partner_pose = ""
partner_outfit_text = deps.natural_label_text(partner_outfit_text, soft_labels)
soft_expression = ""
if not deps.expression_disabled(soft):
soft_expression_source = deps.filter_pov_labeled_clauses(
deps.clean(soft.get("character_expression_text")) or deps.clean(soft.get("expression")),
pov_labels,
)
soft_expression = deps.natural_label_text(
soft_expression_source,
soft_labels,
)
hard_expression = ""
if not deps.expression_disabled(hard):
hard_expression_source = deps.filter_pov_labeled_clauses(
deps.clean(hard.get("character_expression_text")) or deps.clean(hard.get("expression")),
pov_labels,
)
hard_expression = deps.natural_label_text(
hard_expression_source,
hard_labels,
)
soft_item = deps.clean(soft.get("item"))
soft_item_label = deps.clean(soft.get("softcore_item_prompt_label"))
soft_item_phrase = ""
if soft_item:
soft_item_phrase = f"body exposure: {soft_item}" if soft_item_label == "Body exposure" else f"wearing {soft_item}"
soft_parts = [
soft_cast_prose,
soft_cast_presence,
partner_outfit_text,
partner_pose,
deps.pov_soft_camera_phrase(pov_labels) if same_soft_cast else "",
soft_item_phrase,
f"{soft.get('pose')}" if soft.get("pose") else "",
deps.expression_phrase(soft_expression),
f"in {soft.get('scene_text')}" if soft.get("scene_text") else "",
soft_camera_scene,
deps.composition_phrase(soft_output_composition),
soft_camera,
soft_style if detail_level != "concise" else "",
]
hard_parts = [
hard_cast_prose,
hard_action,
deps.pov_camera_phrase(pov_labels),
deps.natural_label_text(
deps.filter_pov_labeled_clauses(deps.natural_clothing_state(row.get("hardcore_clothing_state"), hard_action), pov_labels),
hard_labels,
),
f"set in {hard_scene}" if hard_scene else "",
hard_camera_scene,
deps.expression_phrase(hard_expression),
deps.composition_phrase(hard_output_composition, hard_action, detail_density=hard_detail_density),
hard_camera,
hard_style if detail_level != "concise" else "",
]
return KreaPairPrompts(
soft_prompt=deps.paragraph(soft_parts),
soft_negative=deps.combine_negative(row.get("softcore_negative_prompt")),
hard_prompt=deps.paragraph(hard_parts),
hard_negative=deps.combine_negative(row.get("hardcore_negative_prompt")),
)
def format_insta_pair(request: KreaPairFormatRequest, deps: KreaPairFormatDependencies) -> tuple[str, str, str, str]:
return format_insta_pair_result(request, deps).as_tuple()