PandaArtStation commited on
Commit
7422a7b
·
verified ·
1 Parent(s): bdb0e71

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +314 -296
app.py CHANGED
@@ -7,11 +7,13 @@ from models import InteriorDesignerPro
7
  from design_styles import DESIGN_STYLES, ROOM_TYPES, ROOM_ELEMENTS, get_detailed_prompt
8
  from utils import ImageProcessor, ColorPalette
9
  import os
 
10
  from typing import List, Tuple, Optional
11
 
12
  # Глобальные переменные
13
  designer = None
14
  processor = ImageProcessor()
 
15
 
16
  # CSS стили
17
  custom_css = """
@@ -64,6 +66,24 @@ custom_css = """
64
  }
65
  """
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  # Класс для улучшения изображений
68
  class ImageEnhancer:
69
  def __init__(self):
@@ -85,9 +105,9 @@ class ImageEnhancer:
85
 
86
  # Скачиваем модель если нет
87
  if not os.path.exists(model_path):
 
88
  url = 'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth'
89
  print(f"Downloading Real-ESRGAN model...")
90
- import urllib.request
91
  urllib.request.urlretrieve(url, model_path)
92
 
93
  # Инициализация модели
@@ -144,24 +164,6 @@ class ImageEnhancer:
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", "Unauthorized")
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
  """Инициализация дизайнера"""
@@ -170,6 +172,20 @@ def init_designer():
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=""):
@@ -246,7 +262,7 @@ def process_image(image, style, room_type, strength, quality_mode,
246
  """
247
  for i, color in enumerate(colors[:5]):
248
  hex_color = '#{:02x}{:02x}{:02x}'.format(*color)
249
- info += f"\n • {hex_color}"
250
 
251
  return comparison, variations, palette, info
252
 
@@ -260,7 +276,7 @@ def change_room_element(image, element, value, strength):
260
  """Изменение отдельного элемента"""
261
  if image is None:
262
  return None, "Загрузите изображение"
263
-
264
  global designer
265
  if designer is None:
266
  designer = InteriorDesignerPro()
@@ -271,111 +287,50 @@ def change_room_element(image, element, value, strength):
271
  except Exception as e:
272
  return None, f"❌ Ошибка: {str(e)}"
273
 
274
- @spaces.GPU(duration=60)
275
- def remove_objects_inpaint(image, interactive_mask):
276
- """Удаление объектов через inpainting"""
277
  if image is None:
278
- return None, "Загрузите изображение"
279
 
280
- global designer
281
- if designer is None:
282
- designer = InteriorDesignerPro()
283
 
284
- try:
285
- # Проверяе�� тип данных
286
- if isinstance(interactive_mask, dict) and 'mask' in interactive_mask:
287
- # Новый формат Gradio
288
- mask = interactive_mask['mask']
289
- elif hasattr(interactive_mask, 'save'):
290
- # Это уже изображение маски
291
- mask = interactive_mask
292
- else:
293
- return None, "❌ Не удалось получить маску"
294
-
295
- # Убеждаемся что маска правильного размера
296
- if mask.size != image.size:
297
- mask = mask.resize(image.size, Image.Resampling.NEAREST)
298
-
299
- # Инвертируем маску если нужно (белый = удалить)
300
- mask_array = np.array(mask.convert('L'))
301
- if mask_array.mean() < 128: # Если маска в основном черная
302
- mask_array = 255 - mask_array
303
- mask = Image.fromarray(mask_array)
304
-
305
- # Используем inpaint pipeline
306
- if hasattr(designer, 'inpaint_pipe'):
307
- result = designer.inpaint_pipe(
308
- prompt="empty space, clean background, seamless texture, interior without objects",
309
- negative_prompt="furniture, objects, people, decorations, artifacts",
310
- image=image,
311
- mask_image=mask,
312
- strength=0.99,
313
- num_inference_steps=50,
314
- guidance_scale=7.5
315
- ).images[0]
316
- else:
317
- # Fallback на обычный pipeline
318
- result = designer.pipe(
319
- prompt="clean empty interior space, seamless background",
320
- image=image,
321
- mask_image=mask,
322
- strength=0.99,
323
- num_inference_steps=50
324
- ).images[0]
325
-
326
- return result, "✅ Объекты удалены!"
327
-
328
- except Exception as e:
329
- import traceback
330
- error_details = traceback.format_exc()
331
- return None, f"❌ Ошибка: {str(e)}\n\n{error_details}"
332
 
