fh46jderf / app.py
ssboost's picture
Update app.py
f33cb93 verified
raw
history blame
21.1 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
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-control-tower")
# 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:
# ๋กœ๊ทธ์— ์—”๋“œํฌ์ธํŠธ ์ •๋ณด ์ถœ๋ ฅํ•˜์ง€ ์•Š์Œ
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")
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
# API ํ˜ธ์ถœ ํ•จ์ˆ˜๋“ค (ํด๋ผ์ด์–ธํŠธ๋ฅผ ํ†ตํ•ด ์›๋ณธ API ํ˜ธ์ถœ)
def api_update_dropdowns(bg_type):
"""๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ API ํ˜ธ์ถœ"""
try:
result = client.predict(bg_type=bg_type, api_name="/update_dropdowns")
return result
except Exception as e:
logger.error(f"Error calling update_dropdowns API: {e}")
return None
def api_generate_prompt_with_password_check(password, bg_type, simple, studio, nature, indoor, special, jewelry, special_effects, request_text, aspect_ratio):
"""ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ API ํ˜ธ์ถœ"""
try:
result = 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"
)
return result
except Exception as e:
logger.error(f"Error calling generate_prompt API: {e}")
return f"API ํ˜ธ์ถœ ์˜ค๋ฅ˜: {str(e)}"
def api_check_password(password, image_file, bg_type, simple, studio, nature, indoor, special, jewelry, special_effects, request_text, quality_level, aspect_ratio, output_format, enable_enhancement):
"""์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ API ํ˜ธ์ถœ"""
try:
result = client.predict(
password=password,
param_1=image_file,
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"
)
return result
except Exception as e:
logger.error(f"Error calling check_password API: {e}")
return None, None, None, None, "", "", f"API ํ˜ธ์ถœ ์˜ค๋ฅ˜: {str(e)}"
# Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ (์™„์ „ํžˆ ๋™์ผํ•œ UI)
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()) if SIMPLE_BACKGROUNDS else ["ํ™”์ดํŠธ ๊ธฐ๋ณธ"],
value=list(SIMPLE_BACKGROUNDS.keys())[0] if SIMPLE_BACKGROUNDS else "ํ™”์ดํŠธ ๊ธฐ๋ณธ",
label="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=True,
interactive=True
)
studio_dropdown = gr.Dropdown(
choices=list(STUDIO_BACKGROUNDS.keys()) if STUDIO_BACKGROUNDS else ["์—ฐ๋…น์ƒ‰ ์žฅ๋ฏธ ์ •์›"],
value=list(STUDIO_BACKGROUNDS.keys())[0] if STUDIO_BACKGROUNDS else "์—ฐ๋…น์ƒ‰ ์žฅ๋ฏธ ์ •์›",
label="์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
nature_dropdown = gr.Dropdown(
choices=list(NATURE_BACKGROUNDS.keys()) if NATURE_BACKGROUNDS else ["์ž‘์€ ํŒŒ๋„๊ฐ€ ์žˆ๋Š” ํ•ด๋ณ€"],
value=list(NATURE_BACKGROUNDS.keys())[0] if NATURE_BACKGROUNDS else "์ž‘์€ ํŒŒ๋„๊ฐ€ ์žˆ๋Š” ํ•ด๋ณ€",
label="์ž์—ฐ ํ™˜๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
indoor_dropdown = gr.Dropdown(
choices=list(INDOOR_BACKGROUNDS.keys()) if INDOOR_BACKGROUNDS else ["๊ธฐ๋ณธ ์ฑ…์ƒ"],
value=list(INDOOR_BACKGROUNDS.keys())[0] if INDOOR_BACKGROUNDS else "๊ธฐ๋ณธ ์ฑ…์ƒ",
label="์‹ค๋‚ด ํ™˜๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
special_dropdown = gr.Dropdown(
choices=list(SPECIAL_BACKGROUNDS.keys()) if SPECIAL_BACKGROUNDS else ["๋„ค์ด๋น„ ๋นˆํ‹ฐ์ง€ ํ”Œ๋กœ๋Ÿด ๋ฒฝ์ง€"],
value=list(SPECIAL_BACKGROUNDS.keys())[0] if SPECIAL_BACKGROUNDS else "๋„ค์ด๋น„ ๋นˆํ‹ฐ์ง€ ํ”Œ๋กœ๋Ÿด ๋ฒฝ์ง€",
label="ํŠน์ˆ˜๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
jewelry_dropdown = gr.Dropdown(
choices=list(JEWELRY_BACKGROUNDS.keys()) if JEWELRY_BACKGROUNDS else ["ํ™”์ดํŠธ ๋ฏธ๋Ÿฌ ์ŠคํŒŸ ๋ผ์ดํŠธ"],
value=list(JEWELRY_BACKGROUNDS.keys())[0] if JEWELRY_BACKGROUNDS else "ํ™”์ดํŠธ ๋ฏธ๋Ÿฌ ์ŠคํŒŸ ๋ผ์ดํŠธ",
label="์ฃผ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
special_effects_dropdown = gr.Dropdown(
choices=list(SPECIAL_EFFECTS_BACKGROUNDS.keys()) if SPECIAL_EFFECTS_BACKGROUNDS else ["๋ธ”๋ฃจ๋ธ”๋ž™ ํฐ ๋ฌผ๋ฐฉ์šธ ํšจ๊ณผ"],
value=list(SPECIAL_EFFECTS_BACKGROUNDS.keys())[0] if SPECIAL_EFFECTS_BACKGROUNDS else "๋ธ”๋ฃจ๋ธ”๋ž™ ํฐ ๋ฌผ๋ฐฉ์šธ ํšจ๊ณผ",
label="ํŠน์ˆ˜ํšจ๊ณผ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
# ๋“œ๋กญ๋‹ค์šด ๋ณ€๊ฒฝ ํ•จ์ˆ˜
def update_dropdowns(bg_type):
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]
)
# ์š”์ฒญ์‚ฌํ•ญ ์ž…๋ ฅ
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_wrapper(password, bg_type, simple, studio, nature, indoor, special, jewelry, special_effects, request_text, aspect_ratio):
return api_generate_prompt_with_password_check(
password, bg_type, simple, studio, nature, indoor, special, jewelry, special_effects, request_text, aspect_ratio
)
# ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ (API ํ˜ธ์ถœ)
def process_image_wrapper(password, image, bg_type, simple, studio, nature, indoor, special, jewelry, special_effects, request_text, quality_level, aspect_ratio, output_format, enable_enhancement):
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_check_password(
password, temp_path, bg_type, simple, studio, nature, indoor, special, jewelry, special_effects,
request_text, quality_level, aspect_ratio, output_format, enable_enhancement
)
return result
finally:
# ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
if os.path.exists(temp_path):
try:
os.remove(temp_path)
except:
pass
# ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
generate_prompt_btn.click(
fn=generate_prompt_wrapper,
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=process_image_wrapper,
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
]
)
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 control tower 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()), None, None, None, None, None, None
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 None, None, None, None, None, None, None
# ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๋ฐฐ๊ฒฝ ๋”•์…”๋„ˆ๋ฆฌ๋“ค ๋กœ๋“œ
(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"
}
if not STUDIO_BACKGROUNDS:
STUDIO_BACKGROUNDS = {
"์—ฐ๋…น์ƒ‰ ์žฅ๋ฏธ ์ •์›": "soft green background with rose garden elements",
"์—ฐ๋ถ„ํ™ ์žฅ๋ฏธ ๋Œ€๋ฆฌ์„": "pink rose with marble surface backdrop"
}
if not NATURE_BACKGROUNDS:
NATURE_BACKGROUNDS = {
"์ž‘์€ ํŒŒ๋„๊ฐ€ ์žˆ๋Š” ํ•ด๋ณ€": "serene beach with gentle waves",
"์—ด๋Œ€ํ•ด๋ณ€": "tropical beach setting with palm trees"
}
if not INDOOR_BACKGROUNDS:
INDOOR_BACKGROUNDS = {
"๊ธฐ๋ณธ ์ฑ…์ƒ": "clean modern desk setup",
"๋น›์ด ๋น„์น˜๋Š” ๊ฑฐ์‹ค": "bright living room with natural light"
}
if not SPECIAL_BACKGROUNDS:
SPECIAL_BACKGROUNDS = {
"๋„ค์ด๋น„ ๋นˆํ‹ฐ์ง€ ํ”Œ๋กœ๋Ÿด ๋ฒฝ์ง€": "navy vintage floral wallpaper background"
}
if not JEWELRY_BACKGROUNDS:
JEWELRY_BACKGROUNDS = {
"ํ™”์ดํŠธ ๋ฏธ๋Ÿฌ ์ŠคํŒŸ ๋ผ์ดํŠธ": "white mirror surface with spotlight"
}
if not SPECIAL_EFFECTS_BACKGROUNDS:
SPECIAL_EFFECTS_BACKGROUNDS = {
"๋ธ”๋ฃจ๋ธ”๋ž™ ํฐ ๋ฌผ๋ฐฉ์šธ ํšจ๊ณผ": "blue-black background with water droplet effects"
}
# ์ž„์‹œ ํŒŒ์ผ ์ €์žฅ ํ•จ์ˆ˜
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