Spaces:
Kims12
/
Sleeping

img_3 / app.py
Kims12's picture
Update app.py
56b9002 verified
import os
import tempfile
import logging
import re
import time
import json
from PIL import Image
import gradio as gr
from google import genai
from google.genai import types
import google.generativeai as genai_generative
from dotenv import load_dotenv
load_dotenv()
# ------------------- ๋กœ๊น… ์„ค์ • -------------------
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# ------------------- ๋ฐฐ๊ฒฝ ๋””๋ ‰ํ† ๋ฆฌ ์„ค์ • -------------------
BACKGROUNDS_DIR = "./background"
if not os.path.exists(BACKGROUNDS_DIR):
os.makedirs(BACKGROUNDS_DIR)
logger.info(f"๋ฐฐ๊ฒฝ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค: {BACKGROUNDS_DIR}")
# ------------------- ์ „์—ญ ๋ณ€์ˆ˜ ์„ค์ • -------------------
SIMPLE_BACKGROUNDS = {}
STUDIO_BACKGROUNDS = {}
NATURE_BACKGROUNDS = {}
INDOOR_BACKGROUNDS = {}
TECHNOLOGY_BACKGROUNDS = {}
COLORFUL_PATTERN_BACKGROUNDS = {}
ABSTRACT_BACKGROUNDS = {}
JEWELRY_BACKGROUNDS = {} # ์ฅฌ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ ์ „์—ญ ๋ณ€์ˆ˜ ์ถ”๊ฐ€
# ------------------- ๋ฐฐ๊ฒฝ JSON ํŒŒ์ผ ๋กœ๋“œ ํ•จ์ˆ˜ -------------------
def load_background_json(filename):
"""๋ฐฐ๊ฒฝ JSON ํŒŒ์ผ ๋กœ๋“œ ํ•จ์ˆ˜"""
file_path = os.path.join(BACKGROUNDS_DIR, filename)
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
logger.info(f"{filename} ํŒŒ์ผ์„ ์„ฑ๊ณต์ ์œผ๋กœ ๋กœ๋“œํ–ˆ์Šต๋‹ˆ๋‹ค. {len(data)} ํ•ญ๋ชฉ ํฌํ•จ.")
return data
except FileNotFoundError:
logger.info(f"{filename} ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค.")
return {}
except Exception as e:
logger.warning(f"{filename} ํŒŒ์ผ ๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}.")
return {}
# ------------------- ๋ฐฐ๊ฒฝ ์˜ต์…˜ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜ -------------------
def initialize_backgrounds():
"""๋ชจ๋“  ๋ฐฐ๊ฒฝ ์˜ต์…˜ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜"""
global SIMPLE_BACKGROUNDS, STUDIO_BACKGROUNDS, NATURE_BACKGROUNDS, INDOOR_BACKGROUNDS
global TECHNOLOGY_BACKGROUNDS, COLORFUL_PATTERN_BACKGROUNDS, ABSTRACT_BACKGROUNDS
global JEWELRY_BACKGROUNDS # ์ฅฌ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ ์ถ”๊ฐ€
logger.info(f"Backgrounds ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ: {BACKGROUNDS_DIR}")
logger.info(f"๋””๋ ‰ํ† ๋ฆฌ ๋‚ด ํŒŒ์ผ ๋ชฉ๋ก: {os.listdir(BACKGROUNDS_DIR)}")
SIMPLE_BACKGROUNDS = load_background_json("simple_backgrounds.json")
STUDIO_BACKGROUNDS = load_background_json("studio_backgrounds.json")
NATURE_BACKGROUNDS = load_background_json("nature_backgrounds.json")
INDOOR_BACKGROUNDS = load_background_json("indoor_backgrounds.json")
TECHNOLOGY_BACKGROUNDS = load_background_json("tech-backgrounds-final.json")
COLORFUL_PATTERN_BACKGROUNDS = load_background_json("colorful-pattern-backgrounds.json")
ABSTRACT_BACKGROUNDS = load_background_json("abstract_backgrounds.json")
JEWELRY_BACKGROUNDS = load_background_json("jewelry_backgrounds.json")
# ๊ธฐ๋ณธ๊ฐ’ ์„ค์ • (ํŒŒ์ผ์ด ์—†๊ฑฐ๋‚˜ ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ)
if not SIMPLE_BACKGROUNDS:
SIMPLE_BACKGROUNDS = {"ํด๋ž˜์‹ ํ™”์ดํŠธ": "clean white background with soft even lighting"}
if not STUDIO_BACKGROUNDS:
STUDIO_BACKGROUNDS = {"๋ฏธ๋‹ˆ๋ฉ€ ํ”Œ๋žซ๋ ˆ์ด": "minimalist flat lay with clean white background"}
if not NATURE_BACKGROUNDS:
NATURE_BACKGROUNDS = {"์—ด๋Œ€ ํ•ด๋ณ€": "tropical beach with crystal clear water"}
if not INDOOR_BACKGROUNDS:
INDOOR_BACKGROUNDS = {"๋ฏธ๋‹ˆ๋ฉ€ ์Šค์นธ๋””๋‚˜๋น„์•ˆ ๊ฑฐ์‹ค": "minimalist Scandinavian living room"}
if not TECHNOLOGY_BACKGROUNDS:
TECHNOLOGY_BACKGROUNDS = {"๋‹ค์ด๋‚˜๋ฏน ์Šคํ”Œ๋ž˜์‹œ": "dynamic water splash interaction with product"}
if not COLORFUL_PATTERN_BACKGROUNDS:
COLORFUL_PATTERN_BACKGROUNDS = {"ํ™”๋ คํ•œ ๊ฝƒ ํŒจํ„ด": "vibrant floral pattern backdrop"}
if not ABSTRACT_BACKGROUNDS:
ABSTRACT_BACKGROUNDS = {"๋„ค์˜จ ๋ผ์ดํŠธ": "neon light abstract background with vibrant glowing elements"}
if not JEWELRY_BACKGROUNDS:
JEWELRY_BACKGROUNDS = {"ํด๋ž˜์‹ ํ™”์ดํŠธ ์‹คํฌ": "pristine white silk fabric backdrop"}
logger.info("๋ชจ๋“  ๋ฐฐ๊ฒฝ ์˜ต์…˜ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ")
# ๋ฐฐ๊ฒฝ ๋“œ๋กญ๋‹ค์šด ์ดˆ๊ธฐํ™”๋ฅผ ์œ„ํ•œ ํ•จ์ˆ˜
def initialize_dropdowns():
"""๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜"""
simple_choices = list(SIMPLE_BACKGROUNDS.keys())
studio_choices = list(STUDIO_BACKGROUNDS.keys())
nature_choices = list(NATURE_BACKGROUNDS.keys())
indoor_choices = list(INDOOR_BACKGROUNDS.keys())
tech_choices = list(TECHNOLOGY_BACKGROUNDS.keys())
colorful_choices = list(COLORFUL_PATTERN_BACKGROUNDS.keys())
abstract_choices = list(ABSTRACT_BACKGROUNDS.keys())
jewelry_choices = list(JEWELRY_BACKGROUNDS.keys())
return {
"simple": simple_choices,
"studio": studio_choices,
"nature": nature_choices,
"indoor": indoor_choices,
"tech": tech_choices,
"colorful": colorful_choices,
"abstract": abstract_choices,
"jewelry": jewelry_choices,
}
# ------------------- ๊ธฐ๋ณธ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ -------------------
def save_binary_file(file_name, data):
with open(file_name, "wb") as f:
f.write(data)
def translate_prompt_to_english(prompt):
if not re.search("[๊ฐ€-ํžฃ]", prompt):
return prompt
prompt = prompt.replace("#1", "IMAGE_TAG_ONE")
try:
api_key = os.environ.get("GEMINI_API_KEY")
if not api_key:
logger.error("Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
return prompt
client = genai.Client(api_key=api_key)
translation_prompt = f"""
Translate the following Korean text to English:
{prompt}
IMPORTANT: The token IMAGE_TAG_ONE is a special tag
and must be preserved exactly as is in your translation. Do not translate this token.
"""
logger.info(f"Translation prompt: {translation_prompt}")
response = client.models.generate_content(
model="gemini-2.0-flash",
contents=[translation_prompt],
config=types.GenerateContentConfig(
response_modalities=['Text'],
temperature=0.2,
top_p=0.95,
top_k=40,
max_output_tokens=512
)
)
translated_text = ""
for part in response.candidates[0].content.parts:
if hasattr(part, 'text') and part.text:
translated_text += part.text
if translated_text.strip():
translated_text = translated_text.replace("IMAGE_TAG_ONE", "#1")
logger.info(f"Translated text: {translated_text.strip()}")
return translated_text.strip()
else:
logger.warning("๋ฒˆ์—ญ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์›๋ณธ ํ”„๋กฌํ”„ํŠธ ์‚ฌ์šฉ")
prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
return prompt
except Exception as e:
logger.exception("๋ฒˆ์—ญ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
return prompt
def preprocess_prompt(prompt, image1):
has_img1 = image1 is not None
if "#1" in prompt and not has_img1:
prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
else:
prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
prompt += " ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”. ์ด๋ฏธ์ง€์— ํ…์ŠคํŠธ๋‚˜ ๊ธ€์ž๋ฅผ ํฌํ•จํ•˜์ง€ ๋งˆ์„ธ์š”."
return prompt
# ------------------- ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜ -------------------
def generate_with_images(prompt, images, variation_index=0):
try:
api_key = os.environ.get("GEMINI_API_KEY")
if not api_key:
return None, "API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
client = genai.Client(api_key=api_key)
logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt}, ๋ณ€ํ˜• ์ธ๋ฑ์Šค: {variation_index}")
variation_suffixes = [
" Create this as a professional studio product shot with precise focus on the product details. Do not add any text, watermarks, or labels to the image.",
" Create this as a high-contrast artistic studio shot with dramatic lighting and shadows. Do not add any text, watermarks, or labels to the image.",
" Create this as a soft-lit elegantly styled product shot with complementary elements. Do not add any text, watermarks, or labels to the image.",
" Create this as a high-definition product photography with perfect color accuracy and detail preservation. Do not add any text, watermarks, or labels to the image."
]
if variation_index < len(variation_suffixes):
prompt = prompt + variation_suffixes[variation_index]
else:
prompt = prompt + " Create as high-end commercial product photography. Do not add any text, watermarks, or labels to the image."
contents = [prompt]
for idx, img in enumerate(images, 1):
if img is not None:
contents.append(img)
logger.info(f"์ด๋ฏธ์ง€ #{idx} ์ถ”๊ฐ€๋จ")
response = client.models.generate_content(
model="gemini-2.0-flash-exp-image-generation",
contents=contents,
config=types.GenerateContentConfig(
response_modalities=['Text', 'Image'],
temperature=1.05,
top_p=0.97,
top_k=50,
max_output_tokens=10240
)
)
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
temp_path = tmp.name
result_text = ""
image_found = False
for part in response.candidates[0].content.parts:
if hasattr(part, 'text') and part.text:
result_text += part.text
logger.info(f"์‘๋‹ต ํ…์ŠคํŠธ: {part.text}")
elif hasattr(part, 'inline_data') and part.inline_data:
save_binary_file(temp_path, part.inline_data.data)
image_found = True
logger.info("์‘๋‹ต์—์„œ ์ด๋ฏธ์ง€ ์ถ”์ถœ ์„ฑ๊ณต")
if not image_found:
return None, f"API์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต ํ…์ŠคํŠธ: {result_text}"
result_img = Image.open(temp_path)
if result_img.mode == "RGBA":
result_img = result_img.convert("RGB")
result_img.save(temp_path, format="JPEG", quality=95)
return temp_path, f"์ด๋ฏธ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. {result_text}"
except Exception as e:
logger.exception("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
def process_images_with_prompt(image1, prompt, variation_index=0, max_retries=3):
retry_count = 0
last_error = None
while retry_count < max_retries:
try:
images = [image1]
valid_images = [img for img in images if img is not None]
if not valid_images:
return None, "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", ""
final_prompt = prompt.strip()
result_img, status = generate_with_images(final_prompt, valid_images, variation_index)
if result_img is not None:
return result_img, status, final_prompt
else:
last_error = status
retry_count += 1
logger.warning(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์‹คํŒจ, ์žฌ์‹œ๋„ {retry_count}/{max_retries}: {status}")
time.sleep(1)
except Exception as e:
last_error = str(e)
retry_count += 1
logger.exception(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ์žฌ์‹œ๋„ {retry_count}/{max_retries}:")
time.sleep(1)
return None, f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜({max_retries}ํšŒ) ์ดˆ๊ณผ ํ›„ ์‹คํŒจ: {last_error}", prompt
# ------------------- ํ”„๋กฌํ”„ํŠธ ๊ด€๋ จ ํ•จ์ˆ˜ -------------------
def filter_prompt_only(prompt):
"""Gemini์˜ ์„ค๋ช… ๋ฐ ๋ถˆํ•„์š”ํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์‹ค์ œ ํ”„๋กฌํ”„ํŠธ๋งŒ ์ถ”์ถœํ•˜๋Š” ํ•จ์ˆ˜"""
code_block_pattern = r"```\s*(.*?)```"
code_match = re.search(code_block_pattern, prompt, re.DOTALL)
if code_match:
return code_match.group(1).strip()
if "--ar 1:1" in prompt:
lines = prompt.split('\n')
prompt_lines = []
in_prompt = False
for line in lines:
if (not in_prompt and
("product" in line.lower() or
"magazine" in line.lower() or
"commercial" in line.lower() or
"photography" in line.lower())):
in_prompt = True
prompt_lines.append(line)
elif in_prompt:
if "explanation" in line.lower() or "let me know" in line.lower():
break
prompt_lines.append(line)
if prompt_lines:
return '\n'.join(prompt_lines).strip()
return prompt.strip()
def get_selected_background_info(bg_type, simple, studio, nature, indoor, tech, colorful, abstract, jewelry):
"""์„ ํƒ๋œ ๋ฐฐ๊ฒฝ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜"""
if bg_type == "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ":
return {
"category": "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ",
"name": simple,
"english": SIMPLE_BACKGROUNDS.get(simple, "white background")
}
elif bg_type == "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ":
return {
"category": "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ",
"name": studio,
"english": STUDIO_BACKGROUNDS.get(studio, "product photography studio")
}
elif bg_type == "์ž์—ฐ ํ™˜๊ฒฝ":
return {
"category": "์ž์—ฐ ํ™˜๊ฒฝ",
"name": nature,
"english": NATURE_BACKGROUNDS.get(nature, "natural environment")
}
elif bg_type == "์‹ค๋‚ด ํ™˜๊ฒฝ":
return {
"category": "์‹ค๋‚ด ํ™˜๊ฒฝ",
"name": indoor,
"english": INDOOR_BACKGROUNDS.get(indoor, "indoor environment")
}
elif bg_type == "ํ…Œํฌ๋†€๋กœ์ง€ ๋ฐฐ๊ฒฝ":
return {
"category": "ํ…Œํฌ๋†€๋กœ์ง€ ๋ฐฐ๊ฒฝ",
"name": tech,
"english": TECHNOLOGY_BACKGROUNDS.get(tech, "technology environment")
}
elif bg_type == "์ปฌ๋Ÿฌํ’€ ํŒจํ„ด ๋ฐฐ๊ฒฝ":
return {
"category": "์ปฌ๋Ÿฌํ’€ ํŒจํ„ด ๋ฐฐ๊ฒฝ",
"name": colorful,
"english": COLORFUL_PATTERN_BACKGROUNDS.get(colorful, "colorful pattern background")
}
elif bg_type == "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ":
return {
"category": "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ",
"name": abstract,
"english": ABSTRACT_BACKGROUNDS.get(abstract, "abstract background")
}
elif bg_type == "์ฅฌ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ":
return {
"category": "์ฅฌ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ",
"name": jewelry,
"english": JEWELRY_BACKGROUNDS.get(jewelry, "jewelry backdrop")
}
else:
return {
"category": "๊ธฐ๋ณธ ๋ฐฐ๊ฒฝ",
"name": "ํ™”์ดํŠธ ๋ฐฐ๊ฒฝ",
"english": "white background"
}
def generate_enhanced_system_instruction():
"""ํ–ฅ์ƒ๋œ ์‹œ์Šคํ…œ ์ธ์ŠคํŠธ๋Ÿญ์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜"""
return """๋‹น์‹ ์€ ์ƒํ’ˆ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ์ตœ๊ณ  ํ’ˆ์งˆ์˜ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ƒํ’ˆ๋ช…, ๋ฐฐ๊ฒฝ ์œ ํ˜•, ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋ฏธ๋“œ์ €๋‹ˆ(Midjourney)์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒ์„ธํ•˜๊ณ  ์ „๋ฌธ์ ์ธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์˜์–ด๋กœ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
๋‹ค์Œ ๊ฐ€์ด๋“œ๋ผ์ธ์„ ๋ฐ˜๋“œ์‹œ ์ค€์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:
1. ์ƒํ’ˆ์„ "#1"๋กœ ์ง€์ •ํ•˜์—ฌ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. (์˜ˆ: "skincare tube (#1)")
2. *** ๋งค์šฐ ์ค‘์š”: ์ƒํ’ˆ์˜ ์›๋ž˜ ํŠน์„ฑ(๋””์ž์ธ, ์ƒ‰์ƒ, ํ˜•ํƒœ, ๋กœ๊ณ , ํŒจํ‚ค์ง€ ๋“ฑ)์€ ์–ด๋–ค ์ƒํ™ฉ์—์„œ๋„ ์ ˆ๋Œ€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ***
3. *** ์ƒํ’ˆ์˜ ๋ณธ์งˆ์  ํŠน์„ฑ์„ ์œ ์ง€ํ•˜๋˜, ์ƒํ’ˆ์— ํฌ์ปค์Šค๋ฅผ ๋งž์ถฐ ๋ชจ๋“  ์„ธ๋ถ€ ์‚ฌํ•ญ์ด ์„ ๋ช…ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚˜๋„๋ก ํ•˜๋ฉฐ,
8K ํ•ด์ƒ๋„(8K resolution), ์˜ค๋ฒ„์ƒคํ”„๋‹ ์—†๋Š” ์ดˆ๊ณ ํ™”์งˆ(ultra high definition without oversharpening)๋กœ ๋ Œ๋”๋ง๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ***
4. ์ด๋ฏธ์ง€ ๋น„์œจ์€ ์ •ํ™•ํžˆ 1:1(์ •์‚ฌ๊ฐํ˜•) ํ˜•์‹์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กฌํ”„ํŠธ์— "square format", "1:1 ratio" ๋˜๋Š” "aspect ratio 1:1"์„ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
5. ์ƒํ’ˆ์€ ๋ฐ˜๋“œ์‹œ ์ •์‚ฌ๊ฐํ˜• ๊ตฌ๋„์˜ ์ •์ค‘์•™์— ๋ฐฐ์น˜๋˜์–ด์•ผ ํ•˜๋ฉฐ, ์ ์ ˆํ•œ ํฌ๊ธฐ๋กœ ํ‘œํ˜„ํ•˜์—ฌ ๋””ํ…Œ์ผ์ด ์™„๋ฒฝํ•˜๊ฒŒ ๋ณด์ด๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
6. ์ƒํ’ˆ์„ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ์ดˆ์ ์œผ๋กœ ๋ถ€๊ฐ์‹œํ‚ค๊ณ , ์ƒํ’ˆ์˜ ๋น„์œจ์ด ์ „์ฒด ์ด๋ฏธ์ง€์—์„œ 60-70% ์ด์ƒ ์ฐจ์ง€ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
7. ์กฐ๋ช… ์„ค๋ช…์„ ๋งค์šฐ ๊ตฌ์ฒด์ ์œผ๋กœ ํ•ด์ฃผ์„ธ์š”. ์˜ˆ: "soft directional lighting from left side", "dramatic rim lighting", "diffused natural light through windows"
8. ๋ฐฐ๊ฒฝ์˜ ์žฌ์งˆ๊ณผ ์งˆ๊ฐ์„ ์ƒ์„ธํžˆ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”. ์˜ˆ: "polished marble surface", "rustic wooden table with visible grain", "matte concrete wall with subtle texture"
9. ํ”„๋กฌํ”„ํŠธ์— ๋‹ค์Œ ์š”์†Œ๋“ค์„ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•˜๋˜, ์‚ฌ์šฉ ๋งฅ๋ฝ์— ์ ์ ˆํ•˜๊ฒŒ ๋ณ€ํ˜•ํ•˜์„ธ์š”:
- "award-winning product photography"
- "magazine-worthy commercial product shot"
- "professional advertising imagery with perfect exposure"
- "studio lighting with color-accurate rendering"
- "8K ultra high definition product showcase"
- "commercial product photography with precise detail rendering"
- "ultra high definition"
- "crystal clear details"
10. ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ๊ตฌ์ฒด์ ์ธ ๋ฐฐ๊ฒฝ๊ณผ ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ์„ ํ”„๋กฌํ”„ํŠธ์— ์ •ํ™•ํžˆ ๋ฐ˜์˜ํ•˜๊ณ  ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค.
11. ํ”„๋กฌํ”„ํŠธ ๋์— ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ "--ar 1:1 --s 750 --q 2 --v 5.2" ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฏธ๋“œ์ €๋‹ˆ์—์„œ ๊ณ ํ’ˆ์งˆ ์ •์‚ฌ๊ฐํ˜• ๋น„์œจ์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.
12. ๋งค์šฐ ์ค‘์š”: ํ”„๋กฌํ”„ํŠธ ์™ธ์— ๋‹ค๋ฅธ ์„ค๋ช…์ด๋‚˜ ๋ฉ”ํƒ€ ํ…์ŠคํŠธ๋ฅผ ํฌํ•จํ•˜์ง€ ๋งˆ์„ธ์š”. ์˜ค์ง ํ”„๋กฌํ”„ํŠธ ์ž์ฒด๋งŒ ์ œ๊ณตํ•˜์„ธ์š”.
"""
def generate_prompt_with_gemini(product_name, background_info, additional_info=""):
"""ํ–ฅ์ƒ๋œ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ํ•จ์ˆ˜"""
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
if not GEMINI_API_KEY:
return "Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ GEMINI_API_KEY๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ์ฝ”๋“œ์— ์ง์ ‘ ์ž…๋ ฅํ•˜์„ธ์š”."
try:
genai_generative.configure(api_key=GEMINI_API_KEY)
prompt_request = f"""
์ƒํ’ˆ๋ช…: {product_name}
๋ฐฐ๊ฒฝ ์œ ํ˜•: {background_info.get('english', 'studio')}
๋ฐฐ๊ฒฝ ์นดํ…Œ๊ณ ๋ฆฌ: {background_info.get('category', '')}
๋ฐฐ๊ฒฝ ์ด๋ฆ„: {background_info.get('name', '')}
์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ: {additional_info}
์ค‘์š” ์š”๊ตฌ์‚ฌํ•ญ:
1. ์ƒํ’ˆ(#1)์ด ์ด๋ฏธ์ง€ ๊ตฌ๋„์—์„œ ์ค‘์‹ฌ์ ์ธ ์œ„์น˜๋ฅผ ์ฐจ์ง€ํ•˜๋ฉฐ ์ ์ ˆํ•œ ํฌ๊ธฐ(์ด๋ฏธ์ง€์˜ 60-70%)๋กœ ํ‘œํ˜„๋˜๋„๋ก ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
2. ์ด๋ฏธ์ง€๋Š” ์ •ํ™•ํžˆ 1:1 ๋น„์œจ(์ •์‚ฌ๊ฐํ˜•)์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
3. ์ƒํ’ˆ์˜ ๋””์ž์ธ, ์ƒ‰์ƒ, ํ˜•ํƒœ, ๋กœ๊ณ  ๋“ฑ ๋ณธ์งˆ์  ํŠน์„ฑ์€ ์ ˆ๋Œ€ ์ˆ˜์ •ํ•˜์ง€ ๋งˆ์„ธ์š”.
4. ๊ตฌ์ฒด์ ์ธ ์กฐ๋ช… ๊ธฐ๋ฒ•์„ ์ƒ์„ธํžˆ ๋ช…์‹œํ•ด์ฃผ์„ธ์š”:
- ์ •ํ™•ํ•œ ์กฐ๋ช… ์œ„์น˜ (์˜ˆ: "45-degree key light from upper left")
- ์กฐ๋ช… ํ’ˆ์งˆ (์˜ˆ: "soft diffused light", "hard directional light")
- ์กฐ๋ช… ๊ฐ•๋„์™€ ์ƒ‰์˜จ๋„ (์˜ˆ: "warm tungsten key light with cool blue fill")
- ๋ฐ˜์‚ฌ์™€ ๊ทธ๋ฆผ์ž ์ฒ˜๋ฆฌ ๋ฐฉ์‹ (์˜ˆ: "controlled specular highlights with soft shadow transitions")
5. ์ƒํ’ˆ์„ ๋” ๋‹๋ณด์ด๊ฒŒ ํ•˜๋Š” ๋ณด์กฐ ์š”์†Œ(props)๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ™œ์šฉํ•˜๋˜, ์ƒํ’ˆ์ด ํ•ญ์ƒ ์ฃผ์ธ๊ณต์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
6. ๋ฐฐ๊ฒฝ ์žฌ์งˆ๊ณผ ํ‘œ๋ฉด ์งˆ๊ฐ์„ ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค๋ช…ํ•˜๊ณ , ์ƒํ’ˆ๊ณผ์˜ ์ƒํ˜ธ์ž‘์šฉ ๋ฐฉ์‹์„ ๋ช…์‹œํ•ด์ฃผ์„ธ์š”.
7. ์ƒ‰์ƒ ๊ตฌ์„ฑ(color palette, color harmonies)์„ ๋ช…ํ™•ํžˆ ํ•ด์ฃผ์„ธ์š”.
8. ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ์ƒ์—… ๊ด‘๊ณ  ํ’ˆ์งˆ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋˜๋„๋ก ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.
9. ํ”„๋กฌํ”„ํŠธ ๋์— ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ "--ar 1:1 --s 750 --q 2 --v 5.2"๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.
ํ•œ๊ตญ์–ด ์ž…๋ ฅ ๋‚ด์šฉ์„ ์ „๋ฌธ์ ์ธ ์˜์–ด๋กœ ๋ฒˆ์—ญํ•˜์—ฌ ๋ฐ˜์˜ํ•ด์ฃผ์„ธ์š”.
"""
model = genai_generative.GenerativeModel(
'gemini-2.0-flash',
system_instruction=generate_enhanced_system_instruction()
)
response = model.generate_content(
prompt_request,
generation_config=genai_generative.types.GenerationConfig(
temperature=0.8,
top_p=0.97,
top_k=64,
max_output_tokens=1600,
)
)
response_text = response.text.strip()
if "--ar 1:1" not in response_text:
response_text = response_text.rstrip(".") + ". --ar 1:1 --s 750 --q 2 --v 5.2"
return response_text
except Exception as e:
return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
# ------------------- ๋‹จ์ผ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜ -------------------
def generate_product_image(image, bg_type, simple, studio, nature, indoor, tech, colorful, abstract, jewelry, product_name, additional_info):
if image is None:
return None, "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œ ํ›„ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”."
product_name = product_name.strip() or "์ œํ’ˆ"
background_info = get_selected_background_info(bg_type, simple, studio, nature, indoor, tech, colorful, abstract, jewelry)
generated_prompt = generate_prompt_with_gemini(product_name, background_info, additional_info)
if "Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค" in generated_prompt:
warning_msg = (
"[Gemini API ํ‚ค ๋ˆ„๋ฝ]\n"
"API ํ‚ค ์„ค์ • ๋ฐฉ๋ฒ•:\n"
"1. ํ™˜๊ฒฝ ๋ณ€์ˆ˜: export GEMINI_API_KEY=\"your-api-key\"\n"
"2. ์ฝ”๋“œ ๋‚ด ์ง์ ‘ ์ž…๋ ฅ: GEMINI_API_KEY = \"your-api-key\"\n"
"ํ‚ค ๋ฐœ๊ธ‰: https://aistudio.google.com/apikey"
)
return None, warning_msg, warning_msg
final_prompt = filter_prompt_only(generated_prompt)
result_image, status, _ = process_images_with_prompt(image, final_prompt, 0)
return result_image, status, final_prompt
# ------------------- 4์žฅ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜ -------------------
def generate_product_images(image, bg_type, simple, studio, nature, indoor, tech, colorful, abstract, jewelry, product_name, additional_info):
if image is None:
return None, None, None, None, "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œ ํ›„ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”."
product_name = product_name.strip() or "์ œํ’ˆ"
background_info = get_selected_background_info(bg_type, simple, studio, nature, indoor, tech, colorful, abstract, jewelry)
generated_prompt = generate_prompt_with_gemini(product_name, background_info, additional_info)
if "Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค" in generated_prompt:
warning_msg = (
"[Gemini API ํ‚ค ๋ˆ„๋ฝ]\n"
"API ํ‚ค ์„ค์ • ๋ฐฉ๋ฒ•:\n"
"1. ํ™˜๊ฒฝ ๋ณ€์ˆ˜: export GEMINI_API_KEY=\"your-api-key\"\n"
"2. ์ฝ”๋“œ ๋‚ด ์ง์ ‘ ์ž…๋ ฅ: GEMINI_API_KEY = \"your-api-key\"\n"
"ํ‚ค ๋ฐœ๊ธ‰: https://aistudio.google.com/apikey"
)
return None, None, None, None, warning_msg, warning_msg
final_prompt = filter_prompt_only(generated_prompt)
images_list = []
statuses = []
for i in range(4):
result_img, status, _ = process_images_with_prompt(image, final_prompt, variation_index=i)
images_list.append(result_img)
statuses.append(f"์ด๋ฏธ์ง€ #{i+1}: {status}")
time.sleep(1)
combined_status = "\n".join(statuses)
return images_list[0], images_list[1], images_list[2], images_list[3], combined_status, final_prompt
# ------------------- Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ -------------------
def create_app():
dropdown_options = initialize_dropdowns()
with gr.Blocks(title="๊ณ ๊ธ‰ ์ƒํ’ˆ ์ด๋ฏธ์ง€ ๋ฐฐ๊ฒฝ ํ”„๋กฌํ”„ํŠธ ๋ฐ ์ด๋ฏธ์ง€ ์ƒ์„ฑ") as demo:
gr.Markdown("# ๊ณ ๊ธ‰ ์ƒํ’ˆ ์ด๋ฏธ์ง€ ๋ฐฐ๊ฒฝ ํ”„๋กฌํ”„ํŠธ ๋ฐ ์ด๋ฏธ์ง€ ์ƒ์„ฑ")
gr.Markdown(
"์ƒํ’ˆ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ , ์ƒํ’ˆ๋ช…, ๋ฐฐ๊ฒฝ ์˜ต์…˜, ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ ๋ฐ Gemini API ํ‚ค๋ฅผ ์ž…๋ ฅํ•˜๋ฉด Gemini API๋ฅผ ํ†ตํ•ด ์˜์–ด ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ํ”„๋กฌํ”„ํŠธ๋กœ ์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.\n\n"
"๋‹จ์ผ ์ด๋ฏธ์ง€ ์ƒ์„ฑ๊ณผ 4์žฅ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ชจ๋‘ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.\n\n"
"[Gemini API ํ‚ค ๋ฐ›๊ธฐ](https://aistudio.google.com/apikey)"
)
with gr.Row():
# API ํ‚ค ์ž…๋ ฅ ํ•„๋“œ๋งŒ ํ‘œ์‹œ
gemini_api_key = gr.Textbox(
label="Gemini API ํ‚ค",
type="password",
placeholder="API ํ‚ค๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”",
interactive=True
)
with gr.Row():
with gr.Column(scale=1):
product_name = gr.Textbox(label="์ƒํ’ˆ๋ช… (ํ•œ๊ตญ์–ด ์ž…๋ ฅ)", placeholder="์˜ˆ: ์Šคํ‚จ์ผ€์–ด ํŠœ๋ธŒ, ์Šค๋งˆํŠธ์›Œ์น˜, ํ–ฅ์ˆ˜, ์šด๋™ํ™” ๋“ฑ", interactive=True)
image_input = gr.Image(label="์ƒํ’ˆ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", type="pil")
background_type = gr.Radio(
choices=["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "ํ…Œํฌ๋†€๋กœ์ง€ ๋ฐฐ๊ฒฝ", "์ปฌ๋Ÿฌํ’€ ํŒจํ„ด ๋ฐฐ๊ฒฝ", "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ", "์ฅฌ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ"],
label="๋ฐฐ๊ฒฝ ์œ ํ˜•",
value="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ"
)
simple_dropdown = gr.Dropdown(
choices=dropdown_options["simple"],
value=dropdown_options["simple"][0] if dropdown_options["simple"] else None,
label="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=True,
interactive=True
)
studio_dropdown = gr.Dropdown(
choices=dropdown_options["studio"],
value=dropdown_options["studio"][0] if dropdown_options["studio"] else None,
label="์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
nature_dropdown = gr.Dropdown(
choices=dropdown_options["nature"],
value=dropdown_options["nature"][0] if dropdown_options["nature"] else None,
label="์ž์—ฐ ํ™˜๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
indoor_dropdown = gr.Dropdown(
choices=dropdown_options["indoor"],
value=dropdown_options["indoor"][0] if dropdown_options["indoor"] else None,
label="์‹ค๋‚ด ํ™˜๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
tech_dropdown = gr.Dropdown(
choices=dropdown_options["tech"],
value=dropdown_options["tech"][0] if dropdown_options["tech"] else None,
label="ํ…Œํฌ๋†€๋กœ์ง€ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
colorful_dropdown = gr.Dropdown(
choices=dropdown_options["colorful"],
value=dropdown_options["colorful"][0] if dropdown_options["colorful"] else None,
label="์ปฌ๋Ÿฌํ’€ ํŒจํ„ด ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
abstract_dropdown = gr.Dropdown(
choices=dropdown_options["abstract"],
value=dropdown_options["abstract"][0] if dropdown_options["abstract"] else None,
label="์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
jewelry_dropdown = gr.Dropdown(
choices=dropdown_options["jewelry"],
value=dropdown_options["jewelry"][0] if dropdown_options["jewelry"] else None,
label="์ฅฌ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ ์„ ํƒ",
visible=False,
interactive=True
)
additional_info = gr.Textbox(
label="์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ (์„ ํƒ์‚ฌํ•ญ)",
placeholder="์˜ˆ: ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ๋А๋‚Œ, ๋ฐ์€ ์กฐ๋ช…, ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ณด์กฐ ๊ฐ์ฒด ๋“ฑ",
lines=3,
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 == "์‹ค๋‚ด ํ™˜๊ฒฝ")),
tech_dropdown: gr.update(visible=(bg_type == "ํ…Œํฌ๋†€๋กœ์ง€ ๋ฐฐ๊ฒฝ")),
colorful_dropdown: gr.update(visible=(bg_type == "์ปฌ๋Ÿฌํ’€ ํŒจํ„ด ๋ฐฐ๊ฒฝ")),
abstract_dropdown: gr.update(visible=(bg_type == "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ")),
jewelry_dropdown: gr.update(visible=(bg_type == "์ฅฌ์–ผ๋ฆฌ ๋ฐฐ๊ฒฝ"))
}
background_type.change(
fn=update_dropdowns,
inputs=[background_type],
outputs=[simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, tech_dropdown, colorful_dropdown, abstract_dropdown, jewelry_dropdown]
)
with gr.Row():
single_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ ๋ฐ ๋‹จ์ผ ์ด๋ฏธ์ง€ ์ƒ์„ฑ", variant="primary")
multi_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ ๋ฐ 4์žฅ ์ด๋ฏธ์ง€ ์ƒ์„ฑ", variant="primary")
with gr.Column(scale=1):
# ํ”„๋กฌํ”„ํŠธ ์ถœ๋ ฅ UI ์ œ๊ฑฐ, ์ด๋ฏธ์ง€ 4์žฅ๋งŒ ์ถœ๋ ฅ
with gr.Row():
image_output1 = gr.Image(label="์ด๋ฏธ์ง€ #1", type="filepath")
image_output2 = gr.Image(label="์ด๋ฏธ์ง€ #2", type="filepath")
with gr.Row():
image_output3 = gr.Image(label="์ด๋ฏธ์ง€ #3", type="filepath")
image_output4 = gr.Image(label="์ด๋ฏธ์ง€ #4", type="filepath")
status_output = gr.Textbox(label="๊ฒฐ๊ณผ ์ •๋ณด", lines=3)
# ๋‹จ์ผ ์ด๋ฏธ์ง€ ์ƒ์„ฑ์„ ์œ„ํ•œ ํ•จ์ˆ˜ (API ํ‚ค ์ž…๋ ฅ๊ฐ’ ํ™œ์šฉ)
def modified_single_image_gen(api_key, image, bg_type, simple, studio, nature, indoor, tech, colorful, abstract, jewelry, product_name, additional_info):
os.environ["GEMINI_API_KEY"] = api_key.strip()
result_img, status, _ = generate_product_image(image, bg_type, simple, studio, nature, indoor, tech, colorful, abstract, jewelry, product_name, additional_info)
return result_img, None, None, None, status
single_btn.click(
fn=modified_single_image_gen,
inputs=[gemini_api_key, image_input, background_type, simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, tech_dropdown, colorful_dropdown, abstract_dropdown, jewelry_dropdown, product_name, additional_info],
outputs=[image_output1, image_output2, image_output3, image_output4, status_output]
)
# 4์žฅ ์ด๋ฏธ์ง€ ์ƒ์„ฑ์„ ์œ„ํ•œ ํ•จ์ˆ˜ (API ํ‚ค ์ž…๋ ฅ๊ฐ’ ํ™œ์šฉ)
def modified_multi_image_gen(api_key, image, bg_type, simple, studio, nature, indoor, tech, colorful, abstract, jewelry, product_name, additional_info):
os.environ["GEMINI_API_KEY"] = api_key.strip()
img1, img2, img3, img4, status, _ = generate_product_images(image, bg_type, simple, studio, nature, indoor, tech, colorful, abstract, jewelry, product_name, additional_info)
return img1, img2, img3, img4, status
multi_btn.click(
fn=modified_multi_image_gen,
inputs=[gemini_api_key, image_input, background_type, simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, tech_dropdown, colorful_dropdown, abstract_dropdown, jewelry_dropdown, product_name, additional_info],
outputs=[image_output1, image_output2, image_output3, image_output4, status_output]
)
return demo
# ------------------- ๋ฉ”์ธ ์‹คํ–‰ ํ•จ์ˆ˜ -------------------
if __name__ == "__main__":
initialize_backgrounds()
app = create_app()
app.queue()
app.launch()