Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ name: build
# Builds the app image so an orchestrator can pull and run it; amd64 only, since
# Livepeer GPU work is NVIDIA/amd64.
#
# This image is ~25 GB (CUDA devel, torch, TensorRT, ONNX Runtime), so it does not
# This image is ~15 GB (torch, TensorRT, ONNX Runtime), so it does not
# fit a GitHub-hosted runner as shipped: the job reclaims disk first, skips the
# layer cache (a 25 GB image would blow the 10 GB Actions cache anyway), and does
# layer cache (an image this size would blow the 10 GB Actions cache anyway), and does
# not run on pull requests, where a build this size buys little for what it costs.
#
# GHCR needs no setup (ghcr.io/<owner>/<repo>, public if the repo is). Docker Hub
Expand All @@ -32,7 +32,8 @@ jobs:
steps:
- uses: actions/checkout@v7

# A stock runner has roughly 25 GB free, which this image alone exceeds.
# A stock runner has roughly 25 GB free, which this image plus its build
# layers still crowds.
# These are preinstalled toolchains the build never touches; dropping them
# frees about 25 GB more.
- name: Reclaim disk
Expand Down
49 changes: 32 additions & 17 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,47 @@
# the whole point of the static-registration path — an app needs no SDK, and no
# awareness of Livepeer at all, to run on the network.
#
# NOTE: the fork's own Dockerfile clones the UPSTREAM cumulo-autumn repo, not the
# fork, so it would not run this rewritten server. We clone the fork at a pinned
# commit instead.
FROM nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04
# NOTE: the fork's demo/realtime-img2img/Dockerfile clones the UPSTREAM
# cumulo-autumn repo, not the fork, so it would not run this rewritten server.
# We clone the fork at a pinned commit instead.
#
# Base is python-slim, not nvidia/cuda:*-devel: nothing here compiles against
# CUDA (torch's cu128 wheels carry the runtime, install-tensorrt is pure pip),
# and the driver arrives through the container runtime.
FROM python:3.11-slim

LABEL org.opencontainers.image.title="streamdiffusion-livepeer-runner"
LABEL org.opencontainers.image.description="daydream's StreamDiffusion realtime-img2img server, packaged unmodified to run as a Livepeer live runner"
LABEL org.opencontainers.image.source="https://github.com/livepeer/streamdiffusion-livepeer-runner"
LABEL org.opencontainers.image.licenses="Apache-2.0"

ENV DEBIAN_FRONTEND=noninteractive PYTHONUNBUFFERED=1
ENV HF_HUB_ENABLE_HF_TRANSFER=1

