File size: 4,439 Bytes
7c0d904
9aed51b
7c0d904
 
 
1182ed8
35d495d
3ab13c5
9aed51b
 
7c0d904
3ab13c5
 
7c0d904
 
9aed51b
c72098e
1182ed8
 
 
 
 
 
c72098e
5183bf3
 
 
 
 
 
 
c72098e
35d495d
c72098e
5183bf3
c72098e
35d495d
 
c72098e
35d495d
 
 
 
 
 
3ab13c5
c72098e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35d495d
 
 
c72098e
7c0d904
 
3ab13c5
9aed51b
7c0d904
35d495d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c72098e
35d495d
 
 
 
 
 
c72098e
35d495d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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
import os
import tempfile
import torch
import gradio as gr
import spaces
from huggingface_hub import hf_hub_download
from safetensors.torch import load_file
from diffusers import LTXPipeline, LTXVideoTransformer3DModel
from diffusers.utils import export_to_video

BASE_MODEL = "Lightricks/LTX-Video"
FINE_TUNED_MODEL = "DollasAndSpence/LTX2.3-ICEdit-Insight"
WEIGHT_NAME = "ltx-2.3-edit-insight-dev-fp8.safetensors"

HF_TOKEN = os.environ.get("HF_TOKEN")

print("Downloading checkpoint weights...")
ckpt_path = hf_hub_download(
    repo_id=FINE_TUNED_MODEL,
    filename=WEIGHT_NAME,
    token=HF_TOKEN,
)

print("Configuring transformer model...")
transformer_config = dict(
    LTXVideoTransformer3DModel.load_config(
        BASE_MODEL,
        subfolder="transformer",
        token=HF_TOKEN,
    )
)
# Adjust dimensions for LTX 2.3 / IC-Edit architecture
transformer_config["attention_head_dim"] = 128
transformer_config["caption_channels"] = 4096

# Instantiate model architecture on CPU
transformer = LTXVideoTransformer3DModel.from_config(transformer_config)

print("Loading state dict with shape-mismatch handling...")
state_dict = load_file(ckpt_path)

cleaned_state_dict = {}
for k, v in state_dict.items():
    new_key = k.replace("model.diffusion_model.", "").replace("diffusion_model.", "")
    cleaned_state_dict[new_key] = v

model_state_dict = transformer.state_dict()
loaded_state_dict = {}

for name, param in model_state_dict.items():
    if name in cleaned_state_dict:
        ckpt_param = cleaned_state_dict[name]
        if ckpt_param.shape == param.shape:
            loaded_state_dict[name] = ckpt_param
        else:
            # Handle shape mismatch gracefully (e.g. scale_shift_table or dimensions)
            min_dim0 = min(ckpt_param.shape[0], param.shape[0])
            if len(param.shape) == 2:
                min_dim1 = min(ckpt_param.shape[1], param.shape[1])
                new_tensor = param.clone()
                new_tensor[:min_dim0, :min_dim1] = ckpt_param[:min_dim0, :min_dim1]
                loaded_state_dict[name] = new_tensor
            else:
                new_tensor = param.clone()
                new_tensor[:min_dim0] = ckpt_param[:min_dim0]
                loaded_state_dict[name] = new_tensor
    else:
        # Keep default model parameter if not in checkpoint
        loaded_state_dict[name] = param

transformer.load_state_dict(loaded_state_dict, strict=False)
print("Transformer weights loaded successfully.")

transformer = transformer.to(dtype=torch.bfloat16)

print("Loading LTXPipeline...")
pipe = LTXPipeline.from_pretrained(
    BASE_MODEL,
    transformer=transformer,
    torch_dtype=torch.bfloat16,
    token=HF_TOKEN,
)

@spaces.GPU(duration=120)
def process_video(prompt, input_video_path, inference_steps, guidance_scale):
    if not input_video_path:
        raise gr.Error("Please upload an input video.")

    pipe.to("cuda")

    kwargs = {
        "prompt": prompt,
        "video": input_video_path,
        "num_inference_steps": inference_steps,
        "guidance_scale": guidance_scale,
        "output_type": "np",
    }

    try:
        output = pipe(**kwargs)
    except Exception as e:
        raise gr.Error(f"Inference failed: {str(e)}")

    out_file = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False).name
    export_to_video(output.frames[0], out_file, fps=24)

    return out_file

with gr.Blocks(title="LTX2.3 ICEdit-Insight Video Restoration") as demo:
    gr.Markdown("# 🎥 LTX2.3 ICEdit-Insight Video Restoration")
    gr.Markdown("Upload an input video and provide an instruction prompt to restore or edit it.")
    
    with gr.Row():
        with gr.Column():
            input_vid = gr.Video(label="Input Video")
            prompt = gr.Textbox(
                label="Instruction Prompt",
                placeholder="e.g., Clean up AI inpainting glitches, remove artifacts...",
            )
            steps = gr.Slider(minimum=1, maximum=50, value=30, step=1, label="Inference Steps")
            cfg = gr.Slider(minimum=1.0, maximum=15.0, value=4.0, step=0.1, label="Guidance Scale")
            run_btn = gr.Button("Generate Fix", variant="primary")

        with gr.Column():
            output_vid = gr.Video(label="Restored Output Video")

    run_btn.click(
        fn=process_video,
        inputs=[prompt, input_vid, steps, cfg],
        outputs=output_vid,
    )

if __name__ == "__main__":
    demo.launch()