Tryonn / app.py
Zuii's picture
Update app.py
a474bb6 verified
raw
history blame
9.12 kB
import os
import requests
import json
import time
import cv2
import base64
import random
import numpy as np
import gradio as gr
MAX_SEED = 999999
# βœ… New Pixelcut API key
pixelcut_api_key = "sk_3a15d5b79d5944f3995c54615f8928f8"
# 🎯 Convert image to PNG format
def convert_to_png(image):
return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# πŸ”₯ Encode image to base64 PNG format
def encode_image(image):
image = convert_to_png(image)
_, buffer = cv2.imencode('.png', image)
return base64.b64encode(buffer).decode('utf-8')
# πŸ› οΈ Upload images to a temporary hosting service
def upload_image(image_data):
files = {"file": ("image.png", image_data, "image/png")}
upload_response = requests.post("https://tmpfiles.org/api/v1/upload", files=files)
if upload_response.status_code == 200:
return upload_response.json().get("data", {}).get("url", None)
else:
print("❌ Image upload failed:", upload_response.text)
return None
# πŸš€ Main try-on function using Pixelcut API
def tryon(person_img, garment_img, seed, randomize_seed):
start_time = time.time()
# πŸ›‘ Check if images are provided
if person_img is None or garment_img is None:
return None, None, "Empty image"
# 🎲 Handle seed randomization
if randomize_seed:
seed = random.randint(0, MAX_SEED)
# πŸ”₯ Convert images to base64 PNG
_, person_encoded = cv2.imencode('.png', convert_to_png(person_img))
_, garment_encoded = cv2.imencode('.png', convert_to_png(garment_img))
# βœ… Upload person and garment images to get URLs
person_url = upload_image(person_encoded)
garment_url = upload_image(garment_encoded)
if not person_url or not garment_url:
return None, None, "Image upload failed"
# 🌟 Setup Pixelcut API endpoint and headers
url = "https://api.developer.pixelcut.ai/v1/remove-background"
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-KEY': pixelcut_api_key
}
# πŸ”§ Use uploaded URLs in the payload
person_data = {
"image_url": person_url,
"format": "png"
}
garment_data = {
"image_url": garment_url,
"format": "png"
}
result_img = None
max_retries = 5
retry_delay = 3 # Faster retries now!
try:
session = requests.Session()
# πŸ” Retry loop β€” smarter handling of "please try again later"
for attempt in range(max_retries):
response = session.post(url, headers=headers, json=person_data, timeout=60)
print("Response code:", response.status_code)
# βœ… Success β€” process the result
if response.status_code == 200:
result_url = response.json().get('result_url', '')
print("βœ… Success:", result_url)
# Fetch the final image
if result_url:
result_img_data = requests.get(result_url).content
result_np = np.frombuffer(result_img_data, np.uint8)
result_img = cv2.imdecode(result_np, cv2.IMREAD_UNCHANGED)
info = "βœ… Success"
break
else:
# πŸ”₯ Handle "please try again later" or other errors
error_response = response.json().get('error', '')
if "please try again later" in error_response.lower():
print(f"Attempt {attempt + 1}/{max_retries}: API said 'please try again later'. Retrying in {retry_delay} seconds...")
time.sleep(retry_delay)
retry_delay += 2 # Exponential backoff β€” retries longer each time
else:
info = f"❌ Error: {response.status_code} - {response.text}"
break
else:
# ❌ If all retries fail
info = "API still says 'please try again later' β€” waited too long."
# πŸ›‘ Handle timeouts specifically
except requests.exceptions.ReadTimeout:
print("Timeout!")
info = "⚑ Timeout β€” please try again later"
raise gr.Error("Too many users, please try again later")
# ❗ Handle any other unexpected errors
except Exception as err:
print(f"❌ Other error: {err}")
info = "Error, please contact the admin"
end_time = time.time()
print(f"⏳ Time used: {end_time - start_time:.2f} seconds")
return result_img, seed, info
example_path = os.path.join(os.path.dirname(__file__), 'assets')
garm_list = os.listdir(os.path.join(example_path,"cloth"))
garm_list_path = [os.path.join(example_path,"cloth",garm) for garm in garm_list]
human_list = os.listdir(os.path.join(example_path,"human"))
human_list_path = [os.path.join(example_path,"human",human) for human in human_list]
css="""
#col-left {
margin: 0 auto;
max-width: 430px;
}
#col-mid {
margin: 0 auto;
max-width: 430px;
}
#col-right {
margin: 0 auto;
max-width: 430px;
}
#col-showcase {
margin: 0 auto;
max-width: 1100px;
}
#button {
color: blue;
}
"""
def load_description(fp):
with open(fp, 'r', encoding='utf-8') as f:
content = f.read()
return content
def change_imgs(image1, image2):
return image1, image2
with gr.Blocks(css=css) as Tryon:
gr.HTML(load_description("assets/new_title.md"))
with gr.Row():
with gr.Column(elem_id = "col-left"):
gr.HTML("""
<div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
<div>
Step 1. Upload a person image ⬇️
</div>
</div>
""")
with gr.Column(elem_id = "col-mid"):
gr.HTML("""
<div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
<div>
Step 2. Upload a garment image ⬇️
</div>
</div>
""")
with gr.Column(elem_id = "col-right"):
gr.HTML("""
<div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
<div>
Step 3. Press β€œRun” to get try-on results
</div>
</div>
""")
with gr.Row():
with gr.Column(elem_id = "col-left"):
imgs = gr.Image(label="Person image", sources='upload', type="numpy")
# category = gr.Dropdown(label="Garment category", choices=['upper_body', 'lower_body', 'dresses'], value="upper_body")
example = gr.Examples(
inputs=imgs,
examples_per_page=12,
examples=human_list_path
)
with gr.Column(elem_id = "col-mid"):
garm_img = gr.Image(label="Garment image", sources='upload', type="numpy")
example = gr.Examples(
inputs=garm_img,
examples_per_page=12,
examples=garm_list_path
)
with gr.Column(elem_id = "col-right"):
image_out = gr.Image(label="Result", show_share_button=False)
with gr.Row():
seed = gr.Slider(
label="Seed",
minimum=0,
maximum=MAX_SEED,
step=1,
value=0,
)
randomize_seed = gr.Checkbox(label="Random seed", value=True)
with gr.Row():
seed_used = gr.Number(label="Seed used")
result_info = gr.Text(label="Response")
# try_button = gr.Button(value="Run", elem_id="button")
test_button = gr.Button(value="Run", elem_id="button")
# try_button.click(fn=start_tryon, inputs=[imgs, garm_img, seed, randomize_seed], outputs=[image_out, seed_used, result_info], api_name='tryon',concurrency_limit=10)
test_button.click(fn=tryon, inputs=[imgs, garm_img, seed, randomize_seed], outputs=[image_out, seed_used, result_info], api_name=False, concurrency_limit=45)
with gr.Column(elem_id = "col-showcase"):
gr.HTML("""
<div style="display: flex; justify-content: center; align-items: center; text-align: center; font-size: 20px;">
<div> </div>
<br>
<div>
Virtual try-on examples in pairs of person and garment images
</div>
</div>
""")
show_case = gr.Examples(
examples=[
["assets/examples/model2.png", "assets/examples/garment2.png", "assets/examples/result2.png"],
["assets/examples/model3.png", "assets/examples/garment3.png", "assets/examples/result3.png"],
["assets/examples/model1.png", "assets/examples/garment1.png", "assets/examples/result1.png"],
],
inputs=[imgs, garm_img, image_out],
label=None
)
Tryon.queue(api_open=False).launch(show_api=False)