Kims12 commited on
Commit
fd7e6af
ยท
verified ยท
1 Parent(s): 654ca6d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -38
app.py CHANGED
@@ -47,16 +47,31 @@ def merge_images(person_img_path, product_img_path, background_img_path, prompt,
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
  # ์ƒ์„ฑ ์„ค์ •
@@ -65,7 +80,7 @@ def merge_images(person_img_path, product_img_path, background_img_path, prompt,
65
  top_p=0.95,
66
  top_k=40,
67
  max_output_tokens=8192,
68
- response_modalities=["text", "image"],
69
  )
70
  logger.debug(f"์ƒ์„ฑ ์„ค์ •: {generate_content_config}")
71
 
@@ -73,43 +88,70 @@ def merge_images(person_img_path, product_img_path, background_img_path, prompt,
73
  temp_path = tmp.name
74
  logger.debug(f"์ž„์‹œ ํŒŒ์ผ ์ƒ์„ฑ๋จ: {temp_path}")
75
 
76
- # ๋‹จ์ผ ์š”์ฒญ์œผ๋กœ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
77
- response = client.models.generate_content(
78
  model=model,
79
- contents=contents,
 
 
 
 
 
80
  config=generate_content_config,
81
  )
82
 
83
- logger.debug("์‘๋‹ต ์ฒ˜๋ฆฌ ์‹œ์ž‘...")
84
 
85
  # ์‘๋‹ต์—์„œ ์ด๋ฏธ์ง€์™€ ํ…์ŠคํŠธ ์ถ”์ถœ
86
  image_saved = False
87
  response_text = ""
88
 
89
- for part in response.candidates[0].content.parts:
90
- if hasattr(part, 'text') and part.text:
91
- response_text += part.text
92
- logger.info(f"์ˆ˜์‹ ๋œ ํ…์ŠคํŠธ: {part.text}")
93
- elif hasattr(part, 'inline_data') and part.inline_data:
94
- save_binary_file(temp_path, part.inline_data.data)
95
- logger.info(f"MIME ํƒ€์ž… {part.inline_data.mime_type}์˜ ํŒŒ์ผ์ด ์ €์žฅ๋จ: {temp_path}")
96
- image_saved = True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
  if not image_saved:
99
  logger.warning("์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
100
- return None, response_text
101
 
102
  logger.debug("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ.")
103
  return temp_path, response_text
104
 
105
  except Exception as e:
106
  logger.exception("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
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:
@@ -125,22 +167,34 @@ def process_images_and_prompt(person_pil, product_pil, background_pil, prompt):
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:
129
  person_path = tmp_person.name
130
- person_pil.save(person_path)
 
 
 
 
131
  logger.debug(f"์‚ฌ๋žŒ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {person_path}")
132
 
133
- with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_product:
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
  # ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ ์‹คํ–‰
@@ -154,27 +208,31 @@ def process_images_and_prompt(person_pil, product_pil, background_pil, prompt):
154
  # ์ด๋ฏธ์ง€ ๋ฐ˜ํ™˜ ๋ฐ ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
155
  if result_path:
156
  logger.debug(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ. ๊ฒฝ๋กœ: {result_path}")
157
- result_img = Image.open(result_path)
158
- if result_img.mode == "RGBA":
159
- result_img = result_img.convert("RGB")
160
-
161
- # ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
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:
176
  logger.exception("process_images_and_prompt ํ•จ์ˆ˜์—์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
177
- return [], str(e) # ์˜ค๋ฅ˜ ๏ฟฝ๏ฟฝ ๋นˆ ๋ฆฌ์ŠคํŠธ์™€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
178
 
179
 
180
  # --- Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ ---
 
47
  product_img = Image.open(product_img_path)
48
 
49
  # ์ปจํ…์ธ  ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ
50
+ contents = []
51
+
52
+ # ์‚ฌ๋žŒ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€
53
+ contents.append(
54
+ types.Part.from_data(data=person_img, mime_type="image/jpeg")
55
+ )
56
+
57
+ # ์ƒํ’ˆ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€
58
+ contents.append(
59
+ types.Part.from_data(data=product_img, mime_type="image/jpeg")
60
+ )
61
 
62
  # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์œผ๋ฉด ์ถ”๊ฐ€
63
  if background_img_path:
64
  background_img = Image.open(background_img_path)
65
+ contents.append(
66
+ types.Part.from_data(data=background_img, mime_type="image/jpeg")
67
+ )
68
  logger.debug("๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€๋จ")
69
 
70
  # ๋งˆ์ง€๋ง‰์— ํ”„๋กฌํ”„ํŠธ ์ถ”๊ฐ€
71
+ contents.append(
72
+ types.Part.from_text(text=prompt)
73
+ )
74
+
75
  logger.debug(f"์ปจํ…์ธ  ๊ฐ์ฒด ์ƒ์„ฑ ์™„๋ฃŒ: {len(contents)} ์•„์ดํ…œ")
76
 
77
  # ์ƒ์„ฑ ์„ค์ •
 
80
  top_p=0.95,
81
  top_k=40,
82
  max_output_tokens=8192,
83
+ response_modalities=["image", "text"],
84
  )
85
  logger.debug(f"์ƒ์„ฑ ์„ค์ •: {generate_content_config}")
86
 
 
88
  temp_path = tmp.name
89
  logger.debug(f"์ž„์‹œ ํŒŒ์ผ ์ƒ์„ฑ๋จ: {temp_path}")
90
 
91
+ # ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ ์ˆ˜์‹  (์›๋ž˜ ์ฝ”๋“œ ๋ฐฉ์‹์œผ๋กœ ๋ณต์›)
92
+ response_stream = client.models.generate_content_stream(
93
  model=model,
94
+ contents=[
95
+ types.Content(
96
+ role="user",
97
+ parts=contents,
98
+ ),
99
+ ],
100
  config=generate_content_config,
101
  )
102
 
103
+ logger.debug("์‘๋‹ต ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ ์‹œ์ž‘...")
104
 
105
  # ์‘๋‹ต์—์„œ ์ด๋ฏธ์ง€์™€ ํ…์ŠคํŠธ ์ถ”์ถœ
106
  image_saved = False
107
  response_text = ""
108
 
109
+ for chunk in response_stream:
110
+ logger.debug(f"chunk ์ˆ˜์‹ : {chunk}")
111
+
112
+ # ์‘๋‹ต ๊ฒ€์ฆ
113
+ if not hasattr(chunk, 'candidates') or not chunk.candidates:
114
+ logger.warning("chunk์— candidates๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.")
115
+ continue
116
+
117
+ if not hasattr(chunk.candidates[0], 'content') or not chunk.candidates[0].content:
118
+ logger.warning("chunk.candidates[0]์— content๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.")
119
+ continue
120
+
121
+ if not hasattr(chunk.candidates[0].content, 'parts') or not chunk.candidates[0].content.parts:
122
+ logger.warning("chunk.candidates[0].content์— parts๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.")
123
+ continue
124
+
125
+ for part in chunk.candidates[0].content.parts:
126
+ if hasattr(part, 'text') and part.text:
127
+ response_text += part.text
128
+ logger.info(f"์ˆ˜์‹ ๋œ ํ…์ŠคํŠธ: {part.text}")
129
+ elif hasattr(part, 'inline_data') and part.inline_data:
130
+ save_binary_file(temp_path, part.inline_data.data)
131
+ logger.info(f"MIME ํƒ€์ž… {part.inline_data.mime_type}์˜ ํŒŒ์ผ์ด ์ €์žฅ๋จ: {temp_path}")
132
+ image_saved = True
133
 
134
  if not image_saved:
135
  logger.warning("์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
136
+ return None, response_text or "์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ”„๋กฌํ”„ํŠธ๋‚˜ ์ด๋ฏธ์ง€๋กœ ์‹œ๋„ํ•ด๋ณด์„ธ์š”."
137
 
138
  logger.debug("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ.")
139
  return temp_path, response_text
140
 
141
  except Exception as e:
142
  logger.exception("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
143
+ return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}" # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ None๊ณผ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
144
 
145
 
146
  def process_images_and_prompt(person_pil, product_pil, background_pil, prompt):
147
  logger.debug(f"process_images_and_prompt ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: '{prompt}'")
148
  try:
149
+ # ํ•„์ˆ˜ ์ด๋ฏธ์ง€ ํ™•์ธ
150
+ if person_pil is None:
151
+ return [], "์‚ฌ๋žŒ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”."
152
+ if product_pil is None:
153
+ return [], "์ƒํ’ˆ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”."
154
+
155
  # ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ์„ค์ • (๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ)
156
  if not prompt or not prompt.strip():
157
  if background_pil:
 
167
  prompt += " Create a realistic composite image of this person with this product."
168
 
169
  # ์ด๋ฏธ์ง€ ์ €์žฅ
170
+ with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_person:
171
  person_path = tmp_person.name
172
+ # RGB๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅ
173
+ person_img = person_pil
174
+ if person_img.mode != 'RGB':
175
+ person_img = person_img.convert('RGB')
176
+ person_img.save(person_path, 'JPEG')
177
  logger.debug(f"์‚ฌ๋žŒ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {person_path}")
178
 
179
+ with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_product:
180
  product_path = tmp_product.name
181
+ # RGB๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅ
182
+ product_img = product_pil
183
+ if product_img.mode != 'RGB':
184
+ product_img = product_img.convert('RGB')
185
+ product_img.save(product_path, 'JPEG')
186
  logger.debug(f"์ƒํ’ˆ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {product_path}")
187
 
188
  # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ €์žฅ (์žˆ๋Š” ๊ฒฝ์šฐ)
189
  background_path = None
190
  if background_pil is not None:
191
+ with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_bg:
192
  background_path = tmp_bg.name
193
+ # RGB๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅ
194
+ background_img = background_pil
195
+ if background_img.mode != 'RGB':
196
+ background_img = background_img.convert('RGB')
197
+ background_img.save(background_path, 'JPEG')
198
  logger.debug(f"๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {background_path}")
199
 
200
  # ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ ์‹คํ–‰
 
208
  # ์ด๋ฏธ์ง€ ๋ฐ˜ํ™˜ ๋ฐ ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
209
  if result_path:
210
  logger.debug(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ. ๊ฒฝ๋กœ: {result_path}")
 
 
 
 
 
211
  try:
212
+ result_img = Image.open(result_path)
213
+ if result_img.mode == "RGBA":
214
+ result_img = result_img.convert("RGB")
215
+
216
+ # ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
217
+ try:
218
+ os.unlink(person_path)
219
+ os.unlink(product_path)
220
+ if background_path:
221
+ os.unlink(background_path)
222
+ except Exception as e:
223
+ logger.warning(f"์ž„์‹œ ํŒŒ์ผ ์‚ญ์ œ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
224
+
225
+ return [result_img], response_text or "์ด๋ฏธ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
226
  except Exception as e:
227
+ logger.exception(f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
228
+ return [], f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {str(e)}"
 
229
  else:
230
  logger.error("merge_images ํ•จ์ˆ˜์—์„œ None ๋ฐ˜ํ™˜๋จ.")
231
+ return [], response_text or "์ด๋ฏธ์ง€ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋‚˜ ํ”„๋กฌํ”„ํŠธ๋กœ ์‹œ๋„ํ•ด๋ณด์„ธ์š”."
232
 
233
  except Exception as e:
234
  logger.exception("process_images_and_prompt ํ•จ์ˆ˜์—์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
235
+ return [], f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}" # ์˜ค๋ฅ˜ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ์™€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜
236
 
237
 
238
  # --- Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ ---