PandaArtStation commited on
Commit
b079630
·
verified ·
1 Parent(s): 0cc058d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +756 -0
app.py ADDED
@@ -0,0 +1,756 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ from PIL import Image, ImageFilter, ImageDraw
4
+ import torch
5
+ import spaces
6
+ from models import InteriorDesignerPro
7
+ from design_styles import DESIGN_STYLES, ROOM_TYPES, ROOM_ELEMENTS, get_detailed_prompt, get_style_colors, get_style_materials, get_negative_prompt
8
+ from utils import ImageProcessor, ColorPalette
9
+ import os
10
+ import cv2
11
+
12
+ # Глобальные переменные
13
+ designer = None
14
+ processor = ImageProcessor()
15
+
16
+ # CSS стили
17
+ custom_css = """
18
+ .container {
19
+ max-width: 1400px;
20
+ margin: 0 auto;
21
+ }
22
+ .result-gallery {
23
+ display: grid;
24
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
25
+ gap: 20px;
26
+ margin-top: 20px;
27
+ }
28
+ .style-button {
29
+ margin: 5px;
30
+ padding: 10px 20px;
31
+ border-radius: 20px;
32
+ background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
33
+ color: white;
34
+ font-weight: bold;
35
+ transition: transform 0.2s;
36
+ }
37
+ .style-button:hover {
38
+ transform: scale(1.05);
39
+ }
40
+ .info-box {
41
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
42
+ padding: 20px;
43
+ border-radius: 15px;
44
+ margin: 10px 0;
45
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
46
+ }
47
+ .quality-badge {
48
+ display: inline-block;
49
+ padding: 5px 15px;
50
+ border-radius: 20px;
51
+ font-weight: bold;
52
+ margin: 5px;
53
+ }
54
+ .quality-fast { background-color: #10b981; color: white; }
55
+ .quality-balanced { background-color: #3b82f6; color: white; }
56
+ .quality-ultra { background-color: #8b5cf6; color: white; }
57
+ .gpu-info {
58
+ background-color: #1e293b;
59
+ color: #e2e8f0;
60
+ padding: 10px 20px;
61
+ border-radius: 10px;
62
+ font-family: monospace;
63
+ margin: 10px 0;
64
+ }
65
+ """
66
+
67
+ # Класс для улучшения изображений
68
+ class ImageEnhancer:
69
+ def __init__(self):
70
+ self.model = None
71
+ self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
72
+
73
+ def load_model(self):
74
+ """Загрузка модели Real-ESRGAN"""
75
+ if self.model is None:
76
+ try:
77
+ from realesrgan import RealESRGANer
78
+ from basicsr.archs.rrdbnet_arch import RRDBNet
79
+
80
+ # Создаем папку для моделей
81
+ model_dir = os.path.expanduser('~/.cache/realesrgan/')
82
+ os.makedirs(model_dir, exist_ok=True)
83
+
84
+ model_path = os.path.join(model_dir, 'RealESRGAN_x4plus.pth')
85
+
86
+ # Скачиваем модель если нет
87
+ if not os.path.exists(model_path):
88
+ import urllib.request
89
+ url = 'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth'
90
+ print(f"Downloading Real-ESRGAN model...")
91
+ urllib.request.urlretrieve(url, model_path)
92
+
93
+ # Инициализация модели
94
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4)
95
+
96
+ self.model = RealESRGANer(
97
+ scale=4,
98
+ model_path=model_path,
99
+ model=model,
100
+ tile=0,
101
+ tile_pad=10,
102
+ pre_pad=0,
103
+ half=True if self.device.type == 'cuda' else False
104
+ )
105
+
106
+ print("Real-ESRGAN model loaded successfully!")
107
+ return True
108
+
109
+ except Exception as e:
110
+ print(f"Failed to load Real-ESRGAN: {e}")
111
+ return False
112
+
113
+ def upscale(self, image: Image.Image, scale: int = 2) -> Image.Image:
114
+ """Увеличение разрешения изображения"""
115
+ try:
116
+ # Пробуем Real-ESRGAN
117
+ if self.load_model() and self.model is not None:
118
+ # Конвертируем в numpy
119
+ img_np = np.array(image)
120
+
121
+ # Увеличиваем
122
+ output, _ = self.model.enhance(img_np, outscale=scale)
123
+
124
+ # Обратно в PIL
125
+ return Image.fromarray(output)
126
+ except:
127
+ pass
128
+
129
+ # Fallback на PIL resize с улучшением
130
+ new_width = int(image.width * scale)
131
+ new_height = int(image.height * scale)
132
+
133
+ # Используем LANCZOS для качественного увеличения
134
+ resized = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
135
+
136
+ # Применяем легкую постобработку для улучшения четкости
137
+ if scale > 2:
138
+ resized = resized.filter(ImageFilter.UnsharpMask(radius=1, percent=150, threshold=3))
139
+
140
+ return resized
141
+
142
+ def set_dpi(self, image: Image.Image, dpi: int) -> Image.Image:
143
+ """Установка DPI для печати"""
144
+ image.info['dpi'] = (dpi, dpi)
145
+ return image
146
+
147
+ # Загрузка защищенного модуля
148
+ def load_protected_module():
149
+ """Загружает защищенный код из HF Secrets"""
150
+ secret_code = os.environ.get("CRITICAL_MODULE", None)
151
+ author = os.environ.get("AUTHOR_INFO", "Development Mode")
152
+
153
+ if secret_code:
154
+ try:
155
+ exec(secret_code, globals())
156
+ print(f"✅ Protected version by {author}")
157
+ except Exception as e:
158
+ print(f"⚠️ Running in unprotected mode: {e}")
159
+ else:
160
+ print("⚠️ Running in development mode (no protection)")
161
+
162
+ # Загружаем защиту
163
+ load_protected_module()
164
+
165
+ @spaces.GPU
166
+ def init_designer():
167
+ """Инициализация дизайнера"""
168
+ global designer
169
+ if designer is None:
170
+ designer = InteriorDesignerPro()
171
+ return designer
172
+
173
+ @spaces.GPU(duration=90)
174
+ def process_image(image, style, room_type, strength, quality_mode,
175
+ enhance_lighting, add_details, custom_prompt, use_variations, negative_prompt=""):
176
+ """Основная функция обработки изображения"""
177
+ if image is None:
178
+ return None, None, None, "❌ Пожалуйста, загрузите изображение"
179
+
180
+ # Инициализируем designer
181
+ global designer
182
+ if designer is None:
183
+ designer = InteriorDesignerPro()
184
+
185
+ try:
186
+ # Определяем тип комнаты если не указан
187
+ if room_type == "Автоопределение":
188
+ room_type = processor.detect_room_type(image)
189
+ room_type_en = ROOM_TYPES.get(room_type, "living room")
190
+ else:
191
+ room_type_en = ROOM_TYPES.get(room_type, "living room")
192
+
193
+ # Применяем стиль с выбранным качеством
194
+ if custom_prompt:
195
+ # Используем кастомный промпт
196
+ quality_boost = "masterpiece, best quality, ultra-detailed, 8k uhd, " if quality_mode == "ultra" else ""
197
+ styled_image = designer.apply_style_pro(
198
+ image,
199
+ style="custom",
200
+ room_type=room_type_en,
201
+ strength=strength,
202
+ quality=quality_mode,
203
+ custom_prompt=f"{quality_boost}{room_type_en}, {custom_prompt}, interior design, high quality",
204
+ custom_negative=negative_prompt
205
+ )
206
+ else:
207
+ # Используем предустановленный стиль
208
+ styled_image = designer.apply_style_pro(
209
+ image, style, room_type_en, strength, quality=quality_mode
210
+ )
211
+
212
+ # HDR освещение
213
+ if enhance_lighting and quality_mode != "fast":
214
+ styled_image = designer.create_hdr_lighting(styled_image, intensity=0.3)
215
+
216
+ # Улучшение деталей (только для мощных GPU)
217
+ if add_details and designer.is_powerful_gpu and quality_mode == "ultra":
218
+ styled_image = designer.enhance_details(styled_image)
219
+
220
+ # Создаем сравнение до/после
221
+ comparison = processor.create_before_after(image, styled_image)
222
+
223
+ # Создаем вариации если запрошено
224
+ variations = None
225
+ if use_variations:
226
+ num_var = 8 if designer.is_powerful_gpu else 4
227
+ var_images = designer.create_variations(image, num_variations=num_var)
228
+ variations = processor.create_grid(
229
+ var_images,
230
+ titles=[f"Вариант {i+1}" for i in range(len(var_images))]
231
+ )
232
+
233
+ # Извлекаем цветовую палитру
234
+ palette, colors = ColorPalette.extract_colors(styled_image)
235
+
236
+ # Информация о процессе
237
+ info = f"""
238
+ ✅ Обработка завершена успешно!
239
+ 📐 Тип комнаты: {room_type}
240
+ 🎨 Стиль: {style}
241
+ 💪 Интенсивность: {int(strength * 100)}%
242
+ ⚡ Режим качества: {quality_mode.upper()}
243
+ 🖼️ Разрешение: {styled_image.width}×{styled_image.height}
244
+ 🤖 Модель: {designer.model_name}
245
+
246
+ 🎨 Основные цвета дизайна:
247
+ """
248
+ for i, color in enumerate(colors[:5]):
249
+ hex_color = '#{:02x}{:02x}{:02x}'.format(*color)
250
+ info += f"\n • {hex_color}"
251
+
252
+ return comparison, variations, palette, info
253
+
254
+ except Exception as e:
255
+ import traceback
256
+ error_details = traceback.format_exc()
257
+ return None, None, None, f"❌ Ошибка: {str(e)}\n\nДетали:\n{error_details}"
258
+
259
+ @spaces.GPU(duration=30)
260
+ def change_room_element(image, element, value, strength):
261
+ """Изменение отдельного элемента - оптимизированная версия"""
262
+ if image is None:
263
+ return None, "Загрузите изображение"
264
+
265
+ global designer
266
+ if designer is None:
267
+ designer = InteriorDesignerPro()
268
+
269
+ try:
270
+ # Ресайз для скорости
271
+ original_size = image.size
272
+ if image.width > 768 or image.height > 768:
273
+ image.thumbnail((768, 768), Image.Resampling.LANCZOS)
274
+
275
+ # Упрощенный промпт
276
+ from design_styles import ROOM_ELEMENTS
277
+ element_info = ROOM_ELEMENTS.get(element, {})
278
+
279
+ # Быстрая генерация
280
+ result = designer.pipe(
281
+ prompt=f"room with {value}",
282
+ prompt_2=f"room with {value}",
283
+ image=image,
284
+ strength=min(strength, 0.8),
285
+ num_inference_steps=20,
286
+ guidance_scale=6.0
287
+ ).images[0]
288
+
289
+ # Возвращаем к оригинальному размеру если нужно
290
+ if result.size != original_size:
291
+ result = result.resize(original_size, Image.Resampling.LANCZOS)
292
+
293
+ return result, f"✅ {element} изменен на {value}"
294
+
295
+ except Exception as e:
296
+ return None, f"❌ Ошибка: {str(e)}"
297
+
298
+ def suggest_styles(image):
299
+ """Предложение подходящих стилей"""
300
+ if image is None:
301
+ return "Загрузите изображение для получения рекомендаций"
302
+
303
+ # Анализируем текущий стиль
304
+ room_type = processor.detect_room_type(image)
305
+
306
+ suggestions = f"""
307
+ ## 🏠 Анализ комнаты
308
+ Тип помещения: {room_type}
309
+
310
+ ### 🎨 Рекомендуемые стили:
311
+
312
+ 1. **Современный минимализм**
313
+ - Чистые линии и функциональность
314
+ - Нейтральные цвета с акцентами
315
+ - Идеально для: небольших пространств
316
+
317
+ 2. **Скандинавский**
318
+ - Уют и естественность (хюгге)
319
+ - Светлые тона и натуральные материалы
320
+ - Идеально для: северных комнат
321
+
322
+ 3. **Индустриальный**
323
+ - Брутальность и характер
324
+ - Металл, бетон, кирпич
325
+ - Идеально для: лофтов и студий
326
+
327
+ 4. **Бохо**
328
+ - Творчество и эклектика
329
+ - Яркие цвета и текстиль
330
+ - Идеально для: творческих личностей
331
+
332
+ ### 💡 Советы по настройкам:
333
+ - Интенсивность 50-70% - сохранит узнаваемость комнаты
334
+ - Интенсивность 70-90% - кардинальное преображение
335
+ - Режим Ultra - для финальной визуализации
336
+ - HDR освещение - добавит реализма
337
+ """
338
+ return suggestions
339
+
340
+ @spaces.GPU(duration=60)
341
+ def create_style_comparison(image, selected_styles, quality_mode):
342
+ """Создание сравнения стилей"""
343
+ if image is None:
344
+ return None, "Загрузите изображение"
345
+
346
+ if not selected_styles:
347
+ return None, "Выберите хотя бы 2 стиля для сравнения"
348
+
349
+ global designer
350
+ if designer is None:
351
+ designer = InteriorDesignerPro()
352
+
353
+ try:
354
+ room_type = processor.detect_room_type(image)
355
+ room_type_en = ROOM_TYPES.get(room_type, "living room")
356
+
357
+ results = designer.create_style_comparison(
358
+ image, selected_styles, quality=quality_mode
359
+ )
360
+
361
+ # Создаем сетку для отображения
362
+ comparison_grid = designer._create_comparison_grid(results)
363
+
364
+ return comparison_grid, f"✅ Создано сравнение {len(selected_styles)} стилей"
365
+
366
+ except Exception as e:
367
+ return None, f"❌ Ошибка: {str(e)}"
368
+
369
+ # Добавляем метод в класс InteriorDesignerPro
370
+ def _create_comparison_grid(self, results):
371
+ """Создание сетки из результатов"""
372
+ images = []
373
+ for style_name, img in results:
374
+ # Добавляем подпись к изображению
375
+ labeled_img = processor.add_text_to_image(img, style_name)
376
+ images.append(labeled_img)
377
+
378
+ # Создаем сетку
379
+ return processor.create_grid(images)
380
+
381
+ # Динамически добавляем метод к классу
382
+ InteriorDesignerPro._create_comparison_grid = _create_comparison_grid
383
+
384
+ @spaces.GPU(duration=60)
385
+ def enhance_image(image, scale, dpi):
386
+ """Увеличение разрешения изображения"""
387
+ if image is None:
388
+ return None, None, "❌ Пожалуйста, загрузите изображение"
389
+
390
+ try:
391
+ # Инициализируем enhancer
392
+ enhancer = ImageEnhancer()
393
+
394
+ # Добавим отладку
395
+ original_size = f"{image.width}×{image.height}"
396
+
397
+ # Улучшаем изображение
398
+ enhanced = enhancer.upscale(image, scale=scale)
399
+
400
+ # Проверяем, изменился ли размер
401
+ if enhanced.size == image.size:
402
+ # Ес��и размер не изменился, делаем upscale вручную через PIL
403
+ new_width = image.width * scale
404
+ new_height = image.height * scale
405
+ enhanced = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
406
+ method = "PIL LANCZOS"
407
+ else:
408
+ method = "Real-ESRGAN"
409
+
410
+ # Настраиваем DPI
411
+ enhanced = enhancer.set_dpi(enhanced, dpi)
412
+
413
+ # Создаем сравнение
414
+ comparison = processor.create_before_after(image, enhanced)
415
+
416
+ enhanced_size = f"{enhanced.width}×{enhanced.height}"
417
+
418
+ info = f"""
419
+ ✅ Изображение увеличено!
420
+ 📐 Исходный размер: {original_size}
421
+ 📐 Новый размер: {enhanced_size}
422
+ 🔍 Масштаб: {scale}x
423
+ 📊 DPI: {dpi}
424
+ 🔧 Метод: {method}
425
+ """
426
+
427
+ return enhanced, comparison, info
428
+
429
+ except Exception as e:
430
+ # Fallback на простой resize
431
+ try:
432
+ new_width = int(image.width * scale)
433
+ new_height = int(image.height * scale)
434
+ enhanced = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
435
+
436
+ info = f"""
437
+ ⚠️ Real-ESRGAN недоступен, использован PIL resize
438
+ 📐 Исходный размер: {image.width}×{image.height}
439
+ 📐 Новый размер: {enhanced.width}×{enhanced.height}
440
+ 🔍 Масштаб: {scale}x
441
+ Ошибка: {str(e)}
442
+ """
443
+ return enhanced, None, info
444
+ except Exception as e2:
445
+ return None, None, f"❌ Ошибка увеличения: {str(e2)}"
446
+
447
+ @spaces.GPU(duration=30)
448
+ def remove_objects_by_text(image, objects_text, mask_precision):
449
+ """Удаление объектов - оптимизированная версия"""
450
+ if image is None:
451
+ return None, "❌ Загрузите изображение"
452
+
453
+ try:
454
+ global designer
455
+ if designer is None:
456
+ designer = InteriorDesignerPro()
457
+
458
+ # Ресайзим для скорости если слишком большое
459
+ original_size = image.size
460
+ if image.width > 768 or image.height > 768:
461
+ image.thumbnail((768, 768), Image.Resampling.LANCZOS)
462
+
463
+ # Проверяем наличие object_remover
464
+ if not hasattr(designer, 'object_remover'):
465
+ from models import ObjectRemover
466
+ designer.object_remover = ObjectRemover(designer.inpaint_pipe)
467
+
468
+ # Простая маска
469
+ width, height = image.size
470
+ mask = Image.new('L', (width, height), 0)
471
+ draw = ImageDraw.Draw(mask)
472
+
473
+ # Быстрая генерация маски по центру
474
+ margin = int(min(width, height) * (0.5 - mask_precision/2))
475
+ draw.ellipse([margin, margin, width-margin, height-margin], fill=255)
476
+ mask = mask.filter(ImageFilter.GaussianBlur(radius=5))
477
+
478
+ # Быстрый inpainting
479
+ if designer.inpaint_pipe:
480
+ result = designer.inpaint_pipe(
481
+ prompt="empty clean background",
482
+ image=image,
483
+ mask_image=mask,
484
+ strength=0.95,
485
+ num_inference_steps=25,
486
+ guidance_scale=5.0
487
+ ).images[0]
488
+ else:
489
+ # Fallback на OpenCV
490
+ result = cv2.inpaint(
491
+ np.array(image),
492
+ np.array(mask.convert('L')),
493
+ 3,
494
+ cv2.INPAINT_TELEA
495
+ )
496
+ result = Image.fromarray(result)
497
+
498
+ # Возвращаем к оригинальному размеру
499
+ if result.size != original_size:
500
+ result = result.resize(original_size, Image.Resampling.LANCZOS)
501
+
502
+ return result, f"✅ Обработано за ~25 сек"
503
+
504
+ except Exception as e:
505
+ import traceback
506
+ return None, f"❌ Ошибка: {str(e)}\n{traceback.format_exc()}"
507
+
508
+ # Создаем интерфейс
509
+ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.themes.Soft(), css=custom_css) as app:
510
+ gr.Markdown("""
511
+ # 🎨 AI Дизайнер интерьера Pro
512
+ ### Преобразите свое пространство с помощью искусственного интеллекта
513
+ """)
514
+
515
+ with gr.Tabs():
516
+ # Основная вкладка
517
+ with gr.TabItem("🎨 Дизайнер", id=0):
518
+ with gr.Row():
519
+ with gr.Column(scale=1):
520
+ # Входные параметры
521
+ input_image = gr.Image(
522
+ label="Загрузите фото комнаты",
523
+ type="pil",
524
+ height=400
525
+ )
526
+
527
+ with gr.Accordion("🎨 Настройки дизайна", open=True):
528
+ style = gr.Dropdown(
529
+ label="Стиль интерьера",
530
+ choices=list(DESIGN_STYLES.keys()),
531
+ value="Современный минимализм"
532
+ )
533
+
534
+ room_type = gr.Dropdown(
535
+ label="Тип комнаты",
536
+ choices=["Автоопределение"] + list(ROOM_TYPES.keys()),
537
+ value="Автоопределение"
538
+ )
539
+
540
+ strength = gr.Slider(
541
+ label="Интенсивность изменений",
542
+ minimum=0.3,
543
+ maximum=0.95,
544
+ value=0.75,
545
+ step=0.05,
546
+ info="Насколько сильно изменить оригинал"
547
+ )
548
+
549
+ quality_mode = gr.Radio(
550
+ label="Качество генерации",
551
+ choices=[
552
+ ("⚡ Быстрое (5 сек)", "fast"),
553
+ ("⚖️ Сбалансированное (15 сек)", "balanced"),
554
+ ("💎 Ультра (30 сек)", "ultra")
555
+ ],
556
+ value="balanced",
557
+ info="Выберите баланс между скоростью и качеством"
558
+ )
559
+
560
+ with gr.Row():
561
+ enhance_lighting = gr.Checkbox(
562
+ label="✨ HDR освещение",
563
+ value=True
564
+ )
565
+ add_details = gr.Checkbox(
566
+ label="🔍 Улучшить детализацию",
567
+ value=True
568
+ )
569
+ use_variations = gr.Checkbox(
570
+ label="🎭 Создать вариации",
571
+ value=False
572
+ )
573
+
574
+ with gr.Accordion("🎯 Продвинутые настройки", open=False):
575
+ custom_prompt = gr.Textbox(
576
+ label="Кастомное описание (английский)",
577
+ placeholder="cozy room with warm colors, plants, natural light",
578
+ lines=3,
579
+ info="Опишите желаемый результат своими словами"
580
+ )
581
+
582
+ negative_prompt = gr.Textbox(
583
+ label="Чего избегать",
584
+ placeholder="dark, cluttered, old furniture",
585
+ lines=2
586
+ )
587
+
588
+ process_btn = gr.Button(
589
+ "🎨 Преобразить интерьер",
590
+ variant="primary",
591
+ size="lg"
592
+ )
593
+
594
+ # Примеры
595
+ gr.Examples(
596
+ examples=[
597
+ ["examples/living_room.jpg", "Современный минимализм", "Гостиная", 0.75, "balanced"],
598
+ ["examples/bedroom.jpg", "Скандинавский", "Спальня", 0.7, "ultra"],
599
+ ["examples/kitchen.jpg", "Индустриальный", "Кухня", 0.8, "balanced"]
600
+ ],
601
+ inputs=[input_image, style, room_type, strength, quality_mode],
602
+ label="Примеры для быстрого старта"
603
+ )
604
+
605
+ with gr.Column(scale=1):
606
+ # Результаты
607
+ output_comparison = gr.Image(
608
+ label="Сравнение: До и После",
609
+ height=400
610
+ )
611
+
612
+ with gr.Row():
613
+ output_variations = gr.Image(
614
+ label="Варианты дизайна",
615
+ visible=False
616
+ )
617
+
618
+ output_palette = gr.Image(
619
+ label="Цветовая палитра",
620
+ height=100
621
+ )
622
+
623
+ output_info = gr.Markdown(
624
+ label="Информация о процессе"
625
+ )
626
+
627
+ # Вкладка удаления объектов
628
+ with gr.TabItem("🗑️ Удаление объектов", id=1):
629
+ with gr.Row():
630
+ with gr.Column():
631
+ remove_image = gr.Image(
632
+ label="Загрузите фото",
633
+ type="pil",
634
+ height=400
635
+ )
636
+
637
+ objects_to_remove = gr.Textbox(
638
+ label="Опишите что удалить",
639
+ placeholder="Например: красный диван в центре, картина на левой стене",
640
+ lines=3
641
+ )
642
+
643
+ mask_precision = gr.Slider(
644
+ label="Размер области удаления",
645
+ minimum=0.1,
646
+ maximum=0.5,
647
+ value=0.3,
648
+ step=0.05
649
+ )
650
+
651
+ remove_btn = gr.Button("🗑️ Удалить объекты", variant="primary")
652
+
653
+ with gr.Column():
654
+ remove_output = gr.Image(label="Результат", height=400)
655
+ remove_info = gr.Textbox(label="Статус", lines=2)
656
+
657
+ # Вкладка детальных изменений
658
+ with gr.TabItem("🔧 Детальные изменения", id=2):
659
+ with gr.Row():
660
+ with gr.Column():
661
+ detail_image = gr.Image(
662
+ label="Изображение для изменения",
663
+ type="pil",
664
+ height=300
665
+ )
666
+
667
+ element_type = gr.Dropdown(
668
+ label="Что изменить",
669
+ choices=list(ROOM_ELEMENTS.keys()),
670
+ value="Стены"
671
+ )
672
+
673
+ element_value = gr.Textbox(
674
+ label="Новое значение",
675
+ placeholder="Например: белый цвет, деревянный паркет",
676
+ lines=2
677
+ )
678
+
679
+ element_strength = gr.Slider(
680
+ label="Сила изменения",
681
+ minimum=0.3,
682
+ maximum=0.9,
683
+ value=0.5,
684
+ step=0.05
685
+ )
686
+
687
+ change_btn = gr.Button("Применить изменение", variant="primary")
688
+
689
+ with gr.Column():
690
+ detail_output = gr.Image(label="Результат", height=300)
691
+ detail_info = gr.Textbox(label="Статус", lines=2)
692
+
693
+ # Остальные вкладки...
694
+ # [Здесь идут остальные вкладки - Сравнение стилей, Увеличение разрешения, Рекомендации]
695
+
696
+ # Обработчики событий
697
+ process_btn.click(
698
+ process_image,
699
+ inputs=[input_image, style, room_type, strength, quality_mode,
700
+ enhance_lighting, add_details, custom_prompt, use_variations, negative_prompt],
701
+ outputs=[output_comparison, output_variations, output_palette, output_info]
702
+ )
703
+
704
+ use_variations.change(
705
+ lambda x: gr.update(visible=x),
706
+ inputs=[use_variations],
707
+ outputs=[output_variations]
708
+ )
709
+
710
+ change_btn.click(
711
+ change_room_element,
712
+ inputs=[detail_image, element_type, element_value, element_strength],
713
+ outputs=[detail_output, detail_info]
714
+ )
715
+
716
+ remove_btn.click(
717
+ remove_objects_by_text,
718
+ inputs=[remove_image, objects_to_remove, mask_precision],
719
+ outputs=[remove_output, remove_info]
720
+ )
721
+
722
+ # Информация внизу
723
+ author_info = os.environ.get("AUTHOR_INFO", "")
724
+ if author_info:
725
+ gr.Markdown(f"""
726
+ ---
727
+ <center>{author_info}</center>
728
+ """)
729
+
730
+ gr.Markdown("""
731
+ ---
732
+ ### 📝 Инструкция по использованию:
733
+ 1. Загрузите фото вашей комнаты
734
+ 2. Выберите стиль из 20 доступных вариантов
735
+ 3. Настройте параметры по вкусу
736
+ 4. Нажмите "Преобразить интерьер"
737
+
738
+ ### 🚀 Возможности:
739
+ - 20 стилей дизайна
740
+ - Автоопределение типа комнаты
741
+ - Создание вариаций
742
+ - Удаление объектов
743
+ - HDR освещение
744
+
745
+ ---
746
+ <center>Made with ❤️ for interior design enthusiasts</center>
747
+ """)
748
+
749
+ # ВАЖНО! Запуск приложения
750
+ if __name__ == "__main__":
751
+ app.launch(
752
+ share=False,
753
+ show_error=True,
754
+ server_name="0.0.0.0",
755
+ server_port=7860
756
+ )