Files
DumasNodes/dumas_h3_longvideos_shot_plan.py
T

110 lines
3.3 KiB
Python

# H3-LongVideos -- https://github.com/Smite79/MiniMax-H3-LongVideos
# Copyright (c) 2026 Smite79. All rights reserved.
# Redistribution, in whole or in part, requires written permission.
# This notice may not be removed or altered. See LICENSE.
"""Per-shot records passed from prompt planning to rendering."""
from dataclasses import dataclass, field
@dataclass
class Shot:
prompt: str
cast: list[str]
speech: bool
sounded: bool
voiced_only: bool
events: list[str]
frame_count: int = 0
refs: list[object] = field(default_factory=list)
line_seconds: float = 0.0 # the planner's estimate of the spoken line, words / WORDS_PER_SEC
@dataclass
class ShotPlan:
shots: list[Shot] = field(default_factory=list)
@property
def prompts(self):
return [shot.prompt for shot in self.shots]
def add(self, prompt, cast, speech, sounded, voiced_only, events):
shot = Shot(prompt, list(cast or ()), bool(speech), bool(sounded),
bool(voiced_only), list(events or ()))
self.shots.append(shot)
def set_frame_counts(self, counts):
counts = [int(n) for n in counts]
if len(counts) != len(self.shots) or any(n <= 0 for n in counts):
raise ValueError("frame counts must be positive and match the planned shots")
for shot, count in zip(self.shots, counts):
shot.frame_count = count
def validate(self):
if any(shot.frame_count <= 0 for shot in self.shots):
raise ValueError("each shot needs a positive frame count before rendering")
return self
def __len__(self):
return len(self.shots)
@dataclass
class PreparedVideo:
"""Resolved inputs consumed by the render stage; model/tensor handles are shared."""
_placed_shots: object
_first_is_plate: object
_returns: object
_soft_landing: object
_tagged_names: object
ambient_audio: object
ambient_level: float
apply_model_sampling: bool
audio_vae: object
auto_sound: bool
bared_shots: object
cfg: float
cleanup_between_shots: bool
clip: object
first_frame: object
foley_level: float
h: int
latent_upscale: str
latent_upscale_scale: float
megapixels: float
model: object
moved_shots: object
negative: object
notes: list[str]
plan: ShotPlan
ref_noise_aug: float | None
restart_after_removal: bool
revealed_shots: object
sampler_name: str
scheduler: str
seed: int
shift_audio: float
shift_video: float
sigmas: object
silence_nonspeech: bool
speech_lead_seconds: float
speech_tail_seconds: float
hold_levels: float
handoff_frames: int
staging_shots: object
steps: int
stripped_shots: object
cut_shots: object
tiled_decode: bool
trim_seam: bool
upscale: str
upscale_batch: int
upscale_model: str
upscale_target_short_edge: int
vae: object
w: int
shot_rooms: object = None # {0-based shot: (room it opens in, room it ends in)}
hardware_changed: object = None # 1-based shots that put hardware on or take it off
shot_frames: object = None # {0-based shot: (who its frames show, who is still there at its end)}
reentry_shots: object = None # {0-based shot: who walks in while the keyframe still has them}