DawnC commited on
Commit
d20ba1a
·
verified ·
1 Parent(s): 59d17e6

Update scene_templates.py

Browse files
Files changed (1) hide show
  1. scene_templates.py +384 -347
scene_templates.py CHANGED
@@ -1,297 +1,336 @@
1
  import logging
 
2
  from typing import Dict, List, Optional
3
- from dataclasses import dataclass
4
 
5
  logger = logging.getLogger(__name__)
6
 
 
7
  @dataclass
8
- class SceneTemplate:
9
- """Data class representing a scene template"""
 
10
  key: str
11
  name: str
12
- prompt: str
13
- negative_extra: str
14
  category: str
15
  icon: str
 
 
 
 
 
 
 
 
 
16
  guidance_scale: float = 7.5
 
17
 
 
 
 
18
 
19
- class SceneTemplateManager:
20
- """
21
- Manages curated scene templates for background generation.
22
- Provides categorized presets that users can select with one click.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  """
 
24
 
25
- # Scene template definitions
26
- TEMPLATES: Dict[str, SceneTemplate] = {
27
- # Professional Category
28
- "office_modern": SceneTemplate(
29
- key="office_modern",
30
- name="Modern Office",
31
- prompt="modern minimalist office interior, clean white desk, large floor-to-ceiling windows, natural daylight, professional corporate environment, soft shadows, contemporary furniture",
32
- negative_extra="messy, cluttered, dark, old",
33
- category="Professional",
34
- icon="🏢",
35
- guidance_scale=7.5
36
- ),
37
- "office_executive": SceneTemplate(
38
- key="office_executive",
39
- name="Executive Suite",
40
- prompt="luxurious executive office, mahogany desk, leather chair, city skyline view through windows, warm ambient lighting, bookshelf, elegant professional setting",
41
- negative_extra="cheap, cramped, messy",
42
- category="Professional",
43
- icon="👔",
44
- guidance_scale=7.5
45
- ),
46
- "studio_white": SceneTemplate(
47
- key="studio_white",
48
- name="White Studio",
49
- prompt="clean white photography studio background, professional lighting setup, seamless white backdrop, soft diffused light, minimal shadows",
50
- negative_extra="colored, textured, dirty",
51
- category="Professional",
52
- icon="📷",
53
- guidance_scale=8.0
54
- ),
55
- "coworking": SceneTemplate(
56
- key="coworking",
57
- name="Coworking Space",
58
- prompt="modern coworking space, open plan office, plants, exposed brick, industrial chic design, natural light, collaborative environment",
59
- negative_extra="empty, dark, boring",
60
- category="Professional",
61
- icon="💼",
62
- guidance_scale=7.0
63
- ),
64
- "conference": SceneTemplate(
65
- key="conference",
66
- name="Conference Room",
67
- prompt="modern conference room, large meeting table, glass walls, professional presentation screen, bright corporate lighting, clean minimal design",
68
- negative_extra="small, cramped, outdated",
69
- category="Professional",
70
- icon="🤝",
71
- guidance_scale=7.5
72
- ),
73
 
74
- # Nature Category
75
- "beach_sunset": SceneTemplate(
76
- key="beach_sunset",
77
- name="Sunset Beach",
78
- prompt="beautiful tropical beach at golden hour sunset, palm trees silhouette, calm turquoise ocean waves, warm orange and pink sky, soft sand, paradise vacation vibes",
79
- negative_extra="storm, rain, crowded, trash",
80
- category="Nature",
81
- icon="🏖️",
82
- guidance_scale=7.0
83
- ),
84
- "forest_enchanted": SceneTemplate(
85
- key="forest_enchanted",
86
- name="Enchanted Forest",
87
- prompt="magical enchanted forest, sunlight streaming through tall trees, lush green foliage, mystical atmosphere, morning mist, fairy tale woodland",
88
- negative_extra="dead trees, dark, scary, barren",
89
- category="Nature",
90
- icon="🌲",
91
- guidance_scale=7.0
92
- ),
93
- "mountain_scenic": SceneTemplate(
94
- key="mountain_scenic",
95
- name="Mountain Vista",
96
- prompt="breathtaking mountain landscape, snow-capped peaks, alpine meadow, clear blue sky, majestic scenic view, pristine nature, peaceful atmosphere",
97
- negative_extra="industrial, polluted, crowded",
98
- category="Nature",
99
- icon="🏔️",
100
- guidance_scale=7.5
101
- ),
102
- "garden_spring": SceneTemplate(
103
- key="garden_spring",
104
- name="Spring Garden",
105
- prompt="beautiful spring flower garden, colorful blooming flowers, roses and tulips, manicured hedges, sunny day, botanical paradise, fresh and vibrant",
106
- negative_extra="dead, winter, wilted, dry",
107
- category="Nature",
108
- icon="🌸",
109
- guidance_scale=7.0
110
- ),
111
- "lake_serene": SceneTemplate(
112
- key="lake_serene",
113
- name="Serene Lake",
114
- prompt="peaceful serene lake at dawn, mirror-like water reflection, surrounding mountains, soft morning light, tranquil atmosphere, pristine natural beauty",
115
- negative_extra="stormy, polluted, industrial",
116
- category="Nature",
117
- icon="🏞️",
118
- guidance_scale=7.0
119
- ),
120
- "cherry_blossom": SceneTemplate(
121
- key="cherry_blossom",
122
- name="Cherry Blossom",
123
- prompt="stunning cherry blossom trees in full bloom, pink sakura petals falling gently, Japanese garden aesthetic, soft spring sunlight, romantic atmosphere",
124
- negative_extra="winter, dead, brown, wilted",
125
- category="Nature",
126
- icon="🌸",
127
- guidance_scale=7.0
128
- ),
129
 
130
- # Urban Category
131
- "city_skyline": SceneTemplate(
132
- key="city_skyline",
133
- name="City Skyline",
134
- prompt="modern city skyline at blue hour, impressive skyscrapers, glass buildings reflecting sunset, urban metropolitan view, cinematic atmosphere",
135
- negative_extra="slums, dirty, abandoned, ruins",
136
- category="Urban",
137
- icon="🌆",
138
- guidance_scale=7.5
139
- ),
140
- "cafe_cozy": SceneTemplate(
141
- key="cafe_cozy",
142
- name="Cozy Cafe",
143
- prompt="warm cozy coffee shop interior, wooden furniture, ambient lighting, exposed brick walls, plants, comfortable atmosphere, artisan cafe vibes",
144
- negative_extra="fast food, plastic, harsh lighting",
145
- category="Urban",
146
- icon="☕",
147
- guidance_scale=7.0
148
- ),
149
- "street_european": SceneTemplate(
150
- key="street_european",
151
- name="European Street",
152
- prompt="charming European cobblestone street, historic buildings, outdoor cafe, flowers on balconies, warm afternoon light, romantic Paris or Rome vibes",
153
- negative_extra="modern, industrial, ugly, dirty",
154
- category="Urban",
155
- icon="🏛️",
156
- guidance_scale=7.0
157
- ),
158
- "night_neon": SceneTemplate(
159
- key="night_neon",
160
- name="Neon Nightlife",
161
- prompt="vibrant city nightlife scene, neon lights and signs, urban night atmosphere, colorful reflections on wet street, cyberpunk aesthetic, electric energy",
162
- negative_extra="daytime, boring, plain",
163
- category="Urban",
164
- icon="🌃",
165
- guidance_scale=6.5
166
- ),
167
- "rooftop_view": SceneTemplate(
168
- key="rooftop_view",
169
- name="Rooftop Terrace",
170
- prompt="luxury rooftop terrace, city panoramic view, modern outdoor furniture, string lights, sunset golden hour, sophisticated urban oasis",
171
- negative_extra="cheap, dirty, crowded",
172
- category="Urban",
173
- icon="🏙️",
174
- guidance_scale=7.5
175
- ),
176
 
177
- # Artistic Category
178
- "gradient_soft": SceneTemplate(
179
- key="gradient_soft",
180
- name="Soft Gradient",
181
- prompt="smooth soft gradient background, pastel colors blending beautifully, pink to blue to purple transition, dreamy aesthetic, professional portrait backdrop",
182
- negative_extra="harsh, noisy, textured, busy",
183
- category="Artistic",
 
 
 
184
  icon="🎨",
185
- guidance_scale=8.0
186
- ),
187
- "abstract_modern": SceneTemplate(
188
- key="abstract_modern",
189
- name="Modern Abstract",
190
- prompt="modern abstract art background, geometric shapes, bold colors, contemporary design, artistic composition, museum gallery aesthetic",
191
- negative_extra="realistic, plain, boring",
192
- category="Artistic",
193
- icon="🖼️",
194
- guidance_scale=6.5
195
- ),
196
- "vintage_retro": SceneTemplate(
197
- key="vintage_retro",
198
- name="Vintage Retro",
199
- prompt="vintage retro aesthetic background, warm sepia tones, nostalgic 70s vibes, film grain texture, classic photography style, timeless elegance",
200
- negative_extra="modern, digital, cold, harsh",
201
- category="Artistic",
202
- icon="📻",
203
- guidance_scale=7.0
204
- ),
205
- "watercolor_dream": SceneTemplate(
206
- key="watercolor_dream",
207
- name="Watercolor Dream",
208
- prompt="beautiful watercolor painting background, soft flowing colors, artistic brush strokes, dreamy ethereal atmosphere, delicate artistic aesthetic",
209
- negative_extra="digital, sharp, photorealistic",
210
- category="Artistic",
211
- icon="🖌️",
212
- guidance_scale=6.5
 
 
 
 
 
 
 
 
213
  ),
214
 
215
- # Seasonal Category
216
- "autumn_foliage": SceneTemplate(
217
- key="autumn_foliage",
218
- name="Autumn Foliage",
219
- prompt="beautiful autumn scenery, vibrant fall foliage, orange red and golden leaves, maple trees, warm sunlight filtering through, cozy seasonal atmosphere",
220
- negative_extra="spring, summer, green, snow",
221
- category="Seasonal",
222
- icon="🍂",
223
- guidance_scale=7.0
224
- ),
225
- "winter_snow": SceneTemplate(
226
- key="winter_snow",
227
- name="Winter Wonderland",
228
- prompt="magical winter wonderland, fresh white snow covering everything, snow-laden pine trees, soft snowfall, peaceful cold atmosphere, holiday season vibes",
229
- negative_extra="summer, green, rain, mud",
230
- category="Seasonal",
231
- icon="❄️",
232
- guidance_scale=7.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  ),
234
- "summer_tropical": SceneTemplate(
235
- key="summer_tropical",
236
- name="Tropical Summer",
237
- prompt="vibrant tropical summer scene, lush palm trees, bright sunny day, exotic flowers, paradise vacation destination, warm and inviting atmosphere",
238
- negative_extra="winter, cold, snow, gray",
239
- category="Seasonal",
240
- icon="🌴",
241
- guidance_scale=7.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  ),
243
- "spring_meadow": SceneTemplate(
244
- key="spring_meadow",
245
- name="Spring Meadow",
246
- prompt="beautiful spring meadow, wildflowers blooming, fresh green grass, butterflies, soft warm sunlight, renewal and new beginnings, pastoral beauty",
247
- negative_extra="winter, autumn, dead, dry",
248
- category="Seasonal",
249
- icon="🌷",
250
- guidance_scale=7.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  ),
252
  }
