Kims12 commited on
Commit
0ae66bb
ยท
verified ยท
1 Parent(s): 9a736d4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -139
app.py CHANGED
@@ -27,14 +27,8 @@ def save_binary_file(file_name, data):
27
  logger.debug(f"ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ: {file_name}")
28
 
29
 
30
- def image_to_bytes(img_path):
31
- """ํŒŒ์ผ ๊ฒฝ๋กœ์—์„œ ์ด๋ฏธ์ง€ ๋ฐ”์ดํŠธ ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ"""
32
- with open(img_path, "rb") as f:
33
- return f.read()
34
-
35
-
36
- def merge_images(person_img_path, product_img_path, background_img_path, prompt, model="gemini-2.0-flash-exp-image-generation"):
37
- logger.debug(f"merge_images ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: '{prompt}'")
38
 
39
  try:
40
  # API ํ‚ค๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๋ถˆ๋Ÿฌ์˜ด
@@ -48,48 +42,18 @@ def merge_images(person_img_path, product_img_path, background_img_path, prompt,
48
  client = genai.Client(api_key=effective_api_key)
49
  logger.debug("Gemini ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ.")
50
 
51
- # ์ด๋ฏธ์ง€ ํŒŒ์ผ ์—…๋กœ๋“œ
52
- person_file = client.files.upload(file=person_img_path)
53
- logger.debug(f"์‚ฌ๋žŒ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์™„๋ฃŒ: {person_file.uri}")
54
-
55
- product_file = client.files.upload(file=product_img_path)
56
- logger.debug(f"์ƒํ’ˆ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์™„๋ฃŒ: {product_file.uri}")
57
 
 
 
 
 
58
  # ์ปจํ…์ธ  ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ
59
- parts = []
60
-
61
- # ์‚ฌ๋žŒ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€
62
- parts.append(
63
- types.Part.from_uri(
64
- file_uri=person_file.uri,
65
- mime_type=person_file.mime_type
66
- )
67
- )
68
-
69
- # ์ƒํ’ˆ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€
70
- parts.append(
71
- types.Part.from_uri(
72
- file_uri=product_file.uri,
73
- mime_type=product_file.mime_type
74
- )
75
- )
76
-
77
- # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์œผ๋ฉด ์ถ”๊ฐ€
78
- if background_img_path:
79
- background_file = client.files.upload(file=background_img_path)
80
- logger.debug(f"๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์™„๋ฃŒ: {background_file.uri}")
81
- parts.append(
82
- types.Part.from_uri(
83
- file_uri=background_file.uri,
84
- mime_type=background_file.mime_type
85
- )
86
- )
87
- logger.debug("๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€๋จ")
88
-
89
- # ๋งˆ์ง€๋ง‰์— ํ”„๋กฌํ”„ํŠธ ์ถ”๊ฐ€
90
- parts.append(
91
  types.Part.from_text(text=prompt)
92
- )
93
 
94
  logger.debug(f"์ปจํ…์ธ  ๊ฐ์ฒด ์ƒ์„ฑ ์™„๋ฃŒ: {len(parts)} ์•„์ดํ…œ")
95
 
@@ -152,7 +116,7 @@ def merge_images(person_img_path, product_img_path, background_img_path, prompt,
152
 
153
  if not image_saved:
154
  logger.warning("์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
155
- return None, response_text or "์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ”„๋กฌํ”„ํŠธ๋‚˜ ์ด๋ฏธ์ง€๋กœ ์‹œ๋„ํ•ด๋ณด์„ธ์š”."
156
 
157
  logger.debug("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ.")
158
  return temp_path, response_text
@@ -162,69 +126,17 @@ def merge_images(person_img_path, product_img_path, background_img_path, prompt,
162
  return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}" # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ None๊ณผ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
163
 
164
 
165
- def process_images_and_prompt(person_pil, product_pil, background_pil, prompt):
166
- logger.debug(f"process_images_and_prompt ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: '{prompt}'")
167
  try:
168
- # ํ•„์ˆ˜ ์ด๋ฏธ์ง€ ํ™•์ธ
169
- if person_pil is None:
170
- return [], "์‚ฌ๋žŒ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”."
171
- if product_pil is None:
172
- return [], "์ƒํ’ˆ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”."
173
-
174
- # ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ์„ค์ • (๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ)
175
- if not prompt or not prompt.strip():
176
- if background_pil:
177
- prompt = "์ด ๋ฐฐ๊ฒฝ์— ์ด ์‚ฌ๋žŒ์ด ์ด ์ƒํ’ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ์Šต์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณด์—ฌ์ฃผ์„ธ์š”. ์ƒํ’ˆ์„ ์ž˜ ๋ณด์ด๊ฒŒ ํ•ด์ฃผ์„ธ์š”. Create a natural composite image showing this person using this product in this background setting. Make sure the product is clearly visible."
178
- else:
179
- prompt = "์ด ์‚ฌ๋žŒ์ด ์ด ์ƒํ’ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ์Šต์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณด์—ฌ์ฃผ์„ธ์š”. ์ƒํ’ˆ์„ ์ž˜ ๋ณด์ด๊ฒŒ ํ•ด์ฃผ์„ธ์š”. Create a natural composite image showing this person using this product. Make sure the product is clearly visible."
180
 
181
- # ํ”„๋กฌํ”„ํŠธ์— ์˜์–ด๊ฐ€ ์—†์œผ๋ฉด ์˜์–ด ํ”„๋กฌํ”„ํŠธ ์ถ”๊ฐ€ (๋” ๋‚˜์€ ๊ฒฐ๊ณผ๋ฅผ ์œ„ํ•ด)
182
- if not any(ord(c) < 128 for c in prompt):
183
- if background_pil:
184
- prompt += " Create a realistic composite image of this person with this product in this background."
185
- else:
186
- prompt += " Create a realistic composite image of this person with this product."
187
-
188
- # ์ด๋ฏธ์ง€ ์ €์žฅ
189
- with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_person:
190
- person_path = tmp_person.name
191
- # RGB๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅ
192
- person_img = person_pil
193
- if person_img.mode != 'RGB':
194
- person_img = person_img.convert('RGB')
195
- person_img.save(person_path, 'JPEG')
196
- logger.debug(f"์‚ฌ๋žŒ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {person_path}")
197
-
198
- with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_product:
199
- product_path = tmp_product.name
200
- # RGB๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅ
201
- product_img = product_pil
202
- if product_img.mode != 'RGB':
203
- product_img = product_img.convert('RGB')
204
- product_img.save(product_path, 'JPEG')
205
- logger.debug(f"์ƒํ’ˆ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {product_path}")
206
-
207
- # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ €์žฅ (์žˆ๋Š” ๊ฒฝ์šฐ)
208
- background_path = None
209
- if background_pil is not None:
210
- with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_bg:
211
- background_path = tmp_bg.name
212
- # RGB๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅ
213
- background_img = background_pil
214
- if background_img.mode != 'RGB':
215
- background_img = background_img.convert('RGB')
216
- background_img.save(background_path, 'JPEG')
217
- logger.debug(f"๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {background_path}")
218
-
219
- # ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ ์‹คํ–‰
220
- result_path, response_text = merge_images(
221
- person_img_path=person_path,
222
- product_img_path=product_path,
223
- background_img_path=background_path,
224
- prompt=prompt
225
- )
226
 
227
- # ์ด๋ฏธ์ง€ ๋ฐ˜ํ™˜ ๋ฐ ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
228
  if result_path:
229
  logger.debug(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ. ๊ฒฝ๋กœ: {result_path}")
230
  try:
@@ -232,29 +144,20 @@ def process_images_and_prompt(person_pil, product_pil, background_pil, prompt):
232
  if result_img.mode == "RGBA":
233
  result_img = result_img.convert("RGB")
234
 
235
- # ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
236
- try:
237
- os.unlink(person_path)
238
- os.unlink(product_path)
239
- if background_path:
240
- os.unlink(background_path)
241
- except Exception as e:
242
- logger.warning(f"์ž„์‹œ ํŒŒ์ผ ์‚ญ์ œ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
243
-
244
  return [result_img], response_text or "์ด๋ฏธ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
245
  except Exception as e:
246
  logger.exception(f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
247
  return [], f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {str(e)}"
248
  else:
249
- logger.error("merge_images ํ•จ์ˆ˜์—์„œ None ๋ฐ˜ํ™˜๋จ.")
250
- return [], response_text or "์ด๋ฏธ์ง€ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋‚˜ ํ”„๋กฌํ”„ํŠธ๋กœ ์‹œ๋„ํ•ด๋ณด์„ธ์š”."
251
 
252
  except Exception as e:
253
- logger.exception("process_images_and_prompt ํ•จ์ˆ˜์—์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
254
  return [], f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}" # ์˜ค๋ฅ˜ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ์™€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
255
 
256
 
257
- # --- Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ ---
258
  with gr.Blocks() as demo:
259
  gr.HTML(
260
  """
@@ -263,45 +166,54 @@ with gr.Blocks() as demo:
263
  <img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" style="width: 100px; height: 100px;">
264
  </div>
265
  <div>
266
- <h1>Gemini๋ฅผ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ</h1>
267
- <p>์‚ฌ๋žŒ, ์ƒํ’ˆ, ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ํ•ฉ์„ฑํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ž…๋‹ˆ๋‹ค.</p>
268
  </div>
269
  </div>
270
  """
271
  )
272
- gr.Markdown("์‚ฌ๋žŒ ์ด๋ฏธ์ง€, ์ƒํ’ˆ ์ด๋ฏธ์ง€, ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ , ์–ด๋–ป๊ฒŒ ํ•ฉ์„ฑํ• ์ง€ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.")
273
 
274
  with gr.Row():
275
  with gr.Column():
276
- person_input = gr.Image(type="pil", label="์‚ฌ๋žŒ ์ด๋ฏธ์ง€ (ํ•„์ˆ˜)", image_mode="RGB")
277
- product_input = gr.Image(type="pil", label="์ƒํ’ˆ ์ด๋ฏธ์ง€ (ํ•„์ˆ˜)", image_mode="RGB")
 
278
  background_input = gr.Image(type="pil", label="๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ (์„ ํƒ ์‚ฌํ•ญ)", image_mode="RGB")
 
 
279
  prompt_input = gr.Textbox(
280
- lines=2,
281
- placeholder="ํ•ฉ์„ฑ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”. (์˜ˆ: '์ด ๋ฐฐ๊ฒฝ์—์„œ ์ด ์‚ฌ๋žŒ์ด ์ƒํ’ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ์Šต' ๋˜๋Š” '์ด ์‚ฌ๋žŒ์ด ์ด ์ƒํ’ˆ์„ ๋“ค๊ณ  ์ด ๋ฐฐ๊ฒฝ์— ์„œ ์žˆ๋Š” ๋ชจ์Šต')",
282
- label="ํ•ฉ์„ฑ ๋ฐฉ๋ฒ• ์„ค๋ช…"
283
  )
284
- submit_btn = gr.Button("์ด๋ฏธ์ง€ ํ•ฉ์„ฑ ์‹คํ–‰")
 
285
  with gr.Column():
286
- output_gallery = gr.Gallery(label="ํ•ฉ์„ฑ ๊ฒฐ๊ณผ")
287
  output_text = gr.Textbox(label="AI ์‘๋‹ต ํ…์ŠคํŠธ", visible=True)
288
 
289
  submit_btn.click(
290
- fn=process_images_and_prompt,
291
  inputs=[person_input, product_input, background_input, prompt_input],
292
  outputs=[output_gallery, output_text],
293
  )
294
 
295
  gr.HTML("""
296
  <div style="margin-top: 20px; padding: 10px; background-color: #f8f9fa; border-radius: 8px;">
297
- <h3>์‚ฌ์šฉ ํŒ:</h3>
298
  <ul>
299
- <li><strong>๋ฐฐ๊ฒฝ ํ™œ์šฉ:</strong> "์ด ๋ฐฐ๊ฒฝ์—์„œ ์ด ์‚ฌ๋žŒ์ด ์ด ์ƒํ’ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ชจ์Šต์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."</li>
300
- <li><strong>ํŠน์ • ์œ„์น˜ ์ง€์ •:</strong> "์ด ์‚ฌ๋žŒ์ด ์ด ์ƒํ’ˆ์„ ์†์— ๋“ค๊ณ  ์ด ๋ฐฐ๊ฒฝ ์•ž์— ์„œ ์žˆ๋Š” ๋ชจ์Šต์„ ๋ณด์—ฌ์ฃผ์„ธ์š”."</li>
301
- <li><strong>์ƒํ’ˆ ๊ฐ•์กฐ:</strong> "์ด ์‚ฌ๋žŒ์ด ์ด ๋ฐฐ๊ฒฝ์—์„œ ์ด ์ƒํ’ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ์Šต์„ ๋ณด์—ฌ์ฃผ๋˜, ์ƒํ’ˆ์ด ์ž˜ ๋ณด์ด๋„๋ก ํ•ด์ฃผ์„ธ์š”."</li>
302
- <li><strong>์žฅ๋ฉด ์„ค์ •:</strong> "์ด ์‚ฌ๋žŒ์ด ์ด ์ƒํ’ˆ์œผ๋กœ ์š”๋ฆฌํ•˜๋Š” ๋ชจ์Šต์„ ์ด ์ฃผ๋ฐฉ ๋ฐฐ๊ฒฝ์—์„œ ๋ณด์—ฌ์ฃผ์„ธ์š”."</li>
303
- <li><strong>์˜์–ด ํ”„๋กฌํ”„ํŠธ:</strong> ๋” ๋‚˜์€ ๊ฒฐ๊ณผ๋ฅผ ์œ„ํ•ด ์˜์–ด์™€ ํ•œ๊ตญ์–ด๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.</li>
304
- <li><strong>๋ฐฐ๊ฒฝ ์„ ํƒ์‚ฌํ•ญ:</strong> ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋Š” ์„ ํƒ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ๋ฐฐ๊ฒฝ ์—†์ด ์‚ฌ๋žŒ๊ณผ ์ƒํ’ˆ๋งŒ ํ•ฉ์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.</li>
 
 
 
 
 
305
  </ul>
306
  </div>
307
  """)
 
27
  logger.debug(f"ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ: {file_name}")
28
 
29
 
30
+ def generate_image_from_prompt(prompt, model="gemini-2.0-flash-exp-image-generation"):
31
+ logger.debug(f"generate_image_from_prompt ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: '{prompt}'")
 
 
 
 
 
 
32
 
33
  try:
34
  # API ํ‚ค๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๋ถˆ๋Ÿฌ์˜ด
 
42
  client = genai.Client(api_key=effective_api_key)
43
  logger.debug("Gemini ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ.")
44
 
45
+ # ํ”„๋กฌํ”„ํŠธ ์ฒ˜๋ฆฌ
46
+ if not prompt or not prompt.strip():
47
+ prompt = "A creative and visually appealing image that captures imagination. Use vibrant colors and interesting composition."
 
 
 
48
 
49
+ # ํ•œ๊ตญ์–ด ํ”„๋กฌํ”„ํŠธ์— ์˜์–ด ์„ค๋ช… ์ถ”๊ฐ€
50
+ if not any(ord(c) < 128 for c in prompt):
51
+ prompt += " Create a highly detailed, visually stunning image that captures the essence of the description."
52
+
53
  # ์ปจํ…์ธ  ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ
54
+ parts = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  types.Part.from_text(text=prompt)
56
+ ]
57
 
58
  logger.debug(f"์ปจํ…์ธ  ๊ฐ์ฒด ์ƒ์„ฑ ์™„๋ฃŒ: {len(parts)} ์•„์ดํ…œ")
59
 
 
116
 
117
  if not image_saved:
118
  logger.warning("์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
119
+ return None, response_text or "์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ”„๋กฌํ”„ํŠธ๋กœ ์‹œ๋„ํ•ด๋ณด์„ธ์š”."
120
 
121
  logger.debug("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ.")
122
  return temp_path, response_text
 
126
  return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}" # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ None๊ณผ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
127
 
128
 
129
+ def process_image_generation(person_pil, product_pil, background_pil, prompt):
130
+ logger.debug(f"process_image_generation ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: '{prompt}'")
131
  try:
132
+ # ์ด๋ฏธ์ง€๋“ค์ด ์ œ๊ณต๋˜์—ˆ๋‹ค๋ฉด ๊ธฐ์กด ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ
133
+ if person_pil is not None or product_pil is not None or background_pil is not None:
134
+ return process_images_and_prompt(person_pil, product_pil, background_pil, prompt)
 
 
 
 
 
 
 
 
 
135
 
136
+ # ์ด๋ฏธ์ง€ ์—†์ด ํ”„๋กฌํ”„ํŠธ๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ
137
+ result_path, response_text = generate_image_from_prompt(prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
+ # ์ด๋ฏธ์ง€ ๋ฐ˜ํ™˜ ๋ฐ ์ฒ˜๋ฆฌ
140
  if result_path:
141
  logger.debug(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ. ๊ฒฝ๋กœ: {result_path}")
142
  try:
 
144
  if result_img.mode == "RGBA":
145
  result_img = result_img.convert("RGB")
146
 
 
 
 
 
 
 
 
 
 
147
  return [result_img], response_text or "์ด๋ฏธ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
148
  except Exception as e:
149
  logger.exception(f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
150
  return [], f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {str(e)}"
151
  else:
152
+ logger.error("generate_image_from_prompt ํ•จ์ˆ˜์—์„œ None ๋ฐ˜ํ™˜๋จ.")
153
+ return [], response_text or "์ด๋ฏธ์ง€ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ”„๋กฌํ”„ํŠธ๋กœ ์‹œ๋„ํ•ด๋ณด์„ธ์š”."
154
 
155
  except Exception as e:
156
+ logger.exception("process_image_generation ํ•จ์ˆ˜์—์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
157
  return [], f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}" # ์˜ค๋ฅ˜ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ์™€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
158
 
159
 
160
+ # --- Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ (๊ธฐ์กด ์ฝ”๋“œ๋Š” ๋™์ผํ•˜๊ฒŒ ์œ ์ง€) ---
161
  with gr.Blocks() as demo:
162
  gr.HTML(
163
  """
 
166
  <img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" style="width: 100px; height: 100px;">
167
  </div>
168
  <div>
169
+ <h1>Gemini๋ฅผ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ</h1>
170
+ <p>์‚ฌ๋žŒ, ์ƒํ’ˆ, ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ํ•ฉ์„ฑํ•˜๊ฑฐ๋‚˜ ํ…์ŠคํŠธ๋กœ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.</p>
171
  </div>
172
  </div>
173
  """
174
  )
175
+ gr.Markdown("์‚ฌ๋žŒ ์ด๋ฏธ์ง€, ์ƒํ’ˆ ์ด๋ฏธ์ง€, ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ํ…์ŠคํŠธ๋กœ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")
176
 
177
  with gr.Row():
178
  with gr.Column():
179
+ # ์ด๋ฏธ์ง€ ์ž…๋ ฅ ์„น์…˜ (์„ ํƒ ์‚ฌํ•ญ)
180
+ person_input = gr.Image(type="pil", label="์‚ฌ๋žŒ ์ด๋ฏธ์ง€ (์„ ํƒ ์‚ฌํ•ญ)", image_mode="RGB")
181
+ product_input = gr.Image(type="pil", label="์ƒํ’ˆ ์ด๋ฏธ์ง€ (์„ ํƒ ์‚ฌํ•ญ)", image_mode="RGB")
182
  background_input = gr.Image(type="pil", label="๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ (์„ ํƒ ์‚ฌํ•ญ)", image_mode="RGB")
183
+
184
+ # ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ (ํ•„์ˆ˜)
185
  prompt_input = gr.Textbox(
186
+ lines=3,
187
+ placeholder="์ด๋ฏธ์ง€ ์ƒ์„ฑ ์„ค๋ช…์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”. ์˜ˆ: '๊ฝƒ๋ฐญ์—์„œ ํ–‡๋น›์„ ๋ฐ›์œผ๋ฉฐ ๋ฏธ์†Œ ์ง“๋Š” ์ Š์€ ์—ฌ์„ฑ', 'ํ˜„๋Œ€์ ์ธ ๊ฑฐ์‹ค์—์„œ ๊ณ ๊ธ‰ ์Šค๋งˆํŠธํฐ์„ ์‚ฌ์šฉํ•˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค๋งจ'",
188
+ label="์ด๋ฏธ์ง€ ์ƒ์„ฑ ์„ค๋ช… (ํ•„์ˆ˜)"
189
  )
190
+ submit_btn = gr.Button("์ด๋ฏธ์ง€ ์ƒ์„ฑ")
191
+
192
  with gr.Column():
193
+ output_gallery = gr.Gallery(label="์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€")
194
  output_text = gr.Textbox(label="AI ์‘๋‹ต ํ…์ŠคํŠธ", visible=True)
195
 
196
  submit_btn.click(
197
+ fn=process_image_generation,
198
  inputs=[person_input, product_input, background_input, prompt_input],
199
  outputs=[output_gallery, output_text],
200
  )
201
 
202
  gr.HTML("""
203
  <div style="margin-top: 20px; padding: 10px; background-color: #f8f9fa; border-radius: 8px;">
204
+ <h3>์‚ฌ์šฉ ๋ฐฉ๋ฒ•:</h3>
205
  <ul>
206
+ <li><strong>ํ…์ŠคํŠธ๋กœ ์ด๋ฏธ์ง€ ์ƒ์„ฑ:</strong> ์„ค๋ช…๋งŒ ์ž…๋ ฅํ•˜๊ณ  ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด์„ธ์š”.</li>
207
+ <li><strong>์ด๋ฏธ์ง€ ํ•ฉ์„ฑ:</strong> ์‚ฌ๋žŒ, ์ƒํ’ˆ, ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒ์ ์œผ๋กœ ์—…๋กœ๋“œํ•˜๊ณ  ํ•ฉ์„ฑ ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.</li>
208
+ <li><strong>ํ”„๋กฌํ”„ํŠธ ํŒ:</strong> ๊ตฌ์ฒด์ ์ด๊ณ  ์ƒ์ƒํ•œ ์„ค๋ช…์ผ์ˆ˜๋ก ๋” ์ข‹์€ ์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.</li>
209
+ <li><strong>์˜ˆ์‹œ ํ”„๋กฌํ”„ํŠธ:</strong>
210
+ <ul>
211
+ <li>ํ•œ์ ํ•œ ์นดํŽ˜์—์„œ ๋…ธํŠธ๋ถ์œผ๋กœ ์ž‘์—…ํ•˜๋Š” ํฌ๋ฆฌ์—์ดํ„ฐ</li>
212
+ <li>ํ•ด๋ณ€๊ฐ€์—์„œ ๊ณ ๊ธ‰ ์„ ๊ธ€๋ผ์Šค๋ฅผ ๋ผ๊ณ  ํฌ์ฆˆ ์ทจํ•˜๋Š” ๋ชจ๋ธ</li>
213
+ <li>ํ˜„๋Œ€์ ์ธ ์ฃผ๋ฐฉ์—์„œ ์ตœ์‹  ๋ธ”๋ Œ๋”๋กœ ์Šค๋ฌด๋””๋ฅผ ๋งŒ๋“œ๋Š” ์š”๋ฆฌ์‚ฌ</li>
214
+ </ul>
215
+ </li>
216
+ <li><strong>์–ธ์–ด ํŒ:</strong> ํ•œ๊ตญ์–ด์™€ ์˜์–ด๋ฅผ ํ˜ผํ•ฉํ•ด ์‚ฌ์šฉํ•˜๋ฉด ๋” ์ •ํ™•ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.</li>
217
  </ul>
218
  </div>
219
  """)