Spaces:
Running on Zero
Running on Zero
Real manifest-driven gallery + API temp-dir bugfix (#2)
Browse files- Real manifest-driven gallery + API temp-dir bugfix (ff51da1dbb77510ce6ffd9c1a975d3275276f5c7)
- .gitattributes +102 -99
- app.py +72 -32
- assets/gallery/a_backpack_for_kids_flower_style/glb.glb +3 -0
- assets/gallery/a_backpack_for_kids_flower_style/image.png +3 -0
- assets/gallery/a_backpack_for_kids_flower_style/video.mp4 +3 -0
- assets/gallery/cat_shaped_cake_mold/glb.glb +3 -0
- assets/gallery/cat_shaped_cake_mold/image.png +3 -0
- assets/gallery/cat_shaped_cake_mold/video.mp4 +3 -0
- assets/gallery/manifest.json +23 -0
- assets/gallery/medieval_flip_flops/glb.glb +3 -0
- assets/gallery/medieval_flip_flops/image.png +3 -0
- assets/gallery/medieval_flip_flops/video.mp4 +3 -0
- scripts/generate_gallery.py +144 -0
.gitattributes
CHANGED
|
@@ -1,99 +1,102 @@
|
|
| 1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
-
assets/example_image/T.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
-
assets/example_image/typical_building_building.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
-
assets/example_image/typical_building_castle.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
-
assets/example_image/typical_building_colorful_cottage.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
-
assets/example_image/typical_building_maya_pyramid.png filter=lfs diff=lfs merge=lfs -text
|
| 41 |
-
assets/example_image/typical_building_mushroom.png filter=lfs diff=lfs merge=lfs -text
|
| 42 |
-
assets/example_image/typical_building_space_station.png filter=lfs diff=lfs merge=lfs -text
|
| 43 |
-
assets/example_image/typical_creature_dragon.png filter=lfs diff=lfs merge=lfs -text
|
| 44 |
-
assets/example_image/typical_creature_elephant.png filter=lfs diff=lfs merge=lfs -text
|
| 45 |
-
assets/example_image/typical_creature_furry.png filter=lfs diff=lfs merge=lfs -text
|
| 46 |
-
assets/example_image/typical_creature_quadruped.png filter=lfs diff=lfs merge=lfs -text
|
| 47 |
-
assets/example_image/typical_creature_robot_crab.png filter=lfs diff=lfs merge=lfs -text
|
| 48 |
-
assets/example_image/typical_creature_robot_dinosour.png filter=lfs diff=lfs merge=lfs -text
|
| 49 |
-
assets/example_image/typical_creature_rock_monster.png filter=lfs diff=lfs merge=lfs -text
|
| 50 |
-
assets/example_image/typical_humanoid_block_robot.png filter=lfs diff=lfs merge=lfs -text
|
| 51 |
-
assets/example_image/typical_humanoid_dragonborn.png filter=lfs diff=lfs merge=lfs -text
|
| 52 |
-
assets/example_image/typical_humanoid_dwarf.png filter=lfs diff=lfs merge=lfs -text
|
| 53 |
-
assets/example_image/typical_humanoid_goblin.png filter=lfs diff=lfs merge=lfs -text
|
| 54 |
-
assets/example_image/typical_humanoid_mech.png filter=lfs diff=lfs merge=lfs -text
|
| 55 |
-
assets/example_image/typical_misc_crate.png filter=lfs diff=lfs merge=lfs -text
|
| 56 |
-
assets/example_image/typical_misc_fireplace.png filter=lfs diff=lfs merge=lfs -text
|
| 57 |
-
assets/example_image/typical_misc_gate.png filter=lfs diff=lfs merge=lfs -text
|
| 58 |
-
assets/example_image/typical_misc_lantern.png filter=lfs diff=lfs merge=lfs -text
|
| 59 |
-
assets/example_image/typical_misc_magicbook.png filter=lfs diff=lfs merge=lfs -text
|
| 60 |
-
assets/example_image/typical_misc_mailbox.png filter=lfs diff=lfs merge=lfs -text
|
| 61 |
-
assets/example_image/typical_misc_monster_chest.png filter=lfs diff=lfs merge=lfs -text
|
| 62 |
-
assets/example_image/typical_misc_paper_machine.png filter=lfs diff=lfs merge=lfs -text
|
| 63 |
-
assets/example_image/typical_misc_phonograph.png filter=lfs diff=lfs merge=lfs -text
|
| 64 |
-
assets/example_image/typical_misc_portal2.png filter=lfs diff=lfs merge=lfs -text
|
| 65 |
-
assets/example_image/typical_misc_storage_chest.png filter=lfs diff=lfs merge=lfs -text
|
| 66 |
-
assets/example_image/typical_misc_telephone.png filter=lfs diff=lfs merge=lfs -text
|
| 67 |
-
assets/example_image/typical_misc_television.png filter=lfs diff=lfs merge=lfs -text
|
| 68 |
-
assets/example_image/typical_misc_workbench.png filter=lfs diff=lfs merge=lfs -text
|
| 69 |
-
assets/example_image/typical_vehicle_biplane.png filter=lfs diff=lfs merge=lfs -text
|
| 70 |
-
assets/example_image/typical_vehicle_bulldozer.png filter=lfs diff=lfs merge=lfs -text
|
| 71 |
-
assets/example_image/typical_vehicle_cart.png filter=lfs diff=lfs merge=lfs -text
|
| 72 |
-
assets/example_image/typical_vehicle_excavator.png filter=lfs diff=lfs merge=lfs -text
|
| 73 |
-
assets/example_image/typical_vehicle_helicopter.png filter=lfs diff=lfs merge=lfs -text
|
| 74 |
-
assets/example_image/typical_vehicle_locomotive.png filter=lfs diff=lfs merge=lfs -text
|
| 75 |
-
assets/example_image/typical_vehicle_pirate_ship.png filter=lfs diff=lfs merge=lfs -text
|
| 76 |
-
assets/example_image/weatherworn_misc_paper_machine3.png filter=lfs diff=lfs merge=lfs -text
|
| 77 |
-
assets/example_multi_image/character_1.png filter=lfs diff=lfs merge=lfs -text
|
| 78 |
-
assets/example_multi_image/character_2.png filter=lfs diff=lfs merge=lfs -text
|
| 79 |
-
assets/example_multi_image/character_3.png filter=lfs diff=lfs merge=lfs -text
|
| 80 |
-
assets/example_multi_image/mushroom_1.png filter=lfs diff=lfs merge=lfs -text
|
| 81 |
-
assets/example_multi_image/mushroom_2.png filter=lfs diff=lfs merge=lfs -text
|
| 82 |
-
assets/example_multi_image/mushroom_3.png filter=lfs diff=lfs merge=lfs -text
|
| 83 |
-
assets/example_multi_image/orangeguy_1.png filter=lfs diff=lfs merge=lfs -text
|
| 84 |
-
assets/example_multi_image/orangeguy_2.png filter=lfs diff=lfs merge=lfs -text
|
| 85 |
-
assets/example_multi_image/orangeguy_3.png filter=lfs diff=lfs merge=lfs -text
|
| 86 |
-
assets/example_multi_image/popmart_1.png filter=lfs diff=lfs merge=lfs -text
|
| 87 |
-
assets/example_multi_image/popmart_2.png filter=lfs diff=lfs merge=lfs -text
|
| 88 |
-
assets/example_multi_image/popmart_3.png filter=lfs diff=lfs merge=lfs -text
|
| 89 |
-
assets/example_multi_image/rabbit_1.png filter=lfs diff=lfs merge=lfs -text
|
| 90 |
-
assets/example_multi_image/rabbit_2.png filter=lfs diff=lfs merge=lfs -text
|
| 91 |
-
assets/example_multi_image/rabbit_3.png filter=lfs diff=lfs merge=lfs -text
|
| 92 |
-
assets/example_multi_image/tiger_1.png filter=lfs diff=lfs merge=lfs -text
|
| 93 |
-
assets/example_multi_image/tiger_2.png filter=lfs diff=lfs merge=lfs -text
|
| 94 |
-
assets/example_multi_image/tiger_3.png filter=lfs diff=lfs merge=lfs -text
|
| 95 |
-
assets/example_multi_image/yoimiya_1.png filter=lfs diff=lfs merge=lfs -text
|
| 96 |
-
assets/example_multi_image/yoimiya_2.png filter=lfs diff=lfs merge=lfs -text
|
| 97 |
-
assets/example_multi_image/yoimiya_3.png filter=lfs diff=lfs merge=lfs -text
|
| 98 |
-
wheels/diff_gaussian_rasterization-0.0.0-cp310-cp310-linux_x86_64.whl filter=lfs diff=lfs merge=lfs -text
|
| 99 |
-
wheels/nvdiffrast-0.3.3-cp310-cp310-linux_x86_64.whl filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
assets/example_image/T.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
assets/example_image/typical_building_building.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
assets/example_image/typical_building_castle.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
assets/example_image/typical_building_colorful_cottage.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
assets/example_image/typical_building_maya_pyramid.png filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
assets/example_image/typical_building_mushroom.png filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
assets/example_image/typical_building_space_station.png filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
assets/example_image/typical_creature_dragon.png filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
assets/example_image/typical_creature_elephant.png filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
assets/example_image/typical_creature_furry.png filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
assets/example_image/typical_creature_quadruped.png filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
assets/example_image/typical_creature_robot_crab.png filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
assets/example_image/typical_creature_robot_dinosour.png filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
assets/example_image/typical_creature_rock_monster.png filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
assets/example_image/typical_humanoid_block_robot.png filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
assets/example_image/typical_humanoid_dragonborn.png filter=lfs diff=lfs merge=lfs -text
|
| 52 |
+
assets/example_image/typical_humanoid_dwarf.png filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
assets/example_image/typical_humanoid_goblin.png filter=lfs diff=lfs merge=lfs -text
|
| 54 |
+
assets/example_image/typical_humanoid_mech.png filter=lfs diff=lfs merge=lfs -text
|
| 55 |
+
assets/example_image/typical_misc_crate.png filter=lfs diff=lfs merge=lfs -text
|
| 56 |
+
assets/example_image/typical_misc_fireplace.png filter=lfs diff=lfs merge=lfs -text
|
| 57 |
+
assets/example_image/typical_misc_gate.png filter=lfs diff=lfs merge=lfs -text
|
| 58 |
+
assets/example_image/typical_misc_lantern.png filter=lfs diff=lfs merge=lfs -text
|
| 59 |
+
assets/example_image/typical_misc_magicbook.png filter=lfs diff=lfs merge=lfs -text
|
| 60 |
+
assets/example_image/typical_misc_mailbox.png filter=lfs diff=lfs merge=lfs -text
|
| 61 |
+
assets/example_image/typical_misc_monster_chest.png filter=lfs diff=lfs merge=lfs -text
|
| 62 |
+
assets/example_image/typical_misc_paper_machine.png filter=lfs diff=lfs merge=lfs -text
|
| 63 |
+
assets/example_image/typical_misc_phonograph.png filter=lfs diff=lfs merge=lfs -text
|
| 64 |
+
assets/example_image/typical_misc_portal2.png filter=lfs diff=lfs merge=lfs -text
|
| 65 |
+
assets/example_image/typical_misc_storage_chest.png filter=lfs diff=lfs merge=lfs -text
|
| 66 |
+
assets/example_image/typical_misc_telephone.png filter=lfs diff=lfs merge=lfs -text
|
| 67 |
+
assets/example_image/typical_misc_television.png filter=lfs diff=lfs merge=lfs -text
|
| 68 |
+
assets/example_image/typical_misc_workbench.png filter=lfs diff=lfs merge=lfs -text
|
| 69 |
+
assets/example_image/typical_vehicle_biplane.png filter=lfs diff=lfs merge=lfs -text
|
| 70 |
+
assets/example_image/typical_vehicle_bulldozer.png filter=lfs diff=lfs merge=lfs -text
|
| 71 |
+
assets/example_image/typical_vehicle_cart.png filter=lfs diff=lfs merge=lfs -text
|
| 72 |
+
assets/example_image/typical_vehicle_excavator.png filter=lfs diff=lfs merge=lfs -text
|
| 73 |
+
assets/example_image/typical_vehicle_helicopter.png filter=lfs diff=lfs merge=lfs -text
|
| 74 |
+
assets/example_image/typical_vehicle_locomotive.png filter=lfs diff=lfs merge=lfs -text
|
| 75 |
+
assets/example_image/typical_vehicle_pirate_ship.png filter=lfs diff=lfs merge=lfs -text
|
| 76 |
+
assets/example_image/weatherworn_misc_paper_machine3.png filter=lfs diff=lfs merge=lfs -text
|
| 77 |
+
assets/example_multi_image/character_1.png filter=lfs diff=lfs merge=lfs -text
|
| 78 |
+
assets/example_multi_image/character_2.png filter=lfs diff=lfs merge=lfs -text
|
| 79 |
+
assets/example_multi_image/character_3.png filter=lfs diff=lfs merge=lfs -text
|
| 80 |
+
assets/example_multi_image/mushroom_1.png filter=lfs diff=lfs merge=lfs -text
|
| 81 |
+
assets/example_multi_image/mushroom_2.png filter=lfs diff=lfs merge=lfs -text
|
| 82 |
+
assets/example_multi_image/mushroom_3.png filter=lfs diff=lfs merge=lfs -text
|
| 83 |
+
assets/example_multi_image/orangeguy_1.png filter=lfs diff=lfs merge=lfs -text
|
| 84 |
+
assets/example_multi_image/orangeguy_2.png filter=lfs diff=lfs merge=lfs -text
|
| 85 |
+
assets/example_multi_image/orangeguy_3.png filter=lfs diff=lfs merge=lfs -text
|
| 86 |
+
assets/example_multi_image/popmart_1.png filter=lfs diff=lfs merge=lfs -text
|
| 87 |
+
assets/example_multi_image/popmart_2.png filter=lfs diff=lfs merge=lfs -text
|
| 88 |
+
assets/example_multi_image/popmart_3.png filter=lfs diff=lfs merge=lfs -text
|
| 89 |
+
assets/example_multi_image/rabbit_1.png filter=lfs diff=lfs merge=lfs -text
|
| 90 |
+
assets/example_multi_image/rabbit_2.png filter=lfs diff=lfs merge=lfs -text
|
| 91 |
+
assets/example_multi_image/rabbit_3.png filter=lfs diff=lfs merge=lfs -text
|
| 92 |
+
assets/example_multi_image/tiger_1.png filter=lfs diff=lfs merge=lfs -text
|
| 93 |
+
assets/example_multi_image/tiger_2.png filter=lfs diff=lfs merge=lfs -text
|
| 94 |
+
assets/example_multi_image/tiger_3.png filter=lfs diff=lfs merge=lfs -text
|
| 95 |
+
assets/example_multi_image/yoimiya_1.png filter=lfs diff=lfs merge=lfs -text
|
| 96 |
+
assets/example_multi_image/yoimiya_2.png filter=lfs diff=lfs merge=lfs -text
|
| 97 |
+
assets/example_multi_image/yoimiya_3.png filter=lfs diff=lfs merge=lfs -text
|
| 98 |
+
wheels/diff_gaussian_rasterization-0.0.0-cp310-cp310-linux_x86_64.whl filter=lfs diff=lfs merge=lfs -text
|
| 99 |
+
wheels/nvdiffrast-0.3.3-cp310-cp310-linux_x86_64.whl filter=lfs diff=lfs merge=lfs -text
|
| 100 |
+
assets/gallery/**/*.png filter=lfs diff=lfs merge=lfs -text
|
| 101 |
+
assets/gallery/**/*.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 102 |
+
assets/gallery/**/*.glb filter=lfs diff=lfs merge=lfs -text
|
app.py
CHANGED
|
@@ -230,10 +230,18 @@ def split_reasoning(text: str) -> Tuple[str, str]:
|
|
| 230 |
# Strip any stray opener (e.g. the model omitted the closing tag).
|
| 231 |
prompt = prompt.replace("<think>", "").strip()
|
| 232 |
|
| 233 |
-
# Strip a leading header
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
# Remove wrapping quotation marks.
|
| 239 |
if len(prompt) >= 2 and prompt[0] in "\"'" and prompt[-1] == prompt[0]:
|
|
@@ -358,28 +366,34 @@ css="""
|
|
| 358 |
}
|
| 359 |
"""
|
| 360 |
|
| 361 |
-
#
|
| 362 |
-
#
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
("typical_creature_dragon.png", "Dragon"),
|
| 369 |
-
("typical_building_castle.png", "Castle"),
|
| 370 |
-
("typical_misc_phonograph.png", "Phonograph"),
|
| 371 |
-
("typical_misc_magicbook.png", "Magic book"),
|
| 372 |
-
("typical_vehicle_pirate_ship.png", "Pirate ship"),
|
| 373 |
-
]
|
| 374 |
|
| 375 |
|
| 376 |
def load_gallery():
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 383 |
|
| 384 |
def pack_state(gs: Gaussian, mesh: MeshExtractResult) -> dict:
|
| 385 |
return {
|
|
@@ -458,6 +472,9 @@ def image_to_3d(
|
|
| 458 |
)
|
| 459 |
# temp_dir = os.path.join(TMP_DIR, "temp_output")
|
| 460 |
temp_dir = os.path.join(TMP_DIR, str(req.session_hash))
|
|
|
|
|
|
|
|
|
|
| 461 |
|
| 462 |
video = render_utils.render_video(outputs['gaussian'][0], num_frames=120)['color']
|
| 463 |
video_geo = render_utils.render_video(outputs['mesh'][0], num_frames=120)['normal']
|
|
@@ -672,16 +689,39 @@ def create_interface():
|
|
| 672 |
# ------------------------------------------------------- Gallery
|
| 673 |
with gr.Tab("Galerie"):
|
| 674 |
gr.Markdown(
|
| 675 |
-
"
|
| 676 |
-
"
|
| 677 |
-
|
| 678 |
-
gr.Gallery(
|
| 679 |
-
value=load_gallery(),
|
| 680 |
-
label="Exemples",
|
| 681 |
-
columns=4,
|
| 682 |
-
height="auto",
|
| 683 |
-
object_fit="contain",
|
| 684 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 685 |
|
| 686 |
# --------------------------------------------------- How it works
|
| 687 |
with gr.Tab("Comment ça marche"):
|
|
|
|
| 230 |
# Strip any stray opener (e.g. the model omitted the closing tag).
|
| 231 |
prompt = prompt.replace("<think>", "").strip()
|
| 232 |
|
| 233 |
+
# Strip a leading bold header, whether on its own line ("**Prompt for
|
| 234 |
+
# FLUX:**\n...") or inline ("**Prompt:** actual text"). Only strip when the
|
| 235 |
+
# bold segment looks like a header (mentions "prompt") to avoid removing a
|
| 236 |
+
# legitimate bold opening word.
|
| 237 |
+
stripped = prompt.lstrip()
|
| 238 |
+
if stripped.startswith("**"):
|
| 239 |
+
end = stripped.find("**", 2)
|
| 240 |
+
if end != -1 and "prompt" in stripped[2:end].lower():
|
| 241 |
+
rest = stripped[end + 2:].lstrip()
|
| 242 |
+
if rest.startswith(":"):
|
| 243 |
+
rest = rest[1:]
|
| 244 |
+
prompt = rest.strip()
|
| 245 |
|
| 246 |
# Remove wrapping quotation marks.
|
| 247 |
if len(prompt) >= 2 and prompt[0] in "\"'" and prompt[-1] == prompt[0]:
|
|
|
|
| 366 |
}
|
| 367 |
"""
|
| 368 |
|
| 369 |
+
# Real gallery results produced by running the pipeline on the Space, captured
|
| 370 |
+
# by scripts/generate_gallery.py into assets/gallery/ + manifest.json. Each
|
| 371 |
+
# manifest entry is {prompt, refined_prompt, image, video, glb} with repo-relative
|
| 372 |
+
# asset paths.
|
| 373 |
+
APP_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 374 |
+
GALLERY_DIR = os.path.join(APP_DIR, 'assets', 'gallery')
|
| 375 |
+
GALLERY_MANIFEST = os.path.join(GALLERY_DIR, 'manifest.json')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 376 |
|
| 377 |
|
| 378 |
def load_gallery():
|
| 379 |
+
if not os.path.exists(GALLERY_MANIFEST):
|
| 380 |
+
return []
|
| 381 |
+
import json
|
| 382 |
+
try:
|
| 383 |
+
with open(GALLERY_MANIFEST, encoding='utf-8') as f:
|
| 384 |
+
items = json.load(f)
|
| 385 |
+
except Exception as e:
|
| 386 |
+
print(f"Error loading gallery manifest: {e}")
|
| 387 |
+
return []
|
| 388 |
+
resolved = []
|
| 389 |
+
for it in items:
|
| 390 |
+
entry = dict(it)
|
| 391 |
+
for key in ('image', 'video', 'glb'):
|
| 392 |
+
if it.get(key):
|
| 393 |
+
abs_path = os.path.join(APP_DIR, it[key])
|
| 394 |
+
entry[key] = abs_path if os.path.exists(abs_path) else None
|
| 395 |
+
resolved.append(entry)
|
| 396 |
+
return resolved
|
| 397 |
|
| 398 |
def pack_state(gs: Gaussian, mesh: MeshExtractResult) -> dict:
|
| 399 |
return {
|
|
|
|
| 472 |
)
|
| 473 |
# temp_dir = os.path.join(TMP_DIR, "temp_output")
|
| 474 |
temp_dir = os.path.join(TMP_DIR, str(req.session_hash))
|
| 475 |
+
# The browser `load` event normally creates this via start_session, but
|
| 476 |
+
# API callers (e.g. gradio_client) never trigger it, so ensure it exists.
|
| 477 |
+
os.makedirs(temp_dir, exist_ok=True)
|
| 478 |
|
| 479 |
video = render_utils.render_video(outputs['gaussian'][0], num_frames=120)['color']
|
| 480 |
video_geo = render_utils.render_video(outputs['mesh'][0], num_frames=120)['normal']
|
|
|
|
| 689 |
# ------------------------------------------------------- Gallery
|
| 690 |
with gr.Tab("Galerie"):
|
| 691 |
gr.Markdown(
|
| 692 |
+
"De **vrais résultats** produits par le pipeline complet "
|
| 693 |
+
"(prompt → image → 3D). Affichage instantané, même quand le "
|
| 694 |
+
"GPU est endormi."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 695 |
)
|
| 696 |
+
gallery_items = load_gallery()
|
| 697 |
+
if not gallery_items:
|
| 698 |
+
gr.Markdown(
|
| 699 |
+
"_Galerie en cours de génération — lancez "
|
| 700 |
+
"`python scripts/generate_gallery.py` puis committez "
|
| 701 |
+
"`assets/gallery/`._"
|
| 702 |
+
)
|
| 703 |
+
for item in gallery_items:
|
| 704 |
+
with gr.Group(elem_classes="step-card"):
|
| 705 |
+
gr.Markdown(f"**Prompt :** {item.get('prompt', '')}")
|
| 706 |
+
with gr.Row():
|
| 707 |
+
if item.get("image"):
|
| 708 |
+
gr.Image(
|
| 709 |
+
value=item["image"], label="Image (FLUX)",
|
| 710 |
+
height=260, interactive=False,
|
| 711 |
+
)
|
| 712 |
+
if item.get("video"):
|
| 713 |
+
gr.Video(
|
| 714 |
+
value=item["video"], label="Aperçu (TRELLIS)",
|
| 715 |
+
autoplay=True, loop=True, height=260,
|
| 716 |
+
)
|
| 717 |
+
if item.get("glb"):
|
| 718 |
+
gr.Model3D(
|
| 719 |
+
value=item["glb"],
|
| 720 |
+
label="Modèle 3D interactif", height=260,
|
| 721 |
+
)
|
| 722 |
+
if item.get("refined_prompt"):
|
| 723 |
+
with gr.Accordion("Prompt détaillé (DeepSeek-R1)", open=False):
|
| 724 |
+
gr.Markdown(item["refined_prompt"])
|
| 725 |
|
| 726 |
# --------------------------------------------------- How it works
|
| 727 |
with gr.Tab("Comment ça marche"):
|
assets/gallery/a_backpack_for_kids_flower_style/glb.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:aeaf154b7758697debd18c8b08b0a1925e96ca51d014cc870981950a0129d3b9
|
| 3 |
+
size 1734604
|
assets/gallery/a_backpack_for_kids_flower_style/image.png
ADDED
|
Git LFS Details
|
assets/gallery/a_backpack_for_kids_flower_style/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2b5931fbbad8f0adb7825a825a4d1a29b9d1476c6229c5ca86370a5af21c1f93
|
| 3 |
+
size 466901
|
assets/gallery/cat_shaped_cake_mold/glb.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f474d877306124acc49fd1fb8600021a052440df6dd57b3b33c4178277330220
|
| 3 |
+
size 1187612
|
assets/gallery/cat_shaped_cake_mold/image.png
ADDED
|
Git LFS Details
|
assets/gallery/cat_shaped_cake_mold/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6e2635aa5449891f2d44d0e9a3661b528b417904b4ca767da91c45d9a6f35d92
|
| 3 |
+
size 189857
|
assets/gallery/manifest.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"prompt": "a backpack for kids, flower style",
|
| 4 |
+
"refined_prompt": "A futuristic, flower-themed kids' backpack designed for school. The backpack features a vibrant, photorealistic floral pattern with detailed petal and blooming flower motifs. It has a sleek, kid-friendly design with a front zipper compartment and a small side pocket. The backpack is made from durable, water-resistant material with padded straps for comfort. The color scheme is bright and inviting, with a mix of pink, purple, and yellow flowers. A small flower emblem is placed on the front as the logo. The image is rendered in high quality with a white background, ensuring the backpack is the main focus. The composition is clean and focused, showcasing the backpack's playful and functional design.",
|
| 5 |
+
"image": "assets/gallery/a_backpack_for_kids_flower_style/image.png",
|
| 6 |
+
"video": "assets/gallery/a_backpack_for_kids_flower_style/video.mp4",
|
| 7 |
+
"glb": "assets/gallery/a_backpack_for_kids_flower_style/glb.glb"
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"prompt": "medieval flip flops",
|
| 11 |
+
"refined_prompt": "Design a photorealistic image of a pair of medieval-style flip flops, featuring intricate medieval designs. The flip flops have a strap adorned with knotwork and heraldic motifs, including a crown and a sword. The buckle is an elaborate clasp resembling medieval armor. The soles are made of a durable, slightly textured material resembling leather, with etched patterns matching the strap. The flip flops are rendered in rich colors—deep reds, greens, and golds—with sharp focus and medium focal length. The background is entirely white to highlight the design.",
|
| 12 |
+
"image": "assets/gallery/medieval_flip_flops/image.png",
|
| 13 |
+
"video": "assets/gallery/medieval_flip_flops/video.mp4",
|
| 14 |
+
"glb": "assets/gallery/medieval_flip_flops/glb.glb"
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"prompt": "cat shaped cake mold",
|
| 18 |
+
"refined_prompt": "Design a cat-shaped cake mold that seamlessly integrates functionality with an appealing aesthetic. The mold should feature a realistically shaped cat form, with visible details like ears, a head, and a body that smoothly transitions for easy cake pouring. The mold should be made from high-quality, food-safe materials with a non-stick coating to ensure easy removal of baked goods. The design should be rendered in a photorealistic style with a clean, white background, showcasing the cat's form in sharp detail. The texture of the mold should be subtly realistic, with a slightly glossy finish. The focal length should be wide to capture the entire cat shape clearly, and the grain should be fine to ensure high-quality imaging.",
|
| 19 |
+
"image": "assets/gallery/cat_shaped_cake_mold/image.png",
|
| 20 |
+
"video": "assets/gallery/cat_shaped_cake_mold/video.mp4",
|
| 21 |
+
"glb": "assets/gallery/cat_shaped_cake_mold/glb.glb"
|
| 22 |
+
}
|
| 23 |
+
]
|
assets/gallery/medieval_flip_flops/glb.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c12e085b85b04a80f9f5aa3c0f85bf720be10314192f995a668640a17be44059
|
| 3 |
+
size 1554828
|
assets/gallery/medieval_flip_flops/image.png
ADDED
|
Git LFS Details
|
assets/gallery/medieval_flip_flops/video.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4dd4aadc0c36a6ce3dec9d9ee889f61b8fb52487320e5c8442c56151e920ace0
|
| 3 |
+
size 293568
|
scripts/generate_gallery.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Generate real gallery assets by driving the live Hugging Face Space.
|
| 2 |
+
|
| 3 |
+
The whole pipeline (DeepSeek-R1 -> FLUX -> TRELLIS) runs on the Space's ZeroGPU;
|
| 4 |
+
this script just orchestrates the calls over the gradio_client API and saves the
|
| 5 |
+
produced image / video / GLB locally, then writes a manifest the app reads.
|
| 6 |
+
|
| 7 |
+
Usage:
|
| 8 |
+
python scripts/generate_gallery.py --smoke # one prompt, prints shapes
|
| 9 |
+
python scripts/generate_gallery.py # full list
|
| 10 |
+
|
| 11 |
+
Auth: uses the locally cached HF token (huggingface-cli login).
|
| 12 |
+
"""
|
| 13 |
+
import argparse
|
| 14 |
+
import json
|
| 15 |
+
import os
|
| 16 |
+
import re
|
| 17 |
+
import shutil
|
| 18 |
+
|
| 19 |
+
from gradio_client import Client, handle_file
|
| 20 |
+
from huggingface_hub import get_token
|
| 21 |
+
|
| 22 |
+
SPACE_ID = "yonnel/text-to-3d_flux_trellis"
|
| 23 |
+
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 24 |
+
GALLERY_DIR = os.path.join(ROOT, "assets", "gallery")
|
| 25 |
+
|
| 26 |
+
PROMPTS = [
|
| 27 |
+
"a backpack for kids, flower style",
|
| 28 |
+
"medieval flip flops",
|
| 29 |
+
"cat shaped cake mold",
|
| 30 |
+
]
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def slugify(text: str) -> str:
|
| 34 |
+
return re.sub(r"[^a-z0-9]+", "_", text.lower()).strip("_")[:40]
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def as_path(x):
|
| 38 |
+
"""Extract a local filepath from a gradio_client result item."""
|
| 39 |
+
if x is None:
|
| 40 |
+
return None
|
| 41 |
+
if isinstance(x, str):
|
| 42 |
+
return x
|
| 43 |
+
if isinstance(x, dict):
|
| 44 |
+
if "video" in x:
|
| 45 |
+
v = x["video"]
|
| 46 |
+
return v if isinstance(v, str) else (v.get("path") or v.get("url"))
|
| 47 |
+
return x.get("path") or x.get("url")
|
| 48 |
+
if isinstance(x, (list, tuple)) and x:
|
| 49 |
+
return as_path(x[0])
|
| 50 |
+
return None
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def generate_one(client: Client, prompt: str, verbose: bool = True) -> dict:
|
| 54 |
+
# Step 1 - DeepSeek-R1: prompt refinement
|
| 55 |
+
r1 = client.predict(prompt, api_name="/refine_prompt")
|
| 56 |
+
reasoning, clean_prompt, status1 = r1
|
| 57 |
+
if verbose:
|
| 58 |
+
print(f" [1] status: {status1!r}")
|
| 59 |
+
print(f" [1] clean_prompt: {clean_prompt[:160]!r}")
|
| 60 |
+
if not clean_prompt:
|
| 61 |
+
raise RuntimeError(f"empty refined prompt (status: {status1})")
|
| 62 |
+
|
| 63 |
+
# Step 2 - FLUX: image (fixed seed so the gallery is reproducible)
|
| 64 |
+
r2 = client.predict(
|
| 65 |
+
clean_prompt, 42, False, 512, 512, 6, api_name="/generate_image"
|
| 66 |
+
)
|
| 67 |
+
image_path = as_path(r2[0])
|
| 68 |
+
if verbose:
|
| 69 |
+
print(f" [2] image: {image_path}")
|
| 70 |
+
if not image_path or not os.path.exists(image_path):
|
| 71 |
+
raise RuntimeError(f"no image produced (status: {r2[-1]})")
|
| 72 |
+
|
| 73 |
+
# Step 3 - TRELLIS: video + GLB
|
| 74 |
+
r3 = client.predict(
|
| 75 |
+
handle_file(image_path), 0, 7.5, 12, 3.0, 12, api_name="/image_to_3d"
|
| 76 |
+
)
|
| 77 |
+
video_path = as_path(r3[0])
|
| 78 |
+
glb_path = as_path(r3[1]) or as_path(r3[3])
|
| 79 |
+
if verbose:
|
| 80 |
+
print(f" [3] video: {video_path}")
|
| 81 |
+
print(f" [3] glb: {glb_path}")
|
| 82 |
+
|
| 83 |
+
return {
|
| 84 |
+
"prompt": prompt,
|
| 85 |
+
"refined_prompt": clean_prompt,
|
| 86 |
+
"reasoning": reasoning,
|
| 87 |
+
"_image": image_path,
|
| 88 |
+
"_video": video_path,
|
| 89 |
+
"_glb": glb_path,
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def main():
|
| 94 |
+
ap = argparse.ArgumentParser()
|
| 95 |
+
ap.add_argument("--smoke", action="store_true", help="only the first prompt")
|
| 96 |
+
args = ap.parse_args()
|
| 97 |
+
|
| 98 |
+
prompts = PROMPTS[:1] if args.smoke else PROMPTS
|
| 99 |
+
os.makedirs(GALLERY_DIR, exist_ok=True)
|
| 100 |
+
|
| 101 |
+
print(f"Connecting to {SPACE_ID} ...")
|
| 102 |
+
client = Client(SPACE_ID, token=get_token(), verbose=False)
|
| 103 |
+
# The per-session temp dir is created by the Space's `load` handler, which
|
| 104 |
+
# never fires over the API -> call it explicitly so image_to_3d can write.
|
| 105 |
+
client.predict(api_name="/start_session")
|
| 106 |
+
|
| 107 |
+
manifest = []
|
| 108 |
+
for i, prompt in enumerate(prompts, 1):
|
| 109 |
+
print(f"[{i}/{len(prompts)}] {prompt}")
|
| 110 |
+
try:
|
| 111 |
+
res = generate_one(client, prompt)
|
| 112 |
+
except Exception as e:
|
| 113 |
+
print(f" !! failed: {e}")
|
| 114 |
+
continue
|
| 115 |
+
|
| 116 |
+
slug = slugify(prompt)
|
| 117 |
+
item_dir = os.path.join(GALLERY_DIR, slug)
|
| 118 |
+
os.makedirs(item_dir, exist_ok=True)
|
| 119 |
+
entry = {"prompt": prompt, "refined_prompt": res["refined_prompt"]}
|
| 120 |
+
for kind, key, ext in [
|
| 121 |
+
("image", "_image", ".png"),
|
| 122 |
+
("video", "_video", ".mp4"),
|
| 123 |
+
("glb", "_glb", ".glb"),
|
| 124 |
+
]:
|
| 125 |
+
src = res[key]
|
| 126 |
+
if src and os.path.exists(src):
|
| 127 |
+
dst = os.path.join(item_dir, kind + ext)
|
| 128 |
+
shutil.copyfile(src, dst)
|
| 129 |
+
entry[kind] = os.path.relpath(dst, ROOT).replace("\\", "/")
|
| 130 |
+
manifest.append(entry)
|
| 131 |
+
print(f" -> saved to {item_dir}")
|
| 132 |
+
|
| 133 |
+
if args.smoke:
|
| 134 |
+
print("\nSMOKE RESULT:\n" + json.dumps(manifest, indent=2, ensure_ascii=False))
|
| 135 |
+
return
|
| 136 |
+
|
| 137 |
+
manifest_path = os.path.join(GALLERY_DIR, "manifest.json")
|
| 138 |
+
with open(manifest_path, "w", encoding="utf-8") as f:
|
| 139 |
+
json.dump(manifest, f, indent=2, ensure_ascii=False)
|
| 140 |
+
print(f"\nWrote {manifest_path} ({len(manifest)} items)")
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
if __name__ == "__main__":
|
| 144 |
+
main()
|