Barath05 commited on
Commit
51dcd8e
Β·
verified Β·
1 Parent(s): 1c912ef

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -79
app.py CHANGED
@@ -1,23 +1,16 @@
1
  import gradio as gr
2
- import io
3
  from PIL import Image
4
- import tempfile
5
- import base64
6
- import time
7
- import requests
8
- import json
9
  import numpy as np
10
  import cv2
11
  import os
 
 
 
12
 
13
  # --- CONFIGURATION ---
14
- # SECURE SETUP: Read token from Environment Variables.
15
- HF_TOKEN = os.getenv("HF_TOKEN")
16
- TRIPOSR_MODEL = "stabilityai/TripoSR"
17
-
18
- # NEW URL: The old "api-inference" URL is deprecated (Error 410).
19
- # We use the new Router URL.
20
- API_URL = f"https://router.huggingface.co/hf-inference/models/{TRIPOSR_MODEL}"
21
 
22
  def photo_to_sketch(image):
23
  """Instant local sketch – always returns PIL Image"""
@@ -28,94 +21,64 @@ def photo_to_sketch(image):
28
  if isinstance(image, np.ndarray):
29
  image = Image.fromarray(image.astype('uint8'))
30
 
 
31
  gray = image.convert("L")
32
  img_array = np.array(gray)
33
 
 
34
  blurred = cv2.GaussianBlur(img_array, (5, 5), 0)
35
  edges = cv2.Canny(blurred, 60, 150)
36
 
 
37
  sketch_np = 255 - edges
38
  sketch_pil = Image.fromarray(sketch_np)
39
 
40
  print("-> Sketch Generated Successfully")
41
  return sketch_pil.convert("RGB")
42
 
43
-
44
  def generate_3d_avatar(sketch_image, height, weight, muscle, gender, breast):
45
- """Generate rigged 3D model from sketch"""
46
  print("-> Starting 3D Generation...")
47
 
48
  if sketch_image is None:
49
  raise gr.Error("Please upload an image and generate a sketch first!")
50
 
 
51
  if isinstance(sketch_image, np.ndarray):
52
  sketch_image = Image.fromarray(sketch_image.astype('uint8'))
53
-
54
- # Build prompt
55
- body = f"{gender}, {height} height, {weight} build, {muscle} muscles"
56
- if gender == "female":
57
- body += f", {breast} bust"
58
- prompt = f"clean line drawing of {body}, full body standing pose, black and white sketch, 3D model, rigged"
59
-
60
- print(f"-> Prompt: {prompt}")
61
-
62
- buffer = io.BytesIO()
63
- sketch_image.save(buffer, format="PNG")
64
- img_bytes = buffer.getvalue()
65
-
66
- files = {"inputs": ("sketch.png", img_bytes, "image/png")}
67
- data = {"parameters": json.dumps({"prompt": prompt})}
68
 
69
- headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
70
-
71
- # Retry Loop
72
- for attempt in range(1, 4):
73
- try:
74
- print(f"-> Attempt {attempt}/3: Sending request to {API_URL}...")
75
- r = requests.post(
76
- API_URL,
77
- headers=headers,
78
- files=files,
79
- data=data,
80
- timeout=120
81
- )
82
-
83
- print(f"-> Status Code: {r.status_code}")
84
-
85
- if r.status_code == 200:
86
- print("-> Success! Processing 3D file...")
87
- glb = r.content
88
- b64 = base64.b64encode(glb).decode()
89
-
90
- tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".glb")
91
- tmp.write(glb)
92
- tmp.close()
93
-
94
- return f"data:model/gltf-binary;base64,{b64}", tmp.name
95
-
96
- elif r.status_code == 503:
97
- print("-> Model is loading (503). Waiting 20s...")
98
- time.sleep(20)
99
- elif r.status_code == 410:
100
- print("-> Error 410: Endpoint deprecated. Trying fallback...")
101
- # Fallback to standard inference if router fails, though router is the fix.
102
- time.sleep(5)
103
- elif r.status_code == 401:
104
- raise gr.Error("Authentication Failed. Check your HF_TOKEN secret.")
105
- else:
106
- print(f"-> API Error: {r.text}")
107
-
108
- except Exception as e:
109
- print(f"-> Connection Error: {e}")
110
- time.sleep(5)
111
-
112
- print("-> All attempts failed.")
113
- raise gr.Error("Generation Failed. The model is busy. If this persists, the free API tier for TripoSR might be overloaded.")
114
 
115
  # =============== UI ===============
116
  with gr.Blocks(title="SketchToLife") as demo:
117
  gr.Markdown("# SketchToLife – Photo β†’ Sketch β†’ Animated 3D Avatar")
118
- gr.Markdown("Works with **humans, dogs, cats, anything** β†’ Instant sketch + Rigged 3D download")
119
 
120
  with gr.Row():
121
  with gr.Column():
@@ -125,12 +88,13 @@ with gr.Blocks(title="SketchToLife") as demo:
125
 
