""" Final Image Prompt Service Generates final complete image prompts by converting style descriptions and combining them with base prompts in consistent order. """ from collections import namedtuple from enum import Enum from typing import Optional from loguru import logger # Define preset value structure PresetValue = namedtuple('PresetValue', ['display_name', 'prompt']) class StylePreset(Enum): """Predefined style presets for image generation""" STICK_FIGURE = PresetValue( display_name="Stick Figure", prompt=( "Pure white background, minimalist illustration, matchstick figure style, " "black and white line drawing, simple clean lines" ), ) MINIMAL = PresetValue( display_name="Minimal", prompt=( "Simple and clean background, minimal design, soft colors, " "professional look, modern aesthetic, uncluttered composition" ), ) FUTURISTIC = PresetValue( display_name="Futuristic", prompt=( "Futuristic sci-fi style, high-tech city background, " "blue and silver tones, technology sense, soft neon lights, " "cyberpunk aesthetics, digital art, advanced technology" ), ) CINEMATIC = PresetValue( display_name="Cinematic", prompt=( "Cinematic lighting, dramatic composition, film grain, " "professional photography, depth of field, movie still quality" ), ) class FinalImagePromptService: """ Final Image Prompt Service Generates the final complete image prompt by: 1. Converting style description (preset or custom) 2. Combining style + base prompt in correct order This ensures: - Consistent style conversion logic across all scenarios - Consistent prompt concatenation order (style first, then prompt) - Single source of truth for image prompt generation Usage: # With preset style final = await reelforge.generate_final_image_prompt( prompt="A peaceful mountain landscape", style_preset=StylePreset.FUTURISTIC ) # With custom style (any language) final = await reelforge.generate_final_image_prompt( prompt="A coffee cup on table", custom_style_description="温馨的咖啡馆,暖色调" ) # Only prompt (no style) final = await reelforge.generate_final_image_prompt( prompt="A sunset over the ocean" ) """ def __init__(self, reelforge_core): """ Initialize service Args: reelforge_core: ReelForgeCore instance for accessing LLM """ self.core = reelforge_core async def __call__( self, prompt: str = "", style_preset: Optional[StylePreset] = None, custom_style_description: str = "" ) -> str: """ Generate final image prompt with style Priority: 1. custom_style_description (if provided) → convert via LLM 2. style_preset (if provided) → use predefined English prompt 3. Neither → just return prompt Concatenation: - Style part (if exists) comes first - Base prompt (if exists) comes second - Join with comma: "{style_part}, {prompt}" Args: prompt: Base prompt (optional, e.g., "A peaceful landscape") style_preset: Preset style from StylePreset enum (optional) custom_style_description: Custom description in any language (optional) Overrides style_preset if provided Returns: Final complete image prompt in English Examples: # With preset style (IDE autocomplete!) final = await service( prompt="A mountain landscape", style_preset=StylePreset.FUTURISTIC ) # Returns: "Futuristic sci-fi style..., A mountain landscape" # With custom style (any language) final = await service( prompt="A coffee cup", custom_style_description="温馨的咖啡馆,暖色调" ) # Returns: "Cozy coffee shop interior..., A coffee cup" # Only prompt final = await service(prompt="A sunset scene") # Returns: "A sunset scene" # Only style final = await service(style_preset=StylePreset.MINIMAL) # Returns: "Simple and clean background..." """ # Step 1: Determine style part style_part = "" if custom_style_description: # Priority 1: Custom description (convert via LLM) logger.debug(f"Converting custom style description: {custom_style_description}") style_part = await self._convert_custom_style(custom_style_description) elif style_preset: # Priority 2: Preset style (use prompt from enum value) style_part = style_preset.value.prompt logger.debug(f"Using preset style: {style_preset.name}") # Step 2: Combine parts with comma parts = [p for p in [style_part, prompt] if p] final_prompt = ", ".join(parts) if final_prompt: logger.debug(f"Final image prompt: {final_prompt}") else: logger.warning("Generated empty image prompt") return final_prompt async def _convert_custom_style(self, description: str) -> str: """ Convert custom style description to English image prompt via LLM Args: description: User's style description in any language Returns: Converted English image prompt suitable for image generation models """ from reelforge.prompts import build_style_conversion_prompt # Build prompt using template llm_prompt = build_style_conversion_prompt(description) style_prompt = await self.core.llm(llm_prompt) # Clean up the result (remove extra whitespace, newlines) style_prompt = " ".join(style_prompt.strip().split()) logger.debug(f"Converted custom style to: {style_prompt}") return style_prompt