|
import gradio as gr |
|
import replicate |
|
import os |
|
import requests |
|
from PIL import Image, ImageDraw, ImageFilter, ImageEnhance |
|
import io |
|
import tempfile |
|
import numpy as np |
|
|
|
|
|
REPLICATE_API_TOKEN = os.getenv("REPLICATE_API_TOKEN") |
|
if REPLICATE_API_TOKEN: |
|
os.environ["REPLICATE_API_TOKEN"] = REPLICATE_API_TOKEN |
|
|
|
def upload_image_to_temp_url(image): |
|
"""์ด๋ฏธ์ง๋ฅผ ์์ ํ์ผ๋ก ์ ์ฅ""" |
|
if image is None: |
|
return None |
|
|
|
with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp_file: |
|
image.save(tmp_file.name, format='PNG') |
|
return tmp_file.name |
|
|
|
def remove_background_with_ai(image_path): |
|
"""AI ๋ฐฐ๊ฒฝ ์ ๊ฑฐ""" |
|
if not REPLICATE_API_TOKEN: |
|
return None, "Replicate API ํ ํฐ์ด ํ์ํฉ๋๋ค." |
|
|
|
try: |
|
output = replicate.run( |
|
"851-labs/background-remover:a029dff38972b5fda4ec5d75d7d1cd25aeff621d2cf4946a41055d7db66b80bc", |
|
input={"image": open(image_path, "rb")} |
|
) |
|
|
|
response = requests.get(output) |
|
if response.status_code == 200: |
|
return Image.open(io.BytesIO(response.content)), "๋ฐฐ๊ฒฝ ์ ๊ฑฐ ์๋ฃ" |
|
else: |
|
return None, "๋ฐฐ๊ฒฝ ์ ๊ฑฐ ์คํจ" |
|
|
|
except Exception as e: |
|
return None, f"๋ฐฐ๊ฒฝ ์ ๊ฑฐ ์ค๋ฅ: {str(e)}" |
|
|
|
def upscale_with_clarity(image_path): |
|
"""ํ์ง ๊ฐ์ ์
์ค์ผ์ผ๋ฌ""" |
|
if not REPLICATE_API_TOKEN: |
|
return None, "Replicate API ํ ํฐ์ด ํ์ํฉ๋๋ค." |
|
|
|
try: |
|
output = replicate.run( |
|
"philz1337x/clarity-upscaler:dfad41707589d68ecdccd1dfa600d55a208f9310748e44bfe35b4a6291453d5e", |
|
input={"image": open(image_path, "rb")} |
|
) |
|
|
|
|
|
response = requests.get(output[0]) |
|
if response.status_code == 200: |
|
return Image.open(io.BytesIO(response.content)), "ํ์ง ๊ฐ์ ์๋ฃ" |
|
else: |
|
return None, "ํ์ง ๊ฐ์ ์คํจ" |
|
|
|
except Exception as e: |
|
return None, f"ํ์ง ๊ฐ์ ์ค๋ฅ: {str(e)}" |
|
|
|
def change_product_angle(image_path): |
|
"""์นด๋ฉ๋ผ ์์น๋ฅผ ๋ฐ๊ฟ์ ๋ค๋ฅธ ์ต๊ธ๋ก ์ดฌ์""" |
|
if not REPLICATE_API_TOKEN: |
|
return None, "Replicate API ํ ํฐ์ด ํ์ํฉ๋๋ค." |
|
|
|
try: |
|
|
|
angle_prompt = "Professional product photography of @product from 45-degree side angle, three-quarter view, diagonal perspective, different camera position, clean background" |
|
|
|
with open(image_path, "rb") as image_file: |
|
output = replicate.run( |
|
"runwayml/gen4-image", |
|
input={ |
|
"prompt": angle_prompt, |
|
"aspect_ratio": "1:1", |
|
"resolution": "1080p", |
|
"reference_images": [image_file], |
|
"reference_tags": ["product"] |
|
} |
|
) |
|
|
|
response = requests.get(output) |
|
if response.status_code == 200: |
|
return Image.open(io.BytesIO(response.content)), "์นด๋ฉ๋ผ ์ต๊ธ ๋ณ๊ฒฝ ์๋ฃ (Gen4)" |
|
else: |
|
return None, "์นด๋ฉ๋ผ ์ต๊ธ ๋ณ๊ฒฝ ์คํจ" |
|
|
|
except Exception as e: |
|
return None, f"์นด๋ฉ๋ผ ์ต๊ธ ๋ณ๊ฒฝ ์ค๋ฅ: {str(e)}" |
|
|
|
def add_shadow_only(image_path): |
|
"""๋ฐฐ๊ฒฝ ์ ๊ฑฐ๋ ์ํ์ ๊ทธ๋ฆผ์๋ง ์ถ๊ฐ (์์ ํ ํฐ์ ๋ฐฐ๊ฒฝ)""" |
|
if not REPLICATE_API_TOKEN: |
|
return None, "Replicate API ํ ํฐ์ด ํ์ํฉ๋๋ค." |
|
|
|
try: |
|
|
|
shadow_prompt = "Professional product photography of @product on pure white background with natural soft drop shadow, clean white backdrop, subtle shadow effect, e-commerce style" |
|
|
|
with open(image_path, "rb") as image_file: |
|
output = replicate.run( |
|
"runwayml/gen4-image", |
|
input={ |
|
"prompt": shadow_prompt, |
|
"aspect_ratio": "1:1", |
|
"resolution": "1080p", |
|
"reference_images": [image_file], |
|
"reference_tags": ["product"] |
|
} |
|
) |
|
|
|
response = requests.get(output) |
|
if response.status_code == 200: |
|
return Image.open(io.BytesIO(response.content)), "๊ทธ๋ฆผ์ ์ถ๊ฐ ์๋ฃ (Gen4)" |
|
else: |
|
return None, "๊ทธ๋ฆผ์ ์ถ๊ฐ ์คํจ" |
|
|
|
except Exception as e: |
|
return None, f"๊ทธ๋ฆผ์ ์ถ๊ฐ ์ค๋ฅ: {str(e)}" |
|
|
|
def process_image(image, remove_bg, upscale_quality): |
|
"""๋ฉ์ธ ์ฒ๋ฆฌ ํจ์""" |
|
if image is None: |
|
return None, "์ด๋ฏธ์ง๋ฅผ ์
๋ก๋ํด์ฃผ์ธ์." |
|
|
|
try: |
|
result_image = image.copy() |
|
status_messages = [] |
|
|
|
|
|
temp_path = upload_image_to_temp_url(result_image) |
|
if temp_path: |
|
angled_img, angle_msg = change_product_angle(temp_path) |
|
if angled_img: |
|
result_image = angled_img |
|
status_messages.append(f"โ
{angle_msg}") |
|
else: |
|
status_messages.append(f"โ {angle_msg}") |
|
os.unlink(temp_path) |
|
|
|
|
|
if remove_bg: |
|
temp_path = upload_image_to_temp_url(result_image) |
|
if temp_path: |
|
bg_removed_img, bg_msg = remove_background_with_ai(temp_path) |
|
if bg_removed_img: |
|
result_image = bg_removed_img |
|
status_messages.append(f"โ
{bg_msg}") |
|
else: |
|
status_messages.append(f"โ {bg_msg}") |
|
os.unlink(temp_path) |
|
|
|
|
|
temp_path = upload_image_to_temp_url(result_image) |
|
if temp_path: |
|
shadow_img, shadow_msg = add_shadow_only(temp_path) |
|
if shadow_img: |
|
result_image = shadow_img |
|
status_messages.append(f"โ
{shadow_msg}") |
|
else: |
|
status_messages.append(f"โ {shadow_msg}") |
|
os.unlink(temp_path) |
|
|
|
|
|
if upscale_quality: |
|
temp_path = upload_image_to_temp_url(result_image) |
|
if temp_path: |
|
upscaled_img, upscale_msg = upscale_with_clarity(temp_path) |
|
if upscaled_img: |
|
result_image = upscaled_img |
|
status_messages.append(f"โ
{upscale_msg}") |
|
else: |
|
status_messages.append(f"โ {upscale_msg}") |
|
os.unlink(temp_path) |
|
|
|
|
|
result_image = result_image.resize((1000, 1000), Image.Resampling.LANCZOS) |
|
status_messages.append("โ
1000x1000 ํฌ๊ธฐ ์กฐ์ ์๋ฃ") |
|
|
|
return result_image, "\n".join(status_messages) |
|
|
|
except Exception as e: |
|
return None, f"์ฒ๋ฆฌ ์ค ์ค๋ฅ: {str(e)}" |
|
|
|
|
|
def create_interface(): |
|
with gr.Blocks(title="์ฟ ํก ์ธ๋ค์ผ ์์ฑ๊ธฐ", theme=gr.themes.Soft()) as iface: |
|
|
|
with gr.Row(): |
|
with gr.Column(scale=1): |
|
|
|
input_image = gr.Image( |
|
label="์ํ ์ด๋ฏธ์ง ์
๋ก๋", |
|
type="pil", |
|
height=400 |
|
) |
|
|
|
|
|
with gr.Group(): |
|
remove_bg = gr.Checkbox( |
|
label="๋ฐฐ๊ฒฝ ์ ๊ฑฐ", |
|
value=True, |
|
info="AI๋ก ๋ฐฐ๊ฒฝ์ ์๋ ์ ๊ฑฐํฉ๋๋ค" |
|
) |
|
upscale_quality = gr.Checkbox( |
|
label="ํ์ง ๊ฐ์ ๊ธฐ", |
|
value=True, |
|
info="AI๋ก ํ์ง์ ํฅ์์ํต๋๋ค" |
|
) |
|
|
|
|
|
process_btn = gr.Button("๐ ์ธ๋ค์ผ ์์ฑ", variant="primary", size="lg") |
|
|
|
with gr.Column(scale=1): |
|
|
|
output_image = gr.Image( |
|
label="์ฟ ํก ์ธ๋ค์ผ ๊ฒฐ๊ณผ", |
|
height=400 |
|
) |
|
status_output = gr.Textbox( |
|
label="์ฒ๋ฆฌ ์ํ", |
|
lines=6, |
|
max_lines=10 |
|
) |
|
|
|
|
|
process_btn.click( |
|
process_image, |
|
inputs=[input_image, remove_bg, upscale_quality], |
|
outputs=[output_image, status_output] |
|
) |
|
|
|
return iface |
|
|
|
|
|
if __name__ == "__main__": |
|
app = create_interface() |
|
app.launch( |
|
server_name="0.0.0.0", |
|
server_port=7860, |
|
share=True, |
|
show_error=True |
|
) |