Kims12 commited on
Commit
ba3536d
ยท
verified ยท
1 Parent(s): d86f643

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +136 -167
app.py CHANGED
@@ -18,58 +18,11 @@ load_dotenv()
18
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
19
  logger = logging.getLogger(__name__)
20
 
21
- # LLM ์„ค์ • ๋ฐ ๋ฒˆ์—ญ ํ•จ์ˆ˜
22
- def get_translation(korean_text):
23
- """
24
- ํ•œ๊ตญ์–ด ํ…์ŠคํŠธ๋ฅผ ์˜์–ด๋กœ ๋ฒˆ์—ญ
25
- """
26
- try:
27
- api_key = os.environ.get("GEMINI_API_KEY")
28
- if not api_key:
29
- logger.error("GEMINI_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
30
- return korean_text
31
-
32
- # ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
33
- client = genai.GenerativeModel(
34
- model_name="gemini-2.0-flash",
35
- generation_config={
36
- "temperature": 0.2,
37
- "max_output_tokens": 1024,
38
- "top_p": 0.9,
39
- },
40
- system_instruction="You are a professional translator who translates Korean to English accurately.",
41
- api_key=api_key
42
- )
43
-
44
- # ๋ฒˆ์—ญ ํ”„๋กฌํ”„ํŠธ
45
- translation_prompt = f"""
46
- Translate the following Korean text to English accurately:
47
-
48
- {korean_text}
49
-
50
- Provide only the translation, no explanations.
51
- """
52
-
53
- # ๋ฒˆ์—ญ ์š”์ฒญ
54
- response = client.generate_content(translation_prompt)
55
-
56
- # ์‘๋‹ต์—์„œ ํ…์ŠคํŠธ ์ถ”์ถœ
57
- if hasattr(response, 'text'):
58
- english_text = response.text.strip()
59
- logger.info(f"๋ฒˆ์—ญ ๊ฒฐ๊ณผ: {english_text}")
60
- return english_text
61
- else:
62
- logger.warning("๋ฒˆ์—ญ ์‘๋‹ต์— text ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค.")
63
- return korean_text
64
- except Exception as e:
65
- logger.exception(f"๋ฒˆ์—ญ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
66
- return korean_text # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์›๋ณธ ํ•œ๊ตญ์–ด ํ”„๋กฌํ”„ํŠธ ๋ฐ˜ํ™˜
67
-
68
  def save_binary_file(file_name, data):
69
  with open(file_name, "wb") as f:
70
  f.write(data)
71
 
72
- def preprocess_prompt(prompt, image1=None, image2=None, image3=None):
73
  """
74
  ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ธฐ๋Šฅ ๋ช…๋ น์„ ํ•ด์„
75
  """
@@ -96,9 +49,11 @@ def preprocess_prompt(prompt, image1=None, image2=None, image3=None):
96
 
97
  # ๊ธฐ๋Šฅ ๋ช…๋ น ํ•ด์„
98
  if "1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ" in prompt:
 
99
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ๋ณ€ํ˜•ํ•ด์ฃผ์„ธ์š”. ๋” ์ƒ์ƒํ•˜๊ณ  ์˜ˆ์ˆ ์ ์ธ ๋ฒ„์ „์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
100
 
101
  elif "2. ๊ธ€์ž์ง€์šฐ๊ธฐ" in prompt:
 
102
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์—์„œ ๋ชจ๋“  ํ…์ŠคํŠธ๋ฅผ ์ฐพ์•„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ œ๊ฑฐํ•ด์ฃผ์„ธ์š”. ๊น”๋”ํ•œ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
103
 
104
  elif "3. ์–ผ๊ตด๋ฐ”๊พธ๊ธฐ" in prompt:
@@ -133,13 +88,13 @@ def preprocess_prompt(prompt, image1=None, image2=None, image3=None):
133
 
134
  return prompt
135
 
136
- def generate_with_images(prompt, images):
137
  """
138
  ๊ณต์‹ ๋ฌธ์„œ์— ๊ธฐ๋ฐ˜ํ•œ ์˜ฌ๋ฐ”๋ฅธ API ํ˜ธ์ถœ ๋ฐฉ์‹ ๊ตฌํ˜„
139
- ์žฌ์‹œ๋„ ๋กœ์ง ์ถ”๊ฐ€
140
  """
141
- max_retries = 2
142
  retries = 0
 
143
 
144
  while retries <= max_retries:
145
  try:
@@ -151,18 +106,15 @@ def generate_with_images(prompt, images):
151
  # Gemini ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
152
  client = genai.Client(api_key=api_key)
153
 
154
- # ํ”„๋กฌํ”„ํŠธ ๋ฒˆ์—ญ
155
- english_prompt = get_translation(prompt)
156
- logger.info(f"์›๋ณธ ํ”„๋กฌํ”„ํŠธ: {prompt}")
157
- logger.info(f"๋ฒˆ์—ญ๋œ ํ”„๋กฌํ”„ํŠธ: {english_prompt}")
158
 
159
  # ์ปจํ…์ธ  ์ค€๋น„
160
  contents = []
161
 
162
  # ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ ์ถ”๊ฐ€
163
- contents.append(english_prompt)
164
 
165
- # ์ด๋ฏธ์ง€ ์ถ”๊ฐ€
166
  for idx, img in enumerate(images, 1):
167
  if img is not None:
168
  contents.append(img)
@@ -201,10 +153,9 @@ def generate_with_images(prompt, images):
201
  if not image_found:
202
  if retries < max_retries:
203
  retries += 1
204
- logger.warning(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์‹คํŒจ, ์žฌ์‹œ๋„ {retries}/{max_retries}")
205
  continue
206
- else:
207
- return None, f"API์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต ํ…์ŠคํŠธ: {result_text}"
208
 
209
  # ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋ฐ˜ํ™˜
210
  result_img = Image.open(temp_path)
@@ -214,31 +165,37 @@ def generate_with_images(prompt, images):
214
  return result_img, f"์ด๋ฏธ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. {result_text}"
215
 
216
  except Exception as e:
 
 
217
  if retries < max_retries:
218
  retries += 1
219
- logger.warning(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ์žฌ์‹œ๋„ {retries}/{max_retries}: {str(e)}")
220
- else:
221
- logger.exception("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
222
- return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
 
223
 
224
  def process_images_with_prompt(image1, image2, image3, prompt):
225
  """
226
  3๊ฐœ์˜ ์ด๋ฏธ์ง€์™€ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜
 
227
  """
228
  try:
229
  # ์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜ ํ™•์ธ
230
- images = [img for img in [image1, image2, image3] if img is not None]
 
231
 
232
  # ํ”„๋กฌํ”„ํŠธ ์ฒ˜๋ฆฌ
233
  if not prompt or not prompt.strip():
234
- # ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์—†์œผ๋ฉด ์—…๋กœ๋“œ๋œ ์ด๋ฏธ์ง€ ์ˆ˜์— ๋”ฐ๋ผ ์ž๋™ ํ•ฉ์„ฑ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ
235
- if len(images) == 0:
236
- prompt = "์•„๋ฆ„๋‹ค์šด ์ž์—ฐ ํ’๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”. ์‚ฐ, ํ˜ธ์ˆ˜, ํ•˜๋Š˜์ด ํฌํ•จ๋œ ํ‰ํ™”๋กœ์šด ์žฅ๋ฉด์ด๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค."
237
- logger.info("์ด๋ฏธ์ง€ ์—†์Œ, ๊ธฐ๋ณธ ์ƒ์„ฑ ํ”„๋กฌํ”„ํŠธ ์‚ฌ์šฉ")
238
- elif len(images) == 1:
 
239
  prompt = "์ด ์ด๋ฏธ์ง€๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ๋ณ€ํ˜•ํ•ด์ฃผ์„ธ์š”. ๋” ์ƒ์ƒํ•˜๊ณ  ์˜ˆ์ˆ ์ ์ธ ๋ฒ„์ „์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
240
  logger.info("๋‹จ์ผ ์ด๋ฏธ์ง€ ํ”„๋กฌํ”„ํŠธ ์ž๋™ ์ƒ์„ฑ")
241
- elif len(images) == 2:
242
  prompt = "์ด ๋‘ ์ด๋ฏธ์ง€๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”. ๋‘ ์ด๋ฏธ์ง€์˜ ์š”์†Œ๋ฅผ ์กฐํ™”๋กญ๊ฒŒ ํ†ตํ•ฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
243
  logger.info("๋‘ ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ ํ”„๋กฌํ”„ํŠธ ์ž๋™ ์ƒ์„ฑ")
244
  else:
@@ -248,18 +205,18 @@ def process_images_with_prompt(image1, image2, image3, prompt):
248
  # ํ”„๋กฌํ”„ํŠธ ์ „์ฒ˜๋ฆฌ ๋ฐ ๊ธฐ๋Šฅ ๋ช…๋ น ํ•ด์„
249
  prompt = preprocess_prompt(prompt, image1, image2, image3)
250
 
251
- # ์ด๋ฏธ์ง€ ์ƒ์„ฑ API ํ˜ธ์ถœ
252
- return generate_with_images(prompt, images)
253
 
254
  except Exception as e:
255
  logger.exception("์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
256
  return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
257
 
258
- # ๊ธฐ๋Šฅ ์„ ํƒ ์ฝœ๋ฐฑ (์ˆ˜์ •๋œ ๋ฒ„์ „)
259
  def update_prompt_from_function(function_choice):
260
  function_templates = {
261
- "1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ": "#1์„ ์ฐฝ์˜์ ์œผ๋กœ ๋ณ€ํ˜•ํ•ด์ฃผ์„ธ์š”",
262
- "2. ๊ธ€์ž์ง€์šฐ๊ธฐ": "#1์—์„œ ํ…์ŠคํŠธ๋ฅผ ์ง€์›Œ์ฃผ์„ธ์š”",
263
  "3. ์–ผ๊ตด๋ฐ”๊พธ๊ธฐ": "#1์˜ ์ธ๋ฌผ์„ #2์˜ ์–ผ๊ตด๋กœ ๋ฐ”๊ฟ”๋ผ",
264
  "4. ์˜ท๋ฐ”๊พธ๊ธฐ": "#1์˜ ์ธ๋ฌผ์— #2 ๋˜๋Š” #3์˜ ์˜ท์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ผ",
265
  "5. ๋ฐฐ๊ฒฝ๋ฐ”๊พธ๊ธฐ": "#1์˜ ์ด๋ฏธ์ง€์— #2์˜ ๋ฐฐ๊ฒฝ์œผ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐ”๊ฟ”๋ผ",
@@ -269,104 +226,116 @@ def update_prompt_from_function(function_choice):
269
 
270
  return function_templates.get(function_choice, "")
271
 
272
- # Gradio ์ธํ„ฐํŽ˜์ด์Šค (์ˆ˜์ •๋œ ๋ฒ„์ „)
273
- def create_interface():
274
- with gr.Blocks() as demo:
275
- gr.HTML(
276
- """
277
- <div style="text-align: center; margin-bottom: 1rem;">
278
- <h1>๊ฐ„๋‹จํ•œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ๊ธฐ</h1>
279
- <p>์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ํ”„๋กฌํ”„ํŠธ๋งŒ ์ž…๋ ฅํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.</p>
280
- </div>
281
- """
282
- )
283
-
284
- with gr.Row():
285
- with gr.Column():
286
- # 3๊ฐœ์˜ ์ด๋ฏธ์ง€ ์ž…๋ ฅ
287
- with gr.Row():
288
- image1_input = gr.Image(type="pil", label="#1 (์„ ํƒ์‚ฌํ•ญ)", image_mode="RGB")
289
- image2_input = gr.Image(type="pil", label="#2 (์„ ํƒ์‚ฌํ•ญ)", image_mode="RGB")
290
- image3_input = gr.Image(type="pil", label="#3 (์„ ํƒ์‚ฌํ•ญ)", image_mode="RGB")
291
-
292
- # ๊ธฐ๋Šฅ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด
293
- with gr.Row():
294
- function_dropdown = gr.Dropdown(
295
- choices=[
296
- "1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ",
297
- "2. ๊ธ€์ž์ง€์šฐ๊ธฐ",
298
- "3. ์–ผ๊ตด๋ฐ”๊พธ๊ธฐ",
299
- "4. ์˜ท๋ฐ”๊พธ๊ธฐ",
300
- "5. ๋ฐฐ๊ฒฝ๋ฐ”๊พธ๊ธฐ",
301
- "6. ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ(์ƒํ’ˆํฌํ•จ)",
302
- "7. ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ(์Šคํƒ€์ผ์ ์šฉ)"
303
- ],
304
- label="๊ธฐ๋Šฅ ์„ ํƒ (์„ ํƒํ•˜๋ฉด ์ž๋™์œผ๋กœ ํ”„๋กฌํ”„ํŠธ๊ฐ€ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค)",
305
- value=None
306
- )
307
-
308
- # ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ
309
- prompt_input = gr.Textbox(
310
- lines=3,
311
- placeholder="ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ๋น„์›Œ๋‘๋ฉด ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ํ•œ๊ตญ์–ด๋กœ ์ž…๋ ฅํ•˜์„ธ์š”.",
312
- label="ํ”„๋กฌํ”„ํŠธ"
313
- )
314
-
315
- # ์ƒ์„ฑ ๋ฒ„ํŠผ
316
- submit_btn = gr.Button("์ด๋ฏธ์ง€ ์ƒ์„ฑ", variant="primary")
317
 
318
- with gr.Column():
319
- # ๊ฒฐ๊ณผ ์ถœ๋ ฅ
320
- output_image = gr.Image(label="์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€")
321
- output_text = gr.Textbox(label="์ƒํƒœ ๋ฉ”์‹œ์ง€")
322
-
323
- # ์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ ํ‘œ์‹œ
324
- prompt_display = gr.Textbox(label="์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ", visible=True)
325
-
326
- # ๊ธฐ๋Šฅ ์„ ํƒ ์ด๋ฒคํŠธ (์„ ํƒ๋งŒ์œผ๋กœ ํ”„๋กฌํ”„ํŠธ ๋ณ€๊ฒฝ)
327
- function_dropdown.change(
328
- fn=update_prompt_from_function,
329
- inputs=[function_dropdown],
330
- outputs=[prompt_input]
331
- )
 
 
 
 
 
 
 
 
 
 
332
 
333
- # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
334
- def process_and_show_prompt(image1, image2, image3, prompt):
335
- try:
336
- # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜ ํ˜ธ์ถœ
337
- result_img, status = process_images_with_prompt(image1, image2, image3, prompt)
338
-
339
- # ํ”„๋กฌํ”„ํŠธ ์ „์ฒ˜๋ฆฌ
340
- processed_prompt = preprocess_prompt(prompt, image1, image2, image3)
341
-
342
- return result_img, status, processed_prompt
343
- except Exception as e:
344
- logger.exception("์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
345
- return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}", prompt
 
 
 
 
 
 
 
346
 
347
- submit_btn.click(
348
- fn=process_and_show_prompt,
349
- inputs=[image1_input, image2_input, image3_input, prompt_input],
350
- outputs=[output_image, output_text, prompt_display],
351
- )
352
-
353
- gr.Markdown(
354
- """
355
- ### ์‚ฌ์šฉ ๋ฐฉ๋ฒ•:
 
 
 
 
 
 
356
 
357
- 1. **์ด๋ฏธ์ง€ ์—†์ด ์ƒ์„ฑ**: ํ”„๋กฌํ”„ํŠธ๋งŒ ์ž…๋ ฅํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
358
- 2. **์ž๋™ ํ•ฉ์„ฑ**: ์ด๋ฏธ์ง€๋งŒ ์—…๋กœ๋“œํ•˜๊ณ  ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋น„์›Œ๋‘๋ฉด ์ž๋™์œผ๋กœ ํ•ฉ์„ฑ๋ฉ๋‹ˆ๋‹ค
359
- 3. **๊ธฐ๋Šฅ ์‚ฌ์šฉ**: ๋“œ๋กญ๋‹ค์šด์—์„œ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์„ ํƒํ•˜๋ฉด ์ž๋™์œผ๋กœ ํ”„๋กฌํ”„ํŠธ๊ฐ€ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค
360
- 4. **์ด๋ฏธ์ง€ ์ฐธ์กฐ**: #1, #2, #3์œผ๋กœ ๊ฐ ์ด๋ฏธ์ง€๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
361
- 5. **์ผ๋ถ€ ์ด๋ฏธ์ง€๋งŒ**: ํ•„์š”ํ•œ ์ด๋ฏธ์ง€๋งŒ ์—…๋กœ๋“œํ•ด๋„ ๊ธฐ๋Šฅ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
362
 
363
- > **ํŒ**: ํ•œ๊ตญ์–ด๋กœ ์ž…๋ ฅํ•œ ํ”„๋กฌํ”„ํŠธ๋Š” ์ž๋™์œผ๋กœ ์˜์–ด๋กœ ๋ฒˆ์—ญ๋˜์–ด ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค
364
- """
365
- )
 
366
 
367
- return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
 
369
  # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰
370
  if __name__ == "__main__":
371
- demo = create_interface()
372
  demo.launch(share=True)
 
18
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
19
  logger = logging.getLogger(__name__)
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  def save_binary_file(file_name, data):
22
  with open(file_name, "wb") as f:
23
  f.write(data)
24
 
25
+ def preprocess_prompt(prompt, image1, image2, image3):
26
  """
27
  ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ธฐ๋Šฅ ๋ช…๋ น์„ ํ•ด์„
28
  """
 
49
 
50
  # ๊ธฐ๋Šฅ ๋ช…๋ น ํ•ด์„
51
  if "1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ" in prompt:
52
+ # ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ์ œ๊ณต
53
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ๋ณ€ํ˜•ํ•ด์ฃผ์„ธ์š”. ๋” ์ƒ์ƒํ•˜๊ณ  ์˜ˆ์ˆ ์ ์ธ ๋ฒ„์ „์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
54
 
55
  elif "2. ๊ธ€์ž์ง€์šฐ๊ธฐ" in prompt:
56
+ # ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ์ œ๊ณต
57
  prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์—์„œ ๋ชจ๋“  ํ…์ŠคํŠธ๋ฅผ ์ฐพ์•„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ œ๊ฑฐํ•ด์ฃผ์„ธ์š”. ๊น”๋”ํ•œ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
58
 
59
  elif "3. ์–ผ๊ตด๋ฐ”๊พธ๊ธฐ" in prompt:
 
88
 
89
  return prompt
90
 
91
+ def generate_with_images(prompt, images, max_retries=2):
92
  """
93
  ๊ณต์‹ ๋ฌธ์„œ์— ๊ธฐ๋ฐ˜ํ•œ ์˜ฌ๋ฐ”๋ฅธ API ํ˜ธ์ถœ ๋ฐฉ์‹ ๊ตฌํ˜„
94
+ ์‹คํŒจ ์‹œ ์žฌ์‹œ๋„ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
95
  """
 
96
  retries = 0
97
+ last_error = None
98
 
99
  while retries <= max_retries:
100
  try:
 
106
  # Gemini ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
107
  client = genai.Client(api_key=api_key)
108
 
109
+ logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt} (์‹œ๋„: {retries+1}/{max_retries+1})")
 
 
 
110
 
111
  # ์ปจํ…์ธ  ์ค€๋น„
112
  contents = []
113
 
114
  # ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ ์ถ”๊ฐ€
115
+ contents.append(prompt)
116
 
117
+ # ์ด๋ฏธ์ง€ ์ถ”๊ฐ€ (์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ๋งŒ)
118
  for idx, img in enumerate(images, 1):
119
  if img is not None:
120
  contents.append(img)
 
153
  if not image_found:
154
  if retries < max_retries:
155
  retries += 1
156
+ logger.warning(f"API์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์žฌ์‹œ๋„ ์ค‘... ({retries}/{max_retries})")
157
  continue
158
+ return None, f"API์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต ํ…์ŠคํŠธ: {result_text}"
 
159
 
160
  # ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋ฐ˜ํ™˜
161
  result_img = Image.open(temp_path)
 
165
  return result_img, f"์ด๋ฏธ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. {result_text}"
166
 
167
  except Exception as e:
168
+ last_error = str(e)
169
+ logger.exception(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ (์‹œ๋„: {retries+1}/{max_retries+1}):")
170
  if retries < max_retries:
171
  retries += 1
172
+ logger.info(f"์žฌ์‹œ๋„ ์ค‘... ({retries}/{max_retries})")
173
+ continue
174
+ return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {last_error}"
175
+
176
+ return None, f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ ์ดˆ๊ณผ. ๋งˆ์ง€๋ง‰ ์˜ค๋ฅ˜: {last_error}"
177
 
178
  def process_images_with_prompt(image1, image2, image3, prompt):
179
  """
180
  3๊ฐœ์˜ ์ด๋ฏธ์ง€์™€ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜
181
+ ์ด๋ฏธ์ง€ ์—†์ด ํ”„๋กฌํ”„ํŠธ๋งŒ์œผ๋กœ๋„ ๋™์ž‘
182
  """
183
  try:
184
  # ์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜ ํ™•์ธ
185
+ images = [image1, image2, image3]
186
+ valid_images = [img for img in images if img is not None]
187
 
188
  # ํ”„๋กฌํ”„ํŠธ ์ฒ˜๋ฆฌ
189
  if not prompt or not prompt.strip():
190
+ # ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ
191
+ if not valid_images:
192
+ # ์ด๋ฏธ์ง€๋„ ์—†๊ณ  ํ”„๋กฌํ”„ํŠธ๋„ ์—†๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ์‚ฌ์šฉ
193
+ prompt = "์•„๋ฆ„๋‹ค์šด ํ’๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”. ํ‘ธ๋ฅธ ํ•˜๋Š˜, ์ดˆ๋ก์ƒ‰ ์–ธ๋•, ๊ทธ๋ฆฌ๊ณ  ๋ง‘์€ ํ˜ธ์ˆ˜๊ฐ€ ์žˆ๋Š” ํ‰ํ™”๋กœ์šด ์ž์—ฐ ํ’๊ฒฝ์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
194
+ logger.info("์ด๋ฏธ์ง€์™€ ํ”„๋กฌํ”„ํŠธ ๋ชจ๋‘ ์—†์Œ. ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ")
195
+ elif len(valid_images) == 1:
196
  prompt = "์ด ์ด๋ฏธ์ง€๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ๋ณ€ํ˜•ํ•ด์ฃผ์„ธ์š”. ๋” ์ƒ์ƒํ•˜๊ณ  ์˜ˆ์ˆ ์ ์ธ ๋ฒ„์ „์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
197
  logger.info("๋‹จ์ผ ์ด๋ฏธ์ง€ ํ”„๋กฌํ”„ํŠธ ์ž๋™ ์ƒ์„ฑ")
198
+ elif len(valid_images) == 2:
199
  prompt = "์ด ๋‘ ์ด๋ฏธ์ง€๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”. ๋‘ ์ด๋ฏธ์ง€์˜ ์š”์†Œ๋ฅผ ์กฐํ™”๋กญ๊ฒŒ ํ†ตํ•ฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
200
  logger.info("๋‘ ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ ํ”„๋กฌํ”„ํŠธ ์ž๋™ ์ƒ์„ฑ")
201
  else:
 
205
  # ํ”„๋กฌํ”„ํŠธ ์ „์ฒ˜๋ฆฌ ๋ฐ ๊ธฐ๋Šฅ ๋ช…๋ น ํ•ด์„
206
  prompt = preprocess_prompt(prompt, image1, image2, image3)
207
 
208
+ # ์ƒˆ๋กœ์šด API ํ˜ธ์ถœ ๋ฐฉ์‹ ์‚ฌ์šฉ (์žฌ์‹œ๋„ ๊ธฐ๋Šฅ ํฌํ•จ)
209
+ return generate_with_images(prompt, valid_images)
210
 
211
  except Exception as e:
212
  logger.exception("์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
213
  return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
214
 
215
+ # ๊ธฐ๋Šฅ ์„ ํƒ ์ฝœ๋ฐฑ (์ˆ˜์ •๋จ)
216
  def update_prompt_from_function(function_choice):
217
  function_templates = {
218
+ "1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ": "#1์„ ์ฐฝ์˜์ ์œผ๋กœ ๋ฐ”๊ฟ”๋ผ",
219
+ "2. ๊ธ€์ž์ง€์šฐ๊ธฐ": "#1์—์„œ ํ…์ŠคํŠธ๋ฅผ ์ง€์›Œ๋ผ",
220
  "3. ์–ผ๊ตด๋ฐ”๊พธ๊ธฐ": "#1์˜ ์ธ๋ฌผ์„ #2์˜ ์–ผ๊ตด๋กœ ๋ฐ”๊ฟ”๋ผ",
221
  "4. ์˜ท๋ฐ”๊พธ๊ธฐ": "#1์˜ ์ธ๋ฌผ์— #2 ๋˜๋Š” #3์˜ ์˜ท์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ผ",
222
  "5. ๋ฐฐ๊ฒฝ๋ฐ”๊พธ๊ธฐ": "#1์˜ ์ด๋ฏธ์ง€์— #2์˜ ๋ฐฐ๊ฒฝ์œผ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐ”๊ฟ”๋ผ",
 
226
 
227
  return function_templates.get(function_choice, "")
228
 
229
+ # Gradio ์ธํ„ฐํŽ˜์ด์Šค (์ˆ˜์ •๋จ)
230
+ with gr.Blocks() as demo:
231
+ gr.HTML(
232
+ """
233
+ <div style="text-align: center; margin-bottom: 1rem;">
234
+ <h1>๊ฐ„๋‹จํ•œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ๊ธฐ</h1>
235
+ <p>์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”. ๋‘˜ ๋‹ค ์—†์–ด๋„ ๊ธฐ๋ณธ ์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.</p>
236
+ </div>
237
+ """
238
+ )
239
+
240
+ with gr.Row():
241
+ with gr.Column():
242
+ # 3๊ฐœ์˜ ์ด๋ฏธ์ง€ ์ž…๋ ฅ
243
+ with gr.Row():
244
+ image1_input = gr.Image(type="pil", label="#1", image_mode="RGB")
245
+ image2_input = gr.Image(type="pil", label="#2", image_mode="RGB")
246
+ image3_input = gr.Image(type="pil", label="#3", image_mode="RGB")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
 
248
+ # ๊ธฐ๋Šฅ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด (์ปค์Šคํ…€ ํ…์ŠคํŠธ ์ž…๋ ฅ ์ œ๊ฑฐ)
249
+ function_dropdown = gr.Dropdown(
250
+ choices=[
251
+ "1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ",
252
+ "2. ๊ธ€์ž์ง€์šฐ๊ธฐ",
253
+ "3. ์–ผ๊ตด๋ฐ”๊พธ๊ธฐ",
254
+ "4. ์˜ท๋ฐ”๊พธ๊ธฐ",
255
+ "5. ๋ฐฐ๊ฒฝ๋ฐ”๊พธ๊ธฐ",
256
+ "6. ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ(์ƒํ’ˆํฌํ•จ)",
257
+ "7. ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ(์Šคํƒ€์ผ์ ์šฉ)"
258
+ ],
259
+ label="๊ธฐ๋Šฅ ์„ ํƒ",
260
+ value=None
261
+ )
262
+
263
+ # ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ (์„ ํƒ ์‚ฌํ•ญ)
264
+ prompt_input = gr.Textbox(
265
+ lines=3,
266
+ placeholder="ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ๋น„์›Œ๋‘๋ฉด ์ž๋™ ํ•ฉ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€ ์—†์ด๋„ ํ”„๋กฌํ”„ํŠธ๋งŒ์œผ๋กœ ์ƒ์„ฑ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.",
267
+ label="ํ”„๋กฌํ”„ํŠธ (์„ ํƒ ์‚ฌํ•ญ)"
268
+ )
269
+
270
+ # ์ƒ์„ฑ ๋ฒ„ํŠผ
271
+ submit_btn = gr.Button("์ด๋ฏธ์ง€ ์ƒ์„ฑ", variant="primary")
272
 
273
+ with gr.Column():
274
+ # ๊ฒฐ๊ณผ ์ถœ๋ ฅ
275
+ output_image = gr.Image(label="์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€")
276
+ output_text = gr.Textbox(label="์ƒํƒœ ๋ฉ”์‹œ์ง€")
277
+
278
+ # ์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ ํ‘œ์‹œ
279
+ prompt_display = gr.Textbox(label="์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ", visible=True)
280
+
281
+ # ๊ธฐ๋Šฅ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด ์ด๋ฒคํŠธ (์ฆ‰์‹œ ํ”„๋กฌํ”„ํŠธ ์—…๋ฐ์ดํŠธ)
282
+ function_dropdown.change(
283
+ fn=update_prompt_from_function,
284
+ inputs=[function_dropdown],
285
+ outputs=[prompt_input]
286
+ )
287
+
288
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
289
+ def process_and_show_prompt(image1, image2, image3, prompt):
290
+ # ์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜ ํ™•์ธ
291
+ images = [image1, image2, image3]
292
+ valid_images = [img for img in images if img is not None]
293
 
294
+ try:
295
+ # ์ž๋™ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋˜๋Š” ํ”„๋กฌํ”„ํŠธ ์ „์ฒ˜๋ฆฌ
296
+ auto_prompt = prompt
297
+ if not prompt or not prompt.strip():
298
+ if not valid_images:
299
+ # ์ด๋ฏธ์ง€๋„ ์—†๊ณ  ํ”„๋กฌํ”„ํŠธ๋„ ์—†๋Š” ๊ฒฝ์šฐ
300
+ auto_prompt = "์•„๋ฆ„๋‹ค์šด ํ’๊ฒฝ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”. ํ‘ธ๋ฅธ ํ•˜๋Š˜, ์ดˆ๋ก์ƒ‰ ์–ธ๋•, ๊ทธ๋ฆฌ๊ณ  ๋ง‘์€ ํ˜ธ์ˆ˜๊ฐ€ ์žˆ๋Š” ํ‰ํ™”๋กœ์šด ์ž์—ฐ ํ’๊ฒฝ์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
301
+ elif len(valid_images) == 1:
302
+ auto_prompt = "์ด ์ด๋ฏธ์ง€๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ๋ณ€ํ˜•ํ•ด์ฃผ์„ธ์š”. ๋” ์ƒ์ƒํ•˜๊ณ  ์˜ˆ์ˆ ์ ์ธ ๋ฒ„์ „์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
303
+ elif len(valid_images) == 2:
304
+ auto_prompt = "์ด ๋‘ ์ด๋ฏธ์ง€๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”. ๋‘ ์ด๋ฏธ์ง€์˜ ์š”์†Œ๋ฅผ ์กฐํ™”๋กญ๊ฒŒ ํ†ตํ•ฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
305
+ else:
306
+ auto_prompt = "์ด ์„ธ ์ด๋ฏธ์ง€๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”. ๋ชจ๋“  ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ์š”์†Œ๋ฅผ ํฌํ•จํ•˜๋˜ ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ์ผ๊ด€๋œ ํ•˜๋‚˜์˜ ์žฅ๋ฉด์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
307
+ else:
308
+ auto_prompt = preprocess_prompt(prompt, image1, image2, image3)
309
 
310
+ # ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํ•จ์ˆ˜ ํ˜ธ์ถœ
311
+ result_img, status = process_images_with_prompt(image1, image2, image3, prompt)
 
 
 
312
 
313
+ return result_img, status, auto_prompt
314
+ except Exception as e:
315
+ logger.exception("์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
316
+ return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}", prompt
317
 
318
+ submit_btn.click(
319
+ fn=process_and_show_prompt,
320
+ inputs=[image1_input, image2_input, image3_input, prompt_input],
321
+ outputs=[output_image, output_text, prompt_display],
322
+ )
323
+
324
+ gr.Markdown(
325
+ """
326
+ ### ์‚ฌ์šฉ ๋ฐฉ๋ฒ•:
327
+
328
+ 1. **์ž๋™ ํ•ฉ์„ฑ**: ์ด๋ฏธ์ง€๋งŒ ์—…๋กœ๋“œํ•˜๊ณ  ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋น„์›Œ๋‘๋ฉด ์ž๋™์œผ๋กœ ํ•ฉ์„ฑ๋ฉ๋‹ˆ๋‹ค
329
+ 2. **ํ…์ŠคํŠธ๋งŒ์œผ๋กœ ์ƒ์„ฑ**: ์ด๋ฏธ์ง€ ์—†์ด ํ”„๋กฌํ”„ํŠธ๋งŒ ์ž…๋ ฅํ•ด๋„ ์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค
330
+ 3. **๊ธฐ๋Šฅ ์‚ฌ์šฉ**: ๋“œ๋กญ๋‹ค์šด์—์„œ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์„ ํƒํ•˜๋ฉด ์ž๋™์œผ๋กœ ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์ž…๋ ฅ๋ฉ๋‹ˆ๋‹ค
331
+ 4. **์ด๋ฏธ์ง€ ์ฐธ์กฐ**: #1, #2, #3์œผ๋กœ ๊ฐ ์ด๋ฏธ์ง€๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
332
+ 5. **์ผ๋ถ€ ์ด๋ฏธ์ง€๋งŒ**: ํ•„์š”ํ•œ ์ด๋ฏธ์ง€๋งŒ ์—…๋กœ๋“œํ•ด๋„ ๊ธฐ๋Šฅ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
333
+ 6. **์žฌ์‹œ๋„ ๊ธฐ๋Šฅ**: ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์ž๋™์œผ๋กœ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค
334
+
335
+ > **ํŒ**: ๊ธฐ๋Šฅ์„ ์„ ํƒํ•œ ํ›„์—๋„ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
336
+ """
337
+ )
338
 
339
  # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰
340
  if __name__ == "__main__":
 
341
  demo.launch(share=True)