Kims12 commited on
Commit
fd41e09
ยท
verified ยท
1 Parent(s): c69cb94

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +247 -329
app.py CHANGED
@@ -1,14 +1,14 @@
1
  import os
2
  import tempfile
3
- import json
4
  from PIL import Image
5
  import gradio as gr
6
  import logging
7
  import re
8
  import time
 
9
 
10
- # ํŒจํ‚ค์ง€ ์ž„ํฌํŠธ ๋ฐฉ์‹์„ ๋ณ€๊ฒฝ
11
- import google.generativeai as genai
12
  from dotenv import load_dotenv
13
 
14
  load_dotenv()
@@ -19,27 +19,15 @@ logger = logging.getLogger(__name__)
19
 
20
  # Gemini API ํ‚ค ์„ค์ •
21
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
22
- if GEMINI_API_KEY:
23
- genai.configure(api_key=GEMINI_API_KEY)
24
- else:
25
- logger.warning("GEMINI_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
26
 
27
- # ๋ฐฐ๊ฒฝ JSON ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • - ์ƒ๋Œ€ ๊ฒฝ๋กœ ์‚ฌ์šฉ
28
  BACKGROUNDS_DIR = "./background"
29
 
30
- # ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ
31
  if not os.path.exists(BACKGROUNDS_DIR):
32
  os.makedirs(BACKGROUNDS_DIR)
33
  logger.info(f"๋ฐฐ๊ฒฝ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค: {BACKGROUNDS_DIR}")
34
- else:
35
- logger.info(f"๋ฐฐ๊ฒฝ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค: {BACKGROUNDS_DIR}")
36
-
37
- # ๊ธฐ๋ณธ ๋ฐฐ๊ฒฝ ๋ฐ์ดํ„ฐ
38
- SIMPLE_BACKGROUNDS = {"ํ™”์ดํŠธ ๋ฐฐ๊ฒฝ": "white background", "๋ธ”๋ž™ ๋ฐฐ๊ฒฝ": "black background", "๊ทธ๋ผ๋ฐ์ด์…˜ ๋ฐฐ๊ฒฝ": "gradient background"}
39
- STUDIO_BACKGROUNDS = {"์ œํ’ˆ ์‚ฌ์ง„ ์ŠคํŠœ๋””์˜ค": "product photography studio", "๋ฏธ๋‹ˆ๋ฉ€ ์ŠคํŠœ๋””์˜ค": "minimal studio"}
40
- NATURE_BACKGROUNDS = {"์—ด๋Œ€ ํ•ด๋ณ€": "tropical beach", "์ˆฒ์†": "forest", "์‚ฐ์•… ์ง€๋Œ€": "mountain landscape"}
41
- INDOOR_BACKGROUNDS = {"๋ชจ๋˜ ๋ฆฌ๋น™๋ฃธ": "modern living room", "์„ธ๋ จ๋œ ์‚ฌ๋ฌด์‹ค": "elegant office", "๋Ÿญ์…”๋ฆฌ ํ˜ธํ…”": "luxury hotel"}
42
- ABSTRACT_BACKGROUNDS = {"๋„ค์˜จ ์กฐ๋ช…": "neon lights", "์ถ”์ƒ์  ๊ทธ๋ผ๋ฐ์ด์…˜": "abstract gradient", "์šฐ์ฃผ ๋ฐฐ๊ฒฝ": "space background"}
43
 
44
  # JSON ํŒŒ์ผ ๋กœ๋“œ ํ•จ์ˆ˜
45
  def load_background_json(filename):
@@ -51,34 +39,6 @@ def load_background_json(filename):
51
  return data
52
  except FileNotFoundError:
53
  logger.warning(f"๊ฒฝ๊ณ : {filename} ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
54
- # ๊ธฐ๋ณธ๊ฐ’ ์ƒ์„ฑ - ํŒŒ์ผ์ด ์—†๋Š” ๊ฒฝ์šฐ ์ƒ์„ฑ
55
- try:
56
- with open(file_path, 'w', encoding='utf-8') as f:
57
- if "simple" in filename:
58
- json.dump(SIMPLE_BACKGROUNDS, f, ensure_ascii=False, indent=2)
59
- elif "studio" in filename:
60
- json.dump(STUDIO_BACKGROUNDS, f, ensure_ascii=False, indent=2)
61
- elif "nature" in filename:
62
- json.dump(NATURE_BACKGROUNDS, f, ensure_ascii=False, indent=2)
63
- elif "indoor" in filename:
64
- json.dump(INDOOR_BACKGROUNDS, f, ensure_ascii=False, indent=2)
65
- elif "abstract" in filename:
66
- json.dump(ABSTRACT_BACKGROUNDS, f, ensure_ascii=False, indent=2)
67
- logger.info(f"{filename} ํŒŒ์ผ์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.")
68
- except Exception as e:
69
- logger.error(f"ํŒŒ์ผ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
70
-
71
- # ๊ธฐ๋ณธ๊ฐ’ ๋ฐ˜ํ™˜
72
- if "simple" in filename:
73
- return SIMPLE_BACKGROUNDS
74
- elif "studio" in filename:
75
- return STUDIO_BACKGROUNDS
76
- elif "nature" in filename:
77
- return NATURE_BACKGROUNDS
78
- elif "indoor" in filename:
79
- return INDOOR_BACKGROUNDS
80
- elif "abstract" in filename:
81
- return ABSTRACT_BACKGROUNDS
82
  return {}
83
  except json.JSONDecodeError:
84
  logger.warning(f"๊ฒฝ๊ณ : {filename} ํŒŒ์ผ์˜ JSON ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
@@ -94,75 +54,151 @@ NATURE_BACKGROUNDS = load_background_json("nature_backgrounds.json")
94
  INDOOR_BACKGROUNDS = load_background_json("indoor_backgrounds.json")
95
  ABSTRACT_BACKGROUNDS = load_background_json("abstract_backgrounds.json")
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  def save_binary_file(file_name, data):
98
  with open(file_name, "wb") as f:
99
  f.write(data)
100
 
101
- def translate_prompt_to_english(prompt):
102
- if not re.search("[๊ฐ€-ํžฃ]", prompt):
103
- return prompt
104
-
105
- prompt = prompt.replace("#1", "IMAGE_TAG_ONE")
106
-
107
  try:
108
- if not GEMINI_API_KEY:
109
- logger.error("Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
110
- prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
111
- return prompt
112
-
113
- translation_prompt = f"""
114
- Translate the following Korean text to English:
115
-
116
- {prompt}
117
-
118
- IMPORTANT: The token IMAGE_TAG_ONE is a special tag
119
- and must be preserved exactly as is in your translation. Do not translate this token.
120
- """
121
-
122
- logger.info(f"Translation prompt: {translation_prompt}")
123
-
124
- # ์ƒˆ๋กœ์šด API ์‚ฌ์šฉ ๋ฐฉ์‹
125
- response = genai.generate_text(
126
- model="gemini-2.0-flash",
127
- prompt=translation_prompt,
128
- temperature=0.2,
129
- top_p=0.95,
130
- top_k=40,
131
- max_output_tokens=512
132
  )
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
- translated_text = response.result
135
-
136
- if translated_text and translated_text.strip():
137
- translated_text = translated_text.replace("IMAGE_TAG_ONE", "#1")
138
- logger.info(f"Translated text: {translated_text.strip()}")
139
- return translated_text.strip()
140
- else:
141
- logger.warning("๋ฒˆ์—ญ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์›๋ณธ ํ”„๋กฌํ”„ํŠธ ์‚ฌ์šฉ")
142
- prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
143
- return prompt
144
  except Exception as e:
145
- logger.exception("๋ฒˆ์—ญ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
146
- prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
147
- return prompt
148
-
149
- def preprocess_prompt(prompt, image1):
150
- has_img1 = image1 is not None
151
 
152
- if "#1" in prompt and not has_img1:
153
- prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  else:
155
- prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
156
-
157
- prompt += " ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”. ์ด๋ฏธ์ง€์— ํ…์ŠคํŠธ๋‚˜ ๊ธ€์ž๋ฅผ ํฌํ•จํ•˜์ง€ ๋งˆ์„ธ์š”."
158
- return prompt
 
159
 
160
  def generate_with_images(prompt, images, variation_index=0):
161
  try:
162
- if not GEMINI_API_KEY:
 
163
  return None, "API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
164
 
165
- client = genai.Client(api_key=GEMINI_API_KEY)
166
  logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt}, ๋ณ€ํ˜• ์ธ๋ฑ์Šค: {variation_index}")
167
 
168
  variation_suffixes = [
@@ -236,11 +272,7 @@ def process_images_with_prompt(image1, prompt, variation_index=0, max_retries=3)
236
  return None, "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", ""
237
 
238
  if prompt and prompt.strip():
239
- processed_prompt = preprocess_prompt(prompt, image1)
240
- if re.search("[๊ฐ€-ํžฃ]", processed_prompt):
241
- final_prompt = translate_prompt_to_english(processed_prompt)
242
- else:
243
- final_prompt = processed_prompt
244
  else:
245
  final_prompt = "Please creatively transform this image into a more vivid and artistic version. Do not include any text or watermarks in the generated image."
246
  logger.info("Default prompt generated for single image")
@@ -296,240 +328,94 @@ def generate_multiple_images(image1, prompt, progress=gr.Progress()):
296
 
297
  return results[0], results[1], results[2], results[3], combined_status, combined_prompts
298
 
299
- def generate_system_instruction():
300
- return """๋‹น์‹ ์€ ์ƒํ’ˆ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ๊ณ ํ’ˆ์งˆ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
301
- ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ƒํ’ˆ๋ช…, ๋ฐฐ๊ฒฝ ์œ ํ˜•, ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋ฏธ๋“œ์ €๋‹ˆ(Midjourney)์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”
302
- ์ƒ์„ธํ•˜๊ณ  ์ „๋ฌธ์ ์ธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์˜์–ด๋กœ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
303
- ๋‹ค์Œ ๊ฐ€์ด๋“œ๋ผ์ธ์„ ๋ฐ˜๋“œ์‹œ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค:
304
- 1. ์ƒํ’ˆ์„ "#1"๋กœ ์ง€์ •ํ•˜์—ฌ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. (์˜ˆ: "skincare tube (#1)")
305
- 2. *** ๋งค์šฐ ์ค‘์š”: ์ƒํ’ˆ์˜ ์›๋ž˜ ํŠน์„ฑ(๋””์ž์ธ, ์ƒ‰์ƒ, ํ˜•ํƒœ, ๋กœ๊ณ , ํŒจํ‚ค์ง€ ๋“ฑ)์€ ์–ด๋–ค ์ƒํ™ฉ์—์„œ๋„ ์ ˆ๋Œ€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ***
306
- 3. *** ์ƒํ’ˆ์˜ ๋ณธ์งˆ์  ํŠน์„ฑ์€ ์œ ์ง€ํ•˜๋˜, ์ž์—ฐ์Šค๋Ÿฌ์šด ํ™˜๊ฒฝ ํ†ตํ•ฉ์„ ์œ„ํ•œ ์กฐ๋ช…๊ณผ ๊ทธ๋ฆผ์ž๋Š” ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค: ***
307
- - ์ƒํ’ˆ ์ž์ฒด์˜ ์ƒ‰์ƒ, ๋””์ž์ธ, ํ˜•ํƒœ, ํ…์Šค์ฒ˜๋Š” ์ ˆ๋Œ€ ์ˆ˜์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
308
- - ํ™˜๊ฒฝ๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์–ด์šธ๋ฆฌ๋Š” ๊ทธ๋ฆผ์ž, ์ฃผ๋ณ€ ์กฐ๋ช… ํšจ๊ณผ๋Š” ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.
309
- - ์ƒํ’ˆ์— ๋ฌผ๋ฐฉ์šธ, ์‘์ถ•, ๊ธˆ, ์€๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ์š”์†Œ๋‚˜ ๋ฌผ๋ฆฌ์  ํšจ๊ณผ๋Š” ์ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
310
- - ํ™˜๊ฒฝ์— ์–ด์šธ๋ฆฌ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋น› ๋ฐ˜์‚ฌ, ์ฃผ๋ณ€ ์กฐ๋ช…, ๊ทธ๋ฆผ์ž๋Š” ์‚ฌ์‹ค์  ํ†ตํ•ฉ๊ฐ์„ ์œ„ํ•ด ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
311
- 4. ์ด๋ฏธ์ง€ ๋น„์œจ์€ ์ •ํ™•ํžˆ 1:1(์ •์‚ฌ๊ฐํ˜•) ํ˜•์‹์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กฌํ”„ํŠธ์— "square format", "1:1 ratio" ๋˜๋Š” "aspect ratio 1:1"์„ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
312
- 5. ์ƒํ’ˆ์€ ๋ฐ˜๋“œ์‹œ ์ •์‚ฌ๊ฐํ˜• ๊ตฌ๋„์˜ ์ •์ค‘์•™์— ๋ฐฐ์น˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
313
- 6. ์ƒํ’ˆ์„ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ์ดˆ์ ์œผ๋กœ ๋ถ€๊ฐ์‹œํ‚ค๊ณ , ์ƒํ’ˆ์˜ ๋น„์œจ์ด ์ „์ฒด ์ด๋ฏธ์ง€์—์„œ ํฌ๊ฒŒ ์ฐจ์ง€ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
314
- 7. ์ƒํ’ˆ ์ด๋ฏธ์ง€ ์ปท์•„์›ƒ(#1)์˜ ๊ธฐ๋ณธ ํ˜•ํƒœ์™€ ์ƒ‰์ƒ์€ ์œ ์ง€ํ•˜๋ฉด์„œ, ์„ ํƒํ•œ ํ™˜๊ฒฝ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ†ตํ•ฉ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
315
- 8. ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ์ƒ์—…์  ์ด๋ฏธ์ง€๋ฅผ ์œ„ํ•œ ๋‹ค์Œ ํ™˜๊ฒฝ ์š”์†Œ๋“ค์„ ํฌํ•จํ•˜์„ธ์š”:
316
- - ์ƒํ’ˆ๊ณผ ์–ด์šธ๋ฆฌ๋Š” ์ฃผ๋ณ€ ํ™˜๊ฒฝ/๋ฐฐ๊ฒฝ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ™”์žฅํ’ˆ ์ฃผ๋ณ€์— ๊ฝƒ์ด๋‚˜ ํ—ˆ๋ธŒ, ์Œ๋ฃŒ ์ œํ’ˆ ์˜†์— ๊ณผ์ผ, ์ „์ž์ œํ’ˆ ๊ทผ์ฒ˜์— ํ˜„๋Œ€์  ์†Œํ’ˆ ๋“ฑ.
317
- - ํ™˜๊ฒฝ์˜ ์กฐ๋ช… ํšจ๊ณผ(๋ฆผ ๋ผ์ดํŠธ, ๋ฐฑ๋ผ์ดํŠธ, ์†Œํ”„ํŠธ๋ฐ•์Šค ๋“ฑ)๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
318
- - ์ƒํ’ˆ์ด ํ™˜๊ฒฝ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์กด์žฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋„๋ก ์ ์ ˆํ•œ ๊ทธ๋ฆผ์ž์™€ ๋น› ํ‘œํ˜„์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
319
- - ์ƒํ’ˆ์˜ ์šฉ๋„๋‚˜ ์žฅ์ ์„ ๊ฐ„์ ‘์ ์œผ๋กœ ์•”์‹œํ•˜๋Š” ๋ฐฐ๊ฒฝ ์š”์†Œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
320
- - ํ”„๋กœํŽ˜์…”๋„ํ•œ ์ƒ์—… ์‚ฌ์ง„ ํšจ๊ณผ(์„ ํƒ์  ํ”ผ์‚ฌ๊ณ„ ์‹ฌ๋„, ์†Œํ”„ํŠธ ํฌ์ปค์Šค, ์ŠคํŠœ๋””์˜ค ์กฐ๋ช… ๋“ฑ)๋ฅผ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
321
- 9. ํ”„๋กฌํ”„ํŠธ์— ๋‹ค์Œ ์š”์†Œ๋“ค์„ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•˜์„ธ์š”:
322
- - "highly detailed commercial photography"
323
- - "award-winning product photography"
324
- - "professional advertising imagery"
325
- - "studio quality"
326
- - "magazine advertisement quality"
327
- 10. ๋ฐฐ๊ฒฝ ํ™˜๊ฒฝ ์š”์†Œ๋ฅผ ์ƒํ’ˆ ์นดํ…Œ๊ณ ๋ฆฌ์— ๋งž๊ฒŒ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค:
328
- - ์Šคํ‚จ์ผ€์–ด ์ œํ’ˆ: ๊นจ๋—ํ•œ ์š•์‹ค ์„ ๋ฐ˜, ์šฐ์•„ํ•œ ํ™”์žฅ๋Œ€, ์ŠคํŒŒ ๊ฐ™์€ ํ™˜๊ฒฝ ๋“ฑ
329
- - ์Œ๋ฃŒ ์ œํ’ˆ: ์„ธ๋ จ๋œ ํ…Œ์ด๋ธ”, ํŒŒํ‹ฐ ํ™˜๊ฒฝ, ์•ผ์™ธ ํ”ผํฌ๋‹‰ ์žฅ๋ฉด ๋“ฑ
330
- - ์ „์ž ์ œํ’ˆ: ์„ธ๋ จ๋œ ์ž‘์—… ๊ณต๊ฐ„, ํ˜„๋Œ€์ ์ธ ๊ฑฐ์‹ค, ๋ฏธ๋‹ˆ๋ฉ€ํ•œ ์ฑ…์ƒ ๋“ฑ
331
- - ํŒจ์…˜/์˜๋ฅ˜: ์„ธ๋ จ๋œ ์‡ผ๋ฃธ, ๋„์‹œ ๊ฑฐ๋ฆฌ, ์—˜๋ ˆ๊ฐ•์Šคํ•œ ๋ผ์ดํ”„์Šคํƒ€์ผ ํ™˜๊ฒฝ ๋“ฑ
332
- - ์‹ํ’ˆ ์ œํ’ˆ: ๊น”๋”ํ•œ ์ฃผ๋ฐฉ, ์‹ํƒ, ์š”๋ฆฌ ํ™˜๊ฒฝ ๋“ฑ
333
- 11. ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ๊ตฌ์ฒด์ ์ธ ๋ฐฐ๊ฒฝ๊ณผ ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ์„ ์ •ํ™•ํžˆ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.
334
- 12. ํ”„๋กฌํ”„ํŠธ๋Š” ๋ฏธ๋“œ์ €๋‹ˆ AI์— ์ตœ์ ํ™”๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
335
- 13. ํ”„๋กฌํ”„ํŠธ ๋์— "--ar 1:1 --s 750 --q 2" ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฏธ๋“œ์ €๋‹ˆ์—์„œ ๊ณ ํ’ˆ์งˆ ์ •์‚ฌ๊ฐํ˜• ๋น„์œจ์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.
336
- ์ถœ๋ ฅ ํ˜•์‹์€ ์˜์–ด๋กœ ๋œ ๋‹จ์ผ ๋‹จ๋ฝ์˜ ์ƒ์„ธํ•œ ํ”„๋กฌํ”„ํŠธ์—ฌ์•ผ ํ•˜๋ฉฐ, ๋์— ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
337
- """
338
-
339
- def generate_prompt_with_gemini(product_name, background_info, additional_info=""):
340
- if not GEMINI_API_KEY:
341
- return "Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ GEMINI_API_KEY๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ์ฝ”๋“œ์— ์ง์ ‘ ์ž…๋ ฅํ•˜์„ธ์š”."
342
- try:
343
- prompt_request = f"""
344
- ์ƒํ’ˆ๋ช…: {product_name}
345
- ๋ฐฐ๊ฒฝ ์œ ํ˜•: {background_info.get('english', 'studio')}
346
- ๋ฐฐ๊ฒฝ ์นดํ…Œ๊ณ ๋ฆฌ: {background_info.get('category', '')}
347
- ๋ฐฐ๊ฒฝ ์ด๋ฆ„: {background_info.get('name', '')}
348
- ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ: {additional_info}
349
- ์ค‘์š” ์š”๊ตฌ์‚ฌํ•ญ:
350
- 1. ์ƒํ’ˆ์ด ํฌ๊ฒŒ ๋ถ€๊ฐ๋˜๊ณ  ์ด๋ฏธ์ง€์—์„œ ์ค‘์‹ฌ์ ์ธ ์œ„์น˜๋ฅผ ์ฐจ์ง€ํ•˜๋„๋ก ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
351
- 2. ์ด๋ฏธ์ง€๋Š” ์ •ํ™•ํžˆ 1:1 ๋น„์œจ(์ •์‚ฌ๊ฐํ˜•)์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
352
- 3. ์ƒํ’ˆ์€ ์ •์‚ฌ๊ฐํ˜• ํ”„๋ ˆ์ž„์˜ ์ •์ค‘์•™์— ์œ„์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
353
- 4. ์ƒํ’ˆ์˜ ๋””์ž์ธ, ์ƒ‰์ƒ, ํ˜•ํƒœ, ๋กœ๊ณ  ๋“ฑ ๋ณธ์งˆ์  ํŠน์„ฑ์€ ์ ˆ๋Œ€ ์ˆ˜์ •ํ•˜์ง€ ๋งˆ์„ธ์š”.
354
- 5. ํ™˜๊ฒฝ๊ณผ์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ํ†ตํ•ฉ์„ ์œ„ํ•œ ์กฐ๋ช… ํšจ๊ณผ์™€ ๊ทธ๋ฆผ์ž๋Š” ํฌํ•จํ•ด์ฃผ์„ธ์š”.
355
- 6. ์ƒํ’ˆ์„ ๋” ๋‹๋ณด์ด๊ฒŒ ํ•˜๋Š” ๋ฐฐ๊ฒฝ ํ™˜๊ฒฝ์„ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
356
- 7. ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ์ƒ์—… ๊ด‘๊ณ  ํ’ˆ์งˆ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋˜๋„๋ก ํ™˜๊ฒฝ ์„ค๋ช…์„ ํ•ด์ฃผ์„ธ์š”.
357
- 8. ํ”„๋กฌํ”„ํŠธ ๋์— ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ "--ar 1:1 --s 750 --q 2"๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.
358
- ํ•œ๊ตญ์–ด ์ž…๋ ฅ ๋‚ด์šฉ์„ ์˜์–ด๋กœ ์ ์ ˆํžˆ ๋ฒˆ์—ญํ•˜์—ฌ ๋ฐ˜์˜ํ•ด์ฃผ์„ธ์š”.
359
- """
360
-
361
- # google-generativeai ํŒจํ‚ค์ง€ ์‚ฌ์šฉ ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝ
362
- system_instruction = generate_system_instruction()
363
-
364
- # GenerativeModel ๋Œ€์‹  genai.chat ์‚ฌ์šฉ
365
- chat = genai.chat(
366
- model="gemini-2.0-flash",
367
- messages=[
368
- {"role": "system", "content": system_instruction},
369
- {"role": "user", "content": prompt_request}
370
- ],
371
- generation_config={
372
- "temperature": 0.7,
373
- "top_p": 0.95,
374
- "top_k": 64,
375
- "max_output_tokens": 1024,
376
- }
377
- )
378
-
379
- response_text = chat.last.text.strip()
380
-
381
- if "--ar 1:1" not in response_text:
382
- response_text = response_text.rstrip(".") + ". --ar 1:1 --s 750 --q 2"
383
-
384
- # ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ ์ œ๊ฑฐ (Gemini API์™€๋Š” ๋‹ฌ๋ฆฌ ๋ถˆํ•„์š”ํ•˜๋ฏ€๋กœ)
385
- response_text = response_text.replace(" --ar 1:1 --s 750 --q 2", "")
386
-
387
- return response_text
388
- except Exception as e:
389
- return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
390
-
391
- # ์„ ํƒ๋œ ๋ฐฐ๊ฒฝ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
392
- def get_selected_background_info(bg_type, simple, studio, nature, indoor, abstract):
393
- if bg_type == "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ":
394
- return {
395
- "category": "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ",
396
- "name": simple,
397
- "english": SIMPLE_BACKGROUNDS.get(simple, "white background")
398
- }
399
- elif bg_type == "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ":
400
- return {
401
- "category": "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ",
402
- "name": studio,
403
- "english": STUDIO_BACKGROUNDS.get(studio, "product photography studio")
404
- }
405
- elif bg_type == "์ž์—ฐ ํ™˜๊ฒฝ":
406
- return {
407
- "category": "์ž์—ฐ ํ™˜๊ฒฝ",
408
- "name": nature,
409
- "english": NATURE_BACKGROUNDS.get(nature, "natural environment")
410
- }
411
- elif bg_type == "์‹ค๋‚ด ํ™˜๊ฒฝ":
412
- return {
413
- "category": "์‹ค๋‚ด ํ™˜๊ฒฝ",
414
- "name": indoor,
415
- "english": INDOOR_BACKGROUNDS.get(indoor, "indoor environment")
416
- }
417
- elif bg_type == "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ":
418
- return {
419
- "category": "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ",
420
- "name": abstract,
421
- "english": ABSTRACT_BACKGROUNDS.get(abstract, "abstract background")
422
- }
423
- else:
424
- return {
425
- "category": "๊ธฐ๋ณธ ๋ฐฐ๊ฒฝ",
426
- "name": "ํ™”์ดํŠธ ๋ฐฐ๊ฒฝ",
427
- "english": "white background"
428
- }
429
-
430
- # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ํ•จ์ˆ˜
431
- def create_prompt(image, bg_type, simple, studio, nature, indoor, abstract, product_text, additional_text):
432
- if image is None:
433
- return "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”."
434
-
435
- product_text = product_text.strip() or "์ œํ’ˆ"
436
-
437
- # ๋ฐฐ๊ฒฝ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
438
- background_info = get_selected_background_info(bg_type, simple, studio, nature, indoor, abstract)
439
 
440
- try:
441
- prompt = generate_prompt_with_gemini(product_text, background_info, additional_text)
442
- return prompt
443
- except Exception as e:
444
- error_msg = f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
445
- return error_msg
446
-
447
-
448
- with gr.Blocks() as demo:
449
  with gr.Row():
450
- with gr.Column():
451
  # ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„น์…˜
452
- gr.Markdown("## ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ")
453
- with gr.Row():
454
- image1_input = gr.Image(type="pil", label="์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", image_mode="RGB")
455
 
456
- # ์ œํ’ˆ๋ช… ์ž…๋ ฅ ์„น์…˜
457
- gr.Markdown("## ์ œํ’ˆ ์ •๋ณด")
458
- product_name = gr.Textbox(label="์ œํ’ˆ๋ช… (ํ•œ๊ตญ์–ด ์ž…๋ ฅ)", placeholder="์˜ˆ: ์Šคํ‚จ์ผ€์–ด ํŠœ๋ธŒ, ํ…€๋ธ”๋Ÿฌ ๋“ฑ")
459
 
460
- # ๋ฐฐ๊ฒฝ ์œ ํ˜• ์„น์…˜
461
- gr.Markdown("## ๋ฐฐ๊ฒฝ ์„ค์ •")
462
- background_type = gr.Radio(
463
  choices=["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ"],
464
  label="๋ฐฐ๊ฒฝ ์œ ํ˜•",
465
  value="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ"
466
  )
467
 
468
  # ๊ฐ ๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋งž๋Š” ๋“œ๋กญ๋‹ค์šด ์ปดํฌ๋„ŒํŠธ๋“ค
469
- simple_dropdown = gr.Dropdown(
470
- choices=list(SIMPLE_BACKGROUNDS.keys()),
471
- value=list(SIMPLE_BACKGROUNDS.keys())[0] if SIMPLE_BACKGROUNDS else None,
472
- label="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ ์„ ํƒ",
473
- visible=True,
474
- interactive=True
475
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
 
477
- studio_dropdown = gr.Dropdown(
478
- choices=list(STUDIO_BACKGROUNDS.keys()),
479
- value=list(STUDIO_BACKGROUNDS.keys())[0] if STUDIO_BACKGROUNDS else None,
480
- label="์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ ์„ ํƒ",
481
- visible=False,
482
- interactive=True
483
- )
484
-
485
- nature_dropdown = gr.Dropdown(
486
- choices=list(NATURE_BACKGROUNDS.keys()),
487
- value=list(NATURE_BACKGROUNDS.keys())[0] if NATURE_BACKGROUNDS else None,
488
- label="์ž์—ฐ ํ™˜๊ฒฝ ์„ ํƒ",
489
- visible=False,
490
- interactive=True
491
- )
492
-
493
- indoor_dropdown = gr.Dropdown(
494
- choices=list(INDOOR_BACKGROUNDS.keys()),
495
- value=list(INDOOR_BACKGROUNDS.keys())[0] if INDOOR_BACKGROUNDS else None,
496
- label="์‹ค๋‚ด ํ™˜๊ฒฝ ์„ ํƒ",
497
- visible=False,
498
- interactive=True
499
- )
500
-
501
- abstract_dropdown = gr.Dropdown(
502
- choices=list(ABSTRACT_BACKGROUNDS.keys()),
503
- value=list(ABSTRACT_BACKGROUNDS.keys())[0] if ABSTRACT_BACKGROUNDS else None,
504
- label="์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ ์„ ํƒ",
505
- visible=False,
506
- interactive=True
507
- )
508
-
509
- # ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ
510
  additional_info = gr.Textbox(
511
  label="์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ (์„ ํƒ์‚ฌํ•ญ)",
512
  placeholder="์˜ˆ: ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ๋А๋‚Œ, ๋ฐ์€ ์กฐ๋ช…, ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ณด์กฐ์ ์ธ ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š” ๋“ฑ",
513
- lines=2
 
514
  )
515
 
516
- # ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ & ์ƒ์„ฑ ์„น์…˜
517
- gr.Markdown("## ํ”„๋กฌํ”„ํŠธ ์„ค์ •")
518
-
519
  generate_prompt_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ")
520
 
521
- prompt_input = gr.Textbox(
 
 
 
 
 
 
522
  lines=3,
523
- placeholder="์—ฌ๊ธฐ์— ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ˆ˜๋™์œผ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. '#1'์œผ๋กœ ์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.",
524
- label="์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ"
525
  )
526
 
527
  with gr.Row():
528
- submit_single_btn = gr.Button('์ด๋ฏธ์ง€ ์ƒ์„ฑ (1์žฅ)')
529
- submit_btn = gr.Button('์ด๋ฏธ์ง€ ์ƒ์„ฑ (4์žฅ)')
530
 
531
- with gr.Column():
532
- gr.Markdown("## ์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€")
533
  with gr.Row():
534
  with gr.Column():
535
  output_image1 = gr.Image(label="์ด๋ฏธ์ง€ #1", type="filepath")
@@ -538,9 +424,10 @@ with gr.Blocks() as demo:
538
  output_image2 = gr.Image(label="์ด๋ฏธ์ง€ #2", type="filepath")
539
  output_image4 = gr.Image(label="์ด๋ฏธ์ง€ #4", type="filepath")
540
 
 
541
  output_text = gr.Textbox(label="๊ฒฐ๊ณผ ์ •๋ณด", lines=2)
542
  prompt_display = gr.Textbox(label="์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ (์˜์–ด)", lines=2)
543
-
544
  # ๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋”ฐ๋ผ ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ ์—…๋ฐ์ดํŠธ
545
  def update_dropdowns(bg_type):
546
  return {
@@ -550,20 +437,43 @@ with gr.Blocks() as demo:
550
  indoor_dropdown: gr.update(visible=(bg_type == "์‹ค๋‚ด ํ™˜๊ฒฝ")),
551
  abstract_dropdown: gr.update(visible=(bg_type == "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ"))
552
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553
 
554
- # ๋ฐฐ๊ฒฝ ์œ ํ˜• ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
555
- background_type.change(
 
 
 
 
556
  fn=update_dropdowns,
557
- inputs=[background_type],
558
  outputs=[simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, abstract_dropdown]
559
  )
560
-
561
- # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
562
  generate_prompt_btn.click(
563
- fn=create_prompt,
564
  inputs=[
565
- image1_input,
566
- background_type,
567
  simple_dropdown,
568
  studio_dropdown,
569
  nature_dropdown,
@@ -572,22 +482,30 @@ with gr.Blocks() as demo:
572
  product_name,
573
  additional_info
574
  ],
575
- outputs=[prompt_input]
 
 
 
 
 
 
 
576
  )
577
 
578
  # ๋‹จ์ผ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
579
  submit_single_btn.click(
580
  fn=lambda image1, prompt: process_images_with_prompt(image1, prompt, 0),
581
- inputs=[image1_input, prompt_input],
582
  outputs=[output_image1, output_text, prompt_display],
583
  )
584
 
585
  # 4์žฅ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
586
  submit_btn.click(
587
  fn=generate_multiple_images,
588
- inputs=[image1_input, prompt_input],
589
  outputs=[output_image1, output_image2, output_image3, output_image4, output_text, prompt_display],
590
  )
591
 
592
- demo.queue()
593
- demo.launch()
 
 
1
  import os
2
  import tempfile
 
3
  from PIL import Image
4
  import gradio as gr
5
  import logging
6
  import re
7
  import time
8
+ import json
9
 
10
+ from google import genai
11
+ from google.genai import types
12
  from dotenv import load_dotenv
13
 
14
  load_dotenv()
 
19
 
20
  # Gemini API ํ‚ค ์„ค์ •
21
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
22
+ genai.configure(api_key=GEMINI_API_KEY)
 
 
 
23
 
24
+ # ๋ฐฐ๊ฒฝ JSON ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ •
25
  BACKGROUNDS_DIR = "./background"
26
 
27
+ # ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ
28
  if not os.path.exists(BACKGROUNDS_DIR):
29
  os.makedirs(BACKGROUNDS_DIR)
30
  logger.info(f"๋ฐฐ๊ฒฝ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค: {BACKGROUNDS_DIR}")
 
 
 
 
 
 
 
 
 
31
 
32
  # JSON ํŒŒ์ผ ๋กœ๋“œ ํ•จ์ˆ˜
33
  def load_background_json(filename):
 
39
  return data
40
  except FileNotFoundError:
41
  logger.warning(f"๊ฒฝ๊ณ : {filename} ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  return {}
43
  except json.JSONDecodeError:
44
  logger.warning(f"๊ฒฝ๊ณ : {filename} ํŒŒ์ผ์˜ JSON ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
 
54
  INDOOR_BACKGROUNDS = load_background_json("indoor_backgrounds.json")
55
  ABSTRACT_BACKGROUNDS = load_background_json("abstract_backgrounds.json")
56
 
57
+ # ๋ฐฐ๊ฒฝ์ด ๋กœ๋“œ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •
58
+ if not SIMPLE_BACKGROUNDS:
59
+ SIMPLE_BACKGROUNDS = {"ํ™”์ดํŠธ ๋ฐฐ๊ฒฝ": "white background"}
60
+ if not STUDIO_BACKGROUNDS:
61
+ STUDIO_BACKGROUNDS = {"์ œํ’ˆ ์‚ฌ์ง„ ์ŠคํŠœ๋””์˜ค": "product photography studio"}
62
+ if not NATURE_BACKGROUNDS:
63
+ NATURE_BACKGROUNDS = {"์—ด๋Œ€ ํ•ด๋ณ€": "tropical beach"}
64
+ if not INDOOR_BACKGROUNDS:
65
+ INDOOR_BACKGROUNDS = {"๋ชจ๋˜ ๋ฆฌ๋น™๋ฃธ": "modern living room"}
66
+ if not ABSTRACT_BACKGROUNDS:
67
+ ABSTRACT_BACKGROUNDS = {"๋„ค์˜จ ์กฐ๋ช…": "neon lights"}
68
+
69
+ def generate_system_instruction():
70
+ return """๋‹น์‹ ์€ ์ƒํ’ˆ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ๊ณ ํ’ˆ์งˆ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
71
+ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ƒํ’ˆ๋ช…, ๋ฐฐ๊ฒฝ ์œ ํ˜•, ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋ฏธ๋“œ์ €๋‹ˆ(Midjourney)์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”
72
+ ์ƒ์„ธํ•˜๊ณ  ์ „๋ฌธ์ ์ธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์˜์–ด๋กœ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
73
+ ๋‹ค์Œ ๊ฐ€์ด๋“œ๋ผ์ธ์„ ๋ฐ˜๋“œ์‹œ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค:
74
+ 1. ์ƒํ’ˆ์„ "#1"๋กœ ์ง€์ •ํ•˜์—ฌ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. (์˜ˆ: "skincare tube (#1)")
75
+ 2. *** ๋งค์šฐ ์ค‘์š”: ์ƒํ’ˆ์˜ ์›๋ž˜ ํŠน์„ฑ(๋””์ž์ธ, ์ƒ‰์ƒ, ํ˜•ํƒœ, ๋กœ๊ณ , ํŒจํ‚ค์ง€ ๋“ฑ)์€ ์–ด๋–ค ์ƒํ™ฉ์—์„œ๋„ ์ ˆ๋Œ€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๏ฟฝ๏ฟฝ๋‹ค. ***
76
+ 3. *** ์ƒํ’ˆ์˜ ๋ณธ์งˆ์  ํŠน์„ฑ์€ ์œ ์ง€ํ•˜๋˜, ์ž์—ฐ์Šค๋Ÿฌ์šด ํ™˜๊ฒฝ ํ†ตํ•ฉ์„ ์œ„ํ•œ ์กฐ๋ช…๊ณผ ๊ทธ๋ฆผ์ž๋Š” ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค: ***
77
+ - ์ƒํ’ˆ ์ž์ฒด์˜ ์ƒ‰์ƒ, ๋””์ž์ธ, ํ˜•ํƒœ, ํ…์Šค์ฒ˜๋Š” ์ ˆ๋Œ€ ์ˆ˜์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
78
+ - ํ™˜๊ฒฝ๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์–ด์šธ๋ฆฌ๋Š” ๊ทธ๋ฆผ์ž, ์ฃผ๋ณ€ ์กฐ๋ช… ํšจ๊ณผ๋Š” ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.
79
+ - ์ƒํ’ˆ์— ๋ฌผ๋ฐฉ์šธ, ์‘์ถ•, ๊ธˆ, ์€๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ์š”์†Œ๋‚˜ ๋ฌผ๋ฆฌ์  ํšจ๊ณผ๋Š” ์ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
80
+ - ํ™˜๊ฒฝ์— ์–ด์šธ๋ฆฌ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋น› ๋ฐ˜์‚ฌ, ์ฃผ๋ณ€ ์กฐ๋ช…, ๊ทธ๋ฆผ์ž๋Š” ์‚ฌ์‹ค์  ํ†ตํ•ฉ๊ฐ์„ ์œ„ํ•ด ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
81
+ 4. ์ด๋ฏธ์ง€ ๋น„์œจ์€ ์ •ํ™•ํžˆ 1:1(์ •์‚ฌ๊ฐํ˜•) ํ˜•์‹์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กฌํ”„ํŠธ์— "square format", "1:1 ratio" ๋˜๋Š” "aspect ratio 1:1"์„ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
82
+ 5. ์ƒํ’ˆ์€ ๋ฐ˜๋“œ์‹œ ์ •์‚ฌ๊ฐํ˜• ๊ตฌ๋„์˜ ์ •์ค‘์•™์— ๋ฐฐ์น˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
83
+ 6. ์ƒํ’ˆ์„ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ์ดˆ์ ์œผ๋กœ ๋ถ€๊ฐ์‹œํ‚ค๊ณ , ์ƒํ’ˆ์˜ ๋น„์œจ์ด ์ „์ฒด ์ด๋ฏธ์ง€์—์„œ ํฌ๊ฒŒ ์ฐจ์ง€ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
84
+ 7. ์ƒํ’ˆ ์ด๋ฏธ์ง€ ์ปท์•„์›ƒ(#1)์˜ ๊ธฐ๋ณธ ํ˜•ํƒœ์™€ ์ƒ‰์ƒ์€ ์œ ์ง€ํ•˜๋ฉด์„œ, ์„ ํƒํ•œ ํ™˜๊ฒฝ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ†ตํ•ฉ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
85
+ 8. ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ์ƒ์—…์  ์ด๋ฏธ์ง€๋ฅผ ์œ„ํ•œ ๋‹ค์Œ ํ™˜๊ฒฝ ์š”์†Œ๋“ค์„ ํฌํ•จํ•˜์„ธ์š”:
86
+ - ์ƒํ’ˆ๊ณผ ์–ด์šธ๋ฆฌ๋Š” ์ฃผ๋ณ€ ํ™˜๊ฒฝ/๋ฐฐ๊ฒฝ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ™”์žฅํ’ˆ ์ฃผ๋ณ€์— ๊ฝƒ์ด๋‚˜ ํ—ˆ๋ธŒ, ์Œ๋ฃŒ ์ œํ’ˆ ์˜†์— ๊ณผ์ผ, ์ „์ž์ œํ’ˆ ๊ทผ์ฒ˜์— ํ˜„๋Œ€์  ์†Œํ’ˆ ๋“ฑ.
87
+ - ํ™˜๊ฒฝ์˜ ์กฐ๋ช… ํšจ๊ณผ(๋ฆผ ๋ผ์ดํŠธ, ๋ฐฑ๋ผ์ดํŠธ, ์†Œํ”„ํŠธ๋ฐ•์Šค ๋“ฑ)๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
88
+ - ์ƒํ’ˆ์ด ํ™˜๊ฒฝ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์กด์žฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋„๋ก ์ ์ ˆํ•œ ๊ทธ๋ฆผ์ž์™€ ๋น› ํ‘œํ˜„์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
89
+ - ์ƒํ’ˆ์˜ ์šฉ๋„๋‚˜ ์žฅ์ ์„ ๊ฐ„์ ‘์ ์œผ๋กœ ์•”์‹œํ•˜๋Š” ๋ฐฐ๊ฒฝ ์š”์†Œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
90
+ - ํ”„๋กœํŽ˜์…”๋„ํ•œ ์ƒ์—… ์‚ฌ์ง„ ํšจ๊ณผ(์„ ํƒ์  ํ”ผ์‚ฌ๊ณ„ ์‹ฌ๋„, ์†Œํ”„ํŠธ ํฌ์ปค์Šค, ์ŠคํŠœ๋””์˜ค ์กฐ๋ช… ๋“ฑ)๋ฅผ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
91
+ 9. ํ”„๋กฌํ”„ํŠธ์— ๋‹ค์Œ ์š”์†Œ๋“ค์„ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•˜์„ธ์š”:
92
+ - "highly detailed commercial photography"
93
+ - "award-winning product photography"
94
+ - "professional advertising imagery"
95
+ - "studio quality"
96
+ - "magazine advertisement quality"
97
+ 10. ๋ฐฐ๊ฒฝ ํ™˜๊ฒฝ ์š”์†Œ๋ฅผ ์ƒํ’ˆ ์นดํ…Œ๊ณ ๋ฆฌ์— ๋งž๊ฒŒ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค:
98
+ - ์Šคํ‚จ์ผ€์–ด ์ œํ’ˆ: ๊นจ๋—ํ•œ ์š•์‹ค ์„ ๋ฐ˜, ์šฐ์•„ํ•œ ํ™”์žฅ๋Œ€, ์ŠคํŒŒ ๊ฐ™์€ ํ™˜๊ฒฝ ๋“ฑ
99
+ - ์Œ๋ฃŒ ์ œํ’ˆ: ์„ธ๋ จ๋œ ํ…Œ์ด๋ธ”, ํŒŒํ‹ฐ ํ™˜๊ฒฝ, ์•ผ์™ธ ํ”ผํฌ๋‹‰ ์žฅ๋ฉด ๋“ฑ
100
+ - ์ „์ž ์ œํ’ˆ: ์„ธ๋ จ๋œ ์ž‘์—… ๊ณต๊ฐ„, ํ˜„๋Œ€์ ์ธ ๊ฑฐ์‹ค, ๋ฏธ๋‹ˆ๋ฉ€ํ•œ ์ฑ…์ƒ ๋“ฑ
101
+ - ํŒจ์…˜/์˜๋ฅ˜: ์„ธ๋ จ๋œ ์‡ผ๋ฃธ, ๋„์‹œ ๊ฑฐ๋ฆฌ, ์—˜๋ ˆ๊ฐ•์Šคํ•œ ๋ผ์ดํ”„์Šคํƒ€์ผ ํ™˜๊ฒฝ ๋“ฑ
102
+ - ์‹ํ’ˆ ์ œํ’ˆ: ๊น”๋”ํ•œ ์ฃผ๋ฐฉ, ์‹ํƒ, ์š”๋ฆฌ ํ™˜๊ฒฝ ๋“ฑ
103
+ 11. ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ๊ตฌ์ฒด์ ์ธ ๋ฐฐ๊ฒฝ๊ณผ ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ์„ ์ •ํ™•ํžˆ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.
104
+ 12. ํ”„๋กฌํ”„ํŠธ๋Š” ๋ฏธ๋“œ์ €๋‹ˆ AI์— ์ตœ์ ํ™”๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
105
+ 13. ํ”„๋กฌํ”„ํŠธ ๋์— "--ar 1:1 --s 750 --q 2" ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฏธ๋“œ์ €๋‹ˆ์—์„œ ๊ณ ํ’ˆ์งˆ ์ •์‚ฌ๊ฐํ˜• ๋น„์œจ์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.
106
+ ์ถœ๋ ฅ ํ˜•์‹์€ ์˜์–ด๋กœ ๋œ ๋‹จ์ผ ๋‹จ๋ฝ์˜ ์ƒ์„ธํ•œ ํ”„๋กฌํ”„ํŠธ์—ฌ์•ผ ํ•˜๋ฉฐ, ๋์— ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
107
+ """
108
+
109
  def save_binary_file(file_name, data):
110
  with open(file_name, "wb") as f:
111
  f.write(data)
112
 
113
+ def generate_prompt_with_gemini(product_name, background_info, additional_info=""):
114
+ if not GEMINI_API_KEY:
115
+ return "Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ GEMINI_API_KEY๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ์ฝ”๋“œ์— ์ง์ ‘ ์ž…๋ ฅํ•˜์„ธ์š”."
 
 
 
116
  try:
117
+ prompt_request = f"""
118
+ ์ƒํ’ˆ๋ช…: {product_name}
119
+ ๋ฐฐ๊ฒฝ ์œ ํ˜•: {background_info.get('english', 'studio')}
120
+ ๋ฐฐ๊ฒฝ ์นดํ…Œ๊ณ ๋ฆฌ: {background_info.get('category', '')}
121
+ ๋ฐฐ๊ฒฝ ์ด๋ฆ„: {background_info.get('name', '')}
122
+ ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ: {additional_info}
123
+ ์ค‘์š” ์š”๊ตฌ์‚ฌํ•ญ:
124
+ 1. ์ƒํ’ˆ์ด ํฌ๊ฒŒ ๋ถ€๊ฐ๋˜๊ณ  ์ด๋ฏธ์ง€์—์„œ ์ค‘์‹ฌ์ ์ธ ์œ„์น˜๋ฅผ ์ฐจ์ง€ํ•˜๋„๋ก ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
125
+ 2. ์ด๋ฏธ์ง€๋Š” ์ •ํ™•ํžˆ 1:1 ๋น„์œจ(์ •์‚ฌ๊ฐํ˜•)์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
126
+ 3. ์ƒํ’ˆ์€ ์ •์‚ฌ๊ฐํ˜• ํ”„๋ ˆ์ž„์˜ ์ •์ค‘์•™์— ์œ„์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
127
+ 4. ์ƒํ’ˆ์˜ ๋””์ž์ธ, ์ƒ‰์ƒ, ํ˜•ํƒœ, ๋กœ๊ณ  ๋“ฑ ๋ณธ์งˆ์  ํŠน์„ฑ์€ ์ ˆ๋Œ€ ์ˆ˜์ •ํ•˜์ง€ ๋งˆ์„ธ์š”.
128
+ 5. ํ™˜๊ฒฝ๊ณผ์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ํ†ตํ•ฉ์„ ์œ„ํ•œ ์กฐ๋ช… ํšจ๊ณผ์™€ ๊ทธ๋ฆผ์ž๋Š” ํฌํ•จํ•ด์ฃผ์„ธ์š”.
129
+ 6. ์ƒํ’ˆ์„ ๋” ๋‹๋ณด์ด๊ฒŒ ํ•˜๋Š” ๋ฐฐ๊ฒฝ ํ™˜๊ฒฝ์„ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
130
+ 7. ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ์ƒ์—… ๊ด‘๊ณ  ํ’ˆ์งˆ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋˜๋„๋ก ํ™˜๊ฒฝ ์„ค๋ช…์„ ํ•ด์ฃผ์„ธ์š”.
131
+ 8. ํ”„๋กฌํ”„ํŠธ ๋์— ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ "--ar 1:1 --s 750 --q 2"๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.
132
+ ํ•œ๊ตญ์–ด ์ž…๋ ฅ ๋‚ด์šฉ์„ ์˜์–ด๋กœ ์ ์ ˆํžˆ ๋ฒˆ์—ญํ•˜์—ฌ ๋ฐ˜์˜ํ•ด์ฃผ์„ธ์š”.
133
+ """
134
+ model = genai.GenerativeModel(
135
+ 'gemini-2.0-flash',
136
+ system_instruction=generate_system_instruction()
 
 
 
 
137
  )
138
+ response = model.generate_content(
139
+ prompt_request,
140
+ generation_config=genai.types.GenerationConfig(
141
+ temperature=0.7,
142
+ top_p=0.95,
143
+ top_k=64,
144
+ max_output_tokens=1024,
145
+ )
146
+ )
147
+ response_text = response.text.strip()
148
+ if "--ar 1:1" not in response_text:
149
+ response_text = response_text.rstrip(".") + ". --ar 1:1 --s 750 --q 2"
150
 
151
+ # ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ ์ œ๊ฑฐํ•˜๊ณ  ๋ฐ˜ํ™˜ (์ด๋ฏธ์ง€ ์ƒ์„ฑ์—์„œ๋Š” ํ•„์š”์—†์Œ)
152
+ cleaned_response = re.sub(r'--ar \d+:\d+|--s \d+|--q \d+', '', response_text).strip()
153
+ return cleaned_response
 
 
 
 
 
 
 
154
  except Exception as e:
155
+ return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
 
 
 
 
 
156
 
157
+ def get_selected_background_info(bg_type, simple, studio, nature, indoor, abstract):
158
+ if bg_type == "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ":
159
+ return {
160
+ "category": "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ",
161
+ "name": simple,
162
+ "english": SIMPLE_BACKGROUNDS.get(simple, "white background")
163
+ }
164
+ elif bg_type == "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ":
165
+ return {
166
+ "category": "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ",
167
+ "name": studio,
168
+ "english": STUDIO_BACKGROUNDS.get(studio, "product photography studio")
169
+ }
170
+ elif bg_type == "์ž์—ฐ ํ™˜๊ฒฝ":
171
+ return {
172
+ "category": "์ž์—ฐ ํ™˜๊ฒฝ",
173
+ "name": nature,
174
+ "english": NATURE_BACKGROUNDS.get(nature, "natural environment")
175
+ }
176
+ elif bg_type == "์‹ค๋‚ด ํ™˜๊ฒฝ":
177
+ return {
178
+ "category": "์‹ค๋‚ด ํ™˜๊ฒฝ",
179
+ "name": indoor,
180
+ "english": INDOOR_BACKGROUNDS.get(indoor, "indoor environment")
181
+ }
182
+ elif bg_type == "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ":
183
+ return {
184
+ "category": "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ",
185
+ "name": abstract,
186
+ "english": ABSTRACT_BACKGROUNDS.get(abstract, "abstract background")
187
+ }
188
  else:
189
+ return {
190
+ "category": "๊ธฐ๋ณธ ๋ฐฐ๊ฒฝ",
191
+ "name": "ํ™”์ดํŠธ ๋ฐฐ๊ฒฝ",
192
+ "english": "white background"
193
+ }
194
 
195
  def generate_with_images(prompt, images, variation_index=0):
196
  try:
197
+ api_key = os.environ.get("GEMINI_API_KEY")
198
+ if not api_key:
199
  return None, "API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
200
 
201
+ client = genai.Client(api_key=api_key)
202
  logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt}, ๋ณ€ํ˜• ์ธ๋ฑ์Šค: {variation_index}")
203
 
204
  variation_suffixes = [
 
272
  return None, "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", ""
273
 
274
  if prompt and prompt.strip():
275
+ final_prompt = prompt
 
 
 
 
276
  else:
277
  final_prompt = "Please creatively transform this image into a more vivid and artistic version. Do not include any text or watermarks in the generated image."
278
  logger.info("Default prompt generated for single image")
 
328
 
329
  return results[0], results[1], results[2], results[3], combined_status, combined_prompts
330
 
331
+ # UI ๊ตฌ์„ฑ
332
+ with gr.Blocks(title="์ด๋ฏธ์ง€ ์ƒ์„ฑ๊ธฐ & ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ๊ธฐ") as demo:
333
+ gr.Markdown("# ์ด์ปค๋จธ์Šค ์ด๋ฏธ์ง€ ๋ณ€ํ™˜ ์ƒ์„ฑ๊ธฐ")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
 
 
 
 
 
 
 
 
 
335
  with gr.Row():
336
+ with gr.Column(scale=1):
337
  # ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„น์…˜
338
+ image_input = gr.Image(type="pil", label="์ƒํ’ˆ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", image_mode="RGB")
 
 
339
 
340
+ # ์ƒํ’ˆ๋ช… ์„น์…˜
341
+ product_name = gr.Textbox(label="์ƒํ’ˆ๋ช…", placeholder="์˜ˆ: ์Šคํ‚จ์ผ€์–ด ํŠœ๋ธŒ, ํ…€๋ธ”๋Ÿฌ ๋“ฑ", interactive=True)
 
342
 
343
+ # ๋ฐฐ๊ฒฝ ์œ ํ˜•์„ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•œ ๋ผ๋””์˜ค ๋ฒ„ํŠผ
344
+ bg_type = gr.Radio(
 
345
  choices=["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ"],
346
  label="๋ฐฐ๊ฒฝ ์œ ํ˜•",
347
  value="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ"
348
  )
349
 
350
  # ๊ฐ ๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋งž๋Š” ๋“œ๋กญ๋‹ค์šด ์ปดํฌ๋„ŒํŠธ๋“ค
351
+ with gr.Group():
352
+ simple_dropdown = gr.Dropdown(
353
+ choices=list(SIMPLE_BACKGROUNDS.keys()),
354
+ value=list(SIMPLE_BACKGROUNDS.keys())[0] if SIMPLE_BACKGROUNDS else None,
355
+ label="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ ์„ ํƒ",
356
+ visible=True,
357
+ interactive=True
358
+ )
359
+
360
+ studio_dropdown = gr.Dropdown(
361
+ choices=list(STUDIO_BACKGROUNDS.keys()),
362
+ value=list(STUDIO_BACKGROUNDS.keys())[0] if STUDIO_BACKGROUNDS else None,
363
+ label="์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ ์„ ํƒ",
364
+ visible=False,
365
+ interactive=True
366
+ )
367
+
368
+ nature_dropdown = gr.Dropdown(
369
+ choices=list(NATURE_BACKGROUNDS.keys()),
370
+ value=list(NATURE_BACKGROUNDS.keys())[0] if NATURE_BACKGROUNDS else None,
371
+ label="์ž์—ฐ ํ™˜๊ฒฝ ์„ ํƒ",
372
+ visible=False,
373
+ interactive=True
374
+ )
375
+
376
+ indoor_dropdown = gr.Dropdown(
377
+ choices=list(INDOOR_BACKGROUNDS.keys()),
378
+ value=list(INDOOR_BACKGROUNDS.keys())[0] if INDOOR_BACKGROUNDS else None,
379
+ label="์‹ค๋‚ด ํ™˜๊ฒฝ ์„ ํƒ",
380
+ visible=False,
381
+ interactive=True
382
+ )
383
+
384
+ abstract_dropdown = gr.Dropdown(
385
+ choices=list(ABSTRACT_BACKGROUNDS.keys()),
386
+ value=list(ABSTRACT_BACKGROUNDS.keys())[0] if ABSTRACT_BACKGROUNDS else None,
387
+ label="์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ ์„ ํƒ",
388
+ visible=False,
389
+ interactive=True
390
+ )
391
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  additional_info = gr.Textbox(
393
  label="์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ (์„ ํƒ์‚ฌํ•ญ)",
394
  placeholder="์˜ˆ: ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ๋А๋‚Œ, ๋ฐ์€ ์กฐ๋ช…, ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ณด์กฐ์ ์ธ ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š” ๋“ฑ",
395
+ lines=3,
396
+ interactive=True
397
  )
398
 
399
+ # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ
 
 
400
  generate_prompt_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ")
401
 
402
+ # ์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ ํ‘œ์‹œ
403
+ prompt_output = gr.Textbox(label="์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ", lines=5)
404
+
405
+ # ์ปค์Šคํ…€ ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ (์„ ํƒ์ )
406
+ custom_prompt = gr.Textbox(
407
+ label="์ปค์Šคํ…€ ํ”„๋กฌํ”„ํŠธ (์„ ํƒ์‚ฌํ•ญ)",
408
+ placeholder="์ง์ ‘ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ์œ„์—์„œ ์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค",
409
  lines=3,
410
+ interactive=True
 
411
  )
412
 
413
  with gr.Row():
414
+ submit_single_btn = gr.Button('์ด๋ฏธ์ง€ 1์žฅ ์ƒ์„ฑ')
415
+ submit_btn = gr.Button('์ด๋ฏธ์ง€ 4์žฅ ์ƒ์„ฑ')
416
 
417
+ with gr.Column(scale=1):
418
+ # ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ์„น์…˜
419
  with gr.Row():
420
  with gr.Column():
421
  output_image1 = gr.Image(label="์ด๋ฏธ์ง€ #1", type="filepath")
 
424
  output_image2 = gr.Image(label="์ด๋ฏธ์ง€ #2", type="filepath")
425
  output_image4 = gr.Image(label="์ด๋ฏธ์ง€ #4", type="filepath")
426
 
427
+ # ๊ฒฐ๊ณผ ์ •๋ณด
428
  output_text = gr.Textbox(label="๊ฒฐ๊ณผ ์ •๋ณด", lines=2)
429
  prompt_display = gr.Textbox(label="์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ (์˜์–ด)", lines=2)
430
+
431
  # ๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋”ฐ๋ผ ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ ์—…๋ฐ์ดํŠธ
432
  def update_dropdowns(bg_type):
433
  return {
 
437
  indoor_dropdown: gr.update(visible=(bg_type == "์‹ค๋‚ด ํ™˜๊ฒฝ")),
438
  abstract_dropdown: gr.update(visible=(bg_type == "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ"))
439
  }
440
+
441
+ # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ํ•จ์ˆ˜
442
+ def generate_product_prompt(image, bg_type, simple, studio, nature, indoor, abstract, product_text, additional_text):
443
+ if image is None:
444
+ return "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”."
445
+
446
+ product_text = product_text.strip() or "์ œํ’ˆ"
447
+
448
+ # ๋ฐฐ๊ฒฝ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
449
+ background_info = get_selected_background_info(bg_type, simple, studio, nature, indoor, abstract)
450
+
451
+ try:
452
+ prompt = generate_prompt_with_gemini(product_text, background_info, additional_text)
453
+
454
+ if not GEMINI_API_KEY:
455
+ return "Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ GEMINI_API_KEY๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ์ฝ”๋“œ์— ์ง์ ‘ ์ž…๋ ฅํ•˜์„ธ์š”."
456
+
457
+ return prompt
458
+ except Exception as e:
459
+ return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
460
 
461
+ # ํ”„๋กฌํ”„ํŠธ ์ถœ๋ ฅ์„ ์ปค์Šคํ…€ ํ”„๋กฌํ”„ํŠธ์— ๋ณต์‚ฌ
462
+ def copy_to_custom(prompt):
463
+ return prompt
464
+
465
+ # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
466
+ bg_type.change(
467
  fn=update_dropdowns,
468
+ inputs=[bg_type],
469
  outputs=[simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, abstract_dropdown]
470
  )
471
+
 
472
  generate_prompt_btn.click(
473
+ fn=generate_product_prompt,
474
  inputs=[
475
+ image_input,
476
+ bg_type,
477
  simple_dropdown,
478
  studio_dropdown,
479
  nature_dropdown,
 
482
  product_name,
483
  additional_info
484
  ],
485
+ outputs=prompt_output
486
+ )
487
+
488
+ # ์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ปค์Šคํ…€ ํ”„๋กฌํ”„ํŠธ ํ•„๋“œ์— ๋ณต์‚ฌ
489
+ prompt_output.change(
490
+ fn=copy_to_custom,
491
+ inputs=[prompt_output],
492
+ outputs=[custom_prompt]
493
  )
494
 
495
  # ๋‹จ์ผ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
496
  submit_single_btn.click(
497
  fn=lambda image1, prompt: process_images_with_prompt(image1, prompt, 0),
498
+ inputs=[image_input, custom_prompt],
499
  outputs=[output_image1, output_text, prompt_display],
500
  )
501
 
502
  # 4์žฅ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
503
  submit_btn.click(
504
  fn=generate_multiple_images,
505
+ inputs=[image_input, custom_prompt],
506
  outputs=[output_image1, output_image2, output_image3, output_image4, output_text, prompt_display],
507
  )
508
 
509
+ if __name__ == "__main__":
510
+ demo.queue()
511
+ demo.launch()