Jaward commited on
Commit
ff871df
·
verified ·
1 Parent(s): 878a2e5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -90
app.py CHANGED
@@ -338,30 +338,30 @@ async def update_audio_preview(audio_file):
338
  return None
339
 
340
  # Async function to generate lecture materials and audio
341
- async def on_generate(api_service, api_key, serpapi_key, title, topic, instructions, lecture_type, speaker_audio, num_slides):
342
  if not serpapi_key:
343
- yield {
344
- "html": f"""
345
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
346
  <h2 style="color: #d9534f;">SerpApi key required</h2>
347
  <p style="margin-top: 20px;">Please provide a valid SerpApi key and try again.</p>
348
  </div>
349
  """,
350
- "files": []
351
- }
352
  return
353
 
354
  if tts is None:
355
- yield {
356
- "html": f"""
357
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
358
  <h2 style="color: #d9534f;">TTS model initialization failed</h2>
359
  <p style="margin-top: 20px;">The TTS model failed to initialize at startup.</p>
360
  <p>Please ensure the Coqui TTS model is properly installed and try restarting the application.</p>
361
  </div>
362
  """,
363
- "files": []
364
- }
365
  return
366
 
367
  model_client = get_model_client(api_service, api_key)
@@ -424,21 +424,21 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
424
 
425
  progress = 0
426
  label = "Research: in progress..."
427
- yield {
428
- "html": html_with_progress(label, progress),
429
- "files": []
430
- }
431
  await asyncio.sleep(0.1)
432
 
433
  initial_message = f"""
434
  Lecture Title: {title}
435
- Topic: {topic}
436
  Additional Instructions: {instructions}
437
  Audience: {lecture_type}
438
  Number of Slides: {total_slides}
439
  Please start by researching the topic.
440
  """
441
- logger.info("Starting lecture generation for topic: %s with %d slides", topic, total_slides)
442
 
443
  slides = None
444
  scripts = None
@@ -467,10 +467,10 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
467
  if source == "research_agent" and message.target == "slide_agent":
468
  progress = 25
469
  label = "Slides: generating..."
470
- yield {
471
- "html": html_with_progress(label, progress),
472
- "files": []
473
- }
474
  await asyncio.sleep(0.1)
475
  elif source == "slide_agent" and message.target == "script_agent":
476
  if slides is None:
@@ -492,10 +492,10 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
492
  continue
493
  progress = 50
494
  label = "Scripts: generating..."
495
- yield {
496
- "html": html_with_progress(label, progress),
497
- "files": []
498
- }
499
  await asyncio.sleep(0.1)
500
  elif source == "script_agent" and message.target == "feynman_agent":
501
  if scripts is None:
@@ -506,20 +506,20 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
506
  logger.info("Extracted scripts JSON from HandoffMessage context: %s", scripts)
507
  progress = 75
508
  label = "Review: in progress..."
509
- yield {
510
- "html": html_with_progress(label, progress),
511
- "files": []
512
- }
513
  await asyncio.sleep(0.1)
514
 
515
  elif source == "research_agent" and isinstance(message, TextMessage) and "handoff_to_slide_agent" in message.content:
516
  logger.info("Research Agent completed research")
517
  progress = 25
518
  label = "Slides: generating..."
519
- yield {
520
- "html": html_with_progress(label, progress),
521
- "files": []
522
- }
523
  await asyncio.sleep(0.1)
524
 
525
  elif source == "slide_agent" and isinstance(message, (TextMessage, StructuredMessage)):
@@ -549,10 +549,10 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
549
  logger.error("Error saving slide content to %s: %s", content_file, str(e))
550
  progress = 50
551
  label = "Scripts: generating..."
552
- yield {
553
- "html": html_with_progress(label, progress),
554
- "files": []
555
- }
556
  await asyncio.sleep(0.1)
557
  else:
558
  logger.warning("No JSON extracted from slide_agent message")
@@ -583,10 +583,10 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
583
  logger.error("Error saving raw script to %s: %s", script_file, str(e))
584
  progress = 75
585
  label = "Scripts generated and saved. Reviewing..."
586
- yield {
587
- "html": html_with_progress(label, progress),
588
- "files": []
589
- }
590
  await asyncio.sleep(0.1)
