streaming ¶
Classes¶
fastvideo.entrypoints.streaming.BlobStore ¶
Bases: ABC
Opaque byte-blob storage keyed by id.
A :class:ContinuationState payload can reference large tensors stored in a :class:BlobStore rather than inlining them, so the JSON payload stays small when the state travels over the wire.
fastvideo.entrypoints.streaming.FragmentedMP4Chunk dataclass ¶
A single fMP4 byte chunk emitted by :class:FragmentedMP4Encoder.
kind identifies whether the chunk is the init segment (must be fed into the client's SourceBuffer first) or a media fragment.
fastvideo.entrypoints.streaming.FragmentedMP4Encoder ¶
FragmentedMP4Encoder(*, width: int, height: int, fps: int, segment_idx: int, stream_id: str | None = None, ffmpeg_path: str = 'ffmpeg', preset: str = 'ultrafast', pixel_format_out: str = 'yuv420p', extra_args: list[str] | None = None)
Stream RGB frames in, fMP4 chunks out.
One encoder covers one segment. The server creates a new encoder per :class:`ltx2_segment_start`` boundary so each segment becomes one media fragment the client can append independently.
Example::
encoder = FragmentedMP4Encoder(width=1024, height=576, fps=24,
segment_idx=0)
async with encoder:
async for chunk in encoder.encode(frames):
await websocket.send_bytes(chunk.data)
Source code in fastvideo/entrypoints/streaming/stream.py
Methods:¶
fastvideo.entrypoints.streaming.FragmentedMP4Encoder.encode async ¶
encode(frames: list[ndarray] | AsyncIterator[ndarray]) -> AsyncIterator[FragmentedMP4Chunk]
Feed frames into ffmpeg and yield fMP4 chunks as they appear.
Source code in fastvideo/entrypoints/streaming/stream.py
fastvideo.entrypoints.streaming.GpuPool ¶
Bases: ABC
Abstract GPU pool.
acquire binds a session to a worker and holds that binding across segments so continuation state can stay hot. run submits a single GenerationRequest for a bound session.
Acquire / release are independent of run — a session can run many segments on one acquired worker, and must release on disconnect.
fastvideo.entrypoints.streaming.InMemoryBlobStore ¶
Bases: BlobStore
Thread-safe in-memory :class:BlobStore for single-process servers.
No eviction policy — callers are responsible for calling :meth:drop when a blob's owning state is replaced or a session ends. A redis- or filesystem-backed :class:BlobStore should replace this when the streaming server lands as a real service (PR 7.5+).
Source code in fastvideo/entrypoints/streaming/session_store.py
fastvideo.entrypoints.streaming.InMemorySessionStore ¶
Bases: SessionStore
Thread-safe in-memory :class:SessionStore.
Default implementation used by single-process deployments; a future Redis-backed store can be dropped in without changes to the server.
No eviction / TTL / bounded capacity — sessions only leave via :meth:drop. The live streaming server (PR 7.5+) is responsible for bounding growth and for dropping any :class:BlobStore blobs referenced by a state when that state is replaced or a session ends; this class does not know about blobs.
Source code in fastvideo/entrypoints/streaming/session_store.py
fastvideo.entrypoints.streaming.InProcessGpuPool ¶
InProcessGpuPool(generator: _GeneratorLike, *, gpu_id: int = 0, session_store: SessionStore | None = None)
Bases: GpuPool
Single-process pool backed by one :class:_GeneratorLike.
This is what PR 7.5's server uses by default; PR 7.6 adds the real SubprocessGpuPool alternative but keeps this one for tests and small deployments.
Source code in fastvideo/entrypoints/streaming/gpu_pool.py
fastvideo.entrypoints.streaming.LLMProvider ¶
Bases: Protocol
Provider interface every LLM adapter implements.
Providers are async-first because every built-in implementation talks to an HTTP API. Synchronous providers can wrap their call in asyncio.to_thread internally.
fastvideo.entrypoints.streaming.MockGenerator dataclass ¶
MockGenerator(sleep_ms: float = 0.0)
Generator stand-in that returns synthetic gradient frames.
Each call produces one segment worth of frames whose pixels vary by a constant derived from the request seed and segment index. Latency is configurable via sleep_ms so the caller can exercise slow- generate scenarios without spinning a GPU.
fastvideo.entrypoints.streaming.PoolAcquireTimeout ¶
Bases: RuntimeError
Raised when acquire times out waiting for a free worker.
fastvideo.entrypoints.streaming.PromptEnhancer ¶
PromptEnhancer(*, providers: Sequence[LLMProvider], model: str, timeout_ms: int = 20000, temperature: float = 0.7, max_tokens: int | None = 256, system_prompt_dir: str | None = None)
Orchestrates prompt operations across a priority-ordered provider list with structured fallback + hot-reloadable system prompts.
Usage::
enhancer = PromptEnhancer(
providers=[CerebrasProvider(), GroqProvider()],
model="gpt-oss-120b",
system_prompt_dir="/etc/fastvideo/prompts",
)
response = await enhancer.enhance("a fox running through snow")
Source code in fastvideo/entrypoints/streaming/prompt/enhancer.py
Methods:¶
fastvideo.entrypoints.streaming.PromptEnhancer.register_provider ¶
register_provider(provider: LLMProvider, *, priority: int = -1) -> None
Insert an additional provider. priority=0 makes it primary; priority=-1 (default) appends as a fallback.
Source code in fastvideo/entrypoints/streaming/prompt/enhancer.py
fastvideo.entrypoints.streaming.PromptEnhancer.reload_system_prompts ¶
Re-read the system prompt files from system_prompt_dir.
The streaming server exposes this via a management endpoint so operators can iterate on prompt templates without restarting workers.
Source code in fastvideo/entrypoints/streaming/prompt/enhancer.py
fastvideo.entrypoints.streaming.PromptSafetyFilter ¶
PromptSafetyFilter(*, classifier_path: str | None, enabled: bool = True, block_threshold: float = 0.5)
Minimal fastText-backed prompt safety filter.
Loads the classifier lazily on first use so the streaming server can construct the filter eagerly at startup without paying the model-load cost when safety is disabled.
Source code in fastvideo/entrypoints/streaming/prompt/safety.py
fastvideo.entrypoints.streaming.SafetyDecision ¶
Bases: Enum
fastvideo.entrypoints.streaming.Session dataclass ¶
Session(id: str = (lambda: hex)(), state: SessionState = INITIALIZING, created_at: float = monotonic(), last_activity: float = monotonic(), client_id: str | None = None, preset: str | None = None, preset_label: str | None = None, curated_prompts: list[str] = list(), segment_idx: int = 0, enhancement_enabled: bool = False, auto_extension_enabled: bool = False, loop_generation_enabled: bool = False, single_clip_mode: bool = False, generation_paused: bool = False, stream_mode: str = 'av_fmp4', gpu_id: int | None = None, continuation_state: ContinuationState | None = None, metadata: dict[str, Any] = dict())
Methods:¶
fastvideo.entrypoints.streaming.Session.transition ¶
transition(target: SessionState) -> None
Move to target if the edge is allowed.
Raises :class:InvalidSessionTransition on illegal moves. The self-loop on ACTIVE is legal so the server can re-assert ACTIVE on segment completion without special casing.
Source code in fastvideo/entrypoints/streaming/session.py
fastvideo.entrypoints.streaming.SessionLogEvent dataclass ¶
One line in the session JSONL file.
fastvideo.entrypoints.streaming.SessionLogger ¶
SessionLogger(log_dir: str | None)
Append-only JSONL logger keyed by session id.
Thread-safe; the server may be writing from multiple asyncio tasks (fMP4 encoder thread + control-frame handler) for the same session.
Source code in fastvideo/entrypoints/streaming/session_logger.py
fastvideo.entrypoints.streaming.SessionManager ¶
Registers sessions and enforces per-server session limits.
Source code in fastvideo/entrypoints/streaming/session.py
Methods:¶
fastvideo.entrypoints.streaming.SessionManager.reap_timed_out ¶
Return the ids of sessions that have exceeded the idle timeout.
The caller is responsible for actually closing them — this method only identifies dead sessions so the server can emit session_timeout frames before dropping the WebSocket.
TODO: unused until a background driver calls it. Per-connection idle enforcement currently happens via asyncio.wait_for on receive_json; this helper catches sessions stuck before any receive (e.g. future QUEUED state) and is expected to be wired into the GPU-pool reaper.
Source code in fastvideo/entrypoints/streaming/session.py
fastvideo.entrypoints.streaming.SessionState ¶
Bases: Enum
State-machine positions for a streaming session.
Transitions are server-owned. See docs/design/server_contracts/streaming.md for the full diagram.
fastvideo.entrypoints.streaming.SessionStore ¶
Bases: ABC
Keyed store for per-session continuation state.
Implementations own the session-id → state mapping. The streaming server calls :meth:store after each segment and :meth:snapshot when a client explicitly asks for an exportable state handle.
Methods:¶
fastvideo.entrypoints.streaming.SessionStore.hydrate abstractmethod ¶
Install state as the starting point for a session.
When session_id is None the store allocates a fresh id (UUID4); when provided the store uses it verbatim, overwriting any prior state at that id.
Source code in fastvideo/entrypoints/streaming/session_store.py
fastvideo.entrypoints.streaming.SessionStore.snapshot abstractmethod ¶
snapshot(session_id: str) -> ContinuationState | None
fastvideo.entrypoints.streaming.SubprocessGpuPool ¶
SubprocessGpuPool(generator_config: GeneratorConfig, *, pool_config: GpuPoolConfig, warmup_config: WarmupConfig | None = None, session_store: SessionStore | None = None, worker_factory: WorkerFactory | None = None)
Bases: GpuPool
One multiprocessing.Process per GPU.
Each worker boots :class:fastvideo.VideoGenerator from a typed :class:GeneratorConfig inside the child process (post- CUDA_VISIBLE_DEVICES setup) and consumes jobs from an mp Queue.
This is the production shape: the parent process stays CPU-only, and GPU state never crosses process boundaries. Continuation state is serialized through :class:SessionStore for cross-GPU handoff.
PR 7.6 ships this as an opt-in; PR 7.5's in-process pool remains the default until nightly runs validate the subprocess path.
Source code in fastvideo/entrypoints/streaming/gpu_pool.py
Methods:¶
fastvideo.entrypoints.streaming.SubprocessGpuPool.start async ¶
Spawn worker processes and wait for each to report ready.
Source code in fastvideo/entrypoints/streaming/gpu_pool.py
Functions:¶
fastvideo.entrypoints.streaming.build_app ¶
build_app(serve_config: ServeConfig, generator: _GeneratorProto | None = None, *, pool: GpuPool | None = None, session_store: SessionStore | None = None) -> FastAPI
Build the FastAPI app used by :func:run_server.
Exposed so tests can drive the WebSocket endpoint in-process via starlette.testclient.TestClient(app).websocket_connect(...).
Exactly one of generator (backed by :class:InProcessGpuPool) or pool (for the subprocess-backed production shape) must be given.
Source code in fastvideo/entrypoints/streaming/server.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | |
fastvideo.entrypoints.streaming.build_health_router ¶
Build a router exposing streaming liveness/readiness endpoints.
pool may be either a concrete pool or a zero-argument callable that returns the current pool. The callable form lets product servers keep their own lifespan-managed runtime singleton without adding public global state.
Source code in fastvideo/entrypoints/streaming/health.py
fastvideo.entrypoints.streaming.build_mock_app ¶
build_mock_app(*, sleep_ms: float = 0.0)
Build a FastAPI app backed by :class:MockGenerator.
Source code in fastvideo/entrypoints/streaming/mock_server.py
fastvideo.entrypoints.streaming.get_pool_status async ¶
Return the generic GPU pool status payload used by /status.
Source code in fastvideo/entrypoints/streaming/health.py
fastvideo.entrypoints.streaming.run_server ¶
run_server(serve_config: ServeConfig, *, generator: _GeneratorProto | None = None) -> None
Launch the streaming server.
Boots a :class:fastvideo.VideoGenerator from serve_config.generator unless generator is provided, then serves build_app(...) via uvicorn.