Jaward commited on
Commit
7aeec26
·
verified ·
1 Parent(s): ff871df

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -95
app.py CHANGED
@@ -72,11 +72,11 @@ def search_web(query: str, serpapi_key: str) -> str:
72
 
73
  if "error" in results:
74
  logger.error("SerpApi error: %s", results["error"])
75
- return f"Error during search: {results['error']}"
76
 
77
  if "organic_results" not in results or not results["organic_results"]:
78
  logger.info("No search results found for query: %s", query)
79
- return f"No results found for query: {query}"
80
 
81
  formatted_results = []
82
  for item in results["organic_results"][:5]:
@@ -87,11 +87,11 @@ def search_web(query: str, serpapi_key: str) -> str:
87
 
88
  formatted_output = "\n".join(formatted_results)
89
  logger.info("Successfully retrieved search results for query: %s", query)
90
- return f"Search results for {query}:\n{formatted_output}"
91
 
92
  except Exception as e:
93
  logger.error("Unexpected error during search: %s", str(e))
94
- return f"Unexpected error during search: {str(e)}"
95
 
96
  # Define helper function for progress HTML
97
  def html_with_progress(label, progress):
@@ -338,32 +338,7 @@ 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, 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)
368
 
369
  total_slides = num_slides # Use exactly the number of slides from input
@@ -433,10 +408,9 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
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
 
@@ -451,7 +425,11 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
451
 
452
  try:
453
  logger.info("Research Agent starting...")
454
- task_result = await Console(swarm.run_stream(task=initial_message))
 
 
 
 
455
  logger.info("Swarm execution completed")
456
 
457
  slide_retry_count = 0
@@ -574,13 +552,13 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
574
  scripts = extracted_json
575
  logger.info("Script Agent generated scripts for %d slides", len(scripts))
576
  for i, script in enumerate(scripts):
577
- script_file = os.path.join(OUTPUT_DIR, f"slide_{i+1}_raw_script.txt")
578
  try:
579
  with open(script_file, "w", encoding="utf-8") as f:
580
  f.write(script)
581
- logger.info("Saved raw script to %s", script_file)
582
  except Exception as e:
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 (
@@ -625,7 +603,7 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
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
  []
@@ -708,15 +686,15 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
708
  try:
709
  with open(script_file, "w", encoding="utf-8") as f:
710
  f.write(cleaned_script or "")
711
- logger.info("Saved cleaned script to %s: %s", script_file, cleaned_script)
712
  except Exception as e:
713
- logger.error("Error saving cleaned script to %s: %s", script_file, str(e))
714
 
715
  if not cleaned_script:
716
  logger.error("Skipping audio for slide %d due to empty or invalid script", i + 1)
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
  []
@@ -770,10 +748,10 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
770
  # Generate audio timeline with playable audio elements
771
  audio_timeline = ""
772
  for i, audio_file in enumerate(audio_files):
773
- if audio_file:
774
- audio_timeline += f'<audio id="audio-{i+1}" controls src="{audio_file}" style="margin: 0 5px;"></audio>'
775
  else:
776
- audio_timeline += f'<span id="audio-{i+1}" style="margin: 0 5px;">slide_{i+1}.mp3 (not generated)</span>'
777
 
778
  slides_info = json.dumps({"slides": markdown_slides, "audioFiles": audio_files})
779
 
@@ -782,8 +760,8 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
782
  <div id="slide-content" style="flex: 1; overflow: auto; padding: 20px; text-align: center;">
783
  <!-- Slides will be rendered here -->
784
  </div>
785
- <div style="padding: 20px;">
786
- <div style="text-align: center; margin-bottom: 10px;">
787
  {audio_timeline}
788
  </div>
789
  <div style="display: flex; justify-content: center; margin-bottom: 10px;">
@@ -799,16 +777,19 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
799
  let currentSlide = 0;
800
  const totalSlides = lectureData.slides.length;
801
  let audioElements = [];
802
- let isPlayingAll = false;
803
 
804
  for (let i = 0; i < totalSlides; i++) {{
805
- const audio = document.getElementById(`audio-${{i+1}}`);
806
  audioElements.push(audio);
807
  }}
808
 
809
  function renderSlide() {{
810
  const slideContent = document.getElementById('slide-content');
811
- slideContent.innerHTML = lectureData.slides[currentSlide];
 
 
 
 
812
  }}
813
 
814
  function updateSlide() {{
@@ -836,51 +817,27 @@ Example: 'Received {total_slides} slides and {total_slides} scripts. Lecture is
836
  }}
837
 
838
  function playAll() {{
839
- if (isPlayingAll) {{
840
- audioElements.forEach(audio => {{
841
- if (audio && audio.pause) audio.pause();
842
- }});
843
- isPlayingAll = false;
844
- document.getElementById('play-btn').innerText = '⏯';
845
- return;
846
- }}
847
-
848
- isPlayingAll = true;
849
- document.getElementById('play-btn').innerText = '⏸';
850
- currentSlide = 0;
851
- updateSlide();
852
- playCurrentSlide();
853
- }}
854
-
855
- function playCurrentSlide() {{
856
- if (!isPlayingAll || currentSlide >= totalSlides) {{
857
- isPlayingAll = false;
858
- document.getElementById('play-btn').innerText = '⏯';
859
- return;
860
- }}
861
-
862
- const audio = audioElements[currentSlide];
863
- if (audio && audio.play) {{
864
- audio.play().then(() => {{
865
- audio.addEventListener('ended', () => {{
866
- currentSlide++;
867
- if (currentSlide < totalSlides) {{
868
- updateSlide();
869
- playCurrentSlide();
870
- }} else {{
871
- isPlayingAll = false;
872
- document.getElementById('play-btn').innerText = '⏯';
873
- }}
874
- }}, {{ once: true }});
875
- }}).catch(e => {{
876
- console.error('Audio play failed:', e);
877
- currentSlide++;
878
- playCurrentSlide();
879
- }});
880
- }} else {{
881
- currentSlide++;
882
- playCurrentSlide();
883
  }}
 
884
  }}
885
 
886
  // Attach event listeners
@@ -920,7 +877,6 @@ with gr.Blocks(title="Agent Feynman") as demo:
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=[
@@ -933,7 +889,7 @@ with gr.Blocks(title="Agent Feynman") as demo:
933
  value="Google-gemini-1.5-flash"
934
  )
935
  api_key = gr.Textbox(label="Model Provider API Key", type="password", placeholder="Not required for Ollama")
936
- serpapi_key = gr.Textbox(label="SerpApi Key", type="password", placeholder="Enter your SerpApi key")
937
  num_slides = gr.Slider(1, 20, step=1, label="Number of Slides", value=3)
938
  speaker_audio = gr.Audio(label="Speaker sample audio (MP3 or WAV)", type="filepath", elem_id="speaker-audio")
939
  generate_btn = gr.Button("Generate Lecture")
@@ -955,7 +911,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, lecture_content_description, instructions, lecture_type, speaker_audio, num_slides],
959
  outputs=[slide_display, file_output]