253
 
 
254
  # Category display order
255
- CATEGORIES = ["Professional", "Nature", "Urban", "Artistic", "Seasonal"]
256
 
257
  def __init__(self):
258
- """Initialize the scene template manager"""
259
- logger.info(f"SceneTemplateManager initialized with {len(self.TEMPLATES)} templates")
 
 
 
 
260
 
261
- def get_all_templates(self) -> Dict[str, SceneTemplate]:
262
- """Get all available templates"""
 
 
 
263
  return self.TEMPLATES
264
 
265
- def get_template(self, key: str) -> Optional[SceneTemplate]:
266
- """Get a specific template by key"""
 
 
 
 
 
 
 
 
 
 
 
 
267
  return self.TEMPLATES.get(key)
268
 
269
- def get_templates_by_category(self, category: str) -> List[SceneTemplate]:
270
- """Get all templates in a specific category"""
 
 
 
 
 
 
 
 
 
 
 
 
271
  return [t for t in self.TEMPLATES.values() if t.category == category]
272
 
273
  def get_categories(self) -> List[str]:
274
- """Get list of all categories in display order"""
 
 
 
 
 
 
 
275
  return self.CATEGORIES
276
 
277
  def get_template_choices_sorted(self) -> List[str]:
278
  """
279
  Get template choices formatted for Gradio dropdown.
280
- Returns list of display strings sorted A-Z: "🏢 Modern Office"
 
 
 
 
 
 
 
281
  """
