| import argparse |
| from pathlib import Path |
|
|
| from ...ltx_core.loader import LTXV_LORA_COMFY_RENAMING_MAP, LoraPathStrengthAndSDOps |
| from .constants import ( |
| DEFAULT_1_STAGE_HEIGHT, |
| DEFAULT_1_STAGE_WIDTH, |
| DEFAULT_2_STAGE_HEIGHT, |
| DEFAULT_2_STAGE_WIDTH, |
| DEFAULT_CFG_GUIDANCE_SCALE, |
| DEFAULT_FRAME_RATE, |
| DEFAULT_LORA_STRENGTH, |
| DEFAULT_NEGATIVE_PROMPT, |
| DEFAULT_NUM_FRAMES, |
| DEFAULT_NUM_INFERENCE_STEPS, |
| DEFAULT_SEED, |
| ) |
|
|
|
|
| class VideoConditioningAction(argparse.Action): |
| def __call__( |
| self, |
| parser: argparse.ArgumentParser, |
| namespace: argparse.Namespace, |
| values: list[str], |
| option_string: str | None = None, |
| ) -> None: |
| path, strength_str = values |
| resolved_path = resolve_path(path) |
| strength = float(strength_str) |
| current = getattr(namespace, self.dest) or [] |
| current.append((resolved_path, strength)) |
| setattr(namespace, self.dest, current) |
|
|
|
|
| class ImageAction(argparse.Action): |
| def __call__( |
| self, |
| parser: argparse.ArgumentParser, |
| namespace: argparse.Namespace, |
| values: list[str], |
| option_string: str | None = None, |
| ) -> None: |
| path, frame_idx, strength_str = values |
| resolved_path = resolve_path(path) |
| frame_idx = int(frame_idx) |
| strength = float(strength_str) |
| current = getattr(namespace, self.dest) or [] |
| current.append((resolved_path, frame_idx, strength)) |
| setattr(namespace, self.dest, current) |
|
|
|
|
| class LoraAction(argparse.Action): |
| def __call__( |
| self, |
| parser: argparse.ArgumentParser, |
| namespace: argparse.Namespace, |
| values: list[str], |
| option_string: str | None = None, |
| ) -> None: |
| if len(values) > 2: |
| msg = f"{option_string} accepts at most 2 arguments (PATH and optional STRENGTH), got {len(values)} values" |
| raise argparse.ArgumentError(self, msg) |
|
|
| path = values[0] |
| strength_str = values[1] if len(values) > 1 else str(DEFAULT_LORA_STRENGTH) |
|
|
| resolved_path = resolve_path(path) |
| strength = float(strength_str) |
|
|
| current = getattr(namespace, self.dest) or [] |
| current.append(LoraPathStrengthAndSDOps(resolved_path, strength, LTXV_LORA_COMFY_RENAMING_MAP)) |
| setattr(namespace, self.dest, current) |
|
|
|
|
| def resolve_path(path: str) -> str: |
| return str(Path(path).expanduser().resolve().as_posix()) |
|
|
|
|
| def basic_arg_parser() -> argparse.ArgumentParser: |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "--checkpoint-path", |
| type=resolve_path, |
| required=True, |
| help="Path to LTX-2 model checkpoint (.safetensors file).", |
| ) |
| parser.add_argument( |
| "--gemma-root", |
| type=resolve_path, |
| required=True, |
| help="Path to the root directory containing the Gemma text encoder model files.", |
| ) |
| parser.add_argument( |
| "--prompt", |
| type=str, |
| required=True, |
| help="Text prompt describing the desired video content to be generated by the model.", |
| ) |
| parser.add_argument( |
| "--output-path", |
| type=resolve_path, |
| required=True, |
| help="Path to the output video file (MP4 format).", |
| ) |
| parser.add_argument( |
| "--seed", |
| type=int, |
| default=DEFAULT_SEED, |
| help=( |
| f"Random seed value used to initialize the noise tensor for " |
| f"reproducible generation (default: {DEFAULT_SEED})." |
| ), |
| ) |
| parser.add_argument( |
| "--height", |
| type=int, |
| default=DEFAULT_1_STAGE_HEIGHT, |
| help=f"Height of the generated video in pixels, should be divisible by 32 (default: {DEFAULT_1_STAGE_HEIGHT}).", |
| ) |
| parser.add_argument( |
| "--width", |
| type=int, |
| default=DEFAULT_1_STAGE_WIDTH, |
| help=f"Width of the generated video in pixels, should be divisible by 32 (default: {DEFAULT_1_STAGE_WIDTH}).", |
| ) |
| parser.add_argument( |
| "--num-frames", |
| type=int, |
| default=DEFAULT_NUM_FRAMES, |
| help=f"Number of frames to generate in the output video sequence, num-frames = (8 x K) + 1, " |
| f"where k is a non-negative integer (default: {DEFAULT_NUM_FRAMES}).", |
| ) |
| parser.add_argument( |
| "--frame-rate", |
| type=float, |
| default=DEFAULT_FRAME_RATE, |
| help=f"Frame rate of the generated video (fps) (default: {DEFAULT_FRAME_RATE}).", |
| ) |
| parser.add_argument( |
| "--num-inference-steps", |
| type=int, |
| default=DEFAULT_NUM_INFERENCE_STEPS, |
| help=( |
| f"Number of denoising steps in the diffusion sampling process. " |
| f"Higher values improve quality but increase generation time (default: {DEFAULT_NUM_INFERENCE_STEPS})." |
| ), |
| ) |
| parser.add_argument( |
| "--image", |
| dest="images", |
| action=ImageAction, |
| nargs=3, |
| metavar=("PATH", "FRAME_IDX", "STRENGTH"), |
| default=[], |
| help=( |
| "Image conditioning input: path to image file, target frame index, " |
| "and conditioning strength (all three required). Default: empty list [] (no image conditioning). " |
| "Can be specified multiple times. Example: --image path/to/image1.jpg 0 0.8 " |
| "--image path/to/image2.jpg 160 0.9" |
| ), |
| ) |
| parser.add_argument( |
| "--lora", |
| dest="lora", |
| action=LoraAction, |
| nargs="+", |
| metavar=("PATH", "STRENGTH"), |
| default=[], |
| help=( |
| "LoRA (Low-Rank Adaptation) model: path to model file and optional strength " |
| f"(default strength: {DEFAULT_LORA_STRENGTH}). Can be specified multiple times. " |
| "Example: --lora path/to/lora1.safetensors 0.8 --lora path/to/lora2.safetensors" |
| ), |
| ) |
| parser.add_argument( |
| "--enable-fp8", |
| action="store_true", |
| help="Enable FP8 mode to reduce memory footprint by keeping model in lower precision. " |
| "Note that calculations are still performed in bfloat16 precision.", |
| ) |
| parser.add_argument("--enhance-prompt", action="store_true") |
| return parser |
|
|
|
|
| def default_1_stage_arg_parser() -> argparse.ArgumentParser: |
| parser = basic_arg_parser() |
| parser.add_argument( |
| "--cfg-guidance-scale", |
| type=float, |
| default=DEFAULT_CFG_GUIDANCE_SCALE, |
| help=( |
| f"Classifier-free guidance (CFG) scale controlling how strongly " |
| f"the model adheres to the prompt. Higher values increase prompt " |
| f"adherence but may reduce diversity (default: {DEFAULT_CFG_GUIDANCE_SCALE})." |
| ), |
| ) |
| parser.add_argument( |
| "--negative-prompt", |
| type=str, |
| default=DEFAULT_NEGATIVE_PROMPT, |
| help=( |
| "Negative prompt describing what should not appear in the generated video, " |
| "used to guide the diffusion process away from unwanted content. " |
| "Default: a comprehensive negative prompt covering common artifacts and quality issues." |
| ), |
| ) |
|
|
| return parser |
|
|
|
|
| def default_2_stage_arg_parser() -> argparse.ArgumentParser: |
| parser = default_1_stage_arg_parser() |
| parser.set_defaults(height=DEFAULT_2_STAGE_HEIGHT, width=DEFAULT_2_STAGE_WIDTH) |
| |
| for action in parser._actions: |
| if "--height" in action.option_strings: |
| action.help = ( |
| f"Height of the generated video in pixels, should be divisible by 64 " |
| f"(default: {DEFAULT_2_STAGE_HEIGHT})." |
| ) |
| if "--width" in action.option_strings: |
| action.help = ( |
| f"Width of the generated video in pixels, should be divisible by 64 (default: {DEFAULT_2_STAGE_WIDTH})." |
| ) |
| parser.add_argument( |
| "--distilled-lora", |
| dest="distilled_lora", |
| action=LoraAction, |
| nargs="+", |
| metavar=("PATH", "STRENGTH"), |
| required=True, |
| help=( |
| "Distilled LoRA (Low-Rank Adaptation) model used in the second stage (upscaling and refinement): " |
| f"path to model file and optional strength (default strength: {DEFAULT_LORA_STRENGTH}). " |
| "The second stage upsamples the video by 2x resolution and refines it using a distilled " |
| "denoising schedule (fewer steps, no CFG). The distilled LoRA is specifically trained " |
| "for this refinement process to improve quality at higher resolutions. " |
| "Example: --distilled-lora path/to/distilled_lora.safetensors 0.8" |
| ), |
| ) |
| parser.add_argument( |
| "--spatial-upsampler-path", |
| type=resolve_path, |
| required=True, |
| help=( |
| "Path to the spatial upsampler model used to increase the resolution " |
| "of the generated video in the latent space." |
| ), |
| ) |
| return parser |
|
|
|
|
| def default_2_stage_distilled_arg_parser() -> argparse.ArgumentParser: |
| parser = basic_arg_parser() |
| parser.set_defaults(height=DEFAULT_2_STAGE_HEIGHT, width=DEFAULT_2_STAGE_WIDTH) |
| |
| for action in parser._actions: |
| if "--height" in action.option_strings: |
| action.help = ( |
| f"Height of the generated video in pixels, should be divisible by 64 " |
| f"(default: {DEFAULT_2_STAGE_HEIGHT})." |
| ) |
| if "--width" in action.option_strings: |
| action.help = ( |
| f"Width of the generated video in pixels, should be divisible by 64 (default: {DEFAULT_2_STAGE_WIDTH})." |
| ) |
| parser.add_argument( |
| "--spatial-upsampler-path", |
| type=resolve_path, |
| required=True, |
| help=( |
| "Path to the spatial upsampler model used to increase the resolution " |
| "of the generated video in the latent space." |
| ), |
| ) |
| return parser |
|
|