333
- @spaces.GPU(duration=120)
334
- def create_style_comparison(image, selected_styles, room_type, strength, quality):
335
- """Создание сравнения стилей"""
336
- if image is None:
337
- return None, "❌ Загрузите изображение"
338
-
339
- if not selected_styles or len(selected_styles) < 2:
340
- return None, "❌ Выберите минимум 2 стиля для сравнения"
341
-
342
- global designer
343
- if designer is None:
344
- designer = InteriorDesignerPro()
345
-
346
- try:
347
- # Ограничиваем количество стилей
348
- selected_styles = selected_styles[:6]
349
-
350
- # Применяем каждый стиль
351
- styled_images = []
352
- for style in selected_styles:
353
- if quality == "fast":
354
- # Быстрый режим - уменьшаем разрешение
355
- small_image = image.resize((512, 512), Image.Resampling.LANCZOS)
356
- styled = designer.apply_style_pro(small_image, style, ROOM_TYPES.get(room_type, "living room"), strength, quality="fast")
357
- styled = styled.resize(image.size, Image.Resampling.LANCZOS)
358
- else:
359
- styled = designer.apply_style_pro(image, style, ROOM_TYPES.get(room_type, "living room"), strength, quality=quality)
360
-
361
- styled_images.append(styled)
362
-
363
- # Создаем сетку
364
- comparison = designer._create_comparison_grid(styled_images, selected_styles)
365
-
366
- info = f"""
367
- ✅ Сравнение стилей завершено!
368
- 📊 Стилей: {len(selected_styles)}
369
- 🎨 Выбранные стили: {', '.join(selected_styles)}
370
- ⚡ Режим: {quality}
371
  """
372
-
373
- return comparison, info
374
-
375
- except Exception as e:
376
- return None, f"❌ Ошибка: {str(e)}"
377
 
378
- @spaces.GPU
379
  def enhance_image(image, scale, dpi):
380
  """Увеличение разрешения изображения"""
381
  if image is None:
@@ -438,135 +393,188 @@ def enhance_image(image, scale, dpi):
438
  except Exception as e2:
439
  return None, None, f"❌ Ошибка увеличения: {str(e2)}"
440
 
441
- def suggest_styles(image):
442
- """Предложение подходящих стилей"""
 
443
  if image is None:
444
- return "Загрузите изображение для получения рекомендаций"
445
 
446
- # Анализируем текущий стиль
447
- room_type = processor.detect_room_type(image)
448
 
449
- suggestions = f"""
450
- ## 🏠 Анализ комнаты
451
- Тип помещения: {room_type}
452
-
453
- ### 🎨 Рекомендуемые стили:
454
-
455
- 1. **Современный минимализм** ⭐⭐⭐⭐⭐
456
- - Чистые линии и функциональность
457
- - Нейтральные цвета с акцентами
458
- - Идеально для: небольших пространств
459
-
460
- 2. **Скандинавский** ⭐⭐⭐⭐⭐
461
- - Уют и естественность (хюгге)
462
- - Светлые тона и натуральные материалы
463
- - Идеально для: северных комнат
464
-
465
- 3. **Индустриальный** ⭐⭐⭐⭐
466
- - Брутальность и характер
467
- - Металл, бетон, кирпич
468
- - Идеально для: лофтов и студий
469
-
470
- 4. **Бохо** ⭐⭐⭐⭐
471
- - Творчество и эклектика
472
- - Яркие цвета и текстиль
473
- - Идеально для: творческих личностей
474
-
475
- 5. **Неоклассика** ⭐⭐⭐⭐
476
- - Элегантность и утонченность
477
- - Светлые тона, лепнина, симметрия
478
- - Идеально для: просторных комнат
479
 
480
- ### 💡 Советы по настройкам:
481
- - **Интенсивность 30-50%** - легкие изменения, сохранение структуры
482
- - **Интенсивность 50-70%** - сбалансированное преображение
483
- - **Интенсивность 70-90%** - кардинальная трансформация
484
- - **Режим Ultra** - для финальной визуализации
485
- - **HDR освещение** - добавит реализма и глубины
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
 
487
- ### 🎯 Для вашей комнаты особенно подойдут:
488
- """
 
 
 
489
 
490
- # Добавляем специфичные рекомендации
491
- if "гостиная" in room_type.lower():
492
- suggestions += """
493
- - **Современный минимализм** - создаст ощущение простора
494
- - **Скандинавский** - добавит уюта для семейных вечеров
495
- - **Ар-деко** - для впечатляющего приема гостей
496
- """
497
- elif "спальня" in room_type.lower():
498
- suggestions += """
499
- - **Скандинавский** - для спокойного сна
500
- - **Японский дзен** - минимализм и гармония
501
- - **Прованс** - романтичная атмосфера
502
- """
503
- elif "кухня" in room_type.lower():
504
- suggestions += """
505
- - **Современный минимализм** - функциональность и чистота
506
- - **Индустриальный** - стильно и практично
507
- - **Средиземноморский** - теплая атмосфера
508
- """
509
 
510
- return suggestions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
511
 