282
  display_list = []
283
- for key, template in self.TEMPLATES.items():
284
- display_name = f"{template.icon} {template.name}"
285
- display_list.append(display_name)
286
 
287
- # Sort alphabetically by name (ignoring emoji)
288
- display_list.sort(key=lambda x: x.split(' ', 1)[1] if ' ' in x else x)
 
 
 
 
289
  return display_list
290
 
291
  def get_template_key_from_display(self, display_name: str) -> Optional[str]:
292
  """
293
  Get template key from display name.
294
- Example: "🏢 Modern Office" -> "office_modern"
 
 
 
 
 
 
 
 
 
295
  """
296
  if not display_name:
297
  return None
@@ -301,33 +340,105 @@ class SceneTemplateManager:
301
  return key
302
  return None
303
 
304
- def get_prompt_for_template(self, key: str) -> Optional[str]:
305
- """Get the prompt string for a template"""
 
 
 
 
 
 
 
 
 
 
 
 
306
  template = self.get_template(key)
307
- return template.prompt if template else None
308
-
309
- def get_negative_prompt_for_template(
310
- self,
311
- key: str,
312
- base_negative: str = "blurry, low quality, distorted, people, characters"
313
- ) -> str:
314
- """Get combined negative prompt for a template"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  template = self.get_template(key)
316
- if template and template.negative_extra:
317
- return f"{base_negative}, {template.negative_extra}"
318
- return base_negative
 
 
 
 
 
 
 
 
 
 
319
 
320
- def get_guidance_scale_for_template(self, key: str) -> float:
321
- """Get the recommended guidance scale for a template"""
 
 
 
322
  template = self.get_template(key)
323
- return template.guidance_scale if template else 7.5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
 
325
  def build_gallery_html(self) -> str:
326
  """
