tsqn commited on
Commit
1fd2df8
·
verified ·
1 Parent(s): fcdda4f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -234
app.py CHANGED
@@ -1,266 +1,216 @@
1
  import spaces
2
-
3
- """
4
- Copyright NewGenAI
5
- Code can't be included in commercial app used for monetary gain. No derivative code allowed.
6
- """
7
  import gc
8
- import json
9
- import torch
10
- import tqdm
11
  import gradio as gr
 
12
  import random
13
- import time
14
- from datetime import datetime
15
  import os
16
 
 
17
  from diffusers.utils import export_to_video
18
- from diffusers import LTXPipeline
19
  from transformers import T5EncoderModel, T5Tokenizer
20
- from pathlib import Path
21
- from datetime import datetime
22
- from huggingface_hub import hf_hub_download
23
-
24
- STATE_FILE = "LTX091_state.json"
25
- queue = []
26
-
27
-
28
- def load_state():
29
- if os.path.exists(STATE_FILE):
30
- with open(STATE_FILE, "r") as file:
31
- return json.load(file)
32
- return {}
33
-
34
- # Function to save the current state
35
- def save_state(state):
36
- with open(STATE_FILE, "w") as file:
37
- json.dump(state, file)
38
-
39
- # Load initial state
40
- initial_state = load_state()
41
-
42
- def add_to_queue(prompt, negative_prompt, height, width, num_frames, num_inference_steps, fps, seed):
43
- task = {
44
- "prompt": prompt,
45
- "negative_prompt": negative_prompt,
46
- "height": height,
47
- "width": width,
48
- "num_frames": num_frames,
49
- "num_inference_steps": num_inference_steps,
50
- "fps": fps,
51
- "seed": seed,
52
- }
53
- queue.append(task)
54
- return f"Task added to queue. Current queue length: {len(queue)}"
55
-
56
- def clear_queue():
57
- queue.clear()
58
- return "Queue cleared."
59
-
60
- def process_queue():
61
- if not queue:
62
- return "Queue is empty."
63
-
64
- for i, task in tqdm(enumerate(queue)):
65
- generate_video(**task)
66
- time.sleep(1) # Simulate processing time
67
-
68
- queue.clear()
69
- tqdm.close()
70
- return "All tasks in the queue have been processed."
71
-
72
- def save_ui_state(prompt, negative_prompt, height, width, num_frames, num_inference_steps, fps, seed):
73
- state = {
74
- "prompt": prompt,
75
- "negative_prompt": negative_prompt,
76
- "height": height,
77
- "width": width,
78
- "num_frames": num_frames,
79
- "num_inference_steps": num_inference_steps,
80
- "fps": fps,
81
- "seed": seed,
82
- }
83
- save_state(state)
84
- return "State saved!"
85
-
86
- repo_id = "a-r-r-o-w/LTX-Video-0.9.1-diffusers"
87
- base_path = repo_id
88
- files_to_download = [
89
- "model_index.json",
90
- "scheduler/scheduler_config.json",
91
- "text_encoder/config.json",
92
- "text_encoder/model-00001-of-00004.safetensors",
93
- "text_encoder/model-00002-of-00004.safetensors",
94
- "text_encoder/model-00003-of-00004.safetensors",
95
- "text_encoder/model-00004-of-00004.safetensors",
96
- "text_encoder/model.safetensors.index.json",
97
- "tokenizer/added_tokens.json",
98
- "tokenizer/special_tokens_map.json",
99
- "tokenizer/spiece.model",
100
- "tokenizer/tokenizer_config.json",
101
- "transformer/config.json",
102
- "transformer/diffusion_pytorch_model.safetensors",
103
- "vae/config.json",
104
- "vae/diffusion_pytorch_model.safetensors",
105
- ]
106
- os.makedirs(base_path, exist_ok=True)
107
- for file_path in files_to_download:
108
- try:
109
- # Create the full directory path for this file
110
- full_dir = os.path.join(base_path, os.path.dirname(file_path))
111
- os.makedirs(full_dir, exist_ok=True)
112
-
113
- # Download the file
114
- downloaded_path = hf_hub_download(
115
- repo_id=repo_id,
116
- filename=file_path,
117
- local_dir=base_path,
118
- )
119
-
120
- print(f"Successfully downloaded: {file_path}")
121
-
122
- except Exception as e:
123
- print(f"Error downloading {file_path}: {str(e)}")
124
- raise
125
-
126
- # Download model from different repo
127
- try:
128
- # Create the full directory path for this file
129
- full_dir = os.path.join(base_path, os.path.dirname(file_path))
130
- os.makedirs(full_dir, exist_ok=True)
131
-
132
- # Download the file
133
- downloaded_path = hf_hub_download(
134
- repo_id="Lightricks/LTX-Video",
135
- filename="ltx-video-2b-v0.9.1.safetensors",
136
- local_dir=repo_id,
137
- )
138
- except Exception as e:
139
- print(f"Error downloading 0.9.1 model: {str(e)}")
140
- raise
141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
- single_file_url = repo_id+"/ltx-video-2b-v0.9.1.safetensors"
144
  text_encoder = T5EncoderModel.from_pretrained(
145
- repo_id, subfolder="text_encoder", torch_dtype=torch.bfloat16
 
 
146
  )
 
 
 