512
- # Добавляем метод создания сетки для сравнения стилей
513
- def _create_comparison_grid(self, images: List[Image.Image], titles: List[str]) -> Image.Image:
514
- """Создание сетки изображений для сравнения"""
515
  if not images:
516
  return None
517
-
518
  # Определяем размер сетки
519
  n_images = len(images)
520
- if n_images <= 2:
521
- cols = 2
522
- elif n_images <= 4:
523
- cols = 2
524
- else:
525
- cols = 3
526
  rows = (n_images + cols - 1) // cols
527
 
528
  # Размер одного изображения
529
- img_width, img_height = images[0].size
530
-
531
- # Создаем финальное изображение
532
- margin = 20
533
- title_height = 40
534
 
535
- grid_width = cols * img_width + (cols + 1) * margin
536
- grid_height = rows * (img_height + title_height) + (rows + 1) * margin
 
537
 
538
  grid = Image.new('RGB', (grid_width, grid_height), 'white')
539
 
540
- # Отрисовка
541
- from PIL import ImageDraw, ImageFont
542
- draw = ImageDraw.Draw(grid)
543
-
544
- # Пытаемся загрузить шрифт
545
- try:
546
- font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 24)
547
- except:
548
- font = None
549
-
550
  # Размещаем изображения
551
- for idx, (img, title) in enumerate(zip(images, titles)):
552
  row = idx // cols
553
  col = idx % cols
554
 
555
- x = margin + col * (img_width + margin)
556
- y = margin + row * (img_height + title_height + margin)
 
 
 
 
557
 
558
  # Вставляем изображение
559
- grid.paste(img, (x, y + title_height))
 
 
 
 
 
 
 
 
 
 
560
 
561
- # Добавляем заголовок
562
- text_bbox = draw.textbbox((0, 0), title, font=font) if font else (0, 0, len(title) * 10, 20)
 
563
  text_width = text_bbox[2] - text_bbox[0]
564
  text_x = x + (img_width - text_width) // 2
565
- draw.text((text_x, y + 5), title, fill='black', font=font)
 
 
566
 
567
  return grid
568
 
569
- # Динамически добавляем метод к классу
570
  if 'InteriorDesignerPro' in globals():
571
  InteriorDesignerPro._create_comparison_grid = _create_comparison_grid
572
 
@@ -656,16 +664,16 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
656
  size="lg"
657
  )
658
 
659
- # Примеры
660
- gr.Examples(
661
- examples=[
662
- ["examples/living_room.jpg", "Современный минимализм", "Гостиная", 0.75, "balanced"],
663
- ["examples/bedroom.jpg", "Скандинавский", "Спальня", 0.7, "ultra"],
664
- ["examples/kitchen.jpg", "Индустриальный", "Кухня", 0.8, "balanced"]
665
- ],
666
- inputs=[input_image, style, room_type, strength, quality_mode],
667
- label="Примеры для быстрого старта"
668
- )
669
 
670
  with gr.Column(scale=1):
671
  # Результаты
@@ -692,30 +700,50 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
692
  with gr.TabItem("🗑️ Удаление объектов", id=1):
693
  with gr.Row():
694
  with gr.Column():
695
- gr.Markdown("""
696
- ### 🎨 Как использовать:
697
- 1. Загрузите изображение
698
- 2. Нарисуйте маску поверх объектов которые хотите удалить
699
- 3. Нажмите "Удалить объекты"
700
 
701
- 💡 **Совет:** Закрашивайте объекты полностью для лучшего результата
702
- """)
 
 
 
 
703
 
704
- # Интерактивное изображение для рисования маски
705
- remove_input = gr.Image(
706
- label="Нарисуйте маску на изображении (закрасьте объекты)",
707
- type="pil",
708
- height=500,
709
- interactive=True,
 
710
  )
711
 
712
- remove_btn = gr.Button("🗑️ Удалить объекты", variant="primary", size="lg")
 
 
 
 
 
713
 
 
 
 
 
 
 
714
  with gr.Column():
715
  remove_output = gr.Image(
716
  label="Результат",
717
  height=500
718
  )
 
 
 
 
719
  remove_info = gr.Markdown()
720
 
721
  # Вкладка детальных изменений
@@ -749,7 +777,7 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
749
  )
750
 
751
  change_btn = gr.Button("Применить изменение", variant="primary")
752
-
753
  with gr.Column():
754
  detail_output = gr.Image(label="Результат", height=300)
755
  detail_info = gr.Textbox(label="Статус", lines=2)
@@ -759,7 +787,7 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
759
  with gr.Row():
760
  with gr.Column():
761
  compare_image = gr.Image(
762
- label="Загрузите фото",
763
  type="pil",
764
  height=400
765
  )
