nalin0503 commited on
Commit
c1814c9
·
1 Parent(s): fc27eef

Update app.py robust

Browse files
Files changed (1) hide show
  1. app.py +217 -121
app.py CHANGED
@@ -46,6 +46,27 @@ def create_temp_folder():
46
  return run_folder
47
 
48
  def main():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  # ---------------- CUSTOM CSS FOR A PROFESSIONAL, DARK THEME ----------------
50
  st.markdown(
51
  """
@@ -118,6 +139,13 @@ def main():
118
  transform: scale(1.02);
119
  box-shadow: 0 0 20px rgba(142,68,173,0.8), 0 0 30px rgba(114,45,145,0.6);
120
  }
 
 
 
 
 
 
 
121
  /* File uploader label styling */
122
  .stFileUploader label {
123
  font-size: 1rem;
@@ -129,6 +157,22 @@ def main():
129
  padding-left: 1rem;
130
  margin-left: 1rem;
131
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  </style>
133
  """,
134
  unsafe_allow_html=True
@@ -171,23 +215,61 @@ def main():
171
  unsafe_allow_html=True
172
  )
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  # ---------------- SECTION 1: IMAGE & PROMPT INPUTS ----------------
175
  st.subheader("1. Upload Source Images & Prompts")
176
  col_imgA, col_imgB = st.columns(2)
177
  with col_imgA:
178
  st.markdown("#### Image A")
179
- uploaded_image_A = st.file_uploader("Upload your first image", type=["png", "jpg", "jpeg"], key="imgA")
 
180
  if uploaded_image_A is not None:
181
  st.image(uploaded_image_A, caption="Preview - Image A", use_container_width=True)
182
  prompt_A = st.text_input("Short Description for Image A (optional)", value="", key="promptA",
183
- help="For added interpolation between the two descriptions")
 
184
  with col_imgB:
185
  st.markdown("#### Image B")
186
- uploaded_image_B = st.file_uploader("Upload your second image", type=["png", "jpg", "jpeg"], key="imgB")
 
187
  if uploaded_image_B is not None:
188
  st.image(uploaded_image_B, caption="Preview - Image B", use_container_width=True)
189
  prompt_B = st.text_input("Short Description for Image B (optional)", value="", key="promptB",
190
- help="For added interpolation between the two descriptions")
 
191
 
192
  st.markdown("<hr>", unsafe_allow_html=True)
193
 
@@ -215,7 +297,8 @@ def main():
215
  "Custom ⚙️"
216
  ],
217
  index=0,
218
- label_visibility="collapsed" # Hide the label in the UI but keep it for accessibility
 
219
  )
220
 
221
  # Determine preset defaults based on selection
@@ -252,34 +335,37 @@ def main():
252
  ]
253
  default_model = preset_model if preset_model is not None else "Base Stable Diffusion V1-5"
254
  default_index = options_list.index(default_model)
255
- model_option = st.selectbox("Select Model Card", options=options_list, index=default_index)
256
 
257
  col_left, col_right = st.columns(2)
258
  # Left Column: Keyframe Generator Parameters
259
  with col_left:
260
  st.markdown("##### Keyframe Generator Parameters")
261
- num_frames = st.number_input("Number of keyframes (2–50)", min_value=2, max_value=50, value=16)
262
  lcm_default = preset_lcm if preset_lcm is not None else False
263
  enable_lcm_lora = st.checkbox(
264
  "Enable LCM-LoRA",
265
  value=lcm_default,
266
- help="Accelerates inference with slight quality decrease"
 
267
  )
268
- use_adain = st.checkbox("Use AdaIN", value=True, help="Adaptive Instance Normalization for improved generation")
269
- use_reschedule = st.checkbox("Use reschedule sampling", value=True, help="Better sampling strategy")
270
 
271
  # Right Column: Inter-frame Interpolator Parameters (FILM)
272
  with col_right:
