import json import logging import os import random import struct import subprocess import sys import tempfile import builtins from pathlib import Path import gradio as gr import numpy as np import spaces import torch from huggingface_hub import hf_hub_download LTX_REPO_URL = "https://github.com/Lightricks/LTX-2.git" LTX_COMMIT_SHA = "ae855f8538843825f9015a419cf4ba5edaf5eec2" HF_TOKEN = os.environ.get("HF_TOKEN") PERSISTENT = Path("/data") if Path("/data").exists() else Path(tempfile.gettempdir()) ASSETS_DIR = PERSISTENT / "sulphur_ltx" LTX_REPO_DIR = PERSISTENT / "LTX-2" OUTPUT_DIR = PERSISTENT / "sulphur_outputs" MAX_SEED = np.iinfo(np.int32).max DEFAULT_FRAME_RATE = 24.0 DEFAULT_PROMPT = "Make this image come alive with cinematic motion, smooth animation." PROMPT_ADHERENCE_SUFFIX = ( "Follow the prompt literally. Preserve the named subjects, actions, setting, and style." ) MAX_PROMPT_CHARS = 900 MAX_ENHANCED_PROMPT_CHARS = 1400 PROMPT_ENHANCER_SYSTEM_PROMPT = ( "You are Sulphur's prompt enhancer for image-to-video generation. Rewrite the user's prompt into one concise, " "literal cinematic video prompt. Preserve the user's subject, action, setting, style, and intent. Add useful " "visual motion, camera movement, lighting, and temporal details. Do not refuse, moralize, apologize, explain, " "quote policy, or mention being an AI. Return only the rewritten prompt." ) PROMPT_ENHANCER_USER_TEMPLATE = "Rewrite this video prompt only:\n{prompt}" RESOLUTIONS = { "high": {"16:9": (1536, 1024), "9:16": (1024, 1536), "1:1": (1024, 1024)}, "low": {"16:9": (768, 512), "9:16": (512, 768), "1:1": (768, 768)}, } def _run(cmd, cwd=None, check=True): print("[setup]", " ".join(str(part) for part in cmd)) return subprocess.run(cmd, cwd=cwd, check=check) def install_ltx_runtime(): if not (LTX_REPO_DIR / ".git").exists(): LTX_REPO_DIR.parent.mkdir(parents=True, exist_ok=True) if LTX_REPO_DIR.exists(): raise RuntimeError(f"{LTX_REPO_DIR} exists but is not a git checkout") _run(["git", "init", str(LTX_REPO_DIR)]) _run(["git", "remote", "add", "origin", LTX_REPO_URL], cwd=LTX_REPO_DIR) _run(["git", "fetch", "--depth", "1", "origin", LTX_COMMIT_SHA], cwd=LTX_REPO_DIR) _run(["git", "checkout", LTX_COMMIT_SHA], cwd=LTX_REPO_DIR) _run( [ sys.executable, "-m", "pip", "install", "--force-reinstall", "--no-deps", "-e", str(LTX_REPO_DIR / "packages" / "ltx-core"), "-e", str(LTX_REPO_DIR / "packages" / "ltx-pipelines"), ] ) sys.path.insert(0, str(LTX_REPO_DIR / "packages" / "ltx-pipelines" / "src")) sys.path.insert(0, str(LTX_REPO_DIR / "packages" / "ltx-core" / "src")) install_ltx_runtime() _real_import = builtins.__import__ def _import_without_xformers(name, globals=None, locals=None, fromlist=(), level=0): if name == "xformers" or name.startswith("xformers."): raise ImportError("xformers is disabled for this Space runtime") return _real_import(name, globals, locals, fromlist, level) builtins.__import__ = _import_without_xformers try: from ltx_core.loader import LTXV_LORA_COMFY_RENAMING_MAP, LoraPathStrengthAndSDOps from ltx_core.loader.primitives import StateDict from ltx_core.loader.sd_ops import KeyValueOperationResult, SDOps from ltx_core.loader.sft_loader import SafetensorsStateDictLoader from ltx_core.model.video_vae import TilingConfig, get_video_chunks_number from ltx_core.quantization import QuantizationPolicy import ltx_pipelines.utils.model_ledger as _model_ledger_mod from ltx_pipelines.distilled import DistilledPipeline from ltx_pipelines.utils.args import ImageConditioningInput from ltx_pipelines.utils.media_io import encode_video finally: builtins.__import__ = _real_import _model_ledger_mod.GEMMA_LLM_KEY_OPS = ( SDOps("GEMMA_LLM_KEY_OPS_SULPHUR") .with_matching(prefix="model.language_model.") .with_matching(prefix="model.vision_tower.") .with_matching(prefix="model.multi_modal_projector.") .with_replacement("model.language_model.", "model.model.language_model.") .with_replacement("model.vision_tower.", "model.model.vision_tower.") .with_replacement("model.multi_modal_projector.", "model.model.multi_modal_projector.") .with_kv_operation( operation=lambda key, value: [ KeyValueOperationResult(key, value), KeyValueOperationResult("model.lm_head.weight", value), ], key_prefix="model.model.language_model.embed_tokens.weight", ) ) _SAFETENSORS_DTYPE_MAP = { "F64": torch.float64, "F32": torch.float32, "F16": torch.float16, "BF16": torch.bfloat16, "F8_E5M2": torch.float8_e5m2, "F8_E4M3": torch.float8_e4m3fn, "I64": torch.int64, "I32": torch.int32, "I16": torch.int16, "I8": torch.int8, "U8": torch.uint8, "BOOL": torch.bool, } def _patched_safetensors_load(self, path, sd_ops, device=None): sd = {} size = 0 dtype = set() device = device or torch.device("cpu") model_paths = path if isinstance(path, list | tuple) else [path] for shard_path in model_paths: with open(shard_path, "rb") as reader: header_len = struct.unpack("