# git: pip resolves streamdiffusion from the fork, and demo/ is cloned below.
# libgl1/libglib2.0-0 are opencv's, not CUDA's, so slim needs them either way.
RUN apt-get update && apt-get install -y --no-install-recommends \
software-properties-common ca-certificates curl git \
&& add-apt-repository ppa:deadsnakes/ppa \
&& apt-get update && apt-get install -y --no-install-recommends \
python3.11 python3.11-venv python3.11-dev \
&& ln -sf /usr/bin/python3.11 /usr/local/bin/python \
&& curl -sS https://bootstrap.pypa.io/get-pip.py | python \
&& python -m pip --version \
git libgl1 libglib2.0-0 \
&& apt-get clean && rm -rf /var/lib/apt/lists/*

RUN python -m pip install --no-cache-dir \
torch==2.7.1+cu128 torchvision==0.22.1+cu128 torchaudio==2.7.1+cu128 \
--index-url https://download.pytorch.org/whl/cu128
RUN python -m pip install --no-cache-dir \
"streamdiffusion[tensorrt,controlnet,ipadapter] @ git+https://github.com/daydreamlive/StreamDiffusion.git@94b9b96cb8a17d401ffbce516393d6482326ce62"
RUN apt-get update && apt-get install -y --no-install-recommends \
libgl1 libglib2.0-0 \
# insightface (ipadapter extra) is sdist-only, so it compiles here. Plain g++,
# nothing CUDA: install for this step only, purge in the same layer.
RUN apt-get update && apt-get install -y --no-install-recommends build-essential \
&& python -m pip install --no-cache-dir \
"streamdiffusion[tensorrt,controlnet,ipadapter] @ git+https://github.com/daydreamlive/StreamDiffusion.git@94b9b96cb8a17d401ffbce516393d6482326ce62" \
&& apt-get purge -y --auto-remove build-essential \
&& apt-get clean && rm -rf /var/lib/apt/lists/*

RUN python -m streamdiffusion.tools.install-tensorrt
ENV LD_LIBRARY_PATH=/usr/local/lib/python3.11/site-packages/nvidia/cuda_runtime/lib:/usr/local/lib/python3.11/site-packages/nvidia/cudnn/lib:/usr/local/lib/python3.11/site-packages/nvidia/cublas/lib:/usr/local/lib/python3.11/site-packages/tensorrt_libs

# Pure pip: the tensorrt + cuDNN wheels, polygraphy, onnx-graphsurgeon. polygraphy
# globs libcudart.so* over LD_LIBRARY_PATH, which on slim is the only place it
# will find one; the check fails the build rather than the first stream.
RUN python -m streamdiffusion.tools.install-tensorrt \
&& python -c "import torch,tensorrt; from polygraphy.cuda.cuda import Cuda; Cuda(); print('ok',torch.__version__,tensorrt.__version__)"

# The pip package doesn't ship the demo/ dir, so clone the fork (pinned) for the server.
RUN git clone https://github.com/daydreamlive/StreamDiffusion.git /src \
Expand All @@ -55,4 +68,6 @@ RUN rm -rf engines && ln -s /models/engines engines
EXPOSE 7860

# --api-only: skip the built Node frontend (a Livepeer client drives the API directly).
CMD ["python", "main.py", "--host=0.0.0.0", "--port=7860", "--acceleration=tensorrt", "--api-only"]
# /models/engines is made at start because the volume masks a build-time mkdir,
# and mkdir(exist_ok=True) re-raises on the symlink while it dangles.
CMD ["sh", "-c", "mkdir -p /models/engines && exec python main.py --host=0.0.0.0 --port=7860 --acceleration=tensorrt --api-only"]
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ The price is unchanged by the overlay: static runners advertise it from `runners

CI publishes the image to `ghcr.io/livepeer/streamdiffusion-livepeer-runner` on `main` and `v*` tags. An operator then runs it with a `runners.json` like this repo's, pointed at wherever they run the container, and needs no credentials for a public package.

The image is **~25 GB** (CUDA devel, torch, TensorRT, ONNX Runtime), which is more than a GitHub-hosted runner has free out of the box, so [build.yml](.github/workflows/build.yml) reclaims disk before building and skips the build on pull requests. Building locally is `docker compose build`.
The image is **~15 GB** (torch, TensorRT, ONNX Runtime), which is still close enough to what a GitHub-hosted runner has free that [build.yml](.github/workflows/build.yml) reclaims disk before building and skips the build on pull requests. Building locally is `docker compose build`.

To publish to Docker Hub as well, set the repository variable `DOCKERHUB_NAMESPACE` and the secrets `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN`. GHCR keeps working either way.

Expand All @@ -119,6 +119,12 @@ uvx pre-commit run --all-files

CI runs the same hooks, checks the compose file parses, and builds the image.

## License and attribution

This repo is an **example** of how to run StreamDiffusion on the [live runner](https://github.com/livepeer/go-livepeer/blob/master/doc/live-runner.md), not a production-ready pipeline. The wrapper here (Dockerfile, [client.py](client.py), the compose files, [runners.json](runners.json)) is MIT, and CI publishing to `ghcr.io/livepeer/` is packaging convenience so an operator can pull it, not a product commitment.

What runs inside the image is daydream's [StreamDiffusion](https://github.com/daydreamlive/StreamDiffusion), itself a fork of [cumulo-autumn/StreamDiffusion](https://github.com/cumulo-autumn/StreamDiffusion). Both are **Apache-2.0**, and this repo builds the fork pinned at `94b9b96` and **unmodified**, so redistribution is permitted and there are no changes to state under section 4(b). The fork ships no `NOTICE` file; its `LICENSE` travels in the image at `/src/LICENSE`. Model weights are downloaded from Hugging Face on first run under their own licenses and are not redistributed here.

## Building your own

Start from [**template-livepeer-runner**](https://github.com/livepeer/template-livepeer-runner), then list yours in [**runner-app-examples**](https://github.com/livepeer/runner-app-examples#external-examples). That repo also has a minimal example of each transport, mode, registration, and pricing option; the [live runner docs](https://github.com/livepeer/go-livepeer/blob/master/doc/live-runner.md) are the reference.
Loading