diff --git a/.github/actions/cleanup-runner/action.yaml b/.github/actions/cleanup-runner/action.yaml new file mode 100644 index 00000000..6276de58 --- /dev/null +++ b/.github/actions/cleanup-runner/action.yaml @@ -0,0 +1,33 @@ +name: 'Cleanup Runner' +description: 'Cleans up GitHub-hosted runner to free up disk space for large builds' +runs: + using: "composite" + steps: + - name: Cleanup hosted runner + shell: bash + run: | + # Remove unnecessary packages + sudo apt purge -yqq dotnet-* mono-* llvm-* libllvm* powershell* openjdk-* \ + temurin-* mongodb-* firefox mysql-* \ + hhvm google-chrome-stable \ + libgl1-mesa-dri microsoft-edge-stable azure-cli || true + + # Clean apt cache + sudo apt clean + sudo apt autoremove -y + + # Remove large directories + sudo rm -rf /usr/share/dotnet /usr/local/lib/android + sudo rm -rf /usr/local/share/chromium /usr/local/share/chrome + sudo rm -rf /usr/local/.ghcup /usr/local/share/powershell + sudo rm -rf /opt/hostedtoolcache/* /usr/local/lib/node_modules + + # Clean npm and yarn caches + npm cache clean --force || true + yarn cache clean || true + + # Remove Docker images and build cache + docker system prune -af + + # Show available space after cleanup + df -h diff --git a/.github/workflows/ai-runner-live-pipelines-docker.yaml b/.github/workflows/ai-runner-live-pipelines-docker.yaml new file mode 100644 index 00000000..6b03031b --- /dev/null +++ b/.github/workflows/ai-runner-live-pipelines-docker.yaml @@ -0,0 +1,241 @@ +name: Build ai-runner live pipeline Docker images + +on: + pull_request: + paths: + - "runner/docker/Dockerfile.live-*" + - "runner/app/**" + - "runner/images/**" + push: + branches: + - main + tags: + - '*' + paths: + - "runner/docker/Dockerfile.live-*" + - "runner/app/**" + - "runner/images/**" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + build-common-base: + name: Build common live base image + permissions: + pull-requests: read + runs-on: ubuntu-20.04 + steps: + - name: Check out code + uses: actions/checkout@v4.1.1 + with: + fetch-depth: 50 + ref: ${{ github.event.pull_request.head.sha }} + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files: | + runner/docker/Dockerfile.live-base + + - name: Check if build needed + id: check_build + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + ( + github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name == github.repository && + steps.changed-files.outputs.any_changed == 'true' + ) + run: echo "should_build=true" >> $GITHUB_OUTPUT + + - name: Cleanup hosted runner + uses: ./.github/actions/cleanup-runner + if: steps.check_build.outputs.should_build == 'true' + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.CI_DOCKERHUB_USERNAME }} + password: ${{ secrets.CI_DOCKERHUB_TOKEN }} + + - name: Build and push live-base image + uses: docker/build-push-action@v5 + if: steps.check_build.outputs.should_build == 'true' + with: + context: "{{defaultContext}}:runner" + platforms: linux/amd64 + push: ${{ github.event_name != 'pull_request' }} + tags: livepeer/ai-runner:live-base + file: docker/Dockerfile.live-base + cache-from: type=registry,ref=livepeerci/build:cache + cache-to: type=registry,ref=livepeerci/build:cache,mode=max + + build-pipeline-images: + name: Build pipeline images + needs: build-common-base + runs-on: ubuntu-20.04 + permissions: + pull-requests: read + strategy: + matrix: + pipeline: [streamdiffusion, comfyui, liveportrait] + fail-fast: false + steps: + - name: Check out code + uses: actions/checkout@v4.1.1 + with: + fetch-depth: 50 + ref: ${{ github.event.pull_request.head.sha }} + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files_yaml: | + base_dockerfile: + - runner/docker/Dockerfile.live-base-${{ matrix.pipeline }} + liveportrait: + - runner/images/** + - runner/requirements-liveportrait.txt + + - name: Cleanup hosted runner + uses: ./.github/actions/cleanup-runner + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.CI_DOCKERHUB_USERNAME }} + password: ${{ secrets.CI_DOCKERHUB_TOKEN }} + + - name: Build and push pipeline base image + uses: docker/build-push-action@v5 + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + ( + github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name == github.repository && + ( + steps.changed-files.outputs.base_dockerfile_any_changed == 'true' || + ( + matrix.pipeline == 'liveportrait' && + steps.changed-files.outputs.liveportrait_any_changed == 'true' + ) + ) + ) + with: + context: "{{defaultContext}}:runner" + platforms: linux/amd64 + push: ${{ github.event_name != 'pull_request' }} + tags: livepeer/ai-runner:live-base-${{ matrix.pipeline }} + file: docker/Dockerfile.live-base-${{ matrix.pipeline }} + build-args: | + PIPELINE=${{ matrix.pipeline }} + cache-from: type=registry,ref=livepeerci/build:cache + cache-to: type=registry,ref=livepeerci/build:cache,mode=max + + - name: Extract metadata for app image + id: meta + uses: docker/metadata-action@v5 + with: + images: livepeer/ai-runner + tags: | + type=raw,value=live-app-${{ matrix.pipeline }} + type=sha,prefix=live-app-${{ matrix.pipeline }}- + type=ref,event=pr,prefix=live-app-${{ matrix.pipeline }}- + type=ref,event=tag,prefix=live-app-${{ matrix.pipeline }}- + type=raw,value=latest,enable={{is_default_branch}},prefix=live-app-${{ matrix.pipeline }}- + + - name: Build and push pipeline app image + uses: docker/build-push-action@v5 + with: + context: "{{defaultContext}}:runner" + platforms: linux/amd64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + file: docker/Dockerfile.live-app__PIPELINE__ + build-args: | + PIPELINE=${{ matrix.pipeline }} + cache-from: type=registry,ref=livepeerci/build:cache + cache-to: type=registry,ref=livepeerci/build:cache,mode=max + + build-noop: + name: Build pipeline image (noop) + needs: build-common-base + runs-on: ubuntu-20.04 + permissions: + pull-requests: read + steps: + - name: Check out code + uses: actions/checkout@v4.1.1 + with: + fetch-depth: 50 + ref: ${{ github.event.pull_request.head.sha }} + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files: | + runner/docker/Dockerfile.live-app-noop + runner/app/** + + - name: Check if build needed + id: check_build + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'push' || + ( + github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name == github.repository && + steps.changed-files.outputs.any_changed == 'true' + ) + run: echo "should_build=true" >> $GITHUB_OUTPUT + + - name: Cleanup hosted runner + uses: ./.github/actions/cleanup-runner + if: steps.check_build.outputs.should_build == 'true' + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.CI_DOCKERHUB_USERNAME }} + password: ${{ secrets.CI_DOCKERHUB_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: livepeer/ai-runner + tags: | + type=raw,value=live-app-noop + type=sha,prefix=live-app-noop- + type=ref,event=pr,prefix=live-app-noop- + type=ref,event=tag,prefix=live-app-noop- + type=raw,value=latest,enable={{is_default_branch}},prefix=live-app-noop- + + - name: Build and push noop image + uses: docker/build-push-action@v5 + if: steps.check_build.outputs.should_build == 'true' + with: + context: "{{defaultContext}}:runner" + platforms: linux/amd64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + file: docker/Dockerfile.live-app-noop + cache-from: type=registry,ref=livepeerci/build:cache + cache-to: type=registry,ref=livepeerci/build:cache,mode=max diff --git a/.github/workflows/ai-runner-pipelines-docker.yaml b/.github/workflows/ai-runner-pipelines-docker.yaml index cd25a150..fce99da3 100644 --- a/.github/workflows/ai-runner-pipelines-docker.yaml +++ b/.github/workflows/ai-runner-pipelines-docker.yaml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - dockerfile: + dockerfile: - docker/Dockerfile.segment_anything_2 - docker/Dockerfile.text_to_speech steps: @@ -42,13 +42,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - name: Cleanup hosted runner - run: | - sudo apt purge -yqq dotnet-* mono-* llvm-* libllvm* powershell* openjdk-* \ - temurin-* mongodb-* firefox mysql-* \ - hhvm google-chrome-stable \ - libgl1-mesa-dri microsoft-edge-stable azure-cli || true - sudo apt autoremove -y - sudo rm -rf /usr/share/dotnet /usr/local/lib/android + uses: ./.github/actions/cleanup-runner - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.gitignore b/.gitignore index 0a9429b0..f7e8bcc1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ output aiModels.json models checkpoints +runner/run-lv2v.log # IDE .vscode diff --git a/cmd/examples/dummy-trickle-client/main.go b/cmd/examples/dummy-trickle-client/main.go new file mode 100644 index 00000000..d9f0997e --- /dev/null +++ b/cmd/examples/dummy-trickle-client/main.go @@ -0,0 +1,139 @@ +package main + +import ( + "bytes" + "context" + "flag" + "fmt" + "log/slog" + "os" + "sync" + "time" + "trickle" +) + +type ImagePublisher struct { + publisher *trickle.TricklePublisher + imagePath string + fps int +} + +type ImageSubscriber struct { + subscriber *trickle.TrickleSubscriber + startTime time.Time + frameCount int + mu sync.Mutex +} + +func (ip *ImagePublisher) publishImages(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + + // Read image file + imageData, err := os.ReadFile(ip.imagePath) + if err != nil { + slog.Error("Failed to read image", "error", err) + return + } + + interval := time.Second / time.Duration(ip.fps) + ticker := time.NewTicker(interval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + // Convert []byte to io.Reader using bytes.NewReader + reader := bytes.NewReader(imageData) + err := ip.publisher.Write(reader) + if err != nil { + slog.Error("Failed to publish image", "error", err) + return + } + } + } +} + +func (is *ImageSubscriber) subscribe(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + + is.startTime = time.Now() + for { + select { + case <-ctx.Done(): + return + default: + resp, err := is.subscriber.Read() + if err != nil { + slog.Error("Failed to read segment", "error", err) + continue + } + + is.mu.Lock() + is.frameCount++ + elapsed := time.Since(is.startTime).Seconds() + currentFPS := float64(is.frameCount) / elapsed + slog.Info("FPS Stats", + "frames", is.frameCount, + "elapsed_seconds", fmt.Sprintf("%.2f", elapsed), + "current_fps", fmt.Sprintf("%.2f", currentFPS)) + is.mu.Unlock() + + resp.Body.Close() + } + } +} + +func main() { + imagePath := flag.String("image", "", "Path to image file") + fps := flag.Int("fps", 30, "Target frames per second") + publishURL := flag.String("publishurl", "http://localhost:2865/image-send", "URL to publish images") + subscribeURL := flag.String("subscribeurl", "http://localhost:2865/image-recv", "URL to subscribe to images") + flag.Parse() + + if *imagePath == "" { + slog.Error("Image path is required") + flag.Usage() + os.Exit(1) + } + + // Create publisher + pub, err := trickle.NewTricklePublisher(*publishURL) + if err != nil { + slog.Error("Failed to create publisher", "error", err) + os.Exit(1) + } + defer pub.Close() + + // Create subscriber + sub := trickle.NewTrickleSubscriber(*subscribeURL) + + imagePublisher := &ImagePublisher{ + publisher: pub, + imagePath: *imagePath, + fps: *fps, + } + + imageSubscriber := &ImageSubscriber{ + subscriber: sub, + } + + // Create context for graceful shutdown + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Create WaitGroup for goroutines + var wg sync.WaitGroup + wg.Add(2) + + // Start publisher goroutine + go imagePublisher.publishImages(ctx, &wg) + + // Start subscriber goroutine + go imageSubscriber.subscribe(ctx, &wg) + + // Wait for interrupt signal + slog.Info("Running... Press Ctrl+C to stop") + select {} +} diff --git a/cmd/examples/image-to-image/main.go b/cmd/examples/image-to-image/main.go index b7d9fc13..bb987e69 100644 --- a/cmd/examples/image-to-image/main.go +++ b/cmd/examples/image-to-image/main.go @@ -86,6 +86,11 @@ func main() { for j, media := range resp.Images { outputPath := path.Join(baseOutputPath, strconv.Itoa(i)+"_"+strconv.Itoa(j)+".png") + if err := os.MkdirAll(baseOutputPath, 0755); err != nil { + slog.Error("Error creating output directory", slog.String("error", err.Error())) + return + } + if err := worker.SaveImageB64DataUrl(media.Url, outputPath); err != nil { slog.Error("Error saving b64 data url as image", slog.String("error", err.Error())) return diff --git a/cmd/examples/live-video-to-video/main.go b/cmd/examples/live-video-to-video/main.go new file mode 100644 index 00000000..251f2e7c --- /dev/null +++ b/cmd/examples/live-video-to-video/main.go @@ -0,0 +1,116 @@ +package main + +import ( + "context" + "errors" + "flag" + "log/slog" + "os" + "path/filepath" + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" + docker "github.com/docker/docker/client" + "github.com/livepeer/ai-worker/worker" +) + +func main() { + aiModelsDir := flag.String("aiModelsDir", "runner/models", "path to the models directory") + flag.Parse() + + pipeline := "live-video-to-video" + modelID := "noop" // modelID is used for the name of the live pipeline + // modelID = "liveportrait" + // modelID = "streamdiffusion" + // modelID = "comfyui" + defaultImageID := "livepeer/ai-runner:latest" + subscribeUrl := "http://localhost:2865/image-send" + publishUrl := "http://localhost:2865/image-recv" + gpus := []string{"0"} + + modelsDir, err := filepath.Abs(*aiModelsDir) + if errors.Is(err, os.ErrNotExist) { + slog.Error("Directory does not exist", slog.String("path", *aiModelsDir)) + return + } else if err != nil { + slog.Error("Error getting absolute path for 'aiModelsDir'", slog.String("error", err.Error())) + return + } + + w, err := worker.NewWorker(defaultImageID, gpus, modelsDir) + if err != nil { + slog.Error("Error creating worker", slog.String("error", err.Error())) + return + } + + dockerClient, err := docker.NewClientWithOpts(docker.FromEnv, docker.WithAPIVersionNegotiation()) + if err != nil { + slog.Error("Error creating docker client", slog.String("error", err.Error())) + return + } + + slog.Info("Warming container") + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + if err := w.Warm(ctx, pipeline, modelID, worker.RunnerEndpoint{}, worker.OptimizationFlags{}); err != nil { + slog.Error("Error warming container", slog.String("error", err.Error())) + return + } + + slog.Info("Warm container is up") + + req := worker.GenLiveVideoToVideoJSONRequestBody{ + ModelId: &modelID, + SubscribeUrl: subscribeUrl, + PublishUrl: publishUrl, + } + + slog.Info("Running live-video-to-video") + + resp, err := w.LiveVideoToVideo(ctx, req) + if err != nil { + slog.Error("Error running live-video-to-video", slog.String("error", err.Error())) + return + } + + // The response will be empty since there's no input stream + slog.Info("Got response", slog.Any("response", resp)) + + // Check container status every 5 seconds for up to 2 minutes + timeout := time.After(2 * time.Minute) + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + // Filter for our specific container + f := filters.NewArgs() + f.Add("label", "creator=ai-worker") + f.Add("name", pipeline+"_"+modelID) + + for { + select { + case <-timeout: + slog.Error("Container did not stop within 2 minutes") + w.Stop(ctx) + return + case <-ticker.C: + containers, err := dockerClient.ContainerList(ctx, container.ListOptions{ + Filters: f, + }) + if err != nil { + slog.Error("Error listing containers", slog.String("error", err.Error())) + w.Stop(ctx) + return + } + if len(containers) == 0 { + slog.Info("Container stopped as expected") + return + } + slog.Info("Container still running, checking again in 5 seconds", + slog.Int("container_count", len(containers)), + slog.String("container_name", containers[0].Names[0])) + } + } +} diff --git a/go.mod b/go.mod index 66381ac0..86836e49 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/go-chi/chi/v5 v5.1.0 github.com/oapi-codegen/runtime v1.1.1 github.com/vincent-petithory/dataurl v1.0.0 + trickle v0.0.0-20241120082738-d168ca53a1f5 ) require ( @@ -36,7 +37,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pkg/errors v0.8.1 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect go.opentelemetry.io/otel v1.31.0 // indirect @@ -48,3 +49,5 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect ) + +replace trickle => github.com/j0sh/http-trickle v0.0.0-20241120082738-d168ca53a1f5 \ No newline at end of file diff --git a/go.sum b/go.sum index d5a9b577..201e8fe4 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjw github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= +github.com/j0sh/http-trickle v0.0.0-20241120082738-d168ca53a1f5 h1:YjKZK3aQ3oLQlccaCRGwmF68G04j0IlJHO5lMnCgmeM= +github.com/j0sh/http-trickle v0.0.0-20241120082738-d168ca53a1f5/go.mod h1:CNKseUz1iMoL1d3U/saTo5AK1v45g4h/dvZVMl3qs+M= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= @@ -80,8 +82,9 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= diff --git a/runner/app/live/infer.py b/runner/app/live/infer.py index 546d3ff0..00837ea4 100644 --- a/runner/app/live/infer.py +++ b/runner/app/live/infer.py @@ -100,7 +100,7 @@ async def start_control_subscriber(handler: PipelineStreamer, control_url: str): "--publish-url", type=str, required=True, help="URL to publish output frames (trickle). For zeromq this is the output socket address" ) parser.add_argument( - "--control-url", type=str, help="URL to subscribe for Control API JSON messages" + "--control-url", type=str, help="URL to subscribe for Control API JSON messages to update inference params" ) parser.add_argument( "--input-timeout", diff --git a/runner/docker/Dockerfile.live-base-liveportrait b/runner/docker/Dockerfile.live-base-liveportrait index 42cf6ba8..05e3e0b0 100644 --- a/runner/docker/Dockerfile.live-base-liveportrait +++ b/runner/docker/Dockerfile.live-base-liveportrait @@ -2,7 +2,7 @@ ARG BASE_IMAGE=livepeer/ai-runner:live-base FROM ${BASE_IMAGE} # Download and install the NVIDIA TensorRT repository local deb -RUN wget https://developer.nvidia.com/downloads/compute/machine-learning/tensorrt/secure/8.6.1/local_repos/nv-tensorrt-local-repo-ubuntu2204-8.6.1-cuda-12.0_1.0-1_amd64.deb && \ +RUN wget --progress=dot:mega https://developer.nvidia.com/downloads/compute/machine-learning/tensorrt/secure/8.6.1/local_repos/nv-tensorrt-local-repo-ubuntu2204-8.6.1-cuda-12.0_1.0-1_amd64.deb && \ dpkg -i nv-tensorrt-local-repo-ubuntu2204-8.6.1-cuda-12.0_1.0-1_amd64.deb && \ cp /var/nv-tensorrt-local-repo-ubuntu2204-8.6.1-cuda-12.0/*-keyring.gpg /usr/share/keyrings/ && \ rm nv-tensorrt-local-repo-ubuntu2204-8.6.1-cuda-12.0_1.0-1_amd64.deb @@ -58,7 +58,7 @@ COPY images/flame-serious.jpg \ COPY requirements-liveportrait.txt requirements.txt RUN pip install --no-cache-dir -r requirements.txt -# TODO: Setup dependencies for animal models +# TODO: Setup dependencies for animal models (needs some custom deps detected on runtime which are not on pypi) WORKDIR /app diff --git a/runner/run-lv2v.sh b/runner/run-lv2v.sh index b22b147d..db6b9dc6 100755 --- a/runner/run-lv2v.sh +++ b/runner/run-lv2v.sh @@ -13,8 +13,12 @@ PORT=${4:-9000} # Build images, this will be quick if everything is cached docker build -t livepeer/ai-runner:live-base -f docker/Dockerfile.live-base . -docker build -t livepeer/ai-runner:live-base-${PIPELINE} -f docker/Dockerfile.live-base-${PIPELINE} . -docker build -t livepeer/ai-runner:live-app-${PIPELINE} -f docker/Dockerfile.live-app__PIPELINE__ --build-arg PIPELINE=${PIPELINE} . +if [ "${PIPELINE}" = "noop" ]; then + docker build -t livepeer/ai-runner:live-app-noop -f docker/Dockerfile.live-app-noop . +else + docker build -t livepeer/ai-runner:live-base-${PIPELINE} -f docker/Dockerfile.live-base-${PIPELINE} . + docker build -t livepeer/ai-runner:live-app-${PIPELINE} -f docker/Dockerfile.live-app__PIPELINE__ --build-arg PIPELINE=${PIPELINE} . +fi CONTAINER_NAME=live-video-to-video-${PIPELINE} docker run -it --rm --name ${CONTAINER_NAME} \ diff --git a/worker/docker.go b/worker/docker.go index 46a8cfb4..405ecae2 100644 --- a/worker/docker.go +++ b/worker/docker.go @@ -51,6 +51,7 @@ var pipelineToImage = map[string]string{ } var livePipelineToImage = map[string]string{ + "noop": "livepeer/ai-runner:live-app-noop", "streamdiffusion": "livepeer/ai-runner:live-app-streamdiffusion", "liveportrait": "livepeer/ai-runner:live-app-liveportrait", "comfyui": "livepeer/ai-runner:live-app-comfyui",