You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(live): address PR review feedback on @pipeline decorator
- Fix __qualname__ on function wrapper for correct importlib resolution
- Add module docstring with lifecycle hook reference to create.py
- Improve _build_pipeline docstring documenting hook detection
- Normalize VideoOutput request_id to prevent silent frame drops
- Make prepare_models async-capable via _invoke for sync/async support
- Replace MiDaS example with pure-torch edge detection (no external deps)
- Update docs to use EdgeDetect example throughout
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This guide explains how to create a custom pipeline for the AI Runner from a **separate repository**. We'll use [scope-runner](https://github.com/livepeer/scope-runner) as a reference implementation.
4
4
@@ -9,7 +9,7 @@ This guide explains how to create a custom pipeline for the AI Runner from a **s
9
9
A custom pipeline is a Python package that:
10
10
11
11
1. Extends the `ai-runner[realtime]` library as a dependency (or `ai-runner[batch]` for a batch pipeline)
12
-
2.Implements the [`Pipeline`](../runner/src/runner/live/pipelines/interface.py#L46) interface for frame processing
12
+
2.Uses the [`@pipeline`](../runner/src/runner/live/pipelines/create.py) decorator to define frame processing logic
You have two options: the `@pipeline` decorator (recommended) or the raw `Pipeline` interface (full control over frame queuing, batching, and threading).
80
-
81
-
### Option A: `@pipeline` Decorator (Recommended)
82
-
83
-
The `@pipeline` decorator handles frame queues, lifecycle, threading, and parameter validation automatically.
79
+
Use the `@pipeline` decorator to define your pipeline. The decorator handles frame queues, lifecycle management, parameter validation, and threading automatically.
|`on_update(self, **params)`| No |**Mid-stream**| Handle param changes |
152
+
|`on_stop(self)`| No |**Shutdown**| Release resources |
173
153
174
-
For advanced use cases where you need full control over frame queuing, custom batching, or complex threading. Here's the same depth-midas pipeline implemented with the raw interface:
154
+
Both `async def` and `def` work for all methods. Sync functions automatically run in a thread pool.
175
155
176
-
```python
177
-
# src/my_pipeline/pipeline/pipeline.py
178
-
import asyncio
179
-
import logging
180
-
import torch
181
-
from runner.live.pipelines import Pipeline
182
-
from runner.live.trickle import VideoFrame, VideoOutput
For another real-world example, see [scope-runner's pipeline](https://github.com/daydreamlive/scope-runner/blob/dec9ecf7e306892df9cfae21759c23fdf15b0510/src/scope_runner/pipeline/pipeline.py#L22).
156
+
See [`examples/live-video-to-video/`](../examples/live-video-to-video/) for complete working examples.
The `prepare_models()` classmethod is called when running with the `PREPARE_MODELS=1` environment variable (or `--prepare-models` flag). It is set automatically by `dl_checkpoints.sh` during operator setup.
245
+
The `prepare_models()` classmethod runs at **build time** when an operator sets up their node, not when a stream or request arrives. It is triggered by the `PREPARE_MODELS=1` environment variable (or `--prepare-models` flag), and is called automatically by `dl_checkpoints.sh` during operator setup.
246
+
247
+
This is the right place for any expensive one-time work:
325
248
326
-
Example implementation (in your `pipeline.py`):
249
+
-**Downloading model weights** from HuggingFace, Google Drive, etc.
250
+
-**Compiling TensorRT engines** for optimized GPU inference
251
+
-**Converting model formats** (e.g., ONNX export, quantization)
252
+
-**Warming up caches** or generating lookup tables
253
+
254
+
Unlike runtime (where `HF_HUB_OFFLINE=1` prevents accidental downloads), `prepare_models` runs with full network access so you can fetch weights from HuggingFace, Google Drive, or other sources.
327
255
328
256
```python
329
257
@classmethod
@@ -344,12 +272,26 @@ def prepare_models(cls):
344
272
local_dir_use_symlinks=False,
345
273
)
346
274
347
-
# Compile TensorRT engines if needed
348
-
# This is where you'd run expensive one-time operations
275
+
# Optional: compile TensorRT engine for faster inference
276
+
# import torch_tensorrt
277
+
# model = torch.load(models_dir / "my-model" / "model.pt")
## Step 6: Integration with Livepeer Infrastructure
@@ -492,8 +434,7 @@ The orchestrator will route requests to your local runner at `http://localhost:8
492
434
493
435
### Async Operations
494
436
495
-
- Use `asyncio.to_thread()` for blocking/CPU-bound operations
496
-
- Never block the event loop in `put_video_frame` or `get_processed_video_frame`
437
+
- Both `async def` and `def` work — the `@pipeline` decorator automatically runs sync methods in a thread pool so they won't block the event loop
497
438
498
439
### Error Handling
499
440
@@ -502,8 +443,8 @@ The orchestrator will route requests to your local runner at `http://localhost:8
502
443
503
444
### Parameter Updates
504
445
505
-
- Return nothing from `update_params()` for instant updates
506
-
-Return an `asyncio.Task` for updates that will take a long time, normally a "pipeline reload". The runtime shows loading overlay while the reload is running.
446
+
- Return nothing from `on_update()` for instant updates
447
+
-For slow reloads, the runtime shows a loading overlay while the update is running
507
448
508
449
---
509
450
@@ -519,19 +460,6 @@ The orchestrator will route requests to your local runner at `http://localhost:8
519
460
520
461
---
521
462
522
-
## Publishing to the Marketplace
523
-
524
-
Publish your pipeline to make it discoverable on the marketplace. The CLI extracts the parameter schema from your `@pipeline` decorator and registers it automatically.
0 commit comments