Update app.py
Browse files
app.py
CHANGED
@@ -28,7 +28,6 @@ def save_binary_file(file_name, data):
|
|
28 |
|
29 |
|
30 |
def generate_image_from_prompt(prompt, model="gemini-2.0-flash-exp-image-generation"):
|
31 |
-
"""ํ
์คํธ ํ๋กฌํํธ๋ง์ผ๋ก ์ด๋ฏธ์ง ์์ฑ"""
|
32 |
logger.debug(f"generate_image_from_prompt ํจ์ ์์ - ํ๋กฌํํธ: '{prompt}'")
|
33 |
|
34 |
try:
|
@@ -127,224 +126,17 @@ def generate_image_from_prompt(prompt, model="gemini-2.0-flash-exp-image-generat
|
|
127 |
return None, f"์ค๋ฅ ๋ฐ์: {str(e)}" # ์ค๋ฅ ๋ฐ์ ์ None๊ณผ ์ค๋ฅ ๋ฉ์์ง ๋ฐํ
|
128 |
|
129 |
|
130 |
-
def
|
131 |
-
"
|
132 |
-
logger.debug(f"merge_images ํจ์ ์์ - ํ๋กฌํํธ: '{prompt}'")
|
133 |
-
|
134 |
try:
|
135 |
-
#
|
136 |
-
|
137 |
-
|
138 |
-
logger.debug("ํ๊ฒฝ๋ณ์์์ API ํค ๋ถ๋ฌ์ด")
|
139 |
-
else:
|
140 |
-
logger.error("API ํค๊ฐ ํ๊ฒฝ๋ณ์์ ์ค์ ๋์ง ์์์ต๋๋ค.")
|
141 |
-
raise ValueError("API ํค๊ฐ ํ์ํฉ๋๋ค.")
|
142 |
-
|
143 |
-
client = genai.Client(api_key=effective_api_key)
|
144 |
-
logger.debug("Gemini ํด๋ผ์ด์ธํธ ์ด๊ธฐํ ์๋ฃ.")
|
145 |
-
|
146 |
-
# ์ด๋ฏธ์ง ํ์ผ ์
๋ก๋
|
147 |
-
person_file = client.files.upload(file=person_img_path)
|
148 |
-
logger.debug(f"์ฌ๋ ์ด๋ฏธ์ง ์
๋ก๋ ์๋ฃ: {person_file.uri}")
|
149 |
-
|
150 |
-
product_file = client.files.upload(file=product_img_path)
|
151 |
-
logger.debug(f"์ํ ์ด๋ฏธ์ง ์
๋ก๋ ์๋ฃ: {product_file.uri}")
|
152 |
-
|
153 |
-
# ์ปจํ
์ธ ๋ฆฌ์คํธ ์์ฑ
|
154 |
-
parts = []
|
155 |
|
156 |
-
#
|
157 |
-
|
158 |
-
types.Part.from_uri(
|
159 |
-
file_uri=person_file.uri,
|
160 |
-
mime_type=person_file.mime_type
|
161 |
-
)
|
162 |
-
)
|
163 |
-
|
164 |
-
# ์ํ ์ด๋ฏธ์ง ์ถ๊ฐ
|
165 |
-
parts.append(
|
166 |
-
types.Part.from_uri(
|
167 |
-
file_uri=product_file.uri,
|
168 |
-
mime_type=product_file.mime_type
|
169 |
-
)
|
170 |
-
)
|
171 |
-
|
172 |
-
# ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง๊ฐ ์์ผ๋ฉด ์ถ๊ฐ
|
173 |
-
if background_img_path:
|
174 |
-
background_file = client.files.upload(file=background_img_path)
|
175 |
-
logger.debug(f"๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง ์
๋ก๋ ์๋ฃ: {background_file.uri}")
|
176 |
-
parts.append(
|
177 |
-
types.Part.from_uri(
|
178 |
-
file_uri=background_file.uri,
|
179 |
-
mime_type=background_file.mime_type
|
180 |
-
)
|
181 |
-
)
|
182 |
-
logger.debug("๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง ์ถ๊ฐ๋จ")
|
183 |
-
|
184 |
-
# ๋ง์ง๋ง์ ํ๋กฌํํธ ์ถ๊ฐ
|
185 |
-
parts.append(
|
186 |
-
types.Part.from_text(text=prompt)
|
187 |
-
)
|
188 |
-
|
189 |
-
logger.debug(f"์ปจํ
์ธ ๊ฐ์ฒด ์์ฑ ์๋ฃ: {len(parts)} ์์ดํ
")
|
190 |
-
|
191 |
-
# ์์ฑ ์ค์
|
192 |
-
generate_content_config = types.GenerateContentConfig(
|
193 |
-
temperature=1,
|
194 |
-
top_p=0.95,
|
195 |
-
top_k=40,
|
196 |
-
max_output_tokens=8192,
|
197 |
-
response_modalities=["image", "text"],
|
198 |
-
)
|
199 |
-
logger.debug(f"์์ฑ ์ค์ : {generate_content_config}")
|
200 |
|
201 |
-
|
202 |
-
temp_path = tmp.name
|
203 |
-
logger.debug(f"์์ ํ์ผ ์์ฑ๋จ: {temp_path}")
|
204 |
-
|
205 |
-
# ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ ์์
|
206 |
-
response_stream = client.models.generate_content_stream(
|
207 |
-
model=model,
|
208 |
-
contents=[
|
209 |
-
types.Content(
|
210 |
-
role="user",
|
211 |
-
parts=parts,
|
212 |
-
),
|
213 |
-
],
|
214 |
-
config=generate_content_config,
|
215 |
-
)
|
216 |
-
|
217 |
-
logger.debug("์๋ต ์คํธ๋ฆผ ์ฒ๋ฆฌ ์์...")
|
218 |
-
|
219 |
-
# ์๋ต์์ ์ด๋ฏธ์ง์ ํ
์คํธ ์ถ์ถ
|
220 |
-
image_saved = False
|
221 |
-
response_text = ""
|
222 |
-
|
223 |
-
for chunk in response_stream:
|
224 |
-
logger.debug(f"chunk ์์ : {chunk}")
|
225 |
-
|
226 |
-
# ์๋ต ๊ฒ์ฆ
|
227 |
-
if not hasattr(chunk, 'candidates') or not chunk.candidates or len(chunk.candidates) == 0:
|
228 |
-
logger.warning("chunk์ candidates๊ฐ ์์ต๋๋ค. ๊ฑด๋๋๋๋ค.")
|
229 |
-
continue
|
230 |
-
|
231 |
-
if not hasattr(chunk.candidates[0], 'content') or chunk.candidates[0].content is None:
|
232 |
-
logger.warning("chunk.candidates[0]์ content๊ฐ ์์ต๋๋ค. ๊ฑด๋๋๋๋ค.")
|
233 |
-
continue
|
234 |
-
|
235 |
-
if not hasattr(chunk.candidates[0].content, 'parts') or not chunk.candidates[0].content.parts:
|
236 |
-
logger.warning("chunk.candidates[0].content์ parts๊ฐ ์์ต๋๋ค. ๊ฑด๋๋๋๋ค.")
|
237 |
-
continue
|
238 |
-
|
239 |
-
for part in chunk.candidates[0].content.parts:
|
240 |
-
if hasattr(part, 'text') and part.text:
|
241 |
-
response_text += part.text
|
242 |
-
logger.info(f"์์ ๋ ํ
์คํธ: {part.text}")
|
243 |
-
elif hasattr(part, 'inline_data') and part.inline_data:
|
244 |
-
save_binary_file(temp_path, part.inline_data.data)
|
245 |
-
logger.info(f"MIME ํ์
{part.inline_data.mime_type}์ ํ์ผ์ด ์ ์ฅ๋จ: {temp_path}")
|
246 |
-
image_saved = True
|
247 |
-
|
248 |
-
if not image_saved:
|
249 |
-
logger.warning("์ด๋ฏธ์ง๊ฐ ์์ฑ๋์ง ์์์ต๋๋ค.")
|
250 |
-
return None, response_text or "์ด๋ฏธ์ง๊ฐ ์์ฑ๋์ง ์์์ต๋๋ค. ๋ค๋ฅธ ํ๋กฌํํธ๋ ์ด๋ฏธ์ง๋ก ์๋ํด๋ณด์ธ์."
|
251 |
-
|
252 |
-
logger.debug("์ด๋ฏธ์ง ์์ฑ ์๋ฃ.")
|
253 |
-
return temp_path, response_text
|
254 |
-
|
255 |
-
except Exception as e:
|
256 |
-
logger.exception("์ด๋ฏธ์ง ์์ฑ ์ค ์ค๋ฅ ๋ฐ์:")
|
257 |
-
return None, f"์ค๋ฅ ๋ฐ์: {str(e)}" # ์ค๋ฅ ๋ฐ์ ์ None๊ณผ ์ค๋ฅ ๋ฉ์์ง ๋ฐํ
|
258 |
-
|
259 |
-
|
260 |
-
def process_images_and_prompt(person_pil, product_pil, background_pil, prompt):
|
261 |
-
"""
|
262 |
-
์ด๋ฏธ์ง ๋ฐ ํ๋กฌํํธ๋ฅผ ์ฒ๋ฆฌํ์ฌ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ ํจ์
|
263 |
-
|
264 |
-
์ด๋ฏธ์ง ์
๋ ฅ์ด ์๋ ๊ฒฝ์ฐ ํ
์คํธ ๊ธฐ๋ฐ ์ด๋ฏธ์ง ์์ฑ์ผ๋ก ์ ํ
|
265 |
-
์ด๋ฏธ์ง ์
๋ ฅ์ด ์๋ ๊ฒฝ์ฐ ๊ธฐ์กด์ ์ด๋ฏธ์ง ํฉ์ฑ ๋ก์ง ์ ์ง
|
266 |
-
"""
|
267 |
-
logger.debug(f"process_images_and_prompt ํจ์ ์์ - ํ๋กฌํํธ: '{prompt}'")
|
268 |
-
|
269 |
-
try:
|
270 |
-
# ์ด๋ฏธ์ง ์
๋ ฅ์ด ๋ชจ๋ ์๋ ๊ฒฝ์ฐ ํ
์คํธ ๊ธฐ๋ฐ ์ด๋ฏธ์ง ์์ฑ
|
271 |
-
if person_pil is None and product_pil is None and background_pil is None:
|
272 |
-
logger.debug("์ด๋ฏธ์ง ์์. ํ
์คํธ ๊ธฐ๋ฐ ์ด๋ฏธ์ง ์์ฑ์ผ๋ก ์ ํ")
|
273 |
-
result_path, response_text = generate_image_from_prompt(prompt)
|
274 |
-
|
275 |
-
if result_path:
|
276 |
-
try:
|
277 |
-
result_img = Image.open(result_path)
|
278 |
-
if result_img.mode == "RGBA":
|
279 |
-
result_img = result_img.convert("RGB")
|
280 |
-
|
281 |
-
return [result_img], response_text or "์ด๋ฏธ์ง๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์์ฑ๋์์ต๋๋ค."
|
282 |
-
except Exception as e:
|
283 |
-
logger.exception(f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง ๋ก๋ ์ค ์ค๋ฅ: {str(e)}")
|
284 |
-
return [], f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง ์ฒ๋ฆฌ ์ค ์ค๋ฅ: {str(e)}"
|
285 |
-
else:
|
286 |
-
return [], response_text or "์ด๋ฏธ์ง ์์ฑ์ ์คํจํ์ต๋๋ค."
|
287 |
-
|
288 |
-
# ํ์ ์ด๋ฏธ์ง ํ์ธ (์ด๋ฏธ์ง ํฉ์ฑ ๋ชจ๋)
|
289 |
-
if person_pil is None:
|
290 |
-
return [], "์ฌ๋ ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํด์ฃผ์ธ์."
|
291 |
-
if product_pil is None:
|
292 |
-
return [], "์ํ ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํด์ฃผ์ธ์."
|
293 |
-
|
294 |
-
# ๊ธฐ๋ณธ ํ๋กฌํํธ ์ค์ (๋น์ด์๋ ๊ฒฝ์ฐ)
|
295 |
-
if not prompt or not prompt.strip():
|
296 |
-
if background_pil:
|
297 |
-
prompt = "์ด ๋ฐฐ๊ฒฝ์ ์ด ์ฌ๋์ด ์ด ์ํ์ ์ฌ์ฉํ๋ ๋ชจ์ต์ ์์ฐ์ค๋ฝ๊ฒ ๋ณด์ฌ์ฃผ์ธ์. ์ํ์ ์ ๋ณด์ด๊ฒ ํด์ฃผ์ธ์. Create a natural composite image showing this person using this product in this background setting. Make sure the product is clearly visible."
|
298 |
-
else:
|
299 |
-
prompt = "์ด ์ฌ๋์ด ์ด ์ํ์ ์ฌ์ฉํ๋ ๋ชจ์ต์ ์์ฐ์ค๋ฝ๊ฒ ๋ณด์ฌ์ฃผ์ธ์. ์ํ์ ์ ๋ณด์ด๊ฒ ํด์ฃผ์ธ์. Create a natural composite image showing this person using this product. Make sure the product is clearly visible."
|
300 |
-
|
301 |
-
# ํ๋กฌํํธ์ ์์ด๊ฐ ์์ผ๋ฉด ์์ด ํ๋กฌํํธ ์ถ๊ฐ (๋ ๋์ ๊ฒฐ๊ณผ๋ฅผ ์ํด)
|
302 |
-
if not any(ord(c) < 128 for c in prompt):
|
303 |
-
if background_pil:
|
304 |
-
prompt += " Create a realistic composite image of this person with this product in this background."
|
305 |
-
else:
|
306 |
-
prompt += " Create a realistic composite image of this person with this product."
|
307 |
-
|
308 |
-
# ์ด๋ฏธ์ง ์ ์ฅ
|
309 |
-
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_person:
|
310 |
-
person_path = tmp_person.name
|
311 |
-
# RGB๋ก ๋ณํํ์ฌ ์ ์ฅ
|
312 |
-
person_img = person_pil
|
313 |
-
if person_img.mode != 'RGB':
|
314 |
-
person_img = person_img.convert('RGB')
|
315 |
-
person_img.save(person_path, 'JPEG')
|
316 |
-
logger.debug(f"์ฌ๋ ์ด๋ฏธ์ง ์ ์ฅ ์๋ฃ: {person_path}")
|
317 |
-
|
318 |
-
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_product:
|
319 |
-
product_path = tmp_product.name
|
320 |
-
# RGB๋ก ๋ณํํ์ฌ ์ ์ฅ
|
321 |
-
product_img = product_pil
|
322 |
-
if product_img.mode != 'RGB':
|
323 |
-
product_img = product_img.convert('RGB')
|
324 |
-
product_img.save(product_path, 'JPEG')
|
325 |
-
logger.debug(f"์ํ ์ด๋ฏธ์ง ์ ์ฅ ์๋ฃ: {product_path}")
|
326 |
-
|
327 |
-
# ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง ์ ์ฅ (์๋ ๊ฒฝ์ฐ)
|
328 |
-
background_path = None
|
329 |
-
if background_pil is not None:
|
330 |
-
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_bg:
|
331 |
-
background_path = tmp_bg.name
|
332 |
-
# RGB๋ก ๋ณํํ์ฌ ์ ์ฅ
|
333 |
-
background_img = background_pil
|
334 |
-
if background_img.mode != 'RGB':
|
335 |
-
background_img = background_img.convert('RGB')
|
336 |
-
background_img.save(background_path, 'JPEG')
|
337 |
-
logger.debug(f"๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง ์ ์ฅ ์๋ฃ: {background_path}")
|
338 |
-
|
339 |
-
# ์ด๋ฏธ์ง ํฉ์ฑ ์คํ
|
340 |
-
result_path, response_text = merge_images(
|
341 |
-
person_img_path=person_path,
|
342 |
-
product_img_path=product_path,
|
343 |
-
background_img_path=background_path,
|
344 |
-
prompt=prompt
|
345 |
-
)
|
346 |
-
|
347 |
-
# ์ด๋ฏธ์ง ๋ฐํ ๋ฐ ์์ ํ์ผ ์ ๋ฆฌ
|
348 |
if result_path:
|
349 |
logger.debug(f"์ด๋ฏธ์ง ์์ฑ ์๋ฃ. ๊ฒฝ๋ก: {result_path}")
|
350 |
try:
|
@@ -352,23 +144,80 @@ def process_images_and_prompt(person_pil, product_pil, background_pil, prompt):
|
|
352 |
if result_img.mode == "RGBA":
|
353 |
result_img = result_img.convert("RGB")
|
354 |
|
355 |
-
# ์์ ํ์ผ ์ ๋ฆฌ
|
356 |
-
try:
|
357 |
-
os.unlink(person_path)
|
358 |
-
os.unlink(product_path)
|
359 |
-
if background_path:
|
360 |
-
os.unlink(background_path)
|
361 |
-
except Exception as e:
|
362 |
-
logger.warning(f"์์ ํ์ผ ์ญ์ ์ค ์ค๋ฅ: {str(e)}")
|
363 |
-
|
364 |
return [result_img], response_text or "์ด๋ฏธ์ง๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์์ฑ๋์์ต๋๋ค."
|
365 |
except Exception as e:
|
366 |
logger.exception(f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง ๋ก๋ ์ค ์ค๋ฅ: {str(e)}")
|
367 |
return [], f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง ์ฒ๋ฆฌ ์ค ์ค๋ฅ: {str(e)}"
|
368 |
else:
|
369 |
-
logger.error("
|
370 |
-
return [], response_text or "์ด๋ฏธ์ง ์์ฑ์ ์คํจํ์ต๋๋ค. ๋ค๋ฅธ
|
371 |
|
372 |
except Exception as e:
|
373 |
-
logger.exception("
|
374 |
-
return [], f"์ค๋ฅ ๋ฐ์: {str(e)}" # ์ค๋ฅ ์ ๋น ๋ฆฌ์คํธ์ ์ค๋ฅ ๋ฉ์์ง ๋ฐํ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
|
30 |
def generate_image_from_prompt(prompt, model="gemini-2.0-flash-exp-image-generation"):
|
|
|
31 |
logger.debug(f"generate_image_from_prompt ํจ์ ์์ - ํ๋กฌํํธ: '{prompt}'")
|
32 |
|
33 |
try:
|
|
|
126 |
return None, f"์ค๋ฅ ๋ฐ์: {str(e)}" # ์ค๋ฅ ๋ฐ์ ์ None๊ณผ ์ค๋ฅ ๋ฉ์์ง ๋ฐํ
|
127 |
|
128 |
|
129 |
+
def process_image_generation(person_pil, product_pil, background_pil, prompt):
|
130 |
+
logger.debug(f"process_image_generation ํจ์ ์์ - ํ๋กฌํํธ: '{prompt}'")
|
|
|
|
|
131 |
try:
|
132 |
+
# ์ด๋ฏธ์ง๋ค์ด ์ ๊ณต๋์๋ค๋ฉด ๊ธฐ์กด ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌ
|
133 |
+
if person_pil is not None or product_pil is not None or background_pil is not None:
|
134 |
+
return process_images_and_prompt(person_pil, product_pil, background_pil, prompt)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
|
136 |
+
# ์ด๋ฏธ์ง ์์ด ํ๋กฌํํธ๋ง ์๋ ๊ฒฝ์ฐ
|
137 |
+
result_path, response_text = generate_image_from_prompt(prompt)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
|
139 |
+
# ์ด๋ฏธ์ง ๋ฐํ ๋ฐ ์ฒ๋ฆฌ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
if result_path:
|
141 |
logger.debug(f"์ด๋ฏธ์ง ์์ฑ ์๋ฃ. ๊ฒฝ๋ก: {result_path}")
|
142 |
try:
|
|
|
144 |
if result_img.mode == "RGBA":
|
145 |
result_img = result_img.convert("RGB")
|
146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
return [result_img], response_text or "์ด๋ฏธ์ง๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์์ฑ๋์์ต๋๋ค."
|
148 |
except Exception as e:
|
149 |
logger.exception(f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง ๋ก๋ ์ค ์ค๋ฅ: {str(e)}")
|
150 |
return [], f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง ์ฒ๋ฆฌ ์ค ์ค๋ฅ: {str(e)}"
|
151 |
else:
|
152 |
+
logger.error("generate_image_from_prompt ํจ์์์ None ๋ฐํ๋จ.")
|
153 |
+
return [], response_text or "์ด๋ฏธ์ง ์์ฑ์ ์คํจํ์ต๋๋ค. ๋ค๋ฅธ ํ๋กฌํํธ๋ก ์๋ํด๋ณด์ธ์."
|
154 |
|
155 |
except Exception as e:
|
156 |
+
logger.exception("process_image_generation ํจ์์์ ์ค๋ฅ ๋ฐ์:")
|
157 |
+
return [], f"์ค๋ฅ ๋ฐ์: {str(e)}" # ์ค๋ฅ ์ ๋น ๋ฆฌ์คํธ์ ์ค๋ฅ ๋ฉ์์ง ๋ฐํ
|
158 |
+
|
159 |
+
|
160 |
+
# --- Gradio ์ธํฐํ์ด์ค ๊ตฌ์ฑ (๊ธฐ์กด ์ฝ๋๋ ๋์ผํ๊ฒ ์ ์ง) ---
|
161 |
+
with gr.Blocks() as demo:
|
162 |
+
gr.HTML(
|
163 |
+
"""
|
164 |
+
<div style='display: flex; align-items: center; justify-content: center; gap: 20px'>
|
165 |
+
<div style="background-color: var(--block-background-fill); border-radius: 8px">
|
166 |
+
<img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" style="width: 100px; height: 100px;">
|
167 |
+
</div>
|
168 |
+
<div>
|
169 |
+
<h1>Gemini๋ฅผ ์ด์ฉํ ์ด๋ฏธ์ง ์์ฑ</h1>
|
170 |
+
<p>์ฌ๋, ์ํ, ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง๋ฅผ ํฉ์ฑํ๊ฑฐ๋ ํ
์คํธ๋ก ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.</p>
|
171 |
+
</div>
|
172 |
+
</div>
|
173 |
+
"""
|
174 |
+
)
|
175 |
+
gr.Markdown("์ฌ๋ ์ด๋ฏธ์ง, ์ํ ์ด๋ฏธ์ง, ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํ๊ฑฐ๋ ํ
์คํธ๋ก ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.")
|
176 |
+
|
177 |
+
with gr.Row():
|
178 |
+
with gr.Column():
|
179 |
+
# ์ด๋ฏธ์ง ์
๋ ฅ ์น์
(์ ํ ์ฌํญ)
|
180 |
+
person_input = gr.Image(type="pil", label="์ฌ๋ ์ด๋ฏธ์ง (์ ํ ์ฌํญ)", image_mode="RGB")
|
181 |
+
product_input = gr.Image(type="pil", label="์ํ ์ด๋ฏธ์ง (์ ํ ์ฌํญ)", image_mode="RGB")
|
182 |
+
background_input = gr.Image(type="pil", label="๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง (์ ํ ์ฌํญ)", image_mode="RGB")
|
183 |
+
|
184 |
+
# ํ๋กฌํํธ ์
๋ ฅ (ํ์)
|
185 |
+
prompt_input = gr.Textbox(
|
186 |
+
lines=3,
|
187 |
+
placeholder="์ด๋ฏธ์ง ์์ฑ ์ค๋ช
์ ์
๋ ฅํด์ฃผ์ธ์. ์: '๊ฝ๋ฐญ์์ ํ๋น์ ๋ฐ์ผ๋ฉฐ ๋ฏธ์ ์ง๋ ์ ์ ์ฌ์ฑ', 'ํ๋์ ์ธ ๊ฑฐ์ค์์ ๊ณ ๊ธ ์ค๋งํธํฐ์ ์ฌ์ฉํ๋ ๋น์ฆ๋์ค๋งจ'",
|
188 |
+
label="์ด๋ฏธ์ง ์์ฑ ์ค๋ช
(ํ์)"
|
189 |
+
)
|
190 |
+
submit_btn = gr.Button("์ด๋ฏธ์ง ์์ฑ")
|
191 |
+
|
192 |
+
with gr.Column():
|
193 |
+
output_gallery = gr.Gallery(label="์์ฑ๋ ์ด๋ฏธ์ง")
|
194 |
+
output_text = gr.Textbox(label="AI ์๋ต ํ
์คํธ", visible=True)
|
195 |
+
|
196 |
+
submit_btn.click(
|
197 |
+
fn=process_image_generation,
|
198 |
+
inputs=[person_input, product_input, background_input, prompt_input],
|
199 |
+
outputs=[output_gallery, output_text],
|
200 |
+
)
|
201 |
+
|
202 |
+
gr.HTML("""
|
203 |
+
<div style="margin-top: 20px; padding: 10px; background-color: #f8f9fa; border-radius: 8px;">
|
204 |
+
<h3>์ฌ์ฉ ๋ฐฉ๋ฒ:</h3>
|
205 |
+
<ul>
|
206 |
+
<li><strong>ํ
์คํธ๋ก ์ด๋ฏธ์ง ์์ฑ:</strong> ์ค๋ช
๋ง ์
๋ ฅํ๊ณ ์ด๋ฏธ์ง ์์ฑ ๋ฒํผ์ ๋๋ฅด์ธ์.</li>
|
207 |
+
<li><strong>์ด๋ฏธ์ง ํฉ์ฑ:</strong> ์ฌ๋, ์ํ, ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง๋ฅผ ์ ํ์ ์ผ๋ก ์
๋ก๋ํ๊ณ ํฉ์ฑ ๋ฐฉ๋ฒ์ ์ค๋ช
ํด์ฃผ์ธ์.</li>
|
208 |
+
<li><strong>ํ๋กฌํํธ ํ:</strong> ๊ตฌ์ฒด์ ์ด๊ณ ์์ํ ์ค๋ช
์ผ์๋ก ๋ ์ข์ ์ด๋ฏธ์ง๊ฐ ์์ฑ๋ฉ๋๋ค.</li>
|
209 |
+
<li><strong>์์ ํ๋กฌํํธ:</strong>
|
210 |
+
<ul>
|
211 |
+
<li>ํ์ ํ ์นดํ์์ ๋
ธํธ๋ถ์ผ๋ก ์์
ํ๋ ํฌ๋ฆฌ์์ดํฐ</li>
|
212 |
+
<li>ํด๋ณ๊ฐ์์ ๊ณ ๊ธ ์ ๊ธ๋ผ์ค๋ฅผ ๋ผ๊ณ ํฌ์ฆ ์ทจํ๋ ๋ชจ๋ธ</li>
|
213 |
+
<li>ํ๋์ ์ธ ์ฃผ๋ฐฉ์์ ์ต์ ๋ธ๋ ๋๋ก ์ค๋ฌด๋๋ฅผ ๋ง๋๋ ์๋ฆฌ์ฌ</li>
|
214 |
+
</ul>
|
215 |
+
</li>
|
216 |
+
<li><strong>์ธ์ด ํ:</strong> ํ๊ตญ์ด์ ์์ด๋ฅผ ํผํฉํด ์ฌ์ฉํ๋ฉด ๋ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.</li>
|
217 |
+
</ul>
|
218 |
+
</div>
|
219 |
+
""")
|
220 |
+
|
221 |
+
# --- ์คํ ---
|
222 |
+
if __name__ == "__main__":
|
223 |
+
demo.launch(share=True)
|