591
  else:
592
  logger.warning("No JSON extracted from script_agent message")
@@ -605,10 +605,10 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
605
  logger.info("Feynman Agent completed lecture review: %s", message.content)
606
  progress = 90
607
  label = "Lecture materials ready. Generating audio..."
608
- yield {
609
- "html": html_with_progress(label, progress),
610
- "files": []
611
- }
612
  await asyncio.sleep(0.1)
613
 
614
  logger.info("Slides state: %s", "Generated" if slides else "None")
@@ -621,83 +621,83 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
621
  for msg in task_result.messages:
622
  source = getattr(msg, 'source', getattr(msg, 'sender', None))
623
  logger.debug("Message from %s, type: %s, content: %s", source, type(msg), msg.to_text() if hasattr(msg, 'to_text') else str(msg))
624
- yield {
625
- "html": f"""
626
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
627
  <h2 style="color: #d9534f;">{error_message}</h2>
628
  <p style="margin-top: 20px;">Please try again with a different model (e.g., Anthropic-claude-3-sonnet-20240229) or simplify the topic/instructions.</p>
629
  </div>
630
  """,
631
- "files": []
632
- }
633
  return
634
 
635
  if len(slides) != total_slides:
636
  logger.error("Expected %d slides, but received %d", total_slides, len(slides))
637
- yield {
638
- "html": f"""
639
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
640
  <h2 style="color: #d9534f;">Incorrect number of slides</h2>
641
  <p style="margin-top: 20px;">Expected {total_slides} slides, but generated {len(slides)}. Please try again.</p>
642
  </div>
643
  """,
644
- "files": []
645
- }
646
  return
647
 
648
  if not isinstance(scripts, list) or not all(isinstance(s, str) for s in scripts):
649
  logger.error("Scripts are not a list of strings: %s", scripts)
650
- yield {
651
- "html": f"""
652
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
653
  <h2 style="color: #d9534f;">Invalid script format</h2>
654
  <p style="margin-top: 20px;">Scripts must be a list of strings. Please try again.</p>
655
  </div>
656
  """,
657
- "files": []
658
- }
659
  return
660
 
661
  if len(scripts) != total_slides:
662
  logger.error("Mismatch between number of slides (%d) and scripts (%d)", len(slides), len(scripts))
663
- yield {
664
- "html": f"""
665
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
666
  <h2 style="color: #d9534f;">Mismatch in slides and scripts</h2>
667
  <p style="margin-top: 20px;">Generated {len(slides)} slides but {len(scripts)} scripts. Please try again.</p>
668
  </div>
669
  """,
670
- "files": []
671
- }
672
  return
673
 
674
  markdown_slides = generate_markdown_slides(slides, title)
675
  if not markdown_slides:
676
  logger.error("Failed to generate Markdown slides")
677
- yield {
678
- "html": f"""
679
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
680
  <h2 style="color: #d9534f;">Failed to generate slides</h2>
681
  <p style="margin-top: 20px;">Please try again.</p>
682
  </div>
683
  """,
684
- "files": []
685
- }
686
  return
687
 
688
  audio_files = []
689
  validated_speaker_wav = await validate_and_convert_speaker_audio(speaker_audio)
690
  if not validated_speaker_wav:
691
  logger.error("Invalid speaker audio after conversion, skipping TTS")
692
- yield {
693
- "html": f"""
694
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
695
  <h2 style="color: #d9534f;">Invalid speaker audio</h2>
696
  <p style="margin-top: 20px;">Please upload a valid MP3 or WAV audio file and try again.</p>
697
  </div>
698
  """,
699
- "files": []
700
- }
701
  return
702
 
703
  for i, script in enumerate(scripts):
@@ -717,10 +717,10 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
717
  audio_files.append(None)
718
  progress = 90 + ((i + 1) / len(scripts)) * 10
719
  label = f"Generating speech for slide {i + 1}/{len(scripts)}..."
720
- yield {
721
- "html": html_with_progress(label, progress),
722
- "files": []
723
- }
724
  await asyncio.sleep(0.1)
725
  continue
726
 
@@ -742,10 +742,10 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
742
  audio_files.append(audio_file)
743
  progress = 90 + ((i + 1) / len(scripts)) * 10
