[Core][Diffusion] Camera interaction for diffusion streaming generation (LingBot World 2 as example) (#7198)

Signed-off-by: Huang, Zeyu <11222265+fhfuih@users.noreply.github.com>
This commit is contained in:
Zeyu Huang | 黃澤宇 authored and GitHub committed 2026-09-20 16:19:41 +00:00
1 parent 139a47a578
commit e36babd48f
26 files changed
+2071 -200

No files matched your search

@@ -78,7 +78,7 @@ def _make_diffusion_request_state(*, request_id: str = "req-1", fps: int | None
prompt="hello",
)
state.prompt_embeds = torch.zeros(1, 4, 2)
state.extra = {"window_num_frames": 8}
state.extra = {"window_num_frames": 8, "num_latent_frames_per_chunk": 3}
return state
@@ -109,7 +109,12 @@ def _make_diffusion_model_runner(
# instances; unit tests of submit_interaction stub this. Stepwise path tests
# rebind to the real method.
runner._supports_step_mode = lambda: True
runner._interaction_coordinator = None
# Mirror load_model: coordinator is always present once the runner is "loaded".
# Build now so handlers capture the pipeline's current encode_prompt (tests may
# rebind the mock before calling this helper).
runner._interaction_coordinator = InteractionCoordinator.build(pipeline, runner.od_config)
if hasattr(pipeline, "_interaction_coordinator"):
pipeline._interaction_coordinator = runner._interaction_coordinator
return runner
@@ -155,6 +160,7 @@ class TestPromptUpdateExecution:
supports_step_execution = True
runner = _make_diffusion_model_runner(pipeline=_UnsupportedPipeline())
runner.state_cache["req-1"] = _make_diffusion_request_state()
with pytest.raises(ValueError, match="not supported"):
runner.submit_interaction("req-1", _prompt_interaction())
@@ -168,25 +174,98 @@ class TestPromptUpdateExecution:
"interaction",
[
{},
{"multi_modal_data": {"camera": {"type": "pose"}}},
{"event": {"prompt": "updated", "multi_modal_data": {"camera": {"type": "pose"}}}},
{"event": {"prompt": "updated", "multi_modal_data": {}}},
{"event": {"prompt": "updated", "multi_modal_data": None}},
{"event": {"prompt": "updated", "multi_modal_data": "bad"}},
{"event_id": "bad", "event": {"multi_modal_data": {}}},
{"event_id": "bad", "event": {"multi_modal_data": None}},
{"event_id": "bad", "event": {"prompt": "updated", "multi_modal_data": "bad"}},
{
"event_id": "cam-only",
"event": {
"multi_modal_data": {
"camera": {
"mode": "velocity",
"data": {"translation": [0.0, 0.0, 0.05], "rotation": [0.0, 0.0, 0.0, 1.0]},
},
}
},
},
{
"event_id": "cam-and-prompt",
"event": {
"prompt": "updated",
"multi_modal_data": {
"camera": {
"mode": "velocity",
"data": {"translation": [0.0, 0.0, 0.05], "rotation": [0.0, 0.0, 0.0, 1.0]},
},
},
},
},
],
)
def test_runner_interaction_rejects_structural_payloads_until_implemented(
def test_runner_rejects_unsupported_interactions(
self,
pipeline: HeliosPipeline,
interaction: dict[str, Any],
) -> None:
"""Unsupported interaction dict shapes are preserved to and rejected by the runner."""
"""Helios has no camera handler; malformed / unsupported payloads are rejected."""
runner = _make_diffusion_model_runner(pipeline=pipeline)
runner.state_cache["req-1"] = _make_diffusion_request_state()
state = _make_diffusion_request_state()
runner.state_cache["req-1"] = state
with pytest.raises(NotImplementedError, match="Only text-only prompt update interactions"):
with pytest.raises((ValueError, KeyError, AttributeError, TypeError)):
runner.submit_interaction("req-1", cast(Any, interaction))
# Rejected composite/malformed events must leave interaction queues unchanged.
pipeline.encode_prompt.assert_not_called() # pyright: ignore[reportAttributeAccessIssue]
assert "prompt" not in state.interaction_sessions
assert "camera" not in state.interaction_sessions
def test_rejected_composite_leaves_existing_prompt_queue_unchanged(
self,
pipeline: HeliosPipeline,
) -> None:
"""Helios must not apply a composite prompt when camera modality is unsupported."""
runner = _make_diffusion_model_runner(pipeline=pipeline)
state = _make_diffusion_request_state()
runner.state_cache["req-1"] = state
runner.submit_interaction("req-1", _prompt_interaction("already-queued", event_id="prior"))
session = state.interaction_sessions["prompt"]
assert isinstance(session, PromptSession)
prior = session.pending_event
assert prior is not None
assert prior.event_id == "prior"
pipeline.encode_prompt.reset_mock() # pyright: ignore[reportAttributeAccessIssue]
with pytest.raises(ValueError, match="camera"):
runner.submit_interaction(
"req-1",
cast(
Any,
{
"event_id": "cam-and-prompt",
"event": {
"prompt": "should-not-replace",
"multi_modal_data": {
"camera": {
"mode": "velocity",
"data": {
"translation": [0.0, 0.0, 0.05],
"rotation": [0.0, 0.0, 0.0, 1.0],
},
},
},
},
},
),
)
pipeline.encode_prompt.assert_not_called() # pyright: ignore[reportAttributeAccessIssue]
pending = session.pending_event
assert pending is not None
assert pending.event_id == "prior"
assert pending.prompt == "already-queued"
assert "camera" not in state.interaction_sessions
@pytest.mark.parametrize("model_class_name", ["HeliosPipeline", "HeliosPyramidPipeline"])
def test_coordinator_registers_prompt_for_helios_aliases(
self,
@@ -367,7 +446,11 @@ class TestPromptUpdateExecution:
f"that use the chunk media timeline, got {fps!r} "
f"(request_id={state.request_id!r})"
)
return ChunkMediaSpec(num_frames=int(state.extra["window_num_frames"]), fps=float(fps))
return ChunkMediaSpec(
num_media_frames=int(state.extra["window_num_frames"]),
fps=float(fps),
num_latent_frames=int(state.extra["window_num_frames"]),
)
def prepare_encode(self, state: StepRequestState) -> StepRequestState:
state.prompt_embeds = torch.zeros(1, 4, 2)