Spaces:
Runtime error
Runtime error
Download app.py from Luminia/Kimodo-cpp_momask-codes: direct link, hf CLI and curl.
- Browser
- Download file 9.86 kB
-
https://huggingface.co/spaces/Luminia/Kimodo-cpp_momask-codes/resolve/main/app.py
- Command line
-
hf download hf://spaces/Luminia/Kimodo-cpp_momask-codes/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Luminia/Kimodo-cpp_momask-codes/resolve/main/app.py
9.86 kB
| """Two CPU text-to-motion models in one Space, one tab each. | |
| Import order matters here and is not cosmetic. matplotlib's ft2font is a | |
| pybind11 extension built against the system libstdc++ and fails to initialise if | |
| a differently linked libstdc++ is already resident, so the drawing stack is | |
| imported before anything native. Kimodo then dlopens libkimodo.so together with | |
| its own bundled libgomp at generate time, while MoMask's torch, onnxruntime and | |
| CLIP are held back behind momask_core._ensure_backends() until that tab is | |
| actually used. A visitor who only generates with Kimodo never loads them. | |
| Each pipeline keeps its own weights. Kimodo runs GGUF checkpoints through the | |
| kimodo.cpp GGML port; MoMask runs its own ONNX graphs. Nothing is shared or | |
| substituted between them. | |
| """ | |
| import matplotlib | |
| matplotlib.use("Agg") | |
| import matplotlib.pyplot as plt # noqa: E402,F401 | |
| import gradio as gr # noqa: E402 | |
| import kimodo_core as K # noqa: E402 | |
| import momask_core as M # noqa: E402 | |
| CSS = K.CSS + """ | |
| #mm_log textarea { font-family: ui-monospace, monospace; font-size: 0.8em; } | |
| .tabs { gap: 0 !important; } | |
| """ | |
| HEADER = (f"CPU text to motion · **Kimodo** through " | |
| f"[kimodo.cpp](https://github.com/localai-org/kimodo.cpp) GGML, " | |
| f"**MoMask** through ONNX · {K.CPUS} threads") | |
| def momask_generate(text, length, seed): | |
| """Generate a 3D skeletal animation from a text description of a motion. | |
| Runs MoMask on CPU through ONNX Runtime. Returns a rendered preview and a | |
| BVH file for Blender. Far cheaper than the Kimodo tab because there is no | |
| LLM2Vec encode: CLIP text encoding is part of the graph. | |
| Args: | |
| text: Plain English description of the motion, for example "a person walks forward". | |
| length: Clip length in seconds. 0 asks the length estimator to pick one. | |
| seed: Random seed. The same seed and text reproduce a clip exactly. | |
| """ | |
| if not (text or "").strip(): | |
| raise gr.Error("Describe a motion first, for example " | |
| "\"a person walks forward\".") | |
| _joints, video_path, bvh_path = M.generate_motion( | |
| text, float(length or 0), int(seed) if seed is not None else None) | |
| if video_path is None: | |
| raise gr.Error("MoMask returned no motion. Try a shorter, plainer " | |
| "description, or set Duration above 0.") | |
| return video_path, gr.update(value=bvh_path, interactive=bvh_path is not None) | |
| def kimodo_example(prompt, model_label, frames, seed): | |
| """Examples vary the four columns worth varying; the advanced controls keep | |
| their defaults. Delegating to K.generate rather than duplicating it means a | |
| cached example is the same code path the Generate button runs. | |
| The BVH button is dropped from the yielded tuple on purpose. Caching an | |
| example whose outputs include a gr.DownloadButton crashes inside gradio: | |
| postprocess_data reaches components/base.py `if self.info:` and | |
| DownloadButton has no `info` attribute. Video, skeleton and log cache fine, | |
| and the button still works normally from Generate. | |
| """ | |
| for video, glb, _bvh, status in K.generate( | |
| prompt, model_label, int(frames), 20, int(seed), 2.0, True): | |
| yield video, glb, status | |
| def momask_example(text, length, seed): | |
| """Same reason as above: cache the preview, leave the download button out.""" | |
| video, _bvh = momask_generate(text, length, seed) | |
| return video | |
| def kimodo_tab(): | |
| """Kimodo's own layout, unchanged apart from living inside a tab.""" | |
| with gr.Row(): | |
| with gr.Column(scale=4): | |
| prompt = gr.Textbox( | |
| value="a person runs forward and jumps over an obstacle", | |
| label="Describe the motion", lines=1, max_lines=1, | |
| placeholder="a person performs a spinning back kick") | |
| run = gr.Button( | |
| f"Generate ({K._duration(K.ENCODE_S + K.sampling_seconds(120, 20))})", | |
| variant="primary") | |
| status = gr.Textbox(lines=8, max_lines=K.LOG_LINES + 2, | |
| autoscroll=True, show_label=False, | |
| container=False, elem_id="log") | |
| with gr.Column(scale=3): | |
| model_label = gr.Dropdown( | |
| choices=[c.label for c in K.CHECKPOINTS], | |
| value=K.CHECKPOINTS[0].label, label="Motion model", | |
| info="SOMA is a 30 joint human rig, G1 a 34 joint Unitree " | |
| "robot. RP and SEED are different checkpoints of each.") | |
| frames = gr.Slider(30, 240, value=120, step=10, | |
| label=f"Frames ({120 / K.FPS:.1f} s clip)") | |
| with gr.Accordion("Advanced", open=False): | |
| with gr.Row(): | |
| steps = gr.Slider(4, 50, value=20, step=1, scale=3, | |
| label="Diffusion steps (20)", | |
| info="More steps, cleaner motion.") | |
| seed = gr.Number(value=7, precision=0, label="Seed", scale=1) | |
| with gr.Row(): | |
| text_cfg = gr.Slider(1.0, 5.0, value=2.0, step=0.5, scale=3, | |
| label="Guidance") | |
| deskate = gr.Checkbox(value=True, scale=1, | |
| label="Reduce foot skating") | |
| with gr.Column(scale=5): | |
| viewer = gr.Model3D(label="Skeleton", interactive=False, height=260) | |
| video = gr.Video(label="Preview", autoplay=True, height=180) | |
| bvh = gr.DownloadButton("Download BVH for Blender", size="sm", | |
| interactive=False) | |
| # Defined after the row because Examples needs every input component to exist. | |
| gr.Examples( | |
| examples=[ | |
| ["a person walks forward at a steady pace", K.CHECKPOINTS[0].label, 120, 42], | |
| ["a person performs a roundhouse kick", K.CHECKPOINTS[0].label, 120, 123], | |
| ["a person sits down on a chair", K.CHECKPOINTS[0].label, 90, 456], | |
| ["a person dances happily in place", K.CHECKPOINTS[0].label, 150, 789], | |
| ["a person kicks with their right leg", K.CHECKPOINTS[2].label, 120, 101], | |
| ], | |
| inputs=[prompt, model_label, frames, seed], | |
| outputs=[video, viewer, status], | |
| fn=kimodo_example, | |
| # Lazy is the only sane mode here. Each distinct prompt pays a ~110 s | |
| # LLM2Vec encode, so eager would add roughly ten minutes to every build | |
| # and every wake, and one failure would take the whole Space down with it. | |
| # Lazy caches a row the first time someone clicks it, instantly after. | |
| cache_examples=True, cache_mode="lazy", | |
| label="Examples") | |
| for control in (prompt, frames, steps): | |
| control.change(K.control_labels, inputs=[prompt, frames, steps], | |
| outputs=[frames, steps, run], queue=False, | |
| api_visibility="private") | |
| run.click(K.generate, | |
| inputs=[prompt, model_label, frames, steps, seed, text_cfg, deskate], | |
| outputs=[video, viewer, bvh, status], | |
| api_name="generate").then( | |
| K.control_labels, inputs=[prompt, frames, steps], | |
| outputs=[frames, steps, run], queue=False, api_visibility="private") | |
| def momask_tab(): | |
| """Same shape as the Kimodo tab so switching tabs does not relayout the page: | |
| inputs left, settings middle, outputs right.""" | |
| with gr.Row(): | |
| with gr.Column(scale=4): | |
| text = gr.Textbox(value="a person walks forward", | |
| label="Describe the motion", lines=1, max_lines=1, | |
| placeholder="a person does a salsa dance") | |
| run = gr.Button("Generate (~10 s)", variant="primary") | |
| with gr.Column(scale=3): | |
| length = gr.Slider(0, 10, value=0, step=0.5, | |
| label="Duration (0 = estimate it)", | |
| info="Seconds. The length estimator picks one " | |
| "from the text when this is 0.") | |
| seed = gr.Number(value=42, precision=0, label="Seed") | |
| with gr.Column(scale=5): | |
| video = gr.Video(label="Preview", autoplay=True, height=260) | |
| bvh = gr.DownloadButton("Download BVH for Blender", size="sm", | |
| interactive=False) | |
| # Defined after the row because Examples needs every input component to exist. | |
| gr.Examples( | |
| examples=[ | |
| ["A person walks forward", 0, 42], | |
| ["A person is running on a treadmill", 0, 123], | |
| ["A person jumps up and then lands", 0, 456], | |
| ["A person does a salsa dance", 0, 789], | |
| ["A person kicks with their right leg", 0, 101], | |
| ], | |
| inputs=[text, length, seed], outputs=[video], | |
| fn=momask_example, | |
| # Lazy, not eager. Eager runs every row before the Space serves its first | |
| # request, and it would force torch, onnxruntime and CLIP resident at | |
| # startup for every visitor, which is exactly what _ensure_backends() | |
| # exists to avoid. Lazy caches each row the first time it is clicked and | |
| # serves it instantly to everyone after that. | |
| cache_examples=True, cache_mode="lazy", | |
| label="Examples") | |
| run.click(momask_generate, inputs=[text, length, seed], | |
| outputs=[video, bvh], api_name="momask_generate") | |
| with gr.Blocks(title="Kimodo cpp + MoMask", fill_width=True) as demo: | |
| gr.Markdown(HEADER, elem_id="foot") | |
| with gr.Tabs(): | |
| with gr.Tab("Kimodo (GGML)"): | |
| kimodo_tab() | |
| with gr.Tab("MoMask (ONNX)"): | |
| momask_tab() | |
| if __name__ == "__main__": | |
| demo.queue(max_size=8, default_concurrency_limit=1).launch( | |
| css=CSS, mcp_server=True) | |