img_3 / app.py
Kims12's picture
Update app.py
61b020a verified
raw
history blame
16 kB
import gradio as gr
import google.generativeai as genai
from PIL import Image
import os
import json
# Gemini API ν‚€ μ„€μ • (ν™˜κ²½ λ³€μˆ˜μ—μ„œ κ°€μ Έμ˜€κ±°λ‚˜ 직접 μž…λ ₯)
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
# Gemini API μ΄ˆκΈ°ν™”
genai.configure(api_key=GEMINI_API_KEY)
# λ°°κ²½ JSON 파일 경둜 μ„€μ •
BACKGROUNDS_DIR = os.path.join(os.path.dirname(__file__), "background")
# JSON 파일이 μ‘΄μž¬ν•˜μ§€ μ•Šμ„ 경우 디렉토리 생성
if not os.path.exists(BACKGROUNDS_DIR):
os.makedirs(BACKGROUNDS_DIR)
# JSON 파일 λ‘œλ“œ ν•¨μˆ˜
def load_background_json(filename):
file_path = os.path.join(BACKGROUNDS_DIR, filename)
try:
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
print(f"κ²½κ³ : {filename} νŒŒμΌμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€. 기본값을 μ‚¬μš©ν•©λ‹ˆλ‹€.")
return {}
# λ°°κ²½ 데이터 λ‘œλ“œ
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")
ABSTRACT_BACKGROUNDS = load_background_json("abstract_backgrounds.json")
def generate_system_instruction():
return """당신은 μƒν’ˆ μ΄λ―Έμ§€μ˜ 배경을 λ³€κ²½ν•˜κΈ° μœ„ν•œ κ³ ν’ˆμ§ˆ ν”„λ‘¬ν”„νŠΈλ₯Ό μƒμ„±ν•˜λŠ” μ „λ¬Έκ°€μž…λ‹ˆλ‹€.
μ‚¬μš©μžκ°€ μ œκ³΅ν•˜λŠ” μƒν’ˆλͺ…, λ°°κ²½ μœ ν˜•, μΆ”κ°€ μš”μ²­μ‚¬ν•­μ„ λ°”νƒ•μœΌλ‘œ λ―Έλ“œμ €λ‹ˆ(Midjourney)에 μ‚¬μš©ν•  수 μžˆλŠ”
μƒμ„Έν•˜κ³  전문적인 ν”„λ‘¬ν”„νŠΈλ₯Ό μ˜μ–΄λ‘œ μƒμ„±ν•΄μ£Όμ„Έμš”.
λ‹€μŒ κ°€μ΄λ“œλΌμΈμ„ λ°˜λ“œμ‹œ 따라야 ν•©λ‹ˆλ‹€:
1. μƒν’ˆμ„ "#1"둜 μ§€μ •ν•˜μ—¬ μ°Έμ‘°ν•©λ‹ˆλ‹€. (예: "skincare tube (#1)")
2. *** 맀우 μ€‘μš”: μƒν’ˆμ˜ μ›λž˜ νŠΉμ„±(λ””μžμΈ, 색상, ν˜•νƒœ, 둜고, νŒ¨ν‚€μ§€ λ“±)은 μ–΄λ–€ μƒν™©μ—μ„œλ„ μ ˆλŒ€ λ³€κ²½ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ***
3. *** μƒν’ˆμ˜ 본질적 νŠΉμ„±μ€ μœ μ§€ν•˜λ˜, μžμ—°μŠ€λŸ¬μš΄ ν™˜κ²½ 톡합을 μœ„ν•œ μ‘°λͺ…κ³Ό κ·Έλ¦ΌμžλŠ” ν—ˆμš©ν•©λ‹ˆλ‹€: ***
- μƒν’ˆ 자체의 색상, λ””μžμΈ, ν˜•νƒœ, ν…μŠ€μ²˜λŠ” μ ˆλŒ€ μˆ˜μ •ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
- ν™˜κ²½κ³Ό μžμ—°μŠ€λŸ½κ²Œ μ–΄μšΈλ¦¬λŠ” 그림자, μ£Όλ³€ μ‘°λͺ… νš¨κ³ΌλŠ” ν—ˆμš©λ©λ‹ˆλ‹€.
- μƒν’ˆμ— 물방울, 응좕, 금, 은과 같은 μΆ”κ°€ μš”μ†Œλ‚˜ 물리적 νš¨κ³ΌλŠ” μ μš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
- ν™˜κ²½μ— μ–΄μšΈλ¦¬λŠ” μžμ—°μŠ€λŸ¬μš΄ λΉ› λ°˜μ‚¬, μ£Όλ³€ μ‘°λͺ…, κ·Έλ¦ΌμžλŠ” 사싀적 톡합감을 μœ„ν•΄ μ μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
4. 이미지 λΉ„μœ¨μ€ μ •ν™•νžˆ 1:1(μ •μ‚¬κ°ν˜•) ν˜•μ‹μœΌλ‘œ μ§€μ •ν•©λ‹ˆλ‹€. ν”„λ‘¬ν”„νŠΈμ— "square format", "1:1 ratio" λ˜λŠ” "aspect ratio 1:1"을 λͺ…μ‹œμ μœΌλ‘œ ν¬ν•¨ν•©λ‹ˆλ‹€.
5. μƒν’ˆμ€ λ°˜λ“œμ‹œ μ •μ‚¬κ°ν˜• κ΅¬λ„μ˜ 정쀑앙에 λ°°μΉ˜λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.
6. μƒν’ˆμ„ μ΄λ―Έμ§€μ˜ μ£Όμš” 초점으둜 λΆ€κ°μ‹œν‚€κ³ , μƒν’ˆμ˜ λΉ„μœ¨μ΄ 전체 μ΄λ―Έμ§€μ—μ„œ 크게 μ°¨μ§€ν•˜λ„λ‘ ν•©λ‹ˆλ‹€.
7. μƒν’ˆ 이미지 컷아웃(#1)의 κΈ°λ³Έ ν˜•νƒœμ™€ 색상은 μœ μ§€ν•˜λ©΄μ„œ, μ„ νƒν•œ ν™˜κ²½μ— μžμ—°μŠ€λŸ½κ²Œ ν†΅ν•©λ˜λ„λ‘ ν•©λ‹ˆλ‹€.
8. κ³ κΈ‰μŠ€λŸ¬μš΄ 상업적 이미지λ₯Ό μœ„ν•œ λ‹€μŒ ν™˜κ²½ μš”μ†Œλ“€μ„ ν¬ν•¨ν•˜μ„Έμš”:
- μƒν’ˆκ³Ό μ–΄μšΈλ¦¬λŠ” μ£Όλ³€ ν™˜κ²½/λ°°κ²½ μš”μ†Œλ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, ν™”μž₯ν’ˆ 주변에 κ½ƒμ΄λ‚˜ ν—ˆλΈŒ, 음료 μ œν’ˆ μ˜†μ— 과일, μ „μžμ œν’ˆ κ·Όμ²˜μ— ν˜„λŒ€μ  μ†Œν’ˆ λ“±.
- ν™˜κ²½μ˜ μ‘°λͺ… 효과(λ¦Ό 라이트, 백라이트, μ†Œν”„νŠΈλ°•μŠ€ λ“±)λ₯Ό μ„€λͺ…ν•©λ‹ˆλ‹€.
- μƒν’ˆμ΄ ν™˜κ²½μ— μžμ—°μŠ€λŸ½κ²Œ μ‘΄μž¬ν•˜λŠ” κ²ƒμ²˜λŸΌ 보이도둝 μ μ ˆν•œ κ·Έλ¦Όμžμ™€ λΉ› ν‘œν˜„μ„ ν¬ν•¨ν•©λ‹ˆλ‹€.
- μƒν’ˆμ˜ μš©λ„λ‚˜ μž₯점을 κ°„μ ‘μ μœΌλ‘œ μ•”μ‹œν•˜λŠ” λ°°κ²½ μš”μ†Œλ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.
- ν”„λ‘œνŽ˜μ…”λ„ν•œ 상업 사진 효과(선택적 피사계 심도, μ†Œν”„νŠΈ 포컀슀, μŠ€νŠœλ””μ˜€ μ‘°λͺ… λ“±)λ₯Ό λͺ…μ‹œν•©λ‹ˆλ‹€.
9. ν”„λ‘¬ν”„νŠΈμ— λ‹€μŒ μš”μ†Œλ“€μ„ λͺ…μ‹œμ μœΌλ‘œ ν¬ν•¨ν•˜μ„Έμš”:
- "highly detailed commercial photography"
- "award-winning product photography"
- "professional advertising imagery"
- "studio quality"
- "magazine advertisement quality"
10. λ°°κ²½ ν™˜κ²½ μš”μ†Œλ₯Ό μƒν’ˆ μΉ΄ν…Œκ³ λ¦¬μ— 맞게 μ„ νƒν•©λ‹ˆλ‹€:
- μŠ€ν‚¨μΌ€μ–΄ μ œν’ˆ: κΉ¨λ—ν•œ μš•μ‹€ μ„ λ°˜, μš°μ•„ν•œ ν™”μž₯λŒ€, 슀파 같은 ν™˜κ²½ λ“±
- 음료 μ œν’ˆ: μ„Έλ ¨λœ ν…Œμ΄λΈ”, νŒŒν‹° ν™˜κ²½, μ•Όμ™Έ 피크닉 μž₯λ©΄ λ“±
- μ „μž μ œν’ˆ: μ„Έλ ¨λœ μž‘μ—… 곡간, ν˜„λŒ€μ μΈ κ±°μ‹€, λ―Έλ‹ˆλ©€ν•œ 책상 λ“±
- νŒ¨μ…˜/의λ₯˜: μ„Έλ ¨λœ μ‡Όλ£Έ, λ„μ‹œ 거리, μ—˜λ ˆκ°•μŠ€ν•œ λΌμ΄ν”„μŠ€νƒ€μΌ ν™˜κ²½ λ“±
- μ‹ν’ˆ μ œν’ˆ: κΉ”λ”ν•œ μ£Όλ°©, 식탁, μš”λ¦¬ ν™˜κ²½ λ“±
11. μ‚¬μš©μžκ°€ μ œκ³΅ν•œ ꡬ체적인 λ°°κ²½κ³Ό μΆ”κ°€ μš”μ²­μ‚¬ν•­μ„ μ •ν™•νžˆ λ°˜μ˜ν•©λ‹ˆλ‹€.
12. ν”„λ‘¬ν”„νŠΈλŠ” λ―Έλ“œμ €λ‹ˆ AI에 μ΅œμ ν™”λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.
13. ν”„λ‘¬ν”„νŠΈ 끝에 "--ar 1:1 --s 750 --q 2" νŒŒλΌλ―Έν„°λ₯Ό μΆ”κ°€ν•˜μ—¬ λ―Έλ“œμ €λ‹ˆμ—μ„œ κ³ ν’ˆμ§ˆ μ •μ‚¬κ°ν˜• λΉ„μœ¨μ„ κ°•μ œν•©λ‹ˆλ‹€.
좜λ ₯ ν˜•μ‹μ€ μ˜μ–΄λ‘œ 된 단일 λ‹¨λ½μ˜ μƒμ„Έν•œ ν”„λ‘¬ν”„νŠΈμ—¬μ•Ό ν•˜λ©°, 끝에 λ―Έλ“œμ €λ‹ˆ νŒŒλΌλ―Έν„°κ°€ ν¬ν•¨λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.
"""
def generate_prompt_with_gemini(product_name, background_info, additional_info=""):
if not GEMINI_API_KEY:
return "Gemini API ν‚€κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. ν™˜κ²½ λ³€μˆ˜ GEMINI_API_KEYλ₯Ό μ„€μ •ν•˜κ±°λ‚˜ μ½”λ“œμ— 직접 μž…λ ₯ν•˜μ„Έμš”."
try:
prompt_request = f"""
μƒν’ˆλͺ…: {product_name}
λ°°κ²½ μœ ν˜•: {background_info.get('english', 'studio')}
λ°°κ²½ μΉ΄ν…Œκ³ λ¦¬: {background_info.get('category', '')}
λ°°κ²½ 이름: {background_info.get('name', '')}
μΆ”κ°€ μš”μ²­μ‚¬ν•­: {additional_info}
μ€‘μš” μš”κ΅¬μ‚¬ν•­:
1. μƒν’ˆμ΄ 크게 λΆ€κ°λ˜κ³  μ΄λ―Έμ§€μ—μ„œ 쀑심적인 μœ„μΉ˜λ₯Ό μ°¨μ§€ν•˜λ„λ‘ ν”„λ‘¬ν”„νŠΈλ₯Ό μƒμ„±ν•΄μ£Όμ„Έμš”.
2. μ΄λ―Έμ§€λŠ” μ •ν™•νžˆ 1:1 λΉ„μœ¨(μ •μ‚¬κ°ν˜•)이어야 ν•©λ‹ˆλ‹€.
3. μƒν’ˆμ€ μ •μ‚¬κ°ν˜• ν”„λ ˆμž„μ˜ 정쀑앙에 μœ„μΉ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.
4. μƒν’ˆμ˜ λ””μžμΈ, 색상, ν˜•νƒœ, 둜고 λ“± 본질적 νŠΉμ„±μ€ μ ˆλŒ€ μˆ˜μ •ν•˜μ§€ λ§ˆμ„Έμš”.
5. ν™˜κ²½κ³Όμ˜ μžμ—°μŠ€λŸ¬μš΄ 톡합을 μœ„ν•œ μ‘°λͺ… νš¨κ³Όμ™€ κ·Έλ¦ΌμžλŠ” ν¬ν•¨ν•΄μ£Όμ„Έμš”.
6. μƒν’ˆμ„ 더 λ‹λ³΄μ΄κ²Œ ν•˜λŠ” λ°°κ²½ ν™˜κ²½μ„ μ„€λͺ…ν•΄μ£Όμ„Έμš”.
7. κ³ κΈ‰μŠ€λŸ¬μš΄ 상업 κ΄‘κ³  ν’ˆμ§ˆμ˜ 이미지가 λ˜λ„λ‘ ν™˜κ²½ μ„€λͺ…을 ν•΄μ£Όμ„Έμš”.
8. ν”„λ‘¬ν”„νŠΈ 끝에 λ―Έλ“œμ €λ‹ˆ νŒŒλΌλ―Έν„° "--ar 1:1 --s 750 --q 2"λ₯Ό μΆ”κ°€ν•΄μ£Όμ„Έμš”.
ν•œκ΅­μ–΄ μž…λ ₯ λ‚΄μš©μ„ μ˜μ–΄λ‘œ 적절히 λ²ˆμ—­ν•˜μ—¬ λ°˜μ˜ν•΄μ£Όμ„Έμš”.
"""
model = genai.GenerativeModel(
'gemini-2.0-flash',
system_instruction=generate_system_instruction()
)
response = model.generate_content(
prompt_request,
generation_config=genai.types.GenerationConfig(
temperature=0.7,
top_p=0.95,
top_k=64,
max_output_tokens=1024,
)
)
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"
return response_text
except Exception as e:
return f"ν”„λ‘¬ν”„νŠΈ 생성 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {str(e)}"
def create_app():
with gr.Blocks(title="κ³ κΈ‰ μƒν’ˆ 이미지 λ°°κ²½ ν”„λ‘¬ν”„νŠΈ 생성기") as demo:
gr.Markdown("# κ³ κΈ‰ μƒν’ˆ 이미지 λ°°κ²½ ν”„λ‘¬ν”„νŠΈ 생성기")
gr.Markdown("μƒν’ˆ 이미지λ₯Ό μ—…λ‘œλ“œν•˜κ³  μ˜΅μ…˜μ„ μ„ νƒν•˜λ©΄ κ³ ν’ˆμ§ˆ μƒμ—…μš© ν”„λ‘¬ν”„νŠΈκ°€ μƒμ„±λ©λ‹ˆλ‹€.")
# μƒν’ˆλͺ… μ„Ήμ…˜
with gr.Row():
product_name = gr.Textbox(label="μƒν’ˆλͺ… (ν•œκ΅­μ–΄ μž…λ ₯)", placeholder="예: μŠ€ν‚¨μΌ€μ–΄ 튜브, ν…€λΈ”λŸ¬ λ“±", interactive=True)
with gr.Row():
# 쒌츑 컬럼 - μž…λ ₯ 컨트둀
with gr.Column(scale=1):
image_input = gr.Image(label="μƒν’ˆ 이미지 μ—…λ‘œλ“œ", type="pil")
# λ°°κ²½ νƒ€μž… νƒ­ (μ‹¬ν”Œ, μŠ€νŠœλ””μ˜€, μžμ—°, μ‹€λ‚΄, 좔상)
gr.Markdown("## λ°°κ²½ 선택 (ν•œ κ°€μ§€λ§Œ 선택)")
with gr.Tabs() as background_tabs:
with gr.TabItem("μ‹¬ν”Œ λ°°κ²½"):
simple_dropdown = gr.Dropdown(
choices=list(SIMPLE_BACKGROUNDS.keys()),
value=list(SIMPLE_BACKGROUNDS.keys())[0] if SIMPLE_BACKGROUNDS else None,
label="μ‹¬ν”Œ λ°°κ²½ 선택",
interactive=True
)
with gr.TabItem("μŠ€νŠœλ””μ˜€ λ°°κ²½"):
studio_dropdown = gr.Dropdown(
choices=list(STUDIO_BACKGROUNDS.keys()),
value=list(STUDIO_BACKGROUNDS.keys())[0] if STUDIO_BACKGROUNDS else None,
label="μŠ€νŠœλ””μ˜€ λ°°κ²½ 선택",
interactive=True
)
with gr.TabItem("μžμ—° ν™˜κ²½"):
nature_dropdown = gr.Dropdown(
choices=list(NATURE_BACKGROUNDS.keys()),
value=list(NATURE_BACKGROUNDS.keys())[0] if NATURE_BACKGROUNDS else None,
label="μžμ—° ν™˜κ²½ 선택",
interactive=True
)
with gr.TabItem("μ‹€λ‚΄ ν™˜κ²½"):
indoor_dropdown = gr.Dropdown(
choices=list(INDOOR_BACKGROUNDS.keys()),
value=list(INDOOR_BACKGROUNDS.keys())[0] if INDOOR_BACKGROUNDS else None,
label="μ‹€λ‚΄ ν™˜κ²½ 선택",
interactive=True
)
with gr.TabItem("좔상/특수 λ°°κ²½"):
abstract_dropdown = gr.Dropdown(
choices=list(ABSTRACT_BACKGROUNDS.keys()),
value=list(ABSTRACT_BACKGROUNDS.keys())[0] if ABSTRACT_BACKGROUNDS else None,
label="좔상/특수 λ°°κ²½ 선택",
interactive=True
)
# μΆ”κ°€ μš”μ²­μ‚¬ν•­
additional_info = gr.Textbox(
label="μΆ”κ°€ μš”μ²­μ‚¬ν•­ (선택사항)",
placeholder="예: κ³ κΈ‰μŠ€λŸ¬μš΄ λŠλ‚Œ, 밝은 μ‘°λͺ… λ“±",
lines=3,
interactive=True
)
submit_btn = gr.Button("ν”„λ‘¬ν”„νŠΈ 생성", variant="primary")
# 우츑 컬럼 - 좜λ ₯ κ²°κ³Ό
with gr.Column(scale=1):
prompt_output = gr.Textbox(label="μƒμ„±λœ ν”„λ‘¬ν”„νŠΈ", lines=10)
image_preview = gr.Image(label="μ—…λ‘œλ“œλœ 이미지 (#1)", type="pil")
preview_html = gr.HTML("ν”„λ‘¬ν”„νŠΈ 생성 μ‹œ 여기에 미리보기가 ν‘œμ‹œλ©λ‹ˆλ‹€.")
# μ„ νƒλœ λ°°κ²½ 정보 κ°€μ Έμ˜€κΈ°
def get_selected_background_info(active_tab, simple, studio, nature, indoor, abstract):
if active_tab == "μ‹¬ν”Œ λ°°κ²½" and simple:
return {
"category": "μ‹¬ν”Œ λ°°κ²½",
"name": simple,
"english": SIMPLE_BACKGROUNDS.get(simple, "white background")
}
elif active_tab == "μŠ€νŠœλ””μ˜€ λ°°κ²½" and studio:
return {
"category": "μŠ€νŠœλ””μ˜€ λ°°κ²½",
"name": studio,
"english": STUDIO_BACKGROUNDS.get(studio, "product photography studio")
}
elif active_tab == "μžμ—° ν™˜κ²½" and nature:
return {
"category": "μžμ—° ν™˜κ²½",
"name": nature,
"english": NATURE_BACKGROUNDS.get(nature, "natural environment")
}
elif active_tab == "μ‹€λ‚΄ ν™˜κ²½" and indoor:
return {
"category": "μ‹€λ‚΄ ν™˜κ²½",
"name": indoor,
"english": INDOOR_BACKGROUNDS.get(indoor, "indoor environment")
}
elif active_tab == "좔상/특수 λ°°κ²½" and abstract:
return {
"category": "좔상/특수 λ°°κ²½",
"name": abstract,
"english": ABSTRACT_BACKGROUNDS.get(abstract, "abstract background")
}
else:
return {
"category": "κΈ°λ³Έ λ°°κ²½",
"name": "ν™”μ΄νŠΈ λ°°κ²½",
"english": "white background"
}
# ν”„λ‘¬ν”„νŠΈ 생성 ν•¨μˆ˜
def generate_output(image, active_tab, simple, studio, nature, indoor, abstract, product_text, additional_text):
if image is None:
gr.Warning("이미지λ₯Ό μ—…λ‘œλ“œν•΄μ£Όμ„Έμš”.")
return "이미지λ₯Ό μ—…λ‘œλ“œν•΄μ£Όμ„Έμš”.", None, "이미지λ₯Ό μ—…λ‘œλ“œ ν›„ ν”„λ‘¬ν”„νŠΈλ₯Ό μƒμ„±ν•΄μ£Όμ„Έμš”."
product_text = product_text.strip() or "μ œν’ˆ"
# λ°°κ²½ 정보 κ°€μ Έμ˜€κΈ°
background_info = get_selected_background_info(active_tab, simple, studio, nature, indoor, abstract)
try:
prompt = generate_prompt_with_gemini(product_text, background_info, additional_text)
if not GEMINI_API_KEY:
gr.Warning("Gemini API ν‚€κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. ν‚€λ₯Ό λ°œκΈ‰λ°›μ•„ μ„€μ •ν•΄μ£Όμ„Έμš”.")
prompt = """
[Gemini API ν‚€ λˆ„λ½]
API ν‚€ μ„€μ • 방법:
1. ν™˜κ²½ λ³€μˆ˜: export GEMINI_API_KEY="your-api-key"
2. μ½”λ“œ λ‚΄ 직접 μž…λ ₯: GEMINI_API_KEY = "your-api-key"
ν‚€ λ°œκΈ‰: https://makersuite.google.com/
"""
return prompt, image, "API ν‚€λ₯Ό μ„€μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€."
# ν”„λ‘¬ν”„νŠΈ μš”μ•½ HTML 생성
preview = f"""
<div style="padding:10px; border:1px solid #ddd; border-radius:8px; margin-top:10px;">
<h3>ν”„λ‘¬ν”„νŠΈ μš”μ•½</h3>
<p><strong>총 길이:</strong> {len(prompt)} κΈ€μž</p>
<p><strong>λ°°κ²½:</strong> {background_info['category']} &gt; {background_info['name']}</p>
<p><strong>μ£Όμš” μš”μ†Œ:</strong> {", ".join([kw for kw in ["commercial photography", "product", "square format", "centered", "detailed"] if kw.lower() in prompt.lower()])}</p>
<p><strong>λ―Έλ“œμ €λ‹ˆ νŒŒλΌλ―Έν„°:</strong> {" ".join([param for param in ["--ar 1:1", "--s 750", "--q 2"] if param in prompt])}</p>
</div>
"""
return prompt, image, preview
except Exception as e:
error_msg = f"ν”„λ‘¬ν”„νŠΈ 생성 쀑 였λ₯˜ λ°œμƒ: {str(e)}"
gr.Error(error_msg)
return error_msg, image, "였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€."
# ν”„λ‘¬ν”„νŠΈ 생성 λ²„νŠΌ 클릭 이벀트
submit_btn.click(
fn=generate_output,
inputs=[
image_input,
background_tabs,
simple_dropdown,
studio_dropdown,
nature_dropdown,
indoor_dropdown,
abstract_dropdown,
product_name,
additional_info
],
outputs=[
prompt_output,
image_preview,
preview_html
]
)
return demo
if __name__ == "__main__":
app = create_app()
app.launch()