327
- Build HTML for the scene template gallery.
328
- Returns HTML string for display in Gradio.
 
 
 
 
329
  """
330
- html_parts = ['<div class="scene-gallery">']
331
 
332
  for category in self.CATEGORIES:
333
  templates = self.get_templates_by_category(category)
@@ -335,95 +446,21 @@ class SceneTemplateManager:
335
  continue
336
 
337
  html_parts.append(f'''
338
- <div class="scene-category">
339
- <h4 class="scene-category-title">{category}</h4>
340
- <div class="scene-grid">
341
  ''')
342
 
343
- for template in templates:
344
  html_parts.append(f'''
345
- <button class="scene-card" data-template="{template.key}" onclick="selectTemplate('{template.key}')">
346
- <span class="scene-icon">{template.icon}</span>
347
- <span class="scene-name">{template.name}</span>
348
- </button>
 
349
  ''')
350
 
351
  html_parts.append('</div></div>')
352
 
353
  html_parts.append('</div>')
354
- return ''.join(html_parts)
355
-
356
- def get_gallery_css(self) -> str:
357
- """Get CSS styles for the scene gallery"""
358
- return """
359
- /* Scene Gallery Styles */
360
- .scene-gallery {
361
- margin: 16px 0;
362
- }
363
-
364
- .scene-category {
365
- margin-bottom: 20px;
366
- }
367
-
368
- .scene-category-title {
369
- font-size: 0.9rem;
370
- font-weight: 600;
371
- color: #475569;
372
- margin-bottom: 12px;
373
- padding-bottom: 8px;
374
- border-bottom: 1px solid #e2e8f0;
375
- }
376
-
377
- .scene-grid {
378
- display: grid;
379
- grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
380
- gap: 8px;
381
- }
382
-
383
- .scene-card {
384
- display: flex;
385
- flex-direction: column;
386
- align-items: center;
387
- justify-content: center;
388
- padding: 12px 8px;
389
- background: #f8fafc;
390
- border: 1px solid #e2e8f0;
391
- border-radius: 8px;
392
- cursor: pointer;
393
- transition: all 0.2s ease;
394
- min-height: 70px;
395
- }
396
-
397
- .scene-card:hover {
398
- background: #dbeafe;
399
- border-color: #3b82f6;
400
- transform: translateY(-2px);
401
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
402
- }
403
-
404
- .scene-card.selected {
405
- background: #dbeafe;
406
- border-color: #3b82f6;
407
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3);
408
- }
409
-
410
- .scene-icon {
411
- font-size: 1.5rem;
412
- margin-bottom: 4px;
413
- }
414
-
415
- .scene-name {
416
- font-size: 0.75rem;
417
- font-weight: 500;
418
- color: #1e293b;
419
- text-align: center;
420
- line-height: 1.2;
421
- }
422
-
423
- @media (max-width: 768px) {
424
- .scene-grid {
425
- grid-template-columns: repeat(3, 1fr);
426
- }
427
- }
428
- """
429
-
 
1
  import logging
2
+ from dataclasses import dataclass, field
3
  from typing import Dict, List, Optional
 
4
 
5
  logger = logging.getLogger(__name__)
6
 
7
+
8
  @dataclass
9
+ class InpaintingTemplate:
10
+ """Data class representing an inpainting template."""
11
+
12
  key: str
13
  name: str
 
 
14
  category: str
15
  icon: str
16
+ description: str
17
+
18
+ # Prompt templates
19
+ prompt_template: str
20
+ negative_prompt: str
21
+
22
+ # Recommended parameters
23
+ controlnet_conditioning_scale: float = 0.7
24
+ feather_radius: int = 8
25
  guidance_scale: float = 7.5
26
+ num_inference_steps: int = 25
27
 
28
+ # Inpainting strength (0.0-1.0)
29
+ # 1.0 = fully repaint masked area, 0.0 = keep original
30
+ strength: float = 1.0
31
 
32
+ # Conditioning type preference
33
+ preferred_conditioning: str = "canny" # "canny" or "depth"
34
+
35
+ # Structure preservation in masked area
36
+ # True = keep edges in mask (for color change), False = clear edges (for replacement/removal)
37
+ preserve_structure_in_mask: bool = False
38
+
39
+ # Prompt enhancement control
40
+ enhance_prompt: bool = True # Whether to use OpenCLIP prompt enhancement
41
+
42
+ # Difficulty level for UI display
43
+ difficulty: str = "medium" # "easy", "medium", "advanced"
44
+
45
+ # Tips for users
46
+ usage_tips: List[str] = field(default_factory=list)
47
+
48
+
49
+ class InpaintingTemplateManager:
50
  """