273
  st.markdown("<div class='right-column-divider'>", unsafe_allow_html=True)
274
  st.markdown("##### Inter-frame Interpolator Parameters")
275
  default_use_film = preset_film if preset_film is not None else True
276
- use_film = st.checkbox("Use FILM interpolation", value=default_use_film, help="Frame Interpolation for Large Motion - creates smooth transitions")
277
  film_recursions = st.number_input("FILM recursion passes (1–6)", min_value=1, max_value=6, value=3,
278
- help="Higher values create more intermediate frames (smoother but slower)")
 
279
  # Set default FPS based on whether FILM is enabled
280
  default_fps = 30 if use_film else 4
281
  output_fps = st.number_input("Output FPS (1–120)", min_value=1, max_value=120, value=default_fps,
282
- help="Output video frames per second")
 
283
  st.markdown("</div>", unsafe_allow_html=True)
284
 
285
  st.markdown("<hr>", unsafe_allow_html=True)
@@ -289,122 +375,132 @@ def main():
289
  st.markdown("Once satisfied with your inputs, click below to start the process.")
290
 
291
  # New checkbox for SLAB execution toggle
292
- # using_slab = st.checkbox("Using SLAB GPU Cluster?", value=False, help="If enabled, the pipeline command will be prefixed with SLAB cluster execution parameters.")
293
 
294
- if st.button("Run Morphing Pipeline", key="run_pipeline"):
295
- if not (uploaded_image_A and uploaded_image_B):
296
- st.error("Please upload both images before running the morphing pipeline.")
297
- return
298
-
299
- # Instead of using /tmp, create a folder in the repo for temporary processing.
300
- temp_dir = create_temp_folder()
301
 
302
- try:
303
- # Save uploaded images
304
- imgA_path = os.path.join(temp_dir, "imageA.png")
305
- imgB_path = os.path.join(temp_dir, "imageB.png")
306
- save_uploaded_file(uploaded_image_A, imgA_path)
307
- save_uploaded_file(uploaded_image_B, imgB_path)
308
-
309
- # Create output directories
310
- output_dir = os.path.join(temp_dir, "morph_results")
311
- film_output_dir = os.path.join(temp_dir, "film_output")
312
- os.makedirs(output_dir, exist_ok=True)
313
- os.makedirs(film_output_dir, exist_ok=True)
314
-
315
- actual_model_path = (
316
- "lykon/dreamshaper-7" if model_option == "Dreamshaper-7 (fine-tuned SD V1-5)"
317
- else "stabilityai/stable-diffusion-2-1-base" if model_option == "Base Stable Diffusion V2-1"
318
- else "sd-legacy/stable-diffusion-v1-5"
319
- )
320
-
321
- # Build the command for run_morphing.py
322
- cmd = [
323
- sys.executable, "run_morphing.py",
324
- "--model_path", actual_model_path,
325
- "--image_path_0", imgA_path,
326
- "--image_path_1", imgB_path,
327
- "--prompt_0", prompt_A,
328
- "--prompt_1", prompt_B,
329
- "--output_path", output_dir,
330
- "--film_output_folder", film_output_dir,
331
- "--num_frames", str(num_frames),
332
- "--fps", str(output_fps)
333
- ]
334
-
335
- if enable_lcm_lora:
336
- cmd.append("--use_lcm")
337
- if use_adain:
338
- cmd.append("--use_adain")
339
- if use_reschedule:
340
- cmd.append("--use_reschedule")
341
- if use_film:
342
- cmd.append("--use_film")
343
-
344
- # Add film recursion parameter
345
- cmd.extend(["--film_num_recursions", str(film_recursions)])
346
-
347
- # If SLAB execution is enabled, prepend the srun command prefix.
348
- # if using_slab:
349
- # slab_prefix = [
350
- # "srun", "-p", "rtx3090_slab", "-w", "slabgpu05", "--gres=gpu:1",
351
- # "--job-name=test", "--kill-on-bad-exit=1"
352
- # ]
353
- # cmd = slab_prefix + cmd
354
-
355
- st.info("Initializing pipeline. This may take a few minutes...")
356
- progress_bar = st.progress(0)
357
- status_text = st.empty()
358
-
359
- # Update progress status
360
- for i in range(1, 11):
361
- status_text.text(f"Step {i}/10: {'Preparing images' if i <= 2 else 'Generating keyframes' if i <= 6 else 'Interpolating frames' if i <= 9 else 'Finalizing video'}")
362
- progress_bar.progress(i * 10)
363
 
