interior_room / app_gradio_backup.py
SpacelyJohn's picture
Upload 7 files
c00b86e verified
import gradio as gr
import torch
import numpy as np
from PIL import Image
import os
# ๋ชจ๋ธ import๋“ค
try:
from diffusers import ControlNetModel, StableDiffusionControlNetInpaintPipeline, UniPCMultistepScheduler
from transformers import AutoImageProcessor, SegformerForSemanticSegmentation
from controlnet_aux import MLSDdetector
MLSD_AVAILABLE = True
except ImportError as e:
print(f"์ผ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋”ฉ ์‹คํŒจ: {e}")
MLSD_AVAILABLE = False
class SpacelyFurnitureDesigner:
def __init__(self):
self.pipe = None
self.seg_processor = None
self.segmentor = None
self.mlsd_processor = None
# ํšŒ์‚ฌ์šฉ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ
self.office_templates = {
"๊ฐœ์ธ์‚ฌ๋ฌด์‹ค": "modern private office with executive desk, ergonomic chair, bookshelf, and professional lighting",
"ํšŒ์˜์‹ค": "professional conference room with large meeting table, comfortable chairs, whiteboard, and corporate lighting",
"ํœด๊ฒŒ์‹ค": "corporate break room with comfortable seating, coffee table, plants, and relaxing atmosphere",
"์˜คํ”ˆ์˜คํ”ผ์Šค": "open office space with multiple workstations, modern desks, office chairs, and collaborative areas",
"๋ฆฌ์…‰์…˜": "elegant reception area with reception desk, waiting chairs, company logo wall, and welcoming ambiance",
"CEO์‹ค": "luxury executive office with premium wooden desk, leather chair, awards display, and elegant lighting"
}
self.quality_suffix = "professional interior design, corporate style, clean, modern, functional, well-lit, 4K, high quality"
def load_models(self):
"""๋ชจ๋ธ ์ง€์—ฐ ๋กœ๋”ฉ"""
if self.pipe is None:
print("๐Ÿ”„ AI ๋ชจ๋ธ ๋กœ๋”ฉ ์ค‘...")
try:
if MLSD_AVAILABLE and torch.cuda.is_available():
# ์ „์ฒด ControlNet ์„ค์ •
controlnet = [
ControlNetModel.from_pretrained("BertChristiaens/controlnet-seg-room", torch_dtype=torch.float16),
ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-mlsd", torch_dtype=torch.float16)
]
self.mlsd_processor = MLSDdetector.from_pretrained("lllyasviel/Annotators")
else:
# ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜๋งŒ ์‚ฌ์šฉ
controlnet = ControlNetModel.from_pretrained("BertChristiaens/controlnet-seg-room", torch_dtype=torch.float16)
# ๋ฉ”์ธ ํŒŒ์ดํ”„๋ผ์ธ
self.pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(
"SG161222/Realistic_Vision_V3.0_VAE",
controlnet=controlnet,
safety_checker=None,
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
)
self.pipe.scheduler = UniPCMultistepScheduler.from_config(self.pipe.scheduler.config)
if torch.cuda.is_available():
self.pipe = self.pipe.to("cuda")
try:
self.pipe.enable_xformers_memory_efficient_attention()
except:
pass
# ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ ๋ชจ๋ธ
self.seg_processor = AutoImageProcessor.from_pretrained("nvidia/segformer-b5-finetuned-ade-640-640")
self.segmentor = SegformerForSemanticSegmentation.from_pretrained("nvidia/segformer-b5-finetuned-ade-640-640")
print("โœ… ๋ชจ๋ธ ๋กœ๋”ฉ ์™„๋ฃŒ!")
except Exception as e:
print(f"โŒ ๋ชจ๋ธ ๋กœ๋”ฉ ์‹คํŒจ: {e}")
return False
return True
def resize_dimensions(self, dimensions, target_size=768):
"""๋น„์œจ ์œ ์ง€ํ•˜๋ฉฐ ๋ฆฌ์‚ฌ์ด์ฆˆ"""
width, height = dimensions
if width < target_size and height < target_size:
return dimensions
if width > height:
aspect_ratio = height / width
return (target_size, int(target_size * aspect_ratio))
else:
aspect_ratio = width / height
return (int(target_size * aspect_ratio), target_size)
def create_simple_mask(self, image):
"""๊ฐ„๋‹จํ•œ ๋งˆ์Šคํฌ ์ƒ์„ฑ"""
# ์ „์ฒด ์ด๋ฏธ์ง€๋ฅผ ๋ณ€๊ฒฝ ๋Œ€์ƒ์œผ๋กœ ์„ค์ •
mask = Image.new('RGB', image.size, (255, 255, 255))
return image, mask
def design_space(self, input_image, space_type, custom_prompt="", num_steps=30, guidance_scale=12):
"""๊ณต๊ฐ„ ๋””์ž์ธ ์ƒ์„ฑ ๋ฉ”์ธ ํ•จ์ˆ˜"""
if input_image is None:
return None, "โŒ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”!"
# ๋ชจ๋ธ ๋กœ๋”ฉ
if not self.load_models():
return None, "โŒ AI ๋ชจ๋ธ ๋กœ๋”ฉ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."
try:
# ํ”„๋กฌํ”„ํŠธ ๊ตฌ์„ฑ
if custom_prompt.strip():
base_prompt = custom_prompt
else:
base_prompt = self.office_templates.get(space_type, self.office_templates["๊ฐœ์ธ์‚ฌ๋ฌด์‹ค"])
full_prompt = f"{base_prompt}, {self.quality_suffix}"
# ์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ
orig_w, orig_h = input_image.size
new_width, new_height = self.resize_dimensions(input_image.size, 768)
resized_image = input_image.resize((new_width, new_height))
# ๋งˆ์Šคํฌ ์ƒ์„ฑ
seg_image, mask_image = self.create_simple_mask(resized_image)
# ControlNet ์ด๋ฏธ์ง€ ์ค€๋น„
if MLSD_AVAILABLE and self.mlsd_processor:
mlsd_image = self.mlsd_processor(resized_image)
mlsd_image = mlsd_image.resize(resized_image.size)
control_images = [seg_image, mlsd_image]
controlnet_conditioning_scale = [0.4, 0.2]
control_guidance_start = [0, 0.1]
control_guidance_end = [0.5, 0.25]
else:
control_images = seg_image
controlnet_conditioning_scale = 0.4
control_guidance_start = 0
control_guidance_end = 0.5
# AI ์ด๋ฏธ์ง€ ์ƒ์„ฑ
result = self.pipe(
prompt=full_prompt,
negative_prompt="lowres, watermark, blurry, unprofessional, cluttered, outdated furniture, bad quality",
num_inference_steps=num_steps,
strength=0.8,
guidance_scale=guidance_scale,
image=resized_image,
mask_image=mask_image,
control_image=control_images,
controlnet_conditioning_scale=controlnet_conditioning_scale,
control_guidance_start=control_guidance_start,
control_guidance_end=control_guidance_end
).images[0]
# ์›๋ณธ ํฌ๊ธฐ๋กœ ๋ณต์›
final_image = result.resize((orig_w, orig_h), Image.Resampling.LANCZOS)
success_msg = f"โœ… {space_type} ๋””์ž์ธ ์™„๋ฃŒ!\n๐Ÿ“ ์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ: {full_prompt[:100]}..."
return final_image, success_msg
except Exception as e:
error_msg = f"โŒ ๋””์ž์ธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
print(error_msg)
return None, error_msg
# ์ „์—ญ ๋””์ž์ด๋„ˆ ์ธ์Šคํ„ด์Šค
designer = SpacelyFurnitureDesigner()
def create_ui():
"""Gradio UI ์ƒ์„ฑ"""
with gr.Blocks(
title="๐Ÿข Spacely AI ๊ฐ€๊ตฌ ๋ฐฐ์น˜ ๋””์ž์ด๋„ˆ",
theme=gr.themes.Soft(),
css="""
.gradio-container {
max-width: 1200px !important;
}
.title {
text-align: center;
color: #2D3748;
margin-bottom: 20px;
}
"""
) as demo:
gr.HTML("""
<div class="title">
<h1>๐Ÿข Spacely AI ๊ฐ€๊ตฌ ๋ฐฐ์น˜ ๋””์ž์ด๋„ˆ</h1>
<p>๋นˆ ๋ฐฉ ์‚ฌ์ง„์„ ์—…๋กœ๋“œํ•˜๋ฉด AI๊ฐ€ ์ „๋ฌธ์ ์ธ ์˜คํ”ผ์Šค ๊ณต๊ฐ„์œผ๋กœ ๋””์ž์ธํ•ด๋“œ๋ฆฝ๋‹ˆ๋‹ค</p>
</div>
""")
with gr.Row():
# ์ž…๋ ฅ ์ปฌ๋Ÿผ
with gr.Column(scale=1):
gr.HTML("<h3>๐Ÿ“ ์ž…๋ ฅ ์„ค์ •</h3>")
input_image = gr.Image(
label="๋นˆ๋ฐฉ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ",
type="pil",
height=300
)
space_type = gr.Dropdown(
choices=list(designer.office_templates.keys()),
label="๊ณต๊ฐ„ ํƒ€์ž… ์„ ํƒ",
value="๊ฐœ์ธ์‚ฌ๋ฌด์‹ค"
)
custom_prompt = gr.Textbox(
label="์ปค์Šคํ…€ ํ”„๋กฌํ”„ํŠธ (์„ ํƒ์‚ฌํ•ญ)",
placeholder="์˜ˆ: minimalist CEO office with wooden desk...",
lines=3
)
with gr.Row():
num_steps = gr.Slider(
minimum=10,
maximum=50,
value=30,
step=5,
label="์ƒ์„ฑ ํ’ˆ์งˆ (๋†’์„์ˆ˜๋ก ๋А๋ฆผ)"
)
guidance_scale = gr.Slider(
minimum=5,
maximum=20,
value=12,
step=1,
label="ํ”„๋กฌํ”„ํŠธ ๋ฐ˜์˜๋„"
)
generate_btn = gr.Button(
"๐ŸŽจ AI ๋””์ž์ธ ์ƒ์„ฑ",
variant="primary",
size="lg"
)
# ์ถœ๋ ฅ ์ปฌ๋Ÿผ
with gr.Column(scale=1):
gr.HTML("<h3>โœจ ๋””์ž์ธ ๊ฒฐ๊ณผ</h3>")
output_image = gr.Image(
label="AI๊ฐ€ ๋””์ž์ธํ•œ ์˜คํ”ผ์Šค",
height=300
)
output_text = gr.Textbox(
label="์ƒ์„ฑ ๊ฒฐ๊ณผ",
lines=4,
max_lines=8
)
gr.HTML("""
<div style="margin-top: 20px; padding: 15px; background-color: #F7FAFC; border-radius: 10px;">
<h4>๐Ÿ’ก ์‚ฌ์šฉ ํŒ</h4>
<ul>
<li>๊น”๋”ํ•œ ๋นˆ๋ฐฉ ์‚ฌ์ง„์ผ์ˆ˜๋ก ์ข‹์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค</li>
<li>์ปค์Šคํ…€ ํ”„๋กฌํ”„ํŠธ๋กœ ์›ํ•˜๋Š” ๊ฐ€๊ตฌ๋‚˜ ์Šคํƒ€์ผ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค</li>
<li>์ƒ์„ฑ ํ’ˆ์งˆ์„ ๋†’์ด๋ฉด ๋” ์ •๊ตํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์ง€๋งŒ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค</li>
</ul>
</div>
""")
# ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
generate_btn.click(
fn=designer.design_space,
inputs=[input_image, space_type, custom_prompt, num_steps, guidance_scale],
outputs=[output_image, output_text]
)
# ์˜ˆ์‹œ ์ด๋ฏธ์ง€๋“ค
gr.HTML("<h3>๐Ÿ“ธ ์˜ˆ์‹œ ๊ฒฐ๊ณผ</h3>")
with gr.Row():
gr.Examples(
examples=[
["๊ฐœ์ธ์‚ฌ๋ฌด์‹ค", "modern executive office with wooden desk"],
["ํšŒ์˜์‹ค", "professional conference room for 10 people"],
["ํœด๊ฒŒ์‹ค", "comfortable break room with plants and coffee area"],
],
inputs=[space_type, custom_prompt],
label="๋น ๋ฅธ ์„ค์ • ์˜ˆ์‹œ"
)
return demo
# ์•ฑ ์‹คํ–‰
if __name__ == "__main__":
demo = create_ui()
demo.launch(
server_name="0.0.0.0",
server_port=7860,
show_error=True,
share=True # ๊ณต๊ฐœ URL ์ƒ์„ฑ
)