744
  label = f"Generated audio for slide {i + 1}/{len(scripts)}..."
745
- yield {
746
- "html": html_with_progress(label, progress),
747
- "files": []
748
- }
749
  await asyncio.sleep(0.1)
750
  break
751
  except Exception as e:
@@ -755,10 +755,10 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
755
  audio_files.append(None)
756
  progress = 90 + ((i + 1) / len(scripts)) * 10
757
  label = f"Generated audio for slide {i + 1}/{len(scripts)}..."
758
- yield {
759
- "html": html_with_progress(label, progress),
760
- "files": []
761
- }
762
  await asyncio.sleep(0.1)
763
  break
764
 
@@ -893,23 +893,23 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
893
  </script>
894
  """
895
  logger.info("Lecture generation completed successfully")
896
- yield {
897
- "html": html_output,
898
- "files": txt_file_paths
899
- }
900
 
901
  except Exception as e:
902
  logger.error("Error during lecture generation: %s\n%s", str(e), traceback.format_exc())
903
- yield {
904
- "html": f"""
905
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
906
  <h2 style="color: #d9534f;">Error during lecture generation</h2>
907
  <p style="margin-top: 10px; font-size: 16px;">{str(e)}</p>
908
  <p style="margin-top: 20px;">Please try again or adjust your inputs.</p>
909
  </div>
910
  """,
911
- "files": []
912
- }
913
  return
914
 
915
  # Gradio interface
@@ -919,8 +919,8 @@ with gr.Blocks(title="Agent Feynman") as demo:
919
  with gr.Column(scale=1):
920
  with gr.Group():
921
  title = gr.Textbox(label="Lecture Title", placeholder="e.g. Introduction to AI")
922
- topic = gr.Textbox(label="Topic", placeholder="e.g. Artificial Intelligence")
923
- instructions = gr.Textbox(label="Additional Instructions", placeholder="e.g. Focus on recent advancements")
924
  lecture_type = gr.Dropdown(["Conference", "University", "High school"], label="Audience", value="University")
925
  api_service = gr.Dropdown(
926
  choices=[
@@ -955,7 +955,7 @@ with gr.Blocks(title="Agent Feynman") as demo:
955
 
956
  generate_btn.click(
957
  fn=on_generate,
958
- inputs=[api_service, api_key, serpapi_key, title, topic, instructions, lecture_type, speaker_audio, num_slides],
959
  outputs=[slide_display, file_output]
960
  )
961
 
 
338
  return None
339
 
340
  # Async function to generate lecture materials and audio
341
+ async def on_generate(api_service, api_key, serpapi_key, title, lecture_content_description, instructions, lecture_type, speaker_audio, num_slides):
342
  if not serpapi_key:
343
+ yield (
344
+ f"""
345
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
346
  <h2 style="color: #d9534f;">SerpApi key required</h2>
347
  <p style="margin-top: 20px;">Please provide a valid SerpApi key and try again.</p>
348
  </div>
349
  """,
350
+ []
351
+ )
352
  return
353
 
354
  if tts is None:
355
+ yield (
356
+ f"""
357
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
358
  <h2 style="color: #d9534f;">TTS model initialization failed</h2>
359
  <p style="margin-top: 20px;">The TTS model failed to initialize at startup.</p>
360
  <p>Please ensure the Coqui TTS model is properly installed and try restarting the application.</p>
361
  </div>
362
  """,
363
+ []
364
+ )
365
  return
366
 
367
  model_client = get_model_client(api_service, api_key)
 
424
 
425
  progress = 0
426
  label = "Research: in progress..."
427
+ yield (
428
+ html_with_progress(label, progress),
429
+ []
430
+ )
431
  await asyncio.sleep(0.1)
432
 
433
  initial_message = f"""
434
  Lecture Title: {title}
435
+ Lecture Content Description: {lecture_content_description}
436
  Additional Instructions: {instructions}
437
  Audience: {lecture_type}
438
  Number of Slides: {total_slides}
439
  Please start by researching the topic.
