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

fix status updates

Browse files
Files changed (1) hide show
  1. app/app.py +72 -65
app/app.py CHANGED
@@ -287,7 +287,7 @@ def step1_fetch_and_generate_presentation(
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_textbox: gr.update(value=status_update)}
291
 
292
  # --- Cache Check ---
293
  try:
@@ -340,9 +340,9 @@ def step1_fetch_and_generate_presentation(
340
  status_update = (
341
  "Loaded presentation from cache. Preparing editor..."
342
  )
343
- yield {status_textbox: gr.update(value=status_update)}
344
  logger.info(f"Using cached data for {len(slides_data)} slides.")
345
- # Return updates for the UI state and controls
346
  yield (
347
  gr.update(value=status_update),
348
  temp_dir,
@@ -370,14 +370,14 @@ 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_textbox: gr.update(value=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_textbox: gr.update(value=status_update)}
381
  try:
382
  presentation_md = generate_presentation_with_llm(
383
  hf_client, LLM_MODEL, PRESENTATION_PROMPT, web_content, url
@@ -402,7 +402,7 @@ def step1_fetch_and_generate_presentation(
402
 
403
  progress(0.7, desc="Parsing presentation slides...")
404
  status_update = "Parsing presentation slides..."
405
- yield {status_textbox: gr.update(value=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,10 +446,10 @@ def step1_fetch_and_generate_presentation(
446
 
447
  progress(0.9, desc="Preparing editor...")
448
  status_update = "Generated presentation. Preparing editor..."
449
- yield {status_textbox: gr.update(value=status_update)}
450
  logger.info(f"Prepared data for {len(slides_data)} slides.")
451
 
452
- # Return updates for the UI state and controls
453
  yield (
454
  gr.update(value=status_update),
455
  temp_dir,
@@ -463,18 +463,18 @@ 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_textbox: gr.update(value=status_update)}
467
- # Need to yield the correct number of outputs even on error to avoid issues
468
  yield (
469
  gr.update(value=status_update),
470
  None,
471
  None,
472
  [],
473
- gr.update(),
474
- gr.update(),
475
- gr.update(interactive=True),
476
  )
477
- # Optionally re-raise or handle differently
478
  # raise gr.Error(f"Error during presentation setup: {e}")
479
 
480
 
@@ -491,7 +491,7 @@ 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_textbox: gr.update(value=status_update)}
495
 
496
  num_slides = len(state_slides_data)
497
  MAX_SLIDES = 20
@@ -505,7 +505,7 @@ def step2_build_slides(
505
 
506
  progress(0.1, desc="Saving edited markdown...")
507
  status_update = "Saving edited markdown..."
508
- yield {status_textbox: gr.update(value=status_update)}
509
  updated_slides = []
510
  for i in range(num_slides):
511
  updated_slides.append(
@@ -518,20 +518,21 @@ 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_textbox: gr.update(value=status_update)}
 
522
  yield (
523
  gr.update(value=status_update),
524
  None,
525
  [],
526
  gr.update(),
 
527
  gr.update(),
528
- gr.update(),
529
- )
530
  raise gr.Error(f"Failed to save markdown: {e}")
531
 
532
  progress(0.3, desc="Generating PDF...")
533
  status_update = "Generating PDF..."
534
- yield {status_textbox: gr.update(value=status_update)}
535
  pdf_output_path = os.path.join(state_temp_dir, "presentation.pdf")
536
  try:
537
  generated_pdf_path = generate_pdf_from_markdown(state_md_path, pdf_output_path)
@@ -539,7 +540,8 @@ def step2_build_slides(
539
  raise gr.Error("PDF generation failed (check logs).")
540
  except gr.Error as e:
541
  status_update = f"PDF Generation Error: {e}"
542
- yield {status_textbox: gr.update(value=status_update)}
 
543
  yield (
544
  gr.update(value=status_update),
545
  None,
@@ -547,11 +549,12 @@ def step2_build_slides(
547
  gr.update(),
548
  gr.update(visible=True),
549
  gr.update(),
550
- )
551
  raise e
552
  except Exception as e:
553
  status_update = f"Unexpected PDF Error: {e}"
554
- yield {status_textbox: gr.update(value=status_update)}
 
555
  yield (
556
  gr.update(value=status_update),
557
  None,
@@ -559,12 +562,12 @@ def step2_build_slides(
559
  gr.update(),
560
  gr.update(visible=True),
561
  gr.update(),
562
- )
563
  raise gr.Error(f"Unexpected error generating PDF: {e}")
564
 
565
  progress(0.7, desc="Converting PDF to images...")
566
  status_update = "Converting PDF to images..."
567
- yield {status_textbox: gr.update(value=status_update)}
568
  pdf_images = []
569
  try:
570
  pdf_images = convert_pdf_to_images(
@@ -581,7 +584,8 @@ def step2_build_slides(
581
  except Exception as e:
582
  logger.error(f"Error converting PDF to images: {e}", exc_info=True)
583
  status_update = f"Failed to convert PDF to images: {e}"
584
- yield {status_textbox: gr.update(value=status_update)}
 
585
  yield (
586
  gr.update(value=status_update),
587
  generated_pdf_path,
@@ -589,7 +593,7 @@ def step2_build_slides(
589
  gr.update(),
590
  gr.update(visible=True),
591
  gr.update(value=generated_pdf_path, visible=True),
592
- )
593
  # Proceed without images? Or raise error? Let's raise.
594
  raise gr.Error(f"Failed to convert PDF to images: {e}")
595
 
@@ -655,7 +659,7 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
655
 
656
  logger.info(f"Processing {num_slides} slides for audio generation.")
657
  status_update = "Starting Step 3: Generating audio..."
658
- yield {status_textbox: gr.update(value=status_update)}
659
 
660
  audio_dir = os.path.join(state_temp_dir, "audio")
661
  os.makedirs(audio_dir, exist_ok=True)
@@ -665,7 +669,7 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
665
  # but ensures the audio matches the *latest* notes displayed.
666
  progress(0.1, desc="Saving latest notes...")
667
  status_update = "Saving latest notes..."
668
- yield {status_textbox: gr.update(value=status_update)}
669
  updated_slides_data = []
670
  for i in range(num_slides):
671
  updated_slides_data.append(
@@ -685,17 +689,11 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
685
  warning_msg = f"Warning: Could not save latest notes to markdown file: {e}"
686
  gr.Warning(warning_msg)
687
  status_update += f" ({warning_msg})"
688
- yield {status_textbox: gr.update(value=status_update)}
689
- status_update = f"Warning: {warning_msg}"
690
- yield (
691
- gr.update(value=status_update),
692
- None,
693
- [],
694
- gr.update(),
695
- gr.update(visible=True),
696
- gr.update(),
697
- )
698
- raise gr.Error(f"Failed to save updated markdown before audio gen: {e}")
699
 
700
  generated_audio_paths = ["" for _ in range(num_slides)]
701
  audio_generation_failed = False
@@ -710,7 +708,7 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
710
  desc=f"Audio slide {slide_num}/{num_slides}",
711
  )
712
  status_update = f"Generating audio for slide {slide_num}/{num_slides}..."
713
- yield {status_textbox: gr.update(value=status_update)}
714
 
715
  output_file_path = Path(audio_dir) / f"{slide_num}.wav"
716
  if not note_text or not note_text.strip():
@@ -774,6 +772,7 @@ def step3_generate_audio(*args, progress=gr.Progress(track_tqdm=True)):
774
  status_update = f"Step 3 Complete: {info_msg}"
775
 
776
  # Return tuple including status update + original outputs
 
777
  yield (
778
  gr.update(value=status_update),
779
  audio_dir,
@@ -803,7 +802,7 @@ def step4_generate_video(
803
 
804
  video_output_path = os.path.join(state_temp_dir, "final_presentation.mp4")
805
  status_update = "Starting Step 4: Generating video..."
806
- yield {status_textbox: gr.update(value=status_update)}
807
 
808
  progress(0.1, desc="Preparing video components...")
809
  pdf_images = [] # Initialize to ensure cleanup happens
@@ -820,7 +819,7 @@ def step4_generate_video(
820
  # Convert PDF to images
821
  progress(0.2, desc="Converting PDF to images...")
822
  status_update = "Converting PDF back to images for video..."
823
- yield {status_textbox: gr.update(value=status_update)}
824
  pdf_images = convert_pdf_to_images(state_pdf_path, dpi=150)
825
  if not pdf_images:
826
  raise gr.Error(f"Failed to convert PDF ({state_pdf_path}) to images.")
@@ -832,12 +831,12 @@ def step4_generate_video(
832
  logger.warning(warning_msg)
833
  status_update += f" ({warning_msg})"
834
  # yield status_update # Old yield
835
- yield {status_textbox: gr.update(value=status_update)}
836
 
837
  progress(0.5, desc="Creating individual video clips...")
838
  status_update = "Creating individual video clips..."
839
  # yield status_update # Old yield
840
- yield {status_textbox: gr.update(value=status_update)}
841
  buffer_seconds = 1.0
842
  output_fps = 10
843
  video_clips = create_video_clips(
@@ -850,7 +849,7 @@ def step4_generate_video(
850
  progress(0.8, desc="Concatenating clips...")
851
  status_update = "Concatenating clips into final video..."
852
  # yield status_update # Old yield
853
- yield {status_textbox: gr.update(value=status_update)}
854
  concatenate_clips(video_clips, video_output_path, output_fps)
855
 
856
  logger.info(f"Video concatenation complete: {video_output_path}")
@@ -858,7 +857,7 @@ def step4_generate_video(
858
  progress(0.95, desc="Cleaning up temp images...")
859
  status_update = "Cleaning up temporary image files..."
860
  # yield status_update # Old yield
861
- yield {status_textbox: gr.update(value=status_update)}
862
  cleanup_temp_files(pdf_images) # Pass the list of image paths
863
 
864
  except Exception as e:
@@ -866,8 +865,13 @@ def step4_generate_video(
866
  cleanup_temp_files(pdf_images)
867
  logger.error(f"Video generation failed: {e}", exc_info=True)
868
  status_update = f"Video generation failed: {e}"
869
- yield {status_textbox: gr.update(value=status_update)}
870
- yield (gr.update(value=status_update), gr.update(), gr.update(visible=True))
 
 
 
 
 
871
  raise gr.Error(f"Video generation failed: {e}")
872
 
873
  info_msg = f"Video generated: {os.path.basename(video_output_path)}"
@@ -1132,10 +1136,11 @@ with gr.Blocks(
1132
  show_progress="full",
1133
  ).then(
1134
  fn=lambda s_data: (
1135
- gr.update(value="Editor populated. Proceed to Step 2.") # Update status
1136
- )
1137
- + tuple(
1138
- [
 
1139
  upd
1140
  for i, slide in enumerate(s_data)
1141
  if i < MAX_SLIDES
@@ -1157,8 +1162,8 @@ with gr.Blocks(
1157
  upd
1158
  for i in range(len(s_data), MAX_SLIDES)
1159
  for upd in [gr.update(visible=False)] * 7
1160
- ]
1161
- ), # Keep editor updates
1162
  inputs=[state_slides_data],
1163
  outputs=[status_textbox] + all_editor_components, # Add status_textbox output
1164
  show_progress="hidden",
@@ -1185,17 +1190,18 @@ with gr.Blocks(
1185
  show_progress="full",
1186
  ).then(
1187
  fn=lambda image_paths: (
1188
- gr.update(value="Slide images updated. Proceed to Step 3.") # Update status
1189
- )
1190
- + tuple(
1191
- [
 
1192
  gr.update(
1193
  value=image_paths[i] if i < len(image_paths) else None,
1194
  visible=(i < len(image_paths)),
1195
  )
1196
  for i in range(MAX_SLIDES)
1197
- ]
1198
- ), # Keep image updates
1199
  inputs=[state_pdf_image_paths],
1200
  outputs=[status_textbox] + all_slide_images, # Add status_textbox output
1201
  show_progress="hidden",
@@ -1223,12 +1229,13 @@ with gr.Blocks(
1223
  outputs=step3_outputs,
1224
  show_progress="full",
1225
  ).then(
1226
- lambda: (
1227
  gr.update(value="Audio generated. Proceed to Step 4."),
1228
  gr.update(selected=3),
1229
- ), # Update status and switch tab
1230
- outputs=[status_textbox, tabs_widget], # Add status_textbox output
1231
- show_progress="hidden", # Hide progress for simple status update + tab switch
 
1232
  )
1233
 
1234
  # Step 4 Click Handler
 
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
  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 (
347
  gr.update(value=status_update),
348
  temp_dir,
 
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
 
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
 
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
453
  yield (
454
  gr.update(value=status_update),
455
  temp_dir,
 
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),
470
  None,
471
  None,
472
  [],
473
+ gr.update(visible=False), # Keep editor hidden
474
+ gr.update(visible=False), # Keep build button hidden
475
+ gr.update(interactive=True), # Re-enable fetch button
476
  )
477
+ # Do not re-raise if we want the Gradio app to stay alive
478
  # raise gr.Error(f"Error during presentation setup: {e}")
479
 
480
 
 
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
 
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
  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),
525
  None,
526
  [],
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
  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),
547
  None,
 
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),
560
  None,
 
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
  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),
591
  generated_pdf_path,
 
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
 
 
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
  # 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
  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)
696
+ # raise gr.Error(f"Failed to save updated markdown before audio gen: {e}") # Old raise
 
 
 
 
 
 
697
 
698
  generated_audio_paths = ["" for _ in range(num_slides)]
699
  audio_generation_failed = False
 
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():
 
772
  status_update = f"Step 3 Complete: {info_msg}"
773
 
774
  # Return tuple including status update + original outputs
775
+ # Final yield must match outputs list
776
  yield (
777
  gr.update(value=status_update),
778
  audio_dir,
 
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
  # 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
  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
  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
  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
  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)}"
 
1136
  show_progress="full",
1137
  ).then(
1138
  fn=lambda s_data: (
1139
+ gr.update(
1140
+ value="Editor populated. Proceed to Step 2."
1141
+ ), # Status update first
1142
+ # Then unpack the list/tuple of editor updates
1143
+ *[
1144
  upd
1145
  for i, slide in enumerate(s_data)
1146
  if i < MAX_SLIDES
 
1162
  upd
1163
  for i in range(len(s_data), MAX_SLIDES)
1164
  for upd in [gr.update(visible=False)] * 7
1165
+ ],
1166
+ ), # Correctly construct the output tuple
1167
  inputs=[state_slides_data],
1168
  outputs=[status_textbox] + all_editor_components, # Add status_textbox output
1169
  show_progress="hidden",
 
1190
  show_progress="full",
1191
  ).then(
1192
  fn=lambda image_paths: (
1193
+ gr.update(
1194
+ value="Slide images updated. Proceed to Step 3."
1195
+ ), # Status update first
1196
+ # Then unpack the list/tuple of image updates
1197
+ *[
1198
  gr.update(
1199
  value=image_paths[i] if i < len(image_paths) else None,
1200
  visible=(i < len(image_paths)),
1201
  )
1202
  for i in range(MAX_SLIDES)
1203
+ ],
1204
+ ), # Correctly construct the output tuple
1205
  inputs=[state_pdf_image_paths],
1206
  outputs=[status_textbox] + all_slide_images, # Add status_textbox output
1207
  show_progress="hidden",
 
1229
  outputs=step3_outputs,
1230
  show_progress="full",
1231
  ).then(
1232
+ fn=lambda: (
1233
  gr.update(value="Audio generated. Proceed to Step 4."),
1234
  gr.update(selected=3),
1235
+ ), # Status update is handled by the main function yield now
1236
+ # No inputs needed for this simple status update + tab switch
1237
+ outputs=[status_textbox, tabs_widget],
1238
+ show_progress="hidden",
1239
  )
1240
 
1241
  # Step 4 Click Handler