nalin0503 commited on
Commit
9d2aab3
·
1 Parent(s): 68e417f

5th ver, last

Browse files
Files changed (1) hide show
  1. app.py +146 -218
app.py CHANGED
@@ -59,8 +59,9 @@ def main():
59
  if 'final_video_path' not in st.session_state:
60
  st.session_state.final_video_path = None
61
 
62
- if 'progress_stage' not in st.session_state:
63
- st.session_state.progress_stage = 0
 
64
 
65
  # Restart function to reset session state
66
  def restart():
@@ -68,7 +69,7 @@ def main():
68
  st.session_state.process_complete = False
69
  st.session_state.temp_dir = None
70
  st.session_state.final_video_path = None
71
- st.session_state.progress_stage = 0
72
  st.rerun() # Use st.rerun() instead of experimental_rerun
73
 
74
  # ---------------- CUSTOM CSS FOR A PROFESSIONAL, DARK THEME ----------------
@@ -161,61 +162,13 @@ def main():
161
  padding-left: 1rem;
162
  margin-left: 1rem;
163
  }
164
- /* Processing status box */
165
- .processing-box {
166
- background: rgba(0, 0, 0, 0.6);
167
- border-radius: 10px;
168
- border: 1px solid rgba(142, 68, 173, 0.6);
169
- padding: 20px;
170
- margin: 20px 0;
171
- box-shadow: 0 0 30px rgba(142, 68, 173, 0.4);
172
- text-align: center;
173
- }
174
- .processing-title {
175
- font-size: 1.5rem;
176
- color: #ffffff;
177
- margin-bottom: 15px;
178
- font-weight: bold;
179
- }
180
- .processing-stage {
181
- margin: 15px 0;
182
- font-size: 1.1rem;
183
- color: #f1f1f1;
184
- }
185
- .pulse {
186
- animation: pulse 2s infinite;
187
- }
188
- @keyframes pulse {
189
- 0% { opacity: 1; }
190
- 50% { opacity: 0.6; }
191
- 100% { opacity: 1; }
192
- }
193
- .progress-bar-container {
194
- width: 100%;
195
- background-color: rgba(255, 255, 255, 0.2);
196
- border-radius: 5px;
197
- margin: 15px 0;
198
- overflow: hidden;
199
- }
200
- .progress-bar {
201
- height: 10px;
202
- background-image: linear-gradient(45deg, #8e44ad, #732d91);
203
- border-radius: 5px;
204
- transition: width 0.5s ease;
205
- }
206
- /* Rainbow spinner animation */
207
- .spinner {
208
- width: 40px;
209
- height: 40px;
210
- margin: 15px auto;
211
- border: 4px solid transparent;
212
- border-radius: 50%;
213
- border-image: linear-gradient(45deg, purple, blue, cyan, green, yellow, orange, red) 1;
214
- animation: spin 1s linear infinite;
215
- }
216
- @keyframes spin {
217
- 0% { transform: rotate(0deg); }
218
- 100% { transform: rotate(360deg); }
219
  }
220
  </style>
221
  """,
@@ -259,60 +212,35 @@ def main():
259
  unsafe_allow_html=True
260
  )
261
 
 
 
 
262
  # Show results if processing is complete
263
  if st.session_state.process_complete and st.session_state.final_video_path is not None:
264
- st.success("Morphing complete! 🎉")
265
- # st.video(st.session_state.final_video_path)
266
- try:
267
- with open(st.session_state.final_video_path, "rb") as f:
268
- video_bytes = f.read()
269
- st.download_button(
270
- "Download Morphing Video",
271
- data=video_bytes,
272
- file_name="metamorph_result.mp4",
273
- mime="video/mp4"
274
- )
275
-
276
- # Add a restart button to clear the session state and start over
277
- if st.button("Start New Morphing Project", key="restart"):
278
- restart() # Use the restart function
279
 
280
- except Exception as e:
281
- st.error(f"Error preparing video for download: {e}")
282
-
283
- # Early return to not show the input forms again when we have a result
284
- return
 
 
285
 
286
- # Show enhanced processing status if in processing mode
287
- if st.session_state.processing:
288
- # Define processing stages
289
- stages = [
290
- "Initializing the morphing pipeline...",
291
- "Loading and processing images...",
292
- "Generating keyframes with diffusion model...",
293
- "Creating intermediate frames...",
294
- "Finalizing your morphing video...",
295
- ]
296
-
297
- # Calculate progress percentage (artifically progressing based on time since start)
298
- progress = min(st.session_state.progress_stage / len(stages), 1.0)
299
-
300
- # Show processing status
301
- st.markdown(
302
- f"""
303
- <div class="processing-box">
304
- <div class="processing-title">🔮 Creating Your Morphing Video</div>
305
- <div class="spinner"></div>
306
- <div class="processing-stage pulse">{stages[st.session_state.progress_stage]}</div>
307
- <div class="progress-bar-container">
308
- <div class="progress-bar" style="width: {int(progress * 100)}%"></div>
309
- </div>
310
- <div class="processing-stage">Please wait while we work our magic...</div>
311
- </div>
312
- """,
313
- unsafe_allow_html=True
314
- )
315
-
316
  # ---------------- SECTION 1: IMAGE & PROMPT INPUTS ----------------
317
  st.subheader("1. Upload Source Images & Prompts")
318
  st.markdown("**Note:** Your uploaded images must be of similar topology and same size to achieve the best results.")
@@ -442,132 +370,132 @@ def main():
442
  # Create a container for the run button and its status messages
443
  run_container = st.container()
444
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
445
  with run_container:
446
  # Button text changes based on processing state
447
  button_text = "Processing... Please Wait" if st.session_state.processing else "Run Morphing Pipeline"
448
 
449
  # Button is disabled during processing
450
  if st.button(button_text, key="run_pipeline", disabled=st.session_state.processing):
451
- # Set processing state to True immediately
452
- st.session_state.processing = True
453
- st.rerun() # Force a refresh to apply the disabled state to all UI elements
454
- else:
455
- # This will run after the refresh
456
- if st.session_state.processing:
457
- # Check if both images are uploaded
458
- if not (uploaded_image_A and uploaded_image_B):
459
- st.error("Please upload both images before running the morphing pipeline.")
460
- st.session_state.processing = False # Reset processing state
461
- st.rerun() # Refresh again to enable UI elements
462
- else:
463
- # Increment progress stage periodically
464
- # In a real implementation, these stage updates would be triggered by actual progress
465
- # Here we simulate progress for demonstration
 
 
 
 
 
 
 
 
 
466
 
467
- # Create a temporary folder for processing
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  try:
469
- temp_dir = create_temp_folder()
470
- st.session_state.temp_dir = temp_dir
471
-
472
- # Save uploaded images
473
- imgA_path = os.path.join(temp_dir, "imageA.png")
474
- imgB_path = os.path.join(temp_dir, "imageB.png")
475
- save_uploaded_file(uploaded_image_A, imgA_path)
476
- save_uploaded_file(uploaded_image_B, imgB_path)
477
-
478
- # Update progress stage
479
- st.session_state.progress_stage = 1
480
- st.rerun() # Refresh to update progress
481
-
482
- # Create output directories
483
- timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
484
- output_dir = os.path.join(temp_dir, f"morph_results_{timestamp}")
485
- film_output_dir = os.path.join(temp_dir, f"film_output_{timestamp}")
486
- os.makedirs(output_dir, exist_ok=True)
487
- os.makedirs(film_output_dir, exist_ok=True)
488
 
489
- actual_model_path = (
490
- "lykon/dreamshaper-7" if model_option == "Dreamshaper-7 (fine-tuned SD V1-5)"
491
- else "stabilityai/stable-diffusion-2-1-base" if model_option == "Base Stable Diffusion V2-1"
492
- else "sd-legacy/stable-diffusion-v1-5"
493
- )
 
494
 
495
- # Build the command for run_morphing.py
496
- cmd = [
497
- sys.executable, "run_morphing.py",
498
- "--model_path", actual_model_path,
499
- "--image_path_0", imgA_path,
500
- "--image_path_1", imgB_path,
501
- "--prompt_0", prompt_A,
502
- "--prompt_1", prompt_B,
503
- "--output_path", output_dir,
504
- "--film_output_folder", film_output_dir,
505
- "--num_frames", str(num_frames),
506
- "--fps", str(output_fps)
507
- ]
508
-
509
- if enable_lcm_lora:
510
- cmd.append("--use_lcm")
511
- if use_adain:
512
- cmd.append("--use_adain")
513
- if use_reschedule:
514
- cmd.append("--use_reschedule")
515
- if use_film:
516
- cmd.append("--use_film")
517
-
518
- # Add film recursion parameter
519
- cmd.extend(["--film_num_recursions", str(film_recursions)])
520
-
521
- # Update progress stage - Start generating keyframes
522
- st.session_state.progress_stage = 2
523
- st.rerun() # Refresh to update progress
524
-
525
- # Run the morphing process
526
- try:
527
- subprocess.run(cmd, check=True)
528
-
529
- # Update progress stage - Creating intermediate frames
530
- st.session_state.progress_stage = 3
531
- st.rerun() # Refresh to update progress
532
-
533
- # Check for output video
534
- video_found = False
535
- possible_outputs = [f for f in os.listdir(film_output_dir) if f.endswith(".mp4")]
536
  if possible_outputs:
537
- final_video_path = os.path.join(film_output_dir, possible_outputs[0])
538
  video_found = True
539
-
540
- if not video_found:
541
- possible_outputs = [f for f in os.listdir(output_dir) if f.endswith(".mp4")]
542
- if possible_outputs:
543
- final_video_path = os.path.join(output_dir, possible_outputs[0])
544
- video_found = True
545
-
546
- # Update progress stage - Finalizing video
547
- st.session_state.progress_stage = 4
548
- st.rerun() # Refresh to update progress
549
-
550
- if video_found:
551
- st.session_state.final_video_path = final_video_path
552
- st.session_state.process_complete = True
553
- st.rerun() # Show the results page
554
- else:
555
- st.error("No output video was generated. Check logs for details.")
556
- st.session_state.processing = False
557
- st.session_state.process_complete = False
558
- st.rerun() # Reset the interface
559
-
560
- except subprocess.CalledProcessError as e:
561
- st.error(f"Error running morphing pipeline: {e}")
562
  st.session_state.processing = False
563
  st.session_state.process_complete = False
564
- st.rerun() # Reset the interface
565
-
566
- except Exception as e:
567
- st.error(f"An error occurred during processing: {e}")
568
  st.session_state.processing = False
569
  st.session_state.process_complete = False
570
- st.rerun() # Reset the interface
 
 
 
 
571
 
572
  if __name__ == "__main__":
573
  main()
 
59
  if 'final_video_path' not in st.session_state:
60
  st.session_state.final_video_path = None
61
 
62
+ # Initialize the download container in session state
63
+ if 'show_download' not in st.session_state:
64
+ st.session_state.show_download = False
65
 
66
  # Restart function to reset session state
67
  def restart():
 
69
  st.session_state.process_complete = False
70
  st.session_state.temp_dir = None
71
  st.session_state.final_video_path = None
72
+ st.session_state.show_download = False
73
  st.rerun() # Use st.rerun() instead of experimental_rerun
74
 
75
  # ---------------- CUSTOM CSS FOR A PROFESSIONAL, DARK THEME ----------------
 
162
  padding-left: 1rem;
163
  margin-left: 1rem;
164
  }
165
+ /* Results section styling */
166
+ .results-section {
167
+ margin-top: 2rem;
168
+ padding: 1.5rem;
169
+ background-color: rgba(0, 0, 0, 0.2);
170
+ border-radius: 8px;
171
+ border: 1px solid rgba(255, 255, 255, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  }
173
  </style>
174
  """,
 
212
  unsafe_allow_html=True
213
  )
