Kims12 commited on
Commit
c1f6fb2
ยท
verified ยท
1 Parent(s): a7e1681

Update app.py

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