440
  """
441
+ logger.info("Starting lecture generation for title: %s with %d slides", title, total_slides)
442
 
443
  slides = None
444
  scripts = None
 
467
  if source == "research_agent" and message.target == "slide_agent":
468
  progress = 25
469
  label = "Slides: generating..."
470
+ yield (
471
+ html_with_progress(label, progress),
472
+ []
473
+ )
474
  await asyncio.sleep(0.1)
475
  elif source == "slide_agent" and message.target == "script_agent":
476
  if slides is None:
 
492
  continue
493
  progress = 50
494
  label = "Scripts: generating..."
495
+ yield (
496
+ html_with_progress(label, progress),
497
+ []
498
+ )
499
  await asyncio.sleep(0.1)
500
  elif source == "script_agent" and message.target == "feynman_agent":
501
  if scripts is None:
 
506
  logger.info("Extracted scripts JSON from HandoffMessage context: %s", scripts)
507
  progress = 75
508
  label = "Review: in progress..."
509
+ yield (
510
+ html_with_progress(label, progress),
511
+ []
512
+ )
513
  await asyncio.sleep(0.1)
514
 
515
  elif source == "research_agent" and isinstance(message, TextMessage) and "handoff_to_slide_agent" in message.content:
516
  logger.info("Research Agent completed research")
517
  progress = 25
518
  label = "Slides: generating..."
519
+ yield (
520
+ html_with_progress(label, progress),
521
+ []
522
+ )
523
  await asyncio.sleep(0.1)
524
 
525
  elif source == "slide_agent" and isinstance(message, (TextMessage, StructuredMessage)):
 
549
  logger.error("Error saving slide content to %s: %s", content_file, str(e))
550
  progress = 50
551
  label = "Scripts: generating..."
552
+ yield (
553
+ html_with_progress(label, progress),
554
+ []
555
+ )
556
  await asyncio.sleep(0.1)
557
  else:
558
  logger.warning("No JSON extracted from slide_agent message")
 
583
  logger.error("Error saving raw script to %s: %s", script_file, str(e))
584
  progress = 75
585
  label = "Scripts generated and saved. Reviewing..."
586
+ yield (
587
+ html_with_progress(label, progress),
588
+ []
589
+ )
590
  await asyncio.sleep(0.1)
591
  else:
592
  logger.warning("No JSON extracted from script_agent message")
 
605
  logger.info("Feynman Agent completed lecture review: %s", message.content)
606
  progress = 90
607
  label = "Lecture materials ready. Generating audio..."
608
+ yield (
609
+ html_with_progress(label, progress),
610
+ []
611
+ )
612
  await asyncio.sleep(0.1)
613
 
614
  logger.info("Slides state: %s", "Generated" if slides else "None")
 
621
  for msg in task_result.messages:
622
  source = getattr(msg, 'source', getattr(msg, 'sender', None))
623
  logger.debug("Message from %s, type: %s, content: %s", source, type(msg), msg.to_text() if hasattr(msg, 'to_text') else str(msg))
624
+ yield (
625
+ f"""
626
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
627
  <h2 style="color: #d9534f;">{error_message}</h2>
628
  <p style="margin-top: 20px;">Please try again with a different model (e.g., Anthropic-claude-3-sonnet-20240229) or simplify the topic/instructions.</p>
629
  </div>
630
  """,
631
+ []
632
+ )
633
  return
634
 
635
  if len(slides) != total_slides:
636
  logger.error("Expected %d slides, but received %d", total_slides, len(slides))
637
+ yield (
638
+ f"""
639
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
640
  <h2 style="color: #d9534f;">Incorrect number of slides</h2>
641
  <p style="margin-top: 20px;">Expected {total_slides} slides, but generated {len(slides)}. Please try again.</p>
642
  </div>
643
  """,
644
+ []
645
+ )
646
  return
647
 
648
  if not isinstance(scripts, list) or not all(isinstance(s, str) for s in scripts):
649
  logger.error("Scripts are not a list of strings: %s", scripts)
650
+ yield (
651
+ f"""
652
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
653
  <h2 style="color: #d9534f;">Invalid script format</h2>
654
  <p style="margin-top: 20px;">Scripts must be a list of strings. Please try again.</p>
655
  </div>
656
  """,
657
+ []
658
+ )
659
  return
660
 
661
  if len(scripts) != total_slides:
662
  logger.error("Mismatch between number of slides (%d) and scripts (%d)", len(slides), len(scripts))
663
+ yield (
664
+ f"""
665
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
666
  <h2 style="color: #d9534f;">Mismatch in slides and scripts</h2>