147
  tokenizer = T5Tokenizer.from_pretrained(
148
- repo_id, subfolder="tokenizer", torch_dtype=torch.bfloat16
 
149
  )
150
- pipe = LTXPipeline.from_single_file(
151
- single_file_url,
152
- text_encoder=text_encoder,
153
- tokenizer=tokenizer,
 
 
 
154
  torch_dtype=torch.bfloat16
155
  )
156
- pipe.vae.enable_tiling()
157
- pipe.to("cuda")
158
-
159
- # pipe.load_lora_weights("TODO/TODO", adapter_name="ltx-lora")
160
- # pipe.set_adapters(["lrx-lora"], adapter_weights=[1.0])
161
-
162
-
163
- @spaces.GPU(duration=120)
164
- @torch.inference_mode()
165
- def generate_video(prompt, negative_prompt, height, width, num_frames, num_inference_steps, fps, seed, progress=gr.Progress(track_tqdm=True)):
166
- INTERRUPT_PIPELINE = False
167
- progress_steps = []
168
-
169
- # Randomize seed if seed is 0
170
- if seed == 0:
171
- seed = randomize_seed()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
- torch.cuda.empty_cache()
174
- torch.cuda.synchronize()
175
- # Generating the video <Does not support seed :( >
176
- video = pipe(
177
- prompt=prompt,
178
- negative_prompt=negative_prompt,
179
- width=width,
180
- height=height,
181
- num_frames=num_frames,
182
- num_inference_steps=num_inference_steps,
183
- generator=torch.Generator(device='cuda').manual_seed(seed),
184
- ).frames[0]
185
-
186
- # Create output filename based on prompt and timestamp
187
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
188
- filename = f"{prompt[:10]}_{timestamp}.mp4"
189
-
190
- # Save the video to the output folder
191
- os.makedirs("output_LTX091", exist_ok=True)
192
- output_path = f"./output_LTX091/{filename}"
193
  export_to_video(video, output_path, fps=fps)
194
 
 
195
  torch.cuda.empty_cache()
196
- gc.collect()
197
  return output_path
198
 
199
- # Gradio UI setup
200
- def randomize_seed():
201
- return random.randint(0, 999999)
202
 
203
- with gr.Blocks() as demo:
204
- with gr.Tabs():
205
- with gr.Tab("Generate Video"):
206
- with gr.Row():
207
- prompt = gr.Textbox(label="Prompt", lines=3, value=initial_state.get("prompt", "A dramatic view of the pyramids at Giza during sunset."))
208
- negative_prompt = gr.Textbox(label="Negative Prompt", lines=3, value=initial_state.get("negative_prompt", "worst quality, blurry, distorted"))
209
- with gr.Row():
210
- height = gr.Slider(label="Height", minimum=224, maximum=768, step=32, value=initial_state.get("height", 384))
211
- width = gr.Slider(label="Width", minimum=320, maximum=1280, step=32, value=initial_state.get("width", 640))
212
- with gr.Row():
213
- num_frames = gr.Slider(label="Number of Frames", minimum=1, maximum=121, step=1, value=initial_state.get("num_frames", 49))
214
- num_inference_steps = gr.Slider(label="Number of Inference Steps", minimum=1, maximum=30, step=1, value=initial_state.get("num_inference_steps", 20))
215
- with gr.Row():
216
- fps = gr.Slider(label="FPS", minimum=1, maximum=30, step=1, value=initial_state.get("fps", 16))
217
- seed = gr.Number(label="Seed", value=initial_state.get("seed", 0))
218
- random_seed_button = gr.Button("Randomize Seed")
219
-
220
- output_video = gr.Video(label="Generated Video", show_label=True)
221
- generate_button = gr.Button("Generate Video")
222
- save_state_button = gr.Button("Save State")
223
-
224
- random_seed_button.click(randomize_seed, outputs=seed)
225
- generate_button.click(
226
- generate_video,
227
- inputs=[prompt, negative_prompt, height, width, num_frames, num_inference_steps, fps, seed],
228
- outputs=output_video
229
  )
230
- save_state_button.click(
231
- save_ui_state,
232
- inputs=[prompt, negative_prompt, height, width, num_frames, num_inference_steps, fps, seed],
233
- outputs=gr.Text(label="State Status")
 
234
  )
235
 