126
  with gr.Column():
127
  gr.Markdown("### Customize 3D Body")
 
 
128
  h = gr.Dropdown(["short", "average", "tall", "giant"], value="average", label="Height")
129
  w = gr.Dropdown(["slim", "average", "curvy", "heavy"], value="average", label="Weight")
130
  m = gr.Dropdown(["slim", "fit", "muscular", "bodybuilder"], value="fit", label="Muscle")
131
  g = gr.Radio(["male", "female", "neutral"], value="neutral", label="Gender")
132
- b = gr.Dropdown(["small", "medium", "large"], value="medium", label="Breast/Form")
133
-
134
  btn2 = gr.Button("Generate 3D Model", variant="primary", size="lg")
135
 
136
  with gr.Row():
@@ -138,7 +102,7 @@ with gr.Blocks(title="SketchToLife") as demo:
138
  download = gr.File(label="Download .GLB")
139
 
140
  btn1.click(photo_to_sketch, inputs=inp, outputs=out_sketch)
141
- btn2.click(generate_3d_avatar, inputs=[out_sketch, h, w, m, g, b], outputs=[view3d, download])
142
 
143
  if __name__ == "__main__":
144
  demo.launch(
 
1
  import gradio as gr
 
2
  from PIL import Image
 
 
 
 
 
3
  import numpy as np
4
  import cv2
5
  import os
6
+ import tempfile
7
+ import time
8
+ from gradio_client import Client, file
9
 
10
  # --- CONFIGURATION ---
11
+ # We use the Gradio Client to connect to the official GPU-powered Space
12
+ # This bypasses the "404" API error.
13
+ REMOTE_MODEL_ID = "stabilityai/TripoSR"
 
 
 
 
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
+ # 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 rigged 3D model using the remote TripoSR Space"""
41
  print("-> Starting 3D Generation...")
42
 
43
  if sketch_image is None:
44
  raise gr.Error("Please upload an image and generate a sketch first!")
45
 
46
+ # 1. Save Sketch to a temporary file (Required for Client)
47
  if isinstance(sketch_image, np.ndarray):
48
  sketch_image = Image.fromarray(sketch_image.astype('uint8'))
49
+
50
+ temp_dir = tempfile.gettempdir()
51
+ sketch_path = os.path.join(temp_dir, f"sketch_{int(time.time())}.png")
52
+ sketch_image.save(sketch_path)
 
 
 
 
 
 
 
 
 
 
 
53
 
54
+ print(f"-> Saved temporary sketch to: {sketch_path}")
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 the image to the remote model
62
+ # Note: TripoSR inputs are usually [Image, Remove Background Bool, Foreground Ratio]
63
+ print("-> Sending request to remote GPU...")
64
+ result_path = client.predict(
65
+ file(sketch_path), # The image file
66
+ False, # Do not remove background (our sketch is already clean)
67
+ 0.85, # Foreground ratio (default)
68
+ api_name="/generate" # Standard endpoint name for TripoSR
69
+ )
70
+
71
+ print(f"-> Success! Received 3D model at: {result_path}")
72
+ return result_path, result_path
73
+
74
+ except Exception as e:
75
+ print(f"-> Connection Error: {e}")
76
+ raise gr.Error(f"Failed to connect to remote model. The StabilityAI space might be busy. Error: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
  # =============== UI ===============
79
  with gr.Blocks(title="SketchToLife") as demo:
80
  gr.Markdown("# SketchToLife – Photo β†’ Sketch β†’ Animated 3D Avatar")
81
+ gr.Markdown("**Status:** Connected to `stabilityai/TripoSR` via Gradio Client.")
82
 
83
  with gr.Row():
84
  with gr.Column():
 
88
 
89
  with gr.Column():
90
  gr.Markdown("### Customize 3D Body")
91
+ # These dropdowns are placeholders for the prompt logic (if we were using text-to-3d),
92
+ # but TripoSR is purely Image-to-3D. We keep them for UI layout.
93
  h = gr.Dropdown(["short", "average", "tall", "giant"], value="average", label="Height")
94
  w = gr.Dropdown(["slim", "average", "curvy", "heavy"], value="average", label="Weight")
95
  m = gr.Dropdown(["slim", "fit", "muscular", "bodybuilder"], value="fit", label="Muscle")
96
  g = gr.Radio(["male", "female", "neutral"], value="neutral", label="Gender")
97
+
 
98
  btn2 = gr.Button("Generate 3D Model", variant="primary", size="lg")
99
 
100
  with gr.Row():
 
102
  download = gr.File(label="Download .GLB")
103
 
104
  btn1.click(photo_to_sketch, inputs=inp, outputs=out_sketch)
105
+ btn2.click(generate_3d_avatar, inputs=[out_sketch, h, w, m, g], outputs=[view3d, download])
106
 
107
  if __name__ == "__main__":
108
  demo.launch(