SketchToLife / app.py
Barath05's picture
Update app.py
46e1f05 verified
import gradio as gr
from PIL import Image
import numpy as np
import cv2
import os
import tempfile
import time
from gradio_client import Client, handle_file
# --- CONFIGURATION: FALLBACK LIST ---
# We try these 4 distinct spaces. If one is down, we jump to the next.
MODELS = [
# 1. LGM (ashawkey/LGM) - Very fast, usually online.
{"id": "ashawkey/LGM", "api": "/process", "type": "lgm"},
# 2. InstantMesh (TencentARC) - High quality, try again.
{"id": "TencentARC/InstantMesh", "api": "/generate", "type": "instantmesh"},
# 3. Zero123++ (sudo-ai) - Good alternative architecture.
{"id": "sudo-ai/zero123plus-v1.2", "api": "/generate", "type": "zero123"},
# 4. Shap-E (OpenAI) - The reliable backup.
{"id": "hysts/Shap-E", "api": "/image-to-3d", "type": "shape"}
]
def photo_to_sketch(image):
"""Instant local sketch"""
if image is None: return None
if isinstance(image, np.ndarray):
image = Image.fromarray(image.astype('uint8'))
# Resize to safe dimensions (512x512) to prevent downstream API crashes
image = image.resize((512, 512))
gray = image.convert("L")
img_array = np.array(gray)
blurred = cv2.GaussianBlur(img_array, (5, 5), 0)
edges = cv2.Canny(blurred, 60, 150)
sketch_np = 255 - edges
return Image.fromarray(sketch_np).convert("RGB")
def generate_3d_avatar(sketch_image, height, weight, muscle, gender, breast):
"""Try multiple remote models until one succeeds"""
print(f"-> Starting 3D Generation Process...")
if sketch_image is None:
raise gr.Error("Please upload an image first!")
# --- CRITICAL FIX: Sanitize Image ---
# Many 3D APIs crash if the image is not 256x256 or 512x512 RGB.
if isinstance(sketch_image, np.ndarray):
sketch_image = Image.fromarray(sketch_image.astype('uint8'))
sketch_image = sketch_image.convert("RGB").resize((512, 512))
temp_dir = tempfile.gettempdir()
sketch_path = os.path.join(temp_dir, f"sketch_{int(time.time())}.png")
sketch_image.save(sketch_path)
print(f"-> Saved clean input to {sketch_path}")
last_error = ""
# --- RETRY LOOP ---
for model in MODELS:
try:
model_id = model["id"]
print(f"------------------------------------------")
print(f"-> Attempting Connection to: {model_id}...")
client = Client(model_id)
if model["type"] == "lgm":
# LGM Parameters: [Image, Scale, Steps, Seed]
print("-> Sending request (LGM format)...")
result = client.predict(
handle_file(sketch_path),
api_name=model["api"]
)
elif model["type"] == "instantmesh":
print("-> Sending request (InstantMesh format)...")
result = client.predict(
handle_file(sketch_path), # Image
True, # Remove Background
30, # Steps
42, # Seed
api_name=model["api"]
)
elif model["type"] == "zero123":
print("-> Sending request (Zero123 format)...")
result = client.predict(
handle_file(sketch_path), # Image
True, # Remove Background
api_name=model["api"]
)
elif model["type"] == "shape":
print("-> Sending request (Shap-E format)...")
# Shap-E is strictly: Image, Prompt, Seed, Guidance, Steps
result = client.predict(
handle_file(sketch_path),
"", # Prompt must be string (empty is fine)
0, # Seed
15, # Guidance
64, # Steps
api_name=model["api"]
)
# If we get here, it worked!
print(f"-> SUCCESS! Model generated by {model_id}")
# Handle return types (list of files vs single path)
if isinstance(result, (list, tuple)):
# Find the first .glb or .obj
final_model = next((item for item in result if isinstance(item, str) and item.endswith(('.glb', '.obj', '.gltf', '.ply'))), result[0])
else:
final_model = result
return final_model, final_model
except Exception as e:
print(f"-> FAILED: {model_id} | Error: {e}")
last_error = str(e)
continue # Try next model
# If all fail
raise gr.Error(f"CRITICAL OUTAGE: All 4 backup models failed. The Hugging Face inference cloud is severely degraded right now. Last Error: {last_error}")
# =============== UI ===============
with gr.Blocks(title="SketchToLife") as demo:
gr.Markdown("# SketchToLife – Emergency Backup Mode")
gr.Markdown("**Status:** Trying LGM → InstantMesh → Zero123 → Shap-E")
with gr.Row():
with gr.Column():
inp = gr.Image(label="Upload Photo", type="pil", height=420)
btn1 = gr.Button("Generate Clean Sketch", variant="secondary", size="lg")
out_sketch = gr.Image(label="Your Sketch", height=420, type="pil")
with gr.Column():
gr.Markdown("### Customize Body")
h = gr.Dropdown(["short", "average", "tall", "giant"], value="average", label="Height")
w = gr.Dropdown(["slim", "average", "curvy", "heavy"], value="average", label="Weight")
m = gr.Dropdown(["slim", "fit", "muscular", "bodybuilder"], value="fit", label="Muscle")
g = gr.Radio(["male", "female", "neutral"], value="neutral", label="Gender")
b = gr.Dropdown(["small", "medium", "large"], value="medium", label="Breast/Form")
btn2 = gr.Button("Generate 3D Model", variant="primary", size="lg")
with gr.Row():
view3d = gr.Model3D(label="3D Result", height=520, interactive=True)
download = gr.File(label="Download .GLB")
btn1.click(photo_to_sketch, inputs=inp, outputs=out_sketch)
btn2.click(generate_3d_avatar, inputs=[out_sketch, h, w, m, g, b], outputs=[view3d, download])
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
ssr_mode=False
)