from __future__ import annotations from dataclasses import dataclass from typing import Any, Callable CameraConfigWithMode = Callable[[str | dict[str, Any] | None, str], dict[str, Any]] CameraDirective = Callable[[str | dict[str, Any] | None], tuple[str, dict[str, Any]]] ApplyComposition = Callable[[dict[str, Any], str], dict[str, Any]] CompositionPrompt = Callable[[Any, Any, str], str] CameraSceneDirective = Callable[ [Any, Any, str | dict[str, Any] | None, list[str] | None, str], tuple[str, dict[str, Any]], ] def camera_config_with_detail( camera_config: dict[str, Any], camera_detail: str, camera_detail_choices: list[str] | tuple[str, ...], ) -> dict[str, Any]: if camera_detail in camera_detail_choices: camera_config["camera_detail"] = camera_detail return camera_config def softcore_subject_kind(softcore_cast: Any, hard_women_count: int, hard_men_count: int) -> str: if str(softcore_cast) == "solo": return "woman" total = int(hard_women_count or 0) + int(hard_men_count or 0) if total == 2: return "couple" return "subjects" def hardcore_subject_kind(hard_women_count: int, hard_men_count: int) -> str: total = int(hard_women_count or 0) + int(hard_men_count or 0) if total == 2: return "couple" return "subjects" @dataclass(frozen=True) class InstaPairCameraRoute: soft_row: dict[str, Any] hard_row: dict[str, Any] hard_scene: str hard_composition: str soft_camera_config: dict[str, Any] hard_camera_config: dict[str, Any] soft_camera_directive: str hard_camera_directive: str soft_camera_scene_directive: str hard_camera_scene_directive: str soft_camera_scene_sentence: str hard_camera_scene_sentence: str soft_camera_sentence: str hard_camera_sentence: str def as_dict(self) -> dict[str, Any]: return { "soft_row": self.soft_row, "hard_row": self.hard_row, "hard_scene": self.hard_scene, "hard_composition": self.hard_composition, "soft_camera_config": dict(self.soft_camera_config), "hard_camera_config": dict(self.hard_camera_config), "soft_camera_directive": self.soft_camera_directive, "hard_camera_directive": self.hard_camera_directive, "soft_camera_scene_directive": self.soft_camera_scene_directive, "hard_camera_scene_directive": self.hard_camera_scene_directive, "soft_camera_scene_sentence": self.soft_camera_scene_sentence, "hard_camera_scene_sentence": self.hard_camera_scene_sentence, "soft_camera_sentence": self.soft_camera_sentence, "hard_camera_sentence": self.hard_camera_sentence, } def resolve_insta_pair_camera_result( *, soft_row: dict[str, Any], hard_row: dict[str, Any], options: dict[str, Any], camera_config: str | dict[str, Any] | None, softcore_camera_config: str | dict[str, Any] | None, hardcore_camera_config: str | dict[str, Any] | None, hard_women_count: int, hard_men_count: int, pov_character_labels: list[str], camera_detail_choices: list[str] | tuple[str, ...], camera_config_with_mode: CameraConfigWithMode, camera_directive: CameraDirective, apply_contextual_composition: ApplyComposition, contextual_composition_prompt: CompositionPrompt, composition_prompt: Callable[[Any], str], camera_scene_directive_for_context: CameraSceneDirective, ) -> InstaPairCameraRoute: hard_camera_mode = str(options["hardcore_camera_mode"]) soft_camera_source = softcore_camera_config or camera_config hard_camera_source = hardcore_camera_config or camera_config if hard_camera_mode == "same_as_softcore": hard_camera_mode = str(options["softcore_camera_mode"]) hard_camera_source = soft_camera_source soft_camera_config_dict = camera_config_with_mode(soft_camera_source, str(options["softcore_camera_mode"])) hard_camera_config_dict = camera_config_with_mode(hard_camera_source, hard_camera_mode) soft_camera_config_dict = camera_config_with_detail( soft_camera_config_dict, str(options["camera_detail"]), camera_detail_choices, ) hard_camera_config_dict = camera_config_with_detail( hard_camera_config_dict, str(options["camera_detail"]), camera_detail_choices, ) soft_camera_directive, soft_camera_config_dict = camera_directive(soft_camera_config_dict) hard_camera_directive, hard_camera_config_dict = camera_directive(hard_camera_config_dict) soft_subject_kind = softcore_subject_kind(options["softcore_cast"], hard_women_count, hard_men_count) hard_subject_kind = hardcore_subject_kind(hard_women_count, hard_men_count) soft_row = apply_contextual_composition(soft_row, soft_subject_kind) hard_row = apply_contextual_composition(hard_row, hard_subject_kind) hard_scene = soft_row["scene_text"] if options["continuity"] == "same_creator_same_room" else hard_row["scene_text"] if hard_scene != hard_row.get("scene_text"): hard_row["source_scene_text"] = hard_row.get("source_scene_text") or hard_row.get("scene_text", "") hard_row["scene_text"] = hard_scene hard_composition = contextual_composition_prompt(hard_scene, hard_row["composition"], hard_subject_kind) if hard_composition != hard_row["composition"]: hard_row["source_composition"] = hard_row.get("source_composition") or hard_row["composition"] hard_row["composition"] = hard_composition hard_row["composition_prompt"] = composition_prompt(hard_composition) soft_pov_camera_labels = pov_character_labels if options["softcore_cast"] == "same_as_hardcore" else [] soft_camera_scene_directive, soft_camera_config_dict = camera_scene_directive_for_context( soft_row.get("scene_text"), soft_row.get("composition"), soft_camera_config_dict, soft_pov_camera_labels, soft_subject_kind, ) hard_camera_scene_directive, hard_camera_config_dict = camera_scene_directive_for_context( hard_scene, hard_composition, hard_camera_config_dict, pov_character_labels, hard_subject_kind, ) if soft_pov_camera_labels: soft_camera_directive = "" if pov_character_labels: hard_camera_directive = "" soft_row["camera_config"] = soft_camera_config_dict soft_row["camera_directive"] = soft_camera_directive soft_row["camera_scene_directive"] = soft_camera_scene_directive hard_row["camera_config"] = hard_camera_config_dict hard_row["camera_directive"] = hard_camera_directive hard_row["camera_scene_directive"] = hard_camera_scene_directive return InstaPairCameraRoute( soft_row=soft_row, hard_row=hard_row, hard_scene=hard_scene, hard_composition=hard_composition, soft_camera_config=soft_camera_config_dict, hard_camera_config=hard_camera_config_dict, soft_camera_directive=soft_camera_directive, hard_camera_directive=hard_camera_directive, soft_camera_scene_directive=soft_camera_scene_directive, hard_camera_scene_directive=hard_camera_scene_directive, soft_camera_scene_sentence=f"{soft_camera_scene_directive} " if soft_camera_scene_directive else "", hard_camera_scene_sentence=f"{hard_camera_scene_directive} " if hard_camera_scene_directive else "", soft_camera_sentence=f"Camera control: {soft_camera_directive} " if soft_camera_directive else "", hard_camera_sentence=f"Camera control: {hard_camera_directive} " if hard_camera_directive else "", ) def resolve_insta_pair_camera( *, soft_row: dict[str, Any], hard_row: dict[str, Any], options: dict[str, Any], camera_config: str | dict[str, Any] | None, softcore_camera_config: str | dict[str, Any] | None, hardcore_camera_config: str | dict[str, Any] | None, hard_women_count: int, hard_men_count: int, pov_character_labels: list[str], camera_detail_choices: list[str] | tuple[str, ...], camera_config_with_mode: CameraConfigWithMode, camera_directive: CameraDirective, apply_contextual_composition: ApplyComposition, contextual_composition_prompt: CompositionPrompt, composition_prompt: Callable[[Any], str], camera_scene_directive_for_context: CameraSceneDirective, ) -> dict[str, Any]: return resolve_insta_pair_camera_result( soft_row=soft_row, hard_row=hard_row, options=options, camera_config=camera_config, softcore_camera_config=softcore_camera_config, hardcore_camera_config=hardcore_camera_config, hard_women_count=hard_women_count, hard_men_count=hard_men_count, pov_character_labels=pov_character_labels, camera_detail_choices=camera_detail_choices, camera_config_with_mode=camera_config_with_mode, camera_directive=camera_directive, apply_contextual_composition=apply_contextual_composition, contextual_composition_prompt=contextual_composition_prompt, composition_prompt=composition_prompt, camera_scene_directive_for_context=camera_scene_directive_for_context, ).as_dict()