51
+ Manages inpainting templates for various use cases.
52
 
53
+ Provides categorized presets optimized for different inpainting scenarios
54
+ including object replacement, removal, style transfer, and enhancement.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ Attributes:
57
+ TEMPLATES: Dictionary of all available templates
58
+ CATEGORIES: List of category names in display order
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
+ Example:
61
+ >>> manager = InpaintingTemplateManager()
62
+ >>> template = manager.get_template("object_replacement")
63
+ >>> print(template.prompt_template)
64
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
+ TEMPLATES: Dict[str, InpaintingTemplate] = {
67
+ # ========================================
68
+ # 4 CORE TEMPLATES - Optimized for Speed & Quality
69
+ # ========================================
70
+
71
+ # 1. CHANGE COLOR - Pure color transformation
72
+ "change_color": InpaintingTemplate(
73
+ key="change_color",
74
+ name="Change Color",
75
+ category="Color",
76
  icon="🎨",
77
+ description="Change color ONLY - fills the masked area with a solid, flat color",
78
+ prompt_template="{content} color, solid flat {content}, uniform color, no patterns, smooth surface",
79
+ negative_prompt=(
80
+ "original color, keeping same color, unchanged color, "
81
+ "black, dark, keeping black, maintaining black color, "
82
+ "black clothing, dark colors, dark fabric, black fabric, "
83
+ "patterns, floral, stripes, plaid, checkered, decorative patterns, "
84
+ "diamond pattern, grid pattern, geometric patterns, "
85
+ "texture, textured, wrinkles, folds, creases, "
86
+ "gradients, shading variations, color variations, "
87
+ "complex patterns, printed patterns, embroidery"
88
+ ),
89
+ controlnet_conditioning_scale=0.3, # Low-medium: allow color freedom in masked area
90
+ feather_radius=4, # Low: clean color boundaries
91
+ guidance_scale=15.0, # Very high: strongly follow color prompt
92
+ num_inference_steps=10, # Optimized for speed
93
+ strength=1.0, # Full repaint for color change
94
+ preferred_conditioning="canny", # Edge-based
95
+ preserve_structure_in_mask=False, # KEY: clear edges in mask for pure color fill
96
+ enhance_prompt=False, # Disabled: use color prompt directly
97
+ difficulty="easy",
98
+ usage_tips=[
99
+ "🎯 Purpose: Fill the masked area with a solid, uniform color.",
100
+ "",
101
+ "📝 Example Prompts:",
102
+ " • 'vibrant red' - bold, saturated red",
103
+ " • 'soft pastel pink' - gentle, light pink",
104
+ " • 'deep navy blue' - rich, dark blue",
105
+ " • 'bright yellow' - eye-catching yellow",
106
+ " • 'pure white' - clean, solid white",
107
+ "",
108
+ "💡 Tips:",
109
+ " • Describe ONLY the color, not the object",
110
+ " • Paint the entire area you want to recolor",
111
+ " • Use modifiers: 'bright', 'dark', 'pastel', 'vivid'"
112
+ ]
113
  ),
114
 
115
+ # 2. CLOTHING CHANGE - Style and garment transformation
116
+ "clothing_change": InpaintingTemplate(
117
+ key="clothing_change",
118
+ name="Clothing Change",
119
+ category="Replacement",
120
+ icon="👕",
121
+ description="Change clothing style, material, or design - can include color change",
122
+ prompt_template="{content}, photorealistic, realistic fabric texture, natural fit, high quality",
123
+ negative_prompt=(
124
+ "wrong body proportions, floating fabric, unrealistic wrinkles, "
125
+ "mismatched lighting, visible edges, original clothing style, "
126
+ "keeping same color, original color, faded colors, unchanged appearance, partial change, "
127
+ "black clothing, dark original color, distorted body, naked, nudity, "
128
+ "cartoon, anime, illustration, drawing, painted"
129
+ ),
130
+ controlnet_conditioning_scale=0.30, # Medium: preserves body structure, allows clothing change
131
+ feather_radius=14, # Medium: natural blending with body
132
+ guidance_scale=11.5, # Medium-high: accurate clothing generation
133
+ num_inference_steps=10, # Optimized for speed
134
+ strength=1.0, # Full repaint: completely replace clothing
135
+ preferred_conditioning="depth", # Depth: preserves fabric folds and body structure
136
+ enhance_prompt=True, # Enabled: enriches clothing details
137
+ difficulty="easy",
138
+ usage_tips=[
139
+ "🎯 Purpose: Replace clothing with a different style, material, or design.",
140
+ "",
141
+ "📝 Example Prompts:",
142
+ " • 'tailored charcoal suit with silk tie and white shirt' - formal business",
143
+ " • 'navy blazer with gold buttons over light blue oxford shirt' - smart casual",
144
+ " • 'black tuxedo with bow tie and white dress shirt' - elegant formal",
145
+ " • 'white polo shirt with collar' - casual business",
146
+ " • 'cozy cream knit sweater' - warm casual style",
147
+ " • 'vintage denim jacket' - retro fashion",
148
+ "",
149
+ "💡 Tips:",
150
+ " • Include clothing type + color + details for best results",
151
+ " • For suits: mention 'tailored', 'fitted', specific fabric like 'wool' or 'silk'",
152
+ " • Body structure is preserved automatically"
153
+ ]
154
  ),
155
+
156
+ # 3. OBJECT REPLACEMENT - Replace one object with another
157
+ "object_replacement": InpaintingTemplate(
158
+ key="object_replacement",
159
+ name="Object Replacement",
160
+ category="Replacement",
161
+ icon="🔄",
162
+ description="Replace objects (one type at a time) - all masked areas become the SAME object",
163
+ prompt_template="{content}, photorealistic, natural lighting, seamlessly integrated into scene, high quality",
164
+ negative_prompt=(
165
+ "inconsistent lighting, wrong perspective, mismatched colors, "
166
+ "visible seams, floating objects, unrealistic placement, original object, "
167
+ "poorly integrated, disconnected from scene, keeping original, remnants of original, "
168
+ "multiple different objects, mixed objects, various items, "
169
+ "cartoon, anime, illustration, drawing, painted"
170
+ ),
171
+ controlnet_conditioning_scale=0.25, # Low-medium: allows complete object replacement
172
+ feather_radius=10, # Medium: natural scene integration
173
+ guidance_scale=13.0, # Medium-high: accurate object generation
174
+ num_inference_steps=10, # Optimized for speed
175
+ strength=1.0, # Full repaint: completely replace object
176
+ preferred_conditioning="canny", # Edge-based: preserves scene perspective
177
+ enhance_prompt=True, # Enabled: enriches object details
178
+ difficulty="medium",
179
+ usage_tips=[
180
+ "🎯 Purpose: Replace an object with something completely different.",
181
+ "",
182
+ "📝 Example Prompts:",
183
+ " • 'elegant ceramic vase with fresh roses' - decorative item",
184
+ " • 'modern silver laptop on wooden stand' - tech gadget",
185
+ " • 'stack of leather-bound vintage books' - classic decoration",
186
+ " • 'healthy green potted succulent' - natural element",
187
+ " • 'antique brass table lamp with fabric shade' - lighting",
188
+ "",
189
+ "💡 Tips:",
190
+ " • Replace ONE object type at a time",
191
+ " • Describe what you want, not what you're removing",
192
+ " • Include material and style for realistic results"
193
+ ]
194
  ),
195
+
196
+ # 4. REMOVAL - Remove objects and fill with background
197
+ "removal": InpaintingTemplate(
198
+ key="removal",
199
+ name="Remove Object",
200
+ category="Removal",
201
+ icon="🗑️",
202
+ description="Remove objects and naturally fill with background - describe the background material",
203
+ prompt_template="continue the background with {content}, photorealistic, seamless blending, natural texture continuation, high quality",
204
+ negative_prompt=(
205
+ "new object appearing, adding items, inserting objects, "
206
+ "foreground elements, visible object, thing, item, "
207
+ "unnatural filling, visible patches, inconsistent texture, "
208
+ "mismatched pattern, color discontinuity, artificial blending, "
209
+ "cartoon, anime, illustration, drawing, painted"
210
+ ),
211
+ controlnet_conditioning_scale=0.20, # Low: allows creative background filling
212
+ feather_radius=12, # Medium: smooth background blending
213
+ guidance_scale=12.0, # Medium: balanced control and naturalness
214
+ num_inference_steps=10, # Optimized for speed
215
+ strength=1.0, # Full repaint: completely remove and fill
216
+ preferred_conditioning="depth", # Depth: preserves spatial perspective
217
+ enhance_prompt=False, # Disabled: avoid generating new objects
218
+ difficulty="medium",
219
+ usage_tips=[
220
+ "🎯 Purpose: Remove unwanted objects and fill with background.",
221
+ "",
222
+ "📝 Example Prompts:",
223
+ " • 'polished hardwood floor with natural grain' - indoor floors",
224
+ " • 'smooth white painted wall' - wall backgrounds",
225
+ " • 'lush green grass lawn' - outdoor areas",
226
+ " • 'soft beige carpet texture' - carpeted floors",
227
+ " • 'clear blue sky with soft clouds' - sky backgrounds",
228
+ "",
229
+ "💡 Tips:",
230
+ " • Describe the BACKGROUND texture, not the object",
231
+ " • Leave empty to auto-match surrounding area",
232
+ " • Works best with uniform backgrounds"
233
+ ]
234
  ),
235
  }
