Kims12 commited on
Commit
654ca6d
Β·
verified Β·
1 Parent(s): 811d552

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -21
app.py CHANGED
@@ -27,8 +27,8 @@ def save_binary_file(file_name, data):
27
  logger.debug(f"파일 μ €μž₯ μ™„λ£Œ: {file_name}")
28
 
29
 
30
- def merge_product_and_person(person_img_path, product_img_path, prompt, model="gemini-2.0-flash-exp-image-generation"):
31
- logger.debug(f"merge_product_and_person ν•¨μˆ˜ μ‹œμž‘ - ν”„λ‘¬ν”„νŠΈ: '{prompt}'")
32
 
33
  try:
34
  # API ν‚€λŠ” ν™˜κ²½λ³€μˆ˜μ—μ„œ 뢈러옴
@@ -46,9 +46,17 @@ def merge_product_and_person(person_img_path, product_img_path, prompt, model="g
46
  person_img = Image.open(person_img_path)
47
  product_img = Image.open(product_img_path)
48
 
49
- # 컨텐츠 리슀트 생성 (곡식 λ¬Έμ„œ λ°©μ‹λŒ€λ‘œ)
50
- # μˆœμ„œ: μ‚¬λžŒ 이미지, μƒν’ˆ 이미지, ν”„λ‘¬ν”„νŠΈ ν…μŠ€νŠΈ
51
- contents = [person_img, product_img, prompt]
 
 
 
 
 
 
 
 
52
  logger.debug(f"컨텐츠 객체 생성 μ™„λ£Œ: {len(contents)} μ•„μ΄ν…œ")
53
 
54
  # 생성 μ„€μ •
@@ -99,16 +107,22 @@ def merge_product_and_person(person_img_path, product_img_path, prompt, model="g
99
  return None, str(e) # 였λ₯˜ λ°œμƒ μ‹œ Noneκ³Ό 였λ₯˜ λ©”μ‹œμ§€ λ°˜ν™˜
100
 
101
 
102
- def process_images_and_prompt(person_pil, product_pil, prompt):
103
  logger.debug(f"process_images_and_prompt ν•¨μˆ˜ μ‹œμž‘ - ν”„λ‘¬ν”„νŠΈ: '{prompt}'")
104
  try:
105
  # κΈ°λ³Έ ν”„λ‘¬ν”„νŠΈ μ„€μ • (λΉ„μ–΄μžˆλŠ” 경우)
106
  if not prompt or not prompt.strip():
107
- prompt = "이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ μ‚¬μš©ν•˜λŠ” λͺ¨μŠ΅μ„ μžμ—°μŠ€λŸ½κ²Œ λ³΄μ—¬μ£Όμ„Έμš”. μƒν’ˆμ„ 잘 보이게 ν•΄μ£Όμ„Έμš”. Make a natural composite image showing this person using this product. Make sure the product is clearly visible."
 
 
 
108
 
109
  # ν”„λ‘¬ν”„νŠΈμ— μ˜μ–΄κ°€ μ—†μœΌλ©΄ μ˜μ–΄ ν”„λ‘¬ν”„νŠΈ μΆ”κ°€ (더 λ‚˜μ€ κ²°κ³Όλ₯Ό μœ„ν•΄)
110
  if not any(ord(c) < 128 for c in prompt):
111
- prompt += " Create a realistic composite image of this person with this product."
 
 
 
112
 
113
  # 이미지 μ €μž₯
114
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_person:
@@ -120,11 +134,20 @@ def process_images_and_prompt(person_pil, product_pil, prompt):
120
  product_path = tmp_product.name
121
  product_pil.save(product_path)
122
  logger.debug(f"μƒν’ˆ 이미지 μ €μž₯ μ™„λ£Œ: {product_path}")
 
 
 
 
 
 
 
 
123
 
124
  # 이미지 ν•©μ„± μ‹€ν–‰
125
- result_path, response_text = merge_product_and_person(
126
  person_img_path=person_path,
127
  product_img_path=product_path,
 
128
  prompt=prompt
129
  )
130
 
@@ -139,12 +162,14 @@ def process_images_and_prompt(person_pil, product_pil, prompt):
139
  try:
140
  os.unlink(person_path)
141
  os.unlink(product_path)
 
 
142
  except Exception as e:
143
  logger.warning(f"μž„μ‹œ 파일 μ‚­μ œ 쀑 였λ₯˜: {str(e)}")
144
 
145
  return [result_img], response_text
146
  else:
147
- logger.error("merge_product_and_person ν•¨οΏ½οΏ½οΏ½μ—μ„œ None λ°˜ν™˜λ¨.")
148
  return [], response_text # 였λ₯˜ μ‹œ 빈 리슀트 λ°˜ν™˜
149
 
150
  except Exception as e:
@@ -161,21 +186,22 @@ with gr.Blocks() as demo:
161
  <img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" style="width: 100px; height: 100px;">
162
  </div>
163
  <div>
164
- <h1>Geminiλ₯Ό μ΄μš©ν•œ μƒν’ˆ-μ‚¬λžŒ 이미지 ν•©μ„±</h1>
165
- <p>Gemini API ν‚€λŠ” ν™˜κ²½λ³€μˆ˜(GEMINI_API_KEY)둜 μ„€μ •λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.</p>
166
  </div>
167
  </div>
168
  """
169
  )
170
- gr.Markdown("μ‚¬λžŒ 이미지와 μƒν’ˆ 이미지λ₯Ό μ—…λ‘œλ“œν•˜κ³ , μ–΄λ–»κ²Œ ν•©μ„±ν• μ§€ μ„€λͺ…ν•΄μ£Όμ„Έμš”.")
171
 
172
  with gr.Row():
173
  with gr.Column():
174
- person_input = gr.Image(type="pil", label="μ‚¬λžŒ 이미지", image_mode="RGB")
175
- product_input = gr.Image(type="pil", label="μƒν’ˆ 이미지", image_mode="RGB")
 
176
  prompt_input = gr.Textbox(
177
  lines=2,
178
- placeholder="ν•©μ„± 방법을 μ„€λͺ…ν•΄μ£Όμ„Έμš”. (예: '이 μ‚¬λžŒμ΄ μƒν’ˆμ„ λ“€κ³  μžˆλŠ” λͺ¨μŠ΅' λ˜λŠ” '이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ μ‚¬μš©ν•˜λŠ” λͺ¨μŠ΅')",
179
  label="ν•©μ„± 방법 μ„€λͺ…"
180
  )
181
  submit_btn = gr.Button("이미지 ν•©μ„± μ‹€ν–‰")
@@ -185,7 +211,7 @@ with gr.Blocks() as demo:
185
 
186
  submit_btn.click(
187
  fn=process_images_and_prompt,
188
- inputs=[person_input, product_input, prompt_input],
189
  outputs=[output_gallery, output_text],
190
  )
191
 
@@ -193,11 +219,12 @@ with gr.Blocks() as demo:
193
  <div style="margin-top: 20px; padding: 10px; background-color: #f8f9fa; border-radius: 8px;">
194
  <h3>μ‚¬μš© 팁:</h3>
195
  <ul>
196
- <li><strong>μžμ—°μŠ€λŸ¬μš΄ ν•©μ„±:</strong> "이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ μ‚¬μš©ν•˜λŠ” μžμ—°μŠ€λŸ¬μš΄ λͺ¨μŠ΅μ„ λ§Œλ“€μ–΄μ£Όμ„Έμš”."</li>
197
- <li><strong>νŠΉμ • μœ„μΉ˜ μ§€μ •:</strong> "이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ 손에 λ“€κ³  μžˆλŠ” λͺ¨μŠ΅μ„ λ³΄μ—¬μ£Όμ„Έμš”."</li>
198
- <li><strong>μƒν’ˆ κ°•μ‘°:</strong> "이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ μ‚¬μš©ν•˜λŠ” λͺ¨μŠ΅μ„ λ³΄μ—¬μ£Όλ˜, μƒν’ˆμ΄ 잘 보이도둝 ν•΄μ£Όμ„Έμš”."</li>
 
199
  <li><strong>μ˜μ–΄ ν”„λ‘¬ν”„νŠΈ:</strong> 더 λ‚˜μ€ κ²°κ³Όλ₯Ό μœ„ν•΄ μ˜μ–΄μ™€ ν•œκ΅­μ–΄λ₯Ό ν•¨κ»˜ μ‚¬μš©ν•΄ λ³΄μ„Έμš”.</li>
200
- <li><strong>ꡬ체적인 μ§€μ‹œ:</strong> ν•©μ„± 방법을 ꡬ체적으둜 μ„€λͺ…ν• μˆ˜λ‘ 더 쒋은 κ²°κ³Όλ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.</li>
201
  </ul>
202
  </div>
203
  """)
 
27
  logger.debug(f"파일 μ €μž₯ μ™„λ£Œ: {file_name}")
28
 
29
 
30
+ def merge_images(person_img_path, product_img_path, background_img_path, prompt, model="gemini-2.0-flash-exp-image-generation"):
31
+ logger.debug(f"merge_images ν•¨μˆ˜ μ‹œμž‘ - ν”„λ‘¬ν”„νŠΈ: '{prompt}'")
32
 
33
  try:
34
  # API ν‚€λŠ” ν™˜κ²½λ³€μˆ˜μ—μ„œ 뢈러옴
 
46
  person_img = Image.open(person_img_path)
47
  product_img = Image.open(product_img_path)
48
 
49
+ # 컨텐츠 리슀트 생성
50
+ contents = [person_img, product_img]
51
+
52
+ # λ°°κ²½ 이미지가 있으면 μΆ”κ°€
53
+ if background_img_path:
54
+ background_img = Image.open(background_img_path)
55
+ contents.append(background_img)
56
+ logger.debug("λ°°κ²½ 이미지 좔가됨")
57
+
58
+ # λ§ˆμ§€λ§‰μ— ν”„λ‘¬ν”„νŠΈ μΆ”κ°€
59
+ contents.append(prompt)
60
  logger.debug(f"컨텐츠 객체 생성 μ™„λ£Œ: {len(contents)} μ•„μ΄ν…œ")
61
 
62
  # 생성 μ„€μ •
 
107
  return None, str(e) # 였λ₯˜ λ°œμƒ μ‹œ Noneκ³Ό 였λ₯˜ λ©”μ‹œμ§€ λ°˜ν™˜
108
 
109
 
110
+ def process_images_and_prompt(person_pil, product_pil, background_pil, prompt):
111
  logger.debug(f"process_images_and_prompt ν•¨μˆ˜ μ‹œμž‘ - ν”„λ‘¬ν”„νŠΈ: '{prompt}'")
112
  try:
113
  # κΈ°λ³Έ ν”„λ‘¬ν”„νŠΈ μ„€μ • (λΉ„μ–΄μžˆλŠ” 경우)
114
  if not prompt or not prompt.strip():
115
+ if background_pil:
116
+ prompt = "이 배경에 이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ μ‚¬μš©ν•˜λŠ” λͺ¨μŠ΅μ„ μžμ—°μŠ€λŸ½κ²Œ λ³΄μ—¬μ£Όμ„Έμš”. μƒν’ˆμ„ 잘 보이게 ν•΄μ£Όμ„Έμš”. Create a natural composite image showing this person using this product in this background setting. Make sure the product is clearly visible."
117
+ else:
118
+ prompt = "이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ μ‚¬μš©ν•˜λŠ” λͺ¨μŠ΅μ„ μžμ—°μŠ€λŸ½κ²Œ λ³΄μ—¬μ£Όμ„Έμš”. μƒν’ˆμ„ 잘 보이게 ν•΄μ£Όμ„Έμš”. Create a natural composite image showing this person using this product. Make sure the product is clearly visible."
119
 
120
  # ν”„λ‘¬ν”„νŠΈμ— μ˜μ–΄κ°€ μ—†μœΌλ©΄ μ˜μ–΄ ν”„λ‘¬ν”„νŠΈ μΆ”κ°€ (더 λ‚˜μ€ κ²°κ³Όλ₯Ό μœ„ν•΄)
121
  if not any(ord(c) < 128 for c in prompt):
122
+ if background_pil:
123
+ prompt += " Create a realistic composite image of this person with this product in this background."
124
+ else:
125
+ prompt += " Create a realistic composite image of this person with this product."
126
 
127
  # 이미지 μ €μž₯
128
  with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_person:
 
134
  product_path = tmp_product.name
135
  product_pil.save(product_path)
136
  logger.debug(f"μƒν’ˆ 이미지 μ €μž₯ μ™„λ£Œ: {product_path}")
137
+
138
+ # λ°°κ²½ 이미지 μ €μž₯ (μžˆλŠ” 경우)
139
+ background_path = None
140
+ if background_pil is not None:
141
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_bg:
142
+ background_path = tmp_bg.name
143
+ background_pil.save(background_path)
144
+ logger.debug(f"λ°°κ²½ 이미지 μ €μž₯ μ™„λ£Œ: {background_path}")
145
 
146
  # 이미지 ν•©μ„± μ‹€ν–‰
147
+ result_path, response_text = merge_images(
148
  person_img_path=person_path,
149
  product_img_path=product_path,
150
+ background_img_path=background_path,
151
  prompt=prompt
152
  )
153
 
 
162
  try:
163
  os.unlink(person_path)
164
  os.unlink(product_path)
165
+ if background_path:
166
+ os.unlink(background_path)
167
  except Exception as e:
168
  logger.warning(f"μž„μ‹œ 파일 μ‚­μ œ 쀑 였λ₯˜: {str(e)}")
169
 
170
  return [result_img], response_text
171
  else:
172
+ logger.error("merge_images ν•¨μˆ˜μ—μ„œ None λ°˜ν™˜λ¨.")
173
  return [], response_text # 였λ₯˜ μ‹œ 빈 리슀트 λ°˜ν™˜
174
 
175
  except Exception as e:
 
186
  <img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" style="width: 100px; height: 100px;">
187
  </div>
188
  <div>
189
+ <h1>Geminiλ₯Ό μ΄μš©ν•œ 이미지 ν•©μ„±</h1>
190
+ <p>μ‚¬λžŒ, μƒν’ˆ, λ°°κ²½ 이미지λ₯Ό ν•©μ„±ν•˜λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μž…λ‹ˆλ‹€.</p>
191
  </div>
192
  </div>
193
  """
194
  )
195
+ gr.Markdown("μ‚¬λžŒ 이미지, μƒν’ˆ 이미지, λ°°κ²½ 이미지λ₯Ό μ—…λ‘œλ“œν•˜κ³ , μ–΄λ–»κ²Œ ν•©μ„±ν• μ§€ μ„€λͺ…ν•΄μ£Όμ„Έμš”.")
196
 
197
  with gr.Row():
198
  with gr.Column():
199
+ person_input = gr.Image(type="pil", label="μ‚¬λžŒ 이미지 (ν•„μˆ˜)", image_mode="RGB")
200
+ product_input = gr.Image(type="pil", label="μƒν’ˆ 이미지 (ν•„μˆ˜)", image_mode="RGB")
201
+ background_input = gr.Image(type="pil", label="λ°°κ²½ 이미지 (선택 사항)", image_mode="RGB")
202
  prompt_input = gr.Textbox(
203
  lines=2,
204
+ placeholder="ν•©μ„± 방법을 μ„€λͺ…ν•΄μ£Όμ„Έμš”. (예: '이 λ°°κ²½μ—μ„œ 이 μ‚¬λžŒμ΄ μƒν’ˆμ„ μ‚¬μš©ν•˜λŠ” λͺ¨μŠ΅' λ˜λŠ” '이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ λ“€κ³  이 배경에 μ„œ μžˆλŠ” λͺ¨μŠ΅')",
205
  label="ν•©μ„± 방법 μ„€λͺ…"
206
  )
207
  submit_btn = gr.Button("이미지 ν•©μ„± μ‹€ν–‰")
 
211
 
212
  submit_btn.click(
213
  fn=process_images_and_prompt,
214
+ inputs=[person_input, product_input, background_input, prompt_input],
215
  outputs=[output_gallery, output_text],
216
  )
217
 
 
219
  <div style="margin-top: 20px; padding: 10px; background-color: #f8f9fa; border-radius: 8px;">
220
  <h3>μ‚¬μš© 팁:</h3>
221
  <ul>
222
+ <li><strong>λ°°κ²½ ν™œμš©:</strong> "이 λ°°κ²½μ—μ„œ 이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ μ‚¬μš©ν•˜λŠ” μžμ—°μŠ€λŸ¬μš΄ λͺ¨μŠ΅μ„ λ§Œλ“€μ–΄μ£Όμ„Έμš”."</li>
223
+ <li><strong>νŠΉμ • μœ„μΉ˜ μ§€μ •:</strong> "이 μ‚¬λžŒμ΄ 이 μƒν’ˆμ„ 손에 λ“€κ³  이 λ°°κ²½ μ•žμ— μ„œ μžˆλŠ” λͺ¨μŠ΅μ„ λ³΄μ—¬μ£Όμ„Έμš”."</li>
224
+ <li><strong>μƒν’ˆ κ°•μ‘°:</strong> "이 μ‚¬λžŒμ΄ 이 λ°°κ²½μ—μ„œ 이 μƒν’ˆμ„ μ‚¬μš©ν•˜λŠ” λͺ¨μŠ΅μ„ λ³΄μ—¬μ£Όλ˜, μƒν’ˆμ΄ 잘 보이도둝 ν•΄μ£Όμ„Έμš”."</li>
225
+ <li><strong>μž₯λ©΄ μ„€μ •:</strong> "이 μ‚¬λžŒμ΄ 이 μƒν’ˆμœΌλ‘œ μš”λ¦¬ν•˜λŠ” λͺ¨μŠ΅μ„ 이 μ£Όλ°© λ°°κ²½μ—μ„œ λ³΄μ—¬μ£Όμ„Έμš”."</li>
226
  <li><strong>μ˜μ–΄ ν”„λ‘¬ν”„νŠΈ:</strong> 더 λ‚˜μ€ κ²°κ³Όλ₯Ό μœ„ν•΄ μ˜μ–΄μ™€ ν•œκ΅­μ–΄λ₯Ό ν•¨κ»˜ μ‚¬μš©ν•΄ λ³΄μ„Έμš”.</li>
227
+ <li><strong>λ°°κ²½ 선택사항:</strong> λ°°κ²½ μ΄λ―Έμ§€λŠ” μ„ νƒμ‚¬ν•­μž…λ‹ˆλ‹€. λ°°κ²½ 없이 μ‚¬λžŒκ³Ό μƒν’ˆλ§Œ ν•©μ„±ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.</li>
228
  </ul>
229
  </div>
230
  """)