Spaces:
Running
on
T4
Running
on
T4
Upload gradio_app.py
Browse files- gradio_app.py +25 -165
gradio_app.py
CHANGED
@@ -31,10 +31,9 @@ from hy3dgen.shapegen.utils import logger
|
|
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,38 +42,6 @@ if True:
|
|
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)
|
@@ -366,28 +333,10 @@ def shape_generation(
|
|
366 |
|
367 |
|
368 |
def build_app():
|
369 |
-
title = 'Hunyuan3D-2: High Resolution Textured 3D Assets Generation'
|
370 |
-
if MV_MODE:
|
371 |
-
title = 'Hunyuan3D-2mv: Image to 3D Generation with 1-4 Views'
|
372 |
-
if 'mini' in args.subfolder:
|
373 |
-
title = 'Hunyuan3D-2mini: Strong 0.6B Image to Shape Generator'
|
374 |
-
if TURBO_MODE:
|
375 |
-
title = title.replace(':', '-Turbo: Fast ')
|
376 |
|
377 |
title_html = f"""
|
378 |
<div style="font-size: 2em; font-weight: bold; text-align: center; margin-bottom: 5px">
|
379 |
-
|
380 |
-
{title}
|
381 |
-
</div>
|
382 |
-
<div align="center">
|
383 |
-
Tencent Hunyuan3D Team
|
384 |
-
</div>
|
385 |
-
<div align="center">
|
386 |
-
<a href="https://github.com/tencent/Hunyuan3D-2">Github</a>  
|
387 |
-
<a href="http://3d-models.hunyuan.tencent.com">Homepage</a>  
|
388 |
-
<a href="https://3d.hunyuan.tencent.com">Hunyuan3D Studio</a>  
|
389 |
-
<a href="#">Technical Report</a>  
|
390 |
-
<a href="https://huggingface.co/Tencent/Hunyuan3D-2"> Pretrained Models</a>  
|
391 |
</div>
|
392 |
"""
|
393 |
custom_css = """
|
@@ -401,7 +350,6 @@ def build_app():
|
|
401 |
.mv-image .icon-wrap {
|
402 |
width: 20px;
|
403 |
}
|
404 |
-
|
405 |
"""
|
406 |
|
407 |
with gr.Blocks(theme=gr.themes.Base(), title='Hunyuan-3D-2.0', analytics_enabled=False, css=custom_css) as demo:
|
@@ -417,45 +365,42 @@ def build_app():
|
|
417 |
caption = gr.Textbox(label='Text Prompt',
|
418 |
placeholder='HunyuanDiT will be used to generate image.',
|
419 |
info='Example: A 3D model of a cute cat, white background')
|
|
|
420 |
with gr.Tab('MultiView Prompt', visible=MV_MODE) as tab_mv:
|
421 |
# gr.Label('Please upload at least one front image.')
|
422 |
with gr.Row():
|
423 |
-
mv_image_front = gr.Image(label='
|
424 |
min_width=100, elem_classes='mv-image')
|
425 |
-
mv_image_back = gr.Image(label='
|
426 |
min_width=100, elem_classes='mv-image')
|
427 |
with gr.Row():
|
428 |
-
mv_image_left = gr.Image(label='
|
429 |
min_width=100, elem_classes='mv-image')
|
430 |
-
mv_image_right = gr.Image(label='
|
431 |
min_width=100, elem_classes='mv-image')
|
432 |
|
433 |
with gr.Row():
|
434 |
-
btn = gr.Button(value='
|
435 |
-
btn_all = gr.Button(value='Gen Textured Shape',
|
436 |
-
variant='primary',
|
437 |
-
visible=HAS_TEXTUREGEN,
|
438 |
-
min_width=100)
|
439 |
|
440 |
with gr.Group():
|
441 |
file_out = gr.File(label="File", visible=False)
|
442 |
file_out2 = gr.File(label="File", visible=False)
|
443 |
|
444 |
with gr.Tabs(selected='tab_options' if TURBO_MODE else 'tab_export'):
|
445 |
-
with gr.Tab("
|
446 |
-
gen_mode = gr.Radio(label='
|
447 |
-
info='
|
448 |
choices=['Turbo', 'Fast', 'Standard'], value='Turbo')
|
449 |
-
decode_mode = gr.Radio(label='
|
450 |
-
info='
|
451 |
choices=['Low', 'Standard', 'High'],
|
452 |
value='Standard')
|
453 |
-
with gr.Tab('
|
454 |
with gr.Row():
|
455 |
-
check_box_rembg = gr.Checkbox(value=True, label='
|
456 |
-
randomize_seed = gr.Checkbox(label="
|
457 |
seed = gr.Slider(
|
458 |
-
label="
|
459 |
minimum=0,
|
460 |
maximum=MAX_SEED,
|
461 |
step=1,
|
@@ -486,7 +431,7 @@ def build_app():
|
|
486 |
file_export = gr.DownloadButton(label="Download", variant='primary',
|
487 |
interactive=False, min_width=100)
|
488 |
|
489 |
-
with gr.Column(scale=
|
490 |
with gr.Tabs(selected='gen_mesh_panel') as tabs_output:
|
491 |
with gr.Tab('Generated Mesh', id='gen_mesh_panel'):
|
492 |
html_gen_mesh = gr.HTML(HTML_OUTPUT_PLACEHOLDER, label='Output')
|
@@ -495,48 +440,6 @@ def build_app():
|
|
495 |
with gr.Tab('Mesh Statistic', id='stats_panel'):
|
496 |
stats = gr.Json({}, label='Mesh Stats')
|
497 |
|
498 |
-
with gr.Column(scale=3 if MV_MODE else 2):
|
499 |
-
with gr.Tabs(selected='tab_img_gallery') as gallery:
|
500 |
-
with gr.Tab('Image to 3D Gallery', id='tab_img_gallery', visible=not MV_MODE) as tab_gi:
|
501 |
-
with gr.Row():
|
502 |
-
gr.Examples(examples=example_is, inputs=[image],
|
503 |
-
label=None, examples_per_page=18)
|
504 |
-
|
505 |
-
with gr.Tab('Text to 3D Gallery', id='tab_txt_gallery', visible=HAS_T2I and not MV_MODE) as tab_gt:
|
506 |
-
with gr.Row():
|
507 |
-
gr.Examples(examples=example_ts, inputs=[caption],
|
508 |
-
label=None, examples_per_page=18)
|
509 |
-
with gr.Tab('MultiView to 3D Gallery', id='tab_mv_gallery', visible=MV_MODE) as tab_mv:
|
510 |
-
with gr.Row():
|
511 |
-
gr.Examples(examples=example_mvs,
|
512 |
-
inputs=[mv_image_front, mv_image_back, mv_image_left, mv_image_right],
|
513 |
-
label=None, examples_per_page=6)
|
514 |
-
|
515 |
-
gr.HTML(f"""
|
516 |
-
<div align="center">
|
517 |
-
Activated Model - Shape Generation ({args.model_path}/{args.subfolder}) ; Texture Generation ({'Hunyuan3D-2' if HAS_TEXTUREGEN else 'Unavailable'})
|
518 |
-
</div>
|
519 |
-
""")
|
520 |
-
if not HAS_TEXTUREGEN:
|
521 |
-
gr.HTML("""
|
522 |
-
<div style="margin-top: 5px;" align="center">
|
523 |
-
<b>Warning: </b>
|
524 |
-
Texture synthesis is disable due to missing requirements,
|
525 |
-
please install requirements following <a href="https://github.com/Tencent/Hunyuan3D-2?tab=readme-ov-file#install-requirements">README.md</a>to activate it.
|
526 |
-
</div>
|
527 |
-
""")
|
528 |
-
if not args.enable_t23d:
|
529 |
-
gr.HTML("""
|
530 |
-
<div style="margin-top: 5px;" align="center">
|
531 |
-
<b>Warning: </b>
|
532 |
-
Text to 3D is disable. To activate it, please run `python gradio_app.py --enable_t23d`.
|
533 |
-
</div>
|
534 |
-
""")
|
535 |
-
|
536 |
-
tab_ip.select(fn=lambda: gr.update(selected='tab_img_gallery'), outputs=gallery)
|
537 |
-
if HAS_T2I:
|
538 |
-
tab_tp.select(fn=lambda: gr.update(selected='tab_txt_gallery'), outputs=gallery)
|
539 |
-
|
540 |
|
541 |
btn.click(
|
542 |
shape_generation,
|
@@ -565,33 +468,6 @@ def build_app():
|
|
565 |
outputs=[tabs_output],
|
566 |
)
|
567 |
|
568 |
-
btn_all.click(
|
569 |
-
generation_all,
|
570 |
-
inputs=[
|
571 |
-
caption,
|
572 |
-
image,
|
573 |
-
mv_image_front,
|
574 |
-
mv_image_back,
|
575 |
-
mv_image_left,
|
576 |
-
mv_image_right,
|
577 |
-
num_steps,
|
578 |
-
cfg_scale,
|
579 |
-
seed,
|
580 |
-
octree_resolution,
|
581 |
-
check_box_rembg,
|
582 |
-
num_chunks,
|
583 |
-
randomize_seed,
|
584 |
-
],
|
585 |
-
outputs=[file_out, file_out2, html_gen_mesh, stats, seed]
|
586 |
-
).then(
|
587 |
-
lambda: (gr.update(visible=True, value=True), gr.update(interactive=False), gr.update(interactive=True),
|
588 |
-
gr.update(interactive=False)),
|
589 |
-
outputs=[export_texture, reduce_face, confirm_export, file_export],
|
590 |
-
).then(
|
591 |
-
lambda: gr.update(selected='gen_mesh_panel'),
|
592 |
-
outputs=[tabs_output],
|
593 |
-
)
|
594 |
-
|
595 |
def on_gen_mode_change(value):
|
596 |
if value == 'Turbo':
|
597 |
return gr.update(value=5)
|
@@ -676,12 +552,6 @@ if __name__ == '__main__':
|
|
676 |
parser.add_argument('--low_vram_mode', action='store_true')
|
677 |
args = parser.parse_args()
|
678 |
|
679 |
-
try:
|
680 |
-
port = int(args.port)
|
681 |
-
except ValueError:
|
682 |
-
print(f"Invalid port argument detected: {args.port} — using default 7860")
|
683 |
-
port = 7860
|
684 |
-
|
685 |
args.enable_flashvdm = True
|
686 |
SAVE_DIR = args.cache_path
|
687 |
os.makedirs(SAVE_DIR, exist_ok=True)
|
@@ -695,8 +565,7 @@ if __name__ == '__main__':
|
|
695 |
HTML_OUTPUT_PLACEHOLDER = f"""
|
696 |
<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;'>
|
697 |
<div style='text-align: center; font-size: 16px; color: #6b7280;'>
|
698 |
-
<p style="color: #8d8d8d;">
|
699 |
-
<p style="color: #8d8d8d;">No mesh here.</p>
|
700 |
</div>
|
701 |
</div>
|
702 |
"""
|
@@ -706,14 +575,7 @@ if __name__ == '__main__':
|
|
706 |
border-color: #e5e7eb; order-style: solid; border-width: 1px;'>
|
707 |
</div>
|
708 |
"""
|
709 |
-
|
710 |
-
#demo = gr.Interface(fn=my_gpu_function, inputs=[], outputs="text")
|
711 |
-
#demo.launch()
|
712 |
-
|
713 |
-
example_is = get_example_img_list()
|
714 |
-
example_ts = get_example_txt_list()
|
715 |
-
example_mvs = get_example_mv_list()
|
716 |
-
|
717 |
SUPPORTED_FORMATS = ['glb', 'obj', 'ply', 'stl']
|
718 |
|
719 |
HAS_TEXTUREGEN = False
|
@@ -768,17 +630,15 @@ if __name__ == '__main__':
|
|
768 |
|
769 |
# https://discuss.huggingface.co/t/how-to-serve-an-html-file/33921/2
|
770 |
# create a FastAPI app
|
771 |
-
|
772 |
# create a static directory to store the static files
|
773 |
static_dir = Path(SAVE_DIR).absolute()
|
774 |
static_dir.mkdir(parents=True, exist_ok=True)
|
775 |
-
|
776 |
shutil.copytree('./assets/env_maps', os.path.join(static_dir, 'env_maps'), dirs_exist_ok=True)
|
777 |
|
778 |
-
|
779 |
if args.low_vram_mode:
|
780 |
torch.cuda.empty_cache()
|
781 |
demo = build_app()
|
782 |
-
|
783 |
-
|
784 |
-
#uvicorn.run(app, host=args.host, port=args.port)
|
|
|
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 |
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)
|
|
|
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 |
+
Genera tu modelo 3D desde fotos
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
</div>
|
341 |
"""
|
342 |
custom_css = """
|
|
|
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:
|
|
|
365 |
caption = gr.Textbox(label='Text Prompt',
|
366 |
placeholder='HunyuanDiT will be used to generate image.',
|
367 |
info='Example: A 3D model of a cute cat, white background')
|
368 |
+
|
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='Frente', type='pil', image_mode='RGBA', height=140,
|
373 |
min_width=100, elem_classes='mv-image')
|
374 |
+
mv_image_back = gr.Image(label='Parte trasera', type='pil', image_mode='RGBA', height=140,
|
375 |
min_width=100, elem_classes='mv-image')
|
376 |
with gr.Row():
|
377 |
+
mv_image_left = gr.Image(label='Izquierda', type='pil', image_mode='RGBA', height=140,
|
378 |
min_width=100, elem_classes='mv-image')
|
379 |
+
mv_image_right = gr.Image(label='Derecha', type='pil', image_mode='RGBA', height=140,
|
380 |
min_width=100, elem_classes='mv-image')
|
381 |
|
382 |
with gr.Row():
|
383 |
+
btn = gr.Button(value='Generar modelo', variant='primary', min_width=100)
|
|
|
|
|
|
|
|
|
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("Opciones", id='tab_options', visible=TURBO_MODE):
|
391 |
+
gen_mode = gr.Radio(label='Modo de generacioón',
|
392 |
+
info='Recomendacioón: Turbo por la mayoria, Fast para modelos complejos, Standard para uso cualquiera.',
|
393 |
choices=['Turbo', 'Fast', 'Standard'], value='Turbo')
|
394 |
+
decode_mode = gr.Radio(label='Modo de decoding',
|
395 |
+
info='La resolución para la exportación de la malla desde el vectset generado',
|
396 |
choices=['Low', 'Standard', 'High'],
|
397 |
value='Standard')
|
398 |
+
with gr.Tab('Opciones avanzadas', id='tab_advanced_options'):
|
399 |
with gr.Row():
|
400 |
+
check_box_rembg = gr.Checkbox(value=True, label='Eliminar fondo', min_width=100)
|
401 |
+
randomize_seed = gr.Checkbox(label="Generar semilla aleatoria", value=True, min_width=100)
|
402 |
seed = gr.Slider(
|
403 |
+
label="Semmilla",
|
404 |
minimum=0,
|
405 |
maximum=MAX_SEED,
|
406 |
step=1,
|
|
|
431 |
file_export = gr.DownloadButton(label="Download", variant='primary',
|
432 |
interactive=False, min_width=100)
|
433 |
|
434 |
+
with gr.Column(scale=9):
|
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 |
with gr.Tab('Mesh Statistic', id='stats_panel'):
|
441 |
stats = gr.Json({}, label='Mesh Stats')
|
442 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
443 |
|
444 |
btn.click(
|
445 |
shape_generation,
|
|
|
468 |
outputs=[tabs_output],
|
469 |
)
|
470 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
471 |
def on_gen_mode_change(value):
|
472 |
if value == 'Turbo':
|
473 |
return gr.update(value=5)
|
|
|
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 |
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;">Carga tus fotos para generar el modelo 3D</p>
|
|
|
569 |
</div>
|
570 |
</div>
|
571 |
"""
|
|
|
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
|
|
|
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 |
+
app = gr.mount_gradio_app(app, demo, path="/")
|
644 |
+
uvicorn.run(app, host=args.host, port=args.port)
|
|