364
- if i == 3: # Start processing!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  try:
366
  subprocess.run(cmd, check=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  except subprocess.CalledProcessError as e:
368
  st.error(f"Error running morphing pipeline: {e}")
369
- return
370
- break
371
-
372
- # Set to 100% when done
373
- progress_bar.progress(100)
374
- status_text.text("Processing complete!")
375
-
376
- # Check for output video
377
- video_found = False
378
- possible_outputs = [f for f in os.listdir(film_output_dir) if f.endswith(".mp4")]
379
- if possible_outputs:
380
- final_video_path = os.path.join(film_output_dir, possible_outputs[0])
381
- video_found = True
382
-
383
- if not video_found:
384
- possible_outputs = [f for f in os.listdir(output_dir) if f.endswith(".mp4")]
385
- if possible_outputs:
386
- final_video_path = os.path.join(output_dir, possible_outputs[0])
387
- video_found = True
388
-
389
- if video_found:
390
- st.success("Morphing complete! 🎉")
391
- # st.video(final_video_path) # Comment to remove video preview, buggy
392
- try:
393
- with open(final_video_path, "rb") as f:
394
- video_bytes = f.read()
395
- st.download_button(
396
- "Download Result Video",
397
- data=video_bytes,
398
- file_name="metamorph_result.mp4",
399
- mime="video/mp4"
400
- )
401
- except Exception as e:
402
- st.error(f"Error preparing video for download: {e}")
403
- else:
404
- st.warning("No output video was generated. Check logs for details.")
405
 
406
- except Exception as e:
407
- st.error(f"An error occurred during processing: {e}")
 
 
408
 
409
  if __name__ == "__main__":
410
  main()
 
46
  return run_folder
47
 
48
  def main():
49
+ # Initialize session state for tracking processing status
50
+ if 'processing' not in st.session_state:
51
+ st.session_state.processing = False
52
+
53
+ if 'process_complete' not in st.session_state:
54
+ st.session_state.process_complete = False
55
+
56
+ if 'temp_dir' not in st.session_state:
57
+ st.session_state.temp_dir = None
58
+
59
+ if 'final_video_path' not in st.session_state:
60
+ st.session_state.final_video_path = None
61
+
62
+ # Restart function to reset session state
63
+ def restart():
64
+ st.session_state.processing = False
65
+ st.session_state.process_complete = False
66
+ st.session_state.temp_dir = None
67
+ st.session_state.final_video_path = None
68
+ st.rerun() # Use st.rerun() instead of experimental_rerun
69
+
70
  # ---------------- CUSTOM CSS FOR A PROFESSIONAL, DARK THEME ----------------
71
  st.markdown(
72
  """
 
139
  transform: scale(1.02);
140
  box-shadow: 0 0 20px rgba(142,68,173,0.8), 0 0 30px rgba(114,45,145,0.6);
141
  }
142
+ /* Disabled button styling */
143
+ div.stButton > button:disabled {
144
+ background-image: linear-gradient(45deg, #6b6b6b, #4a4a4a);
145
+ box-shadow: none;
146
+ cursor: not-allowed;
147
+ opacity: 0.7;
148
+ }
149
  /* File uploader label styling */
150
  .stFileUploader label {
151
  font-size: 1rem;
 
157
  padding-left: 1rem;
158
  margin-left: 1rem;
159
  }
160
+ /* Processing overlay */
161
+ .processing-overlay {
162
+ position: fixed;
163
+ top: 0;
164
+ left: 0;
165
+ right: 0;
166
+ bottom: 0;
167
+ background-color: rgba(0, 0, 0, 0.7);
168
+ z-index: 1000;
169
+ display: flex;
170
+ flex-direction: column;
171
+ justify-content: center;
172
+ align-items: center;
173
+ color: white;
174
+ font-size: 1.5rem;
175
+ }
176
  </style>
177
  """,
178
  unsafe_allow_html=True
 
215
  unsafe_allow_html=True
216
  )
217
 
218
+ # Show results if processing is complete
219
+ if st.session_state.process_complete and st.session_state.final_video_path is not None:
220
+ st.success("Morphing complete! 🎉")
221
+ # st.video(st.session_state.final_video_path)
222
+ try:
223
+ with open(st.session_state.final_video_path, "rb") as f:
224
+ video_bytes = f.read()
225
+ st.download_button(
226
+ "Download Result Video",
227
+ data=video_bytes,
228
+ file_name="metamorph_result.mp4",
229
+ mime="video/mp4"
230
+ )
231
+
232
+ # Add a restart button to clear the session state and start over
233
+ if st.button("Start New Morphing Project", key="restart"):
234
+ restart() # Use the restart function
235
+
236
+ except Exception as e:
237
+ st.error(f"Error preparing video for download: {e}")
238
+
239
+ # Early return to not show the input forms again when we have a result
240
+ return
241
+
242
+ # Show processing indicator if currently processing
243
+ if st.session_state.processing:
244
+ progress_container = st.container()
245
+ with progress_container:
246
+ st.info("Processing your morphing request. Please wait...")
247
+ progress_bar = st.progress(0)
248
+ status_text = st.empty()
249
+ status_text.text("Initializing pipeline. Please do not close this page.")
250
+ st.warning("⚠️ Please wait for the current process to complete. Do not press the run button again.")
251
+
252
  # ---------------- SECTION 1: IMAGE & PROMPT INPUTS ----------------
253
  st.subheader("1. Upload Source Images & Prompts")
254
  col_imgA, col_imgB = st.columns(2)
255
  with col_imgA:
256
  st.markdown("#### Image A")
257
+ uploaded_image_A = st.file_uploader("Upload your first image", type=["png", "jpg", "jpeg"], key="imgA",
258
+ disabled=st.session_state.processing)
259
  if uploaded_image_A is not None:
260
  st.image(uploaded_image_A, caption="Preview - Image A", use_container_width=True)
261
  prompt_A = st.text_input("Short Description for Image A (optional)", value="", key="promptA",
262
+ help="For added interpolation between the two descriptions",
263
+ disabled=st.session_state.processing)
264
  with col_imgB:
265
  st.markdown("#### Image B")
266
+ uploaded_image_B = st.file_uploader("Upload your second image", type=["png", "jpg", "jpeg"], key="imgB",
267
+ disabled=st.session_state.processing)
268
  if uploaded_image_B is not None:
269
  st.image(uploaded_image_B, caption="Preview - Image B", use_container_width=True)
270
  prompt_B = st.text_input("Short Description for Image B (optional)", value="", key="promptB",
271
+ help="For added interpolation between the two descriptions",
272
+ disabled=st.session_state.processing)
273
 
274
  st.markdown("<hr>", unsafe_allow_html=True)
275
 
 
297
  "Custom ⚙️"
298
  ],
