from __future__ import annotations import re from dataclasses import dataclass from typing import Any, Callable @dataclass(frozen=True) class KreaNormalRowRequest: row: dict[str, Any] detail_level: str style_mode: str subject_type: str primary: str item: str scene: str pose: str expression: str composition: str camera: str camera_scene: str style: str @dataclass(frozen=True) class KreaNormalRowPrompt: prompt: str method: str def as_tuple(self) -> tuple[str, str]: return self.prompt, self.method @dataclass(frozen=True) class KreaNormalRowDependencies: clean: Callable[[Any], str] row_value: Callable[[dict[str, Any], str, tuple[str, ...]], str] age_subject: Callable[[dict[str, Any], str], str] age_detail_phrase: Callable[[Any], str] appearance_phrase: Callable[[dict[str, Any]], str] with_indefinite_article: Callable[[str], str] paragraph: Callable[[list[str]], str] def _couple_clothing_phrase(item: str, clean: Callable[[Any], str]) -> str: item = clean(item) lower = item.lower() partner_text = re.sub(r"\bPartner ([AB]) wears\b", r"Partner \1 wearing", item) partner_text = re.sub(r"\bPartner ([AB]) has\b", r"Partner \1 with", partner_text) if lower.startswith("partner a "): return f"The outfits show {partner_text}" if lower.startswith(("two ", "paired ", "coordinated ")): return f"The outfits are {partner_text}" return f"The couple wears {item}" def _cap_first(text: str) -> str: text = str(text or "").strip() return f"{text[:1].upper()}{text[1:]}" if text else "" def _couple_subject_phrase(subject: str, ages: str) -> str: subject = _cap_first(subject or "adult couple") ages = str(ages or "").strip() if ages: return f"{subject}, {ages}" return subject def format_normal_row_result( request: KreaNormalRowRequest, deps: KreaNormalRowDependencies, ) -> KreaNormalRowPrompt: row = request.row subject_type = request.subject_type primary = request.primary item = request.item scene = request.scene pose = request.pose expression = request.expression composition = request.composition camera = request.camera camera_scene = request.camera_scene style = request.style detail_level = request.detail_level if primary in ("woman", "man") or subject_type in ("woman", "man", "single_any"): subject = deps.age_subject(row, "adult woman") appearance = deps.appearance_phrase(row) parts = [ deps.with_indefinite_article(subject), f"with {appearance}" if appearance else "", f"wearing {item}" if item else "", f"{pose}" if pose else "", f"with {expression}" if expression else "", f"in {scene}" if scene else "", camera_scene, f"framed as {composition}" if composition else "", camera, style if detail_level != "concise" else "", ] return KreaNormalRowPrompt( deps.paragraph([", ".join(part for part in parts[:6] if part), *parts[6:]]), "metadata(single)", ) if subject_type == "couple" or primary in ("two women", "two men", "a woman and a man"): subject = deps.clean(row.get("subject_phrase") or primary or "adult couple") if subject == "woman and man": subject = "a woman and a man" ages = deps.age_detail_phrase(deps.row_value(row, "age", ("Ages",)) or row.get("age_band")) body = deps.row_value(row, "body", ("Body types",)) or deps.clean(row.get("body_type")) parts = [ _couple_subject_phrase(subject, ages), f"Body types: {body}" if body else "", _couple_clothing_phrase(item, deps.clean) if item else "", f"The pose is {pose}" if pose else "", f"The setting is {scene}" if scene else "", camera_scene, f"Facial expressions are {expression}" if expression else "", f"The image is framed as {composition}" if composition else "", camera, style if detail_level != "concise" else "", ] return KreaNormalRowPrompt(deps.paragraph(parts), "metadata(couple)") subject = deps.age_subject(row, primary or "adult scene") parts = [ f"{subject}", f"featuring {item}" if item else "", f"in {scene}" if scene else "", camera_scene, f"with {expression}" if expression else "", f"framed as {composition}" if composition else "", camera, style if detail_level != "concise" else "", ] return KreaNormalRowPrompt(deps.paragraph(parts), "metadata(generic)") def format_normal_row( request: KreaNormalRowRequest, deps: KreaNormalRowDependencies, ) -> tuple[str, str]: return format_normal_row_result(request, deps).as_tuple()