fh46jderf / app.py
ssboost's picture
Update app.py
a5a8f57 verified
raw
history blame
33 kB
import os
import sys
import base64
import io
import logging
import tempfile
import traceback
import requests
from PIL import Image
import gradio as gr
from gradio_client import Client, handle_file
from dotenv import load_dotenv
# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋กœ๋“œ
load_dotenv()
# ๋กœ๊น… ์„ค์ • (๋ฏผ๊ฐํ•œ ์ •๋ณด ์ œ์™ธ)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("app.log"),
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger("image-enhancer-app")
# API ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” (ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ)
API_ENDPOINT = os.environ.get("API_ENDPOINT")
if not API_ENDPOINT:
logger.error("API_ENDPOINT environment variable is not set")
sys.exit(1)
try:
# ๋กœ๊ทธ์— ์—”๋“œํฌ์ธํŠธ ์ •๋ณด ์ถœ๋ ฅํ•˜์ง€ ์•Š์Œ
api_client = Client(API_ENDPOINT)
logger.info("API client initialized successfully")
except Exception as e:
logger.error(f"Failed to initialize API client: {e}")
sys.exit(1)
# backgrounds.py ์ „์ฒด ๋‚ด์šฉ์„ ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ
def load_backgrounds_from_env():
"""ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ backgrounds.py ์ „์ฒด ๋‚ด์šฉ ๋กœ๋“œ"""
backgrounds_code = os.environ.get("BACKGROUNDS_DATA", "")
if not backgrounds_code:
logger.warning("BACKGROUNDS_DATA environment variable is empty")
return {}, {}, {}, {}, {}, {}, {}
try:
# ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๊ฐ€์ ธ์˜จ ์ฝ”๋“œ ์‹คํ–‰ํ•˜์—ฌ ๋”•์…”๋„ˆ๋ฆฌ๋“ค ์ถ”์ถœ
local_vars = {}
exec(backgrounds_code, {}, local_vars)
return (
local_vars.get("SIMPLE_BACKGROUNDS", {}),
local_vars.get("STUDIO_BACKGROUNDS", {}),
local_vars.get("NATURE_BACKGROUNDS", {}),
local_vars.get("INDOOR_BACKGROUNDS", {}),
local_vars.get("SPECIAL_BACKGROUNDS", {}),
local_vars.get("JEWELRY_BACKGROUNDS", {}),
local_vars.get("SPECIAL_EFFECTS_BACKGROUNDS", {})
)
except Exception as e:
logger.error(f"Failed to parse BACKGROUNDS_DATA: {e}")
return {}, {}, {}, {}, {}, {}, {}
# ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๋ฐฐ๊ฒฝ ๋”•์…”๋„ˆ๋ฆฌ๋“ค ๋กœ๋“œ
(SIMPLE_BACKGROUNDS, STUDIO_BACKGROUNDS, NATURE_BACKGROUNDS,
INDOOR_BACKGROUNDS, SPECIAL_BACKGROUNDS, JEWELRY_BACKGROUNDS,
SPECIAL_EFFECTS_BACKGROUNDS) = load_backgrounds_from_env()
# ๋งŒ์•ฝ ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ๋น„์–ด์žˆ๋‹ค๋ฉด ๊ธฐ๋ณธ๊ฐ’ ์‚ฌ์šฉ
if not SIMPLE_BACKGROUNDS:
SIMPLE_BACKGROUNDS = {
"ํ™”์ดํŠธ ๊ธฐ๋ณธ": "clean white background with soft lighting",
"ํšŒ์ƒ‰ ํˆฌํ†ค": "light gray background with minimal shadows",
"๋ผ์ดํŠธ ๊ทธ๋ ˆ์ด": "soft light gray backdrop with even illumination",
"๊ทธ๋ ˆ์ด ๊ทธ๋ผ๋ฐ์ด์…˜ ์ŠคํฌํŠธ๋ผ์ดํŠธ": "gray gradient with spotlight",
"ํ”„๋ฆฌ๋ฏธ์—„ ๋“œ๋ผ๋งˆํ‹ฑ ๋ธ”๋ž™": "premium dramatic black background",
"๋”ฅ๋ธ”๋ฃจ ์œ ๋ฆฌ๋ฐ˜์‚ฌ": "deep blue glass reflection",
"ํŒŒ์Šคํ…” ๊ทธ๋ผ๋ฐ์ด์…˜": "pastel gradient background",
"์Šค์นด์ด๋ธ”๋ฃจ ํŒŒ์Šคํ…”": "sky blue pastel",
"๋ฒ„ํ„ฐ์˜๋กœ์šฐ ํŒŒ์Šคํ…”": "butter yellow pastel",
"๋ธ”๋ฃจ ์›์ƒ‰": "pure blue background",
"๋ ˆ๋“œ ์›์ƒ‰": "pure red background"
}
if not STUDIO_BACKGROUNDS:
STUDIO_BACKGROUNDS = {
"์—ฐ๋…น์ƒ‰ ์žฅ๋ฏธ ์ •์›": "soft green rose garden",
"์—ฐ๋ถ„ํ™ ์žฅ๋ฏธ ๋Œ€๋ฆฌ์„": "pink rose with marble",
"ํŒŒ์Šคํ…” ๋ธ”๋ฃจ ์ˆ˜๊ตญ": "pastel blue hydrangea",
"์†Œํ”„ํŠธ ํ•‘ํฌ ๋ฒš๊ฝƒ": "soft pink cherry blossom",
"ํŒŒ์Šคํ…” ์˜๋กœ์šฐ ๊ฝƒ๋ด‰์˜ค๋ฆฌ": "pastel yellow buds",
"์•„์ด๋ณด๋ฆฌ ๋กœ์ฆˆ ์‹ฌํ”Œ": "ivory rose simple",
"์‹ฌํ”Œ ํ™”์ดํŠธ ์ž‘์€ ํ™”๋ถ„": "simple white small pot",
"ํผํ”Œ ์žฅ๋‚œ์Šค๋Ÿฌ์šด ์‹ฌ๋น„๋กœ์šด ๋ถ„์œ„๊ธฐ": "purple playful mood",
"์ฝ”์ง€ ๋ฐ์Šคํฌ ํ”Œ๋žœํŠธ": "cozy desk plant",
"์—ฐํ•‘ํฌ ํŠค๋ฆฝ ์ž‘์€ํ…Œ์ด๋ธ”": "light pink tulip small table",
"์˜คํฌ์šฐ๋“œ ํŠค๋ฆฝ ์ƒค์›Œ ํ‘ธํ”„": "oak wood tulip shower puff",
"ํฌ๋ฆผ ์ฝ”ํŠผ": "cream cotton",
"๋ธŒ๋ผ์šด ๊ฑฐ์นœ ํŽ˜์ดํผ": "brown rough paper"
}
if not NATURE_BACKGROUNDS:
NATURE_BACKGROUNDS = {
"์ž‘์€ ํŒŒ๋„๊ฐ€ ์žˆ๋Š” ํ•ด๋ณ€": "beach with small waves",
"ํŽญ๊ท„์ด ์žˆ๋Š” ๋น™์‚ฐ": "iceberg with penguin",
"๋ˆˆ๋‚ด๋ฆฌ๋Š” ์‚ฐ์•… ์„ค์›": "snowy mountain field",
"์—ด๋Œ€ํ•ด๋ณ€": "tropical beach",
"์ผ์ถœ ์ง์ „์˜ ๋ฐ”์œ„์‚ฐ": "rocky mountain before sunrise",
"์ดˆ๊ทผ์ ‘ ๋ด„๊ฝƒ ๋“คํŒ": "close-up spring flower field",
"๋ฌผ๊ฐ€ ๋ฐ”์œ„": "waterside rocks",
"์ž‘์€ ๋Œ์ด ๊น”๋ฆฐ ์–•์€ ๋ฌผ๊ฐ€": "shallow water with small stones",
"๋‚˜๋ฌด ํ…Œ์ด๋ธ” ์ˆฒ์† ๊ณ„๊ณก": "wooden table forest valley",
"์•ˆ๊ฐœ ๋‚€ ์ˆฒ": "foggy forest",
"์ผ๋ชฐ ๋ฐ”๋‹ค": "sunset sea",
"๋ณ„์ด ๋น›๋‚˜๋Š” ์บ ํ•‘": "starry camping"
}
if not INDOOR_BACKGROUNDS:
INDOOR_BACKGROUNDS = {
"๊ธฐ๋ณธ ์ฑ…์ƒ": "basic desk",
"๋น›์ด ๋น„์น˜๋Š” ์ฑ…์ƒ": "desk with light",
"๋น›์ด ๋น„์น˜๋Š” ๊ฑฐ์‹ค": "living room with light",
"์ŠคํŠœ๋””์–ด ๊ฑฐ์‹ค": "studio living room",
"ํ™”๋ถ„์ด ์žˆ๋Š” ๊ฑฐ์‹ค": "living room with plants",
"์ „์ฒด์ ์ธ ๊ฑฐ์‹ค๋ชจ์Šต": "overall living room view",
"ํฌ์ธํŠธ ๊ฑฐ์‹ค": "point living room",
"์ค‘์•™ ๊ฑฐ์‹ค": "central living room",
"์„œ๋žํ…Œ์ด๋ธ”": "drawer table",
"์นจ์‹ค ํƒ์ž์œ„": "bedroom table top",
"์›๋ชฉ ํ…Œ์ด๋ธ” ๋ธ”๋ก": "wood table block",
"ํ…Œ์ด๋ธ” ์‹ฌํ”Œ": "simple table",
"๋ถ„์œ„๊ธฐ ์žˆ๋Š” ์นจ์‹ค": "atmospheric bedroom",
"๋‚˜๋ฌดํ…Œ์ด๋ธ”์œ„": "on wooden table",
"์ฑ…์œ„ ๊ฑฐ์‹คํ…Œ์ด๋ธ”": "living room table with books",
"์œ ๋ฆฌํ…Œ์ด๋ธ”์œ„": "on glass table",
"์นจ์‹ค ์˜† ์ž‘์€ํƒ์ž": "small bedside table",
"๋ถ„์œ„๊ธฐ ์žˆ๋Š” ์›ํ˜• ํ…Œ์ด๋ธ”": "atmospheric round table",
"ํฌ์ปค์Šค ํƒ์ž": "focus table",
"ํˆฌํ†ค ๋ฒฝ๋ฉด": "two-tone wall",
"์•„๋Š‘ํ•œ ํ…Œ์ด๋ธ”์œ„ ์•ก์„ธ์„œ๋ฆฌ": "cozy table accessories",
"์•„๋Š‘ํ•œ ํ…Œ์ด๋ธ” ๋ณด ์œ„": "on cozy tablecloth",
"์œ ๋ฆฌ ๋ฐ”๋‹ฅ": "glass floor",
"๋น›์น˜๋Š” ์‹ํƒ์œ„": "dining table with light",
"๋‚˜๋Š‘ํ•œ ์‹ํƒ์œ„ ์ž‘์—…๋Œ€": "cozy dining workspace"
}
if not SPECIAL_BACKGROUNDS:
SPECIAL_BACKGROUNDS = {
"๋„ค์ด๋น„ ๋นˆํ‹ฐ์ง€ ํ”Œ๋กœ๋Ÿด ๋ฒฝ์ง€": "navy vintage floral wallpaper",
"๋นˆํ‹ฐ์ง€ ๊ฝƒ๋ฌด๋Šฌ ํŒจ๋ธŒ๋ฆญ ๋ฐฐ๊ฒฝ": "vintage floral fabric background",
"ํŒ ๋„ํŠธ์™€ ๊ณผ์ผ": "pop dots and fruits",
"๋ธ”๋ฃจ ๋งˆ๋ธ” ์ž‰ํฌ ํ…์Šค์ฒ˜ ๋ฐฐ๊ฒฝ": "blue marble ink texture",
"์˜ค๋ Œ์ง€๋ธ”๋ฃจ ์›Œํ„ฐ์ปฌ๋Ÿฌ ๋ฐฐ๊ฒฝ": "orange blue watercolor",
"๋ ˆ๋“œ๋ธŒ๋Ÿฌ์‹œ ํŽ˜์ธํŒ… ์•„ํŠธ ๋ฐฐ๊ฒฝ": "red brush painting art",
"๋ธ”๋ฃจ์˜ค๋ Œ์ง€ ํŽ˜์ธํŒ… ์•„ํŠธ": "blue orange painting art"
}
if not JEWELRY_BACKGROUNDS:
JEWELRY_BACKGROUNDS = {
"ํ™”์ดํŠธ ๋ฏธ๋Ÿฌ ์ŠคํŒŸ ๋ผ์ดํŠธ": "white mirror spotlight",
"๊ทธ๋ ˆ์ด ๊ทธ๋ผ๋ฐ์ด์…˜ ๋ฏธ๋Ÿฌ": "gray gradient mirror",
"๋„ค์ด๋น„ ๋ฒจ๋ฒณ": "navy velvet",
"๋ธ”๋ž™ ๋ฏธ๋Ÿฌ ์‹œ๋„ค๋งˆํ‹ฑ": "black mirror cinematic",
"ํ™”์ดํŠธ ๋งˆ๋ธ” ํ”„๋ฆฌ๋ฏธ์—„": "white marble premium",
"ํŒŒ์Šคํ…” ๋ธ”๋ฃจ ํ๋ธŒ ํ”Œ๋žซํผ": "pastel blue cube platform",
"๋‚ด์ถ”๋Ÿด ๊ทธ๋ผ์Šค": "natural grass",
"์†Œํ”„ํŠธ ๋ฒ ์ด์ง ํŒจ๋ธŒ๋ฆญ": "soft basic fabric",
"๋งˆ์ดํฌ๋กœํ…์Šค์ณ ํ”„๋ฆฌ๋ฏธ์—„": "micro texture premium"
}
if not SPECIAL_EFFECTS_BACKGROUNDS:
SPECIAL_EFFECTS_BACKGROUNDS = {
"๋ธ”๋ฃจ๋ธ”๋ž™ ํฐ ๋ฌผ๋ฐฉ์šธ ํšจ๊ณผ": "blue black water drop effect",
"ํฌ๋ฆฌ์Šคํƒˆ ๋ฒ„๋ธ” ๋ฌผ์† ์žฅ๋ฉด": "crystal bubble underwater scene",
"์ž” ๋ฌผ๊ฒฐ ์ˆ˜๋ฉด ์œ„ ์žฅ๋ฉด": "gentle ripple water surface scene",
"์ปฌ๋Ÿฌ ์Šค๋ชจํฌ ํšจ๊ณผ": "color smoke effect",
"์ž์˜ฅํ•œ ์•ˆ๊ฐœ ํšจ๊ณผ": "dense fog effect",
"๊ฐ€์Šต๊ธฐ ์ˆ˜์ค‘๊ธฐ ํšจ๊ณผ": "humidifier mist effect"
}
# ์ž„์‹œ ํŒŒ์ผ ์ €์žฅ ํ•จ์ˆ˜ (์›๋ณธ๊ณผ ๋™์ผ)
def save_uploaded_file(uploaded_file, suffix='.png'):
try:
logger.info(f"Processing uploaded file: {type(uploaded_file)}")
if uploaded_file is None:
logger.warning("Uploaded file is None")
return None
with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as temp_file:
temp_filename = temp_file.name
logger.info(f"Created temporary file: {temp_filename}")
# Gradio ์—…๋กœ๋“œ ํŒŒ์ผ ์ฒ˜๋ฆฌ
if isinstance(uploaded_file, str): # ์ด๋ฏธ ํŒŒ์ผ ๊ฒฝ๋กœ์ธ ๊ฒฝ์šฐ
logger.info(f"Uploaded file is already a path: {uploaded_file}")
return uploaded_file
# PIL Image ์ฒ˜๋ฆฌ
if isinstance(uploaded_file, Image.Image):
logger.info("Uploaded file is a PIL Image")
uploaded_file.save(temp_filename, format="PNG")
return temp_filename
# ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
with open(temp_filename, "wb") as f:
if hasattr(uploaded_file, "read"): # ํŒŒ์ผ ๊ฐ์ฒด์ธ ๊ฒฝ์šฐ
logger.info("Processing file object")
content = uploaded_file.read()
f.write(content)
logger.info(f"Wrote {len(content)} bytes to {temp_filename}")
else: # ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ์ธ ๊ฒฝ์šฐ
logger.info("Processing binary data")
f.write(uploaded_file)
logger.info(f"Wrote data to {temp_filename}")
return temp_filename
except Exception as e:
logger.error(f"Error saving uploaded file: {e}")
logger.error(traceback.format_exc())
return None
# Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ (์›๋ณธ๊ณผ ์™„์ „ ๋™์ผ)
def create_gradio_interface():
try:
logger.info("Creating Gradio interface")
with gr.Blocks(title="AI ์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ ") as app:
gr.Markdown("# AI ์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„  ๋„๊ตฌ")
# ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํ•„๋“œ
password_box = gr.Textbox(
label="๋น„๋ฐ€๋ฒˆํ˜ธ",
type="password",
placeholder="์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”",
interactive=True
)
# ์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„  ์ธํ„ฐํŽ˜์ด์Šค
with gr.Row():
with gr.Column():
# ์ƒํ’ˆ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
image = gr.Image(label="์ƒํ’ˆ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", type="pil")
with gr.Row():
with gr.Column():
background_type = gr.Radio(
choices=["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "ํŠน์ˆ˜๋ฐฐ๊ฒฝ", "์ฃผ์–ผ๋ฆฌ", "ํŠน์ˆ˜ํšจ๊ณผ"],
label="๋ฐฐ๊ฒฝ ์œ ํ˜•",
value="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ"
)
# ๋“œ๋กญ๋‹ค์šด ์ปดํฌ๋„ŒํŠธ๋“ค
simple_dropdown = gr.Dropdown(
choices=list(SIMPLE_BACKGROUNDS.keys()),
value=list(SIMPLE_BACKGROUNDS.keys())[0] if SIMPLE_BACKGROUNDS else None,
label="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=True,
interactive=True
)
studio_dropdown = gr.Dropdown(
choices=list(STUDIO_BACKGROUNDS.keys()),
value=list(STUDIO_BACKGROUNDS.keys())[0] if STUDIO_BACKGROUNDS else None,
label="์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
nature_dropdown = gr.Dropdown(
choices=list(NATURE_BACKGROUNDS.keys()),
value=list(NATURE_BACKGROUNDS.keys())[0] if NATURE_BACKGROUNDS else None,
label="์ž์—ฐ ํ™˜๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
indoor_dropdown = gr.Dropdown(
choices=list(INDOOR_BACKGROUNDS.keys()),
value=list(INDOOR_BACKGROUNDS.keys())[0] if INDOOR_BACKGROUNDS else None,
label="์‹ค๋‚ด ํ™˜๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
special_dropdown = gr.Dropdown(
choices=list(SPECIAL_BACKGROUNDS.keys()),
value=list(SPECIAL_BACKGROUNDS.keys())[0] if SPECIAL_BACKGROUNDS else None,
label="ํŠน์ˆ˜๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
jewelry_dropdown = gr.Dropdown(
choices=list(JEWELRY_BACKGROUNDS.keys()),
value=list(JEWELRY_BACKGROUNDS.keys())[0] if JEWELRY_BACKGROUNDS else None,
label="์ฃผ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
special_effects_dropdown = gr.Dropdown(
choices=list(SPECIAL_EFFECTS_BACKGROUNDS.keys()),
value=list(SPECIAL_EFFECTS_BACKGROUNDS.keys())[0] if SPECIAL_EFFECTS_BACKGROUNDS else None,
label="ํŠน์ˆ˜ํšจ๊ณผ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
# ๋“œ๋กญ๋‹ค์šด ๋ณ€๊ฒฝ ํ•จ์ˆ˜ (์›๋ณธ๊ณผ ๋™์ผ, API ์—”๋“œํฌ์ธํŠธ ์ƒ์„ฑ)
def update_dropdowns(bg_type):
try:
# API ํ˜ธ์ถœ
result = api_client.predict(bg_type=bg_type, api_name="/update_dropdowns")
return result
except:
# ๋ฐฑ์—…์šฉ ๋กœ์ปฌ ๋กœ์ง
return {
simple_dropdown: gr.update(visible=(bg_type == "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ")),
studio_dropdown: gr.update(visible=(bg_type == "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ")),
nature_dropdown: gr.update(visible=(bg_type == "์ž์—ฐ ํ™˜๊ฒฝ")),
indoor_dropdown: gr.update(visible=(bg_type == "์‹ค๋‚ด ํ™˜๊ฒฝ")),
special_dropdown: gr.update(visible=(bg_type == "ํŠน์ˆ˜๋ฐฐ๊ฒฝ")),
jewelry_dropdown: gr.update(visible=(bg_type == "์ฃผ์–ผ๋ฆฌ")),
special_effects_dropdown: gr.update(visible=(bg_type == "ํŠน์ˆ˜ํšจ๊ณผ"))
}
background_type.change(
fn=update_dropdowns,
inputs=[background_type],
outputs=[simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, special_dropdown, jewelry_dropdown, special_effects_dropdown],
api_name="update_dropdowns"
)
# ์š”์ฒญ์‚ฌํ•ญ ์ž…๋ ฅ
request_text = gr.Textbox(
label="์š”์ฒญ์‚ฌํ•ญ",
placeholder="์ƒํ’ˆ ์ด๋ฏธ์ง€์— ์ ์šฉํ•  ์Šคํƒ€์ผ, ๋ถ„์œ„๊ธฐ, ํŠน๋ณ„ ์š”์ฒญ์‚ฌํ•ญ ๋“ฑ์„ ์ž…๋ ฅํ•˜์„ธ์š”.",
lines=3
)
# ์ƒˆ๋กœ์šด ์˜ต์…˜๋“ค
quality_level = gr.Radio(
label="ํ’ˆ์งˆ ๋ ˆ๋ฒจ",
choices=["gpt", "flux"],
value="flux",
info="GPT: GPT ๋ชจ๋ธ (๊ณ ํ’ˆ์งˆ), ์ผ๋ฐ˜: Flux ๋ชจ๋ธ (๋น ๋ฅธ ์ฒ˜๋ฆฌ + ๊ธฐ๋ณธ ํ™”์งˆ๊ฐœ์„ )"
)
aspect_ratio = gr.Dropdown(
label="์ข…ํšก๋น„",
choices=["1:1", "3:2", "2:3"],
value="1:1"
)
output_format = gr.Dropdown(
label="์ด๋ฏธ์ง€ ํ˜•์‹",
choices=["jpg", "png"],
value="jpg"
)
# ํ™”์งˆ ๊ฐœ์„  ์˜ต์…˜
enable_enhancement = gr.Checkbox(
label="์ถ”๊ฐ€ ํ™”์งˆ ๊ฐœ์„ ",
value=False,
info="GPT: 1ํšŒ ํ™”์งˆ๊ฐœ์„ , Flux: 2์ฐจ ํ™”์งˆ๊ฐœ์„  (๊ธฐ๋ณธ 1ํšŒ + ์ถ”๊ฐ€ 1ํšŒ)"
)
enhancement_level = gr.Slider(label="ํ™”์งˆ ๊ฐœ์„  ๋ ˆ๋ฒจ", minimum=1, maximum=4, value=2, step=1, visible=False)
# ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ
generate_prompt_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ๋งŒ ์ƒ์„ฑ")
# ํŽธ์ง‘ ๋ฒ„ํŠผ
edit_btn = gr.Button("์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ ")
with gr.Column():
with gr.Row():
with gr.Column():
gr.Markdown("## ํŽธ์ง‘๋œ ์ด๋ฏธ์ง€")
original_output = gr.Gallery(label="ํŽธ์ง‘ ๊ฒฐ๊ณผ", preview=True)
original_download = gr.File(label="ํŽธ์ง‘ ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ", interactive=False)
with gr.Column():
gr.Markdown("## ํ™”์งˆ ๊ฐœ์„ ๋œ ์ด๋ฏธ์ง€")
enhanced_output = gr.Gallery(label="ํ™”์งˆ ๊ฐœ์„  ๊ฒฐ๊ณผ", preview=True)
enhanced_download = gr.File(label="๊ฐœ์„  ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ", interactive=False)
# ํ”„๋กฌํ”„ํŠธ ์ถœ๋ ฅ
prompt_output = gr.Textbox(label="์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ", lines=10, interactive=False)
info = gr.Textbox(label="์ฒ˜๋ฆฌ ์ •๋ณด", interactive=False)
error = gr.Textbox(label="์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€", interactive=False, visible=True)
# ํ”„๋กฌํ”„ํŠธ๋งŒ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜ (์›๋ณธ๊ณผ ๋™์ผํ•œ ์—”๋“œํฌ์ธํŠธ, API ํ˜ธ์ถœ)
def generate_prompt_with_password_check(password, bg_type, simple, studio, nature, indoor, special, jewelry, special_effects, request_text, aspect_ratio):
try:
return api_client.predict(
password=password,
bg_type=bg_type,
simple=simple,
studio=studio,
nature=nature,
indoor=indoor,
special=special,
jewelry=jewelry,
special_effects=special_effects,
request_text=request_text,
aspect_ratio=aspect_ratio,
api_name="/generate_prompt_with_password_check"
)
except Exception as e:
return f"API ํ˜ธ์ถœ ์˜ค๋ฅ˜: {str(e)}"
# ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ํ•จ์ˆ˜ (์›๋ณธ๊ณผ ๋™์ผํ•œ ์—”๋“œํฌ์ธํŠธ, API ํ˜ธ์ถœ)
def check_password(password, *args):
try:
image, bg_type, simple, studio, nature, indoor, special, jewelry, special_effects, request_text, quality_level, aspect_ratio, output_format, enable_enhancement = args
if image is None:
return ([], None, [], None, "", "", "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
# ์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
temp_path = save_uploaded_file(image)
if temp_path is None:
return ([], None, [], None, "", "", "์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.")
try:
# API ํ˜ธ์ถœ (์›๋ณธ๊ณผ ๋™์ผํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ)
result = api_client.predict(
password=password,
param_1=handle_file(temp_path),
param_2=bg_type,
param_3=simple,
param_4=studio,
param_5=nature,
param_6=indoor,
param_7=special,
param_8=jewelry,
param_9=special_effects,
param_10=request_text,
param_11=quality_level,
param_12=aspect_ratio,
param_13=output_format,
param_14=enable_enhancement,
api_name="/check_password"
)
# API ์‘๋‹ต ์ฒ˜๋ฆฌ - ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์›๋ณธ์ฒ˜๋Ÿผ PIL Image๋กœ ๋ณ€ํ™˜
if result and len(result) >= 7:
original_output, original_download, enhanced_output, enhanced_download, prompt_output, info, error = result
# ๋””๋ฒ„๊น…: API ์‘๋‹ต ๊ตฌ์กฐ ๋กœ๊น…
logger.info(f"Original output type: {type(original_output)}")
logger.info(f"Enhanced output type: {type(enhanced_output)}")
if original_output:
logger.info(f"Original output first item: {type(original_output[0]) if original_output else 'Empty'}")
if original_output and isinstance(original_output[0], dict):
logger.info(f"Original output keys: {list(original_output[0].keys())}")
# Gallery ๋ฐ์ดํ„ฐ๋ฅผ PIL Image ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜
def convert_gallery_to_images(gallery_data):
if not gallery_data:
return []
images = []
logger.info(f"Converting gallery data, length: {len(gallery_data)}")
for i, item in enumerate(gallery_data):
try:
logger.info(f"Processing gallery item {i}: {type(item)}")
img_url = None
if isinstance(item, dict):
# ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ ์‹œ๋„
if 'image' in item:
if isinstance(item['image'], dict):
img_url = item['image'].get('url') or item['image'].get('path')
else:
img_url = item['image']
elif 'url' in item:
img_url = item['url']
elif 'path' in item:
img_url = item['path']
logger.info(f"Extracted URL from dict: {img_url}")
elif isinstance(item, str):
# ์ง์ ‘ URL์ธ ๊ฒฝ์šฐ
img_url = item
logger.info(f"Direct URL: {img_url}")
if img_url:
# URL์ด ์ƒ๋Œ€ ๊ฒฝ๋กœ์ธ ๊ฒฝ์šฐ ์ ˆ๋Œ€ ๊ฒฝ๋กœ๋กœ ๋ณ€ํ™˜
if img_url.startswith('/'):
img_url = f"https://happydoggg-49493h.hf.space/gradio_api/file={img_url}"
elif not img_url.startswith('http'):
img_url = f"https://happydoggg-49493h.hf.space/gradio_api/file={img_url}"
logger.info(f"Final URL: {img_url}")
# URL์—์„œ ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œํ•˜์—ฌ PIL Image๋กœ ๋ณ€ํ™˜
response = requests.get(img_url)
if response.status_code == 200:
pil_image = Image.open(io.BytesIO(response.content))
images.append(pil_image)
logger.info(f"Successfully converted image {i}")
else:
logger.warning(f"Failed to download image from {img_url}, status: {response.status_code}")
else:
logger.warning(f"No URL found in item {i}: {item}")
except Exception as e:
logger.error(f"Failed to convert gallery item {i}: {e}")
logger.error(f"Item content: {item}")
continue
logger.info(f"Converted {len(images)} images from gallery data")
return images
# Gallery ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜
converted_original = convert_gallery_to_images(original_output)
converted_enhanced = convert_gallery_to_images(enhanced_output)
# ๋ณ€ํ™˜๋œ ์ด๋ฏธ์ง€๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ ์‹œ๋„
if not converted_original and original_output:
logger.info("No converted original images, trying to use original data directly")
converted_original = original_output
if not converted_enhanced and enhanced_output:
logger.info("No converted enhanced images, trying to use enhanced data directly")
converted_enhanced = enhanced_output
# ๋‹ค์šด๋กœ๋“œ ํŒŒ์ผ ์ฒ˜๋ฆฌ - ์›๋ณธ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ
original_file = None
enhanced_file = None
# ์›๋ณธ ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ƒ์„ฑ
if converted_original:
try:
original_file_path = f"original_image.{output_format}"
converted_original[0].save(original_file_path, format=output_format.upper())
original_file = original_file_path
except Exception as e:
logger.error(f"Error saving original image: {e}")
# ๊ฐœ์„ ๋œ ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ƒ์„ฑ
if converted_enhanced:
try:
enhanced_file_path = f"enhanced_image.{output_format}"
converted_enhanced[0].save(enhanced_file_path, format=output_format.upper())
enhanced_file = enhanced_file_path
except Exception as e:
logger.error(f"Error saving enhanced image: {e}")
return (
converted_original, # PIL Image ๋ฆฌ์ŠคํŠธ
original_file, # ๋‹ค์šด๋กœ๋“œ ํŒŒ์ผ ๊ฒฝ๋กœ
converted_enhanced, # PIL Image ๋ฆฌ์ŠคํŠธ
enhanced_file, # ๋‹ค์šด๋กœ๋“œ ํŒŒ์ผ ๊ฒฝ๋กœ
prompt_output, # ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ
info, # ์ฒ˜๋ฆฌ ์ •๋ณด
error # ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€
)
else:
return ([], None, [], None, "", "", "API ์‘๋‹ต์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
finally:
# ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
if os.path.exists(temp_path):
try:
os.remove(temp_path)
except:
pass
except Exception as e:
logger.error(f"Error in check_password: {e}")
logger.error(f"Full traceback: {traceback.format_exc()}")
return ([], None, [], None, "", "", f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
# ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
generate_prompt_btn.click(
fn=generate_prompt_with_password_check,
inputs=[
password_box,
background_type,
simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, special_dropdown,
jewelry_dropdown, special_effects_dropdown,
request_text, aspect_ratio
],
outputs=[prompt_output],
api_name="generate_prompt_with_password_check"
)
# ํŽธ์ง‘ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
edit_btn.click(
fn=check_password,
inputs=[
password_box,
image, background_type,
simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, special_dropdown,
jewelry_dropdown, special_effects_dropdown,
request_text, quality_level, aspect_ratio, output_format, enable_enhancement
],
outputs=[
original_output, original_download,
enhanced_output, enhanced_download,
prompt_output, info, error
],
api_name="check_password"
)
logger.info("Gradio interface created successfully")
return app
except Exception as e:
logger.error(f"Error creating Gradio interface: {e}")
logger.error(traceback.format_exc())
raise
# ์•ฑ ์‹คํ–‰
if __name__ == "__main__":
try:
logger.info("Starting application")
# imgs ๋””๋ ‰ํ† ๋ฆฌ ํ™•์ธ/์ƒ์„ฑ
os.makedirs("imgs", exist_ok=True)
logger.info("์ด๋ฏธ์ง€ ๋””๋ ‰ํ† ๋ฆฌ ์ค€๋น„ ์™„๋ฃŒ")
app = create_gradio_interface()
logger.info("Launching Gradio app")
app.launch(share=True)
except Exception as e:
logger.error(f"Error running app: {e}")
logger.error(traceback.format_exc())