Kims12 commited on
Commit
e703784
ยท
verified ยท
1 Parent(s): 2a58e16

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -37
app.py CHANGED
@@ -4,7 +4,6 @@ from PIL import Image
4
  import gradio as gr
5
  import logging
6
  import re
7
- import io
8
  from io import BytesIO
9
 
10
  from google import genai
@@ -69,22 +68,22 @@ def preprocess_prompt(prompt, image1, image2, image3):
69
  has_img1 = image1 is not None
70
  has_img2 = image2 is not None
71
  has_img3 = image3 is not None
72
-
73
  if "#1" in prompt and not has_img1:
74
  prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
75
  else:
76
  prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
77
-
78
  if "#2" in prompt and not has_img2:
79
  prompt = prompt.replace("#2", "๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
80
  else:
81
  prompt = prompt.replace("#2", "๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
82
-
83
  if "#3" in prompt and not has_img3:
84
  prompt = prompt.replace("#3", "์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
85
  else:
86
  prompt = prompt.replace("#3", "์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
87
-
88
  if "1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ" in prompt:
89
  desc_match = re.search(r'#1์„ "(.*?)"์œผ๋กœ ๋ฐ”๊ฟ”๋ผ', prompt)
90
  if desc_match:
@@ -92,7 +91,7 @@ def preprocess_prompt(prompt, image1, image2, image3):
92
  prompt = f"์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ {description}์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”. ์›๋ณธ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ๋‚ด์šฉ์€ ์œ ์ง€ํ•˜๋˜ ์ƒˆ๋กœ์šด ์Šคํƒ€์ผ๊ณผ ๋ถ„์œ„๊ธฐ๋กœ ์žฌํ•ด์„ํ•ด์ฃผ์„ธ์š”."
93
  else:
94
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ๋ณ€ํ˜•ํ•ด์ฃผ์„ธ์š”. ๋” ์ƒ์ƒํ•˜๊ณ  ์˜ˆ์ˆ ์ ์ธ ๋ฒ„์ „์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
95
-
96
  elif "2. ๊ธ€์ž์ง€์šฐ๊ธฐ" in prompt:
97
  text_match = re.search(r'#1์—์„œ "(.*?)"๋ฅผ ์ง€์›Œ๋ผ', prompt)
98
  if text_match:
@@ -100,40 +99,37 @@ def preprocess_prompt(prompt, image1, image2, image3):
100
  prompt = f"์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์—์„œ '{text_to_remove}' ํ…์ŠคํŠธ๋ฅผ ์ฐพ์•„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ œ๊ฑฐํ•ด์ฃผ์„ธ์š”. ํ…์ŠคํŠธ๊ฐ€ ์žˆ๋˜ ๋ถ€๋ถ„์„ ๋ฐฐ๊ฒฝ๊ณผ ์กฐํ™”๋กญ๊ฒŒ ์ฑ„์›Œ์ฃผ์„ธ์š”."
101
  else:
102
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์—์„œ ๋ชจ๋“  ํ…์ŠคํŠธ๋ฅผ ์ฐพ์•„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ œ๊ฑฐํ•ด์ฃผ์„ธ์š”. ๊น”๋”ํ•œ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
103
-
104
  elif "4. ์˜ท๋ฐ”๊พธ๊ธฐ" in prompt:
105
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์ธ๋ฌผ ์˜์ƒ์„ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์˜์ƒ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”. ์˜์ƒ์˜ ์Šคํƒ€์ผ๊ณผ ์ƒ‰์ƒ์€ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ๋”ฐ๋ฅด๋˜, ์‹ ์ฒด ๋น„์œจ๊ณผ ํฌ์ฆˆ๋Š” ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ์œ ์ง€ํ•ด์ฃผ์„ธ์š”."
106
-
107
  elif "5. ๋ฐฐ๊ฒฝ๋ฐ”๊พธ๊ธฐ" in prompt:
108
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์„ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”. ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ํ”ผ์‚ฌ์ฒด๋Š” ์œ ์ง€ํ•˜๊ณ , ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ๊ณผ ์กฐํ™”๋กญ๊ฒŒ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”."
109
-
110
  elif "6. ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ(์ƒํ’ˆํฌํ•จ)" in prompt:
111
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์™€ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(๋˜๋Š” ์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€)๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”. ๋ชจ๋“  ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ์š”์†Œ๋ฅผ ํฌํ•จํ•˜๊ณ , ํŠนํžˆ ์ƒํ’ˆ์ด ๋‹๋ณด์ด๋„๋ก ์กฐํ™”๋กญ๊ฒŒ ํ†ตํ•ฉํ•ด์ฃผ์„ธ์š”."
112
-
113
  prompt += " ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”."
114
-
115
  return prompt
116
 
117
  def generate_with_images(prompt, images):
118
  """
119
- ๊ณต์‹ ๋ฌธ์„œ์— ๊ธฐ๋ฐ˜ํ•œ ์˜ฌ๋ฐ”๋ฅธ API ํ˜ธ์ถœ ๋ฐฉ์‹ ๊ตฌํ˜„
120
  """
121
  try:
122
  api_key = os.environ.get("GEMINI_API_KEY")
123
  if not api_key:
124
  return None, "API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
125
-
126
  client = genai.Client(api_key=api_key)
127
  logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt}")
128
-
129
- contents = []
130
- contents.append(prompt)
131
-
132
  for idx, img in enumerate(images, 1):
133
  if img is not None:
134
  contents.append(img)
135
  logger.info(f"์ด๋ฏธ์ง€ #{idx} ์ถ”๊ฐ€๋จ")
136
-
137
  response = client.models.generate_content(
138
  model="gemini-2.0-flash-exp-image-generation",
139
  contents=contents,
@@ -145,7 +141,7 @@ def generate_with_images(prompt, images):
145
  max_output_tokens=8192
146
  )
147
  )
148
-
149
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
150
  temp_path = tmp.name
151
  result_text = ""
@@ -170,16 +166,15 @@ def generate_with_images(prompt, images):
170
 
171
  def process_images_with_prompt(image1, image2, image3, prompt):
172
  """
173
- 3๊ฐœ์˜ ์ด๋ฏธ์ง€์™€ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜.
174
- ์ตœ์ข…์ ์œผ๋กœ ์˜์–ด๋กœ ๋ฒˆ์—ญ๋œ ํ”„๋กฌํ”„ํŠธ(final_prompt)๋ฅผ ์ƒ์„ฑํ•˜์—ฌ API์— ์ ์šฉํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ์™€ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
175
  """
176
  try:
177
  images = [image1, image2, image3]
178
  valid_images = [img for img in images if img is not None]
179
  if not valid_images:
180
  return None, "์ ์–ด๋„ ํ•˜๋‚˜์˜ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", ""
181
-
182
- # ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์ž…๋ ฅ๋œ ๊ฒฝ์šฐ: ์ „์ฒ˜๋ฆฌ ํ›„ ์ตœ์ข… ์˜์–ด ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ
183
  if prompt and prompt.strip():
184
  processed_prompt = preprocess_prompt(prompt, image1, image2, image3)
185
  if re.search("[๊ฐ€-ํžฃ]", processed_prompt):
@@ -187,7 +182,6 @@ def process_images_with_prompt(image1, image2, image3, prompt):
187
  else:
188
  final_prompt = processed_prompt
189
  else:
190
- # ํ”„๋กฌํ”„ํŠธ ๋ฏธ์ž…๋ ฅ ์‹œ, ์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜์— ๋”ฐ๋ฅธ ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ (์˜์–ด)
191
  if len(valid_images) == 1:
192
  final_prompt = "Please creatively transform this image into a more vivid and artistic version."
193
  logger.info("Default prompt generated for single image")
@@ -197,7 +191,7 @@ def process_images_with_prompt(image1, image2, image3, prompt):
197
  else:
198
  final_prompt = "Please creatively composite these three images, combining their main elements into a cohesive and natural scene."
199
  logger.info("Default prompt generated for three images")
200
-
201
  result_img, status = generate_with_images(final_prompt, valid_images)
202
  return result_img, status, final_prompt
203
  except Exception as e:
@@ -205,9 +199,6 @@ def process_images_with_prompt(image1, image2, image3, prompt):
205
  return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}", prompt
206
 
207
  def process_and_show_prompt(image1, image2, image3, prompt):
208
- """
209
- ์ตœ์ข…์ ์œผ๋กœ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฐ ์˜์–ด ์ตœ์ข… ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜.
210
- """
211
  try:
212
  result_img, status, final_prompt = process_images_with_prompt(image1, image2, image3, prompt)
213
  return result_img, status, final_prompt
@@ -215,13 +206,42 @@ def process_and_show_prompt(image1, image2, image3, prompt):
215
  logger.exception("์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
216
  return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}", prompt
217
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  # Gradio ์ธํ„ฐํŽ˜์ด์Šค
219
  with gr.Blocks() as demo:
220
  gr.HTML(
221
  """
222
  <div style="text-align: center; margin-bottom: 1rem;">
223
- <h1>๊ฐ„๋‹จํ•œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ๊ธฐ</h1>
224
- <p>์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ  ๋ฐ”๋กœ ์‹คํ–‰ํ•˜๋ฉด ์ž๋™์œผ๋กœ ํ•ฉ์„ฑํ•ฉ๋‹ˆ๋‹ค.</p>
225
  </div>
226
  """
227
  )
@@ -237,7 +257,6 @@ with gr.Blocks() as demo:
237
  placeholder="ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ๋น„์›Œ๋‘๋ฉด ์ž๋™ ํ•ฉ์„ฑ๋ฉ๋‹ˆ๋‹ค.",
238
  label="ํ”„๋กฌํ”„ํŠธ (์„ ํƒ ์‚ฌํ•ญ)"
239
  )