214
 
215
+ # Create a persistent container for the results section
216
+ results_container = st.container()
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
+ with results_container:
221
+ st.markdown("<div class='results-section'>", unsafe_allow_html=True)
222
+ st.success("Morphing complete! 🎉")
223
+ try:
224
+ with open(st.session_state.final_video_path, "rb") as f:
225
+ video_bytes = f.read()
226
+ st.session_state.video_bytes = video_bytes # Store video bytes in session state
227
+ st.video(video_bytes)
228
+ st.download_button(
229
+ "Download Morphing Video",
230
+ data=video_bytes,
231
+ file_name="metamorph_result.mp4",
232
+ mime="video/mp4"
233
+ )
234
+ st.session_state.show_download = True
235
 
236
+ # Add a restart button to clear the session state and start over
237
+ if st.button("Start New Morphing Project", key="restart"):
238
+ restart()
239
+
240
+ except Exception as e:
241
+ st.error(f"Error preparing video for download: {e}")
242
+ st.markdown("</div>", unsafe_allow_html=True)
243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  # ---------------- SECTION 1: IMAGE & PROMPT INPUTS ----------------
245
  st.subheader("1. Upload Source Images & Prompts")
246
  st.markdown("**Note:** Your uploaded images must be of similar topology and same size to achieve the best results.")
 
