Kims12 commited on
Commit
25faada
ยท
verified ยท
1 Parent(s): 86b3e0e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -259
app.py CHANGED
@@ -1,24 +1,13 @@
1
  import gradio as gr
2
  import google.generativeai as genai
3
- from google.generativeai import types
4
  from PIL import Image
5
  import os
6
  import json
7
- import tempfile
8
- import logging
9
- import re
10
- import time
11
- import base64
12
- from io import BytesIO
13
-
14
- # ๋กœ๊น… ์„ค์ •
15
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
16
- logger = logging.getLogger(__name__)
17
 
18
  # Gemini API ํ‚ค ์„ค์ • (ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—์„œ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์ง์ ‘ ์ž…๋ ฅ)
19
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
20
 
21
- # Gemini API ์ดˆ๊ธฐํ™” (์•„๋ž˜ ํ•จ์ˆ˜์—์„œ ์žฌ์„ค์ •๋จ)
22
  genai.configure(api_key=GEMINI_API_KEY)
23
 
24
  # ๋ฐฐ๊ฒฝ JSON ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • - ์ƒ๋Œ€ ๊ฒฝ๋กœ ์‚ฌ์šฉ
@@ -160,7 +149,7 @@ def generate_prompt_with_gemini(product_name, background_info, additional_info="
160
  )
