Spaces:
Running
Running
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 ์์ฑ | |
) |