370
  # Create a container for the run button and its status messages
371
  run_container = st.container()
372
 
373
+ # Create a separate container for displaying the download button
374
+ download_container = st.container()
375
+
376
+ # Check if we should display the download button even when the form is disabled
377
+ if st.session_state.show_download and st.session_state.final_video_path is not None:
378
+ with download_container:
379
+ st.markdown("<div class='results-section'>", unsafe_allow_html=True)
380
+ st.success("Morphing complete! 🎉")
381
+ try:
382
+ with open(st.session_state.final_video_path, "rb") as f:
383
+ video_bytes = f.read()
384
+ st.video(video_bytes)
385
+ st.download_button(
386
+ "Download Morphing Video",
387
+ data=video_bytes,
388
+ file_name="metamorph_result.mp4",
389
+ mime="video/mp4"
390
+ )
391
+
392
+ # Add a restart button to clear the session state and start over
393
+ if st.button("Start New Morphing Project", key="restart_bottom"):
394
+ restart()
395
+
396
+ except Exception as e:
397
+ st.error(f"Error preparing video for download: {e}")
398
+ st.markdown("</div>", unsafe_allow_html=True)
399
+
400
  with run_container:
401
  # Button text changes based on processing state
402
  button_text = "Processing... Please Wait" if st.session_state.processing else "Run Morphing Pipeline"
