Ryukijano commited on
Commit
b556a2f
1 Parent(s): fd2eadd

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. app.py +219 -390
  3. requirements.txt +4 -29
README.md CHANGED
@@ -1,12 +1,14 @@
1
  ---
2
- title: Era3D MV Demo
3
- emoji: 🐠
4
- colorFrom: purple
5
- colorTo: pink
6
  sdk: gradio
7
- sdk_version: 4.31.5
8
  app_file: app.py
9
  pinned: false
 
 
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: LLaMA Mesh
3
+ emoji: 👀
4
+ colorFrom: red
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: 5.6.0
8
  app_file: app.py
9
  pinned: false
10
+ license: llama3.1
11
+ short_description: Create 3D mesh by chatting.
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -1,411 +1,240 @@
1
- import os
2
- import torch
3
- import fire
4
  import gradio as gr
5
- from PIL import Image
6
- from functools import partial
7
- import spaces
8
- import cv2
9
- import time
10
- import numpy as np
11
- from rembg import remove
12
- from segment_anything import sam_model_registry, SamPredictor
13
-
14
  import os
15
- import torch
16
-
17
- from PIL import Image
18
- from typing import Dict, Optional, List
19
- from dataclasses import dataclass
20
- from mvdiffusion.data.single_image_dataset import SingleImageDataset
21
- from mvdiffusion.pipelines.pipeline_mvdiffusion_unclip import StableUnCLIPImg2ImgPipeline
22
- from einops import rearrange
23
- import numpy as np
24
- import subprocess
25
- from datetime import datetime
26
- from icecream import ic
27
- def save_image(tensor):
28
- ndarr = tensor.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy()
29
- # pdb.set_trace()
30
- im = Image.fromarray(ndarr)
31
- return ndarr
32
-
33
 
34
- def save_image_to_disk(tensor, fp):
35
- ndarr = tensor.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 0).to("cpu", torch.uint8).numpy()
36
- # pdb.set_trace()
37
- im = Image.fromarray(ndarr)
38
- im.save(fp)
39
- return ndarr
40
 
41
 
42
- def save_image_numpy(ndarr, fp):
43
- im = Image.fromarray(ndarr)
44
- im.save(fp)
45
-
46
-
47
- weight_dtype = torch.float16
48
-
49
- _TITLE = '''Era3D: High-Resolution Multiview Diffusion using Efficient Row-wise Attention'''
50
- _DESCRIPTION = '''
51
  <div>
52
- Generate consistent high-resolution multi-view normals maps and color images.
53
- </div>
54
  <div>
55
- The demo does not include the mesh reconstruction part, please visit <a href="https://github.com/pengHTYX/Era3D"><img src='https://img.shields.io/github/stars/pengHTYX/Era3D?style=social' style="display: inline-block; vertical-align: middle;"/></a> to get a textured mesh.
 
 
 
 
 
 
56
  </div>
57
  '''
58
- _GPU_ID = 0
59
-
60
-
61
- if not hasattr(Image, 'Resampling'):
62
- Image.Resampling = Image
63
-
64
-
65
- def sam_init():
66
- sam_checkpoint = os.path.join(os.path.dirname(__file__), "sam_pt", "sam_vit_h_4b8939.pth")
67
- model_type = "vit_h"
68
-
69
- sam = sam_model_registry[model_type](checkpoint=sam_checkpoint).to(device=f"cuda:{_GPU_ID}")
70
- predictor = SamPredictor(sam)
71
- return predictor
72
-
73
- @spaces.GPU
74
- def sam_segment(predictor, input_image, *bbox_coords):
75
- bbox = np.array(bbox_coords)
76
- image = np.asarray(input_image)
77
-
78
- start_time = time.time()
79
- predictor.set_image(image)
80
-
81
- masks_bbox, scores_bbox, logits_bbox = predictor.predict(box=bbox, multimask_output=True)
82
-
83
- print(f"SAM Time: {time.time() - start_time:.3f}s")
84
- out_image = np.zeros((image.shape[0], image.shape[1], 4), dtype=np.uint8)
85
- out_image[:, :, :3] = image
86
- out_image_bbox = out_image.copy()
87
- out_image_bbox[:, :, 3] = masks_bbox[-1].astype(np.uint8) * 255
88
- torch.cuda.empty_cache()
89
- return Image.fromarray(out_image_bbox, mode='RGBA')
90
-
91
 
