Spaces:
ginigen
/
Running on Zero

Design / app.py
ginipick's picture
Update app.py
25537ba verified
raw
history blame
9.79 kB
import gradio as gr
import numpy as np
import random
import torch
from diffusers import DiffusionPipeline
import spaces
from transformers import pipeline
# ๊ธฐ๋ณธ ์„ค์ •
dtype = torch.bfloat16
device = "cuda" if torch.cuda.is_available() else "cpu"
# ํ•œ๊ตญ์–ด-์˜์–ด ๋ฒˆ์—ญ ๋ชจ๋ธ ๋กœ๋“œ (CPU์—์„œ ์‹คํ–‰)
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-ko-en", device="cpu")
# ๋ชจ๋ธ ๋กœ๋“œ
pipe = DiffusionPipeline.from_pretrained(
"black-forest-labs/FLUX.1-schnell",
torch_dtype=dtype
).to(device)
MAX_SEED = np.iinfo(np.int32).max
MAX_IMAGE_SIZE = 2048
# ์ œํ’ˆ ๋””์ž์ธ ์ปจ์…‰ ์˜ˆ์‹œ
EXAMPLES = [
{
"title": "Smart Coffee Machine",
"prompt": """A sleek industrial design concept for a coffee machine:
- Curved metallic body with minimal bezel
- Touchscreen panel for settings
- Modern matte black finish
- Hand-drawn concept sketch style""",
"width": 1024,
"height": 1024
},
{
"title": "AI Speaker",
"prompt": """A futuristic AI speaker concept:
- Cylindrical shape with LED ring near top
- Voice assistant concept, floating panel controls
- Smooth glossy finish with minimal seams
- Techy, modern look in grayscale""",
"width": 1024,
"height": 1024
},
{
"title": "Next-Gen Smartphone",
"prompt": """A wireframe-style concept for a bezel-less smartphone:
- Edge-to-edge display
- Integrated camera under screen
- Metallic frame, minimal ports
- Sleek, glossy black design""",
"width": 1024,
"height": 1024
},
{
"title": "Futuristic Electric Bicycle",
"prompt": """An industrial design sketch of an electric bike:
- Lightweight carbon frame, aerodynamic lines
- Integrated battery, sleek display on handlebars
- Neon color highlights on wheels
- High-tech vibe, minimal clutter""",
"width": 1024,
"height": 1024
},
{
"title": "Concept Car Interior",
"prompt": """A luxurious and futuristic car interior concept:
- Wrap-around digital dashboard
- Minimalistic steering control, seat controls on touchscreen
- Ambient LED accent lights
- Soft leather seats, bright accent stitching""",
"width": 1024,
"height": 1024
}
]
# Convert examples to Gradio format (if needed)
GRADIO_EXAMPLES = [
[example["prompt"], example["width"], example["height"]]
for example in EXAMPLES
]
# ํ•œ๊ตญ์–ด ๊ฐ์ง€ ํ•จ์ˆ˜
def contains_korean(text):
for char in text:
if ord('๊ฐ€') <= ord(char) <= ord('ํžฃ'):
return True
return False
# ํ•„์š”์‹œ ๋ฒˆ์—ญ ํ›„ ์ถ”๋ก  ํ•จ์ˆ˜
@spaces.GPU()
def infer(prompt, seed=42, randomize_seed=False, width=1024, height=1024, num_inference_steps=4, progress=gr.Progress(track_tqdm=True)):
# ํ•œ๊ตญ์–ด ๊ฐ์ง€ ๋ฐ ๋ฒˆ์—ญ
original_prompt = prompt
translated = False
if contains_korean(prompt):
translated = True
translation = translator(prompt)
prompt = translation[0]['translation_text']
# ๋žœ๋ค ์‹œ๋“œ ์„ค์ •
if randomize_seed:
seed = random.randint(0, MAX_SEED)
generator = torch.Generator().manual_seed(seed)
# ๋ชจ๋ธ ์‹คํ–‰
image = pipe(
prompt=prompt,
width=width,
height=height,
num_inference_steps=num_inference_steps,
generator=generator,
guidance_scale=0.0
).images[0]
# ๋ฒˆ์—ญ ์ •๋ณด ๋ฐ˜ํ™˜
if translated:
return image, seed, original_prompt, prompt
else:
return image, seed, None, None
# CSS ์Šคํƒ€์ผ (๊ธฐ์กด ๊ตฌ์กฐ ์œ ์ง€)
css = """
.container {
display: flex;
flex-direction: row;
height: 100%;
}
.input-column {
flex: 1;
padding: 20px;
border-right: 2px solid #eee;
max-width: 800px;
}
.examples-column {
flex: 1;
padding: 20px;
overflow-y: auto;
background: #f7f7f7;
}
.title {
text-align: center;
color: #2a2a2a;
padding: 20px;
font-size: 2.5em;
font-weight: bold;
background: linear-gradient(90deg, #f0f0f0 0%, #ffffff 100%);
border-bottom: 3px solid #ddd;
margin-bottom: 30px;
}
.subtitle {
text-align: center;
color: #666;
margin-bottom: 30px;
}
.input-box {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
margin-bottom: 20px;
width: 100%;
}
.input-box textarea {
width: 100% !important;
min-width: 600px !important;
font-size: 14px !important;
line-height: 1.5 !important;
padding: 12px !important;
}
.example-card {
background: white;
padding: 15px;
margin: 10px 0;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
.example-title {
font-weight: bold;
color: #2a2a2a;
margin-bottom: 10px;
}
.contain {
max-width: 1400px !important;
margin: 0 auto !important;
}
.input-area {
flex: 2 !important;
}
.examples-area {
flex: 1 !important;
}
.translation-info {
background-color: #f8f9fa;
border-left: 4px solid #17a2b8;
padding: 10px 15px;
margin-top: 10px;
border-radius: 4px;
font-size: 14px;
}
"""
with gr.Blocks(css=css) as demo:
gr.Markdown(
"""
<div class="title">GINI Design</div>
<div class="subtitle">Generate sleek industrial/product design concepts with FLUX AI</div>
""")
with gr.Row(equal_height=True):
# ์™ผ์ชฝ ์ž…๋ ฅ ์ปฌ๋Ÿผ
with gr.Column(elem_id="input-column", scale=2):
with gr.Group(elem_classes="input-box"):
prompt = gr.Text(
label="Design Prompt (ํ•œ๊ตญ์–ด ๋˜๋Š” ์˜์–ด๋กœ ์ž…๋ ฅํ•˜์„ธ์š”)",
placeholder="Enter your product design concept details in Korean or English...",
lines=10,
elem_classes="prompt-input"
)
run_button = gr.Button("Generate Design", variant="primary")
result = gr.Image(label="Generated Design")
# ๋ฒˆ์—ญ ์ •๋ณด ํ‘œ์‹œ ์˜์—ญ
original_prompt = gr.Textbox(visible=False)
translated_prompt = gr.Textbox(visible=False)
translation_info = gr.Markdown(visible=False, elem_classes="translation-info")
# ๋ฒˆ์—ญ ์ •๋ณด ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜
def update_translation_info(original, translated):
if original and translated:
return gr.update(visible=True, value=f"๐Ÿ”„ Korean prompt was translated to English:\n\n**Original:** {original}\n\n**Translated:** {translated}")
else:
return gr.update(visible=False)
with gr.Accordion("Advanced Settings", open=False):
seed = gr.Slider(
label="Seed",
minimum=0,
maximum=MAX_SEED,
step=1,
value=0,
)
randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
with gr.Row():
width = gr.Slider(
label="Width",
minimum=256,
maximum=MAX_IMAGE_SIZE,
step=32,
value=1024,
)
height = gr.Slider(
label="Height",
minimum=256,
maximum=MAX_IMAGE_SIZE,
step=32,
value=1024,
)
num_inference_steps = gr.Slider(
label="Number of inference steps",
minimum=1,
maximum=50,
step=1,
value=4,
)
# ์˜ค๋ฅธ์ชฝ ์˜ˆ์ œ ์ปฌ๋Ÿผ
with gr.Column(elem_id="examples-column", scale=1):
gr.Markdown("### Example Product Designs")
for example in EXAMPLES:
with gr.Group(elem_classes="example-card"):
gr.Markdown(f"#### {example['title']}")
gr.Markdown(f"```\n{example['prompt']}\n```")
def create_example_handler(ex):
def handler():
return {
prompt: ex["prompt"],
width: ex["width"],
height: ex["height"]
}
return handler
gr.Button("Use This Example", size="sm").click(
fn=create_example_handler(example),
outputs=[prompt, width, height]
)
# ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ (๋ฒ„ํŠผ ํด๋ฆญ & ํ…์ŠคํŠธ๋ฐ•์Šค ์—”ํ„ฐ)
gr.on(
triggers=[run_button.click, prompt.submit],
fn=infer,
inputs=[prompt, seed, randomize_seed, width, height, num_inference_steps],
outputs=[result, seed, original_prompt, translated_prompt]
)
# ๋ฒˆ์—ญ ์ •๋ณด ์—…๋ฐ์ดํŠธ ์ด๋ฒคํŠธ
gr.on(
triggers=[original_prompt.change, translated_prompt.change],
fn=update_translation_info,
inputs=[original_prompt, translated_prompt],
outputs=[translation_info]
)
if __name__ == "__main__":
demo.queue()
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
show_error=True,
debug=True
)