299
  index=0,
300
+ label_visibility="collapsed",
301
+ disabled=st.session_state.processing
302
  )
303
 
304
  # Determine preset defaults based on selection
 
335
  ]
336
  default_model = preset_model if preset_model is not None else "Base Stable Diffusion V1-5"
337
  default_index = options_list.index(default_model)
338
+ model_option = st.selectbox("Select Model Card", options=options_list, index=default_index, disabled=st.session_state.processing)
339
 
340
  col_left, col_right = st.columns(2)
341
  # Left Column: Keyframe Generator Parameters
342
  with col_left:
343
  st.markdown("##### Keyframe Generator Parameters")
344
+ num_frames = st.number_input("Number of keyframes (2–50)", min_value=2, max_value=50, value=16, disabled=st.session_state.processing)
345
  lcm_default = preset_lcm if preset_lcm is not None else False
346
  enable_lcm_lora = st.checkbox(
347
  "Enable LCM-LoRA",
348
  value=lcm_default,
349
+ help="Accelerates inference with slight quality decrease",
350
+ disabled=st.session_state.processing
351
  )
352
+ use_adain = st.checkbox("Use AdaIN", value=True, help="Adaptive Instance Normalization for improved generation", disabled=st.session_state.processing)
353
+ use_reschedule = st.checkbox("Use reschedule sampling", value=True, help="Better sampling strategy", disabled=st.session_state.processing)
354
 
