ssboost commited on
Commit
9fe69b6
·
verified ·
1 Parent(s): 6d2b23f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -378
app.py CHANGED
@@ -4,267 +4,93 @@ import os
4
  import requests
5
  from PIL import Image, ImageDraw, ImageFilter, ImageEnhance
6
  import io
7
- import base64
8
  import tempfile
9
  import numpy as np
10
 
11
- # Replicate API 토큰 설정 (환경변수에서 가져오기)
12
  REPLICATE_API_TOKEN = os.getenv("REPLICATE_API_TOKEN")
13
  if REPLICATE_API_TOKEN:
14
  os.environ["REPLICATE_API_TOKEN"] = REPLICATE_API_TOKEN
15
 
 
 
 
 
 
 
 
 
 
16
  def remove_background_with_ai(image_path):
17
- """AI 이용한 배경 제거"""
18
  if not REPLICATE_API_TOKEN:
19
- return None, "Replicate API 토큰이 설정되지 않았습니다."
20
 
21
  try:
22
- # Replicate Background Remover API 호출
23
  output = replicate.run(
24
  "851-labs/background-remover:a029dff38972b5fda4ec5d75d7d1cd25aeff621d2cf4946a41055d7db66b80bc",
25
- input={
26
- "image": open(image_path, "rb")
27
- }
28
  )
29
 
30
- # 결과 이미지 다운로드
31
  response = requests.get(output)
32
  if response.status_code == 200:
33
- bg_removed_image = Image.open(io.BytesIO(response.content))
34
- return bg_removed_image, "배경 제거 완료"
35
  else:
36
  return None, "배경 제거 실패"
37
 
38
  except Exception as e:
39
- return None, f"배경 제거 오류: {str(e)}"
40
-
41
- def upload_image_to_temp_url(image):
42
- """이미지를 임시 URL로 업로드하는 함수 (실제로는 base64 인코딩)"""
43
- if image is None:
44
- return None
45
-
46
- # PIL Image를 base64로 인코딩
47
- buffer = io.BytesIO()
48
- image.save(buffer, format='PNG')
49
- buffer.seek(0)
50
-
51
- # 임시 파일로 저장
52
- with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp_file:
53
- image.save(tmp_file.name, format='PNG')
54
- return tmp_file.name
55
- """이미지를 임시 URL로 업로드하는 함수 (실제로는 base64 인코딩)"""
56
- if image is None:
57
- return None
58
-
59
- # PIL Image를 base64로 인코딩
60
- buffer = io.BytesIO()
61
- image.save(buffer, format='PNG')
62
- buffer.seek(0)
63
-
64
- # 임시 파일로 저장
65
- with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp_file:
66
- image.save(tmp_file.name, format='PNG')
67
- return tmp_file.name
68
-
69
- def create_perfect_white_background(image, margin=100):
70
- """완전한 흰색 배경 생성"""
71
- if image.mode != 'RGBA':
72
- image = image.convert('RGBA')
73
-
74
- # 원본 이미지 크기
75
- width, height = image.size
76
-
77
- # 여백을 포함한 새로운 크기
78
- new_width = width + margin * 2
79
- new_height = height + margin * 2
80
-
81
- # 완전한 흰색 배경 생성
82
- white_background = Image.new('RGB', (new_width, new_height), (255, 255, 255))
83
-
84
- # 원본 이미지를 중앙에 배치
85
- paste_x = (new_width - width) // 2
86
- paste_y = (new_height - height) // 2
87
-
88
- # 알파 채널이 있는 경우 투명 부분 처리
89
- if image.mode == 'RGBA':
90
- # 투명 배경을 흰색으로 변경
91
- white_bg_temp = Image.new('RGBA', image.size, (255, 255, 255, 255))
92
- alpha_composite = Image.alpha_composite(white_bg_temp, image)
93
- white_background.paste(alpha_composite.convert('RGB'), (paste_x, paste_y))
94
- else:
95
- white_background.paste(image, (paste_x, paste_y))
96
-
97
- return white_background
98
-
99
- def ensure_white_background_85_percent(image):
100
- """85% 흰색 배경 규칙을 확실히 만족시키기"""
101
- # 현재 흰색 비율 확인
102
- is_compliant, white_ratio = check_white_background_ratio(image)
103
-
104
- if not is_compliant:
105
- # 85% 미달시 이미지를 축소하여 흰색 영역 늘리기
106
- current_size = image.size
107
- # 현재 흰색 비율에 따라 축소 비율 계산
108
- target_ratio = 0.87 # 85%보다 약간 여유있게
109
- if white_ratio > 0:
110
- scale_factor = min(0.8, (white_ratio / target_ratio) * 0.9)
111
- else:
112
- scale_factor = 0.7
113
-
114
- new_size = (int(current_size[0] * scale_factor), int(current_size[1] * scale_factor))
115
- resized_image = image.resize(new_size, Image.Resampling.LANCZOS)
116
-
117
- # 완전한 흰색 배경에 축소된 이미지를 중앙 배치
118
- final_image = Image.new('RGB', current_size, (255, 255, 255))
119
- paste_x = (current_size[0] - new_size[0]) // 2
120
- paste_y = (current_size[1] - new_size[1]) // 2
121
- final_image.paste(resized_image, (paste_x, paste_y))
122
-
123
- return final_image
124
-
125
- return image
126
- """흰 배경에 그림자 효과 추가"""
127
- if image.mode != 'RGBA':
128
- image = image.convert('RGBA')
129
-
130
- # 원본 이미지 크기
131
- width, height = image.size
132
-
133
- # 그림자를 위한 여백 추가
134
- shadow_margin = max(shadow_offset) + 20
135
- new_width = width + shadow_margin * 2
136
- new_height = height + shadow_margin * 2
137
-
138
- # 흰색 배경 생성
139
- result = Image.new('RGBA', (new_width, new_height), (255, 255, 255, 255))
140
-
141
- # 그림자 생성
142
- shadow = Image.new('RGBA', (new_width, new_height), (0, 0, 0, 0))
143
- shadow_draw = ImageDraw.Draw(shadow)
144
-
145
- # 원본 이미지의 알파 채널을 이용해 그림자 마스크 생성
146
- alpha = image.split()[-1]
147
- shadow_pos = (shadow_margin + shadow_offset[0], shadow_margin + shadow_offset[1])
148
- shadow.paste(Image.new('RGBA', image.size, (0, 0, 0, int(255 * shadow_intensity))), shadow_pos, alpha)
149
-
150
- # 그림자 블러 효과
151
- shadow = shadow.filter(ImageFilter.GaussianBlur(radius=8))
152
-
153
- # 그림자를 배경에 합성
154
- result = Image.alpha_composite(result, shadow)
155
-
156
- # 원본 이미지를 중앙에 배치
157
- image_pos = (shadow_margin, shadow_margin)
158
- result.paste(image, image_pos, image)
159
-
160
- return result.convert('RGB')
161
-
162
- def enhance_image_quality(image):
163
- """이미지 화질 향상"""
164
- # 선명도 향상
165
- enhancer = ImageEnhance.Sharpness(image)
166
- image = enhancer.enhance(1.2)
167
-
168
- # 대비 향상
169
- enhancer = ImageEnhance.Contrast(image)
170
- image = enhancer.enhance(1.1)
171
-
172
- # 색상 채도 향상
173
- enhancer = ImageEnhance.Color(image)
174
- image = enhancer.enhance(1.05)
175
-
176
- return image
177
 
178
- def change_product_angle_with_ai(image_path, angle_option):
179
- """AI를 이용한 상품 각도/방향 변경으로 아이템 위너 회피"""
180
  if not REPLICATE_API_TOKEN:
181
- return None, "Replicate API 토큰이 설정되지 않았습니다."
182
 
183
  try:
184
- # 각도 변경 프롬프트 옵션 (완전한 흰색 배경 강조)
185
- angle_prompts = {
186
- "왼쪽 45도": "Change the product angle to show it from 45-degree left side view, professional product photography, pure white background #FFFFFF, clean white backdrop, no shadows, solid white background",
187
- "오른쪽 45도": "Change the product angle to show it from 45-degree right side view, professional product photography, pure white background #FFFFFF, clean white backdrop, no shadows, solid white background",
188
- "상단 앵글": "Change to top-down angle view of the product, bird's eye view, professional product photography, pure white background #FFFFFF, clean white backdrop, no shadows, solid white background",
189
- "3/4 뷰": "Change to 3/4 angle view of the product, three-quarter perspective, professional product photography, pure white background #FFFFFF, clean white backdrop, no shadows, solid white background",
190
- "정면에서 측면": "Change from front view to side view of the product, profile angle, professional product photography, pure white background #FFFFFF, clean white backdrop, no shadows, solid white background",
191
- "측면에서 정면": "Change from side view to front view of the product, frontal angle, professional product photography, pure white background #FFFFFF, clean white backdrop, no shadows, solid white background"
192
- }
193
-
194
- selected_prompt = angle_prompts.get(angle_option, angle_prompts["3/4 뷰"])
195
-
196
- # Replicate API 호출
197
  output = replicate.run(
198
- "black-forest-labs/flux-kontext-pro",
199
- input={
200
- "prompt": selected_prompt,
201
- "input_image": open(image_path, "rb"),
202
- "output_format": "jpg"
203
- }
204
  )
205
 
206
- # 결과 이미지 다운로드
207
- response = requests.get(output)
208
  if response.status_code == 200:
209
- angled_image = Image.open(io.BytesIO(response.content))
210
- return angled_image, f"상품 각도 변경 완료: {angle_option}"
211
  else:
212
- return None, "각도 변경 실패"
213
 
214
  except Exception as e:
215
- return None, f"각도 변경 오류: {str(e)}"
216
-
217
- def check_white_background_ratio(image, threshold=0.85):
218
- """흰색 배경 비율 확인 (85% 규칙)"""
219
- if image.mode != 'RGB':
220
- image = image.convert('RGB')
221
-
222
- pixels = np.array(image)
223
- white_pixels = np.sum(np.all(pixels >= [240, 240, 240], axis=2))
224
- total_pixels = pixels.shape[0] * pixels.shape[1]
225
- white_ratio = white_pixels / total_pixels
226
-
227
- return white_ratio >= threshold, white_ratio
228
 
229
- def process_with_ai_enhancement(image_path, prompt_option):
230
- """AI를 이용한 이미지 품질 향상"""
231
  if not REPLICATE_API_TOKEN:
232
- return None, "Replicate API 토큰이 설정되지 않았습니다."
233
 
234
  try:
235
- # 프롬프트 옵션별 설정 (완전한 흰색 배경 강조)
236
- prompts = {
237
- "기본 품질향상": "Enhance image quality, make it more professional and crisp, pure white background #FFFFFF, clean white backdrop, no shadows, solid white background",
238
- "제품 사진 최적화": "Transform into professional product photography, clean pure white background #FFFFFF, high quality, studio lighting, solid white backdrop, no shadows",
239
- "쿠팡 스타일": "Make it look like a professional e-commerce product photo for Korean online shopping, clean pure white background #FFFFFF, perfect lighting, solid white backdrop, no shadows",
240
- "프리미엄 느낌": "Make it look premium and luxury, professional product shot, perfect pure white background #FFFFFF, studio quality, clean white backdrop, no shadows, solid white background"
241
- }
242
-
243
- selected_prompt = prompts.get(prompt_option, prompts["기본 품질향상"])
244
 