236
- with gr.Tab("Batch Processing"):
237
- with gr.Row():
238
- batch_prompt = gr.Textbox(label="Prompt", lines=3, value="A batch of videos depicting different landscapes.")
239
- batch_negative_prompt = gr.Textbox(label="Negative Prompt", lines=3, value="low quality, inconsistent, jittery")
240
- with gr.Row():
241
- batch_height = gr.Slider(label="Height", minimum=224, maximum=768, step=32, value=384)
242
- batch_width = gr.Slider(label="Width", minimum=320, maximum=1280, step=32, value=640)
243
- with gr.Row():
244
- batch_num_frames = gr.Slider(label="Number of Frames", minimum=1, maximum=121, step=1, value=49)
245
- batch_num_inference_steps = gr.Slider(label="Number of Inference Steps", minimum=1, maximum=30, step=1, value=20)
 
 
 
 
 
 
 
246
  with gr.Row():
247
- batch_fps = gr.Slider(label="FPS", minimum=1, maximum=30, step=1, value=16)
248
- batch_seed = gr.Number(label="Seed", value=0)
249
- random_seed_batch_button = gr.Button("Randomize Seed")
 
 
 
 
 
 
 
 
 
 
 
 
250
 
251
- add_to_queue_button = gr.Button("Add to Queue")
252
- clear_queue_button = gr.Button("Clear Queue")
253
- process_queue_button = gr.Button("Process Queue")
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
- queue_status = gr.Text(label="Queue Status")
256
 
257
- random_seed_batch_button.click(randomize_seed, outputs=batch_seed)
258
- add_to_queue_button.click(
259
- add_to_queue,
260
- inputs=[batch_prompt, batch_negative_prompt, batch_height, batch_width, batch_num_frames, batch_num_inference_steps, batch_fps, batch_seed],
261
- outputs=queue_status
262
- )
263
- clear_queue_button.click(clear_queue, outputs=queue_status)
264
- process_queue_button.click(process_queue, outputs=queue_status)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
 
266
- demo.launch()
 
 
 
1
  import spaces
2
+ from datetime import datetime
 
 
 
 
3
  import gc
 
 
 
4
  import gradio as gr
5
+ import numpy as np
6
  import random
7
+ from pathlib import Path
 
8
  import os
9
 
10
+ from diffusers import AutoencoderKLLTXVideo, LTXPipeline, LTXVideoTransformer3DModel
11
  from diffusers.utils import export_to_video
 
12
  from transformers import T5EncoderModel, T5Tokenizer
13
+ import torch
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ from utils import install_packages
16
+
17
+ torch.backends.cuda.matmul.allow_tf32 = True
18
+ torch.backends.cudnn.allow_tf32 = True
19
+ torch.jit._state.disable()
20
+ torch.set_grad_enabled(False)
21
+
22
+ gc.collect()
23
+ torch.cuda.empty_cache()
24
+
25
+ ckpt_path = Path("a-r-r-o-w/LTX-Video-0.9.1-diffusers")
26
+ single_file_url = "https://huggingface.co/Lightricks/LTX-Video/ltx-video-2b-v0.9.1.safetensors"
27
+ transformer = LTXVideoTransformer3DModel.from_single_file(
28
+ single_file_url, torch_dtype=torch.bfloat16
29
+ )
30
+ vae = AutoencoderKLLTXVideo.from_single_file(
31
+ single_file_url, torch_dtype=torch.bfloat16)
32
+ vae.eval()
33
+ vae = vae.to("cuda")
34
 
 
35
  text_encoder = T5EncoderModel.from_pretrained(
36
+ ckpt_path,
37
+ subfolder="text_encoder",
38
+ torch_dtype=torch.bfloat16
39
  )
40
+ text_encoder.eval()
41
+ text_encoder = text_encoder.to("cuda")
42
+
43
  tokenizer = T5Tokenizer.from_pretrained(
44
+ ckpt_path,
45
+ subfolder="tokenizer"
46
  )
47
+
48
+ pipeline = LTXPipeline.from_single_file(
49
+ single_file_url,
50
+ transformer=transformer,
51
+ text_encoder=text_encoder,
52
+ tokenizer=tokenizer,
53
+ vae=vae,
54
  torch_dtype=torch.bfloat16
55
  )