355
  # Right Column: Inter-frame Interpolator Parameters (FILM)
356
  with col_right:
357
  st.markdown("<div class='right-column-divider'>", unsafe_allow_html=True)
358
  st.markdown("##### Inter-frame Interpolator Parameters")
359
  default_use_film = preset_film if preset_film is not None else True
360
+ use_film = st.checkbox("Use FILM interpolation", value=default_use_film, help="Frame Interpolation for Large Motion - creates smooth transitions", disabled=st.session_state.processing)
361
  film_recursions = st.number_input("FILM recursion passes (1–6)", min_value=1, max_value=6, value=3,
362
+ help="Higher values create more intermediate frames (smoother but slower)",
363
+ disabled=st.session_state.processing)
364
  # Set default FPS based on whether FILM is enabled
365
  default_fps = 30 if use_film else 4
366
  output_fps = st.number_input("Output FPS (1–120)", min_value=1, max_value=120, value=default_fps,
367
+ help="Output video frames per second",
368
+ disabled=st.session_state.processing)
369
  st.markdown("</div>", unsafe_allow_html=True)
370
 
371
  st.markdown("<hr>", unsafe_allow_html=True)
 
375
  st.markdown("Once satisfied with your inputs, click below to start the process.")
376
 
377
  # New checkbox for SLAB execution toggle
378
+ # using_slab = st.checkbox("Using SLAB GPU Cluster?", value=False, help="If enabled, the pipeline command will be prefixed with SLAB cluster execution parameters.", disabled=st.session_state.processing)
379
 
380
+ # Create a container for the run button and its status messages
381
+ run_container = st.container()
382
+
383
+ with run_container:
384
+ # Button text changes based on processing state
385
+ button_text = "Processing... Please Wait" if st.session_state.processing else "Run Morphing Pipeline"
 
386
 
