From 13b3b36b8b47b7ec298cfd9e22cb3529c9691544 Mon Sep 17 00:00:00 2001 From: Shao Duan <46639847+shaoxiongduan@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:07:37 -0700 Subject: [PATCH] [feat] Add Infinite Livestream app (#1878) Co-authored-by: SolitaryThinker Co-authored-by: Claude Opus 5.5 (1M context) --- .buildkite/scripts/unit_test.sh | 4 + .github/scripts/plan_merge_ci.py | 4 + apps/infinite_livestream/README.md | 290 ++++++++++ .../infinite_livestream/__init__.py | 5 + .../infinite_livestream/backend.py | 516 ++++++++++++++++++ .../infinite_livestream/chat.py | 83 +++ .../infinite_livestream/clip_plan.py | 162 ++++++ .../infinite_livestream/clip_queue.py | 148 +++++ .../infinite_livestream/config.py | 328 +++++++++++ .../configs/infinite_livestream.yaml | 93 ++++ .../infinite_livestream/director.py | 408 ++++++++++++++ .../infinite_livestream/engine.py | 475 ++++++++++++++++ .../infinite_livestream/group_tag.py | 54 ++ .../infinite_livestream/main.py | 147 +++++ .../infinite_livestream/metadata.py | 56 ++ .../infinite_livestream/moderator.py | 52 ++ .../infinite_livestream/muxer.py | 139 +++++ .../infinite_livestream/pacer.py | 193 +++++++ .../infinite_livestream/presets/fillers.json | 130 +++++ .../infinite_livestream/server_entry.py | 30 + .../infinite_livestream/sink.py | 454 +++++++++++++++ .../infinite_livestream/tests/__init__.py | 0 .../infinite_livestream/tests/conftest.py | 22 + .../tests/test_chat_endpoint.py | 53 ++ .../tests/test_clip_plan.py | 86 +++ .../infinite_livestream/tests/test_config.py | 156 ++++++ .../tests/test_director_admission.py | 155 ++++++ .../tests/test_frame_metadata.py | 126 +++++ .../tests/test_hls_metadata.py | 136 +++++ .../tests/test_import_contract.py | 99 ++++ .../tests/test_metadata_player.cjs | 219 ++++++++ .../tests/test_prompt_flow.py | 97 ++++ .../tests/test_service_lifecycle.py | 55 ++ .../tests/test_sink_shutdown.py | 128 +++++ .../tests/test_state_mirror.py | 76 +++ .../infinite_livestream/upsampler.py | 359 ++++++++++++ .../infinite_livestream/web/icon.svg | 6 + .../infinite_livestream/web/index.html | 497 +++++++++++++++++ .../infinite_livestream/web/logo.svg | 18 + .../infinite_livestream/web/metadata.js | 137 +++++ .../infinite_livestream/webapp.py | 261 +++++++++ apps/infinite_livestream/pyproject.toml | 34 ++ .../tests/contract/test_merge_ci_plan.py | 6 + pyproject.toml | 19 +- 44 files changed, 6512 insertions(+), 4 deletions(-) create mode 100644 apps/infinite_livestream/README.md create mode 100644 apps/infinite_livestream/infinite_livestream/__init__.py create mode 100644 apps/infinite_livestream/infinite_livestream/backend.py create mode 100644 apps/infinite_livestream/infinite_livestream/chat.py create mode 100644 apps/infinite_livestream/infinite_livestream/clip_plan.py create mode 100644 apps/infinite_livestream/infinite_livestream/clip_queue.py create mode 100644 apps/infinite_livestream/infinite_livestream/config.py create mode 100644 apps/infinite_livestream/infinite_livestream/configs/infinite_livestream.yaml create mode 100644 apps/infinite_livestream/infinite_livestream/director.py create mode 100644 apps/infinite_livestream/infinite_livestream/engine.py create mode 100644 apps/infinite_livestream/infinite_livestream/group_tag.py create mode 100644 apps/infinite_livestream/infinite_livestream/main.py create mode 100644 apps/infinite_livestream/infinite_livestream/metadata.py create mode 100644 apps/infinite_livestream/infinite_livestream/moderator.py create mode 100644 apps/infinite_livestream/infinite_livestream/muxer.py create mode 100644 apps/infinite_livestream/infinite_livestream/pacer.py create mode 100644 apps/infinite_livestream/infinite_livestream/presets/fillers.json create mode 100644 apps/infinite_livestream/infinite_livestream/server_entry.py create mode 100644 apps/infinite_livestream/infinite_livestream/sink.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/__init__.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/conftest.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_chat_endpoint.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_clip_plan.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_config.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_director_admission.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_frame_metadata.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_hls_metadata.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_import_contract.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_metadata_player.cjs create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_prompt_flow.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_service_lifecycle.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_sink_shutdown.py create mode 100644 apps/infinite_livestream/infinite_livestream/tests/test_state_mirror.py create mode 100644 apps/infinite_livestream/infinite_livestream/upsampler.py create mode 100644 apps/infinite_livestream/infinite_livestream/web/icon.svg create mode 100644 apps/infinite_livestream/infinite_livestream/web/index.html create mode 100644 apps/infinite_livestream/infinite_livestream/web/logo.svg create mode 100644 apps/infinite_livestream/infinite_livestream/web/metadata.js create mode 100644 apps/infinite_livestream/infinite_livestream/webapp.py create mode 100644 apps/infinite_livestream/pyproject.toml diff --git a/.buildkite/scripts/unit_test.sh b/.buildkite/scripts/unit_test.sh index aacba0fcc..63bf27ecc 100644 --- a/.buildkite/scripts/unit_test.sh +++ b/.buildkite/scripts/unit_test.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash set -euo pipefail +# The livestream app's tests are CPU-only; its single gpu-marked module is +# deselected, and DreamVerse's GPU tests have their own lane. exec pytest \ + ./apps/infinite_livestream/infinite_livestream/tests \ ./fastvideo/tests/api/ \ ./fastvideo/tests/contract/ \ ./fastvideo/tests/dataset/ \ @@ -27,4 +30,5 @@ exec pytest \ --ignore=./fastvideo/tests/entrypoints/test_openai_api_integration.py \ --ignore=./fastvideo/tests/train/models \ --ignore=./fastvideo/tests/train/methods \ + -m "not gpu" \ -vs diff --git a/.github/scripts/plan_merge_ci.py b/.github/scripts/plan_merge_ci.py index 7025d81e7..867fca88f 100644 --- a/.github/scripts/plan_merge_ci.py +++ b/.github/scripts/plan_merge_ci.py @@ -523,6 +523,10 @@ def classify_paths(paths: list[str]) -> MergePlan: # DreamVerse is already one of the six automatic Fastcheck lanes. plan.reasons.append(f"covered by automatic DreamVerse Fastcheck: {path}") continue + if path.startswith("apps/infinite_livestream/"): + # The app's CPU-only tests run in the automatic unit Fastcheck lane. + plan.reasons.append(f"covered by automatic unit Fastcheck: {path}") + continue if path.startswith("fastvideo/tests/"): # The automatic unit/component Fastcheck lanes own the remaining # package tests. Domain-specific expensive test roots were handled diff --git a/apps/infinite_livestream/README.md b/apps/infinite_livestream/README.md new file mode 100644 index 000000000..af1add185 --- /dev/null +++ b/apps/infinite_livestream/README.md @@ -0,0 +1,290 @@ +# Infinite Livestream + +Infinite Livestream is a chat-driven FastH3 broadcast. Viewers type prompts into a web +page, the app rewrites them with an LLM, generates clips with FastVideo, and +plays them back as one continuous HLS stream on that same page. When nobody is +typing it feeds itself from a preset of idle prompts, so the channel never goes +dark. + +It lives in this monorepo under `apps/infinite_livestream/`. + +``` +chat -> Director -> PromptUpsampler (OpenAI-compatible LLM) + | + v enqueue / move / pop + Engine -> FastH3Backend -> FastVideo + | frames + audio + v + Pacer -> HlsSink -> the page's