236
 
237
+
238
  # Category display order
239
+ CATEGORIES = ["Color", "Replacement", "Removal"] # 4 core templates only
240
 
241
  def __init__(self):
242
+ """Initialize the InpaintingTemplateManager."""
243
+ logger.info(f"InpaintingTemplateManager initialized with {len(self.TEMPLATES)} templates")
244
+
245
+ def get_all_templates(self) -> Dict[str, InpaintingTemplate]:
246
+ """
247
+ Get all available templates.
248
 
249
+ Returns
250
+ -------
251
+ dict
252
+ Dictionary of all templates keyed by template key
253
+ """
254
  return self.TEMPLATES
255
 
256
+ def get_template(self, key: str) -> Optional[InpaintingTemplate]:
257
+ """
258
+ Get a specific template by key.
259
+
260
+ Parameters
261
+ ----------
262
+ key : str
263
+ Template identifier
264
+
265
+ Returns
266
+ -------
267
+ InpaintingTemplate or None
268
+ Template if found, None otherwise
269
+ """
270
  return self.TEMPLATES.get(key)
271
 
272
+ def get_templates_by_category(self, category: str) -> List[InpaintingTemplate]:
273
+ """
274
+ Get all templates in a specific category.
275
+
276
+ Parameters
277
+ ----------
278
+ category : str
279
+ Category name
280
+
281
+ Returns
282
+ -------
283
+ list
284
+ List of templates in the category
285
+ """
286
  return [t for t in self.TEMPLATES.values() if t.category == category]
