Returns progress, frame, total_frames from Celery task state
so clients can display rendering progress.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove stream_dir deletion in finally block to prevent IPFS upload failures
- Add on_progress callback to StreamInterpreter for real-time progress updates
- Task now sends progress updates to Celery state during rendering
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add "Run Again" button that reruns the recipe with same parameters
- Add "Delete" button with confirmation to delete run and artifacts
- Consolidate result display into single #action-result span
- Implement POST /runs/rerun/{recipe_id} endpoint
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CUDA sync before encoding to ensure RGB->NV12 kernel completes
- Add debug logging for frame data validation (sum check)
- Handle GPUFrame objects in GPUHLSOutput.write()
- Fix cv2.resize for CuPy arrays (use cupyx.scipy.ndimage.zoom)
- Fix fused pipeline parameter ordering (geometric first, color second)
- Add raindrop-style ripple with random position/freq/decay/amp
- Generate final VOD playlist with #EXT-X-ENDLIST
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Return ipfs_playlist_cid from pending_runs while task is running
- Add Cache-Control: no-cache headers to prevent browser/CDN caching
- Fix streaming clients getting stale playlist CIDs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Recipe should work on both CPU and GPU. The interpreter
auto-selects *_gpu versions when available.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Python fallback path was reading amplitude directly from effect dict
instead of checking dynamic_params first like the CUDA kernel path does.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Zoom now driven by audio energy via core:map-range
- Ripple amplitude reads from dynamic_params in sexp_to_cuda
- Crossfade transition with zoom in/out effect
- Move git clone before COPY in Dockerfile for better caching
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When running with --pool=solo, there may already be a running event loop.
Use thread pool to run async coroutines when a loop is already running.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Downstream code expects arrays with .flags attribute, not GPUFrame.
Extract the underlying gpu/cpu array before returning.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The fallback path was passing raw numpy/cupy arrays to GPU functions
that expect GPUFrame objects with .cpu property.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Audio playback path was being resolved during parsing when database
may not be ready, causing fallback to non-existent path. Now resolves
lazily when stream starts, matching how audio analyzer works.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace slow scipy.ndimage operations with custom CUDA kernels:
- gpu_rotate: AFFINE_WARP_KERNEL (< 1ms vs 20ms for scipy)
- gpu_blend: BLEND_KERNEL for fast alpha blending
- gpu_brightness/contrast: BRIGHTNESS_CONTRAST_KERNEL
- Add gpu_zoom, gpu_hue_shift, gpu_invert, gpu_ripple
Preserve GPU arrays through pipeline:
- Updated _maybe_to_numpy() to keep CuPy arrays for GPU primitives
- Primitives detect CuPy arrays via __cuda_array_interface__
- No unnecessary CPU round-trips between operations
New jit_compiler.py contains all CUDA kernels with FastGPUOps
class using ping-pong buffer strategy for efficient in-place ops.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- New GPUHLSOutput class for direct GPU-to-NVENC encoding
- RGB→NV12 conversion via CUDA kernel (no CPU transfer)
- Uses PyNvVideoCodec for zero-copy GPU encoding
- ~220fps vs ~4fps with CPU pipe approach
- Automatically used when PyNvVideoCodec is available
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use devel image for compilation, runtime for final image.
Keeps image smaller while enabling NVDEC decode.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>