92
- def expand2square(pil_img, background_color):
93
- width, height = pil_img.size
94
- if width == height:
95
- return pil_img
96
- elif width > height:
97
- result = Image.new(pil_img.mode, (width, width), background_color)
98
- result.paste(pil_img, (0, (width - height) // 2))
99
- return result
100
- else:
101
- result = Image.new(pil_img.mode, (height, height), background_color)
102
- result.paste(pil_img, ((height - width) // 2, 0))
103
- return result
104
 
 
 
 
105
 
106
- def preprocess(predictor, input_image, chk_group=None, segment=True, rescale=False):
107
- RES = 1024
108
- input_image.thumbnail([RES, RES], Image.Resampling.LANCZOS)
109
- if chk_group is not None:
110
- segment = "Background Removal" in chk_group
111
- rescale = "Rescale" in chk_group
112
- if segment:
113
- image_rem = input_image.convert('RGBA')
114
- image_nobg = remove(image_rem, alpha_matting=True)
115
- arr = np.asarray(image_nobg)[:, :, -1]
116
- x_nonzero = np.nonzero(arr.sum(axis=0))
117
- y_nonzero = np.nonzero(arr.sum(axis=1))
118
- x_min = int(x_nonzero[0].min())
119
- y_min = int(y_nonzero[0].min())
120
- x_max = int(x_nonzero[0].max())
121
- y_max = int(y_nonzero[0].max())
122
- input_image = sam_segment(predictor, input_image.convert('RGB'), x_min, y_min, x_max, y_max)
123
- # Rescale and recenter
124
- if rescale:
125
- image_arr = np.array(input_image)
126
- in_w, in_h = image_arr.shape[:2]
127
- out_res = min(RES, max(in_w, in_h))
128
- ret, mask = cv2.threshold(np.array(input_image.split()[-1]), 0, 255, cv2.THRESH_BINARY)
129
- x, y, w, h = cv2.boundingRect(mask)
130
- max_size = max(w, h)
131
- ratio = 0.75
132
- side_len = int(max_size / ratio)
133
- padded_image = np.zeros((side_len, side_len, 4), dtype=np.uint8)
134
- center = side_len // 2
135
- padded_image[center - h // 2 : center - h // 2 + h, center - w // 2 : center - w // 2 + w] = image_arr[y : y + h, x : x + w]
136
- rgba = Image.fromarray(padded_image).resize((out_res, out_res), Image.LANCZOS)
137
-
138
- rgba_arr = np.array(rgba) / 255.0
139
- rgb = rgba_arr[..., :3] * rgba_arr[..., -1:] + (1 - rgba_arr[..., -1:])
140
- input_image = Image.fromarray((rgb * 255).astype(np.uint8))
141
- else:
142
- input_image = expand2square(input_image, (127, 127, 127, 0))
143
- return input_image, input_image.resize((320, 320), Image.Resampling.LANCZOS)
144
-
145
- def load_era3d_pipeline(cfg):
146
- # Load scheduler, tokenizer and models.
147
-
148
- pipeline = StableUnCLIPImg2ImgPipeline.from_pretrained(
149
- cfg.pretrained_model_name_or_path,
150
- torch_dtype=weight_dtype
151
- )
152
- # sys.main_lock = threading.Lock()
153
- return pipeline
154
-
155
-
156
- from mvdiffusion.data.single_image_dataset import SingleImageDataset
157
-
158
-
159
- def prepare_data(single_image, crop_size, cfg):
160
- dataset = SingleImageDataset(root_dir='', num_views=6, img_wh=[512, 512], bg_color='white',
161
- crop_size=crop_size, single_image=single_image, prompt_embeds_path=cfg.validation_dataset.prompt_embeds_path)
162
- return dataset[0]
163
-
164
- scene = 'scene'
165
- def run_pipeline(pipeline, cfg, single_image, guidance_scale, steps, seed, crop_size, chk_group=None):
166
- pipeline.to(device=f'cuda:{_GPU_ID}')
167
- pipeline.unet.enable_xformers_memory_efficient_attention()
168
-
169
- global scene
170
- # pdb.set_trace()
171
-
172
- if chk_group is not None:
173
- write_image = "Write Results" in chk_group
174
-
175
- batch = prepare_data(single_image, crop_size, cfg)
176
-
177
- pipeline.set_progress_bar_config(disable=True)
178
- seed = int(seed)
179
- generator = torch.Generator(device=pipeline.unet.device).manual_seed(seed)
180
-
181
-
182
- imgs_in = torch.cat([batch['imgs_in']]*2, dim=0)
183
- num_views = imgs_in.shape[1]
184
- imgs_in = rearrange(imgs_in, "B Nv C H W -> (B Nv) C H W")# (B*Nv, 3, H, W)
185
-
186
- normal_prompt_embeddings, clr_prompt_embeddings = batch['normal_prompt_embeddings'], batch['color_prompt_embeddings']
187
- prompt_embeddings = torch.cat([normal_prompt_embeddings, clr_prompt_embeddings], dim=0)
188
- prompt_embeddings = rearrange(prompt_embeddings, "B Nv N C -> (B Nv) N C")
189
-
190
 
191
- imgs_in = imgs_in.to(device=f'cuda:{_GPU_ID}', dtype=weight_dtype)
192
- prompt_embeddings = prompt_embeddings.to(device=f'cuda:{_GPU_ID}', dtype=weight_dtype)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
- out = pipeline(
195
- imgs_in,
196
- None,
197
- prompt_embeds=prompt_embeddings,
198
- generator=generator,
199
- guidance_scale=guidance_scale,
200
- output_type='pt',
201
- num_images_per_prompt=1,
202
- # return_elevation_focal=cfg.log_elevation_focal_length,
203
- **cfg.pipe_validation_kwargs
204
- ).images
205
-
206
- bsz = out.shape[0] // 2
207
- normals_pred = out[:bsz]
208
- images_pred = out[bsz:]
209
- num_views = 6
210
- if write_image:
211
- VIEWS = ['front', 'front_right', 'right', 'back', 'left', 'front_left']
212
- cur_dir = os.path.join(cfg.save_dir, f"cropsize-{int(crop_size)}-cfg{guidance_scale:.1f}")
213
-
214
- scene = 'scene'+datetime.now().strftime('@%Y%m%d-%H%M%S')
215
- scene_dir = os.path.join(cur_dir, scene)
216
- os.makedirs(scene_dir, exist_ok=True)
217
-
218
- for j in range(num_views):
219
- view = VIEWS[j]
220
- normal = normals_pred[j]
221
- color = images_pred[j]
222
-
223
- normal_filename = f"normals_{view}_masked.png"
224
- color_filename = f"color_{view}_masked.png"
225
- normal = save_image_to_disk(normal, os.path.join(scene_dir, normal_filename))
226
- color = save_image_to_disk(color, os.path.join(scene_dir, color_filename))
227
-
228
-
229
- normals_pred = [save_image(normals_pred[i]) for i in range(bsz)]
230
- images_pred = [save_image(images_pred[i]) for i in range(bsz)]
231
-
232
- out = images_pred + normals_pred
233
- return images_pred, normals_pred
234
-
235
-
236
- def process_3d(mode, data_dir, guidance_scale, crop_size):
237
- dir = None
238
- global scene
239
-
240
- cur_dir = os.path.dirname(os.path.abspath(__file__))
241
-
242
- subprocess.run(
243
- f'cd instant-nsr-pl && bash run.sh 0 {scene} exp_demo && cd ..',
244
- shell=True,
245
  )
246
- import glob
247
-
248
- obj_files = glob.glob(f'{cur_dir}/instant-nsr-pl/exp_demo/{scene}/*/save/*.obj', recursive=True)
249
- print(obj_files)
250
- if obj_files:
251
- dir = obj_files[0]
252
- return dir
253
-
254
-
255
- @dataclass
256
- class TestConfig:
257
- pretrained_model_name_or_path: str
258
- pretrained_unet_path:Optional[str]
259
- revision: Optional[str]
260
- validation_dataset: Dict
261
- save_dir: str
262
- seed: Optional[int]
263
- validation_batch_size: int
264
- dataloader_num_workers: int
265
- # save_single_views: bool
266
- save_mode: str
267
- local_rank: int
268
-
269
- pipe_kwargs: Dict
270
- pipe_validation_kwargs: Dict
271
- unet_from_pretrained_kwargs: Dict
272
- validation_guidance_scales: List[float]
273
- validation_grid_nrow: int
274
- camera_embedding_lr_mult: float
275
-
276
- num_views: int
277
- camera_embedding_type: str
278
-
279
- pred_type: str # joint, or ablation
280
- regress_elevation: bool
281
- enable_xformers_memory_efficient_attention: bool
282
-
283
- cond_on_normals: bool
284
- cond_on_colors: bool
285
-
286
- regress_elevation: bool
287
- regress_focal_length: bool
288
-
289
-
290
-
291
- def run_demo():
292
- from utils.misc import load_config
293
- from omegaconf import OmegaConf
294
-
295
- # parse YAML config to OmegaConf
296
- cfg = load_config("./configs/test_unclip-512-6view.yaml")
297
- # print(cfg)
298
- schema = OmegaConf.structured(TestConfig)
299
- cfg = OmegaConf.merge(schema, cfg)
300
-
301
- pipeline = load_era3d_pipeline(cfg)
302
- torch.set_grad_enabled(False)
303
-
304
-
305
- predictor = sam_init()
306
-
307
 
308
- custom_theme = gr.themes.Soft(primary_hue="blue").set(
309
- button_secondary_background_fill="*neutral_100", button_secondary_background_fill_hover="*neutral_200"
310
- )
311
- custom_css = '''#disp_image {
312
- text-align: center; /* Horizontally center the content */
313
- }'''
314
-
315
 
316
- with gr.Blocks(title=_TITLE, theme=custom_theme, css=custom_css) as demo:
 
 
 
317
  with gr.Row():
318
- with gr.Column(scale=1):
319
- gr.Markdown('# ' + _TITLE)
320
- gr.Markdown(_DESCRIPTION)
321
- with gr.Row(variant='panel'):
322
- with gr.Column(scale=1):
323
- input_image = gr.Image(type='pil', image_mode='RGBA', height=320, label='Input image')
324
-
325
- with gr.Column(scale=1):
326
- processed_image_highres = gr.Image(type='pil', image_mode='RGBA', visible=False)
327
-
328
- processed_image = gr.Image(
329
- type='pil',
330
- label="Processed Image",
331
- interactive=False,
332
- # height=320,
333
- image_mode='RGBA',
334
- elem_id="disp_image",
335
- visible=True,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336
  )
337
- # with gr.Column(scale=1):
338
- # ## add 3D Model
339
- # obj_3d = gr.Model3D(
340
- # # clear_color=[0.0, 0.0, 0.0, 0.0],
341
- # label="3D Model", height=320,
342
- # # camera_position=[0,0,2.0]
343
- # )
344
 
345
- with gr.Row(variant='panel'):
346
- with gr.Column(scale=1):
347
- example_folder = os.path.join(os.path.dirname(__file__), "./examples")
348
- example_fns = [os.path.join(example_folder, example) for example in os.listdir(example_folder)]
349
- gr.Examples(
350
- examples=example_fns,
351
- inputs=[input_image],
352
- outputs=[input_image],
353
- cache_examples=False,
354
- label='Examples (click one of the images below to start)',
355
- examples_per_page=30,
356
  )
357
- with gr.Column(scale=1):
358
- with gr.Row():
359
- with gr.Column():
360
- with gr.Accordion('Advanced options', open=True):
361
- input_processing = gr.CheckboxGroup(
362
- ['Background Removal'],
363
- label='Input Image Preprocessing',
364
- value=['Background Removal'],
365
- info='untick this, if masked image with alpha channel',
366
- )
367
- with gr.Column():
368
- with gr.Accordion('Advanced options', open=False):
369
- output_processing = gr.CheckboxGroup(
370
- ['Write Results'], label='write the results in mv_res folder', value=['Write Results']
371
- )
372
- with gr.Row():
373
- with gr.Column():
374
- scale_slider = gr.Slider(1, 5, value=3, step=1, label='Classifier Free Guidance Scale')
375
- with gr.Column():
376
- steps_slider = gr.Slider(15, 100, value=40, step=1, label='Number of Diffusion Inference Steps')
377
- with gr.Row():
378
- with gr.Column():
379
- seed = gr.Number(600, label='Seed', info='100 for digital portraits')
380
- with gr.Column():
381
- crop_size = gr.Number(420, label='Crop size', info='380 for digital portraits')
382
-
383
- mode = gr.Textbox('train', visible=False)
384
- data_dir = gr.Textbox('outputs', visible=False)
385
- # with gr.Row():
386
- # method = gr.Radio(choices=['instant-nsr-pl', 'NeuS'], label='Method (Default: instant-nsr-pl)', value='instant-nsr-pl')
387
- run_btn = gr.Button('Generate Normals and Colors', variant='primary', interactive=True)
388
- # recon_btn = gr.Button('Reconstruct 3D model', variant='primary', interactive=True)
389
- # gr.Markdown("<span style='color:red'>First click Generate button, then click Reconstruct button. Reconstruction may cost several minutes.</span>")
390
-
391
- with gr.Row():
392
- view_gallery = gr.Gallery(label='Multiview Images')
393
- normal_gallery = gr.Gallery(label='Multiview Normals')
394
-
395
- print('Launching...')
396
- run_btn.click(
397
- fn=partial(preprocess, predictor), inputs=[input_image, input_processing], outputs=[processed_image_highres, processed_image], queue=True
398
- ).success(
399
- fn=partial(run_pipeline, pipeline, cfg),
400
- inputs=[processed_image_highres, scale_slider, steps_slider, seed, crop_size, output_processing],
401
- outputs=[view_gallery, normal_gallery],
402
- )
403
- # recon_btn.click(
404
- # process_3d, inputs=[mode, data_dir, scale_slider, crop_size], outputs=[obj_3d]
405
- # )
406
-
407
- demo.queue().launch(share=True, max_threads=80)
408
-
409
-
410
- if __name__ == '__main__':
411
- fire.Fire(run_demo)
 
 
 
 
1
  import gradio as gr
 
 
 
 
 
 
 
 
 
2
  import os
3
+ import spaces
4
+ from transformers import GemmaTokenizer, AutoModelForCausalLM
5
+ from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
6
+ from threading import Thread
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ # Set an environment variable
9
+ HF_TOKEN = os.environ.get("HF_TOKEN", None)
 
 
 
 
10
 
11
 
12
+ DESCRIPTION = '''
 
 
 
 
 
 
 
 
13
  <div>
14
+ <h1 style="text-align: center;">LLaMA-Mesh</h1>
 
15
  <div>
16
+ <a style="display:inline-block" href="https://research.nvidia.com/labs/toronto-ai/LLaMA-Mesh/"><img src='https://img.shields.io/badge/public_website-8A2BE2'></a>
17
+ <a style="display:inline-block; margin-left: .5em" href="https://github.com/nv-tlabs/LLaMA-Mesh"><img src='https://img.shields.io/github/stars/nv-tlabs/LLaMA-Mesh?style=social'/></a>
18
+ </div>
19
+ <p>LLaMA-Mesh: Unifying 3D Mesh Generation with Language Models.<a style="display:inline-block" href="https://research.nvidia.com/labs/toronto-ai/LLaMA-Mesh/">[Project Page]</a> <a style="display:inline-block" href="https://github.com/nv-tlabs/LLaMA-Mesh">[Code]</a></p>
20
+ <p> Notice: (1) This demo supports up to 4096 tokens due to computational limits, while our full model supports 8k tokens. This limitation may result in incomplete generated meshes. To experience the full 8k token context, please run our model locally.</p>
21
+ <p>(2) We only support generating a single mesh per dialog round. To generate another mesh, click the "clear" button and start a new dialog.</p>
22
+ <p>(3) If the LLM refuses to generate a 3D mesh, try adding more explicit instructions to the prompt, such as "create a 3D model of a table <strong>in OBJ format</strong>." A more effective approach is to request the mesh generation at the start of the dialog.</p>
23
  </div>
24
  '''
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ LICENSE = """
27
+ <p/>
 
 
 
 
 
 
 
 
 
 
28
 
29
+ ---
30
+ Built with Meta Llama 3.1 8B
31
+ """
32
 
33
+ PLACEHOLDER = """
34
+ <div style="padding: 30px; text-align: center; display: flex; flex-direction: column; align-items: center;">
35
+ <h1 style="font-size: 28px; margin-bottom: 2px; opacity: 0.55;">LLaMA-Mesh</h1>
36
+ <p style="font-size: 18px; margin-bottom: 2px; opacity: 0.65;">Create 3D meshes by chatting.</p>
37
+ </div>
38
+ """
39
+
40
+
41
+ css = """
42
+ h1 {
43
+ text-align: center;
44
+ display: block;
45
+ }
46
+
47
+ #duplicate-button {
48
+ margin: auto;
49
+ color: white;
50
+ background: #1565c0;
51
+ border-radius: 100vh;
52
+ }
53
+ """
54
+ # Load the tokenizer and model
55
+ model_path = "Zhengyi/LLaMA-Mesh"
56
+ tokenizer = AutoTokenizer.from_pretrained(model_path)
57
+ model = AutoModelForCausalLM.from_pretrained(model_path, device_map="auto")
58
+ terminators = [
59
+ tokenizer.eos_token_id,
60
+ tokenizer.convert_tokens_to_ids("<|eot_id|>")
61
+ ]
62
+
63
+
64
+ from trimesh.exchange.gltf import export_glb
65
+ import gradio as gr
66
+ import trimesh
67
+ import numpy as np
68
+ import tempfile
69
+ def apply_gradient_color(mesh_text):
70
+ """
71
+ Apply a gradient color to the mesh vertices based on the Y-axis and save as GLB.
72
+ Args:
73
+ mesh_text (str): The input mesh in OBJ format as a string.
74
+ Returns:
75
+ str: Path to the GLB file with gradient colors applied.
76
+ """
77
+ # Load the mesh
78
+ temp_file = tempfile.NamedTemporaryFile(suffix=f"", delete=False).name#"temp_mesh.obj"
79
+ with open(temp_file+".obj", "w") as f:
80
+ f.write(mesh_text)
81
+ # return temp_file
82
+ mesh = trimesh.load_mesh(temp_file+".obj", file_type='obj')
83
+
84
+ # Get vertex coordinates
85
+ vertices = mesh.vertices
86
+ y_values = vertices[:, 1] # Y-axis values
87
+
88
+ # Normalize Y values to range [0, 1] for color mapping
89
+ y_normalized = (y_values - y_values.min()) / (y_values.max() - y_values.min())
90
+
91
+ # Generate colors: Map normalized Y values to RGB gradient (e.g., blue to red)
92
+ colors = np.zeros((len(vertices), 4)) # RGBA
93
+ colors[:, 0] = y_normalized # Red channel
94
+ colors[:, 2] = 1 - y_normalized # Blue channel
95
+ colors[:, 3] = 1.0 # Alpha channel (fully opaque)
96
+
97
+ # Attach colors to mesh vertices
98
+ mesh.visual.vertex_colors = colors
99
+
100
+ # Export to GLB format
101
+ glb_path = temp_file+".glb"
102
+ with open(glb_path, "wb") as f:
103
+ f.write(export_glb(mesh))
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
+ return glb_path
106
+
107
+ def visualize_mesh(mesh_text):
108
+ """
109
+ Convert the provided 3D mesh text into a visualizable format.
110
+ This function assumes the input is in OBJ format.
111
+ """
112
+ temp_file = "temp_mesh.obj"
113
+ with open(temp_file, "w") as f:
114
+ f.write(mesh_text)
115
+ return temp_file
116
+
117
+ @spaces.GPU(duration=120)
118
+ def chat_llama3_8b(message: str,
119
+ history: list,
120
+ temperature: float,
121
+ max_new_tokens: int
122
+ ) -> str:
123
+ """
124
+ Generate a streaming response using the llama3-8b model.
125
+ Args:
126
+ message (str): The input message.
127
+ history (list): The conversation history used by ChatInterface.
128
+ temperature (float): The temperature for generating the response.
129
+ max_new_tokens (int): The maximum number of new tokens to generate.
130
+ Returns:
131
+ str: The generated response.
132
+ """
133
+ conversation = []
134
+ for user, assistant in history:
135
+ conversation.extend([{"role": "user", "content": user}, {"role": "assistant", "content": assistant}])
136
+ conversation.append({"role": "user", "content": message})
137
+
138
+ input_ids = tokenizer.apply_chat_template(conversation, return_tensors="pt").to(model.device)
139
 
140
+ streamer = TextIteratorStreamer(tokenizer, timeout=10.0, skip_prompt=True, skip_special_tokens=True)
141
+ # print(max_new_tokens)
142
+ max_new_tokens=4096
143
+ temperature=0.9
144
+ generate_kwargs = dict(
145
+ input_ids= input_ids,
146
+ streamer=streamer,
147
+ max_new_tokens=max_new_tokens,
148
+ do_sample=True,
149
+ temperature=temperature,
150
+ eos_token_id=terminators,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  )
152
+ # This will enforce greedy generation (do_sample=False) when the temperature is passed 0, avoiding the crash.
153
+ if temperature == 0:
154
+ generate_kwargs['do_sample'] = False
155
+
156
+ t = Thread(target=model.generate, kwargs=generate_kwargs)
157
+ t.start()
158
+
159
+ outputs = []
160
+ for text in streamer:
161
+ outputs.append(text)
162
+ #print(outputs)
163
+ yield "".join(outputs)
164
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
+ # Gradio block
167
+ chatbot=gr.Chatbot(height=450, placeholder=PLACEHOLDER, label='Gradio ChatInterface')
 
 
 
 
 
168
 
169
+ with gr.Blocks(fill_height=True, css=css) as demo:
170
+ with gr.Column():
171
+ gr.Markdown(DESCRIPTION)
172
+ # gr.DuplicateButton(value="Duplicate Space for private use", elem_id="duplicate-button")
173
  with gr.Row():
174
+ with gr.Column(scale=3):
175
+ gr.ChatInterface(
176
+ fn=chat_llama3_8b,
177
+ chatbot=chatbot,
178
+ fill_height=True,
179
+ additional_inputs_accordion=gr.Accordion(label="⚙️ Parameters", open=False, render=False),
180
+ additional_inputs=[
181
+ gr.Slider(minimum=0,
182
+ maximum=1,
183
+ step=0.1,
184
+ value=0.9,
185
+ label="Temperature",
186
+ interactive = False,
187
+ render=False),
188
+ gr.Slider(minimum=128,
189
+ maximum=4096,
190
+ step=1,
191
+ value=4096,
192
+ label="Max new tokens",
193
+ interactive = False,
194
+ render=False),
195
+ ],
196
+ examples=[
197
+ ['Create a 3D model of a wooden hammer'],
198
+ ['Create a 3D model of a pyramid in obj format'],
199
+ ['Create a 3D model of a cabinet.'],
200
+ ['Create a low poly 3D model of a coffe cup'],
201
+ ['Create a 3D model of a table.'],
202
+ ["Create a low poly 3D model of a tree."],
203
+ ['Write a python code for sorting.'],
204
+ ['How to setup a human base on Mars? Give short answer.'],
205
+ ['Explain theory of relativity to me like I’m 8 years old.'],
206
+ ['What is 9,000 * 9,000?'],
207
+ ['Create a 3D model of a soda can.'],
208
+ ['Create a 3D model of a sword.'],
209
+ ['Create a 3D model of a wooden barrel'],
210
+ ['Create a 3D model of a chair.']
211
+ ],
212
+ cache_examples=False,
213
+ )
214
+ gr.Markdown(LICENSE)
215
+
216
+ with gr.Column(scale=2):
217
+ output_model = gr.Model3D(
218
+ label="3D Mesh Visualization",
219
+ interactive=False,
220
+ )
221
+ gr.Markdown("You can copy the generated 3d objects in the left and paste in the textbox below. Put the button and you will see the visualization of the 3D mesh.")
222
+
223
+ # Add the text box for 3D mesh input and button
224
+ mesh_input = gr.Textbox(
225
+ label="3D Mesh Input",
226
+ placeholder="Paste your 3D mesh in OBJ format here...",
227
+ lines=5,
228
  )
229
+ visualize_button = gr.Button("Visualize 3D Mesh")
 
 
 
 
 
 
230
 
231
+ # Link the button to the visualization function
232
+ visualize_button.click(
233
+ fn=apply_gradient_color,
234
+ inputs=[mesh_input],
235
+ outputs=[output_model]
 
 
 
 
 
 
236
  )
237
+
238
+ if __name__ == "__main__":
239
+ demo.launch()
240
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,29 +1,4 @@
1
- --extra-index-url https://download.pytorch.org/whl/cu118 --extra-index-url https://download.pytorch.org/whl/cu118
2
- diffusers[torch]
3
- transformers
4
- decord
5
- pytorch-lightning
6
- omegaconf
7
- nerfacc
8
- trimesh
9
- pyhocon
10
- icecream
11
- PyMCubes
12
- accelerate
13
- modelcards
14
- einops
15
- ftfy
16
- piq
17
- matplotlib
18
- opencv-python
19
- imageio
20
- imageio-ffmpeg
21
- scipy
22
- pyransac3d
23
- torch_efficient_distloss
24
- tensorboard
25
- rembg
26
- segment_anything
27
- gradio==4.31.5
28
- kornia
29
- fire
 
1
+ accelerate
2
+ transformers
3
+ trimesh
4
+ numpy