fh46jderf / app.py
ssboost's picture
Update app.py
83d7da1 verified
raw
history blame
23.7 kB
import os
import sys
import logging
import tempfile
import traceback
from typing import List, Tuple, Optional, Any
import gradio as gr
from gradio_client import Client, handle_file
from dotenv import load_dotenv
import time
# .env ํŒŒ์ผ ๋กœ๋“œ
load_dotenv()
# ๋กœ๊น… ์„ค์ • (API ์—”๋“œํฌ์ธํŠธ ์ •๋ณด๋Š” ๋กœ๊ทธ์— ๋‚จ๊ธฐ์ง€ ์•Š์Œ)
class SafeFormatter(logging.Formatter):
"""API ์—”๋“œํฌ์ธํŠธ ์ •๋ณด๋ฅผ ๋กœ๊ทธ์—์„œ ์ œ๊ฑฐํ•˜๋Š” ์•ˆ์ „ํ•œ ํฌ๋งคํ„ฐ"""
def format(self, record):
# API_ENDPOINT ๊ด€๋ จ ์ •๋ณด ํ•„ํ„ฐ๋ง
msg = super().format(record)
# ๋ฏผ๊ฐํ•œ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ ๊ฒฝ์šฐ ๋งˆ์Šคํ‚น
if "API_ENDPOINT" in msg or "happydoggg" in msg or "49493h" in msg:
return msg.replace(os.environ.get("API_ENDPOINT", ""), "[API_ENDPOINT_HIDDEN]")
return msg
# ๋กœ๊ทธ ํ•ธ๋“ค๋Ÿฌ ์„ค์ •
file_handler = logging.FileHandler("app.log")
console_handler = logging.StreamHandler(sys.stdout)
formatter = SafeFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
logger = logging.getLogger("image-enhancer-control-tower")
logger.setLevel(logging.INFO)
logger.addHandler(file_handler)
logger.addHandler(console_handler)
class GradioClientController:
"""ํ—ˆ๊น…ํŽ˜์ด์Šค ๊ทธ๋ผ๋””์˜ค API ํด๋ผ์ด์–ธํŠธ ์ปจํŠธ๋กค๋Ÿฌ"""
def __init__(self):
self.client = None
self.api_endpoint = None
self.background_options = {} # ์บ์‹œ๋œ ๋ฐฐ๊ฒฝ ์˜ต์…˜
self._initialize_client()
def _initialize_client(self):
"""ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” (์—”๋“œํฌ์ธํŠธ ์ •๋ณด๋Š” ๋กœ๊ทธ์— ๋‚จ๊ธฐ์ง€ ์•Š์Œ)"""
try:
self.api_endpoint = os.environ.get("API_ENDPOINT")
if not self.api_endpoint:
logger.error("API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
raise ValueError("API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.")
# ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์‹œ๋„ (์žฌ์‹œ๋„ ๋กœ์ง ํฌํ•จ)
max_retries = 3
for attempt in range(max_retries):
try:
self.client = Client(self.api_endpoint)
logger.info("API ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ดˆ๊ธฐํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
# ์ดˆ๊ธฐํ™” ์„ฑ๊ณต ์‹œ ๋ฐฐ๊ฒฝ ์˜ต์…˜ ๋กœ๋“œ
self._load_background_options()
return
except Exception as e:
if attempt < max_retries - 1:
logger.warning(f"ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์žฌ์‹œ๋„ {attempt + 1}/{max_retries}")
time.sleep(2)
else:
raise e
except Exception as e:
logger.error(f"ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์‹คํŒจ: {str(e)}")
self.client = None
def _load_background_options(self):
"""๋ฐฐ๊ฒฝ ์˜ต์…˜์„ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•˜์—ฌ ์บ์‹œ"""
try:
if self.client:
# ๊ฐ ๋ฐฐ๊ฒฝ ํƒ€์ž…๋ณ„๋กœ ์˜ต์…˜ ๋กœ๋“œ
background_types = ["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "ํŠน์ˆ˜๋ฐฐ๊ฒฝ", "์ฃผ์–ผ๋ฆฌ", "ํŠน์ˆ˜ํšจ๊ณผ"]
for bg_type in background_types:
result = self.client.predict(bg_type, api_name="/update_dropdowns")
if isinstance(result, (list, tuple)) and len(result) >= 7:
self.background_options[bg_type] = result
logger.info(f"๋ฐฐ๊ฒฝ ์˜ต์…˜ ๋กœ๋“œ ์™„๋ฃŒ: {bg_type}")
time.sleep(0.1) # API ํ˜ธ์ถœ ๊ฐ„๊ฒฉ
except Exception as e:
logger.warning(f"๋ฐฐ๊ฒฝ ์˜ต์…˜ ๋ฏธ๋ฆฌ ๋กœ๋“œ ์‹คํŒจ: {str(e)}")
# ์‹คํŒจํ•ด๋„ ๊ณ„์† ์ง„ํ–‰
def _ensure_client(self) -> bool:
"""ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์ƒํƒœ ํ™•์ธ ๋ฐ ์žฌ์—ฐ๊ฒฐ"""
if self.client is None:
logger.info("ํด๋ผ์ด์–ธํŠธ ์žฌ์—ฐ๊ฒฐ ์‹œ๋„")
self._initialize_client()
return self.client is not None
def update_dropdowns(self, bg_type: str) -> Tuple:
"""๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋”ฐ๋ฅธ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ"""
try:
if not self._ensure_client():
logger.error("ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์‹คํŒจ")
# ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ
if bg_type in self.background_options:
result = self.background_options[bg_type]
logger.info(f"์บ์‹œ๋œ ๋“œ๋กญ๋‹ค์šด ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ: {bg_type}")
else:
return tuple([gr.update() for _ in range(7)])
else:
# ์‹ค์‹œ๊ฐ„์œผ๋กœ API ํ˜ธ์ถœ
result = self.client.predict(bg_type, api_name="/update_dropdowns")
logger.info(f"์‹ค์‹œ๊ฐ„ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ: {bg_type}")
# ๊ฒฐ๊ณผ๋ฅผ Gradio ์—…๋ฐ์ดํŠธ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
if isinstance(result, (list, tuple)) and len(result) >= 7:
updates = []
visibility_map = ["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "ํŠน์ˆ˜๋ฐฐ๊ฒฝ", "์ฃผ์–ผ๋ฆฌ", "ํŠน์ˆ˜ํšจ๊ณผ"]
for i, choices in enumerate(result[:7]):
is_visible = (bg_type == visibility_map[i])
updates.append(gr.update(
visible=is_visible,
choices=choices if choices else [],
value=choices[0] if choices and len(choices) > 0 else None
))
return tuple(updates)
else:
logger.warning("API์—์„œ ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅธ ํ˜•์‹์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.")
return tuple([gr.update() for _ in range(7)])
except Exception as e:
logger.error(f"๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ ์˜ค๋ฅ˜: {str(e)}")
# ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ ์‹œ๋„
if bg_type in self.background_options:
try:
result = self.background_options[bg_type]
updates = []
visibility_map = ["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "ํŠน์ˆ˜๋ฐฐ๊ฒฝ", "์ฃผ์–ผ๋ฆฌ", "ํŠน์ˆ˜ํšจ๊ณผ"]
for i, choices in enumerate(result[:7]):
is_visible = (bg_type == visibility_map[i])
updates.append(gr.update(
visible=is_visible,
choices=choices if choices else [],
value=choices[0] if choices and len(choices) > 0 else None
))
logger.info(f"์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋กœ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ: {bg_type}")
return tuple(updates)
except:
pass
return tuple([gr.update() for _ in range(7)])
def generate_prompt_only(self, password: str, bg_type: str, simple: str, studio: str,
nature: str, indoor: str, special: str, jewelry: str,
special_effects: str, request_text: str, aspect_ratio: str) -> str:
"""ํ”„๋กฌํ”„ํŠธ๋งŒ ์ƒ์„ฑ"""
try:
if not self._ensure_client():
return "ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”."
result = self.client.predict(
password,
bg_type,
simple or "",
studio or "",
nature or "",
indoor or "",
special or "",
jewelry or "",
special_effects or "",
request_text or "",
aspect_ratio,
api_name="/generate_prompt_with_password_check"
)
logger.info("ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์™„๋ฃŒ")
return result if result else "ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."
except Exception as e:
logger.error(f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์˜ค๋ฅ˜: {str(e)}")
return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์˜ค๋ฅ˜: {str(e)}"
def process_image(self, password: str, image, bg_type: str, simple: str, studio: str,
nature: str, indoor: str, special: str, jewelry: str, special_effects: str,
request_text: str, quality_level: str, aspect_ratio: str,
output_format: str, enable_enhancement: bool) -> Tuple:
"""์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ (ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ ) - API ๋ฌธ์„œ์™€ ์ •ํ™•ํžˆ ๋งค์นญ"""
temp_path = None
try:
if not self._ensure_client():
return ([], None, [], None, "", "", "ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.")
# ์ด๋ฏธ์ง€ ๊ฒ€์ฆ
if image is None:
return ([], None, [], None, "", "", "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
# ์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
temp_path = tempfile.mktemp(suffix='.png')
try:
image.save(temp_path, format='PNG')
logger.info(f"์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ: {os.path.basename(temp_path)}")
except Exception as e:
logger.error(f"์ด๋ฏธ์ง€ ์ €์žฅ ์‹คํŒจ: {str(e)}")
return ([], None, [], None, "", "", "์ด๋ฏธ์ง€ ์ €์žฅ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋ฅผ ์‹œ๋„ํ•ด๋ณด์„ธ์š”.")
# API ํ˜ธ์ถœ - ๋งค๊ฐœ๋ณ€์ˆ˜ ์ˆœ์„œ๋ฅผ API ๋ฌธ์„œ์™€ ์ •ํ™•ํžˆ ๋งž์ถค
logger.info("์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ API ํ˜ธ์ถœ ์‹œ์ž‘")
result = self.client.predict(
password, # password (str)
handle_file(temp_path), # param_1 (image file)
bg_type, # param_2 (๋ฐฐ๊ฒฝ ์œ ํ˜•)
simple or "", # param_3 (์‹ฌํ”Œ ๋ฐฐ๊ฒฝ)
studio or "", # param_4 (์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ)
nature or "", # param_5 (์ž์—ฐ ํ™˜๊ฒฝ)
indoor or "", # param_6 (์‹ค๋‚ด ํ™˜๊ฒฝ)
special or "", # param_7 (ํŠน์ˆ˜๋ฐฐ๊ฒฝ)
jewelry or "", # param_8 (์ฃผ์–ผ๋ฆฌ)
special_effects or "", # param_9 (ํŠน์ˆ˜ํšจ๊ณผ)
request_text or "", # param_10 (์š”์ฒญ์‚ฌํ•ญ)
quality_level, # param_11 (ํ’ˆ์งˆ ๋ ˆ๋ฒจ)
aspect_ratio, # param_12 (์ข…ํšก๋น„)
output_format, # param_13 (์ด๋ฏธ์ง€ ํ˜•์‹)
enable_enhancement, # param_14 (์ถ”๊ฐ€ ํ™”์งˆ ๊ฐœ์„ )
api_name="/check_password"
)
logger.info("์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ API ํ˜ธ์ถœ ์™„๋ฃŒ")
# ๊ฒฐ๊ณผ ๊ฒ€์ฆ ๋ฐ ๋ฐ˜ํ™˜ - API ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด tuple of 7 elements
if isinstance(result, (list, tuple)) and len(result) >= 7:
# [0] original_gallery, [1] original_file, [2] enhanced_gallery,
# [3] enhanced_file, [4] prompt_text, [5] info_text, [6] error_text
return result[:7] # ์ •ํ™•ํžˆ 7๊ฐœ ์š”์†Œ๋งŒ ๋ฐ˜ํ™˜
else:
logger.warning(f"API ์‘๋‹ต ํ˜•์‹ ์ด์ƒ: type={type(result)}, length={len(result) if hasattr(result, '__len__') else 'N/A'}")
return ([], None, [], None, "", "", "API์—์„œ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ์‘๋‹ต์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.")
except Exception as e:
error_msg = str(e)
logger.error(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์˜ค๋ฅ˜: {error_msg}")
# ์ผ๋ฐ˜์ ์ธ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๊ฐœ์„ 
if "timeout" in error_msg.lower():
user_error = "์š”์ฒญ ์ฒ˜๋ฆฌ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”."
elif "connection" in error_msg.lower():
user_error = "์„œ๋ฒ„ ์—ฐ๊ฒฐ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋„คํŠธ์›Œํฌ ์ƒํƒœ๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
elif "unauthorized" in error_msg.lower() or "password" in error_msg.lower():
user_error = "์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
else:
user_error = f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {error_msg}"
return ([], None, [], None, "", "", user_error)
finally:
# ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
if temp_path and os.path.exists(temp_path):
try:
os.remove(temp_path)
logger.info("์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ ์™„๋ฃŒ")
except Exception as e:
logger.warning(f"์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ ์‹คํŒจ: {str(e)}")
# ์ „์—ญ ํด๋ผ์ด์–ธํŠธ ์ปจํŠธ๋กค๋Ÿฌ ์ธ์Šคํ„ด์Šค
controller = GradioClientController()
def create_gradio_interface():
"""Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ"""
try:
logger.info("Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ์‹œ์ž‘")
# ๋ฐฐ๊ฒฝ ์œ ํ˜• ์„ ํƒ์ง€
background_types = ["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "ํŠน์ˆ˜๋ฐฐ๊ฒฝ", "์ฃผ์–ผ๋ฆฌ", "ํŠน์ˆ˜ํšจ๊ณผ"]
# ์ปค์Šคํ…€ CSS ์ถ”๊ฐ€ (์›๋ณธ๊ณผ ๋™์ผํ•œ ์Šคํƒ€์ผ ์œ ์ง€)
css = """
.gradio-container {
max-width: 1200px !important;
}
"""
with gr.Blocks(title="AI ์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ ", css=css, theme=gr.themes.Soft()) 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=background_types,
label="๋ฐฐ๊ฒฝ ์œ ํ˜•",
value="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ"
)
# ๋“œ๋กญ๋‹ค์šด ์ปดํฌ๋„ŒํŠธ๋“ค (API์—์„œ ๋™์ ์œผ๋กœ ๋กœ๋“œ)
simple_dropdown = gr.Dropdown(
choices=[],
label="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=True,
interactive=True
)
studio_dropdown = gr.Dropdown(
choices=[],
label="์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
nature_dropdown = gr.Dropdown(
choices=[],
label="์ž์—ฐ ํ™˜๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
indoor_dropdown = gr.Dropdown(
choices=[],
label="์‹ค๋‚ด ํ™˜๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
special_dropdown = gr.Dropdown(
choices=[],
label="ํŠน์ˆ˜๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
jewelry_dropdown = gr.Dropdown(
choices=[],
label="์ฃผ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
special_effects_dropdown = gr.Dropdown(
choices=[],
label="ํŠน์ˆ˜ํšจ๊ณผ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
# ์š”์ฒญ์‚ฌํ•ญ ์ž…๋ ฅ
request_text = gr.Textbox(
label="์š”์ฒญ์‚ฌํ•ญ",
placeholder="์ƒํ’ˆ ์ด๋ฏธ์ง€์— ์ ์šฉํ•  ์Šคํƒ€์ผ, ๋ถ„์œ„๊ธฐ, ํŠน๋ณ„ ์š”์ฒญ์‚ฌํ•ญ ๋“ฑ์„ ์ž…๋ ฅํ•˜์„ธ์š”.",
lines=3
)
# ์ƒˆ๋กœ์šด ์˜ต์…˜๋“ค
quality_level = gr.Radio(
label="ํ’ˆ์งˆ ๋ ˆ๋ฒจ",
choices=["gpt", "flux"],
value="flux",
info="GPT: GPT ๋ชจ๋ธ (๊ณ ํ’ˆ์งˆ), Flux: 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ํšŒ)"
)
# ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ
generate_prompt_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ๋งŒ ์ƒ์„ฑ", variant="secondary")
# ํŽธ์ง‘ ๋ฒ„ํŠผ
edit_btn = gr.Button("์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ ", variant="primary")
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)
# ๋“œ๋กญ๋‹ค์šด ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ
background_type.change(
fn=controller.update_dropdowns,
inputs=[background_type],
outputs=[simple_dropdown, studio_dropdown, nature_dropdown,
indoor_dropdown, special_dropdown, jewelry_dropdown, special_effects_dropdown]
)
# ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
generate_prompt_btn.click(
fn=controller.generate_prompt_only,
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]
)
# ํŽธ์ง‘ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
edit_btn.click(
fn=controller.process_image,
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
]
)
# ์•ฑ ๋กœ๋“œ ์‹œ ์ดˆ๊ธฐ ๋“œ๋กญ๋‹ค์šด ์„ค์ •
app.load(
fn=controller.update_dropdowns,
inputs=[background_type],
outputs=[simple_dropdown, studio_dropdown, nature_dropdown,
indoor_dropdown, special_dropdown, jewelry_dropdown, special_effects_dropdown]
)
logger.info("Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ์™„๋ฃŒ")
return app
except Exception as e:
logger.error(f"Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ์˜ค๋ฅ˜: {str(e)}")
logger.error(traceback.format_exc())
raise
# ์•ฑ ์‹คํ–‰
if __name__ == "__main__":
try:
logger.info("์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘")
# imgs ๋””๋ ‰ํ† ๋ฆฌ ํ™•์ธ/์ƒ์„ฑ
os.makedirs("imgs", exist_ok=True)
logger.info("์ด๋ฏธ์ง€ ๋””๋ ‰ํ† ๋ฆฌ ์ค€๋น„ ์™„๋ฃŒ")
# API ์—”๋“œํฌ์ธํŠธ ํ™•์ธ
if not os.environ.get("API_ENDPOINT"):
logger.error("API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
print("\nโŒ ์˜ค๋ฅ˜: API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
print("ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ .env ํŒŒ์ผ์— API_ENDPOINT๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
sys.exit(1)
app = create_gradio_interface()
logger.info("Gradio ์•ฑ ์‹œ์ž‘")
app.launch(
share=True,
server_name="0.0.0.0",
server_port=7860,
show_error=True,
quiet=False
)
except KeyboardInterrupt:
logger.info("์‚ฌ์šฉ์ž์— ์˜ํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ค‘๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
except Exception as e:
logger.error(f"์•ฑ ์‹คํ–‰ ์˜ค๋ฅ˜: {str(e)}")
logger.error(traceback.format_exc())
print(f"\nโŒ ์‹ฌ๊ฐํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}")
print("์ž์„ธํ•œ ๋‚ด์šฉ์€ app.log ํŒŒ์ผ์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.")