Update app.py
Browse files
app.py
CHANGED
@@ -27,8 +27,8 @@ def save_binary_file(file_name, data):
|
|
27 |
logger.debug(f"νμΌ μ μ₯ μλ£: {file_name}")
|
28 |
|
29 |
|
30 |
-
def
|
31 |
-
logger.debug(f"
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
|
|
|
|
108 |
|
109 |
# ν둬ννΈμ μμ΄κ° μμΌλ©΄ μμ΄ ν둬ννΈ μΆκ° (λ λμ κ²°κ³Όλ₯Ό μν΄)
|
110 |
if not any(ord(c) < 128 for c in prompt):
|
111 |
-
|
|
|
|
|
|
|
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 =
|
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("
|
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λ₯Ό μ΄μ©ν
|
165 |
-
<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
|
197 |
-
<li><strong>νΉμ μμΉ μ§μ :</strong> "μ΄ μ¬λμ΄ μ΄ μνμ μμ λ€κ³ μλ λͺ¨μ΅μ 보μ¬μ£ΌμΈμ."</li>
|
198 |
-
<li><strong>μν κ°μ‘°:</strong> "μ΄ μ¬λμ΄ μ΄ μνμ μ¬μ©νλ λͺ¨μ΅μ 보μ¬μ£Όλ, μνμ΄ μ 보μ΄λλ‘ ν΄μ£ΌμΈμ."</li>
|
|
|
199 |
<li><strong>μμ΄ ν둬ννΈ:</strong> λ λμ κ²°κ³Όλ₯Ό μν΄ μμ΄μ νκ΅μ΄λ₯Ό ν¨κ» μ¬μ©ν΄ 보μΈμ.</li>
|
200 |
-
<li><strong
|
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 |
""")
|