import logging from dataclasses import dataclass, field from typing import Dict, List, Optional logger = logging.getLogger(__name__) @dataclass class InpaintingTemplate: """Data class representing an inpainting template.""" key: str name: str category: str icon: str description: str # Prompt templates prompt_template: str negative_prompt: str # Recommended parameters controlnet_conditioning_scale: float = 0.7 feather_radius: int = 8 guidance_scale: float = 7.5 num_inference_steps: int = 25 # Conditioning type preference preferred_conditioning: str = "canny" # "canny" or "depth" # Difficulty level for UI display difficulty: str = "medium" # "easy", "medium", "advanced" # Tips for users usage_tips: List[str] = field(default_factory=list) class InpaintingTemplateManager: """ Manages inpainting templates for various use cases. Provides categorized presets optimized for different inpainting scenarios including object replacement, removal, style transfer, and enhancement. Attributes: TEMPLATES: Dictionary of all available templates CATEGORIES: List of category names in display order Example: >>> manager = InpaintingTemplateManager() >>> template = manager.get_template("object_replacement") >>> print(template.prompt_template) """ TEMPLATES: Dict[str, InpaintingTemplate] = { # Object Replacement Category "object_replacement": InpaintingTemplate( key="object_replacement", name="Object Replacement", category="Replacement", icon="πŸ”„", description="Replace selected objects with new content while preserving context", prompt_template="{content}, seamlessly integrated into scene, matching lighting and perspective, realistic placement", negative_prompt=( "inconsistent lighting, wrong perspective, mismatched colors, " "visible seams, floating objects, unrealistic placement, original object, " "poorly integrated, disconnected from scene, keeping original, remnants of original" ), controlnet_conditioning_scale=0.32, # Optimized: Lower for clean replacement (was 0.38) feather_radius=10, # Optimized: Tighter blending (was 14) guidance_scale=11.0, # Optimized: Higher for object accuracy (was 10.0) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="canny", # βœ… KEPT: Edge-based replacement difficulty="medium", usage_tips=[ "Draw mask PRECISELY around the object to replace (include small margin)", "Low conditioning (0.32) helps remove original object completely", "Be specific: Instead of 'plant', use 'large green potted fern with detailed leaves'", "πŸ“ Example prompts:", " β€’ 'elegant white ceramic teacup with delicate gold rim and floral pattern'", " β€’ 'modern silver laptop computer with sleek metallic finish'", " β€’ 'vintage wooden desk lamp with warm brass details'" ] ), "face_swap": InpaintingTemplate( key="face_swap", name="Face Enhancement", category="Replacement", icon="πŸ‘€", description="Enhance or modify facial features - SUBTLE adjustments only (skin, expression, lighting)", prompt_template="{content}, natural skin texture, proper facial proportions, realistic lighting, detailed facial features", negative_prompt=( "deformed face, asymmetric features, unnatural skin, " "plastic appearance, wrong eye direction, blurry features, " "artificial smoothing, uncanny valley, distorted proportions" ), controlnet_conditioning_scale=0.88, # Very high - preserves facial structure feather_radius=6, guidance_scale=8.5, num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="canny", difficulty="advanced", # ⚠️ Advanced: Faces are sensitive usage_tips=[ "⚠️ ADVANCED: Best for SUBTLE enhancements (skin tone, blemishes, expression)", "NOT for major changes (face shape, eye size, feature positions)", "Draw mask CAREFULLY around face outline (avoid hair and neck)", "High conditioning (0.88) preserves facial structure - only small modifications", "πŸ“ Example prompts:", " β€’ 'warm friendly smile with bright eyes and natural expression'", " β€’ 'professional headshot with confident neutral expression, clear smooth skin'", " β€’ 'gentle smile with soft natural lighting on face'" ] ), "clothing_change": InpaintingTemplate( key="clothing_change", name="Clothing Change", category="Replacement", icon="πŸ‘•", description="Change clothing color, pattern, style - preserves fabric folds and texture", prompt_template="CHANGE to {content}, vivid saturated color, natural fabric texture, proper folds and wrinkles, correct fit", negative_prompt=( "wrong body proportions, floating fabric, unrealistic wrinkles, " "mismatched lighting, visible edges, original clothing style, " "keeping same color, original color, faded colors, unchanged appearance, partial change, " "black clothing, dark original color" ), controlnet_conditioning_scale=0.30, # Optimized: Much lower for color change freedom (was 0.42) feather_radius=14, guidance_scale=11.5, # Optimized: Higher for color accuracy (was 10.5) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="depth", # βœ… KEPT: Preserves fabric folds and texture difficulty="easy", # βœ… Easy: Good success rate usage_tips=[ "βœ… BALANCED: Low conditioning (0.30) allows color change while depth preserves folds", "Works for both moderate and dramatic color changes (blackβ†’red now possible!)", "For extreme changes, be VERY specific with color: 'BRIGHT red', 'PURE white'", "πŸ“ Example prompts:", " β€’ 'BRIGHT red polo shirt with vivid saturated color, clean collar and soft fabric'", " β€’ 'deep navy blue formal blazer with fine texture and professional fit'", " β€’ 'PURE white dress shirt with crisp clean fabric'" ] ), "dramatic_color_change": InpaintingTemplate( key="dramatic_color_change", name="Dramatic Color Change", category="Replacement", icon="🎨", description="Extreme color transformations (dark↔light, black↔white) - especially for illustrations", prompt_template="COMPLETELY SOLID {content}, entire area pure color, all fabric same vivid color, no original color remaining", negative_prompt=( "original color, keeping same shade, partial change, color bleeding, " "faded colors, mixed tones, subtle change, gradual transition, " "original appearance, unchanged, dark remnants, light patches, " "black clothing, dark colors, keeping original darkness, " "black fabric, keeping black, original black color, dark body, " "partial color change, colored trim only, colored edges only, colored outline only, " "black body with colored decoration, original color body" ), controlnet_conditioning_scale=0.15, # Optimized: Extremely low for anime/illustration (was 0.25) feather_radius=16, guidance_scale=15.5, # Optimized: Very high for strong color adherence (was 13.5) num_inference_steps=10, # Optimized: 10 steps sufficient (was 12) preferred_conditioning="canny", # Optimized: Canny for color freedom (was depth) difficulty="medium", # ⚠️ Medium: Extreme changes challenging usage_tips=[ "βœ… OPTIMIZED for anime/illustration extreme color changes (black↔white, black↔red)", "Use COMPLETE descriptors: 'solid PURE WHITE', 'completely BRIGHT RED', 'entire garment JET BLACK'", "Very low conditioning (0.15) allows complete color transformation on flat-color illustrations", "Add 'completely', 'solid', 'entire', 'pure' to ensure full coverage", "πŸ“ Example prompts:", " β€’ 'solid PURE WHITE dress shirt, completely white fabric'", " β€’ 'completely JET BLACK leather jacket, entire garment black'", " β€’ 'solid BRIGHT RED polo shirt, all fabric vivid red, no black'" ] ), "clothing_addition": InpaintingTemplate( key="clothing_addition", name="Add Accessories", category="Replacement", icon="πŸ‘”", description="⚑ EXPERIMENTAL: Add ties, pockets, buttons to clothing - challenging, may require multiple attempts", prompt_template="{content}, clearly visible, highly detailed accessory, seamlessly integrated into clothing, proper placement and perspective", negative_prompt=( "missing details, incomplete, floating objects, disconnected, " "unrealistic placement, wrong perspective, blurry, poorly integrated, " "invisible, faint, unclear, hidden, absent, not visible" ), controlnet_conditioning_scale=0.20, # Optimized: Extremely low for object generation (was 0.25) feather_radius=12, guidance_scale=15.0, # Optimized: Very high for strong prompt adherence (was 14.0) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="canny", # Optimized: Canny for maximum freedom (was depth) difficulty="advanced", # ⚠️⚠️ ADVANCED: Low success rate, experimental usage_tips=[ "⚑⚑ EXPERIMENTAL FEATURE: Adding new objects is very challenging", "⚠️ Lower success rate due to complexity - may require multiple attempts", "Draw mask from NECK to CHEST (vertical strip) for ties, not just collar area", "Very low conditioning (0.20) gives model maximum freedom to generate new objects", "πŸ“ Example prompts:", " β€’ 'burgundy silk necktie with diagonal stripes and Windsor knot, hanging down from collar to chest'", " β€’ 'white pocket square with neat fold, visible in breast pocket'", " β€’ 'silver lapel pin with detailed engraving on left collar'", "πŸ’‘ TIP: For ties, mask should cover the entire length where tie should appear" ] ), # Object Removal Category "object_removal": InpaintingTemplate( key="object_removal", name="Object Removal", category="Removal", icon="πŸ—‘οΈ", description="Remove unwanted objects and fill with matching background", prompt_template="clean background, seamless continuation, {content}", negative_prompt=( "visible patches, color mismatch, texture inconsistency, " "ghost artifacts, blur spots, repeated patterns, visible seams, remnants" ), controlnet_conditioning_scale=0.42, # Optimized: Lower for cleaner removal (was 0.48) feather_radius=14, guidance_scale=8.5, # Optimized: Higher for accuracy (was 8.0) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="canny", # βœ… KEPT: Edge-based removal difficulty="easy", # βœ… Easy: Inpainting core strength usage_tips=[ "Draw mask slightly BEYOND object edges for better blending", "Lower conditioning (0.42) ensures complete removal without traces", "Describe what background SHOULD look like (e.g., 'grass lawn', 'wooden floor')", "πŸ“ Example prompts:", " β€’ 'clean grass lawn with natural green color'", " β€’ 'smooth wooden floor with consistent grain pattern'", " β€’ 'plain white wall with even texture'" ] ), "watermark_removal": InpaintingTemplate( key="watermark_removal", name="Watermark Removal", category="Removal", icon="πŸ’§", description="Remove watermarks and text overlays", prompt_template="clean image, no text, seamless background, {content}", negative_prompt=( "text, watermark, logo, signature, letters, numbers, visible artifacts, " "color inconsistency, blur, remnants, ghost text" ), controlnet_conditioning_scale=0.40, # Optimized: Lower for complete removal (was 0.45) feather_radius=12, guidance_scale=9.0, # Optimized: Higher for clean result (was 8.5) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="canny", # βœ… KEPT: Edge-based removal difficulty="easy", # βœ… Easy: Good success rate usage_tips=[ "Draw mask covering ALL watermark/text areas precisely", "Lower conditioning (0.40) ensures watermark disappears completely", "Describe what SHOULD be there instead (e.g., 'sky', 'fabric texture')", "πŸ“ Example prompts:", " β€’ 'clean blue sky with smooth gradient'", " β€’ 'natural skin texture without marks'", " β€’ 'smooth fabric surface with consistent color'" ] ), "blemish_removal": InpaintingTemplate( key="blemish_removal", name="Blemish Removal", category="Removal", icon="✨", description="Remove skin blemishes, scratches, or small imperfections", prompt_template="clean smooth surface, natural texture, {content}", negative_prompt=( "artificial smoothing, plastic texture, visible editing, " "color patches, unnatural appearance, over-processed" ), controlnet_conditioning_scale=0.6, feather_radius=6, guidance_scale=6.5, num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="canny", difficulty="easy", # βœ… Easy: Small areas, high success usage_tips=[ "Draw small precise masks for EACH blemish/imperfection", "Lower guidance (6.5) preserves natural skin texture", "πŸ“ Example prompts:", " β€’ 'natural clean skin with smooth texture'", " β€’ 'smooth surface without scratches or marks'", " β€’ 'clear skin with natural pores and texture'" ] ), # Style Transfer Category "style_artistic": InpaintingTemplate( key="style_artistic", name="Artistic Style", category="Style", icon="🎨", description="Apply artistic style to selected region", prompt_template="{content}, distinctive artistic style, strong painterly effect, creative interpretation, visible brushstrokes", negative_prompt=( "photorealistic, plain, boring, low contrast, unchanged, " "inconsistent style, harsh transitions, original appearance, realistic photo" ), controlnet_conditioning_scale=0.42, # Optimized: Lower for style freedom (was 0.52) feather_radius=12, guidance_scale=12.5, # Optimized: Higher for style accuracy (was 11.5) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="canny", # βœ… KEPT: Edge-based styling difficulty="medium", # ⚠️ Medium: Style changes need steps usage_tips=[ "Works best on larger areas (faces, clothing, backgrounds) for visible transformation", "Lower conditioning (0.42) allows artistic reinterpretation", "Be VERY specific about art style for best results", "πŸ“ Example prompts:", " β€’ 'impressionist oil painting with visible thick brushstrokes and vibrant colors'", " β€’ 'watercolor painting with soft edges and delicate color washes'", " β€’ 'Van Gogh style with swirling brushstrokes and bold color contrasts'" ] ), "style_vintage": InpaintingTemplate( key="style_vintage", name="Vintage Look", category="Style", icon="πŸ“»", description="Apply vintage or retro aesthetic to selected area", prompt_template="{content}, strong vintage aesthetic, warm sepia tones, film grain texture, nostalgic atmosphere", negative_prompt=( "modern, digital, cold colors, harsh contrast, " "oversaturated, neon colors, contemporary look, clean digital, crisp" ), controlnet_conditioning_scale=0.45, # Optimized: Lower for style freedom (was 0.55) feather_radius=14, guidance_scale=11.0, # Optimized: Higher for era accuracy (was 10.5) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="depth", # Optimized: Depth for texture/grain (was canny) difficulty="medium", # ⚠️ Medium: Color/texture adjustments usage_tips=[ "Works best on medium to large regions for visible aesthetic change", "Depth conditioning preserves texture while applying vintage look", "Specify era and style for best results", "πŸ“ Example prompts:", " β€’ '1920s sepia photograph with faded brown tones and soft grain'", " β€’ '1970s vintage photo with warm orange tones and slight film grain'", " β€’ '1950s Kodachrome with saturated warm colors and nostalgic feel'" ] ), "style_anime": InpaintingTemplate( key="style_anime", name="Anime Style", category="Style", icon="🎌", description="⚑ Transform to anime style - dramatic change, may need multiple attempts", prompt_template="{content}, anime illustration style, clean sharp lines, vibrant saturated colors, cel-shaded with flat colors", negative_prompt=( "photorealistic, blurry lines, muddy colors, realistic photo, " "3D render, uncanny valley, western cartoon, gradient shading, photographic" ), controlnet_conditioning_scale=0.35, # Optimized: Lower for dramatic style change (was 0.48) feather_radius=10, guidance_scale=14.0, # Optimized: Higher for style accuracy (was 12.5) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="canny", difficulty="advanced", # ⚠️ Advanced: Extreme style transformation usage_tips=[ "⚑ DRAMATIC transformation - best for portraits and characters", "⚠️ Significant stylistic changes require good source image quality", "Lower conditioning (0.35) allows dramatic style transformation", "Expect anime-style interpretation, not exact anime conversion", "πŸ“ Example prompts:", " β€’ 'modern anime style with large expressive eyes and vibrant colors'", " β€’ 'Studio Ghibli style with soft features and warm color palette'", " β€’ 'manga style with clean black lines and cel-shaded coloring'" ] ), # Detail Enhancement Category "detail_enhance": InpaintingTemplate( key="detail_enhance", name="Detail Enhancement", category="Enhancement", icon="πŸ”", description="Add fine details and textures to selected area", prompt_template="{content}, highly detailed, intricate textures, fine details, sharp focus", negative_prompt=( "blurry, smooth, low detail, soft focus, " "oversimplified, lacking texture" ), controlnet_conditioning_scale=0.85, # Very high - preserves structure feather_radius=4, guidance_scale=8.0, num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="depth", difficulty="easy", # βœ… Easy: Enhancement not generation usage_tips=[ "High conditioning (0.85) preserves overall structure while adding detail", "Best for adding fine details to existing objects", "πŸ“ Example prompts:", " β€’ 'highly detailed fabric with visible weave and fine threads'", " β€’ 'intricate wood grain with natural knots and detailed texture'", " β€’ 'sharp facial features with fine skin pores and detail'" ] ), "texture_add": InpaintingTemplate( key="texture_add", name="Texture Addition", category="Enhancement", icon="🧱", description="Add or enhance surface textures", prompt_template="{content} texture, realistic surface detail, natural material appearance", negative_prompt=( "flat, smooth, unrealistic, plastic, " "wrong material, inconsistent texture" ), controlnet_conditioning_scale=0.8, # High - preserves shape feather_radius=5, guidance_scale=7.5, num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="depth", difficulty="easy", # βœ… Easy: Texture overlay usage_tips=[ "Specify material type clearly for best results", "Depth conditioning preserves 3D form while changing texture", "πŸ“ Example prompts:", " β€’ 'rough wood texture with natural grain and knots'", " β€’ 'soft cotton fabric with gentle weave pattern'", " β€’ 'smooth marble surface with subtle veining'" ] ), "lighting_fix": InpaintingTemplate( key="lighting_fix", name="Lighting Correction", category="Enhancement", icon="πŸ’‘", description="Correct or enhance lighting in selected area", prompt_template="{content}, proper lighting, natural shadows, balanced exposure", negative_prompt=( "harsh shadows, overexposed, underexposed, " "flat lighting, unnatural highlights" ), controlnet_conditioning_scale=0.65, feather_radius=15, # Large for smooth transitions guidance_scale=7.0, num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="depth", difficulty="easy", # βœ… Easy: Lighting adjustments usage_tips=[ "Use large feather (15px) for smooth lighting transitions", "Best for fixing uneven lighting or adding natural light", "πŸ“ Example prompts:", " β€’ 'soft natural lighting from window, gentle shadows'", " β€’ 'balanced exposure with warm golden hour light'", " β€’ 'even studio lighting with soft diffused shadows'" ] ), # Background Category "background_extend": InpaintingTemplate( key="background_extend", name="Background Extension", category="Background", icon="πŸ“", description="Extend image background seamlessly", prompt_template="seamless background extension, {content}, consistent style and lighting", negative_prompt=( "visible seams, style mismatch, lighting inconsistency, " "repeated elements, unnatural continuation, abrupt changes" ), controlnet_conditioning_scale=0.45, # Optimized: Lower for extension freedom (was 0.55) feather_radius=20, # Largest for smooth blending guidance_scale=8.5, # Optimized: Higher for consistency (was 8.0) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="canny", # βœ… KEPT: Edge-based extension difficulty="medium", # ⚠️ Medium: Needs consistency usage_tips=[ "Draw mask on area to extend (edges of image)", "Large feather (20px) ensures smooth blending with existing background", "Canny conditioning focuses on edges for seamless continuation", "πŸ“ Example prompts:", " β€’ 'continue the wooden floor with same grain pattern'", " β€’ 'extend blue sky with matching clouds and lighting'", " β€’ 'seamless continuation of brick wall texture'" ] ), "background_replace": InpaintingTemplate( key="background_replace", name="Background Replacement", category="Background", icon="πŸ–ΌοΈ", description="Replace background while keeping subject intact", prompt_template="{content}, professional background scene, seamless integration with subject, matching lighting and atmosphere", negative_prompt=( "floating subject, inconsistent lighting, disconnected, " "wrong perspective, visible edges, color mismatch, original background, " "poor integration, obvious composite" ), controlnet_conditioning_scale=0.48, # Optimized: Lower for background freedom (was 0.60) feather_radius=12, guidance_scale=10.5, # Optimized: Higher for scene accuracy (was 9.5) num_inference_steps=10, # Optimized: 10 steps (was 12) preferred_conditioning="depth", # βœ… KEPT: Preserves depth relationships difficulty="medium", # ⚠️ Medium: Large area replacement usage_tips=[ "Draw mask around ENTIRE background (leave subject unmasked with small margin)", "Depth conditioning (0.48) preserves subject-background spatial relationship", "Include lighting description to match subject for natural results", "πŸ“ Example prompts:", " β€’ 'professional photography studio with white backdrop and soft lighting'", " β€’ 'modern minimalist office with white walls and bright natural lighting'", " β€’ 'sunny beach with blue ocean and golden hour lighting'" ] ), } # Category display order CATEGORIES = ["Replacement", "Removal", "Style", "Enhancement", "Background"] def __init__(self): """Initialize the InpaintingTemplateManager.""" logger.info(f"InpaintingTemplateManager initialized with {len(self.TEMPLATES)} templates") def get_all_templates(self) -> Dict[str, InpaintingTemplate]: """ Get all available templates. Returns ------- dict Dictionary of all templates keyed by template key """ return self.TEMPLATES def get_template(self, key: str) -> Optional[InpaintingTemplate]: """ Get a specific template by key. Parameters ---------- key : str Template identifier Returns ------- InpaintingTemplate or None Template if found, None otherwise """ return self.TEMPLATES.get(key) def get_templates_by_category(self, category: str) -> List[InpaintingTemplate]: """ Get all templates in a specific category. Parameters ---------- category : str Category name Returns ------- list List of templates in the category """ return [t for t in self.TEMPLATES.values() if t.category == category] def get_categories(self) -> List[str]: """ Get list of all categories in display order. Returns ------- list Category names """ return self.CATEGORIES def get_template_choices_sorted(self) -> List[str]: """ Get template choices formatted for Gradio dropdown. Returns list of display strings sorted by category then A-Z. Format: "icon Name" Returns ------- list Formatted display strings for dropdown """ display_list = [] for category in self.CATEGORIES: templates = self.get_templates_by_category(category) for template in sorted(templates, key=lambda t: t.name): display_name = f"{template.icon} {template.name}" display_list.append(display_name) return display_list def get_template_key_from_display(self, display_name: str) -> Optional[str]: """ Get template key from display name. Parameters ---------- display_name : str Display string like "πŸ”„ Object Replacement" Returns ------- str or None Template key if found """ if not display_name: return None for key, template in self.TEMPLATES.items(): if f"{template.icon} {template.name}" == display_name: return key return None def get_parameters_for_template(self, key: str) -> Dict[str, any]: """ Get recommended parameters for a template. Parameters ---------- key : str Template key Returns ------- dict Dictionary of parameter names and values """ template = self.get_template(key) if not template: return {} return { "controlnet_conditioning_scale": template.controlnet_conditioning_scale, "feather_radius": template.feather_radius, "guidance_scale": template.guidance_scale, "num_inference_steps": template.num_inference_steps, "preferred_conditioning": template.preferred_conditioning } def build_prompt(self, key: str, content: str) -> str: """ Build complete prompt from template and user content. Parameters ---------- key : str Template key content : str User-provided content description Returns ------- str Formatted prompt with content inserted """ template = self.get_template(key) if not template: return content return template.prompt_template.format(content=content) def get_negative_prompt(self, key: str) -> str: """ Get negative prompt for a template. Parameters ---------- key : str Template key Returns ------- str Negative prompt string """ template = self.get_template(key) if not template: return "" return template.negative_prompt def get_usage_tips(self, key: str) -> List[str]: """ Get usage tips for a template. Parameters ---------- key : str Template key Returns ------- list List of tip strings """ template = self.get_template(key) if not template: return [] return template.usage_tips def build_gallery_html(self) -> str: """ Build HTML for template gallery display. Returns ------- str HTML string for Gradio display """ html_parts = ['') return ''.join(html_parts)