Spaces:
Running on Zero
Running on Zero
Barebone interactive ABot-World on Modular Diffusers: one pipe.stream(action_source=...) loop
Browse files- .gitattributes +4 -0
- README.md +12 -7
- app.py +109 -0
- examples/desert_valley.png +3 -0
- examples/example.png +3 -0
- examples/forest_stream.png +3 -0
- examples/mountain_meadow.png +3 -0
- requirements.txt +5 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,7 @@ saved_model/**/* 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
examples/desert_valley.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
examples/example.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
examples/forest_stream.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
examples/mountain_meadow.png filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,13 +1,18 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version: 6.
|
| 8 |
-
python_version: '3.
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: ABot World Interactive
|
| 3 |
+
emoji: 🕹️
|
| 4 |
+
colorFrom: yellow
|
| 5 |
+
colorTo: green
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 6.5.1
|
| 8 |
+
python_version: '3.12'
|
| 9 |
app_file: app.py
|
| 10 |
pinned: false
|
| 11 |
+
short_description: Drive a live world model with Modular Diffusers
|
| 12 |
---
|
| 13 |
|
| 14 |
+
Interactive [ABot-World](https://huggingface.co/YiYiXu/ABot-World-0-5B-LF-Diffusers) (a real-time,
|
| 15 |
+
action-conditioned world model, Wan2.2-TI2V-5B) running natively on Modular Diffusers: the whole app is a
|
| 16 |
+
`pipe.stream(action_source=...)` consumer — the pipeline polls the held control once per generated block.
|
| 17 |
+
|
| 18 |
+
Needs a persistent GPU (the rollout keeps a K/V cache alive across blocks); ~20 GB VRAM in bf16.
|
app.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import threading
|
| 2 |
+
|
| 3 |
+
import gradio as gr
|
| 4 |
+
import numpy as np
|
| 5 |
+
import torch
|
| 6 |
+
|
| 7 |
+
from diffusers.modular_pipelines import ABotWorldStreamingBlocks
|
| 8 |
+
from diffusers.utils import load_image
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
REPO = "YiYiXu/ABot-World-0-5B-LF-Diffusers"
|
| 12 |
+
|
| 13 |
+
pipe = ABotWorldStreamingBlocks().init_pipeline(REPO)
|
| 14 |
+
pipe.load_components(dtype=torch.bfloat16)
|
| 15 |
+
pipe.to("cuda")
|
| 16 |
+
|
| 17 |
+
DEFAULT_PROMPT = (
|
| 18 |
+
"A realistic outdoor world scene with a navigable path, natural lighting, "
|
| 19 |
+
"detailed ground texture, and stable forward motion."
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
CONTROLS = {
|
| 23 |
+
"▲ forward (W)": [1, 0, 0, 0, 0, 0, 0, 0],
|
| 24 |
+
"◀ left (A)": [0, 1, 0, 0, 0, 0, 0, 0],
|
| 25 |
+
"▼ back (S)": [0, 0, 1, 0, 0, 0, 0, 0],
|
| 26 |
+
"▶ right (D)": [0, 0, 0, 1, 0, 0, 0, 0],
|
| 27 |
+
"cam ↑ (I)": [0, 0, 0, 0, 1, 0, 0, 0],
|
| 28 |
+
"cam ◀ (J)": [0, 0, 0, 0, 0, 1, 0, 0],
|
| 29 |
+
"cam ↓ (K)": [0, 0, 0, 0, 0, 0, 1, 0],
|
| 30 |
+
"cam ▶ (L)": [0, 0, 0, 0, 0, 0, 0, 1],
|
| 31 |
+
"· idle": [0] * 8,
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
# one live world at a time: buttons write the held control here, the rollout polls it per block
|
| 35 |
+
session = {"action": [0] * 8, "stop": False}
|
| 36 |
+
run_lock = threading.Lock()
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def hold(control):
|
| 40 |
+
session["action"] = CONTROLS[control]
|
| 41 |
+
return f"holding: {control}"
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def stop():
|
| 45 |
+
session["stop"] = True
|
| 46 |
+
return "stopping after this block…"
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def play(image, prompt, max_blocks):
|
| 50 |
+
if not run_lock.acquire(blocking=False):
|
| 51 |
+
raise gr.Error("A session is already running — stop it first.")
|
| 52 |
+
try:
|
| 53 |
+
if image is None:
|
| 54 |
+
image = load_image("examples/desert_valley.png")
|
| 55 |
+
session["stop"] = False
|
| 56 |
+
session["action"] = CONTROLS["▲ forward (W)"]
|
| 57 |
+
|
| 58 |
+
def action_source(block_index):
|
| 59 |
+
if session["stop"] or block_index >= max_blocks:
|
| 60 |
+
return None
|
| 61 |
+
return session["action"]
|
| 62 |
+
|
| 63 |
+
for event in pipe.stream(
|
| 64 |
+
prompt=(prompt or DEFAULT_PROMPT).strip() or DEFAULT_PROMPT,
|
| 65 |
+
image=image,
|
| 66 |
+
action_source=action_source,
|
| 67 |
+
generator=torch.Generator("cpu").manual_seed(42),
|
| 68 |
+
):
|
| 69 |
+
if event.path != "denoise.rollout":
|
| 70 |
+
continue
|
| 71 |
+
frames = event.state.get("frames")
|
| 72 |
+
yield (frames[-1] * 255).clip(0, 255).astype(np.uint8)
|
| 73 |
+
finally:
|
| 74 |
+
run_lock.release()
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
with gr.Blocks(title="ABot-World Interactive") as demo:
|
| 78 |
+
gr.Markdown(
|
| 79 |
+
"""# ABot-World — interactive world, Modular Diffusers
|
| 80 |
+
Upload a scene, press Start, then hold a control: each ~1 s block is generated live by
|
| 81 |
+
[ABot-World](https://huggingface.co/YiYiXu/ABot-World-0-5B-LF-Diffusers) conditioned on the held action.
|
| 82 |
+
The whole app is one `pipe.stream(action_source=...)` loop — the pipeline polls your current input once
|
| 83 |
+
per block ([huggingface/diffusers#14159](https://github.com/huggingface/diffusers/pull/14159))."""
|
| 84 |
+
)
|
| 85 |
+
with gr.Row():
|
| 86 |
+
with gr.Column(scale=1):
|
| 87 |
+
image = gr.Image(label="starting scene", type="pil", height=220)
|
| 88 |
+
prompt = gr.Textbox(label="scene prompt", value=DEFAULT_PROMPT, lines=2)
|
| 89 |
+
max_blocks = gr.Slider(label="max blocks (~seconds)", minimum=4, maximum=120, step=1, value=60)
|
| 90 |
+
with gr.Row():
|
| 91 |
+
start_button = gr.Button("Start", variant="primary")
|
| 92 |
+
stop_button = gr.Button("Stop")
|
| 93 |
+
gr.Examples(
|
| 94 |
+
examples=[["examples/desert_valley.png"], ["examples/forest_stream.png"],
|
| 95 |
+
["examples/mountain_meadow.png"], ["examples/example.png"]],
|
| 96 |
+
inputs=[image],
|
| 97 |
+
)
|
| 98 |
+
with gr.Column(scale=2):
|
| 99 |
+
view = gr.Image(label="world", show_label=False, interactive=False)
|
| 100 |
+
status = gr.Textbox(value="holding: ▲ forward (W)", show_label=False, container=False)
|
| 101 |
+
with gr.Row():
|
| 102 |
+
buttons = [gr.Button(name, size="sm") for name in CONTROLS]
|
| 103 |
+
|
| 104 |
+
for button in buttons:
|
| 105 |
+
button.click(hold, inputs=gr.State(button.value), outputs=status, api_name="hold")
|
| 106 |
+
start_button.click(play, inputs=[image, prompt, max_blocks], outputs=view, api_name="play")
|
| 107 |
+
stop_button.click(stop, outputs=status, api_name="stop")
|
| 108 |
+
|
| 109 |
+
demo.launch(show_error=True)
|
examples/desert_valley.png
ADDED
|
Git LFS Details
|
examples/example.png
ADDED
|
Git LFS Details
|
examples/forest_stream.png
ADDED
|
Git LFS Details
|
examples/mountain_meadow.png
ADDED
|
Git LFS Details
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
accelerate
|
| 2 |
+
git+https://github.com/huggingface/diffusers.git@abot-world-modular
|
| 3 |
+
torch
|
| 4 |
+
transformers
|
| 5 |
+
ftfy
|