burtenshaw commited on
Commit
dfd0eac
·
1 Parent(s): 99f7dee

another status fix

Browse files
Files changed (1) hide show
  1. app/app.py +161 -51
app/app.py CHANGED
@@ -278,16 +278,22 @@ def load_css(css_filename="style.scss"):
278
  # --- Gradio Workflow Functions ---
279
 
280
 
281
- def step1_fetch_and_generate_presentation(
282
- url, status_textbox, progress=gr.Progress(track_tqdm=True)
283
- ):
284
  """Fetches content, generates presentation markdown, prepares editor, and copies template. Uses caching based on URL."""
285
  if not url:
286
  raise gr.Error("Please enter a URL.")
287
  logger.info(f"Step 1: Fetching & Generating for {url}")
288
 
289
  status_update = f"Starting Step 1: Fetching content from {url}..."
290
- yield status_update
 
 
 
 
 
 
 
 
291
 
292
  # --- Cache Check ---
293
  try:
@@ -340,7 +346,15 @@ def step1_fetch_and_generate_presentation(
340
  status_update = (
341
  "Loaded presentation from cache. Preparing editor..."
342
  )
343
- yield status_update
 
 
 
 
 
 
 
 
344
  logger.info(f"Using cached data for {len(slides_data)} slides.")
345
  # Final yield must match outputs list
346
  yield (
@@ -370,14 +384,30 @@ def step1_fetch_and_generate_presentation(
370
  raise gr.Error("LLM Client not initialized. Check API Key.")
371
 
372
  status_update = "Fetching webpage content..."
373
- yield status_update
 
 
 
 
 
 
 
 
374
  web_content = fetch_webpage_content(url)
375
  if not web_content:
376
  raise gr.Error("Failed to fetch or parse content from the URL.")
377
 
378
  progress(0.3, desc="Generating presentation with LLM...")
379
  status_update = "Generating presentation with LLM..."
380
- yield status_update
 
 
 
 
 
 
 
 
381
  try:
382
  presentation_md = generate_presentation_with_llm(
383
  hf_client, LLM_MODEL, PRESENTATION_PROMPT, web_content, url
@@ -402,7 +432,15 @@ def step1_fetch_and_generate_presentation(
402
 
403
  progress(0.7, desc="Parsing presentation slides...")
404
  status_update = "Parsing presentation slides..."
405
- yield status_update
 
 
 
 
 
 
 
 
406
  slides_data = parse_presentation_markdown(presentation_md)
407
  if not slides_data:
408
  logger.error("Parsing markdown resulted in zero slides.")
@@ -446,7 +484,15 @@ def step1_fetch_and_generate_presentation(
446
 
447
  progress(0.9, desc="Preparing editor...")
448
  status_update = "Generated presentation. Preparing editor..."
449
- yield status_update
 
 
 
 
 
 
 
 
450
  logger.info(f"Prepared data for {len(slides_data)} slides.")
451
 
452
  # Final yield must match outputs list
@@ -463,7 +509,15 @@ def step1_fetch_and_generate_presentation(
463
  except Exception as e:
464
  logger.error(f"Error in step 1 (fetch/generate): {e}", exc_info=True)
465
  status_update = f"Error during presentation setup: {e}"
466
- yield status_update
 
 
 
 
 
 
 
 
467
  # Yield a final tuple matching outputs, indicating error state if possible
468
  yield (
469
  gr.update(value=status_update),
@@ -482,7 +536,6 @@ def step2_build_slides(
482
  state_temp_dir,
483
  state_md_path,
484
  state_slides_data,
485
- status_textbox,
486
  *editors,
487
  progress=gr.Progress(track_tqdm=True),
488
  ):
@@ -491,7 +544,14 @@ def step2_build_slides(
491
  raise gr.Error("Session state missing.")
492
  logger.info("Step 2: Building Slides (PDF + Images)")
493
  status_update = "Starting Step 2: Building slides..."
494
- yield status_update
 
 
 
 
 
 
 
495
 
496
  num_slides = len(state_slides_data)
497
  MAX_SLIDES = 20
@@ -505,7 +565,14 @@ def step2_build_slides(
505
 
506
  progress(0.1, desc="Saving edited markdown...")
507
  status_update = "Saving edited markdown..."
508
- yield status_update
 
 
 
 
 
 
 
509
  updated_slides = []
510
  for i in range(num_slides):
511
  updated_slides.append(
@@ -518,7 +585,14 @@ def step2_build_slides(
518
  logger.info(f"Saved edited markdown: {state_md_path}")
519
  except IOError as e:
520
  status_update = f"Failed to save markdown: {e}"
521
- yield status_update
 
 
 
 
 
 
 
522
  # Final yield must match outputs
523
  yield (
524
  gr.update(value=status_update),
@@ -527,12 +601,19 @@ def step2_build_slides(
527
  gr.update(),
528
  gr.update(visible=True),
529
  gr.update(),
530
- ) # Keep build button visible
531
  raise gr.Error(f"Failed to save markdown: {e}")
532
 
533
  progress(0.3, desc="Generating PDF...")
534
  status_update = "Generating PDF..."
535
- yield status_update
 
 
 
 
 
 
 
536
  pdf_output_path = os.path.join(state_temp_dir, "presentation.pdf")
537
  try:
538
  generated_pdf_path = generate_pdf_from_markdown(state_md_path, pdf_output_path)
@@ -540,7 +621,14 @@ def step2_build_slides(
540
  raise gr.Error("PDF generation failed (check logs).")
541
  except gr.Error as e:
542
  status_update = f"PDF Generation Error: {e}"
543
- yield status_update
 
 
 
 
 
 
 
544
  # Final yield must match outputs
545
  yield (
546
  gr.update(value=status_update),
@@ -549,11 +637,18 @@ def step2_build_slides(
549
  gr.update(),
550
  gr.update(visible=True),
551
  gr.update(),
552
- ) # Keep build button visible
553
  raise e
554
  except Exception as e:
555
  status_update = f"Unexpected PDF Error: {e}"
556
- yield status_update
 
 
 
 
 
 
 
557
  # Final yield must match outputs
558
  yield (
559
  gr.update(value=status_update),
@@ -562,12 +657,19 @@ def step2_build_slides(
562
  gr.update(),
563
  gr.update(visible=True),
564
  gr.update(),
565
- ) # Keep build button visible
566
  raise gr.Error(f"Unexpected error generating PDF: {e}")
567
 
568
  progress(0.7, desc="Converting PDF to images...")
569
  status_update = "Converting PDF to images..."
570
- yield status_update
 
 
 
 
 
 
 
571
  pdf_images = []
572
  try:
573
  pdf_images = convert_pdf_to_images(
@@ -584,7 +686,14 @@ def step2_build_slides(
584
  except Exception as e:
585
  logger.error(f"Error converting PDF to images: {e}", exc_info=True)
586
  status_update = f"Failed to convert PDF to images: {e}"
587
- yield status_update
 
 
 
 
 
 
 
588
  # Final yield must match outputs
589
  yield (
590
  gr.update(value=status_update),
@@ -593,7 +702,7 @@ def step2_build_slides(
593
  gr.update(),
594
  gr.update(visible=True),
595
  gr.update(value=generated_pdf_path, visible=True),
596
- ) # Keep build button visible
597
  # Proceed without images? Or raise error? Let's raise.
598
  raise gr.Error(f"Failed to convert PDF to images: {e}")
599
 
@@ -617,13 +726,11 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
617
  # args[0]: state_temp_dir
618
  # args[1]: state_md_path
619
  # args[2]: original_slides_data
620
- # args[3]: status_textbox <- Now passed explicitly
621
- # args[4...]: editors
622
 
623
  state_temp_dir = args[0]
624
  state_md_path = args[1]
625
  original_slides_data = args[2]
626
- status_textbox = args[3]
627
 
628
  # editors = args[3:] # Old slicing
629
  num_slides = len(original_slides_data)
@@ -632,10 +739,10 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
632
  raise gr.Error("No slide data available. Please start over.")
633
 
634
  MAX_SLIDES = 20 # Ensure this matches UI definition
635
- # --- Adjust indices based on adding status_textbox input ---
636
- # Start editors from index 4 now
637
- code_editors_start_index = 4
638
- notes_textboxes_start_index = 4 + MAX_SLIDES
639
 
640
  # Slice the *actual* edited values based on num_slides
641
  edited_contents = args[
@@ -659,7 +766,9 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
659
 
660
  logger.info(f"Processing {num_slides} slides for audio generation.")
661
  status_update = "Starting Step 3: Generating audio..."
662
- yield status_update
 
 
663
 
664
  audio_dir = os.path.join(state_temp_dir, "audio")
665
  os.makedirs(audio_dir, exist_ok=True)
@@ -669,7 +778,9 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
669
  # but ensures the audio matches the *latest* notes displayed.
670
  progress(0.1, desc="Saving latest notes...")
671
  status_update = "Saving latest notes..."
672
- yield status_update
 
 
673
  updated_slides_data = []
674
  for i in range(num_slides):
675
  updated_slides_data.append(
@@ -689,7 +800,9 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
689
  warning_msg = f"Warning: Could not save latest notes to markdown file: {e}"
690
  gr.Warning(warning_msg)
691
  status_update += f" ({warning_msg})"
692
- yield status_update # Yield the warning status string
 
 
693
  # Note: We continue processing audio even if saving markdown fails
694
  # If we need to stop and return final state, do it here:
695
  # yield (gr.update(value=status_update), state_audio_dir, gr.update(), gr.update(visible=True), *[gr.update()]*N, *[gr.update()]*N)
@@ -708,7 +821,9 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
708
  desc=f"Audio slide {slide_num}/{num_slides}",
709
  )
710
  status_update = f"Generating audio for slide {slide_num}/{num_slides}..."
711
- yield status_update
 
 
712
 
713
  output_file_path = Path(audio_dir) / f"{slide_num}.wav"
714
  if not note_text or not note_text.strip():
@@ -787,7 +902,6 @@ def step4_generate_video(
787
  state_temp_dir,
788
  state_audio_dir,
789
  state_pdf_path, # Use PDF path from state
790
- status_textbox,
791
  progress=gr.Progress(track_tqdm=True),
792
  ):
793
  """Generates the final video using PDF images and audio files."""
@@ -802,7 +916,7 @@ def step4_generate_video(
802
 
803
  video_output_path = os.path.join(state_temp_dir, "final_presentation.mp4")
804
  status_update = "Starting Step 4: Generating video..."
805
- yield status_update
806
 
807
  progress(0.1, desc="Preparing video components...")
808
  pdf_images = [] # Initialize to ensure cleanup happens
@@ -819,7 +933,7 @@ def step4_generate_video(
819
  # Convert PDF to images
820
  progress(0.2, desc="Converting PDF to images...")
821
  status_update = "Converting PDF back to images for video..."
822
- yield status_update
823
  pdf_images = convert_pdf_to_images(state_pdf_path, dpi=150)
824
  if not pdf_images:
825
  raise gr.Error(f"Failed to convert PDF ({state_pdf_path}) to images.")
@@ -831,12 +945,12 @@ def step4_generate_video(
831
  logger.warning(warning_msg)
832
  status_update += f" ({warning_msg})"
833
  # yield status_update # Old yield
834
- yield status_update # Yield the warning status string
835
 
836
  progress(0.5, desc="Creating individual video clips...")
837
  status_update = "Creating individual video clips..."
838
  # yield status_update # Old yield
839
- yield status_update
840
  buffer_seconds = 1.0
841
  output_fps = 10
842
  video_clips = create_video_clips(
@@ -849,7 +963,7 @@ def step4_generate_video(
849
  progress(0.8, desc="Concatenating clips...")
850
  status_update = "Concatenating clips into final video..."
851
  # yield status_update # Old yield
852
- yield status_update
853
  concatenate_clips(video_clips, video_output_path, output_fps)
854
 
855
  logger.info(f"Video concatenation complete: {video_output_path}")
@@ -857,7 +971,7 @@ def step4_generate_video(
857
  progress(0.95, desc="Cleaning up temp images...")
858
  status_update = "Cleaning up temporary image files..."
859
  # yield status_update # Old yield
860
- yield status_update
861
  cleanup_temp_files(pdf_images) # Pass the list of image paths
862
 
863
  except Exception as e:
@@ -865,13 +979,9 @@ def step4_generate_video(
865
  cleanup_temp_files(pdf_images)
866
  logger.error(f"Video generation failed: {e}", exc_info=True)
867
  status_update = f"Video generation failed: {e}"
868
- yield status_update
869
  # Final yield must match outputs
870
- yield (
871
- gr.update(value=status_update),
872
- gr.update(),
873
- gr.update(visible=True),
874
- ) # Keep button visible
875
  raise gr.Error(f"Video generation failed: {e}")
876
 
877
  info_msg = f"Video generated: {os.path.basename(video_output_path)}"
@@ -1131,7 +1241,7 @@ with gr.Blocks(
1131
  ]
1132
  btn_fetch_generate.click(
1133
  fn=step1_fetch_and_generate_presentation,
1134
- inputs=[input_url, status_textbox],
1135
  outputs=step1_outputs,
1136
  show_progress="full",
1137
  ).then(
@@ -1171,7 +1281,7 @@ with gr.Blocks(
1171
 
1172
  # Step 2 Click Handler
1173
  step2_inputs = (
1174
- [state_temp_dir, state_md_path, state_slides_data, status_textbox]
1175
  + all_code_editors
1176
  + all_notes_textboxes
1177
  )
@@ -1209,7 +1319,7 @@ with gr.Blocks(
1209
 
1210
  # Step 3 Click Handler
1211
  step3_inputs = (
1212
- [state_temp_dir, state_md_path, state_slides_data, status_textbox]
1213
  + all_code_editors
1214
  + all_notes_textboxes
1215
  )
@@ -1239,7 +1349,7 @@ with gr.Blocks(
1239
  )
1240
 
1241
  # Step 4 Click Handler
1242
- step4_inputs = [state_temp_dir, state_audio_dir, state_pdf_path, status_textbox]
1243
  step4_outputs = [
1244
  status_textbox, # Added status output
1245
  video_output, # Update video output in Tab 4
 
278
  # --- Gradio Workflow Functions ---
279
 
280
 
281
+ def step1_fetch_and_generate_presentation(url, progress=gr.Progress(track_tqdm=True)):
 
 
282
  """Fetches content, generates presentation markdown, prepares editor, and copies template. Uses caching based on URL."""
283
  if not url:
284
  raise gr.Error("Please enter a URL.")
285
  logger.info(f"Step 1: Fetching & Generating for {url}")
286
 
287
  status_update = f"Starting Step 1: Fetching content from {url}..."
288
+ yield (
289
+ gr.update(value=status_update),
290
+ None,
291
+ None,
292
+ [],
293
+ gr.update(),
294
+ gr.update(),
295
+ gr.update(),
296
+ )
297
 
298
  # --- Cache Check ---
299
  try:
 
346
  status_update = (
347
  "Loaded presentation from cache. Preparing editor..."
348
  )
349
+ yield (
350
+ gr.update(value=status_update),
351
+ None,
352
+ None,
353
+ [],
354
+ gr.update(),
355
+ gr.update(),
356
+ gr.update(),
357
+ )
358
  logger.info(f"Using cached data for {len(slides_data)} slides.")
359
  # Final yield must match outputs list
360
  yield (
 
384
  raise gr.Error("LLM Client not initialized. Check API Key.")
385
 
386
  status_update = "Fetching webpage content..."
387
+ yield (
388
+ gr.update(value=status_update),
389
+ None,
390
+ None,
391
+ [],
392
+ gr.update(),
393
+ gr.update(),
394
+ gr.update(),
395
+ )
396
  web_content = fetch_webpage_content(url)
397
  if not web_content:
398
  raise gr.Error("Failed to fetch or parse content from the URL.")
399
 
400
  progress(0.3, desc="Generating presentation with LLM...")
401
  status_update = "Generating presentation with LLM..."
402
+ yield (
403
+ gr.update(value=status_update),
404
+ None,
405
+ None,
406
+ [],
407
+ gr.update(),
408
+ gr.update(),
409
+ gr.update(),
410
+ )
411
  try:
412
  presentation_md = generate_presentation_with_llm(
413
  hf_client, LLM_MODEL, PRESENTATION_PROMPT, web_content, url
 
432
 
433
  progress(0.7, desc="Parsing presentation slides...")
434
  status_update = "Parsing presentation slides..."
435
+ yield (
436
+ gr.update(value=status_update),
437
+ None,
438
+ None,
439
+ [],
440
+ gr.update(),
441
+ gr.update(),
442
+ gr.update(),
443
+ )
444
  slides_data = parse_presentation_markdown(presentation_md)
445
  if not slides_data:
446
  logger.error("Parsing markdown resulted in zero slides.")
 
484
 
485
  progress(0.9, desc="Preparing editor...")
486
  status_update = "Generated presentation. Preparing editor..."
487
+ yield (
488
+ gr.update(value=status_update),
489
+ None,
490
+ None,
491
+ [],
492
+ gr.update(),
493
+ gr.update(),
494
+ gr.update(),
495
+ )
496
  logger.info(f"Prepared data for {len(slides_data)} slides.")
497
 
498
  # Final yield must match outputs list
 
509
  except Exception as e:
510
  logger.error(f"Error in step 1 (fetch/generate): {e}", exc_info=True)
511
  status_update = f"Error during presentation setup: {e}"
512
+ yield (
513
+ gr.update(value=status_update),
514
+ None,
515
+ None,
516
+ [],
517
+ gr.update(),
518
+ gr.update(),
519
+ gr.update(),
520
+ )
521
  # Yield a final tuple matching outputs, indicating error state if possible
522
  yield (
523
  gr.update(value=status_update),
 
536
  state_temp_dir,
537
  state_md_path,
538
  state_slides_data,
 
539
  *editors,
540
  progress=gr.Progress(track_tqdm=True),
541
  ):
 
544
  raise gr.Error("Session state missing.")
545
  logger.info("Step 2: Building Slides (PDF + Images)")
546
  status_update = "Starting Step 2: Building slides..."
547
+ yield (
548
+ gr.update(value=status_update),
549
+ None,
550
+ [],
551
+ gr.update(),
552
+ gr.update(),
553
+ gr.update(),
554
+ )
555
 
556
  num_slides = len(state_slides_data)
557
  MAX_SLIDES = 20
 
565
 
566
  progress(0.1, desc="Saving edited markdown...")
567
  status_update = "Saving edited markdown..."
568
+ yield (
569
+ gr.update(value=status_update),
570
+ None,
571
+ [],
572
+ gr.update(),
573
+ gr.update(),
574
+ gr.update(),
575
+ )
576
  updated_slides = []
577
  for i in range(num_slides):
578
  updated_slides.append(
 
585
  logger.info(f"Saved edited markdown: {state_md_path}")
586
  except IOError as e:
587
  status_update = f"Failed to save markdown: {e}"
588
+ yield (
589
+ gr.update(value=status_update),
590
+ None,
591
+ [],
592
+ gr.update(),
593
+ gr.update(),
594
+ gr.update(),
595
+ )
596
  # Final yield must match outputs
597
  yield (
598
  gr.update(value=status_update),
 
601
  gr.update(),
602
  gr.update(visible=True),
603
  gr.update(),
604
+ )
605
  raise gr.Error(f"Failed to save markdown: {e}")
606
 
607
  progress(0.3, desc="Generating PDF...")
608
  status_update = "Generating PDF..."
609
+ yield (
610
+ gr.update(value=status_update),
611
+ None,
612
+ [],
613
+ gr.update(),
614
+ gr.update(),
615
+ gr.update(),
616
+ )
617
  pdf_output_path = os.path.join(state_temp_dir, "presentation.pdf")
618
  try:
619
  generated_pdf_path = generate_pdf_from_markdown(state_md_path, pdf_output_path)
 
621
  raise gr.Error("PDF generation failed (check logs).")
622
  except gr.Error as e:
623
  status_update = f"PDF Generation Error: {e}"
624
+ yield (
625
+ gr.update(value=status_update),
626
+ None,
627
+ [],
628
+ gr.update(),
629
+ gr.update(),
630
+ gr.update(),
631
+ )
632
  # Final yield must match outputs
633
  yield (
634
  gr.update(value=status_update),
 
637
  gr.update(),
638
  gr.update(visible=True),
639
  gr.update(),
640
+ )
641
  raise e
642
  except Exception as e:
643
  status_update = f"Unexpected PDF Error: {e}"
644
+ yield (
645
+ gr.update(value=status_update),
646
+ None,
647
+ [],
648
+ gr.update(),
649
+ gr.update(),
650
+ gr.update(),
651
+ )
652
  # Final yield must match outputs
653
  yield (
654
  gr.update(value=status_update),
 
657
  gr.update(),
658
  gr.update(visible=True),
659
  gr.update(),
660
+ )
661
  raise gr.Error(f"Unexpected error generating PDF: {e}")
662
 
663
  progress(0.7, desc="Converting PDF to images...")
664
  status_update = "Converting PDF to images..."
665
+ yield (
666
+ gr.update(value=status_update),
667
+ generated_pdf_path,
668
+ [],
669
+ gr.update(),
670
+ gr.update(),
671
+ gr.update(),
672
+ )
673
  pdf_images = []
674
  try:
675
  pdf_images = convert_pdf_to_images(
 
686
  except Exception as e:
687
  logger.error(f"Error converting PDF to images: {e}", exc_info=True)
688
  status_update = f"Failed to convert PDF to images: {e}"
689
+ yield (
690
+ gr.update(value=status_update),
691
+ generated_pdf_path,
692
+ [],
693
+ gr.update(),
694
+ gr.update(),
695
+ gr.update(),
696
+ )
697
  # Final yield must match outputs
698
  yield (
699
  gr.update(value=status_update),
 
702
  gr.update(),
703
  gr.update(visible=True),
704
  gr.update(value=generated_pdf_path, visible=True),
705
+ )
706
  # Proceed without images? Or raise error? Let's raise.
707
  raise gr.Error(f"Failed to convert PDF to images: {e}")
708
 
 
726
  # args[0]: state_temp_dir
727
  # args[1]: state_md_path
728
  # args[2]: original_slides_data
729
+ # args[3...]: editors
 
730
 
731
  state_temp_dir = args[0]
732
  state_md_path = args[1]
733
  original_slides_data = args[2]
 
734
 
735
  # editors = args[3:] # Old slicing
736
  num_slides = len(original_slides_data)
 
739
  raise gr.Error("No slide data available. Please start over.")
740
 
741
  MAX_SLIDES = 20 # Ensure this matches UI definition
742
+ # --- Adjust indices based on removing status_textbox input ---
743
+ # Start editors from index 3 now
744
+ code_editors_start_index = 3
745
+ notes_textboxes_start_index = 3 + MAX_SLIDES
746
 
747
  # Slice the *actual* edited values based on num_slides
748
  edited_contents = args[
 
766
 
767
  logger.info(f"Processing {num_slides} slides for audio generation.")
768
  status_update = "Starting Step 3: Generating audio..."
769
+ yield (gr.update(value=status_update), None, gr.update(), gr.update()) + (
770
+ gr.update(),
771
+ ) * MAX_SLIDES * 2
772
 
773
  audio_dir = os.path.join(state_temp_dir, "audio")
774
  os.makedirs(audio_dir, exist_ok=True)
 
778
  # but ensures the audio matches the *latest* notes displayed.
779
  progress(0.1, desc="Saving latest notes...")
780
  status_update = "Saving latest notes..."
781
+ yield (gr.update(value=status_update), None, gr.update(), gr.update()) + (
782
+ gr.update(),
783
+ ) * MAX_SLIDES * 2
784
  updated_slides_data = []
785
  for i in range(num_slides):
786
  updated_slides_data.append(
 
800
  warning_msg = f"Warning: Could not save latest notes to markdown file: {e}"
801
  gr.Warning(warning_msg)
802
  status_update += f" ({warning_msg})"
803
+ yield (gr.update(value=status_update), None, gr.update(), gr.update()) + (
804
+ gr.update(),
805
+ ) * MAX_SLIDES * 2
806
  # Note: We continue processing audio even if saving markdown fails
807
  # If we need to stop and return final state, do it here:
808
  # yield (gr.update(value=status_update), state_audio_dir, gr.update(), gr.update(visible=True), *[gr.update()]*N, *[gr.update()]*N)
 
821
  desc=f"Audio slide {slide_num}/{num_slides}",
822
  )
823
  status_update = f"Generating audio for slide {slide_num}/{num_slides}..."
824
+ yield (gr.update(value=status_update), audio_dir, gr.update(), gr.update()) + (
825
+ gr.update(),
826
+ ) * MAX_SLIDES * 2
827
 
828
  output_file_path = Path(audio_dir) / f"{slide_num}.wav"
829
  if not note_text or not note_text.strip():
 
902
  state_temp_dir,
903
  state_audio_dir,
904
  state_pdf_path, # Use PDF path from state
 
905
  progress=gr.Progress(track_tqdm=True),
906
  ):
907
  """Generates the final video using PDF images and audio files."""
 
916
 
917
  video_output_path = os.path.join(state_temp_dir, "final_presentation.mp4")
918
  status_update = "Starting Step 4: Generating video..."
919
+ yield (gr.update(value=status_update), gr.update(), gr.update())
920
 
921
  progress(0.1, desc="Preparing video components...")
922
  pdf_images = [] # Initialize to ensure cleanup happens
 
933
  # Convert PDF to images
934
  progress(0.2, desc="Converting PDF to images...")
935
  status_update = "Converting PDF back to images for video..."
936
+ yield (gr.update(value=status_update), gr.update(), gr.update())
937
  pdf_images = convert_pdf_to_images(state_pdf_path, dpi=150)
938
  if not pdf_images:
939
  raise gr.Error(f"Failed to convert PDF ({state_pdf_path}) to images.")
 
945
  logger.warning(warning_msg)
946
  status_update += f" ({warning_msg})"
947
  # yield status_update # Old yield
948
+ yield (gr.update(value=status_update), gr.update(), gr.update())
949
 
950
  progress(0.5, desc="Creating individual video clips...")
951
  status_update = "Creating individual video clips..."
952
  # yield status_update # Old yield
953
+ yield (gr.update(value=status_update), gr.update(), gr.update())
954
  buffer_seconds = 1.0
955
  output_fps = 10
956
  video_clips = create_video_clips(
 
963
  progress(0.8, desc="Concatenating clips...")
964
  status_update = "Concatenating clips into final video..."
965
  # yield status_update # Old yield
966
+ yield (gr.update(value=status_update), gr.update(), gr.update())
967
  concatenate_clips(video_clips, video_output_path, output_fps)
968
 
969
  logger.info(f"Video concatenation complete: {video_output_path}")
 
971
  progress(0.95, desc="Cleaning up temp images...")
972
  status_update = "Cleaning up temporary image files..."
973
  # yield status_update # Old yield
974
+ yield (gr.update(value=status_update), gr.update(), gr.update())
975
  cleanup_temp_files(pdf_images) # Pass the list of image paths
976
 
977
  except Exception as e:
 
979
  cleanup_temp_files(pdf_images)
980
  logger.error(f"Video generation failed: {e}", exc_info=True)
981
  status_update = f"Video generation failed: {e}"
982
+ yield (gr.update(value=status_update), gr.update(), gr.update())
983
  # Final yield must match outputs
984
+ yield (gr.update(value=status_update), gr.update(), gr.update(visible=True))
 
 
 
 
985
  raise gr.Error(f"Video generation failed: {e}")
986
 
987
  info_msg = f"Video generated: {os.path.basename(video_output_path)}"
 
1241
  ]
1242
  btn_fetch_generate.click(
1243
  fn=step1_fetch_and_generate_presentation,
1244
+ inputs=[input_url],
1245
  outputs=step1_outputs,
1246
  show_progress="full",
1247
  ).then(
 
1281
 
1282
  # Step 2 Click Handler
1283
  step2_inputs = (
1284
+ [state_temp_dir, state_md_path, state_slides_data]
1285
  + all_code_editors
1286
  + all_notes_textboxes
1287
  )
 
1319
 
1320
  # Step 3 Click Handler
1321
  step3_inputs = (
1322
+ [state_temp_dir, state_md_path, state_slides_data]
1323
  + all_code_editors
1324
  + all_notes_textboxes
1325
  )
 
1349
  )
1350
 
1351
  # Step 4 Click Handler
1352
+ step4_inputs = [state_temp_dir, state_audio_dir, state_pdf_path]
1353
  step4_outputs = [
1354
  status_textbox, # Added status output
1355
  video_output, # Update video output in Tab 4