667
  <p style="margin-top: 20px;">Generated {len(slides)} slides but {len(scripts)} scripts. Please try again.</p>
668
  </div>
669
  """,
670
+ []
671
+ )
672
  return
673
 
674
  markdown_slides = generate_markdown_slides(slides, title)
675
  if not markdown_slides:
676
  logger.error("Failed to generate Markdown slides")
677
+ yield (
678
+ f"""
679
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
680
  <h2 style="color: #d9534f;">Failed to generate slides</h2>
681
  <p style="margin-top: 20px;">Please try again.</p>
682
  </div>
683
  """,
684
+ []
685
+ )
686
  return
687
 
688
  audio_files = []
689
  validated_speaker_wav = await validate_and_convert_speaker_audio(speaker_audio)
690
  if not validated_speaker_wav:
691
  logger.error("Invalid speaker audio after conversion, skipping TTS")
692
+ yield (
693
+ f"""
694
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
695
  <h2 style="color: #d9534f;">Invalid speaker audio</h2>
696
  <p style="margin-top: 20px;">Please upload a valid MP3 or WAV audio file and try again.</p>
697
  </div>
698
  """,
699
+ []
700
+ )
701
  return
702
 
703
  for i, script in enumerate(scripts):
 
717
  audio_files.append(None)
718
  progress = 90 + ((i + 1) / len(scripts)) * 10
719
  label = f"Generating speech for slide {i + 1}/{len(scripts)}..."
720
+ yield (
721
+ html_with_progress(label, progress),
722
+ []
723
+ )
724
  await asyncio.sleep(0.1)
725
  continue
726
 
 
742
  audio_files.append(audio_file)
743
  progress = 90 + ((i + 1) / len(scripts)) * 10
744
  label = f"Generated audio for slide {i + 1}/{len(scripts)}..."
745
+ yield (
746
+ html_with_progress(label, progress),
747
+ []
748
+ )
749
  await asyncio.sleep(0.1)
750
  break
751
  except Exception as e:
 
755
  audio_files.append(None)
756
  progress = 90 + ((i + 1) / len(scripts)) * 10
757
  label = f"Generated audio for slide {i + 1}/{len(scripts)}..."
758
+ yield (
759
+ html_with_progress(label, progress),
760
+ []
761
+ )
762
  await asyncio.sleep(0.1)
763
  break
764
 
 
893
  </script>
894
  """
895
  logger.info("Lecture generation completed successfully")
896
+ yield (
897
+ html_output,
898
+ txt_file_paths
899
+ )
900
 
901
  except Exception as e:
902
  logger.error("Error during lecture generation: %s\n%s", str(e), traceback.format_exc())
903
+ yield (
904
+ f"""
905
  <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100%; min-height: 700px; padding: 20px; text-align: center; border: 1px solid #ddd; border-radius: 8px;">
906
  <h2 style="color: #d9534f;">Error during lecture generation</h2>
907
  <p style="margin-top: 10px; font-size: 16px;">{str(e)}</p>
908
  <p style="margin-top: 20px;">Please try again or adjust your inputs.</p>
909
  </div>
910
  """,
911
+ []
912
+ )
913
  return
914
 
915
  # Gradio interface
 
919
  with gr.Column(scale=1):
920
  with gr.Group():
921
  title = gr.Textbox(label="Lecture Title", placeholder="e.g. Introduction to AI")
922
+ lecture_content_description = gr.Textbox(label="Lecture Content Description", placeholder="e.g. Focus on recent advancements")
923
+ instructions = gr.Textbox(label="Additional Instructions", placeholder="e.g. Include examples")
924
  lecture_type = gr.Dropdown(["Conference", "University", "High school"], label="Audience", value="University")
925
  api_service = gr.Dropdown(
926
  choices=[
 
955
 
956
  generate_btn.click(
957
  fn=on_generate,
958
+ inputs=[api_service, api_key, serpapi_key, title, lecture_content_description, instructions, lecture_type, speaker_audio, num_slides],
959
  outputs=[slide_display, file_output]
960
  )
961