387
+ # Button is disabled during processing
388
+ if st.button(button_text, key="run_pipeline", disabled=st.session_state.processing):
389
+ if not (uploaded_image_A and uploaded_image_B):
390
+ st.error("Please upload both images before running the morphing pipeline.")
391
+ else:
392
+ # Set the processing state to True to prevent multiple runs
393
+ st.session_state.processing = True
394
+
395
+ # Create progress indicators
396
+ progress_bar = st.progress(0)
397
+ status_text = st.empty()
398
+ status_text.text("Initializing pipeline. This may take a few minutes...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
 
400
+ # Instead of using /tmp, create a folder in the repo for temporary processing.
401
+ temp_dir = create_temp_folder()
402
+ st.session_state.temp_dir = temp_dir
403
+
404
+ try:
405
+ # Save uploaded images
406
+ imgA_path = os.path.join(temp_dir, "imageA.png")
407
+ imgB_path = os.path.join(temp_dir, "imageB.png")
408
+ save_uploaded_file(uploaded_image_A, imgA_path)
409
+ save_uploaded_file(uploaded_image_B, imgB_path)
410
+
411
+ # Create output directories
412
+ output_dir = os.path.join(temp_dir, "morph_results")
413
+ film_output_dir = os.path.join(temp_dir, "film_output")
414
+ os.makedirs(output_dir, exist_ok=True)
415
+ os.makedirs(film_output_dir, exist_ok=True)
416
+
417
+ actual_model_path = (
418
+ "lykon/dreamshaper-7" if model_option == "Dreamshaper-7 (fine-tuned SD V1-5)"
419
+ else "stabilityai/stable-diffusion-2-1-base" if model_option == "Base Stable Diffusion V2-1"
420
+ else "sd-legacy/stable-diffusion-v1-5"
421
+ )
422
+
423
+ # Build the command for run_morphing.py
424
+ cmd = [
425
+ sys.executable, "run_morphing.py",
426
+ "--model_path", actual_model_path,
427
+ "--image_path_0", imgA_path,
428
+ "--image_path_1", imgB_path,
429
+ "--prompt_0", prompt_A,
430
+ "--prompt_1", prompt_B,
431
+ "--output_path", output_dir,
432
+ "--film_output_folder", film_output_dir,
433
+ "--num_frames", str(num_frames),
434
+ "--fps", str(output_fps)
435
+ ]
436
+
437
+ if enable_lcm_lora:
438
+ cmd.append("--use_lcm")
439
+ if use_adain:
440
+ cmd.append("--use_adain")
441
+ if use_reschedule:
442
+ cmd.append("--use_reschedule")
443
+ if use_film:
444
+ cmd.append("--use_film")
445
+
446
+ # Add film recursion parameter
447
+ cmd.extend(["--film_num_recursions", str(film_recursions)])
448
+
449
+ # If SLAB execution is enabled, prepend the srun command prefix.
450
+ # if using_slab:
451
+ # slab_prefix = [
452
+ # "srun", "-p", "rtx3090_slab", "-w", "slabgpu05", "--gres=gpu:1",
453
+ # "--job-name=test", "--kill-on-bad-exit=1"
454
+ # ]
455
+ # cmd = slab_prefix + cmd
456
+
457
+ # Update progress status for preparing phase
458
+ progress_bar.progress(10)
459
+ status_text.text("Preparing images and configuration...")
460
+
461
+ # Run the morphing process
462
  try:
463
  subprocess.run(cmd, check=True)
464
+
465
+ # Update progress
466
+ progress_bar.progress(90)
467
+ status_text.text("Processing complete! Preparing results...")
468
+
469
+ # Check for output video
470
+ video_found = False
471
+ possible_outputs = [f for f in os.listdir(film_output_dir) if f.endswith(".mp4")]
472
+ if possible_outputs:
473
+ final_video_path = os.path.join(film_output_dir, possible_outputs[0])
474
+ video_found = True
475
+
476
+ if not video_found:
477
+ possible_outputs = [f for f in os.listdir(output_dir) if f.endswith(".mp4")]
478
+ if possible_outputs:
479
+ final_video_path = os.path.join(output_dir, possible_outputs[0])
480
+ video_found = True
481
+
482
+ if video_found:
483
+ st.session_state.final_video_path = final_video_path
484
+ st.session_state.process_complete = True
485
+
486
+ # Set progress to 100%
487
+ progress_bar.progress(100)
488
+
489
+ st.rerun()
490
+ else:
491
+ status_text.warning("No output video was generated. Check logs for details.")
492
+ st.session_state.processing = False
493
+ st.session_state.process_complete = False
494
+
495
  except subprocess.CalledProcessError as e:
496
  st.error(f"Error running morphing pipeline: {e}")
497
+ st.session_state.processing = False
498
+ st.session_state.process_complete = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
 
500
+ except Exception as e:
501
+ st.error(f"An error occurred during processing: {e}")
502
+ st.session_state.processing = False
503
+ st.session_state.process_complete = False
504
 
505
  if __name__ == "__main__":
506
  main()