@@ -770,30 +798,16 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
770
  value=["Современный минимализм", "Скандинавский"]
771
  )
772
 
773
- compare_room_type = gr.Dropdown(
774
- label="Тип комнаты",
775
- choices=list(ROOM_TYPES.keys()),
776
- value="Гостиная"
777
- )
778
-
779
- compare_strength = gr.Slider(
780
- label="Интенсивность",
781
- minimum=0.3,
782
- maximum=0.9,
783
- value=0.7,
784
- step=0.05
785
- )
786
-
787
  compare_quality = gr.Radio(
788
  label="Скорость генерации",
789
  choices=[("Быстро", "fast"), ("Качественно", "balanced")],
790
  value="fast"
791
  )
792
 
793
- compare_btn = gr.Button("🎭 Сравнить стили", variant="primary", size="lg")
794
-
795
  with gr.Column():
796
- compare_output = gr.Image(label="Сравнение стилей", height=600)
797
  compare_info = gr.Markdown()
798
 
799
  # Вкладка увеличения разрешения
@@ -801,7 +815,7 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
801
  with gr.Row():
802
  with gr.Column():
803
  upscale_image = gr.Image(
804
- label="Загрузите изображение",
805
  type="pil",
806
  height=400
807
  )
@@ -815,18 +829,18 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
815
  upscale_dpi = gr.Radio(
816
  label="DPI для печати",
817
  choices=[
818
- ("Экран (96 DPI)", 96),
819
  ("Печать (150 DPI)", 150),
820
  ("Высокое качество (300 DPI)", 300)
821
  ],
822
- value=96
823
  )
824
 
825
- upscale_btn = gr.Button("🔍 Увеличить разрешение", variant="primary", size="lg")
826
-
827
  with gr.Column():
828
  upscale_output = gr.Image(label="Увеличенное изображение")
829
- upscale_comparison = gr.Image(label="Сравнение размеров")
830
  upscale_info = gr.Markdown()
831
 
832
  # Вкладка рекомендаций
@@ -839,7 +853,7 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
839
  height=400
840
  )
841
  suggest_btn = gr.Button("Получить рекомендации", variant="primary")
842
-
843
  with gr.Column():
844
  suggestions = gr.Markdown()
845
 
@@ -865,9 +879,9 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
865
  )
866
 
867
  remove_btn.click(
868
- remove_objects_inpaint,
869
- inputs=[remove_input],
870
- outputs=[remove_output, remove_info]
871
  )
872
 
873
  change_btn.click(
@@ -878,7 +892,7 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
878
 
879
  compare_btn.click(
880
  create_style_comparison,
881
- inputs=[compare_image, compare_styles, compare_room_type, compare_strength, compare_quality],
882
  outputs=[compare_output, compare_info]
883
  )
884
 
@@ -894,41 +908,45 @@ with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.them
894
  outputs=[suggestions]
895
  )
896
 
 
 
 
 
 
 
 
 
 
 
 
 
 
897
  # Информация внизу
898
  gr.Markdown("""
899
  ---
900
  ### 📝 Инструкция по использованию:
901
- 1. **Основной дизайн** - загрузите фото и выберите стиль
902
- 2. **Удаление объектов** - нарисуйте маску прямо на изображении
903
- 3. **Детальные изменения** - меняйте отдельные элементы
904
- 4. **Сравнение стилей** - посмотрите несколько вариантов сразу
905
- 5. **Увеличение качества** - подготовьте для печати
906
 
907
  ### 🚀 Возможности:
908
- - 20+ стилей дизайна с детальной настройкой
909
- - Удаление объектов с сохранением интерьера
910
- - Сравнение до 6 стилей одновременно
911
- - HDR освещение и улучшение деталей
912
- - Увеличение разрешения до 4x
913
- - Умные рекомендации по стилю
 
 
 
914
 
915
  ---
916
  <center>Made with ❤️ for interior design enthusiasts</center>
917
  """)
918
-
919
- # Показываем информацию об авторе если есть
920
- author_info = os.environ.get("AUTHOR_INFO", None)
921
- if author_info:
922
- gr.Markdown(f"""
923
- <center>
924
- <div style='background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
925
- padding: 20px; border-radius: 10px; color: white; margin-top: 20px;'>
926
- <h3>🔒 {author_info}</h3>
927
- </div>
928
- </center>
929
- """)
930
 
931
- # ВАЖНО! Запуск приложения
932
  if __name__ == "__main__":
