Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -8,9 +8,9 @@ import time
|
|
| 8 |
from gradio_client import Client, file
|
| 9 |
|
| 10 |
# --- CONFIGURATION ---
|
| 11 |
-
#
|
| 12 |
-
#
|
| 13 |
-
REMOTE_MODEL_ID = "
|
| 14 |
|
| 15 |
def photo_to_sketch(image):
|
| 16 |
"""Instant local sketch β always returns PIL Image"""
|
|
@@ -21,29 +21,25 @@ def photo_to_sketch(image):
|
|
| 21 |
if isinstance(image, np.ndarray):
|
| 22 |
image = Image.fromarray(image.astype('uint8'))
|
| 23 |
|
| 24 |
-
# Convert to grayscale
|
| 25 |
gray = image.convert("L")
|
| 26 |
img_array = np.array(gray)
|
| 27 |
|
| 28 |
-
# Blur + Canny edges
|
| 29 |
blurred = cv2.GaussianBlur(img_array, (5, 5), 0)
|
| 30 |
edges = cv2.Canny(blurred, 60, 150)
|
| 31 |
|
| 32 |
-
# White lines on black background
|
| 33 |
sketch_np = 255 - edges
|
| 34 |
sketch_pil = Image.fromarray(sketch_np)
|
| 35 |
|
| 36 |
-
print("-> Sketch Generated Successfully")
|
| 37 |
return sketch_pil.convert("RGB")
|
| 38 |
|
| 39 |
def generate_3d_avatar(sketch_image, height, weight, muscle, gender, breast):
|
| 40 |
-
"""Generate
|
| 41 |
print(f"-> Starting 3D Generation using {REMOTE_MODEL_ID}...")
|
| 42 |
|
| 43 |
if sketch_image is None:
|
| 44 |
-
raise gr.Error("Please upload an image
|
| 45 |
|
| 46 |
-
# 1. Save Sketch to a temporary file
|
| 47 |
if isinstance(sketch_image, np.ndarray):
|
| 48 |
sketch_image = Image.fromarray(sketch_image.astype('uint8'))
|
| 49 |
|
|
@@ -51,45 +47,38 @@ def generate_3d_avatar(sketch_image, height, weight, muscle, gender, breast):
|
|
| 51 |
sketch_path = os.path.join(temp_dir, f"sketch_{int(time.time())}.png")
|
| 52 |
sketch_image.save(sketch_path)
|
| 53 |
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
# 2. Connect to the Remote Space
|
| 57 |
try:
|
| 58 |
print(f"-> Connecting to {REMOTE_MODEL_ID}...")
|
| 59 |
client = Client(REMOTE_MODEL_ID)
|
| 60 |
|
| 61 |
-
# 3. Send request
|
| 62 |
-
|
| 63 |
-
print("-> Sending request to remote GPU...")
|
| 64 |
|
| 65 |
-
#
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
|
|
|
|
|
|
| 72 |
)
|
| 73 |
|
| 74 |
-
#
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
final_glb = result_path[0]
|
| 78 |
-
else:
|
| 79 |
-
final_glb = result_path
|
| 80 |
-
|
| 81 |
-
print(f"-> Success! Received 3D model at: {final_glb}")
|
| 82 |
-
return final_glb, final_glb
|
| 83 |
|
| 84 |
except Exception as e:
|
| 85 |
print(f"-> Connection Error: {e}")
|
| 86 |
-
#
|
| 87 |
-
raise gr.Error(f"
|
| 88 |
|
| 89 |
# =============== UI ===============
|
| 90 |
with gr.Blocks(title="SketchToLife") as demo:
|
| 91 |
-
gr.Markdown("# SketchToLife β Photo β Sketch β 3D Avatar
|
| 92 |
-
gr.Markdown(f"**Status:** Connected to `
|
| 93 |
|
| 94 |
with gr.Row():
|
| 95 |
with gr.Column():
|
|
@@ -99,7 +88,7 @@ with gr.Blocks(title="SketchToLife") as demo:
|
|
| 99 |
|
| 100 |
with gr.Column():
|
| 101 |
gr.Markdown("### Customize 3D Body")
|
| 102 |
-
# Placeholders to
|
| 103 |
h = gr.Dropdown(["short", "average", "tall", "giant"], value="average", label="Height")
|
| 104 |
w = gr.Dropdown(["slim", "average", "curvy", "heavy"], value="average", label="Weight")
|
| 105 |
m = gr.Dropdown(["slim", "fit", "muscular", "bodybuilder"], value="fit", label="Muscle")
|
|
@@ -114,7 +103,7 @@ with gr.Blocks(title="SketchToLife") as demo:
|
|
| 114 |
|
| 115 |
btn1.click(photo_to_sketch, inputs=inp, outputs=out_sketch)
|
| 116 |
|
| 117 |
-
#
|
| 118 |
btn2.click(generate_3d_avatar, inputs=[out_sketch, h, w, m, g, b], outputs=[view3d, download])
|
| 119 |
|
| 120 |
if __name__ == "__main__":
|
|
|
|
| 8 |
from gradio_client import Client, file
|
| 9 |
|
| 10 |
# --- CONFIGURATION ---
|
| 11 |
+
# We switched to "hysts/Shap-E" (OpenAI's model).
|
| 12 |
+
# It is extremely reliable and rarely crashes compared to TripoSR/InstantMesh.
|
| 13 |
+
REMOTE_MODEL_ID = "hysts/Shap-E"
|
| 14 |
|
| 15 |
def photo_to_sketch(image):
|
| 16 |
"""Instant local sketch β always returns PIL Image"""
|
|
|
|
| 21 |
if isinstance(image, np.ndarray):
|
| 22 |
image = Image.fromarray(image.astype('uint8'))
|
| 23 |
|
|
|
|
| 24 |
gray = image.convert("L")
|
| 25 |
img_array = np.array(gray)
|
| 26 |
|
|
|
|
| 27 |
blurred = cv2.GaussianBlur(img_array, (5, 5), 0)
|
| 28 |
edges = cv2.Canny(blurred, 60, 150)
|
| 29 |
|
|
|
|
| 30 |
sketch_np = 255 - edges
|
| 31 |
sketch_pil = Image.fromarray(sketch_np)
|
| 32 |
|
|
|
|
| 33 |
return sketch_pil.convert("RGB")
|
| 34 |
|
| 35 |
def generate_3d_avatar(sketch_image, height, weight, muscle, gender, breast):
|
| 36 |
+
"""Generate 3D model using OpenAI Shap-E (Reliable Fallback)"""
|
| 37 |
print(f"-> Starting 3D Generation using {REMOTE_MODEL_ID}...")
|
| 38 |
|
| 39 |
if sketch_image is None:
|
| 40 |
+
raise gr.Error("Please upload an image first!")
|
| 41 |
|
| 42 |
+
# 1. Save Sketch to a temporary file
|
| 43 |
if isinstance(sketch_image, np.ndarray):
|
| 44 |
sketch_image = Image.fromarray(sketch_image.astype('uint8'))
|
| 45 |
|
|
|
|
| 47 |
sketch_path = os.path.join(temp_dir, f"sketch_{int(time.time())}.png")
|
| 48 |
sketch_image.save(sketch_path)
|
| 49 |
|
| 50 |
+
# 2. Connect to Shap-E
|
|
|
|
|
|
|
| 51 |
try:
|
| 52 |
print(f"-> Connecting to {REMOTE_MODEL_ID}...")
|
| 53 |
client = Client(REMOTE_MODEL_ID)
|
| 54 |
|
| 55 |
+
# 3. Send request (Shap-E API parameters)
|
| 56 |
+
print("-> Sending request to Shap-E...")
|
|
|
|
| 57 |
|
| 58 |
+
# Shap-E expects: [image, prompt_text, seed, guidance_scale, num_inference_steps]
|
| 59 |
+
# We leave prompt empty to force Image-to-3D mode
|
| 60 |
+
result = client.predict(
|
| 61 |
+
file(sketch_path), # Input Image
|
| 62 |
+
"", # Text Prompt (Empty for Img-to-3D)
|
| 63 |
+
0, # Seed
|
| 64 |
+
15, # Guidance Scale
|
| 65 |
+
64, # Steps (64 is fast, 128 is better)
|
| 66 |
+
api_name="/image-to-3d"
|
| 67 |
)
|
| 68 |
|
| 69 |
+
# Result is just the file path string
|
| 70 |
+
print(f"-> Success! Received model: {result}")
|
| 71 |
+
return result, result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
|
| 73 |
except Exception as e:
|
| 74 |
print(f"-> Connection Error: {e}")
|
| 75 |
+
# If even Shap-E fails, we raise a clear error
|
| 76 |
+
raise gr.Error(f"All 3D models are currently busy. Error: {e}")
|
| 77 |
|
| 78 |
# =============== UI ===============
|
| 79 |
with gr.Blocks(title="SketchToLife") as demo:
|
| 80 |
+
gr.Markdown("# SketchToLife β Photo β Sketch β 3D Avatar")
|
| 81 |
+
gr.Markdown(f"**Status:** Connected to `OpenAI Shap-E` (High Stability Backup).")
|
| 82 |
|
| 83 |
with gr.Row():
|
| 84 |
with gr.Column():
|
|
|
|
| 88 |
|
| 89 |
with gr.Column():
|
| 90 |
gr.Markdown("### Customize 3D Body")
|
| 91 |
+
# Placeholders to prevent argument errors
|
| 92 |
h = gr.Dropdown(["short", "average", "tall", "giant"], value="average", label="Height")
|
| 93 |
w = gr.Dropdown(["slim", "average", "curvy", "heavy"], value="average", label="Weight")
|
| 94 |
m = gr.Dropdown(["slim", "fit", "muscular", "bodybuilder"], value="fit", label="Muscle")
|
|
|
|
| 103 |
|
| 104 |
btn1.click(photo_to_sketch, inputs=inp, outputs=out_sketch)
|
| 105 |
|
| 106 |
+
# 6 inputs -> 6 arguments
|
| 107 |
btn2.click(generate_3d_avatar, inputs=[out_sketch, h, w, m, g, b], outputs=[view3d, download])
|
| 108 |
|
| 109 |
if __name__ == "__main__":
|