Spaces:
Running
on
Zero
Running
on
Zero
import gradio as gr | |
import numpy as np | |
from PIL import Image, ImageFilter, ImageDraw | |
import torch | |
import spaces | |
from models import InteriorDesignerPro | |
from design_styles import DESIGN_STYLES, ROOM_TYPES, ROOM_ELEMENTS, get_detailed_prompt, get_style_colors, get_style_materials, get_negative_prompt | |
from utils import ImageProcessor, ColorPalette | |
import os | |
import cv2 | |
# Глобальные переменные | |
designer = None | |
processor = ImageProcessor() | |
# CSS стили | |
custom_css = """ | |
.container { | |
max-width: 1400px; | |
margin: 0 auto; | |
} | |
.result-gallery { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); | |
gap: 20px; | |
margin-top: 20px; | |
} | |
.style-button { | |
margin: 5px; | |
padding: 10px 20px; | |
border-radius: 20px; | |
background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); | |
color: white; | |
font-weight: bold; | |
transition: transform 0.2s; | |
} | |
.style-button:hover { | |
transform: scale(1.05); | |
} | |
.info-box { | |
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); | |
padding: 20px; | |
border-radius: 15px; | |
margin: 10px 0; | |
box-shadow: 0 4px 6px rgba(0,0,0,0.1); | |
} | |
.quality-badge { | |
display: inline-block; | |
padding: 5px 15px; | |
border-radius: 20px; | |
font-weight: bold; | |
margin: 5px; | |
} | |
.quality-fast { background-color: #10b981; color: white; } | |
.quality-balanced { background-color: #3b82f6; color: white; } | |
.quality-ultra { background-color: #8b5cf6; color: white; } | |
.gpu-info { | |
background-color: #1e293b; | |
color: #e2e8f0; | |
padding: 10px 20px; | |
border-radius: 10px; | |
font-family: monospace; | |
margin: 10px 0; | |
} | |
""" | |
# Класс для улучшения изображений | |
class ImageEnhancer: | |
def __init__(self): | |
self.model = None | |
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
def load_model(self): | |
"""Загрузка модели Real-ESRGAN""" | |
if self.model is None: | |
try: | |
from realesrgan import RealESRGANer | |
from basicsr.archs.rrdbnet_arch import RRDBNet | |
# Создаем папку для моделей | |
model_dir = os.path.expanduser('~/.cache/realesrgan/') | |
os.makedirs(model_dir, exist_ok=True) | |
model_path = os.path.join(model_dir, 'RealESRGAN_x4plus.pth') | |
# Скачиваем модель если нет | |
if not os.path.exists(model_path): | |
import urllib.request | |
url = 'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth' | |
print(f"Downloading Real-ESRGAN model...") | |
urllib.request.urlretrieve(url, model_path) | |
# Инициализация модели | |
model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4) | |
self.model = RealESRGANer( | |
scale=4, | |
model_path=model_path, | |
model=model, | |
tile=0, | |
tile_pad=10, | |
pre_pad=0, | |
half=True if self.device.type == 'cuda' else False | |
) | |
print("Real-ESRGAN model loaded successfully!") | |
return True | |
except Exception as e: | |
print(f"Failed to load Real-ESRGAN: {e}") | |
return False | |
def upscale(self, image: Image.Image, scale: int = 2) -> Image.Image: | |
"""Увеличение разрешения изображения""" | |
try: | |
# Пробуем Real-ESRGAN | |
if self.load_model() and self.model is not None: | |
# Конвертируем в numpy | |
img_np = np.array(image) | |
# Увеличиваем | |
output, _ = self.model.enhance(img_np, outscale=scale) | |
# Обратно в PIL | |
return Image.fromarray(output) | |
except: | |
pass | |
# Fallback на PIL resize с улучшением | |
new_width = int(image.width * scale) | |
new_height = int(image.height * scale) | |
# Используем LANCZOS для качественного увеличения | |
resized = image.resize((new_width, new_height), Image.Resampling.LANCZOS) | |
# Применяем легкую постобработку для улучшения четкости | |
if scale > 2: | |
resized = resized.filter(ImageFilter.UnsharpMask(radius=1, percent=150, threshold=3)) | |
return resized | |
def set_dpi(self, image: Image.Image, dpi: int) -> Image.Image: | |
"""Установка DPI для печати""" | |
image.info['dpi'] = (dpi, dpi) | |
return image | |
# Загрузка защищенного модуля | |
def load_protected_module(): | |
"""Загружает защищенный код из HF Secrets""" | |
secret_code = os.environ.get("CRITICAL_MODULE", None) | |
author = os.environ.get("AUTHOR_INFO", "Development Mode") | |
if secret_code: | |
try: | |
exec(secret_code, globals()) | |
print(f"✅ Protected version by {author}") | |
except Exception as e: | |
print(f"⚠️ Running in unprotected mode: {e}") | |
else: | |
print("⚠️ Running in development mode (no protection)") | |
# Загружаем защиту | |
load_protected_module() | |
def init_designer(): | |
"""Инициализация дизайнера""" | |
global designer | |
if designer is None: | |
designer = InteriorDesignerPro() | |
return designer | |
def process_image(image, style, room_type, strength, quality_mode, | |
enhance_lighting, add_details, custom_prompt, use_variations, negative_prompt=""): | |
"""Основная функция обработки изображения""" | |
if image is None: | |
return None, None, None, "❌ Пожалуйста, загрузите изображение" | |
# Инициализируем designer | |
global designer | |
if designer is None: | |
designer = InteriorDesignerPro() | |
try: | |
# Определяем тип комнаты если не указан | |
if room_type == "Автоопределение": | |
room_type = processor.detect_room_type(image) | |
room_type_en = ROOM_TYPES.get(room_type, "living room") | |
else: | |
room_type_en = ROOM_TYPES.get(room_type, "living room") | |
# Применяем стиль с выбранным качеством | |
if custom_prompt: | |
# Используем кастомный промпт | |
quality_boost = "masterpiece, best quality, ultra-detailed, 8k uhd, " if quality_mode == "ultra" else "" | |
styled_image = designer.apply_style_pro( | |
image, | |
style="custom", | |
room_type=room_type_en, | |
strength=strength, | |
quality=quality_mode, | |
custom_prompt=f"{quality_boost}{room_type_en}, {custom_prompt}, interior design, high quality", | |
custom_negative=negative_prompt | |
) | |
else: | |
# Используем предустановленный стиль | |
styled_image = designer.apply_style_pro( | |
image, style, room_type_en, strength, quality=quality_mode | |
) | |
# HDR освещение | |
if enhance_lighting and quality_mode != "fast": | |
styled_image = designer.create_hdr_lighting(styled_image, intensity=0.3) | |
# Улучшение деталей (только для мощных GPU) | |
if add_details and designer.is_powerful_gpu and quality_mode == "ultra": | |
styled_image = designer.enhance_details(styled_image) | |
# Создаем сравнение до/после | |
comparison = processor.create_before_after(image, styled_image) | |
# Создаем вариации если запрошено | |
variations = None | |
if use_variations: | |
num_var = 8 if designer.is_powerful_gpu else 4 | |
var_images = designer.create_variations(image, num_variations=num_var) | |
variations = processor.create_grid( | |
var_images, | |
titles=[f"Вариант {i+1}" for i in range(len(var_images))] | |
) | |
# Извлекаем цветовую палитру | |
palette, colors = ColorPalette.extract_colors(styled_image) | |
# Информация о процессе | |
info = f""" | |
✅ Обработка завершена успешно! | |
📐 Тип комнаты: {room_type} | |
🎨 Стиль: {style} | |
💪 Интенсивность: {int(strength * 100)}% | |
⚡ Режим качества: {quality_mode.upper()} | |
🖼️ Разрешение: {styled_image.width}×{styled_image.height} | |
🤖 Модель: {designer.model_name} | |
🎨 Основные цвета дизайна: | |
""" | |
for i, color in enumerate(colors[:5]): | |
hex_color = '#{:02x}{:02x}{:02x}'.format(*color) | |
info += f"\n • {hex_color}" | |
return comparison, variations, palette, info | |
except Exception as e: | |
import traceback | |
error_details = traceback.format_exc() | |
return None, None, None, f"❌ Ошибка: {str(e)}\n\nДетали:\n{error_details}" | |
def change_room_element(image, element, value, strength): | |
"""Изменение отдельного элемента - оптимизированная версия""" | |
if image is None: | |
return None, "Загрузите изображение" | |
global designer | |
if designer is None: | |
designer = InteriorDesignerPro() | |
try: | |
# Ресайз для скорости | |
original_size = image.size | |
if image.width > 768 or image.height > 768: | |
image.thumbnail((768, 768), Image.Resampling.LANCZOS) | |
# Упрощенный промпт | |
from design_styles import ROOM_ELEMENTS | |
element_info = ROOM_ELEMENTS.get(element, {}) | |
# Быстрая генерация | |
result = designer.pipe( | |
prompt=f"room with {value}", | |
prompt_2=f"room with {value}", | |
image=image, | |
strength=min(strength, 0.8), | |
num_inference_steps=20, | |
guidance_scale=6.0 | |
).images[0] | |
# Возвращаем к оригинальному размеру если нужно | |
if result.size != original_size: | |
result = result.resize(original_size, Image.Resampling.LANCZOS) | |
return result, f"✅ {element} изменен на {value}" | |
except Exception as e: | |
return None, f"❌ Ошибка: {str(e)}" | |
def suggest_styles(image): | |
"""Предложение подходящих стилей""" | |
if image is None: | |
return "Загрузите изображение для получения рекомендаций" | |
# Анализируем текущий стиль | |
room_type = processor.detect_room_type(image) | |
suggestions = f""" | |
## 🏠 Анализ комнаты | |
Тип помещения: {room_type} | |
### 🎨 Рекомендуемые стили: | |
1. **Современный минимализм** | |
- Чистые линии и функциональность | |
- Нейтральные цвета с акцентами | |
- Идеально для: небольших пространств | |
2. **Скандинавский** | |
- Уют и естественность (хюгге) | |
- Светлые тона и натуральные материалы | |
- Идеально для: северных комнат | |
3. **Индустриальный** | |
- Брутальность и характер | |
- Металл, бетон, кирпич | |
- Идеально для: лофтов и студий | |
4. **Бохо** | |
- Творчество и эклектика | |
- Яркие цвета и текстиль | |
- Идеально для: творческих личностей | |
### 💡 Советы по настройкам: | |
- Интенсивность 50-70% - сохранит узнаваемость комнаты | |
- Интенсивность 70-90% - кардинальное преображение | |
- Режим Ultra - для финальной визуализации | |
- HDR освещение - добавит реализма | |
""" | |
return suggestions | |
def create_style_comparison(image, selected_styles, quality_mode): | |
"""Создание сравнения стилей""" | |
if image is None: | |
return None, "Загрузите изображение" | |
if not selected_styles: | |
return None, "Выберите хотя бы 2 стиля для сравнения" | |
global designer | |
if designer is None: | |
designer = InteriorDesignerPro() | |
try: | |
room_type = processor.detect_room_type(image) | |
room_type_en = ROOM_TYPES.get(room_type, "living room") | |
results = designer.create_style_comparison( | |
image, selected_styles, quality=quality_mode | |
) | |
# Создаем сетку для отображения | |
comparison_grid = designer._create_comparison_grid(results) | |
return comparison_grid, f"✅ Создано сравнение {len(selected_styles)} стилей" | |
except Exception as e: | |
return None, f"❌ Ошибка: {str(e)}" | |
# Добавляем метод в класс InteriorDesignerPro | |
def _create_comparison_grid(self, results): | |
"""Создание сетки из результатов""" | |
images = [] | |
for style_name, img in results: | |
# Добавляем подпись к изображению | |
labeled_img = processor.add_text_to_image(img, style_name) | |
images.append(labeled_img) | |
# Создаем сетку | |
return processor.create_grid(images) | |
# Динамически добавляем метод к классу | |
InteriorDesignerPro._create_comparison_grid = _create_comparison_grid | |
def enhance_image(image, scale, dpi): | |
"""Увеличение разрешения изображения""" | |
if image is None: | |
return None, None, "❌ Пожалуйста, загрузите изображение" | |
try: | |
# Инициализируем enhancer | |
enhancer = ImageEnhancer() | |
# Добавим отладку | |
original_size = f"{image.width}×{image.height}" | |
# Улучшаем изображение | |
enhanced = enhancer.upscale(image, scale=scale) | |
# Проверяем, изменился ли размер | |
if enhanced.size == image.size: | |
# Если размер не изменился, делаем upscale вручную через PIL | |
new_width = image.width * scale | |
new_height = image.height * scale | |
enhanced = image.resize((new_width, new_height), Image.Resampling.LANCZOS) | |
method = "PIL LANCZOS" | |
else: | |
method = "Real-ESRGAN" | |
# Настраиваем DPI | |
enhanced = enhancer.set_dpi(enhanced, dpi) | |
# Создаем сравнение | |
comparison = processor.create_before_after(image, enhanced) | |
enhanced_size = f"{enhanced.width}×{enhanced.height}" | |
info = f""" | |
✅ Изображение увеличено! | |
📐 Исходный размер: {original_size} | |
📐 Новый размер: {enhanced_size} | |
🔍 Масштаб: {scale}x | |
📊 DPI: {dpi} | |
🔧 Метод: {method} | |
""" | |
return enhanced, comparison, info | |
except Exception as e: | |
# Fallback на простой resize | |
try: | |
new_width = int(image.width * scale) | |
new_height = int(image.height * scale) | |
enhanced = image.resize((new_width, new_height), Image.Resampling.LANCZOS) | |
info = f""" | |
⚠️ Real-ESRGAN недоступен, использован PIL resize | |
📐 Исходный размер: {image.width}×{image.height} | |
📐 Новый размер: {enhanced.width}×{enhanced.height} | |
🔍 Масштаб: {scale}x | |
Ошибка: {str(e)} | |
""" | |
return enhanced, None, info | |
except Exception as e2: | |
return None, None, f"❌ Ошибка увеличения: {str(e2)}" | |
def remove_objects_by_text(image, objects_text, mask_precision): | |
"""Удаление объектов - улучшенная версия""" | |
if image is None: | |
return None, "❌ Загрузите изображение" | |
try: | |
global designer | |
if designer is None: | |
designer = InteriorDesignerPro() | |
# Ресайзим для скорости | |
original_size = image.size | |
if image.width > 768 or image.height > 768: | |
image.thumbnail((768, 768), Image.Resampling.LANCZOS) | |
# Создаем маску на основе описания | |
width, height = image.size | |
mask = Image.new('L', (width, height), 0) | |
draw = ImageDraw.Draw(mask) | |
# Улучшенная логика создания маски | |
objects_lower = objects_text.lower() | |
# Проверяем ключевые слова для позиции | |
if any(word in objects_lower for word in ["весь", "все", "полностью"]): | |
# Маска на все изображение | |
draw.rectangle([0, 0, width, height], fill=255) | |
elif any(word in objects_lower for word in ["центр", "середина", "диван", "стол", "кресло"]): | |
# Центральная область (для мебели обычно в центре) | |
margin_x = int(width * 0.2) | |
margin_y = int(height * 0.25) | |
draw.rectangle([margin_x, margin_y, width-margin_x, height-margin_y], fill=255) | |
elif any(word in objects_lower for word in ["лев", "слева"]): | |
# Левая часть | |
draw.rectangle([0, 0, int(width * 0.4), height], fill=255) | |
elif any(word in objects_lower for word in ["прав", "справа"]): | |
# Правая часть | |
draw.rectangle([int(width * 0.6), 0, width, height], fill=255) | |
elif any(word in objects_lower for word in ["верх", "потолок", "люстра"]): | |
# Верхняя часть | |
draw.rectangle([0, 0, width, int(height * 0.4)], fill=255) | |
elif any(word in objects_lower for word in ["низ", "пол", "ковер", "коврик"]): | |
# Нижняя часть | |
draw.rectangle([0, int(height * 0.6), width, height], fill=255) | |
elif any(word in objects_lower for word in ["картин", "рам", "постер"]): | |
# Области на стенах (обычно в верхней половине) | |
# Левая стена | |
draw.rectangle([0, int(height * 0.2), int(width * 0.2), int(height * 0.6)], fill=255) | |
# Правая стена | |
draw.rectangle([int(width * 0.8), int(height * 0.2), width, int(height * 0.6)], fill=255) | |
elif any(word in objects_lower for word in ["угол", "углу"]): | |
# Углы | |
corner_size = int(min(width, height) * 0.3) | |
if "лев" in objects_lower: | |
draw.rectangle([0, 0, corner_size, corner_size], fill=255) | |
elif "прав" in objects_lower: | |
draw.rectangle([width-corner_size, 0, width, corner_size], fill=255) | |
else: | |
# Все углы | |
draw.rectangle([0, 0, corner_size, corner_size], fill=255) | |
draw.rectangle([width-corner_size, 0, width, corner_size], fill=255) | |
else: | |
# По умолчанию - центральная область с учетом precision | |
margin = int(min(width, height) * (0.5 - mask_precision)) | |
draw.ellipse([margin, margin, width-margin, height-margin], fill=255) | |
# Размываем маску для плавных краев | |
mask = mask.filter(ImageFilter.GaussianBlur(radius=10)) | |
# Усиливаем inpainting промпт на основе контекста | |
room_type = "interior" | |
if any(word in objects_lower for word in ["гостин", "зал"]): | |
room_type = "living room" | |
elif any(word in objects_lower for word in ["спальн", "кроват"]): | |
room_type = "bedroom" | |
elif any(word in objects_lower for word in ["кухн", "кухон"]): | |
room_type = "kitchen" | |
# Проверяем наличие inpaint_pipe | |
if designer.inpaint_pipe: | |
result = designer.inpaint_pipe( | |
prompt=f"empty {room_type}, clean walls, seamless floor, no furniture", | |
negative_prompt=f"{objects_text}, furniture, objects, people", | |
image=image, | |
mask_image=mask, | |
strength=0.99, # Максимальная сила для полного удаления | |
num_inference_steps=30, # Немного больше шагов для качества | |
guidance_scale=7.5 # Выше для лучшего следования промпту | |
).images[0] | |
else: | |
# Fallback | |
from models import ObjectRemover | |
if not hasattr(designer, 'object_remover'): | |
designer.object_remover = ObjectRemover(None) | |
result = designer.object_remover.simple_inpaint(image, mask) | |
# Возвращаем к оригинальному размеру | |
if result.size != original_size: | |
result = result.resize(original_size, Image.Resampling.LANCZOS) | |
return result, f"✅ Удалено: {objects_text}" | |
except Exception as e: | |
import traceback | |
return None, f"❌ Ошибка: {str(e)}\n{traceback.format_exc()}" | |
# Создаем интерфейс | |
with gr.Blocks(title="AI Дизайнер интерьера Pro", theme=gr.themes.Soft(), css=custom_css) as app: | |
gr.Markdown(""" | |
# 🎨 AI Дизайнер интерьера Pro | |
### Преобразите свое пространство с помощью искусственного интеллекта | |
""") | |
with gr.Tabs(): | |
# Основная вкладка | |
with gr.TabItem("🎨 Дизайнер", id=0): | |
with gr.Row(): | |
with gr.Column(scale=1): | |
# Входные параметры | |
input_image = gr.Image( | |
label="Загрузите фото комнаты", | |
type="pil", | |
height=400 | |
) | |
with gr.Accordion("🎨 Настройки дизайна", open=True): | |
style = gr.Dropdown( | |
label="Стиль интерьера", | |
choices=list(DESIGN_STYLES.keys()), | |
value="Современный минимализм" | |
) | |
room_type = gr.Dropdown( | |
label="Тип комнаты", | |
choices=["Автоопределение"] + list(ROOM_TYPES.keys()), | |
value="Автоопределение" | |
) | |
strength = gr.Slider( | |
label="Интенсивность изменений", | |
minimum=0.3, | |
maximum=0.95, | |
value=0.75, | |
step=0.05, | |
info="Насколько сильно изменить оригинал" | |
) | |
quality_mode = gr.Radio( | |
label="Качество генерации", | |
choices=[ | |
("⚡ Быстрое (5 сек)", "fast"), | |
("⚖️ Сбалансированное (15 сек)", "balanced"), | |
("💎 Ультра (30 сек)", "ultra") | |
], | |
value="balanced", | |
info="Выберите баланс между скоростью и качеством" | |
) | |
with gr.Row(): | |
enhance_lighting = gr.Checkbox( | |
label="✨ HDR освещение", | |
value=True | |
) | |
add_details = gr.Checkbox( | |
label="🔍 Улучшить детализацию", | |
value=True | |
) | |
use_variations = gr.Checkbox( | |
label="🎭 Создать вариации", | |
value=False | |
) | |
with gr.Accordion("🎯 Продвинутые настройки", open=False): | |
custom_prompt = gr.Textbox( | |
label="Кастомное описание (английский)", | |
placeholder="cozy room with warm colors, plants, natural light", | |
lines=3, | |
info="Опишите желаемый результат своими словами" | |
) | |
negative_prompt = gr.Textbox( | |
label="Чего избегать", | |
placeholder="dark, cluttered, old furniture", | |
lines=2 | |
) | |
process_btn = gr.Button( | |
"🎨 Преобразить интерьер", | |
variant="primary", | |
size="lg" | |
) | |
# Примеры | |
gr.Examples( | |
examples=[ | |
["examples/living_room.jpg", "Современный минимализм", "Гостиная", 0.75, "balanced"], | |
["examples/bedroom.jpg", "Скандинавский", "Спальня", 0.7, "ultra"], | |
["examples/kitchen.jpg", "Индустриальный", "Кухня", 0.8, "balanced"] | |
], | |
inputs=[input_image, style, room_type, strength, quality_mode], | |
label="Примеры для быстрого старта" | |
) | |
with gr.Column(scale=1): | |
# Результаты | |
output_comparison = gr.Image( | |
label="Сравнение: До и После", | |
height=400 | |
) | |
with gr.Row(): | |
output_variations = gr.Image( | |
label="Варианты дизайна", | |
visible=False | |
) | |
output_palette = gr.Image( | |
label="Цветовая палитра", | |
height=100 | |
) | |
output_info = gr.Markdown( | |
label="Информация о процессе" | |
) | |
# Вкладка удаления объектов | |
with gr.TabItem("🗑️ Удаление объектов", id=1): | |
with gr.Row(): | |
with gr.Column(): | |
remove_image = gr.Image( | |
label="Загрузите фото", | |
type="pil", | |
height=400 | |
) | |
objects_to_remove = gr.Textbox( | |
label="Опишите что удалить", | |
placeholder="Например: красный диван в центре, картина на левой стене", | |
lines=3 | |
) | |
mask_precision = gr.Slider( | |
label="Размер области удаления", | |
minimum=0.1, | |
maximum=0.5, | |
value=0.3, | |
step=0.05 | |
) | |
remove_btn = gr.Button("🗑️ Удалить объекты", variant="primary") | |
with gr.Column(): | |
remove_output = gr.Image(label="Результат", height=400) | |
remove_info = gr.Textbox(label="Статус", lines=2) | |
# Вкладка детальных изменений | |
with gr.TabItem("🔧 Детальные изменения", id=2): | |
with gr.Row(): | |
with gr.Column(): | |
detail_image = gr.Image( | |
label="Изображение для изменения", | |
type="pil", | |
height=300 | |
) | |
element_type = gr.Dropdown( | |
label="Что изменить", | |
choices=list(ROOM_ELEMENTS.keys()), | |
value="Стены" | |
) | |
element_value = gr.Textbox( | |
label="Новое значение", | |
placeholder="Например: белый цвет, деревянный паркет", | |
lines=2 | |
) | |
element_strength = gr.Slider( | |
label="Сила изменения", | |
minimum=0.3, | |
maximum=0.9, | |
value=0.5, | |
step=0.05 | |
) | |
change_btn = gr.Button("Применить изменение", variant="primary") | |
with gr.Column(): | |
detail_output = gr.Image(label="Результат", height=300) | |
detail_info = gr.Textbox(label="Статус", lines=2) | |
# Вкладка сравнения стилей | |
with gr.TabItem("🎭 Сравнение стилей", id=3): | |
with gr.Row(): | |
with gr.Column(): | |
compare_image = gr.Image( | |
label="Загрузите фото для сравнения стилей", | |
type="pil", | |
height=400 | |
) | |
selected_styles = gr.CheckboxGroup( | |
label="Выберите стили для сравнения (2-6)", | |
choices=list(DESIGN_STYLES.keys()), | |
value=["Современный минимализм", "Скандинавский"] | |
) | |
compare_quality = gr.Radio( | |
label="Скорость генерации", | |
choices=[("Быстро", "fast"), ("Качественно", "balanced")], | |
value="fast" | |
) | |
compare_btn = gr.Button("🎭 Сравнить стили", variant="primary") | |
with gr.Column(): | |
compare_output = gr.Image(label="Сравнение стилей", height=600) | |
compare_info = gr.Textbox(label="Статус", lines=2) | |
# Вкладка увеличения разрешения | |
with gr.TabItem("🔍 Увеличение разрешения", id=4): | |
with gr.Row(): | |
with gr.Column(): | |
upscale_image = gr.Image( | |
label="Изображение для увеличения", | |
type="pil", | |
height=400 | |
) | |
scale_factor = gr.Radio( | |
label="Масштаб увеличения", | |
choices=[("2x", 2), ("4x", 4)], | |
value=2 | |
) | |
dpi_setting = gr.Radio( | |
label="DPI для печати", | |
choices=[("Экран (96)", 96), ("Печать (150)", 150), ("Высокое качество (300)", 300)], | |
value=96 | |
) | |
upscale_btn = gr.Button("🔍 Увеличить разрешение", variant="primary") | |
with gr.Column(): | |
upscale_output = gr.Image(label="Увеличенное изображение", height=400) | |
upscale_comparison = gr.Image(label="Сравнение", height=200) | |
upscale_info = gr.Markdown() | |
# Вкладка рекомендаций | |
with gr.TabItem("💡 Рекомендации", id=5): | |
with gr.Row(): | |
with gr.Column(): | |
suggest_image = gr.Image( | |
label="Загрузите фото для анализа", | |
type="pil", | |
height=400 | |
) | |
suggest_btn = gr.Button("Получить рекомендации", variant="primary") | |
with gr.Column(): | |
suggestions = gr.Markdown() | |
# Цветовые палитры для стилей | |
gr.Markdown("### 🎨 Цветовые палитры популярных стилей") | |
for style_name in list(DESIGN_STYLES.keys())[:4]: | |
colors = get_style_colors(style_name) | |
color_blocks = " ".join([f'<span style="background-color:{c}; padding:10px 20px; margin:2px; display:inline-block; border-radius:5px;"></span>' for c in colors]) | |
gr.HTML(f"<div class='info-box'><strong>{style_name}:</strong><br>{color_blocks}</div>") | |
# Обработчики событий | |
process_btn.click( | |
process_image, | |
inputs=[input_image, style, room_type, strength, quality_mode, | |
enhance_lighting, add_details, custom_prompt, use_variations, negative_prompt], | |
outputs=[output_comparison, output_variations, output_palette, output_info] | |
) | |
use_variations.change( | |
lambda x: gr.update(visible=x), | |
inputs=[use_variations], | |
outputs=[output_variations] | |
) | |
change_btn.click( | |
change_room_element, | |
inputs=[detail_image, element_type, element_value, element_strength], | |
outputs=[detail_output, detail_info] | |
) | |
remove_btn.click( | |
remove_objects_by_text, | |
inputs=[remove_image, objects_to_remove, mask_precision], | |
outputs=[remove_output, remove_info] | |
) | |
compare_btn.click( | |
create_style_comparison, | |
inputs=[compare_image, selected_styles, compare_quality], | |
outputs=[compare_output, compare_info] | |
) | |
upscale_btn.click( | |
enhance_image, | |
inputs=[upscale_image, scale_factor, dpi_setting], | |
outputs=[upscale_output, upscale_comparison, upscale_info] | |
) | |
suggest_btn.click( | |
suggest_styles, | |
inputs=[suggest_image], | |
outputs=[suggestions] | |
) | |
# Информация внизу | |
author_info = os.environ.get("AUTHOR_INFO", "") | |
if author_info: | |
gr.Markdown(f""" | |
--- | |
<center>{author_info}</center> | |
""") | |
gr.Markdown(""" | |
--- | |
### 📝 Инструкция по использованию: | |
1. Загрузите фото вашей комнаты | |
2. Выберите стиль из 20 доступных вариантов | |
3. Настройте параметры по вкусу | |
4. Нажмите "Преобразить интерьер" | |
### 🚀 Возможности: | |
- 20 стилей дизайна - от минимализма до ар-деко | |
- Автоопределение типа комнаты | |
- Создание вариаций - до 8 вариантов за раз | |
- Детальные изменения - меняйте отдельные элементы | |
- HDR освещение - профессиональная обработка света | |
- Анализ цветовой палитры | |
--- | |
<center>Made with ❤️ for interior design enthusiasts</center> | |
""") | |
# ВАЖНО! Запуск приложения | |
if __name__ == "__main__": | |
app.launch( | |
share=False, | |
show_error=True, | |
server_name="0.0.0.0", | |
server_port=7860 | |
) | |