933
  app.launch(
934
  share=False,
 
7
  from design_styles import DESIGN_STYLES, ROOM_TYPES, ROOM_ELEMENTS, get_detailed_prompt
8
  from utils import ImageProcessor, ColorPalette
9
  import os
10
+ import threading
11
  from typing import List, Tuple, Optional
12
 
13
  # Глобальные переменные
14
  designer = None
15
  processor = ImageProcessor()
16
+ inpaint_pipe = None
17
 
18
  # CSS стили
19
  custom_css = """
 
66
  }
67
  """
68
 
69
+ # Загрузка защитного модуля
70
+ def load_protected_module():
71
+ """Загружает защищенный код из HF Secrets"""
72
+ secret_code = os.environ.get("CRITICAL_MODULE", None)
73
+ author = os.environ.get("AUTHOR_INFO", "Unauthorized")
74
+
75
+ if secret_code:
76
+ try:
77
+ exec(secret_code, globals())
78
+ print(f"✅ Protected version by {author}")
79
+ except Exception as e:
80
+ print(f"⚠️ Running in unprotected mode: {e}")
81
+ else:
82
+ print("⚠️ Running in development mode (no protection)")
83
+
84
+ # Загружаем защиту
85
+ load_protected_module()
86
+
87
  # Класс для улучшения изображений
88
  class ImageEnhancer:
89
  def __init__(self):
 
105
 
106
  # Скачиваем модель если нет
107
  if not os.path.exists(model_path):
108
+ import urllib.request
109
  url = 'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth'
110
  print(f"Downloading Real-ESRGAN model...")
 
111
  urllib.request.urlretrieve(url, model_path)
112
 
113
  # Инициализация модели
 
164
  image.info['dpi'] = (dpi, dpi)
165
  return image
166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  @spaces.GPU
168
  def init_designer():
169
  """Инициализация дизайнера"""
 
172
  designer = InteriorDesignerPro()
173
  return designer
174
 
175
+ @spaces.GPU
176
+ def init_inpaint_model():
177
+ """Инициализация модели для удаления объектов"""
178
+ global inpaint_pipe
179
+ if inpaint_pipe is None:
180
+ from diffusers import StableDiffusionInpaintPipeline
181
+ inpaint_pipe = StableDiffusionInpaintPipeline.from_pretrained(
182
+ "runwayml/stable-diffusion-inpainting",
183
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
184
+ )
185
+ if torch.cuda.is_available():
186
+ inpaint_pipe = inpaint_pipe.to("cuda")
187
+ return inpaint_pipe
188
+
189
  @spaces.GPU(duration=90)
190
  def process_image(image, style, room_type, strength, quality_mode,
191
  enhance_lighting, add_details, custom_prompt, use_variations, negative_prompt=""):
 
262
  """
263
  for i, color in enumerate(colors[:5]):
264
  hex_color = '#{:02x}{:02x}{:02x}'.format(*color)
265
+ info += f"\n • {hex_color}"
266
 
267
  return comparison, variations, palette, info
268
 
 
276
  """Изменение отдельного элемента"""
277
  if image is None:
278
  return None, "Загрузите изображение"
279
+
280
  global designer
281
  if designer is None:
282
  designer = InteriorDesignerPro()
 
287
  except Exception as e:
288
  return None, f"❌ Ошибка: {str(e)}"
289
 
290
+ def suggest_styles(image):
291
+ """Предложение подходящих стилей"""
 
292
  if image is None:
293
+ return "Загрузите изображение для получения рекомендаций"
294
 
295
+ # Анализируем текущий стиль
296
+ room_type = processor.detect_room_type(image)
 
297
 
298
+ suggestions = f"""
299
+ ## 🏠 Анализ комнаты
300
+ Тип помещения: {room_type}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
 
302
+ ### 🎨 Рекомендуемые стили:
303
+
304
+ 1. **Современный минимализм**
305
+ - Чистые линии и функциональность
306
+ - Нейтральные цвета с акцентами
307
+ - Идеально для: небольших пространств
308
+
309
+ 2. **Скандинавский**
310
+ - Уют и естественность (хюгге)
311
+ - Светлые тона и натуральные материалы
312
+ - Идеально для: северных комнат
313
+
314
+ 3. **Индустриальный**
315
+ - Брутальность и характер
316
+ - Металл, бетон, кирпич
317
+ - Идеально для: лофтов и студий
318
+
319
+ 4. **Бохо**
320
+ - Творчество и эклектика
321
+ - Яркие цвета и текстиль
322
+ - Идеально для: творческих личностей
323
+
324
+ ### 💡 Советы по настройкам:
325
+ - Интенсивность 50-70% - сохранит узнаваемость комнаты
326
+ - Интенсивность 70-90% - кардинальное п��еображение
327
+ - Режим Ultra - для финальной визуализации
328
+ - HDR освещение - добавит реализма
 
 
 
 
 
 
 
 
 
 
 
329
  """
330
+
331
+ return suggestions
 
 
 
332
 
333
+ @spaces.GPU(duration=60)
334
  def enhance_image(image, scale, dpi):
335
  """Увеличение разрешения изображения"""
336
  if image is None:
 
393
  except Exception as e2:
394
  return None, None, f"❌ Ошибка увеличения: {str(e2)}"
395
 
396
+ @spaces.GPU(duration=60)
397
+ def create_style_comparison(image, selected_styles, quality="fast"):
398
+ """Создание сравнения стилей"""
399
  if image is None:
400
+ return None, "Загрузите изображение"
401
 
402
+ if not selected_styles:
403
+ return None, "❌ Выберите хотя бы 2 стиля"
404
 
405
+ global designer
406
+ if designer is None:
407
+ designer = InteriorDesignerPro()
408
+
409
+ try:
410
+ comparison = designer.create_style_comparison(
411
+ image,
412
+ selected_styles,
413
+ quality=quality
414
+ )
415
+
416
+ info = f"""
417
+ Сравнение создано!
418
+ 🎨 Стили: {', '.join(selected_styles)}
419
+ Режим: {quality}
420
+ """
421
+
422
+ return comparison, info
423
+
424
+ except Exception as e:
425
+ return None, f"❌ Ошибка: {str(e)}"
 
 
 
 
 
 
 
 
 
426
 
427
+ def generate_mask_from_text(image, text_description, precision):
428
+ """Генерация маски на основе текстового описания"""
429
+ # Простая реализация - создаем маску в центре изображения
430
+ # В реальном приложении здесь был бы SAM или другая модель сегментации
431
+
432
+ mask = Image.new('L', image.size, 0)
433
+ width, height = image.size
434
+
435
+ # Определяем размер области на основе точности
436
+ mask_size = {
437
+ 0.3: 0.2, # 20% изображения
438
+ 0.5: 0.3, # 30% изображения
439
+ 0.7: 0.4, # 40% изображения
440
+ 0.9: 0.5 # 50% изображения
441
+ }.get(precision, 0.3)
442
+
443
+ # Создаем маску в центре
444
+ from PIL import ImageDraw
445
+ draw = ImageDraw.Draw(mask)
446
+
447
+ # Вычисляем координаты
448
+ center_x, center_y = width // 2, height // 2
449
+ radius_x = int(width * mask_size / 2)
450
+ radius_y = int(height * mask_size / 2)
451
+
452
+ # Рисуем эллипс
453
+ draw.ellipse(
454
+ [(center_x - radius_x, center_y - radius_y),
455
+ (center_x + radius_x, center_y + radius_y)],
456
+ fill=255
457
+ )
458
+
459
+ # Применяем размытие для ��лавных краев
460
+ mask = mask.filter(ImageFilter.GaussianBlur(radius=10))
461
+
462
+ return mask
463
 
464
+ @spaces.GPU(duration=60)
465
+ def remove_objects_by_text(image, objects_text, mask_precision):
466
+ """Удаление объектов по текстовому описанию"""
467
+ if image is None:
468
+ return None, None, "❌ Загрузите изображение"
469
 
470
+ if not objects_text.strip():
471
+ return None, None, " Опишите объекты для удаления"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
 
473
+ # Инициализируем inpaint pipeline
474
+ global inpaint_pipe
475
+ if inpaint_pipe is None:
476
+ inpaint_pipe = init_inpaint_model()
477
+
478
+ try:
479
+ # Генерируем маску на основе описания
480
+ mask = generate_mask_from_text(image, objects_text, mask_precision)
481
+
482
+ # Определяем тип комнаты для контекста
483
+ room_type = processor.detect_room_type(image)
484
+ room_type_en = ROOM_TYPES.get(room_type, "room")
485
+
486
+ # Inpainting
487
+ result = inpaint_pipe(
488
+ prompt=f"empty {room_type_en}, clean background, seamless texture, no {objects_text}",
489
+ negative_prompt=f"{objects_text}, furniture, objects, people",
490
+ image=image,
491
+ mask_image=mask,
492
+ strength=0.99,
493
+ num_inference_steps=50,
494
+ guidance_scale=7.5
495
+ ).images[0]
496
+
497
+ # Создаем визуализацию маски
498
+ mask_visual = Image.new('RGBA', image.size, (0, 0, 0, 0))
499
+ mask_colored = Image.new('RGBA', image.size, (255, 0, 0, 100))
500
+ mask_visual.paste(mask_colored, mask=mask)
501
+
502
+ # Накладываем маску на оригинал для показа
503
+ preview = image.convert('RGBA')
504
+ preview = Image.alpha_composite(preview, mask_visual)
505
+
506
+ info = f"""
507
+ ✅ Объекты удалены!
508
+ 🎯 Удалено: {objects_text}
509
+ 📏 Точность маски: {int(mask_precision * 100)}%
510
+ 🏠 Тип комнаты: {room_type}
511
+ """
512
+
513
+ return result, preview, info
514
+
515
+ except Exception as e:
516
+ import traceback
517
+ error_details = traceback.format_exc()
518
+ return None, None, f"❌ Ошибка: {str(e)}\n\nДетали:\n{error_details}"
519
 
520
+ # Динамически добавляем метод _create_comparison_grid к InteriorDesignerPro
521
+ def _create_comparison_grid(self, images: List[Image.Image], styles: List[str], max_width: int = 1920) -> Image.Image:
522
+ """Создает сетку из изображений для сравнения стилей"""
523
  if not images:
524
  return None
525
+
526
  # Определяем размер сетки
527
  n_images = len(images)
528
+ cols = min(3, n_images) # Максимум 3 колонки
 
 
 
 
 
529
  rows = (n_images + cols - 1) // cols
530
 
531
  # Размер одного изображения
532
+ img_width = min(images[0].width, max_width // cols)
533
+ img_height = int(img_width * images[0].height / images[0].width)
 
 
 
534
 
535
+ # Создаем холст
536
+ grid_width = img_width * cols
537
+ grid_height = img_height * rows + 50 * rows # +50px для подписей
538
 
539
  grid = Image.new('RGB', (grid_width, grid_height), 'white')
540
 
 
 
 
 
 
 
 
 
 
 
541
  # Размещаем изображения
542
+ for idx, (img, style) in enumerate(zip(images, styles)):
543
  row = idx // cols
544
  col = idx % cols
545
 
546
+ # Ресайзим изображение
547
+ img_resized = img.resize((img_width, img_height), Image.Resampling.LANCZOS)
548
+
549
+ # Позиция
550
+ x = col * img_width
551
+ y = row * (img_height + 50)
552
 
553
  # Вставляем изображение
554
+ grid.paste(img_resized, (x, y))
555
+
556
+ # Добавляем подпись
557
+ from PIL import ImageDraw, ImageFont
558
+ draw = ImageDraw.Draw(grid)
559
+
560
+ # Пытаемся загрузить шрифт
561
+ try:
562
+ font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20)
563
+ except:
564
+ font = ImageFont.load_default()
565
 
566
+ # Текст по центру под изображением
567
+ text = style
568
+ text_bbox = draw.textbbox((0, 0), text, font=font)
569
  text_width = text_bbox[2] - text_bbox[0]
570
  text_x = x + (img_width - text_width) // 2
571
+ text_y = y + img_height + 10
572
+
573
+ draw.text((text_x, text_y), text, fill='black', font=font)
574
 
575
  return grid
576
 
577
+ # Добавляем метод к классу перед запуском
578
  if 'InteriorDesignerPro' in globals():
579
  InteriorDesignerPro._create_comparison_grid = _create_comparison_grid
580
 
 
664
  size="lg"
665
  )
666
 
667
+ # Примеры (закомментированы если нет папки)
668
+ # gr.Examples(
669
+ # examples=[
670
+ # ["examples/living_room.jpg", "Современный минимализм", "Гостиная", 0.75, "balanced"],
671
+ # ["examples/bedroom.jpg", "Скандинавский", "Спальня", 0.7, "ultra"],
672
+ # ["examples/kitchen.jpg", "Индустриальный", "Кухня", 0.8, "balanced"]
673
+ # ],
674
+ # inputs=[input_image, style, room_type, strength, quality_mode],
675
+ # label="Примеры для быстрого старта"
676
+ # )
677
 
678
  with gr.Column(scale=1):
679
  # Результаты
 
700
  with gr.TabItem("🗑️ Удаление объектов", id=1):
701
  with gr.Row():
702
  with gr.Column():
703
+ remove_image = gr.Image(
704
+ label="Загрузите фото",
705
+ type="pil",
706
+ height=500
707
+ )
708
 
709
+ objects_to_remove = gr.Textbox(
710
+ label="Опишите объекты для удаления",
711
+ placeholder="Например: красный диван, картина на левой стене, стол в центре",
712
+ lines=3,
713
+ info="Опишите что нужно удалить с изображения"
714
+ )
715
 
716
+ mask_precision = gr.Slider(
717
+ label="Точность выделения",
718
+ minimum=0.3,
719
+ maximum=0.9,
720
+ value=0.5,
721
+ step=0.1,
722
+ info="Насколько точно выделять объекты"
723
  )
724
 
725
+ gr.Markdown("""
726
+ ### 💡 Советы:
727
+ - Описывайте объекты максимально конкретно
728
+ - Указывайте расположение: "слева", "в центре", "на стене"
729
+ - Можно перечислить несколько объектов через запятую
730
+ """)
731
 
732
+ remove_btn = gr.Button(
733
+ "🗑️ Удалить объекты",
734
+ variant="primary",
735
+ size="lg"
736
+ )
737
+
738
  with gr.Column():
739
  remove_output = gr.Image(
740
  label="Результат",
741
  height=500
742
  )
743
+ remove_preview = gr.Image(
744
+ label="Предпросмотр маски",
745
+ height=200
746
+ )
747
  remove_info = gr.Markdown()
748
 
749
  # Вкладка детальных изменений
 
777
  )
778
 
779
  change_btn = gr.Button("Применить изменение", variant="primary")
780
+
781
  with gr.Column():
782
  detail_output = gr.Image(label="Результат", height=300)
783
  detail_info = gr.Textbox(label="Статус", lines=2)
 
787
  with gr.Row():
788
  with gr.Column():
789
  compare_image = gr.Image(
790
+ label="Загрузите фото для сравнения",
791
  type="pil",
792
  height=400
793
  )
 
798
  value=["Современный минимализм", "Скандинавский"]
799
  )
800
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
801
  compare_quality = gr.Radio(
802
  label="Скорость генерации",
803
  choices=[("Быстро", "fast"), ("Качественно", "balanced")],
804
  value="fast"
805
  )
806
 
807
+ compare_btn = gr.Button("🎭 Сравнить стили", variant="primary")
808
+
809
  with gr.Column():
810
+ compare_output = gr.Image(label="Сравнение стилей")
811
  compare_info = gr.Markdown()
812
 
813
  # Вкладка увеличения разрешения
 
815
  with gr.Row():
816
  with gr.Column():
817
  upscale_image = gr.Image(
818
+ label="Изображение для увеличения",
819
  type="pil",
820
  height=400
821
  )
 
829
  upscale_dpi = gr.Radio(
830
  label="DPI для печати",
831
  choices=[
832
+ ("Веб (96 DPI)", 96),
833
  ("Печать (150 DPI)", 150),
834
  ("Высокое качество (300 DPI)", 300)
835
  ],
836
+ value=150
837
  )
838
 
839
+ upscale_btn = gr.Button("🔍 Увеличить разрешение", variant="primary")
840
+
841
  with gr.Column():
842
  upscale_output = gr.Image(label="Увеличенное изображение")
843
+ upscale_comparison = gr.Image(label="Сравнение")
844
  upscale_info = gr.Markdown()
845
 
846
  # Вкладка рекомендаций
 
853
  height=400
854
  )
855
  suggest_btn = gr.Button("Получить рекомендации", variant="primary")
856
+
857
  with gr.Column():
858
  suggestions = gr.Markdown()
859
 
 
879
  )
880
 
881
  remove_btn.click(
882
+ remove_objects_by_text,
883
+ inputs=[remove_image, objects_to_remove, mask_precision],
884
+ outputs=[remove_output, remove_preview, remove_info]
885
  )
886
 
887
  change_btn.click(
 
892
 
893
  compare_btn.click(
894
  create_style_comparison,
895
+ inputs=[compare_image, compare_styles, compare_quality],
896
  outputs=[compare_output, compare_info]
897
  )
898
 
 
908
  outputs=[suggestions]
909
  )
910
 
911
+ # Информация об авторе
912
+ author_info = os.environ.get("AUTHOR_INFO", "AI Interior Designer Pro")
913
+ with gr.Row():
914
+ gr.Markdown(f"""
915
+ ---
916
+ <center>
917
+ <div style='background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
918
+ padding: 20px; border-radius: 10px; color: white;'>
919
+ <h3>🔒 {author_info}</h3>
920
+ </div>
921
+ </center>
922
+ """)
923
+
924
  # Информация внизу
925
  gr.Markdown("""
926
  ---
927
  ### 📝 Инструкция по использованию:
928
+
929
+ 1. Загрузите фото вашей комнаты
930
+ 2. Выберите стиль из 20 доступных вариантов
931
+ 3. Настройте параметры по вкусу
932
+ 4. Нажмите "Преобразить интерьер"
933
 
934
  ### 🚀 Возможности:
935
+
936
+ - **20 стилей дизайна** - от минимализма до ар-деко
937
+ - **Автоопределение типа комнаты**
938
+ - **Удаление объектов** по текстовому описанию
939
+ - **Создание вариаций** - до 8 вариантов за раз
940
+ - **Детальные изменения** - меняйте отдельные элементы
941
+ - **HDR освещение** - профессиональная обработка света
942
+ - **Увеличение разрешения** - до 4x с AI
943
+ - **Сравнение стилей** - до 6 стилей одновременно
944
 
945
  ---
946
  <center>Made with ❤️ for interior design enthusiasts</center>
947
  """)
 
 
 
 
 
 
 
 
 
 
 
 
948
 
949
+ # Запуск приложения
950
  if __name__ == "__main__":
951
  app.launch(
952
  share=False,