vivekchakraverty commited on
Commit
b1eeac5
·
verified ·
1 Parent(s): 9d2c9dd

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -210
app.py DELETED
@@ -1,210 +0,0 @@
1
- """
2
- Hunyuan3D-2 — Shape-only HuggingFace Space
3
- Uses Hunyuan3D-2mini-Turbo (0.6 B, step-distilled) for fast shape generation
4
- within standard ZeroGPU quota. No texture pipeline — mesh only.
5
- """
6
-
7
- import os
8
- import tempfile
9
-
10
- import gradio as gr
11
- import spaces # ZeroGPU decorator
12
- import torch
13
- from PIL import Image
14
-
15
- # ---------------------------------------------------------------------------
16
- # Lazy global pipeline — loaded once on first GPU call
17
- # ---------------------------------------------------------------------------
18
- _pipeline = None
19
-
20
-
21
- def _get_pipeline():
22
- """Load the shape pipeline once and cache it."""
23
- global _pipeline
24
- if _pipeline is None:
25
- from hy3dgen.shapegen import Hunyuan3DDiTFlowMatchingPipeline
26
-
27
- _pipeline = Hunyuan3DDiTFlowMatchingPipeline.from_pretrained(
28
- "tencent/Hunyuan3D-2mini",
29
- subfolder="hunyuan3d-dit-v2-mini-turbo", # step-distilled turbo variant
30
- use_safetensors=True,
31
- torch_dtype=torch.float16,
32
- )
33
- return _pipeline
34
-
35
-
36
- # ---------------------------------------------------------------------------
37
- # Background removal (CPU-side pre-processing, outside the GPU block)
38
- # ---------------------------------------------------------------------------
39
- def remove_background(pil_image: Image.Image) -> Image.Image:
40
- """Return RGBA image with background removed via rembg."""
41
- try:
42
- from rembg import remove as rembg_remove
43
- return rembg_remove(pil_image)
44
- except Exception:
45
- # Graceful fallback: return image as-is (model handles white BG)
46
- return pil_image.convert("RGBA")
47
-
48
-
49
- def preprocess_image(pil_image: Image.Image) -> Image.Image:
50
- """Resize, strip background, and composite on white for the model."""
51
- pil_image = pil_image.convert("RGBA")
52
- pil_image = remove_background(pil_image)
53
-
54
- # Composite RGBA onto white background (model was trained this way)
55
- white_bg = Image.new("RGBA", pil_image.size, (255, 255, 255, 255))
56
- white_bg.paste(pil_image, mask=pil_image.split()[3])
57
- result = white_bg.convert("RGB")
58
-
59
- # Resize to 512×512 — model's native conditioning resolution
60
- result = result.resize((512, 512), Image.LANCZOS)
61
- return result
62
-
63
-
64
- # ---------------------------------------------------------------------------
65
- # Core generation — wrapped in @spaces.GPU for ZeroGPU
66
- # ---------------------------------------------------------------------------
67
- @spaces.GPU(duration=60) # 60 s is sufficient for mini-turbo at low step counts
68
- def generate_shape(image: Image.Image, seed: int, steps: int, octree_res: int):
69
- """
70
- Run Hunyuan3D-DiT shape generation and return a GLB file path.
71
-
72
- Parameters
73
- ----------
74
- image : PIL.Image
75
- Pre-processed condition image (RGB, 512×512).
76
- seed : int
77
- Random seed for reproducibility.
78
- steps : int
79
- Number of diffusion steps (fewer = faster; turbo model works well at 5-10).
80
- octree_res : int
81
- Octree resolution for mesh extraction — higher = more detail, slower.
82
-
83
- Returns
84
- -------
85
- str
86
- Path to the output .glb file (written to a temp directory).
87
- """
88
- pipeline = _get_pipeline()
89
- pipeline = pipeline.to("cuda")
90
-
91
- generator = torch.Generator(device="cuda").manual_seed(seed)
92
-
93
- meshes = pipeline(
94
- image=image,
95
- num_inference_steps=steps,
96
- octree_resolution=octree_res,
97
- num_chunks=8000, # chunk size for memory efficiency
98
- generator=generator,
99
- output_type="trimesh",
100
- )
101
- mesh = meshes[0]
102
-
103
- # Save to a temp file so Gradio can serve it
104
- tmp_dir = tempfile.mkdtemp()
105
- out_path = os.path.join(tmp_dir, "shape.glb")
106
- mesh.export(out_path)
107
- return out_path
108
-
109
-
110
- # ---------------------------------------------------------------------------
111
- # Gradio UI
112
- # ---------------------------------------------------------------------------
113
- def run(image, seed, steps, octree_res, progress=gr.Progress(track_tqdm=True)):
114
- if image is None:
115
- raise gr.Error("Please upload an image first.")
116
-
117
- progress(0.1, desc="Removing background …")
118
- pil = Image.fromarray(image) if not isinstance(image, Image.Image) else image
119
- processed = preprocess_image(pil)
120
-
121
- progress(0.3, desc="Running shape diffusion …")
122
- glb_path = generate_shape(processed, int(seed), int(steps), int(octree_res))
123
-
124
- progress(1.0, desc="Done!")
125
- return glb_path, processed, glb_path
126
-
127
-
128
- with gr.Blocks(title="Hunyuan3D-2 Shape Generator", theme=gr.themes.Soft()) as demo:
129
- gr.Markdown(
130
- """
131
- # 🧊 Hunyuan3D-2 — Shape Generator
132
- Upload any image to generate an **untextured 3-D mesh** using
133
- [Hunyuan3D-2mini-Turbo](https://huggingface.co/tencent/Hunyuan3D-2mini).
134
- Shape only — no texture — so it stays well within the ZeroGPU free quota.
135
- """
136
- )
137
-
138
- with gr.Row():
139
- with gr.Column(scale=1):
140
- input_image = gr.Image(
141
- label="Input Image",
142
- type="pil",
143
- sources=["upload", "webcam", "clipboard"],
144
- height=340,
145
- )
146
-
147
- with gr.Accordion("⚙️ Advanced settings", open=False):
148
- seed = gr.Slider(
149
- label="Seed",
150
- minimum=0, maximum=2**31 - 1,
151
- value=42, step=1,
152
- )
153
- steps = gr.Slider(
154
- label="Diffusion steps",
155
- minimum=5, maximum=50,
156
- value=5, step=1,
157
- info="5-15 works well with the turbo model.",
158
- )
159
- octree_res = gr.Slider(
160
- label="Octree resolution",
161
- minimum=128, maximum=512,
162
- value=192, step=64,
163
- info="Higher = finer mesh detail but more VRAM & time.",
164
- )
165
-
166
- generate_btn = gr.Button("✨ Generate Shape", variant="primary")
167
-
168
- with gr.Column(scale=1):
169
- preview_img = gr.Image(
170
- label="Preprocessed image (sent to model)",
171
- type="pil",
172
- interactive=False,
173
- height=200,
174
- )
175
- output_3d = gr.Model3D(
176
- label="3-D Shape (GLB)",
177
- height=400,
178
- clear_color=[0.9, 0.9, 0.9, 1.0],
179
- )
180
- download_file = gr.File(label="⬇ Download GLB", visible=True)
181
-
182
- gr.Examples(
183
- examples=[
184
- # Add your own example image paths here after uploading them to the Space
185
- ],
186
- inputs=[input_image],
187
- label="Examples (upload your own to try)",
188
- )
189
-
190
- gr.Markdown(
191
- """
192
- ---
193
- **Tips**
194
- - Works best on isolated objects on a plain background.
195
- - The background is removed automatically — results improve with clean subjects.
196
- - Lower octree resolution (128–256) is faster and still looks great for most objects.
197
- - Model: *Hunyuan3D-DiT-v2-mini-Turbo* — 0.6 B parameters, step-distilled.
198
- """
199
- )
200
-
201
- # Wire up events
202
- generate_btn.click(
203
- fn=run,
204
- inputs=[input_image, seed, steps, octree_res],
205
- outputs=[output_3d, preview_img, download_file],
206
- )
207
-
208
-
209
- if __name__ == "__main__":
210
- demo.queue(max_size=5).launch()