287
 
288
  def get_categories(self) -> List[str]:
289
+ """
290
+ Get list of all categories in display order.
291
+
292
+ Returns
293
+ -------
294
+ list
295
+ Category names
296
+ """
297
  return self.CATEGORIES
298
 
299
  def get_template_choices_sorted(self) -> List[str]:
300
  """
301
  Get template choices formatted for Gradio dropdown.
302
+
303
+ Returns list of display strings sorted by category then A-Z.
304
+ Format: "icon Name"
305
+
306
+ Returns
307
+ -------
308
+ list
309
+ Formatted display strings for dropdown
310
  """
311
  display_list = []
 
 
 
312
 
313
+ for category in self.CATEGORIES:
314
+ templates = self.get_templates_by_category(category)
315
+ for template in sorted(templates, key=lambda t: t.name):
316
+ display_name = f"{template.icon} {template.name}"
317
+ display_list.append(display_name)
318
+
319
  return display_list
320
 
321
  def get_template_key_from_display(self, display_name: str) -> Optional[str]:
322
  """
323
  Get template key from display name.
324
+
325
+ Parameters
326
+ ----------
327
+ display_name : str
328
+ Display string like "🔄 Object Replacement"
329
+
330
+ Returns
331
+ -------
332
+ str or None
333
+ Template key if found
334
  """