161
  response = model.generate_content(
162
  prompt_request,
163
- generation_config=genai.GenerationConfig(
164
  temperature=0.7,
165
  top_p=0.95,
166
  top_k=64,
@@ -174,214 +163,10 @@ def generate_prompt_with_gemini(product_name, background_info, additional_info="
174
  except Exception as e:
175
  return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
176
 
177
- # --- ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๊ด€๋ จ ํ•จ์ˆ˜๋“ค (์ˆ˜์ • ์ ์šฉ) ---
178
-
179
- def save_binary_file(file_name, data):
180
- with open(file_name, "wb") as f:
181
- f.write(data)
182
-
183
- def translate_prompt_to_english(prompt):
184
- # ๊ธฐ์กด ํ•จ์ˆ˜๋ฅผ ์ˆ˜์ •
185
- if not re.search("[๊ฐ€-ํžฃ]", prompt):
186
- return prompt
187
-
188
- prompt = prompt.replace("#1", "IMAGE_TAG_ONE")
189
-
190
- try:
191
- api_key = os.environ.get("GEMINI_API_KEY")
192
- if not api_key:
193
- logger.error("Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
194
- prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
195
- return prompt
196
-
197
- genai.configure(api_key=api_key)
198
- model = genai.GenerativeModel('gemini-2.0-flash')
199
-
200
- translation_prompt = f"""
201
- Translate the following Korean text to English:
202
-
203
- {prompt}
204
-
205
- IMPORTANT: The token IMAGE_TAG_ONE is a special tag
206
- and must be preserved exactly as is in your translation. Do not translate this token.
207
- """
208
-
209
- logger.info(f"Translation prompt: {translation_prompt}")
210
- response = model.generate_content(translation_prompt)
211
-
212
- translated_text = response.text
213
-
214
- if translated_text.strip():
215
- translated_text = translated_text.replace("IMAGE_TAG_ONE", "#1")
216
- logger.info(f"Translated text: {translated_text.strip()}")
217
- return translated_text.strip()
218
- else:
219
- logger.warning("๋ฒˆ์—ญ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์›๋ณธ ํ”„๋กฌํ”„ํŠธ ์‚ฌ์šฉ")
220
- prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
221
- return prompt
222
- except Exception as e:
223
- logger.exception("๋ฒˆ์—ญ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
224
- prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
225
- return prompt
226
-
227
- def preprocess_prompt(prompt, image1, image2, image3):
228
- has_img1 = image1 is not None
229
-
230
- if "#1" in prompt and not has_img1:
231
- prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
232
- else:
233
- prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
234
-
235
- prompt += " ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”. ์ด๋ฏธ์ง€์— ํ…์ŠคํŠธ๋‚˜ ๊ธ€์ž๋ฅผ ํฌํ•จํ•˜์ง€ ๋งˆ์„ธ์š”."
236
- return prompt
237
-
238
- # --- ์ˆ˜์ •๋œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜ ---
239
- def generate_with_images(prompt, images, variation_index=0):
240
- try:
241
- api_key = os.environ.get("GEMINI_API_KEY")
242
- if not api_key:
243
- return None, "API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
244
- genai.configure(api_key=api_key)
245
- model = genai.GenerativeModel('gemini-2.0-flash-exp-image-generation')
246
- logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt}, ๋ณ€ํ˜• ์ธ๋ฑ์Šค: {variation_index}")
247
-
248
- variation_suffixes = [
249
- " Create this as the first variation. Do not add any text, watermarks, or labels to the image.",
250
- " Create this as the second variation with more vivid colors. Do not add any text, watermarks, or labels to the image.",
251
- " Create this as the third variation with a more creative style. Do not add any text, watermarks, or labels to the image.",
252
- " Create this as the fourth variation with enhanced details. Do not add any text, watermarks, or labels to the image."
253
- ]
254
-
255
- if variation_index < len(variation_suffixes):
256
- prompt = prompt + variation_suffixes[variation_index]
257
- else:
258
- prompt = prompt + " Do not add any text, watermarks, or labels to the image."
259
-
260
- # ์ด๋ฏธ์ง€ ๊ฐ์ฒด๋ฅผ ๊ทธ๋Œ€๋กœ contents์— ์ถ”๊ฐ€ (base64 ์ธ์ฝ”๋”ฉ ์—†์ด)
261
- contents = [prompt]
262
- for idx, img in enumerate(images, 1):
263
- if img is not None:
264
- contents.append(img)
265
- logger.info(f"์ด๋ฏธ์ง€ #{idx} ์ถ”๊ฐ€๋จ")
266
-
267
- response = model.generate_content(
268
- contents,
269
- generation_config=genai.GenerationConfig(
270
- temperature=1,
271
- top_p=0.95,
272
- top_k=40,
273
- max_output_tokens=8192
274
- )
275
- )
276
- with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
277
- temp_path = tmp.name
278
- result_text = ""
279
- image_found = False
280
- for part in response.candidates[0].content.parts:
281
- if hasattr(part, 'text') and part.text:
282
- result_text += part.text
283
- logger.info(f"์‘๋‹ต ํ…์ŠคํŠธ: {part.text}")
284
- elif hasattr(part, 'inline_data') and part.inline_data:
285
- save_binary_file(temp_path, part.inline_data.data)
286
- image_found = True
287
- logger.info("์‘๋‹ต์—์„œ ์ด๋ฏธ์ง€ ์ถ”์ถœ ์„ฑ๊ณต")
288
- if not image_found:
289
- return None, f"API์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต ํ…์ŠคํŠธ: {result_text}"
290
-
291
- result_img = Image.open(temp_path)
292
- if result_img.mode == "RGBA":
293
- result_img = result_img.convert("RGB")
294
- result_img.save(temp_path, format="JPEG", quality=95)
295
-
296
- return temp_path, f"์ด๋ฏธ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. {result_text}"
297
- except Exception as e:
298
- logger.exception("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
299
- return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
300
-
301
- def process_images_with_prompt(image1, image2, image3, prompt, variation_index=0, max_retries=3):
302
- retry_count = 0
303
- last_error = None
304
-
305
- while retry_count < max_retries:
306
- try:
307
- images = [image1, image2, image3]
308
- valid_images = [img for img in images if img is not None]
309
- if not valid_images:
310
- return None, "์ ์–ด๋„ ํ•˜๋‚˜์˜ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", ""
311
-
312
- if prompt and prompt.strip():
313
- processed_prompt = preprocess_prompt(prompt, image1, image2, image3)
314
- if re.search("[๊ฐ€-ํžฃ]", processed_prompt):
315
- final_prompt = translate_prompt_to_english(processed_prompt)
316
- else:
317
- final_prompt = processed_prompt
318
- else:
319
- if len(valid_images) == 1:
320
- 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."
321
- logger.info("Default prompt generated for single image")
322
- elif len(valid_images) == 2:
323
- final_prompt = "Please seamlessly composite these two images, integrating their key elements harmoniously into a single image. Do not include any text or watermarks in the generated image."
324
- logger.info("Default prompt generated for two images")
325
- else:
326
- final_prompt = "Please creatively composite these three images, combining their main elements into a cohesive and natural scene. Do not include any text or watermarks in the generated image."
327
- logger.info("Default prompt generated for three images")
328
-
329
- result_img, status = generate_with_images(final_prompt, valid_images, variation_index)
330
- if result_img is not None:
331
- return result_img, status, final_prompt
332
- else:
333
- last_error = status
334
- retry_count += 1
335
- logger.warning(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์‹คํŒจ, ์žฌ์‹œ๋„ {retry_count}/{max_retries}: {status}")
336
- time.sleep(1)
337
- except Exception as e:
338
- last_error = str(e)
339
- retry_count += 1
340
- logger.exception(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ์žฌ์‹œ๋„ {retry_count}/{max_retries}:")
341
- time.sleep(1)
342
-
343
- return None, f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜({max_retries}ํšŒ) ์ดˆ๊ณผ ํ›„ ์‹คํŒจ: {last_error}", prompt
344
-
345
- def generate_multiple_images(image1, image2, image3, prompt, progress=gr.Progress()):
346
- results = []
347
- statuses = []
348
- prompts = []
349
-
350
- num_images = 4
351
- max_retries = 3
352
-
353
- progress(0, desc="์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค€๋น„ ์ค‘...")
354
-
355
- for i in range(num_images):
356
- progress((i / num_images), desc=f"{i+1}/{num_images} ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘...")
357
- result_img, status, final_prompt = process_images_with_prompt(image1, image2, image3, prompt, i, max_retries)
358
-
359
- if result_img is not None:
360
- results.append(result_img)
361
- statuses.append(f"์ด๋ฏธ์ง€ #{i+1}: {status}")
362
- prompts.append(f"์ด๋ฏธ์ง€ #{i+1}: {final_prompt}")
363
- else:
364
- results.append(None)
365
- statuses.append(f"์ด๋ฏธ์ง€ #{i+1} ์ƒ์„ฑ ์‹คํŒจ: {status}")
366
- prompts.append(f"์ด๋ฏธ์ง€ #{i+1}: {final_prompt}")
367
-
368
- time.sleep(1)
369
-
370
- progress(1.0, desc="์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ!")
371
-
372
- while len(results) < 4:
373
- results.append(None)
374
-
375
- combined_status = "\n".join(statuses)
376
- combined_prompts = "\n".join(prompts)
377
-
378
- return results[0], results[1], results[2], results[3], combined_status, combined_prompts
379
-
380
- # --- ์•ฑ UI ๊ตฌ์„ฑ ---
381
  def create_app():
382
- with gr.Blocks(title="์ด๋ฏธ์ง€ ์ƒ์„ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜") as demo:
383
- gr.Markdown("# ์ƒํ’ˆ ์ด๋ฏธ์ง€ ๋ฐฐ๊ฒฝ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ๊ธฐ & ์ด๋ฏธ์ง€ ์ƒ์„ฑ๊ธฐ")
384
- gr.Markdown("์ƒํ’ˆ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ  ์˜ต์…˜์„ ์„ ํƒํ•˜๋ฉด ๊ณ ํ’ˆ์งˆ ์ƒ์—…์šฉ ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.")
385
 
386
  # ์ƒํ’ˆ๋ช… ์„น์…˜
387
  with gr.Row():
@@ -453,26 +238,13 @@ def create_app():
453
  interactive=True
454
  )
455
 
456
- # ๋ฒ„ํŠผ ์˜์—ญ
457
- with gr.Row():
458
- generate_prompt_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ")
459
- submit_single_btn = gr.Button("์ด๋ฏธ์ง€ ์ƒ์„ฑ (1์žฅ)")
460
- submit_btn = gr.Button("์ด๋ฏธ์ง€ ์ƒ์„ฑ (4์žฅ)")
461
 
462
  # ์šฐ์ธก ์ปฌ๋Ÿผ - ์ถœ๋ ฅ ๊ฒฐ๊ณผ
463
  with gr.Column(scale=1):
464
  prompt_output = gr.Textbox(label="์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ", lines=10)
465
-
466
- # ์ด๋ฏธ์ง€ ์ถœ๋ ฅ ์˜์—ญ
467
- gr.Markdown("## ์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€")
468
- with gr.Row():
469
- output_image1 = gr.Image(label="์ด๋ฏธ์ง€ #1", type="pil")
470
- output_image2 = gr.Image(label="์ด๋ฏธ์ง€ #2", type="pil")
471
- with gr.Row():
472
- output_image3 = gr.Image(label="์ด๋ฏธ์ง€ #3", type="pil")
473
- output_image4 = gr.Image(label="์ด๋ฏธ์ง€ #4", type="pil")
474
-
475
- output_text = gr.Textbox(label="์ƒํƒœ ๋ฉ”์‹œ์ง€", lines=2)
476
 
477
  # ๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋”ฐ๋ผ ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ ์—…๋ฐ์ดํŠธ
478
  def update_dropdowns(bg_type):
@@ -531,9 +303,12 @@ def create_app():
531
  }
532
 
533
  # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ํ•จ์ˆ˜
534
- def generate_prompt(bg_type, simple, studio, nature, indoor, abstract, product_text, additional_text):
535
- if not product_text.strip():
536
- product_text = "์ œํ’ˆ"
 
 
 
537
 
538
  # ๋ฐฐ๊ฒฝ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
539
  background_info = get_selected_background_info(bg_type, simple, studio, nature, indoor, abstract)
@@ -550,17 +325,30 @@ API ํ‚ค ์„ค์ • ๋ฐฉ๋ฒ•:
550
  2. ์ฝ”๋“œ ๋‚ด ์ง์ ‘ ์ž…๋ ฅ: GEMINI_API_KEY = "your-api-key"
551
  ํ‚ค ๋ฐœ๊ธ‰: https://makersuite.google.com/
552
  """
 
553
 
554
- return prompt
 
 
 
 
 
 
 
 
 
 
 
555
  except Exception as e:
556
  error_msg = f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
557
  gr.Error(error_msg)
558
- return error_msg
559
 
560
  # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
561
- generate_prompt_btn.click(
562
- fn=generate_prompt,
563
  inputs=[
 
564
  background_type,
565
  simple_dropdown,
566
  studio_dropdown,
@@ -570,25 +358,15 @@ API ํ‚ค ์„ค์ • ๋ฐฉ๋ฒ•:
570
  product_name,
571
  additional_info
572
  ],
573
- outputs=prompt_output
574
- )
575
-
576
- # ๋‹จ์ผ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
577
- submit_single_btn.click(
578
- fn=lambda image, prompt: process_images_with_prompt(image, None, None, prompt, 0),
579
- inputs=[image_input, prompt_output],
580
- outputs=[output_text],
581
- )
582
-
583
- # 4์žฅ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
584
- submit_btn.click(
585
- fn=lambda image, prompt: generate_multiple_images(image, None, None, prompt),
586
- inputs=[image_input, prompt_output],
587
- outputs=[output_text],
588
  )
589
 
590
  return demo
591
 
592
  if __name__ == "__main__":
593
  app = create_app()
594
- app.launch()
 
1
  import gradio as gr
2
  import google.generativeai as genai
 
3
  from PIL import Image
4
  import os
5
  import json
 
 
 
 
 
 
 
 
 
 
6
 
7
  # Gemini API ํ‚ค ์„ค์ • (ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—์„œ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์ง์ ‘ ์ž…๋ ฅ)
8
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
9
 
10
+ # Gemini API ์ดˆ๊ธฐํ™”
11
  genai.configure(api_key=GEMINI_API_KEY)
12
 
13
  # ๋ฐฐ๊ฒฝ JSON ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • - ์ƒ๋Œ€ ๊ฒฝ๋กœ ์‚ฌ์šฉ
 
149
  )
150
  response = model.generate_content(
151
  prompt_request,
152
+ generation_config=genai.types.GenerationConfig(
153
  temperature=0.7,
154
  top_p=0.95,
155
  top_k=64,
 
163
  except Exception as e:
164
  return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  def create_app():
167
+ with gr.Blocks(title="๊ณ ๊ธ‰ ์ƒํ’ˆ ์ด๋ฏธ์ง€ ๋ฐฐ๊ฒฝ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ๊ธฐ") as demo:
168
+ gr.Markdown("# ๊ณ ๊ธ‰ ์ƒํ’ˆ ์ด๋ฏธ์ง€ ๋ฐฐ๊ฒฝ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ๊ธฐ")
169
+ gr.Markdown("์ƒํ’ˆ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ  ์˜ต์…˜์„ ์„ ํƒํ•˜๋ฉด ๊ณ ํ’ˆ์งˆ ์ƒ์—…์šฉ ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.")
170
 
171
  # ์ƒํ’ˆ๋ช… ์„น์…˜
172
  with gr.Row():
 
238
  interactive=True
239
  )
240
 
241
+ submit_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ", variant="primary")
 
 
 
 
242
 
243
  # ์šฐ์ธก ์ปฌ๋Ÿผ - ์ถœ๋ ฅ ๊ฒฐ๊ณผ
244
  with gr.Column(scale=1):
245
  prompt_output = gr.Textbox(label="์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ", lines=10)
246
+ image_preview = gr.Image(label="์—…๋กœ๋“œ๋œ ์ด๋ฏธ์ง€ (#1)", type="pil")
247
+ preview_html = gr.HTML("ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์‹œ ์—ฌ๊ธฐ์— ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.")
 
 
 
 
 
 
 
 
 
248
 
249
  # ๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋”ฐ๋ผ ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ ์—…๋ฐ์ดํŠธ
250
  def update_dropdowns(bg_type):
 
303
  }
304
 
305
  # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ํ•จ์ˆ˜
306
+ def generate_output(image, bg_type, simple, studio, nature, indoor, abstract, product_text, additional_text):
307
+ if image is None:
308
+ gr.Warning("์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
309
+ return "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", None, "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œ ํ›„ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”."
310
+
311
+ product_text = product_text.strip() or "์ œํ’ˆ"
312
 
313
  # ๋ฐฐ๊ฒฝ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
314
  background_info = get_selected_background_info(bg_type, simple, studio, nature, indoor, abstract)
 
325
  2. ์ฝ”๋“œ ๋‚ด ์ง์ ‘ ์ž…๋ ฅ: GEMINI_API_KEY = "your-api-key"
326
  ํ‚ค ๋ฐœ๊ธ‰: https://makersuite.google.com/
327
  """
328
+ return prompt, image, "API ํ‚ค๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค."
329
 
330
+ # ํ”„๋กฌํ”„ํŠธ ์š”์•ฝ HTML ์ƒ์„ฑ
331
+ preview = f"""
332
+ <div style="padding:10px; border:1px solid #ddd; border-radius:8px; margin-top:10px;">
333
+ <h3>ํ”„๋กฌํ”„ํŠธ ์š”์•ฝ</h3>
334
+ <p><strong>์ด ๊ธธ์ด:</strong> {len(prompt)} ๊ธ€์ž</p>
335
+ <p><strong>๋ฐฐ๊ฒฝ:</strong> {background_info['category']} &gt; {background_info['name']}</p>
336
+ <p><strong>์ฃผ์š” ์š”์†Œ:</strong> {", ".join([kw for kw in ["commercial photography", "product", "square format", "centered", "detailed"] if kw.lower() in prompt.lower()])}</p>
337
+ <p><strong>๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ:</strong> {" ".join([param for param in ["--ar 1:1", "--s 750", "--q 2"] if param in prompt])}</p>
338
+ </div>
339
+ """
340
+
341
+ return prompt, image, preview
342
  except Exception as e:
343
  error_msg = f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
344
  gr.Error(error_msg)
345
+ return error_msg, image, "์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."
346
 
347
  # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
348
+ submit_btn.click(
349
+ fn=generate_output,
350
  inputs=[
351
+ image_input,
352
  background_type,
353
  simple_dropdown,
354
  studio_dropdown,
 
358
  product_name,
359
  additional_info
360
  ],
361
+ outputs=[
362
+ prompt_output,
363
+ image_preview,
364
+ preview_html
365
+ ]
 
 
 
 
 
 
 
 
 
 
366
  )
367
 
368
  return demo
369
 
370
  if __name__ == "__main__":
371
  app = create_app()
372
+ app.launch()