Lemonator commited on
Commit
1f619e0
Β·
verified Β·
1 Parent(s): 314e10e

Update app_lora.py

Browse files
Files changed (1) hide show
  1. app_lora.py +49 -37
app_lora.py CHANGED
@@ -20,32 +20,46 @@ MODEL_ID = "Wan-AI/Wan2.1-I2V-14B-480P-Diffusers"
20
  LORA_REPO_ID = "vrgamedevgirl84/Wan14BT2VFusioniX"
21
  LORA_FILENAME = "FusionX_LoRa/Wan2.1_I2V_14B_FusionX_LoRA.safetensors"
22
 
23
- # --- Model Initialization ---
24
  pipe = None
25
- # This check correctly identifies if the Hugging Face Space has a GPU.
26
- if torch.cuda.is_available():
27
- image_encoder = CLIPVisionModel.from_pretrained(MODEL_ID, subfolder="image_encoder", torch_dtype=torch.float16)
28
- vae = AutoencoderKLWan.from_pretrained(MODEL_ID, subfolder="vae", torch_dtype=torch.float16)
29
- pipe = WanImageToVideoPipeline.from_pretrained(
30
- MODEL_ID, vae=vae, image_encoder=image_encoder, torch_dtype=torch.float16
31
- )
32
- pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config, flow_shift=8.0)
33
- pipe.enable_model_cpu_offload()
34
 