960
  )
961
 
 
72
 
73
  if "error" in results:
74
  logger.error("SerpApi error: %s", results["error"])
75
+ return None
76
 
77
  if "organic_results" not in results or not results["organic_results"]:
78
  logger.info("No search results found for query: %s", query)
79
+ return None
80
 
81
  formatted_results = []
82
  for item in results["organic_results"][:5]:
 
87
 
88
  formatted_output = "\n".join(formatted_results)
89
  logger.info("Successfully retrieved search results for query: %s", query)
90
+ return formatted_output
91
 
92
  except Exception as e:
93
  logger.error("Unexpected error during search: %s", str(e))
94
+ return None
95
 
96
  # Define helper function for progress HTML
97
  def html_with_progress(label, progress):
 
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, lecture_type, speaker_audio, num_slides):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  model_client = get_model_client(api_service, api_key)
343
 
344
  total_slides = num_slides # Use exactly the number of slides from input
 
408
  initial_message = f"""
409
  Lecture Title: {title}
410
  Lecture Content Description: {lecture_content_description}
 
411
  Audience: {lecture_type}
412
  Number of Slides: {total_slides}
413
+ Please start by researching the topic, or proceed without research if search is unavailable.
414
  """
415
  logger.info("Starting lecture generation for title: %s with %d slides", title, total_slides)
416
 
 
425
 
426
  try:
427
  logger.info("Research Agent starting...")
428
+ if serpapi_key:
429
+ task_result = await Console(swarm.run_stream(task=initial_message))
430
+ else:
431
+ logger.warning("No SerpApi key provided, bypassing research phase")
432
+ task_result = await Console(swarm.run_stream(task=f"{initial_message}\nNo search available, proceed with slide generation."))
433
  logger.info("Swarm execution completed")
434
 
435
  slide_retry_count = 0
 
552
  scripts = extracted_json
553
  logger.info("Script Agent generated scripts for %d slides", len(scripts))
554
  for i, script in enumerate(scripts):
555
+ script_file = os.path.join(OUTPUT_DIR, f"slide_{i+1}_script.txt")
556
  try:
557
  with open(script_file, "w", encoding="utf-8") as f:
558
  f.write(script)
559
+ logger.info("Saved script to %s", script_file)
560
  except Exception as e:
561
+ logger.error("Error saving script to %s: %s", script_file, str(e))
562
  progress = 75
563
  label = "Scripts generated and saved. Reviewing..."
