from __future__ import annotations from typing import Any, Mapping CAMERA_DIRECTIONS = ( "front-right quarter view", "right side view", "back-right quarter view", "back view", "back-left quarter view", "left side view", "front-left quarter view", "front view", ) CAMERA_ELEVATIONS = ("low-angle shot", "eye-level shot", "elevated shot", "high-angle shot") CAMERA_DISTANCES = ( "wide shot", "full-body shot", "three-quarter body shot", "medium shot", "close-up", "extreme close-up", ) SCENE_CAMERA_PROFILES: tuple[dict[str, Any], ...] = ( { "key": "business_cafe", "family": "coworking", "terms": ("business cafe", "work cafe", "coworking counter", "cafe counter with laptops", "coffee-counter work spots"), "layout_label": "Business cafe camera layout", "place": "business cafe coworking counter", "foreground": "counter edge, laptop corner, and small plant", "midground": "bar stools, warm desk lamps, and coffee-counter work spots", "background": "plants, mirror strip, menu wall, and repeated cafe work tables", "detail_label": "cafe details", "composition": { "woman": "business-cafe selfie frame with the woman near a counter edge and warm work-table depth behind her", "man": "business-cafe portrait frame with the man near a counter edge and warm work-table depth behind him", "default": "business-cafe frame with the subjects near a counter edge and warm work-table depth behind them", }, }, { "key": "office_after_hours", "family": "coworking", "terms": ("corporate office", "office after hours", "copier", "office lounge"), "layout_label": "Office camera layout", "place": "empty after-hours office", "foreground": "copier alcove edge, chair backs, and nearest desk corner", "midground": "repeating desks, glass partition seams, and muted monitor glow", "background": "rows of empty workstations, city-light windows, and quiet office depth", "detail_label": "office details", "composition": { "woman": "after-hours office frame with the woman near a desk edge and glass-partition depth behind her", "man": "after-hours office frame with the man near a desk edge and glass-partition depth behind him", "default": "after-hours office frame with the subjects near a desk edge and glass-partition depth behind them", }, }, { "key": "coworking_lounge", "family": "coworking", "terms": ( "coworking", "cowork", "shared office", "laptops", "warm desks", "repeating desks", "glass partitions", ), "layout_label": "Coworking camera layout", "place": "coworking lounge", "foreground": "near desk edge, laptop corner, and chair back", "midground": "warm work desks, laptop tables, and glass partition seams", "background": "tall windows, repeated desk rows, plants, and soft shared-office depth", "detail_label": "coworking details", "composition": { "woman": "coworking lounge selfie frame with the woman near a desk edge and tall-window depth behind her", "man": "coworking lounge portrait frame with the man near a desk edge and tall-window depth behind him", "default": "coworking lounge frame with the subjects near a desk edge and tall-window depth behind them", }, }, { "key": "classical_library", "family": "library", "terms": ( "classical library", "library stacks", "large library", "grand library", "reading room", "book stacks", "rare-books", "rare books", "rolling ladders", ), "layout_label": "Library camera layout", "place": "classical library", "foreground": "near bookshelf edge, reading-table corner, and brass lamp", "midground": "towering bookshelves, rolling ladders, carved columns, and marble floor lines", "background": "arched windows, repeated book aisles, warm brass lamps, and deep quiet library depth", "detail_label": "library details", "composition": { "woman": "classical library frame with the woman near a bookshelf edge and long shelf depth behind her", "man": "classical library frame with the man near a bookshelf edge and long shelf depth behind him", "default": "classical library frame with the subjects near a bookshelf edge and long shelf depth behind them", }, }, { "key": "creator_bedroom", "family": "private_creator", "terms": ( "creator bedroom", "content setup", "phone tripod", "ring light", "phone on a mini tripod", "creator studio", "creator-shot framing", "vertical creator-video", ), "layout_label": "Creator room camera layout", "place": "private creator room", "foreground": "bed edge, phone tripod, and rumpled sheets", "midground": "ring light stand, warm lamps, pillows, and creator props", "background": "soft bedding, curtains, mirror edge, and warm private-room depth", "detail_label": "creator-room details", "composition": { "woman": "creator-room frame with the woman near the bed edge and phone-tripod setup behind her", "man": "creator-room frame with the man near the bed edge and phone-tripod setup behind him", "default": "creator-room frame with the subjects near the bed edge and phone-tripod setup behind them", }, }, { "key": "mirror_room", "family": "private_creator", "terms": ( "mirror selfie setup", "mirror wall", "mirror-facing", "floor mirror", "vanity mirror", "phone reflection", "reflected bodies", "black lacquer mirror", "neon mirror wall", ), "layout_label": "Mirror-room camera layout", "place": "private mirror room", "foreground": "mirror edge, reflected phone angle, and floor reflection line", "midground": "bedside surface, vanity bulbs, glossy furniture, and reflected body plane", "background": "mirror depth, warm lamps, curtains, and repeated reflected sightlines", "detail_label": "mirror-room details", "composition": { "woman": "mirror-room frame with the woman aligned to the reflected phone angle and room depth behind her", "man": "mirror-room frame with the man aligned to the reflected phone angle and room depth behind him", "default": "mirror-room frame with the subjects aligned to the reflected phone angle and room depth behind them", }, }, { "key": "boudoir_bedroom", "family": "private_creator", "terms": ( "boudoir bedroom", "silk-sheet bed", "silk sheets", "velvet headboard", "canopy bed", "four-poster bed", "satin bedding", "bedside phone", "hotel bedroom", ), "layout_label": "Boudoir bedroom camera layout", "place": "boudoir bedroom", "foreground": "sheet fold, bedside edge, and pillow line", "midground": "rumpled bedding, warm lamps, canopy curtains, and soft floor shadows", "background": "headboard, drapes, mirror edge, and intimate bedroom depth", "detail_label": "bedroom details", "composition": { "woman": "boudoir bedroom frame with the woman on or beside the bed and warm bedroom depth behind her", "man": "boudoir bedroom frame with the man on or beside the bed and warm bedroom depth behind him", "default": "boudoir bedroom frame with the subjects on or beside the bed and warm bedroom depth behind them", }, }, { "key": "bathroom_shower", "family": "private_creator", "terms": ( "bathroom counter", "private bathroom", "shower room", "wet tile", "steam", "steamy", "glass reflections", "vanity counter", "wet towels", ), "layout_label": "Bathroom camera layout", "place": "private bathroom", "foreground": "counter edge, glass partition line, and towel edge", "midground": "mirror haze, vanity bulbs, wet tile, and reflected glass seams", "background": "shower wall, warm reflected light, steam, and tight private-room depth", "detail_label": "bathroom details", "composition": { "woman": "bathroom frame with the woman near the mirror or glass partition and tile depth behind her", "man": "bathroom frame with the man near the mirror or glass partition and tile depth behind him", "default": "bathroom frame with the subjects near the mirror or glass partition and tile depth behind them", }, }, { "key": "private_studio", "family": "private_creator", "terms": ( "fetish studio", "private studio", "glossy black floor", "harness-wall", "chrome studio", "industrial loft", "neon-lit lacquer", "reflective panels", "controlled rim light", ), "layout_label": "Private studio camera layout", "place": "private studio set", "foreground": "floor reflection edge, prop stand, and lighting-stand line", "midground": "controlled lights, reflective panels, backdrop seams, and studio props", "background": "dark curtains, glossy walls, rim light, and staged private-set depth", "detail_label": "studio details", "composition": { "woman": "private studio frame with the woman on the glossy floor plane and controlled lights behind her", "man": "private studio frame with the man on the glossy floor plane and controlled lights behind him", "default": "private studio frame with the subjects on the glossy floor plane and controlled lights behind them", }, }, { "key": "car_interior", "family": "private_creator", "terms": ( "parked car interior", "private car backseat", "car backseat", "dashboard glow", "tinted windows", "seat reflections", ), "layout_label": "Car interior camera layout", "place": "parked car interior", "foreground": "seat edge, door frame, and dashboard glow", "midground": "upholstery seams, window reflections, center console, and tight cabin geometry", "background": "tinted windows, rear seat depth, and enclosed car interior shadows", "detail_label": "car-interior details", "composition": { "woman": "car interior frame with the woman inside the tight cabin geometry and window reflections behind her", "man": "car interior frame with the man inside the tight cabin geometry and window reflections behind him", "default": "car interior frame with the subjects inside the tight cabin geometry and window reflections behind them", }, }, { "key": "hotel_corridor", "family": "semi_public", "terms": ( "hotel corridor", "hotel service corridor", "hotel service alcove", "service alcove", "service hallway", "service hall", "repeating numbered doors", "numbered doors", "luggage carts", "stair landing", "hotel stair landing", ), "layout_label": "Hotel corridor camera layout", "place": "hotel corridor", "foreground": "nearest doorframe edge, patterned carpet line, and wall sconce", "midground": "repeating numbered doors, brass wall lamps, service-alcove turns, and luggage carts", "background": "long corridor perspective, closed doors, warm late-night depth, and quiet hotel sightlines", "detail_label": "hotel corridor details", "composition": { "woman": "hotel corridor frame with the woman near a doorframe edge and repeated doors behind her", "man": "hotel corridor frame with the man near a doorframe edge and repeated doors behind him", "default": "hotel corridor frame with the subjects near a doorframe edge and repeated doors behind them", }, }, { "key": "parking_garage", "family": "semi_public", "terms": ( "parking garage", "parking deck", "underground garage", "multi-level parking", "concrete pillars", "numbered pillars", "painted floor lines", "painted bay lines", "parked cars", ), "layout_label": "Parking garage camera layout", "place": "parking garage", "foreground": "nearest concrete pillar, painted floor line, and car bumper edge", "midground": "repeating concrete pillars, parked cars, painted bay lines, and glossy concrete lanes", "background": "shadowed corners, fluorescent depth, numbered pillars, and long garage perspective", "detail_label": "parking garage details", "composition": { "woman": "parking garage frame with the woman beside a concrete pillar and repeated bay lines behind her", "man": "parking garage frame with the man beside a concrete pillar and repeated bay lines behind him", "default": "parking garage frame with the subjects beside a concrete pillar and repeated bay lines behind them", }, }, { "key": "theater_backstage", "family": "semi_public", "terms": ( "theater backstage", "backstage wings", "cabaret backstage", "prop storage", "prop racks", "costume racks", "costume rails", "stage ropes", "scenery flats", ), "layout_label": "Backstage camera layout", "place": "theater backstage", "foreground": "curtain edge, prop trunk corner, and costume-rack line", "midground": "layered velvet curtains, costume racks, prop shelves, and vanity bulb mirrors", "background": "dark stage wings, repeated scenery flats, narrow backstage passages, and warm light spill", "detail_label": "backstage details", "composition": { "woman": "backstage frame with the woman partly framed by curtains and costume racks behind her", "man": "backstage frame with the man partly framed by curtains and costume racks behind him", "default": "backstage frame with the subjects partly framed by curtains and costume racks behind them", }, }, { "key": "wine_cellar", "family": "semi_public", "terms": ( "wine cellar", "wine storage", "bottle racks", "bottle shelves", "arched cellar", "brick niches", "cellar corridor", "stacked bottle", ), "layout_label": "Wine cellar camera layout", "place": "wine cellar", "foreground": "near bottle-rack edge, crate corner, and stone floor line", "midground": "repeating bottle racks, arched brick niches, narrow aisles, and low amber lamps", "background": "cool shadowed depth, stacked shelves, cellar arches, and secluded rack rows", "detail_label": "wine cellar details", "composition": { "woman": "wine cellar frame with the woman between bottle racks and arched cellar depth behind her", "man": "wine cellar frame with the man between bottle racks and arched cellar depth behind him", "default": "wine cellar frame with the subjects between bottle racks and arched cellar depth behind them", }, }, { "key": "museum_archive", "family": "semi_public", "terms": ( "museum archive", "gallery storage", "rare-books archive", "archive room", "storage shelves", "labeled boxes", "rolling shelves", "catalog drawers", "compact shelving", ), "layout_label": "Archive camera layout", "place": "museum archive", "foreground": "storage-shelf edge, archive box corner, and work-table line", "midground": "labeled boxes, rolling shelves, frame racks, catalog drawers, and long work tables", "background": "compact shelving rows, soft overhead lights, archival aisles, and hidden storage depth", "detail_label": "archive details", "composition": { "woman": "archive frame with the woman beside labeled storage shelves and compact rows behind her", "man": "archive frame with the man beside labeled storage shelves and compact rows behind him", "default": "archive frame with the subjects beside labeled storage shelves and compact rows behind them", }, }, { "key": "laundromat_late_night", "family": "semi_public", "terms": ( "laundromat", "coin laundry", "washing machines", "stacked dryers", "washer-door", "washer door", "folding tables", "detergent shelves", "machine row", ), "layout_label": "Laundromat camera layout", "place": "late-night laundromat", "foreground": "folding-table edge, chrome washer door, and tiled floor line", "midground": "repeating washing machines, stacked dryers, detergent shelves, and empty machine rows", "background": "cool fluorescent depth, mirrored machine doors, front glass, and quiet back-corner sightlines", "detail_label": "laundromat details", "composition": { "woman": "laundromat frame with the woman near a folding table and repeated washer doors behind her", "man": "laundromat frame with the man near a folding table and repeated washer doors behind him", "default": "laundromat frame with the subjects near a folding table and repeated washer doors behind them", }, }, { "key": "train_station_lockers", "family": "semi_public", "terms": ( "train-station locker", "train station locker", "locker corridor", "station underpass", "station service passage", "metal lockers", "vending machines", "utility doors", "warning stripes", ), "layout_label": "Station locker camera layout", "place": "train-station locker corridor", "foreground": "locker edge, vending-machine corner, and tiled floor line", "midground": "repeating metal lockers, tiled wall seams, poster frames, and utility doors", "background": "fluorescent underpass depth, stair railings, warning stripes, and hidden side alcoves", "detail_label": "station locker details", "composition": { "woman": "station locker frame with the woman beside metal lockers and tiled depth behind her", "man": "station locker frame with the man beside metal lockers and tiled depth behind him", "default": "station locker frame with the subjects beside metal lockers and tiled depth behind them", }, }, { "key": "nightclub_back_hall", "family": "semi_public", "terms": ( "nightclub back hallway", "club vip corridor", "vip club corridor", "music venue greenroom", "greenroom corridor", "coat-check racks", "neon strips", "velvet ropes", "mirrored wall panels", "stickered doors", ), "layout_label": "Nightclub back-hall camera layout", "place": "nightclub back hallway", "foreground": "black door edge, velvet-rope post, and mirrored wall strip", "midground": "repeated dark doors, neon strips, coat-check racks, mirrored panels, and booth edges", "background": "distant colored dance-floor light, dim practical lamps, cable cases, and narrow hallway depth", "detail_label": "nightclub back-hall details", "composition": { "woman": "nightclub back-hall frame with the woman near a dark door edge and neon hallway depth behind her", "man": "nightclub back-hall frame with the man near a dark door edge and neon hallway depth behind him", "default": "nightclub back-hall frame with the subjects near a dark door edge and neon hallway depth behind them", }, }, { "key": "restaurant_private_booth", "family": "semi_public", "terms": ( "restaurant private booth", "private booth", "bistro back corner", "after-hours dining", "afterhours dining", "high banquettes", "dark wood partitions", "folded napkins", "stacked chairs", "small round tables", ), "layout_label": "Restaurant booth camera layout", "place": "restaurant private booth", "foreground": "table edge, high banquette back, and dark wood partition", "midground": "repeating table lamps, folded napkins, mirrored wall panels, and empty tables", "background": "after-hours dining-room depth, stacked chairs, service doorway, and secluded sightlines", "detail_label": "restaurant booth details", "composition": { "woman": "restaurant booth frame with the woman beside a high banquette and table lamps behind her", "man": "restaurant booth frame with the man beside a high banquette and table lamps behind him", "default": "restaurant booth frame with the subjects beside a high banquette and table lamps behind them", }, }, ) SCENE_CAMERA_PROFILE_KEYS = {str(profile["key"]): dict(profile) for profile in SCENE_CAMERA_PROFILES} THEME_PROFILE_KEYS = { "classical_library": "classical_library", "creator_bedroom": "creator_bedroom", "mirror_room": "mirror_room", "boudoir_bedroom": "boudoir_bedroom", "bathroom_shower": "bathroom_shower", "private_studio": "private_studio", "car_interior": "car_interior", "fetish_studio": "private_studio", "hotel_corridor": "hotel_corridor", "parking_garage": "parking_garage", "theater_backstage": "theater_backstage", "wine_cellar": "wine_cellar", "museum_archive": "museum_archive", "laundromat_late_night": "laundromat_late_night", "train_station_lockers": "train_station_lockers", "nightclub_back_hall": "nightclub_back_hall", "restaurant_private_booth": "restaurant_private_booth", } SCENE_SLUG_PROFILE_KEYS = { "coworking_lounge_window": "coworking_lounge", "business_cafe_counter": "business_cafe", "office_afterhours_affair": "office_after_hours", "classical_large_library": "classical_library", "old_world_reading_room": "classical_library", "hidden_library_stacks": "classical_library", "library_stacks_secret": "classical_library", "creator_bedroom_ring_light": "creator_bedroom", "onlyfans_mirror_bedroom": "mirror_room", "walk_in_closet_tryon": "mirror_room", "hotel_bed_phone_tripod": "creator_bedroom", "bathroom_counter_selfie": "bathroom_shower", "vanity_ring_light_close": "mirror_room", "apartment_floor_content": "creator_bedroom", "balcony_phone_selfie": "creator_bedroom", "car_interior_creator_selfie": "car_interior", "shower_steam_phone_reflection": "bathroom_shower", "studio_bedroom_backdrop": "creator_bedroom", "couch_lamp_creator_clip": "creator_bedroom", "large_bedroom_mirror_selfie": "mirror_room", "antique_mirror_boudoir": "mirror_room", "bathroom_mirror_haze": "bathroom_shower", "closet_full_length_mirror": "mirror_room", "hotel_mirror_city_view": "mirror_room", "neon_mirror_wall": "mirror_room", "gold_vanity_mirror": "mirror_room", "black_lacquer_mirror_room": "mirror_room", "hardcore_bedroom_mirror_pair": "mirror_room", "hardcore_hotel_mirror_pair": "mirror_room", "hardcore_shower_mirror_pair": "bathroom_shower", "hardcore_threesome_mirror_suite": "mirror_room", "warm_boudoir_canopy_bed": "boudoir_bedroom", "silk_bed_close_creator": "boudoir_bedroom", "velvet_headboard_bedroom": "boudoir_bedroom", "four_poster_lingerie_room": "boudoir_bedroom", "hotel_satin_bedroom": "boudoir_bedroom", "rose_lamp_bedroom": "boudoir_bedroom", "black_latex_studio_floor": "private_studio", "red_velvet_lacquer_room": "private_studio", "industrial_loft_private_set": "private_studio", "neon_lacquer_private_room": "private_studio", "harness_wall_studio": "private_studio", "chrome_fetish_set": "private_studio", "costume_dressing_room_phone": "theater_backstage", "burlesque_stage_close": "theater_backstage", "cabaret_backstage_vanity": "theater_backstage", "after_dark_private_office": "office_after_hours", "fantasy_parlor_content_set": "private_studio", "cosplay_hotel_mirror": "mirror_room", "hardcore_bedroom_phone_tripod": "creator_bedroom", "hardcore_hotel_bed_city": "boudoir_bedroom", "hardcore_mirror_bedroom": "mirror_room", "hardcore_low_mattress_studio": "private_studio", "hardcore_velvet_room": "private_studio", "hardcore_shower_room": "bathroom_shower", "hardcore_lounge_couch": "private_studio", "hardcore_floor_cushion_room": "boudoir_bedroom", "hardcore_ring_light_bed": "creator_bedroom", "hardcore_bathroom_counter": "bathroom_shower", "hardcore_walk_in_closet_floor": "mirror_room", "hardcore_car_backseat": "car_interior", "bed_edge_close_contact": "boudoir_bedroom", "low_bed_mirror_angle": "mirror_room", "hotel_bed_overhead": "boudoir_bedroom", "floor_mattress_creator_set": "creator_bedroom", "canopy_bed_explicit_set": "boudoir_bedroom", "velvet_bedroom_wide": "boudoir_bedroom", "penetration_mirror_bedroom": "mirror_room", "penetration_edge_of_bed": "boudoir_bedroom", "penetration_low_mattress": "private_studio", "penetration_couch_lounge": "private_studio", "penetration_shower_bench": "bathroom_shower", "penetration_floor_cushions": "boudoir_bedroom", "oral_bed_kneeling_close": "boudoir_bedroom", "oral_mirror_floor": "mirror_room", "oral_couch_front_view": "private_studio", "oral_shower_steam": "bathroom_shower", "oral_vanity_floor": "mirror_room", "oral_hotel_bed_close": "boudoir_bedroom", "anal_rear_mirror_bed": "mirror_room", "anal_bent_over_couch": "private_studio", "anal_edge_bed_low_angle": "boudoir_bedroom", "anal_shower_wall": "bathroom_shower", "anal_velvet_bench": "private_studio", "anal_floor_mattress_mirror": "mirror_room", "threesome_wide_bedroom": "boudoir_bedroom", "threesome_hotel_suite": "boudoir_bedroom", "threesome_floor_cushions": "boudoir_bedroom", "threesome_studio_mattress": "private_studio", "threesome_shower_room": "bathroom_shower", "threesome_velvet_lounge": "private_studio", "group_suite_wide_bed": "boudoir_bedroom", "group_studio_mattress_room": "private_studio", "group_velvet_orgy_room": "private_studio", "group_lounge_couches": "private_studio", "group_floor_pillow_room": "boudoir_bedroom", "group_shower_spa_room": "bathroom_shower", "group_rooftop_private_party": "creator_bedroom", "group_hotel_party_bedroom": "boudoir_bedroom", "group_backstage_private_room": "theater_backstage", "group_neon_loft_room": "private_studio", "group_mirror_wall_suite": "mirror_room", "group_lacquer_mirror_lounge": "mirror_room", "climax_bed_close_flash": "boudoir_bedroom", "climax_mirror_counter": "mirror_room", "climax_floor_sheets": "boudoir_bedroom", "climax_hotel_bed_flash": "boudoir_bedroom", "climax_shower_tile": "bathroom_shower", "climax_velvet_couch": "private_studio", } PROFILE_TEXT_FIELDS = ( "key", "family", "layout_label", "place", "foreground", "midground", "background", "detail_label", ) MISMATCHED_COMPOSITION_TERMS = ( "camera-aware", "camera aware", "outfit-check", "outfit check", "mirror view", "mirror pose", "bag", "shoes", "footwear", ) def _clean_text(value: Any) -> str: return " ".join(str(value or "").strip().split()) def _profile_by_key(value: Any) -> dict[str, Any]: key = str(value or "").strip() if not key: return {} if key in SCENE_CAMERA_PROFILE_KEYS: return dict(SCENE_CAMERA_PROFILE_KEYS[key]) mapped_key = THEME_PROFILE_KEYS.get(key) if mapped_key and mapped_key in SCENE_CAMERA_PROFILE_KEYS: return dict(SCENE_CAMERA_PROFILE_KEYS[mapped_key]) return {} def _profile_title(value: str) -> str: text = _clean_text(value).replace("_", " ").replace("-", " ") if not text: return "Scene" return " ".join(part[:1].upper() + part[1:] for part in text.split()) def _default_composition(profile: dict[str, Any]) -> dict[str, str]: place = _clean_text(profile.get("place")) or "scene" foreground = _clean_text(profile.get("foreground")) or "foreground anchor" background = _clean_text(profile.get("background")) or "environment depth" return { "woman": f"{place} frame with the woman near {foreground} and {background} behind her", "man": f"{place} frame with the man near {foreground} and {background} behind him", "default": f"{place} frame with the subjects near {foreground} and {background} behind them", } def normalize_scene_camera_profile(value: Any) -> dict[str, Any]: if not isinstance(value, dict): return {} base = _profile_by_key(value.get("base_profile_key") or value.get("extends")) merged = dict(base) for key, raw_value in value.items(): if key in ("base_profile_key", "extends"): continue merged[key] = raw_value has_profile_fields = any(_clean_text(merged.get(key)) for key in ("layout_label", "place", "foreground", "midground", "background")) if not has_profile_fields: return {} key = _clean_text(merged.get("key") or merged.get("slug") or merged.get("name") or base.get("key") or "custom_scene") place = _clean_text(merged.get("place") or merged.get("name") or key.replace("_", " ")) profile = {field: _clean_text(merged.get(field)) for field in PROFILE_TEXT_FIELDS} profile["key"] = key profile["family"] = profile["family"] or "custom" profile["place"] = place profile["layout_label"] = profile["layout_label"] or f"{_profile_title(place)} camera layout" profile["foreground"] = profile["foreground"] or base.get("foreground", "foreground anchor") profile["midground"] = profile["midground"] or base.get("midground", "midground environment anchors") profile["background"] = profile["background"] or base.get("background", "background depth") profile["detail_label"] = profile["detail_label"] or f"{place} details" composition = merged.get("composition") if isinstance(composition, dict): profile["composition"] = { str(key): _clean_text(text) for key, text in composition.items() if _clean_text(text) } else: base_composition = base.get("composition") if isinstance(base.get("composition"), dict) else {} profile["composition"] = dict(base_composition) if base_composition else _default_composition(profile) if not profile["composition"]: profile["composition"] = _default_composition(profile) return profile def _scene_entry_text(scene_entry: Any) -> str: if not isinstance(scene_entry, dict): return "" return str( scene_entry.get("prompt") or scene_entry.get("description") or scene_entry.get("text") or scene_entry.get("name") or "" ).strip() def _scene_entry_profile_key(scene_entry: Any) -> str: if not isinstance(scene_entry, dict): return "" explicit = str( scene_entry.get("scene_camera_profile_key") or scene_entry.get("camera_profile_key") or scene_entry.get("camera_profile") or scene_entry.get("profile") or "" ).strip() if explicit: return explicit slug = str(scene_entry.get("slug") or "").strip() return SCENE_SLUG_PROFILE_KEYS.get(slug, "") def _scene_entry_profile(scene_entry: Any) -> dict[str, Any]: if not isinstance(scene_entry, dict): return {} for key in ("scene_camera_profile", "camera_profile"): profile = normalize_scene_camera_profile(scene_entry.get(key)) if profile: return profile profile = normalize_scene_camera_profile(scene_entry.get("profile")) if profile: return profile return normalize_scene_camera_profile(scene_entry) def scene_camera_profile( scene_text: Any = "", *, scene_entry: Any = None, theme: Any = "", profile_key: Any = "", ) -> dict[str, Any]: inline_explicit_profile = normalize_scene_camera_profile(profile_key) if inline_explicit_profile: return inline_explicit_profile explicit_profile = _profile_by_key(profile_key) if explicit_profile: return explicit_profile inline_entry_profile = _scene_entry_profile(scene_entry) if inline_entry_profile: return inline_entry_profile entry_profile = _profile_by_key(_scene_entry_profile_key(scene_entry)) if entry_profile: return entry_profile theme_profile = _profile_by_key(theme) if theme_profile: return theme_profile if isinstance(scene_entry, dict): entry_theme_profile = _profile_by_key(scene_entry.get("theme")) if entry_theme_profile: return entry_theme_profile text = " ".join(part for part in (str(scene_text or ""), _scene_entry_text(scene_entry)) if part).lower() if not text: return {} for profile in SCENE_CAMERA_PROFILES: if any(term in text for term in profile["terms"]): return dict(profile) return {} def is_coworking_scene(scene_text: Any) -> bool: return scene_camera_profile(scene_text).get("family") == "coworking" def is_scene_camera_aware(scene_text: Any) -> bool: return bool(scene_camera_profile(scene_text)) def _compact_label(value: Any, compact_labels: Mapping[str, str] | None = None) -> str: text = str(value or "") if compact_labels and text in compact_labels: return compact_labels[text] return text.replace("_", " ") def camera_geometry_phrase(parsed: dict[str, Any], compact_labels: Mapping[str, str] | None = None) -> str: direction = str(parsed.get("orbit_direction") or "").strip() elevation = str(parsed.get("orbit_elevation_label") or "").strip() distance = str(parsed.get("orbit_distance_label") or "").strip() custom = str(parsed.get("custom_camera_prompt") or "").strip() if not any((direction, elevation, distance)) and custom: return custom parts = [part for part in (direction, elevation, distance) if part and part != "auto"] if parts: return ", ".join(parts) compact_parts = [ _compact_label(parsed.get(key), compact_labels) for key in ("shot_size", "angle", "distance") ] compact_parts = [part for part in compact_parts if part and part != "auto"] return ", ".join(compact_parts) def camera_direction_from_text(text: Any) -> str: source = str(text or "").lower() for label in CAMERA_DIRECTIONS: if label in source: return label return "" def camera_elevation_from_text(text: Any) -> str: source = str(text or "").lower() for label in CAMERA_ELEVATIONS: if label in source: return label return "" def camera_distance_from_text(text: Any) -> str: source = str(text or "").lower() for label in CAMERA_DISTANCES: if label in source: return label return "" def coworking_location_profile(scene_text: Any) -> dict[str, str]: profile = scene_camera_profile(scene_text) if profile.get("family") == "coworking": return profile return scene_camera_profile("coworking lounge") def scene_subject_terms(subject_kind: str, pov_labels: list[str] | None = None) -> tuple[str, str]: if pov_labels: return "the visible partner", "them" if subject_kind == "woman": return "the woman", "her" if subject_kind == "man": return "the man", "him" if subject_kind == "couple": return "the couple", "them" return "the subjects", "them" def coworking_subject_terms(subject_kind: str, pov_labels: list[str] | None = None) -> tuple[str, str]: return scene_subject_terms(subject_kind, pov_labels) def scene_direction_detail( direction: str, profile: dict[str, str], pov_labels: list[str] | None = None, subject_kind: str = "subjects", ) -> str: direction = str(direction or "").strip().lower() foreground = profile["foreground"] midground = profile["midground"] background = profile["background"] detail_label = profile.get("detail_label") or "location details" subject, pronoun = scene_subject_terms(subject_kind, pov_labels) is_verb = "are" if subject == "the subjects" else "is" face_verb = "face" if subject == "the subjects" else "faces" if pov_labels: if "right side" in direction: return f"{subject} {is_verb} in right-side profile; {midground} run behind {pronoun} toward {background}, with {detail_label} kept at the frame edges" if "left side" in direction: return f"{subject} {is_verb} in left-side profile; {midground} run behind {pronoun} toward {background}, with {detail_label} kept at the frame edges" if "back-right" in direction or "back-left" in direction: return f"{subject} stays close in one continuous diagonal first-person body angle; {midground} lead toward {background} behind {pronoun} at the edges, not in the lower foreground" if direction == "back view": return f"the viewer looks past {subject}'s back toward {midground}, then into {background}; only POV body cues sit low in frame" if "front-right" in direction or "front-left" in direction: return f"{subject} fills the first-person front-quarter view; {midground} recede diagonally behind {pronoun} toward {background}" return f"{subject} faces the viewer in first-person view; {midground} and {background} stay behind {pronoun}, not between viewer and body" if "right side" in direction or "left side" in direction: return f"{subject} {is_verb} held in side profile along the {foreground}; {midground} run laterally behind {pronoun}, with {background} still readable" if "back-right" in direction or "back-left" in direction: return f"{subject} {is_verb} viewed from a rear-quarter angle, partly turning back toward camera; the {foreground} stays low in frame while {midground} lead into {background}" if direction == "back view": return f"{subject} {is_verb} seen from behind with the {foreground} at camera side, facing into {midground} and {background}" if "front-right" in direction or "front-left" in direction: return f"{subject} {is_verb} placed beside the {foreground}; {midground} recede diagonally behind {pronoun} toward {background}" return f"{subject} {face_verb} camera beside the {foreground}; {midground} sit between {pronoun} and {background}" def coworking_direction_detail( direction: str, profile: dict[str, str], pov_labels: list[str] | None = None, subject_kind: str = "subjects", ) -> str: return scene_direction_detail(direction, profile, pov_labels, subject_kind) def scene_distance_detail( distance: str, profile: dict[str, str], subject_kind: str, pov_labels: list[str] | None = None, ) -> str: distance = str(distance or "").strip().lower() subject, _pronoun = scene_subject_terms(subject_kind, pov_labels) if pov_labels: if "wide" in distance or "full-body" in distance or "full body" in distance: return f"wide POV keeps {subject} readable with {profile['place']} context behind them and environmental anchors only beside or beyond the action" if "close" in distance: return f"close POV keeps {subject} dominant with {profile['place']} context only at the sides or background" return f"medium POV keeps {subject} dominant with room context beside or behind them" if "wide" in distance or "full-body" in distance or "full body" in distance: return f"wide crop keeps the {profile['foreground']}, {profile['midground']}, and {profile['background']} readable" if "close" in distance: return f"close crop keeps one anchor from the {profile['foreground']} visible" return f"medium crop keeps {subject} dominant" def coworking_distance_detail( distance: str, profile: dict[str, str], subject_kind: str, pov_labels: list[str] | None = None, ) -> str: return scene_distance_detail(distance, profile, subject_kind, pov_labels) def scene_elevation_detail( elevation: str, profile: dict[str, str], subject_kind: str, pov_labels: list[str] | None = None, ) -> str: elevation = str(elevation or "").strip().lower() subject, pronoun = scene_subject_terms(subject_kind, pov_labels) if pov_labels: if "low-angle" in elevation: return f"low angle keeps POV body cues low while the {profile['background']} rises behind {pronoun}" if "elevated" in elevation: return f"elevated POV keeps the viewer's eye line slightly higher than {subject}, with location anchors only beside or behind {pronoun}" if "high-angle" in elevation: return f"high angle looks down from the viewer's position with {profile['midground']} only in the background" return f"eye-level angle keeps {profile['midground']} behind {pronoun}" if "low-angle" in elevation: return f"low angle keeps the {profile['foreground']} low while {profile['background']} rises behind {pronoun}" if "elevated" in elevation: return f"elevated angle shows the {profile['foreground']} and {profile['midground']} around {pronoun}" if "high-angle" in elevation: return f"high angle shows the {profile['place']} layout and placement of {pronoun}" return f"eye-level angle keeps {profile['midground']} visually stable" def coworking_elevation_detail( elevation: str, profile: dict[str, str], subject_kind: str, pov_labels: list[str] | None = None, ) -> str: return scene_elevation_detail(elevation, profile, subject_kind, pov_labels) def scene_camera_directive( scene_text: Any, parsed: dict[str, Any], pov_labels: list[str] | None = None, subject_kind: str = "subjects", compact_labels: Mapping[str, str] | None = None, *, scene_entry: Any = None, theme: Any = "", profile_key: Any = "", ) -> str: profile = scene_camera_profile(scene_text, scene_entry=scene_entry, theme=theme, profile_key=profile_key) if not profile: return "" direction = str(parsed.get("orbit_direction") or "").strip() elevation = str(parsed.get("orbit_elevation_label") or "").strip() distance = str(parsed.get("orbit_distance_label") or "").strip() custom_prompt = str(parsed.get("custom_camera_prompt") or "").strip() direction = direction or camera_direction_from_text(custom_prompt) elevation = elevation or camera_elevation_from_text(custom_prompt) distance = distance or camera_distance_from_text(custom_prompt) if not any((direction, elevation, distance, custom_prompt)): return "" direction_detail = scene_direction_detail(direction, profile, pov_labels, subject_kind) distance_detail = scene_distance_detail(distance, profile, subject_kind, pov_labels) elevation_detail = scene_elevation_detail(elevation, profile, subject_kind, pov_labels) geometry = camera_geometry_phrase(parsed, compact_labels) geometry_clause = f" ({geometry})" if geometry else "" if pov_labels: return ( f"{profile['layout_label']} from POV{geometry_clause}: {direction_detail}. " f"{distance_detail}; {elevation_detail}; lower foreground is reserved for POV body or hand cues; " f"use the multiangle camera only as first-person spatial geometry." ) return ( f"{profile['layout_label']}{geometry_clause}: {direction_detail}; " f"{distance_detail}; {elevation_detail}." ) def coworking_camera_scene_directive( scene_text: Any, parsed: dict[str, Any], pov_labels: list[str] | None = None, subject_kind: str = "subjects", compact_labels: Mapping[str, str] | None = None, ) -> str: if not is_coworking_scene(scene_text): return "" return scene_camera_directive(scene_text, parsed, pov_labels, subject_kind, compact_labels) def profile_composition_text(profile: dict[str, Any], subject_kind: str) -> str: composition = profile.get("composition") if isinstance(profile.get("composition"), dict) else {} if subject_kind == "woman" and composition.get("woman"): return str(composition["woman"]) if subject_kind == "man" and composition.get("man"): return str(composition["man"]) text = str(composition.get("default") or f"{profile['place']} frame with the subjects clearly placed in the room") if subject_kind == "couple": text = text.replace("the subjects", "the couple") if "composition" not in text.lower(): text = f"{text} composition" return text def contextual_composition_prompt( scene_text: Any, composition: Any, subject_kind: str = "subjects", *, scene_entry: Any = None, theme: Any = "", profile_key: Any = "", ) -> str: text = str(composition or "").strip() if not text: return text profile = scene_camera_profile(scene_text, scene_entry=scene_entry, theme=theme, profile_key=profile_key) if not profile: return text lower = text.lower() profile_lower = " ".join( str(profile.get(key, "")).lower() for key in ("place", "foreground", "midground", "background") ) already_matches = any(term and term in lower for term in profile_lower.replace(",", " ").split()) mismatched = any(term in lower for term in MISMATCHED_COMPOSITION_TERMS) office_generic = any(term in lower for term in ("office-lobby", "office lobby", "walking composition", "outfit-check")) if not mismatched and not office_generic and already_matches: return text if not mismatched and not office_generic and profile.get("family") != "coworking": return text return profile_composition_text(profile, subject_kind) def coworking_composition_prompt(scene_text: Any, composition: Any, subject_kind: str = "subjects") -> str: return contextual_composition_prompt(scene_text, composition, subject_kind) def camera_scene_directive_for_context( scene_text: Any, parsed_camera_config: dict[str, Any], pov_labels: list[str] | None = None, subject_kind: str = "subjects", compact_labels: Mapping[str, str] | None = None, *, scene_entry: Any = None, theme: Any = "", profile_key: Any = "", ) -> str: if ( parsed_camera_config.get("camera_detail") == "off" or parsed_camera_config.get("camera_mode") == "disabled" ): return "" return scene_camera_directive( scene_text, parsed_camera_config, pov_labels, subject_kind, compact_labels, scene_entry=scene_entry, theme=theme, profile_key=profile_key, )