56
+ # pipeline.enable_model_cpu_offload()
57
+
58
+ pipeline.vae.enable_tiling()
59
+ pipeline.vae.enable_slicing()
60
+
61
+ pipeline = pipeline.to("cuda")
62
+
63
+
64
+ MAX_SEED = np.iinfo(np.int32).max
65
+ MAX_IMAGE_SIZE = 1280
66
+
67
+
68
+ @spaces.GPU()
69
+ def infer(
70
+ prompt,
71
+ negative_prompt,
72
+ seed,
73
+ randomize_seed,
74
+ width=704,
75
+ height=448,
76
+ num_frames=129,
77
+ fps=24,
78
+ num_inference_steps=30,
79
+ progress=gr.Progress(track_tqdm=True),
80
+ ):
81
+ if randomize_seed:
82
+ seed = random.randint(0, MAX_SEED)
83
+
84
+ generator = torch.Generator(device='cuda').manual_seed(seed)
85
+
86
+ with torch.amp.autocast_mode.autocast('cuda', torch.bfloat16), torch.no_grad(), torch.inference_mode():
87
+ video = pipeline(
88
+ prompt=prompt,
89
+ negative_prompt=negative_prompt,
90
+ width=width,
91
+ height=height,
92
+ num_frames=num_frames,
93
+ # guidance_scale=guidance_scale,
94
+ num_inference_steps=num_inference_steps,
95
+ # decode_timestep=decode_timestep,
96
+ # decode_noise_scale=decode_noise_scale,
97
+ generator=generator,
98
+ # max_sequence_length=512,
99
+ ).frames[0]
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
102
+ filename = f"output_{timestamp}.mp4"
103
+ os.makedirs("output", exist_ok=True)
104
+ output_path = f"./output/{filename}"
 
 
105
  export_to_video(video, output_path, fps=fps)
106
 
107
+ gc.collect
108
  torch.cuda.empty_cache()
 
109
  return output_path
110
 
 
 
 
111
 
112
+ css = """
113
+ #col-container {
114
+ margin: 0 auto;
115
+ max-width: 640px;
116
+ }
117
+ """
118
+
119
+ with gr.Blocks(css=css) as demo:
120
+ with gr.Column(elem_id="col-container"):
121
+ gr.Markdown(" # Text-to-Image Gradio Template")
122
+
123
+ with gr.Row():
124
+ prompt = gr.Textbox(
125
+ label="Prompt",
126
+ lines=3,
127
+ value=str("A woman with long brown hair and light skin smiles at another woman with long blonde hair. The woman with brown hair wears a black jacket and has a small, barely noticeable mole on her right cheek. The camera angle is a close-up, focused on the woman with brown hair's face. The lighting is warm and natural, likely from the setting sun, casting a soft glow on the scene. The scene appears to be real-life footage"),
 
 
 
 
 
 
 
 
 
 
128
  )
129
+
130
+ negative_prompt = gr.Textbox(
131
+ label="Negative prompt",
132
+ lines=3,
133
+ value=str("worst quality, blurry, distorted"),
134
  )
135
 
136
+ with gr.Row():
137
+ run_button = gr.Button("Run", scale=0, variant="huggingface")
138
+
139
+ with gr.Row():
140
+ result = gr.Video(label="Result", show_label=False)
141
+
142
+ with gr.Accordion("Advanced Settings", open=False):
143
+ seed = gr.Slider(
144
+ label="Seed",
145
+ minimum=0,
146
+ maximum=MAX_SEED,
147
+ step=1,
148
+ value=0,
149
+ )
150
+
151
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
152
+
153
  with gr.Row():
154
+ width = gr.Slider(
155
+ label="Width",
156
+ minimum=256,
157
+ maximum=MAX_IMAGE_SIZE,
158
+ step=32,
159
+ value=704, # Replace with defaults that work for your model
160
+ )
161
+
162
+ height = gr.Slider(
163
+ label="Height",
164
+ minimum=256,
165
+ maximum=MAX_IMAGE_SIZE,
166
+ step=32,
167
+ value=448, # Replace with defaults that work for your model
168
+ )
169
 
170
+ with gr.Row():
171
+ num_frames = gr.Slider(
172
+ label="Number of frames",
173
+ minimum=1,
174
+ maximum=257,
175
+ step=32,
176
+ value=129, # Replace with defaults that work for your model
177
+ )
178
+
179
+ fps = gr.Slider(
180
+ label="Number of frames per second",
181
+ minimum=1,
182
+ maximum=30,
183
+ step=1,
184
+ value=24, # Replace with defaults that work for your model
185
+ )
186
 
187
+ with gr.Row():
188
 
189
+ num_inference_steps = gr.Slider(
190
+ label="Number of inference steps",
191
+ minimum=1,
192
+ maximum=50,
193
+ step=1,
194
+ value=30, # Replace with defaults that work for your model
195
+ )
196
+
197
+ gr.on(
198
+ triggers=[run_button.click, prompt.submit],
199
+ fn=infer,
200
+ inputs=[
201
+ prompt,
202
+ negative_prompt,
203
+ seed,
204
+ randomize_seed,
205
+ width,
206
+ height,
207
+ num_frames,
208
+ fps,
209
+ num_inference_steps,
210
+ ],
211
+ outputs=[result],
212
+ )
213
 
214
+ if __name__ == "__main__":
215
+ install_packages()
216
+ demo.launch()