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 _framed_composition_phrase(composition: str, prefix: str = "framed as") -> str: composition = re.sub(r"\s+composition$", "", str(composition or "").strip(), flags=re.IGNORECASE) composition = re.sub( r"\bcomposition\b", "frame", composition, flags=re.IGNORECASE, ).strip(" ,") if not composition: return "" return f"{prefix} {composition}" def _appearance_with_phrase(appearance: str, with_indefinite_article: Callable[[str], str]) -> str: appearance = str(appearance or "").strip() if not appearance: return "" first_clause = appearance.split(",", 1)[0].lower() if re.search(r"\b(?:body|build|figure|frame|physique|silhouette)\b", first_clause): nested_shape = re.match( r"^(.+\b(?:body|build|figure|frame|physique|silhouette))\s+with\s+(.+?)(?=,\s+[^,]*(?:skin|hair|eyes)\b|$)(.*)$", appearance, flags=re.IGNORECASE, ) if nested_shape: shape = with_indefinite_article(nested_shape.group(1).strip()) detail = nested_shape.group(2).strip() rest = nested_shape.group(3).strip() return f"with {shape} defined by {detail}{rest}" appearance = with_indefinite_article(appearance) return f"with {appearance}" 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) subject_phrase = deps.with_indefinite_article(subject) appearance_phrase = _appearance_with_phrase(appearance, deps.with_indefinite_article) if appearance_phrase: subject_phrase = f"{subject_phrase} {appearance_phrase}" parts = [ subject_phrase, 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, _framed_composition_phrase(composition), camera, style if detail_level != "concise" else "", ] return KreaNormalRowPrompt( deps.paragraph([", ".join(part for part in parts[:5] if part), *parts[5:]]), "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 "", _framed_composition_phrase(composition, "The image is framed as"), 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 "", _framed_composition_phrase(composition), 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()