335
  if not display_name:
336
  return None
 
340
  return key
341
  return None
342
 
343
+ def get_parameters_for_template(self, key: str) -> Dict[str, any]:
344
+ """
345
+ Get recommended parameters for a template.
346
+
347
+ Parameters
348
+ ----------
349
+ key : str
350
+ Template key
351
+
352
+ Returns
353
+ -------
354
+ dict
355
+ Dictionary of parameter names and values
356
+ """
357
  template = self.get_template(key)
358
+ if not template:
359
+ return {}
360
+
361
+ return {
362
+ "controlnet_conditioning_scale": template.controlnet_conditioning_scale,
363
+ "feather_radius": template.feather_radius,
364
+ "guidance_scale": template.guidance_scale,
365
+ "num_inference_steps": template.num_inference_steps,
366
+ "strength": template.strength,
367
+ "preferred_conditioning": template.preferred_conditioning,
368
+ "preserve_structure_in_mask": template.preserve_structure_in_mask,
369
+ "enhance_prompt": template.enhance_prompt
370
+ }
371
+
372
+ def build_prompt(self, key: str, content: str) -> str:
373
+ """
374
+ Build complete prompt from template and user content.
375
+
376
+ Parameters
377
+ ----------
378
+ key : str
379
+ Template key
380
+ content : str
381
+ User-provided content description
382
+
383
+ Returns
384
+ -------
385
+ str
386
+ Formatted prompt with content inserted
387
+ """
388
  template = self.get_template(key)
389
+ if not template:
390
+ return content
391
+
392
+ return template.prompt_template.format(content=content)
393
+
394
+ def get_negative_prompt(self, key: str) -> str:
395
+ """
396
+ Get negative prompt for a template.
397
+
398
+ Parameters
399
+ ----------
400
+ key : str
401
+ Template key
402
 
403
+ Returns
404
+ -------
405
+ str
406
+ Negative prompt string
407
+ """
408
  template = self.get_template(key)
409
+ if not template:
410
+ return ""
411
+ return template.negative_prompt
412
+
413
+ def get_usage_tips(self, key: str) -> List[str]:
414
+ """
415
+ Get usage tips for a template.
416
+
417
+ Parameters
418
+ ----------
419
+ key : str
420
+ Template key
421
+
422
+ Returns
423
+ -------
424
+ list
425
+ List of tip strings
426
+ """
427
+ template = self.get_template(key)
428
+ if not template:
429
+ return []
430
+ return template.usage_tips
431
 
432
  def build_gallery_html(self) -> str:
433
  """
434
+ Build HTML for template gallery display.
435
+
436
+ Returns
437
+ -------
438
+ str
439
+ HTML string for Gradio display
440
  """
441
+ html_parts = ['<div class="inpainting-gallery">']
442
 
443
  for category in self.CATEGORIES:
444
  templates = self.get_templates_by_category(category)
 
446
  continue
447
 
448
  html_parts.append(f'''
449
+ <div class="inpainting-category">
450
+ <h4 class="inpainting-category-title">{category}</h4>
451
+ <div class="inpainting-grid">
452
  ''')
453
 
454
+ for template in sorted(templates, key=lambda t: t.name):
455
  html_parts.append(f'''
456
+ <div class="inpainting-card" data-template="{template.key}">
457
+ <span class="inpainting-icon">{template.icon}</span>
458
+ <span class="inpainting-name">{template.name}</span>
459
+ <span class="inpainting-desc">{template.description[:50]}...</span>
460
+ </div>
461
  ''')
462
 
463
  html_parts.append('</div></div>')
464
 
465
  html_parts.append('</div>')
466
+ return ''.join(html_parts)