35
- try:
36
- causvid_path = hf_hub_download(repo_id=LORA_REPO_ID, filename=LORA_FILENAME)
37
- print("βœ… LoRA downloaded to:", causvid_path)
38
- pipe.load_lora_weights(causvid_path, adapter_name="causvid_lora")
39
- pipe.set_adapters(["causvid_lora"], adapter_weights=[0.75])
40
- pipe.fuse_lora()
41
- except Exception as e:
42
- import traceback
43
- print("❌ Error during LoRA loading:")
44
- traceback.print_exc()
45
- else:
46
- print("CUDA is not available. This script requires a GPU. Please upgrade your Space hardware.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
  # --- Constants and Helper Functions ---
 
49
  MOD_VALUE = 32
50
  DEFAULT_H_SLIDER_VALUE, DEFAULT_W_SLIDER_VALUE = 640, 1024
51
  NEW_FORMULA_MAX_AREA = 640.0 * 1024.0
@@ -99,8 +113,11 @@ def generate_video(input_image, prompt, height, width,
99
  negative_prompt, duration_seconds,
100
  guidance_scale, steps, seed, randomize_seed,
101
  progress=gr.Progress(track_tqdm=True)):
102
- if pipe is None:
103
- raise gr.Error("Pipeline not initialized. Check logs for GPU availability.")
 
 
 
104
  if input_image is None:
105
  raise gr.Error("Please upload an input image.")
106
 
@@ -118,9 +135,9 @@ def generate_video(input_image, prompt, height, width,
118
 
119
  current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
120
  resized_image = input_image.resize((target_w, target_h), Image.Resampling.LANCZOS)
121
- torch.cuda.empty_cache()
122
-
123
  try:
 
124
  with torch.inference_mode(), torch.autocast("cuda", dtype=torch.float16):
125
  output_frames_list = pipe(
126
  image=resized_image, prompt=prompt, negative_prompt=negative_prompt,
@@ -136,14 +153,13 @@ def generate_video(input_image, prompt, height, width,
136
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmpfile:
137
  video_path = tmpfile.name
138
  export_video_with_ffmpeg(output_frames_list, video_path, fps=FIXED_FPS)
139
- # Optional: FFmpeg optimization
140
- # ...
141
  return video_path, current_seed
142
 
143
  # --- Gradio UI ---
144
  with gr.Blocks() as demo:
145
- gr.Markdown("# Wan 2.1 I2V FusionX-LoRA")
146
- gr.Markdown("GPU is required. If this doesn't load, check your Space hardware settings.")
147
 
148
  with gr.Row():
149
  with gr.Column():
@@ -159,7 +175,7 @@ with gr.Blocks() as demo:
159
  width_input = gr.Slider(minimum=SLIDER_MIN_W, maximum=SLIDER_MAX_W, step=MOD_VALUE, value=DEFAULT_W_SLIDER_VALUE, label="Width")
160
  steps_slider = gr.Slider(minimum=1, maximum=30, step=1, value=4, label="Inference Steps")
161
  guidance_scale_input = gr.Slider(minimum=0.0, maximum=20.0, step=0.5, value=1.0, label="Guidance Scale", visible=False)
162
- generate_button = gr.Button("Generate Video", variant="primary", interactive=(pipe is not None))
163
  with gr.Column():
164
  video_output = gr.Video(label="Generated Video", autoplay=True, interactive=False)
165
  gr.Markdown("### Tips:\n- Longer videos need more memory.\n- 4-8 steps is optimal.")
@@ -170,9 +186,5 @@ with gr.Blocks() as demo:
170
  generate_button.click(fn=generate_video, inputs=ui_inputs, outputs=[video_output, seed_input])
171
 
172
  if __name__ == "__main__":
173
- if pipe is not None:
174
- demo.queue(max_size=3).launch()
175
- else:
176
- # This provides a clean message in the UI if the app can't start.
177
- gr.Markdown("# Application Start Failed").launch()
178
- gr.Info("A GPU is required to run this application. Please ensure your Hugging Face Space is configured with GPU hardware.")
 
20
  LORA_REPO_ID = "vrgamedevgirl84/Wan14BT2VFusioniX"
21
  LORA_FILENAME = "FusionX_LoRa/Wan2.1_I2V_14B_FusionX_LoRA.safetensors"
22
 
23
+ # Global variable to hold the pipeline. It's initialized to None.
24
  pipe = None
 
 
 
 
 
 
 
 
 
25
 
26
+ def initialize_pipeline():
27
+ """
28
+ Initializes the model pipeline on the first request.
29
+ This function is designed for serverless GPU environments like ZeroGPU.
30
+ """
31
+ global pipe
32
+ # The 'pipe' global variable acts as a flag. If it's not None, we've already initialized.
33
+ if pipe is None:
34
+ print("First time setup: Initializing model pipeline...")
35
+ gr.Info("Cold start: The first generation will take longer as the model is loaded.")
36
+
37
+ if not torch.cuda.is_available():
38
+ raise gr.Error("GPU not available. This application requires a GPU to run.")
39
+
40
+ image_encoder = CLIPVisionModel.from_pretrained(MODEL_ID, subfolder="image_encoder", torch_dtype=torch.float16)
41
+ vae = AutoencoderKLWan.from_pretrained(MODEL_ID, subfolder="vae", torch_dtype=torch.float16)
42
+
43
+ # All model loading happens here, when a GPU is guaranteed to be active.
44
+ pipe = WanImageToVideoPipeline.from_pretrained(
45
+ MODEL_ID, vae=vae, image_encoder=image_encoder, torch_dtype=torch.float16
46
+ )
47
+ pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config, flow_shift=8.0)
48
+ pipe.enable_model_cpu_offload()
49
+
50
+ try:
51
+ causvid_path = hf_hub_download(repo_id=LORA_REPO_ID, filename=LORA_FILENAME)
52
+ print("βœ… LoRA downloaded to:", causvid_path)
53
+ pipe.load_lora_weights(causvid_path, adapter_name="causvid_lora")
54
+ pipe.set_adapters(["causvid_lora"], adapter_weights=[0.75])
55
+ pipe.fuse_lora()
56
+ except Exception as e:
57
+ raise gr.Error(f"Error loading LoRA: {e}")
58
+
59
+ print("βœ… Pipeline initialized successfully.")
60
 
61
  # --- Constants and Helper Functions ---
62
+ # (These are unchanged)
63
  MOD_VALUE = 32
64
  DEFAULT_H_SLIDER_VALUE, DEFAULT_W_SLIDER_VALUE = 640, 1024
65
  NEW_FORMULA_MAX_AREA = 640.0 * 1024.0
 
113
  negative_prompt, duration_seconds,
114
  guidance_scale, steps, seed, randomize_seed,
115
  progress=gr.Progress(track_tqdm=True)):
116
+
117
+ # --- LAZY LOADING TRIGGER ---
118
+ # This will load the model on the first run, and do nothing on subsequent runs.
119
+ initialize_pipeline()
120
+
121
  if input_image is None:
122
  raise gr.Error("Please upload an input image.")
123
 
 
135
 
136
  current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
137
  resized_image = input_image.resize((target_w, target_h), Image.Resampling.LANCZOS)
138
+
 
139
  try:
140
+ torch.cuda.empty_cache()
141
  with torch.inference_mode(), torch.autocast("cuda", dtype=torch.float16):
142
  output_frames_list = pipe(
143
  image=resized_image, prompt=prompt, negative_prompt=negative_prompt,
 
153
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmpfile:
154
  video_path = tmpfile.name
155
  export_video_with_ffmpeg(output_frames_list, video_path, fps=FIXED_FPS)
156
+
 
157
  return video_path, current_seed
158
 
159
  # --- Gradio UI ---
160
  with gr.Blocks() as demo:
161
+ gr.Markdown("# Wan 2.1 I2V FusionX-LoRA (ZeroGPU Ready)")
162
+ gr.Markdown("The first generation will be slow due to a 'cold start'. Subsequent generations will be much faster.")
163
 
164
  with gr.Row():
165
  with gr.Column():
 
175
  width_input = gr.Slider(minimum=SLIDER_MIN_W, maximum=SLIDER_MAX_W, step=MOD_VALUE, value=DEFAULT_W_SLIDER_VALUE, label="Width")
176
  steps_slider = gr.Slider(minimum=1, maximum=30, step=1, value=4, label="Inference Steps")
177
  guidance_scale_input = gr.Slider(minimum=0.0, maximum=20.0, step=0.5, value=1.0, label="Guidance Scale", visible=False)
178
+ generate_button = gr.Button("Generate Video", variant="primary")
179
  with gr.Column():
180
  video_output = gr.Video(label="Generated Video", autoplay=True, interactive=False)
181
  gr.Markdown("### Tips:\n- Longer videos need more memory.\n- 4-8 steps is optimal.")
 
186
  generate_button.click(fn=generate_video, inputs=ui_inputs, outputs=[video_output, seed_input])
187
 
188
  if __name__ == "__main__":
189
+ # We launch the demo unconditionally now. The GPU check is deferred until the first click.
190
+ demo.queue(max_size=3).launch()