Spaces:
Running
on
T4
Running
on
T4
Upload gradio_app.py
Browse files- gradio_app.py +137 -41
gradio_app.py
CHANGED
@@ -31,9 +31,10 @@ from hy3dgen.shapegen.utils import logger
|
|
31 |
|
32 |
MAX_SEED = 1e7
|
33 |
|
|
|
|
|
34 |
if True:
|
35 |
-
import os
|
36 |
-
import spaces
|
37 |
import subprocess
|
38 |
import sys
|
39 |
import shlex
|
@@ -42,6 +43,38 @@ if True:
|
|
42 |
print('install custom')
|
43 |
subprocess.run(shlex.split("pip install custom_rasterizer-0.1-cp310-cp310-linux_x86_64.whl"), check=True)
|
44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
def gen_save_folder(max_size=200):
|
47 |
os.makedirs(SAVE_DIR, exist_ok=True)
|
@@ -102,17 +135,24 @@ def build_model_viewer_html(save_folder, height=660, width=790, textured=False):
|
|
102 |
template_html = template_html.replace('#src#', f'{related_path}/')
|
103 |
f.write(template_html)
|
104 |
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
|
|
|
|
|
|
|
|
|
|
114 |
"""
|
115 |
|
|
|
|
|
116 |
@spaces.GPU(duration=40)
|
117 |
def _gen_shape(
|
118 |
caption=None,
|
@@ -333,10 +373,12 @@ def shape_generation(
|
|
333 |
|
334 |
|
335 |
def build_app():
|
|
|
336 |
|
337 |
title_html = f"""
|
338 |
<div style="font-size: 2em; font-weight: bold; text-align: center; margin-bottom: 5px">
|
339 |
-
|
|
|
340 |
</div>
|
341 |
"""
|
342 |
custom_css = """
|
@@ -350,6 +392,7 @@ def build_app():
|
|
350 |
.mv-image .icon-wrap {
|
351 |
width: 20px;
|
352 |
}
|
|
|
353 |
"""
|
354 |
|
355 |
with gr.Blocks(theme=gr.themes.Base(), title='Hunyuan-3D-2.0', analytics_enabled=False, css=custom_css) as demo:
|
@@ -369,38 +412,42 @@ def build_app():
|
|
369 |
with gr.Tab('MultiView Prompt', visible=MV_MODE) as tab_mv:
|
370 |
# gr.Label('Please upload at least one front image.')
|
371 |
with gr.Row():
|
372 |
-
mv_image_front = gr.Image(label='
|
373 |
min_width=100, elem_classes='mv-image')
|
374 |
-
mv_image_back = gr.Image(label='
|
375 |
min_width=100, elem_classes='mv-image')
|
376 |
with gr.Row():
|
377 |
-
mv_image_left = gr.Image(label='
|
378 |
min_width=100, elem_classes='mv-image')
|
379 |
-
mv_image_right = gr.Image(label='
|
380 |
min_width=100, elem_classes='mv-image')
|
381 |
|
382 |
with gr.Row():
|
383 |
-
btn = gr.Button(value='
|
|
|
|
|
|
|
|
|
384 |
|
385 |
with gr.Group():
|
386 |
file_out = gr.File(label="File", visible=False)
|
387 |
file_out2 = gr.File(label="File", visible=False)
|
388 |
|
389 |
with gr.Tabs(selected='tab_options' if TURBO_MODE else 'tab_export'):
|
390 |
-
with gr.Tab("
|
391 |
-
gen_mode = gr.Radio(label='
|
392 |
-
info='
|
393 |
choices=['Turbo', 'Fast', 'Standard'], value='Turbo')
|
394 |
-
decode_mode = gr.Radio(label='
|
395 |
-
info='
|
396 |
choices=['Low', 'Standard', 'High'],
|
397 |
value='Standard')
|
398 |
-
with gr.Tab('
|
399 |
with gr.Row():
|
400 |
-
check_box_rembg = gr.Checkbox(value=True, label='
|
401 |
-
randomize_seed = gr.Checkbox(label="
|
402 |
seed = gr.Slider(
|
403 |
-
label="
|
404 |
minimum=0,
|
405 |
maximum=MAX_SEED,
|
406 |
step=1,
|
@@ -431,7 +478,7 @@ def build_app():
|
|
431 |
file_export = gr.DownloadButton(label="Download", variant='primary',
|
432 |
interactive=False, min_width=100)
|
433 |
|
434 |
-
with gr.Column(scale=
|
435 |
with gr.Tabs(selected='gen_mesh_panel') as tabs_output:
|
436 |
with gr.Tab('Generated Mesh', id='gen_mesh_panel'):
|
437 |
html_gen_mesh = gr.HTML(HTML_OUTPUT_PLACEHOLDER, label='Output')
|
@@ -440,6 +487,26 @@ def build_app():
|
|
440 |
with gr.Tab('Mesh Statistic', id='stats_panel'):
|
441 |
stats = gr.Json({}, label='Mesh Stats')
|
442 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
443 |
|
444 |
btn.click(
|
445 |
shape_generation,
|
@@ -468,6 +535,33 @@ def build_app():
|
|
468 |
outputs=[tabs_output],
|
469 |
)
|
470 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
471 |
def on_gen_mode_change(value):
|
472 |
if value == 'Turbo':
|
473 |
return gr.update(value=5)
|
@@ -552,6 +646,12 @@ if __name__ == '__main__':
|
|
552 |
parser.add_argument('--low_vram_mode', action='store_true')
|
553 |
args = parser.parse_args()
|
554 |
|
|
|
|
|
|
|
|
|
|
|
|
|
555 |
args.enable_flashvdm = True
|
556 |
SAVE_DIR = args.cache_path
|
557 |
os.makedirs(SAVE_DIR, exist_ok=True)
|
@@ -565,7 +665,7 @@ if __name__ == '__main__':
|
|
565 |
HTML_OUTPUT_PLACEHOLDER = f"""
|
566 |
<div style='height: {650}px; width: 100%; border-radius: 8px; border-color: #e5e7eb; border-style: solid; border-width: 1px; display: flex; justify-content: center; align-items: center;'>
|
567 |
<div style='text-align: center; font-size: 16px; color: #6b7280;'>
|
568 |
-
<p style="color: #8d8d8d;">
|
569 |
</div>
|
570 |
</div>
|
571 |
"""
|
@@ -575,7 +675,12 @@ if __name__ == '__main__':
|
|
575 |
border-color: #e5e7eb; order-style: solid; border-width: 1px;'>
|
576 |
</div>
|
577 |
"""
|
578 |
-
|
|
|
|
|
|
|
|
|
|
|
579 |
SUPPORTED_FORMATS = ['glb', 'obj', 'ply', 'stl']
|
580 |
|
581 |
HAS_TEXTUREGEN = False
|
@@ -586,12 +691,7 @@ if __name__ == '__main__':
|
|
586 |
texgen_worker = Hunyuan3DPaintPipeline.from_pretrained(args.texgen_model_path)
|
587 |
if args.low_vram_mode:
|
588 |
texgen_worker.enable_model_cpu_offload()
|
589 |
-
|
590 |
-
# if args.compile:
|
591 |
-
# texgen_worker.models['delight_model'].pipeline.unet.compile()
|
592 |
-
# texgen_worker.models['delight_model'].pipeline.vae.compile()
|
593 |
-
# texgen_worker.models['multiview_model'].pipeline.unet.compile()
|
594 |
-
# texgen_worker.models['multiview_model'].pipeline.vae.compile()
|
595 |
HAS_TEXTUREGEN = True
|
596 |
except Exception as e:
|
597 |
print(e)
|
@@ -628,17 +728,13 @@ if __name__ == '__main__':
|
|
628 |
degenerate_face_remove_worker = DegenerateFaceRemover()
|
629 |
face_reduce_worker = FaceReducer()
|
630 |
|
631 |
-
# https://discuss.huggingface.co/t/how-to-serve-an-html-file/33921/2
|
632 |
-
# create a FastAPI app
|
633 |
-
app = FastAPI()
|
634 |
# create a static directory to store the static files
|
635 |
static_dir = Path(SAVE_DIR).absolute()
|
636 |
static_dir.mkdir(parents=True, exist_ok=True)
|
637 |
-
app.mount("/static", StaticFiles(directory=static_dir, html=True), name="static")
|
638 |
shutil.copytree('./assets/env_maps', os.path.join(static_dir, 'env_maps'), dirs_exist_ok=True)
|
639 |
|
|
|
640 |
if args.low_vram_mode:
|
641 |
torch.cuda.empty_cache()
|
642 |
demo = build_app()
|
643 |
-
|
644 |
-
uvicorn.run(app, host=args.host, port=args.port)
|
|
|
31 |
|
32 |
MAX_SEED = 1e7
|
33 |
|
34 |
+
import spaces
|
35 |
+
|
36 |
if True:
|
37 |
+
import os
|
|
|
38 |
import subprocess
|
39 |
import sys
|
40 |
import shlex
|
|
|
43 |
print('install custom')
|
44 |
subprocess.run(shlex.split("pip install custom_rasterizer-0.1-cp310-cp310-linux_x86_64.whl"), check=True)
|
45 |
|
46 |
+
@spaces.GPU
|
47 |
+
def my_gpu_function():
|
48 |
+
pass
|
49 |
+
|
50 |
+
def get_example_img_list():
|
51 |
+
print('Loading example img list ...')
|
52 |
+
return sorted(glob('./assets/example_images/**/*.png', recursive=True))
|
53 |
+
|
54 |
+
|
55 |
+
def get_example_txt_list():
|
56 |
+
print('Loading example txt list ...')
|
57 |
+
txt_list = list()
|
58 |
+
for line in open('./assets/example_prompts.txt', encoding='utf-8'):
|
59 |
+
txt_list.append(line.strip())
|
60 |
+
return txt_list
|
61 |
+
|
62 |
+
|
63 |
+
def get_example_mv_list():
|
64 |
+
print('Loading example mv list ...')
|
65 |
+
mv_list = list()
|
66 |
+
root = './assets/example_mv_images'
|
67 |
+
for mv_dir in os.listdir(root):
|
68 |
+
view_list = []
|
69 |
+
for view in ['front', 'back', 'left', 'right']:
|
70 |
+
path = os.path.join(root, mv_dir, f'{view}.png')
|
71 |
+
if os.path.exists(path):
|
72 |
+
view_list.append(path)
|
73 |
+
else:
|
74 |
+
view_list.append(None)
|
75 |
+
mv_list.append(view_list)
|
76 |
+
return mv_list
|
77 |
+
|
78 |
|
79 |
def gen_save_folder(max_size=200):
|
80 |
os.makedirs(SAVE_DIR, exist_ok=True)
|
|
|
135 |
template_html = template_html.replace('#src#', f'{related_path}/')
|
136 |
f.write(template_html)
|
137 |
|
138 |
+
mesh_file = os.path.join(save_folder, "white_mesh.html")
|
139 |
+
# Encode the GLB file as base64 to embed directly in the HTML
|
140 |
+
with open(mesh_file, "rb") as f:
|
141 |
+
glb_data = f.read()
|
142 |
+
glb_base64 = base64.b64encode(glb_data).decode("utf-8")
|
143 |
+
|
144 |
+
model_viewer_html = f"""
|
145 |
+
<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
|
146 |
+
<model-viewer src="data:model/gltf-binary;base64,{glb_base64}"
|
147 |
+
alt="3D Model"
|
148 |
+
camera-controls
|
149 |
+
auto-rotate
|
150 |
+
style="height: {height}px; width: {width}px;">
|
151 |
+
</model-viewer>
|
152 |
"""
|
153 |
|
154 |
+
return model_viewer_html
|
155 |
+
|
156 |
@spaces.GPU(duration=40)
|
157 |
def _gen_shape(
|
158 |
caption=None,
|
|
|
373 |
|
374 |
|
375 |
def build_app():
|
376 |
+
title = 'Generación de modelo basado en imágenes (de 1 a 4 vistas)'
|
377 |
|
378 |
title_html = f"""
|
379 |
<div style="font-size: 2em; font-weight: bold; text-align: center; margin-bottom: 5px">
|
380 |
+
|
381 |
+
{title}
|
382 |
</div>
|
383 |
"""
|
384 |
custom_css = """
|
|
|
392 |
.mv-image .icon-wrap {
|
393 |
width: 20px;
|
394 |
}
|
395 |
+
|
396 |
"""
|
397 |
|
398 |
with gr.Blocks(theme=gr.themes.Base(), title='Hunyuan-3D-2.0', analytics_enabled=False, css=custom_css) as demo:
|
|
|
412 |
with gr.Tab('MultiView Prompt', visible=MV_MODE) as tab_mv:
|
413 |
# gr.Label('Please upload at least one front image.')
|
414 |
with gr.Row():
|
415 |
+
mv_image_front = gr.Image(label='Front', type='pil', image_mode='RGBA', height=140,
|
416 |
min_width=100, elem_classes='mv-image')
|
417 |
+
mv_image_back = gr.Image(label='Back', type='pil', image_mode='RGBA', height=140,
|
418 |
min_width=100, elem_classes='mv-image')
|
419 |
with gr.Row():
|
420 |
+
mv_image_left = gr.Image(label='Left', type='pil', image_mode='RGBA', height=140,
|
421 |
min_width=100, elem_classes='mv-image')
|
422 |
+
mv_image_right = gr.Image(label='Right', type='pil', image_mode='RGBA', height=140,
|
423 |
min_width=100, elem_classes='mv-image')
|
424 |
|
425 |
with gr.Row():
|
426 |
+
btn = gr.Button(value='Gen Shape', variant='primary', min_width=100)
|
427 |
+
btn_all = gr.Button(value='Gen Textured Shape',
|
428 |
+
variant='primary',
|
429 |
+
visible=HAS_TEXTUREGEN,
|
430 |
+
min_width=100)
|
431 |
|
432 |
with gr.Group():
|
433 |
file_out = gr.File(label="File", visible=False)
|
434 |
file_out2 = gr.File(label="File", visible=False)
|
435 |
|
436 |
with gr.Tabs(selected='tab_options' if TURBO_MODE else 'tab_export'):
|
437 |
+
with gr.Tab("Options", id='tab_options', visible=TURBO_MODE):
|
438 |
+
gen_mode = gr.Radio(label='Generation Mode',
|
439 |
+
info='Recommendation: Turbo for most cases, Fast for very complex cases, Standard seldom use.',
|
440 |
choices=['Turbo', 'Fast', 'Standard'], value='Turbo')
|
441 |
+
decode_mode = gr.Radio(label='Decoding Mode',
|
442 |
+
info='The resolution for exporting mesh from generated vectset',
|
443 |
choices=['Low', 'Standard', 'High'],
|
444 |
value='Standard')
|
445 |
+
with gr.Tab('Advanced Options', id='tab_advanced_options'):
|
446 |
with gr.Row():
|
447 |
+
check_box_rembg = gr.Checkbox(value=True, label='Remove Background', min_width=100)
|
448 |
+
randomize_seed = gr.Checkbox(label="Randomize seed", value=True, min_width=100)
|
449 |
seed = gr.Slider(
|
450 |
+
label="Seed",
|
451 |
minimum=0,
|
452 |
maximum=MAX_SEED,
|
453 |
step=1,
|
|
|
478 |
file_export = gr.DownloadButton(label="Download", variant='primary',
|
479 |
interactive=False, min_width=100)
|
480 |
|
481 |
+
with gr.Column(scale=6):
|
482 |
with gr.Tabs(selected='gen_mesh_panel') as tabs_output:
|
483 |
with gr.Tab('Generated Mesh', id='gen_mesh_panel'):
|
484 |
html_gen_mesh = gr.HTML(HTML_OUTPUT_PLACEHOLDER, label='Output')
|
|
|
487 |
with gr.Tab('Mesh Statistic', id='stats_panel'):
|
488 |
stats = gr.Json({}, label='Mesh Stats')
|
489 |
|
490 |
+
with gr.Column(scale=3 if MV_MODE else 2):
|
491 |
+
with gr.Tabs(selected='tab_img_gallery') as gallery:
|
492 |
+
with gr.Tab('Image to 3D Gallery', id='tab_img_gallery', visible=not MV_MODE) as tab_gi:
|
493 |
+
with gr.Row():
|
494 |
+
gr.Examples(examples=example_is, inputs=[image],
|
495 |
+
label=None, examples_per_page=18)
|
496 |
+
|
497 |
+
with gr.Tab('Text to 3D Gallery', id='tab_txt_gallery', visible=HAS_T2I and not MV_MODE) as tab_gt:
|
498 |
+
with gr.Row():
|
499 |
+
gr.Examples(examples=example_ts, inputs=[caption],
|
500 |
+
label=None, examples_per_page=18)
|
501 |
+
with gr.Tab('MultiView to 3D Gallery', id='tab_mv_gallery', visible=MV_MODE) as tab_mv:
|
502 |
+
with gr.Row():
|
503 |
+
gr.Examples(examples=example_mvs,
|
504 |
+
inputs=[mv_image_front, mv_image_back, mv_image_left, mv_image_right],
|
505 |
+
label=None, examples_per_page=6)
|
506 |
+
|
507 |
+
tab_ip.select(fn=lambda: gr.update(selected='tab_img_gallery'), outputs=gallery)
|
508 |
+
if HAS_T2I:
|
509 |
+
tab_tp.select(fn=lambda: gr.update(selected='tab_txt_gallery'), outputs=gallery)
|
510 |
|
511 |
btn.click(
|
512 |
shape_generation,
|
|
|
535 |
outputs=[tabs_output],
|
536 |
)
|
537 |
|
538 |
+
btn_all.click(
|
539 |
+
generation_all,
|
540 |
+
inputs=[
|
541 |
+
caption,
|
542 |
+
image,
|
543 |
+
mv_image_front,
|
544 |
+
mv_image_back,
|
545 |
+
mv_image_left,
|
546 |
+
mv_image_right,
|
547 |
+
num_steps,
|
548 |
+
cfg_scale,
|
549 |
+
seed,
|
550 |
+
octree_resolution,
|
551 |
+
check_box_rembg,
|
552 |
+
num_chunks,
|
553 |
+
randomize_seed,
|
554 |
+
],
|
555 |
+
outputs=[file_out, file_out2, html_gen_mesh, stats, seed]
|
556 |
+
).then(
|
557 |
+
lambda: (gr.update(visible=True, value=True), gr.update(interactive=False), gr.update(interactive=True),
|
558 |
+
gr.update(interactive=False)),
|
559 |
+
outputs=[export_texture, reduce_face, confirm_export, file_export],
|
560 |
+
).then(
|
561 |
+
lambda: gr.update(selected='gen_mesh_panel'),
|
562 |
+
outputs=[tabs_output],
|
563 |
+
)
|
564 |
+
|
565 |
def on_gen_mode_change(value):
|
566 |
if value == 'Turbo':
|
567 |
return gr.update(value=5)
|
|
|
646 |
parser.add_argument('--low_vram_mode', action='store_true')
|
647 |
args = parser.parse_args()
|
648 |
|
649 |
+
try:
|
650 |
+
port = int(args.port)
|
651 |
+
except ValueError:
|
652 |
+
print(f"Invalid port argument detected: {args.port} — using default 7860")
|
653 |
+
port = 7860
|
654 |
+
|
655 |
args.enable_flashvdm = True
|
656 |
SAVE_DIR = args.cache_path
|
657 |
os.makedirs(SAVE_DIR, exist_ok=True)
|
|
|
665 |
HTML_OUTPUT_PLACEHOLDER = f"""
|
666 |
<div style='height: {650}px; width: 100%; border-radius: 8px; border-color: #e5e7eb; border-style: solid; border-width: 1px; display: flex; justify-content: center; align-items: center;'>
|
667 |
<div style='text-align: center; font-size: 16px; color: #6b7280;'>
|
668 |
+
<p style="color: #8d8d8d;">Bienvenido a 3DMarket</p>
|
669 |
</div>
|
670 |
</div>
|
671 |
"""
|
|
|
675 |
border-color: #e5e7eb; order-style: solid; border-width: 1px;'>
|
676 |
</div>
|
677 |
"""
|
678 |
+
|
679 |
+
demo = gr.Interface(fn=my_gpu_function, inputs=[], outputs="text")
|
680 |
+
example_is = get_example_img_list()
|
681 |
+
example_ts = get_example_txt_list()
|
682 |
+
example_mvs = get_example_mv_list()
|
683 |
+
|
684 |
SUPPORTED_FORMATS = ['glb', 'obj', 'ply', 'stl']
|
685 |
|
686 |
HAS_TEXTUREGEN = False
|
|
|
691 |
texgen_worker = Hunyuan3DPaintPipeline.from_pretrained(args.texgen_model_path)
|
692 |
if args.low_vram_mode:
|
693 |
texgen_worker.enable_model_cpu_offload()
|
694 |
+
|
|
|
|
|
|
|
|
|
|
|
695 |
HAS_TEXTUREGEN = True
|
696 |
except Exception as e:
|
697 |
print(e)
|
|
|
728 |
degenerate_face_remove_worker = DegenerateFaceRemover()
|
729 |
face_reduce_worker = FaceReducer()
|
730 |
|
|
|
|
|
|
|
731 |
# create a static directory to store the static files
|
732 |
static_dir = Path(SAVE_DIR).absolute()
|
733 |
static_dir.mkdir(parents=True, exist_ok=True)
|
|
|
734 |
shutil.copytree('./assets/env_maps', os.path.join(static_dir, 'env_maps'), dirs_exist_ok=True)
|
735 |
|
736 |
+
|
737 |
if args.low_vram_mode:
|
738 |
torch.cuda.empty_cache()
|
739 |
demo = build_app()
|
740 |
+
demo.launch()
|
|