240
-
241
  with gr.Row():
242
  image_change_btn = gr.Button("์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ")
243
  text_remove_btn = gr.Button("๊ธ€์ž์ง€์šฐ๊ธฐ")
@@ -250,7 +269,7 @@ with gr.Blocks() as demo:
250
  output_text = gr.Textbox(label="์ƒํƒœ ๋ฉ”์‹œ์ง€")
251
  prompt_display = gr.Textbox(label="์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ (์˜์–ด)", visible=True)
252
 
253
- # ์„ ํƒ ์˜ต์…˜ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ๋ž€ ์—…๋ฐ์ดํŠธ (ํ•œ๊ตญ์–ด ๋ฌธ๊ตฌ ์ž…๋ ฅ)
254
  image_change_btn.click(
255
  fn=lambda: "#1 ์ด๋ฏธ์ง€์˜ [๋‹ค๋ฅธ ๋ชจ์Šต]์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ผ.",
256
  inputs=[],
@@ -282,16 +301,30 @@ with gr.Blocks() as demo:
282
  inputs=[image1_input, image2_input, image3_input, prompt_input],
283
  outputs=[output_image, output_text, prompt_display],
284
  )
285
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  gr.Markdown(
287
  """
288
  ### ์‚ฌ์šฉ ๋ฐฉ๋ฒ•:
289
 
290
- 1. **์ž๋™ ํ•ฉ์„ฑ**: ์ด๋ฏธ์ง€๋งŒ ์—…๋กœ๋“œํ•˜๊ณ  ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋น„์›Œ๋‘๋ฉด ์ž๋™์œผ๋กœ ํ•ฉ์„ฑ๋ฉ๋‹ˆ๋‹ค.
291
  2. **์ด๋ฏธ์ง€ ์ฐธ์กฐ**: #1, #2, #3์œผ๋กœ ๊ฐ ์ด๋ฏธ์ง€๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
292
- 3. **์ผ๋ถ€ ์ด๋ฏธ์ง€๋งŒ**: ํ•„์š”ํ•œ ์ด๋ฏธ์ง€๋งŒ ์—…๋กœ๋“œํ•ด๋„ ๊ธฐ๋Šฅ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
293
- 4. **์„ ํƒ ์˜ต์…˜**: ์œ„์˜ ๋งˆํฌ๋‹ค์šด ํ˜•์‹์˜ ์˜ต์…˜์—์„œ ์›ํ•˜๋Š” ํ•ญ๋ชฉ์„ ํด๋ฆญํ•˜๋ฉด ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ๋ž€์— ํ•œ๊ตญ์–ด ๋ฌธ๊ตฌ๊ฐ€ ์ฑ„์›Œ์ง€๊ณ ,
294
- ์ดํ›„ Geminiโ€‘2.0โ€‘flash ๋ชจ๋ธ์„ ํ†ตํ•ด ์˜์–ด๋กœ ๋ฒˆ์—ญ๋˜์–ด ์‹ค์ œ API ํ˜ธ์ถœ ํ”„๋กฌํ”„ํŠธ๋กœ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.
295
 
296
  > **ํŒ**: ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
297
  """
 
4
  import gradio as gr
5
  import logging
6
  import re
 
7
  from io import BytesIO
8
 
9
  from google import genai
 
68
  has_img1 = image1 is not None
69
  has_img2 = image2 is not None
70
  has_img3 = image3 is not None
71
+
72
  if "#1" in prompt and not has_img1:
73
  prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
74
  else:
75
  prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
76
+
77
  if "#2" in prompt and not has_img2:
78
  prompt = prompt.replace("#2", "๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
79
  else:
80
  prompt = prompt.replace("#2", "๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
81
+
82
  if "#3" in prompt and not has_img3:
83
  prompt = prompt.replace("#3", "์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
84
  else:
85
  prompt = prompt.replace("#3", "์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
86
+
87
  if "1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ" in prompt:
88
  desc_match = re.search(r'#1์„ "(.*?)"์œผ๋กœ ๋ฐ”๊ฟ”๋ผ', prompt)
89
  if desc_match:
 
91
  prompt = f"์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ {description}์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”. ์›๋ณธ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ๋‚ด์šฉ์€ ์œ ์ง€ํ•˜๋˜ ์ƒˆ๋กœ์šด ์Šคํƒ€์ผ๊ณผ ๋ถ„์œ„๊ธฐ๋กœ ์žฌํ•ด์„ํ•ด์ฃผ์„ธ์š”."
92
  else:
93
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ๋ณ€ํ˜•ํ•ด์ฃผ์„ธ์š”. ๋” ์ƒ์ƒํ•˜๊ณ  ์˜ˆ์ˆ ์ ์ธ ๋ฒ„์ „์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
94
+
95
  elif "2. ๊ธ€์ž์ง€์šฐ๊ธฐ" in prompt:
96
  text_match = re.search(r'#1์—์„œ "(.*?)"๋ฅผ ์ง€์›Œ๋ผ', prompt)
97
  if text_match:
 
99
  prompt = f"์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์—์„œ '{text_to_remove}' ํ…์ŠคํŠธ๋ฅผ ์ฐพ์•„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ œ๊ฑฐํ•ด์ฃผ์„ธ์š”. ํ…์ŠคํŠธ๊ฐ€ ์žˆ๋˜ ๋ถ€๋ถ„์„ ๋ฐฐ๊ฒฝ๊ณผ ์กฐํ™”๋กญ๊ฒŒ ์ฑ„์›Œ์ฃผ์„ธ์š”."
100
  else:
101
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์—์„œ ๋ชจ๋“  ํ…์ŠคํŠธ๋ฅผ ์ฐพ์•„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ œ๊ฑฐํ•ด์ฃผ์„ธ์š”. ๊น”๋”ํ•œ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
102
+
103
  elif "4. ์˜ท๋ฐ”๊พธ๊ธฐ" in prompt:
104
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์ธ๋ฌผ ์˜์ƒ์„ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์˜์ƒ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”. ์˜์ƒ์˜ ์Šคํƒ€์ผ๊ณผ ์ƒ‰์ƒ์€ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ๋”ฐ๋ฅด๋˜, ์‹ ์ฒด ๋น„์œจ๊ณผ ํฌ์ฆˆ๋Š” ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ์œ ์ง€ํ•ด์ฃผ์„ธ์š”."
105
+
106
  elif "5. ๋ฐฐ๊ฒฝ๋ฐ”๊พธ๊ธฐ" in prompt:
107
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์„ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”. ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ํ”ผ์‚ฌ์ฒด๋Š” ์œ ์ง€ํ•˜๊ณ , ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ๊ณผ ์กฐํ™”๋กญ๊ฒŒ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”."
108
+
109
  elif "6. ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ(์ƒํ’ˆํฌํ•จ)" in prompt:
110
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์™€ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(๋˜๋Š” ์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€)๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”. ๋ชจ๋“  ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ์š”์†Œ๋ฅผ ํฌํ•จํ•˜๊ณ , ํŠนํžˆ ์ƒํ’ˆ์ด ๋‹๋ณด์ด๋„๋ก ์กฐํ™”๋กญ๊ฒŒ ํ†ตํ•ฉํ•ด์ฃผ์„ธ์š”."
111
+
112
  prompt += " ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”."
 
113
  return prompt
114
 
115
  def generate_with_images(prompt, images):
116
  """
117
+ API ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
118
  """
119
  try:
120
  api_key = os.environ.get("GEMINI_API_KEY")
121
  if not api_key:
122
  return None, "API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
123
+
124
  client = genai.Client(api_key=api_key)
125
  logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt}")
126
+
127
+ contents = [prompt]
 
 
128
  for idx, img in enumerate(images, 1):
129
  if img is not None:
130
  contents.append(img)
131
  logger.info(f"์ด๋ฏธ์ง€ #{idx} ์ถ”๊ฐ€๋จ")
132
+
133
  response = client.models.generate_content(
134
  model="gemini-2.0-flash-exp-image-generation",
135
  contents=contents,
 
141
  max_output_tokens=8192
142
  )
143
  )
144
+
145
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
146
  temp_path = tmp.name
147
  result_text = ""
 
166
 
167
  def process_images_with_prompt(image1, image2, image3, prompt):
168
  """
169
+ 3๊ฐœ์˜ ์ด๋ฏธ์ง€์™€ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ตœ์ข… ์˜์–ด ํ”„๋กฌํ”„ํŠธ(final_prompt)๋ฅผ ์ƒ์„ฑํ•œ ํ›„,
170
+ API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
171
  """
172
  try:
173
  images = [image1, image2, image3]
174
  valid_images = [img for img in images if img is not None]
175
  if not valid_images:
176
  return None, "์ ์–ด๋„ ํ•˜๋‚˜์˜ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", ""
177
+
 
178
  if prompt and prompt.strip():
179
  processed_prompt = preprocess_prompt(prompt, image1, image2, image3)
180
  if re.search("[๊ฐ€-ํžฃ]", processed_prompt):
 
182
  else:
183
  final_prompt = processed_prompt
184
  else:
 
185
  if len(valid_images) == 1:
186
  final_prompt = "Please creatively transform this image into a more vivid and artistic version."
187
  logger.info("Default prompt generated for single image")
 
191
  else:
192
  final_prompt = "Please creatively composite these three images, combining their main elements into a cohesive and natural scene."
193
  logger.info("Default prompt generated for three images")
194
+
195
  result_img, status = generate_with_images(final_prompt, valid_images)
196
  return result_img, status, final_prompt
197
  except Exception as e:
 
199
  return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}", prompt
200
 
201
  def process_and_show_prompt(image1, image2, image3, prompt):
 
 
 
202
  try:
203
  result_img, status, final_prompt = process_images_with_prompt(image1, image2, image3, prompt)
204
  return result_img, status, final_prompt
 
206
  logger.exception("์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
207
  return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}", prompt
208
 
209
+ # ์˜ˆ์ œ ์‹คํ–‰ ํ•จ์ˆ˜๋“ค
210
+ def run_example_1():
211
+ """์˜ˆ์ œ 1: ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ ์˜ˆ์ œ"""
212
+ input_path = os.path.join("down", "1_in-1.png")
213
+ output_path = os.path.join("down", "1_out-1.webp")
214
+ try:
215
+ input_img = Image.open(input_path)
216
+ except Exception as e:
217
+ return None, f"์ž…๋ ฅ ์ด๋ฏธ์ง€ ์—ด๊ธฐ ์˜ค๋ฅ˜: {str(e)}", ""
218
+ prompt = "#1 ์ด๋ฏธ์ง€์˜ [์ฒญ์ƒ‰ ์ƒ์–ด๋ ˆ๊ณ ๋ฅผ ๊ฒ€์€ ๊ณ ๋ž˜๋ ˆ๊ณ ]์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ผ."
219
+ result_img, status, final_prompt = process_and_show_prompt(input_img, None, None, prompt)
220
+ if result_img is not None:
221
+ result_img.save(output_path, "WEBP")
222
+ return result_img, status, final_prompt
223
+
224
+ def run_example_2():
225
+ """์˜ˆ์ œ 2: ๊ธ€์ž์ง€์šฐ๊ธฐ ์˜ˆ์ œ"""
226
+ input_path = os.path.join("down", "2_in-1.png")
227
+ output_path = os.path.join("down", "2_out-1.webp")
228
+ try:
229
+ input_img = Image.open(input_path)
230
+ except Exception as e:
231
+ return None, f"์ž…๋ ฅ ์ด๋ฏธ์ง€ ์—ด๊ธฐ ์˜ค๋ฅ˜: {str(e)}", ""
232
+ prompt = "#1 ์ด๋ฏธ์ง€์˜ [์ค‘๊ตญ์–ด๋ฅผ ๋ชจ๋‘]๋ฅผ ์ œ๊ฑฐํ•˜๋ผ."
233
+ result_img, status, final_prompt = process_and_show_prompt(input_img, None, None, prompt)
234
+ if result_img is not None:
235
+ result_img.save(output_path, "WEBP")
236
+ return result_img, status, final_prompt
237
+
238
  # Gradio ์ธํ„ฐํŽ˜์ด์Šค
239
  with gr.Blocks() as demo:
240
  gr.HTML(
241
  """
242
  <div style="text-align: center; margin-bottom: 1rem;">
243
+ <h1>๊ฐ„๋‹จํ•œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ๊ธฐ (์˜ˆ์ œ ํฌํ•จ)</h1>
244
+ <p>์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ์•„๋ž˜ ์˜ˆ์ œ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ฒ˜๋ฆฌ๋œ ๊ฒฐ๊ณผ๊ฐ€ down ํด๋”์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.</p>
245
  </div>
246
  """
247
  )
 
257
  placeholder="ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ๋น„์›Œ๋‘๋ฉด ์ž๋™ ํ•ฉ์„ฑ๋ฉ๋‹ˆ๋‹ค.",
258
  label="ํ”„๋กฌํ”„ํŠธ (์„ ํƒ ์‚ฌํ•ญ)"
259
  )
 
260
  with gr.Row():
261
  image_change_btn = gr.Button("์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ")
262
  text_remove_btn = gr.Button("๊ธ€์ž์ง€์šฐ๊ธฐ")
 
269
  output_text = gr.Textbox(label="์ƒํƒœ ๋ฉ”์‹œ์ง€")
270
  prompt_display = gr.Textbox(label="์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ (์˜์–ด)", visible=True)
271
 
272
+ # ์„ ํƒ ์˜ต์…˜ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ๋ž€ ์—…๋ฐ์ดํŠธ (ํ•œ๊ตญ์–ด ๋ฌธ๊ตฌ)
273
  image_change_btn.click(
274
  fn=lambda: "#1 ์ด๋ฏธ์ง€์˜ [๋‹ค๋ฅธ ๋ชจ์Šต]์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ผ.",
275
  inputs=[],
 
301
  inputs=[image1_input, image2_input, image3_input, prompt_input],
302
  outputs=[output_image, output_text, prompt_display],
303
  )
304
+
305
+ with gr.Row():
306
+ example1_btn = gr.Button("์˜ˆ์ œ 1 ์‹คํ–‰")
307
+ example2_btn = gr.Button("์˜ˆ์ œ 2 ์‹คํ–‰")
308
+
309
+ example1_btn.click(
310
+ fn=run_example_1,
311
+ inputs=[],
312
+ outputs=[output_image, output_text, prompt_display]
313
+ )
314
+ example2_btn.click(
315
+ fn=run_example_2,
316
+ inputs=[],
317
+ outputs=[output_image, output_text, prompt_display]
318
+ )
319
+
320
  gr.Markdown(
321
  """
322
  ### ์‚ฌ์šฉ ๋ฐฉ๋ฒ•:
323
 
324
+ 1. **์ž๋™ ํ•ฉ์„ฑ**: ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ  ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋น„์›Œ๋‘๋ฉด ์ž๋™์œผ๋กœ ํ•ฉ์„ฑ๋ฉ๋‹ˆ๋‹ค.
325
  2. **์ด๋ฏธ์ง€ ์ฐธ์กฐ**: #1, #2, #3์œผ๋กœ ๊ฐ ์ด๋ฏธ์ง€๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
326
+ 3. **์˜ˆ์ œ ์‹คํ–‰**: ์•„๋ž˜ "์˜ˆ์ œ 1 ์‹คํ–‰" ๋˜๋Š” "์˜ˆ์ œ 2 ์‹คํ–‰" ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด down ํด๋”์˜ ์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
327
+ 4. **์„ ํƒ ์˜ต์…˜**: ์œ„์˜ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ๋ž€์— ํ•œ๊ตญ์–ด ๋ฌธ๊ตฌ๊ฐ€ ์ฑ„์›Œ์ง€๊ณ , ์ดํ›„ Geminiโ€‘2.0โ€‘flash ๋ชจ๋ธ์„ ํ†ตํ•ด ์˜์–ด๋กœ ๋ฒˆ์—ญ๋˜์–ด ์‹ค์ œ API ํ˜ธ์ถœ ํ”„๋กฌํ”„ํŠธ๋กœ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.
 
328
 
329
  > **ํŒ**: ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
330
  """