245
- # Replicate API 호출
246
  output = replicate.run(
247
  "black-forest-labs/flux-kontext-pro",
248
  input={
249
- "prompt": selected_prompt,
250
  "input_image": open(image_path, "rb"),
251
  "output_format": "jpg"
252
  }
253
  )
254
 
255
- # 결과 이미지 다운로드
256
  response = requests.get(output)
257
  if response.status_code == 200:
258
- enhanced_image = Image.open(io.BytesIO(response.content))
259
- return enhanced_image, "AI 향상 완료"
260
  else:
261
- return None, "AI 처리 실패"
262
 
263
  except Exception as e:
264
- return None, f"AI 처리 오류: {str(e)}"
265
 
266
- def create_coupang_thumbnail(image, auto_remove_bg, white_bg_mode, apply_angle_change, angle_option, ai_enhancement, prompt_option):
267
- """쿠팡 썸네일 생성 메인 함수"""
268
  if image is None:
269
  return None, "이미지를 업로드해주세요."
270
 
@@ -272,213 +98,95 @@ def create_coupang_thumbnail(image, auto_remove_bg, white_bg_mode, apply_angle_c
272
  result_image = image.copy()
273
  status_messages = []
274
 
275
- # 0단계: 자동 배경 제거 (선택사항)
276
- if auto_remove_bg and REPLICATE_API_TOKEN:
277
  temp_path = upload_image_to_temp_url(result_image)
278
  if temp_path:
279
  bg_removed_img, bg_msg = remove_background_with_ai(temp_path)
280
  if bg_removed_img:
281
  result_image = bg_removed_img
282
- status_messages.append(f"✅ 자동 배경 제거: {bg_msg}")
283
  else:
284
- status_messages.append(f"❌ 배경 제거: {bg_msg}")
285
- os.unlink(temp_path) # 임시 파일 삭제
286
- elif auto_remove_bg and not REPLICATE_API_TOKEN:
287
- status_messages.append("⚠️ 배경 제거에는 Replicate API 토큰이 필요합니다")
288
 
289
- # 1단계: 상품 각도 변경 (아이템 위너 회피)
290
- if apply_angle_change and REPLICATE_API_TOKEN:
291
  temp_path = upload_image_to_temp_url(result_image)
292
  if temp_path:
293
- angled_img, angle_msg = change_product_angle_with_ai(temp_path, angle_option)
294
- if angled_img:
295
- result_image = angled_img
296
- status_messages.append(f"✅ 상품 각도 변경: {angle_msg}")
297
  else:
298
- status_messages.append(f"❌ 각도 변경: {angle_msg}")
299
- os.unlink(temp_path) # 임시 파일 삭제
300
- elif apply_angle_change and not REPLICATE_API_TOKEN:
301
- status_messages.append("⚠️ 각도 변경에는 Replicate API 토큰이 필요합니다")
302
-
303
- # 2단계: AI 품질 향상 (선택사항)
304
- if ai_enhancement and REPLICATE_API_TOKEN:
305
- temp_path = upload_image_to_temp_url(result_image)
306
- if temp_path:
307
- enhanced_img, ai_msg = process_with_ai_enhancement(temp_path, prompt_option)
308
- if enhanced_img:
309
- result_image = enhanced_img
310
- status_messages.append(f"✅ AI 향상: {ai_msg}")
311
- else:
312
- status_messages.append(f"❌ AI 향상: {ai_msg}")
313
- os.unlink(temp_path) # 임시 파일 삭제
314
-
315
- # 3단계: 화질 향상
316
- result_image = enhance_image_quality(result_image)
317
- status_messages.append("✅ 화질 향상 완료")
318
-
319
- # 4단계: 배경 처리 (흰색 배경 모드 선택)
320
- if white_bg_mode == "완전한 흰색":
321
- result_image = create_perfect_white_background(result_image)
322
- status_messages.append("✅ 완전한 흰색 배경 적용")
323
- elif white_bg_mode == "그림자 효과":
324
- result_image = create_white_background_shadow(result_image)
325
- status_messages.append("✅ 그림자 효과가 있는 흰색 배경 적용")
326
- else: # "기본 흰색"
327
- # 그림자 없이 흰 배경만 적용
328
- if result_image.mode == 'RGBA':
329
- white_bg = Image.new('RGB', result_image.size, (255, 255, 255))
330
- white_bg.paste(result_image, mask=result_image.split()[-1] if result_image.mode == 'RGBA' else None)
331
- result_image = white_bg
332
- status_messages.append("✅ 기본 흰색 배경 적용")
333
-
334
- # 5단계: 85% 흰색 배경 규칙 강제 적용
335
- result_image = ensure_white_background_85_percent(result_image)
336
-
337
- # 85% 흰색 배경 규칙 확인
338
- is_compliant, white_ratio = check_white_background_ratio(result_image)
339
- if is_compliant:
340
- status_messages.append(f"✅ 85% 흰색 배경 규칙 준수 ({white_ratio:.1%})")
341
- else:
342
- status_messages.append(f"⚠️ 흰색 배경 비율: ({white_ratio:.1%}) - 추가 조정 필요")
343
-
344
- # 최종 이미지 크기 조정 (쿠팡 권장 사이즈)
345
- result_image = result_image.resize((1000, 1000), Image.Resampling.LANCZOS)
346
- status_messages.append("✅ 1000x1000 크기로 조정 완료")
347
 
348
  return result_image, "\n".join(status_messages)
349
 
350
  except Exception as e:
351
- return None, f"처리 중 오류가 발생했습니다: {str(e)}"
352
 
353
- # Gradio 인터페이스 생성
354
  def create_interface():
355
- with gr.Blocks(title="🛒 쿠팡 썸네일 생성기", theme=gr.themes.Soft()) as iface:
356
- gr.Markdown("""
357
- # 쿠팡 썸네일 생성기 - Gradio 5.0+
358
-
359
- 일반 상품 이미지를 업로드하면 **자동 배경 제거 → 쿠팡 규정 준수 썸네일**로 한 번에 변환해드립니다!
360
-
361
- ## 💡 완전 자동화된 쿠팡 규정 대응:
362
- - 🎯 **자동 배경 제거** (AI 기반)
363
- - ✅ **흰 배경 + 85% 규칙** 완벽 준수
364
- - ✅ **AI 마법 프롬프트**로 화질 향상
365
- - ✅ **상품 각도 변경**으로 아이템 위너(중복) 회피
366
- - ✅ **그림자 효과**로 자연스러운 입체감 연출
367
- """)
368
 
369
  with gr.Row():
370
  with gr.Column(scale=1):
371
- gr.Markdown("### 📤 이미지 업로드")
372
  input_image = gr.Image(
373
- label="상품 이미지 (배경 있어도 OK!)",
374
  type="pil",
375
- height=300
376
  )
377
 
378
- gr.Markdown("### ⚙️ 옵션 설정")
379
-
380
  with gr.Group():
381
- gr.Markdown("**🔧 전처리 옵션**")
382
- auto_remove_bg = gr.Checkbox(
383
- label="자동 배경 제거",
384
  value=True,
385
- info="AI로 배경을 자동 제거 (Replicate API 필요)"
386
- )
387
-
388
- with gr.Group():
389
- gr.Markdown("**🎨 배경 옵션**")
390
- white_bg_mode = gr.Radio(
391
- choices=["완전한 흰색", "그림자 효과", "기본 흰색"],
392
- value="완전한 흰색",
393
- label="흰색 배경 모드",
394
- info="완전한 흰색: 100% 순백색 / 그림자 효과: 입체감 연출 / 기본 흰색: 단순 배경"
395
  )
396
- apply_angle_change = gr.Checkbox(
397
- label="상품 각도 변경 (아이템 위너 회피)",
398
  value=True,
399
- info="AI로 상품의 각도/방향을 변경하여 중복 회피"
400
- )
401
- angle_option = gr.Dropdown(
402
- choices=["왼쪽 45도", "오른쪽 45도", "상단 앵글", "3/4 뷰", "정면에서 측면", "측면에서 정면"],
403
- value="3/4 뷰",
404
- label="변경할 각도",
405
- info="상품을 어떤 각도로 변경할지 선택",
406
- visible=True
407
- )
408
-
409
- with gr.Group():
410
- gr.Markdown("**🤖 AI 향상 (Replicate API 필요)**")
411
- ai_enhancement = gr.Checkbox(
412
- label="AI 품질 향상 사용",
413
- value=False,
414
- info="Replicate API 토큰이 필요합니다"
415
- )
416
- prompt_option = gr.Dropdown(
417
- choices=["기본 품질향상", "제품 사진 최적화", "쿠팡 스타일", "프리미엄 느낌"],
418
- value="쿠팡 스타일",
419
- label="AI 향상 스타일"
420
  )
421
 
422
- process_btn = gr.Button("🚀 쿠팡 썸네일 생성", variant="primary", size="lg")
 
423
 
424
  with gr.Column(scale=1):
425
- gr.Markdown("### 📥 결과")
426
  output_image = gr.Image(
427
- label="쿠팡 규정 썸네일",
428
  height=400
429
  )
430
  status_output = gr.Textbox(
431
  label="처리 상태",
432
- lines=8,
433
- max_lines=15
434
  )
435
 
436
- # 사용 예시
437
- gr.Markdown("""
438
- ---
439
- ## 📋 사용 방법
440
- 1. **일반 상품 이미지**를 업로드하세요 (배경 있어도 OK!)
441
- 2. **자동 배경 제거** 옵션을 켜두세요 (기본값)
442
- 3. **상품 각도 변경 옵션**을 선택하여 아이템 위너(중복)를 회피하세요
443
- 4. 원하는 **효과 옵션**을 선택하세요
444
- 5. **Replicate API 토큰**을 환경변수로 설정하세요 (필수)
445
- 6. **'쿠팡 썸네일 생성'** 버튼을 클릭하세요
446
-
447
- ## 🔄 완전 자동화 워크플로우
448
- **원본 이미지** → **배경 제거** → **각도 변경** → **품질 향상** → **쿠팡 규정 썸네일**
449
-
450
- ## 🎯 상품 각도 변경 옵션 설명
451
- - **왼쪽 45도**: 상품을 왼쪽에서 45도 각도로 촬영한 느낌
452
- - **오른쪽 45도**: 상품을 오른쪽에서 45도 각도로 촬영한 느낌
453
- - **상단 앵글**: 위에서 내려다본 탑뷰 각도
454
- - **3/4 뷰**: 가장 일반적인 상품 촬영 각도 (추천)
455
- - **정면에서 측면**: 정면 이미지를 측면 각도로 변경
456
- - **측면에서 정면**: 측면 이미지를 정면 각도로 변경
457
-
458
- ## 🔑 API 설정 (선택사항)
459
- AI 향상 기능을 사용하려면 환경변수를 설정하세요:
460
- ```bash
461
- export REPLICATE_API_TOKEN=your_token_here
462
- ```
463
- """)
464
-
465
- # 이벤트 처리
466
- def update_angle_visibility(apply_angle):
467
- return gr.update(visible=apply_angle)
468
-
469
- apply_angle_change.change(update_angle_visibility, apply_angle_change, angle_option)
470
-
471
  process_btn.click(
472
- create_coupang_thumbnail,
473
- inputs=[
474
- input_image,
475
- auto_remove_bg,
476
- white_bg_mode,
477
- apply_angle_change,
478
- angle_option,
479
- ai_enhancement,
480
- prompt_option
481
- ],
482
  outputs=[output_image, status_output]
483
  )
484
 
 
4
  import requests
5
  from PIL import Image, ImageDraw, ImageFilter, ImageEnhance
6
  import io
 
7
  import tempfile
8
  import numpy as np
9
 
10
+ # Replicate API 토큰 설정
11
  REPLICATE_API_TOKEN = os.getenv("REPLICATE_API_TOKEN")
12
  if REPLICATE_API_TOKEN:
13
  os.environ["REPLICATE_API_TOKEN"] = REPLICATE_API_TOKEN
14
 
15
+ def upload_image_to_temp_url(image):
16
+ """이미지를 임시 파일로 저장"""
17
+ if image is None:
18
+ return None
19
+
20
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp_file:
21
+ image.save(tmp_file.name, format='PNG')
22
+ return tmp_file.name
23
+
24
  def remove_background_with_ai(image_path):
25
+ """AI 배경 제거"""
26
  if not REPLICATE_API_TOKEN:
27
+ return None, "Replicate API 토큰이 필요합니다."
28
 
29
  try:
 
30
  output = replicate.run(
31
  "851-labs/background-remover:a029dff38972b5fda4ec5d75d7d1cd25aeff621d2cf4946a41055d7db66b80bc",
32
+ input={"image": open(image_path, "rb")}
 
 
33
  )
34
 
 
35
  response = requests.get(output)
36
  if response.status_code == 200:
37
+ return Image.open(io.BytesIO(response.content)), "배경 제거 완료"
 
38
  else:
39
  return None, "배경 제거 실패"
40
 
41
  except Exception as e:
42
+ return None, f"배경 제거 오류: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ def upscale_with_clarity(image_path):
45
+ """화질 개선 업스케일러"""
46
  if not REPLICATE_API_TOKEN:
47
+ return None, "Replicate API 토큰이 필요합니다."
48
 
49
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  output = replicate.run(
51
+ "philz1337x/clarity-upscaler:dfad41707589d68ecdccd1dfa600d55a208f9310748e44bfe35b4a6291453d5e",
52
+ input={"image": open(image_path, "rb")}
 
 
 
 
53
  )
54
 
55
+ # output은 리스트이므로 첫 번째 항목 사용
56
+ response = requests.get(output[0])
57
  if response.status_code == 200:
58
+ return Image.open(io.BytesIO(response.content)), "화질 개선 완료"
 
59
  else:
60
+ return None, "화질 개선 실패"
61
 
62
  except Exception as e:
63
+ return None, f"화질 개선 오류: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ def create_coupang_thumbnail_fixed(image_path):
66
+ """고정된 설정으로 쿠팡 썸네일 생성"""
67
  if not REPLICATE_API_TOKEN:
68
+ return None, "Replicate API 토큰이 필요합니다."
69
 
70
  try:
71
+ # 고정된 프롬프트: 완전한 흰색배경, 85%상품이미지, 그림자효과, 3/4뷰 고정
72
+ fixed_prompt = "Professional product photography, 3/4 angle view, pure white background #FFFFFF, natural soft shadows, clean white backdrop, high quality e-commerce photo, solid white background, product takes 85% of image space"
 
 
 
 
 
 
 
73
 
 
74
  output = replicate.run(
75
  "black-forest-labs/flux-kontext-pro",
76
  input={
77
+ "prompt": fixed_prompt,
78
  "input_image": open(image_path, "rb"),
79
  "output_format": "jpg"
80
  }
81
  )
82
 
 
83
  response = requests.get(output)
84
  if response.status_code == 200:
85
+ return Image.open(io.BytesIO(response.content)), "썸네일 생성 완료"
 
86
  else:
87
+ return None, "썸네일 생성 실패"
88
 
89
  except Exception as e:
90
+ return None, f"썸네일 생성 오류: {str(e)}"
91
 
92
+ def process_image(image, remove_bg, upscale_quality):
93
+ """메인 처리 함수"""
94
  if image is None:
95
  return None, "이미지를 업로드해주세요."
96
 
 
98
  result_image = image.copy()
99
  status_messages = []
100
 
101
+ # 1단계: 배경 제거 (선택사항)
102
+ if remove_bg:
103
  temp_path = upload_image_to_temp_url(result_image)
104
  if temp_path:
105
  bg_removed_img, bg_msg = remove_background_with_ai(temp_path)
106
  if bg_removed_img:
107
  result_image = bg_removed_img
108
+ status_messages.append(f"✅ {bg_msg}")
109
  else:
110
+ status_messages.append(f"❌ {bg_msg}")
111
+ os.unlink(temp_path)
 
 
112
 
113
+ # 2단계: 화질 개선 (선택사항)
114
+ if upscale_quality:
115
  temp_path = upload_image_to_temp_url(result_image)
116
  if temp_path:
117
+ upscaled_img, upscale_msg = upscale_with_clarity(temp_path)
118
+ if upscaled_img:
119
+ result_image = upscaled_img
120
+ status_messages.append(f"✅ {upscale_msg}")
121
  else:
122
+ status_messages.append(f"❌ {upscale_msg}")
123
+ os.unlink(temp_path)
124
+
125
+ # 3단계: 쿠팡 썸네일 생성 (고정 설정)
126
+ temp_path = upload_image_to_temp_url(result_image)
127
+ if temp_path:
128
+ final_img, final_msg = create_coupang_thumbnail_fixed(temp_path)
129
+ if final_img:
130
+ result_image = final_img
131
+ status_messages.append(f"✅ {final_msg}")
132
+
133
+ # 최종 크기 조정
134
+ result_image = result_image.resize((1000, 1000), Image.Resampling.LANCZOS)
135
+ status_messages.append("✅ 1000x1000 크기 조정 완료")
136
+ else:
137
+ status_messages.append(f"❌ {final_msg}")
138
+ os.unlink(temp_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  return result_image, "\n".join(status_messages)
141
 
142
  except Exception as e:
143
+ return None, f"처리 중 오류: {str(e)}"
144
 
145
+ # Gradio 인터페이스
146
  def create_interface():
147
+ with gr.Blocks(title="쿠팡 썸네일 생성기", theme=gr.themes.Soft()) as iface:
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
  with gr.Row():
150
  with gr.Column(scale=1):
151
+ # 이미지 업로드
152
  input_image = gr.Image(
153
+ label="상품 이미지 업로드",
154
  type="pil",
155
+ height=400
156
  )
157
 
158
+ # 선택 기능 2가지
 
159
  with gr.Group():
160
+ remove_bg = gr.Checkbox(
161
+ label="배경 제거",
 
162
  value=True,
163
+ info="AI로 배경을 자동 제거합니다"
 
 
 
 
 
 
 
 
 
164
  )
165
+ upscale_quality = gr.Checkbox(
166
+ label="화질 개선기",
167
  value=True,
168
+ info="AI로 화질을 향상시킵니다"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  )
170
 
171
+ # 실행 버튼
172
+ process_btn = gr.Button("🚀 썸네일 생성", variant="primary", size="lg")
173
 
174
  with gr.Column(scale=1):
175
+ # 출력 이미지
176
  output_image = gr.Image(
177
+ label="쿠팡 썸네일 결과",
178
  height=400
179
  )
180
  status_output = gr.Textbox(
181
  label="처리 상태",
182
+ lines=6,
183
+ max_lines=10
184
  )
185
 
186
+ # 버튼 클릭 이벤트
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  process_btn.click(
188
+ process_image,
189
+ inputs=[input_image, remove_bg, upscale_quality],
 
 
 
 
 
 
 
 
190
  outputs=[output_image, status_output]
191
  )
192