403
 
404
  # Button is disabled during processing
405
  if st.button(button_text, key="run_pipeline", disabled=st.session_state.processing):
406
+ if not (uploaded_image_A and uploaded_image_B):
407
+ st.error("Please upload both images before running the morphing pipeline.")
408
+ else:
409
+ # Set the processing state to True to prevent multiple runs
410
+ st.session_state.processing = True
411
+ st.info("Processing your morphing request. Please wait...")
412
+
413
+ # Create a temporary folder for processing
414
+ temp_dir = create_temp_folder()
415
+ st.session_state.temp_dir = temp_dir
416
+
417
+ try:
418
+ # Save uploaded images
419
+ imgA_path = os.path.join(temp_dir, "imageA.png")
420
+ imgB_path = os.path.join(temp_dir, "imageB.png")
421
+ save_uploaded_file(uploaded_image_A, imgA_path)
422
+ save_uploaded_file(uploaded_image_B, imgB_path)
423
+
424
+ # Create output directories
425
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
426
+ output_dir = os.path.join(temp_dir, f"morph_results_{timestamp}")
427
+ film_output_dir = os.path.join(temp_dir, f"film_output_{timestamp}")
428
+ os.makedirs(output_dir, exist_ok=True)
429
+ os.makedirs(film_output_dir, exist_ok=True)
430
 
431
+ actual_model_path = (
432
+ "lykon/dreamshaper-7" if model_option == "Dreamshaper-7 (fine-tuned SD V1-5)"
433
+ else "stabilityai/stable-diffusion-2-1-base" if model_option == "Base Stable Diffusion V2-1"
434
+ else "sd-legacy/stable-diffusion-v1-5"
435
+ )
436
+
437
+ # Build the command for run_morphing.py
438
+ cmd = [
439
+ sys.executable, "run_morphing.py",
440
+ "--model_path", actual_model_path,
441
+ "--image_path_0", imgA_path,
442
+ "--image_path_1", imgB_path,
443
+ "--prompt_0", prompt_A,
444
+ "--prompt_1", prompt_B,
445
+ "--output_path", output_dir,
446
+ "--film_output_folder", film_output_dir,
447
+ "--num_frames", str(num_frames),
448
+ "--fps", str(output_fps)
449
+ ]
450
+
451
+ if enable_lcm_lora:
452
+ cmd.append("--use_lcm")
453
+ if use_adain:
454
+ cmd.append("--use_adain")
455
+ if use_reschedule:
456
+ cmd.append("--use_reschedule")
457
+ if use_film:
458
+ cmd.append("--use_film")
459
+
460
+ # Add film recursion parameter
461
+ cmd.extend(["--film_num_recursions", str(film_recursions)])
462
+
463
+ # Run the morphing process
464
  try:
465
+ subprocess.run(cmd, check=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
 
467
+ # Check for output video
468
+ video_found = False
469
+ possible_outputs = [f for f in os.listdir(film_output_dir) if f.endswith(".mp4")]
470
+ if possible_outputs:
471
+ final_video_path = os.path.join(film_output_dir, possible_outputs[0])
472
+ video_found = True
473
 
474
+ if not video_found:
475
+ possible_outputs = [f for f in os.listdir(output_dir) if f.endswith(".mp4")]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
  if possible_outputs:
477
+ final_video_path = os.path.join(output_dir, possible_outputs[0])
478
  video_found = True
479
+
480
+ if video_found:
481
+ st.session_state.final_video_path = final_video_path
482
+ st.session_state.process_complete = True
483
+ st.session_state.show_download = True
484
+ st.rerun() # This is crucial for showing the results page
485
+ else:
486
+ st.error("No output video was generated. Check logs for details.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  st.session_state.processing = False
488
  st.session_state.process_complete = False
489
+
490
+ except subprocess.CalledProcessError as e:
491
+ st.error(f"Error running morphing pipeline: {e}")
 
492
  st.session_state.processing = False
493
  st.session_state.process_complete = False
494
+
495
+ except Exception as e:
496
+ st.error(f"An error occurred during processing: {e}")
497
+ st.session_state.processing = False
498
+ st.session_state.process_complete = False
499
 
500
  if __name__ == "__main__":
501
  main()