564
  yield (
 
603
  f"""
604
  <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;">
605
  <h2 style="color: #d9534f;">{error_message}</h2>
606
+ <p style="margin-top: 20px;">Please try again with a different model or adjust your inputs.</p>
607
  </div>
608
  """,
609
  []
 
686
  try:
687
  with open(script_file, "w", encoding="utf-8") as f:
688
  f.write(cleaned_script or "")
689
+ logger.info("Saved script to %s: %s", script_file, cleaned_script)
690
  except Exception as e:
691
+ logger.error("Error saving script to %s: %s", script_file, str(e))
692
 
693
  if not cleaned_script:
694
  logger.error("Skipping audio for slide %d due to empty or invalid script", i + 1)
695
  audio_files.append(None)
696
  progress = 90 + ((i + 1) / len(scripts)) * 10
697
+ label = f"Generated speech for slide {i + 1}/{len(scripts)}..."
698
  yield (
699
  html_with_progress(label, progress),
700
  []
 
748
  # Generate audio timeline with playable audio elements
749
  audio_timeline = ""
750
  for i, audio_file in enumerate(audio_files):
751
+ if audio_file and os.path.exists(audio_file):
752
+ audio_timeline += f'<audio id="audio-{i+1}" controls src="file://{audio_file}" style="display: inline-block; margin: 0 10px; width: 200px;"></audio>'
753
  else:
754
+ audio_timeline += f'<span id="audio-{i+1}" style="display: inline-block; margin: 0 10px;">slide_{i+1}.mp3 (not generated)</span>'
755
 
756
  slides_info = json.dumps({"slides": markdown_slides, "audioFiles": audio_files})
757
 
 
760
  <div id="slide-content" style="flex: 1; overflow: auto; padding: 20px; text-align: center;">
761
  <!-- Slides will be rendered here -->
762
  </div>
763
+ <div style="padding: 20px; text-align: center;">
764
+ <div style="display: flex; justify-content: center; margin-bottom: 10px;">
765
  {audio_timeline}
766
  </div>
767
  <div style="display: flex; justify-content: center; margin-bottom: 10px;">
 
777
  let currentSlide = 0;
778
  const totalSlides = lectureData.slides.length;
779
  let audioElements = [];
 
780
 
781
  for (let i = 0; i < totalSlides; i++) {{
782
+ const audio = document.getElementById(`audio-${i+1}`);
783
  audioElements.push(audio);
784
  }}
785
 
786
  function renderSlide() {{
787
  const slideContent = document.getElementById('slide-content');
788
+ if (lectureData.slides[currentSlide]) {{
789
+ slideContent.innerHTML = lectureData.slides[currentSlide];
790
+ }} else {{
791
+ slideContent.innerHTML = '<h2>No slide content available</h2>';
792
+ }}
793
  }}
794
 
795
  function updateSlide() {{
 
817
  }}
818
 
819
  function playAll() {{
820
+ let index = 0;
821
+ function playNext() {{
822
+ if (index >= totalSlides) return;
823
+ const audio = audioElements[index];
824
+ if (audio && audio.play) {{
825
+ audio.play().then(() => {{
826
+ audio.addEventListener('ended', () => {{
827
+ index++;
828
+ playNext();
829
+ }}, {{ once: true }});
830
+ }}).catch(e => {{
831
+ console.error('Audio play failed:', e);
832
+ index++;
833
+ playNext();
834
+ }});
835
+ }} else {{
836
+ index++;
837
+ playNext();
838
+ }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
839
  }}
840
+ playNext();
841
  }}
842
 
843
  // Attach event listeners
 
877
  with gr.Group():
878
  title = gr.Textbox(label="Lecture Title", placeholder="e.g. Introduction to AI")
879
  lecture_content_description = gr.Textbox(label="Lecture Content Description", placeholder="e.g. Focus on recent advancements")
 
880
  lecture_type = gr.Dropdown(["Conference", "University", "High school"], label="Audience", value="University")
881
  api_service = gr.Dropdown(
882
  choices=[
 
889
  value="Google-gemini-1.5-flash"
890
  )
891
  api_key = gr.Textbox(label="Model Provider API Key", type="password", placeholder="Not required for Ollama")
892
+ serpapi_key = gr.Textbox(label="SerpApi Key", type="password", placeholder="Enter your SerpApi key (optional)")
893
  num_slides = gr.Slider(1, 20, step=1, label="Number of Slides", value=3)
894
  speaker_audio = gr.Audio(label="Speaker sample audio (MP3 or WAV)", type="filepath", elem_id="speaker-audio")
895
  generate_btn = gr.Button("Generate Lecture")
 
911
 
912
  generate_btn.click(
913
  fn=on_generate,
914
+ inputs=[api_service, api_key, serpapi_key, title, lecture_content_description, lecture_type, speaker_audio, num_slides],
915
  outputs=[slide_display, file_output]
916
  )
917