gladguy commited on
Commit
5625e63
·
1 Parent(s): 3409908

Add welcome screen for student name collection at app start with personalized VIVA greetings

Browse files
Files changed (1) hide show
  1. app.py +129 -54
app.py CHANGED
@@ -25,9 +25,10 @@ ELEVENLABS_API_URL = "https://api.elevenlabs.io/v1/text-to-speech"
25
  # Voice ID for "Brian": nPczCjzI2devNBz1zQrb
26
  ELEVENLABS_VOICE_ID = "nPczCjzI2devNBz1zQrb"
27
 
28
- def generate_audio(text: str) -> str:
29
  """
30
  Generate audio from text using ElevenLabs API.
 
31
  Returns path to temporary audio file or None if failed.
32
  """
33
  if not ELEVENLABS_API_KEY:
@@ -37,6 +38,10 @@ def generate_audio(text: str) -> str:
37
  if not text:
38
  print("⚠️ No text provided for audio generation")
39
  return None
 
 
 
 
40
 
41
  print(f"Generating audio for text: {text[:50]}...")
42
 
@@ -550,13 +555,13 @@ Be professional, accurate, and suitable for medical school level study."""
550
 
551
 
552
  # VIVA Mode Handler Functions
553
- def start_viva_mode(topic, image):
554
  """Initialize VIVA mode with questions."""
555
  if not topic or not image:
556
  return (
557
  gr.update(visible=False), # viva_container
558
  "Please learn about a topic first before starting VIVA mode!", # viva_status
559
- None, None, None, None, None, None, [] # other outputs
560
  )
561
 
562
  questions = generate_viva_questions(topic)
@@ -565,33 +570,42 @@ def start_viva_mode(topic, image):
565
  return (
566
  gr.update(visible=False),
567
  "Error generating VIVA questions. Please try again.",
568
- None, None, None, None, None, None, []
569
  )
570
 
571
  # Start with question 1
572
  q1 = questions[0]
573
 
574
- # Generate audio for first question
575
- audio_path = generate_audio(q1['question'])
576
 
577
  return (
578
  gr.update(visible=True), # Show VIVA container
579
  f"**VIVA MODE ACTIVE** 📝\nTopic: {topic}", # viva_status
580
  image, # viva_image
581
- f"### Question 1 of 5\n\n**{q1['question']}**", # current_question
582
  f"💡 **Hint:** {q1.get('hint', 'Think about the key anatomical features.')}", # hint_display
583
  "", # Clear answer input
584
  "", # Clear feedback
585
  gr.update(interactive=True, value="Submit Answer"), # Enable submit button
586
  questions, # Store questions in state
587
- audio_path # Return audio path
 
588
  )
589
 
 
 
 
 
 
 
 
 
590
 
591
- def submit_viva_answer(answer, questions, current_q_idx):
592
  """Process student's answer and move to next question."""
593
  if not questions or current_q_idx >= len(questions):
594
- return ("VIVA Complete!", "", "", gr.update(interactive=False), current_q_idx)
595
 
596
  q = questions[current_q_idx]
597
  feedback_text, emoji = evaluate_viva_answer(q['question'], answer, q.get('answer', ''))
@@ -604,8 +618,8 @@ def submit_viva_answer(answer, questions, current_q_idx):
604
  next_question = f"### Question {next_idx + 1} of 5\n\n**{next_q['question']}**"
605
  next_hint = f"💡 **Hint:** {next_q.get('hint', 'Think carefully about the anatomical relationships.')}"
606
 
607
- # Generate audio for next question
608
- audio_path = generate_audio(next_q['question'])
609
 
610
  return (
611
  next_question, # Show next question
@@ -632,21 +646,59 @@ def submit_viva_answer(answer, questions, current_q_idx):
632
 
633
  # Create Gradio interface
634
  with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
635
- gr.Markdown(
636
- """
637
- # 🩺 AnatomyBot - Your MBBS Anatomy Tutor
638
-
639
- Master anatomy through AI-powered learning and interactive VIVA practice!
640
- """
641
- )
642
-
643
- # State variables for VIVA mode
644
  viva_questions_state = gr.State([])
645
  current_question_idx = gr.State(0)
646
  current_topic = gr.State("")
647
  current_image_state = gr.State(None)
648
 
649
- with gr.Tabs() as tabs:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
650
  # LEARNING MODE TAB
651
  with gr.Tab("📚 Learning Mode"):
652
  # Search and examples at the top
@@ -697,6 +749,9 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
697
  with gr.Tab("🎯 VIVA Training Mode") as viva_tab:
698
  viva_status = gr.Markdown("Click 'Start VIVA Training' from Learning Mode after studying a topic!")
699
 
 
 
 
700
  with gr.Column(visible=False) as viva_container:
701
  with gr.Row():
702
  with gr.Column(scale=1):
@@ -793,33 +848,55 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
793
  outputs=[selected_page_image, analysis_output, current_book_topic, start_viva_book_btn]
794
  )
795
 
796
- # Start VIVA from Book Mode
797
- start_viva_book_btn.click(
798
- fn=lambda: gr.update(value="⏳ Processing VIVA Question...", interactive=False),
799
- outputs=[start_viva_book_btn]
800
- ).then(
801
- fn=start_viva_mode,
802
- inputs=[current_book_topic, selected_page_image],
803
- outputs=[
804
- viva_container, viva_status, viva_image,
805
- current_question_display, hint_display,
806
- student_answer, feedback_display, submit_answer_btn,
807
- viva_questions_state,
808
- question_audio
809
- ]
810
- ).then(
811
- fn=lambda: gr.update(selected=1), # Switch to VIVA tab (index 1 is VIVA tab)
812
- outputs=[tabs]
813
- ).then(
814
- fn=lambda: gr.update(value="🎯 Start VIVA Training from this Page", interactive=True),
815
- outputs=[start_viva_book_btn]
816
- ).then(
817
- fn=lambda: 0,
818
- outputs=[current_question_idx]
819
- )
820
 
821
 
822
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823
  # Event handlers for Learning Mode
824
  def handle_query(query):
825
  """Handle learning mode query and store topic/image."""
@@ -840,19 +917,20 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
840
  outputs=[image_output, info_output, error_output, current_topic, current_image_state, start_viva_btn]
841
  )
842
 
843
- # Start VIVA Mode
844
  start_viva_btn.click(
845
  fn=lambda: gr.update(value="⏳ Processing VIVA Question...", interactive=False),
846
  outputs=[start_viva_btn]
847
  ).then(
848
- fn=start_viva_mode,
849
- inputs=[current_topic, current_image_state],
850
  outputs=[
851
  viva_container, viva_status, viva_image,
852
  current_question_display, hint_display,
853
  student_answer, feedback_display, submit_answer_btn,
854
  viva_questions_state,
855
- question_audio # Output audio
 
856
  ]
857
  ).then(
858
  fn=lambda: gr.update(selected=1), # Switch to VIVA tab
@@ -860,9 +938,6 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
860
  ).then(
861
  fn=lambda: gr.update(value="🎯 Start VIVA Training", interactive=True), # Reset button
862
  outputs=[start_viva_btn]
863
- ).then(
864
- fn=lambda: gr.update(selected=1), # Switch to VIVA tab
865
- outputs=[tabs]
866
  ).then(
867
  fn=lambda: 0, # Reset question index
868
  outputs=[current_question_idx]
@@ -871,7 +946,7 @@ with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
871
  # Submit VIVA Answer
872
  submit_answer_btn.click(
873
  fn=submit_viva_answer,
874
- inputs=[student_answer, viva_questions_state, current_question_idx],
875
  outputs=[
876
  current_question_display, hint_display, student_answer,
877
  feedback_display, submit_answer_btn, current_question_idx,
 
25
  # Voice ID for "Brian": nPczCjzI2devNBz1zQrb
26
  ELEVENLABS_VOICE_ID = "nPczCjzI2devNBz1zQrb"
27
 
28
+ def generate_audio(text: str, student_name: str = None) -> str:
29
  """
30
  Generate audio from text using ElevenLabs API.
31
+ If student_name is provided, prepends a personalized greeting.
32
  Returns path to temporary audio file or None if failed.
33
  """
34
  if not ELEVENLABS_API_KEY:
 
38
  if not text:
39
  print("⚠️ No text provided for audio generation")
40
  return None
41
+
42
+ # Add personalized greeting if student name is provided
43
+ if student_name:
44
+ text = f"Welcome to Viva, Doctor {student_name}, let's start. {text}"
45
 
46
  print(f"Generating audio for text: {text[:50]}...")
47
 
 
555
 
556
 
557
  # VIVA Mode Handler Functions
558
+ def start_viva_mode(topic, image, student_name=""):
559
  """Initialize VIVA mode with questions."""
560
  if not topic or not image:
561
  return (
562
  gr.update(visible=False), # viva_container
563
  "Please learn about a topic first before starting VIVA mode!", # viva_status
564
+ None, None, None, None, None, None, [], None, student_name # other outputs
565
  )
566
 
567
  questions = generate_viva_questions(topic)
 
570
  return (
571
  gr.update(visible=False),
572
  "Error generating VIVA questions. Please try again.",
573
+ None, None, None, None, None, gr.update(interactive=False), [], None, student_name
574
  )
575
 
576
  # Start with question 1
577
  q1 = questions[0]
578
 
579
+ # Generate audio for first question with student name
580
+ audio_path = generate_audio(q1['question'], student_name if student_name else None)
581
 
582
  return (
583
  gr.update(visible=True), # Show VIVA container
584
  f"**VIVA MODE ACTIVE** 📝\nTopic: {topic}", # viva_status
585
  image, # viva_image
586
+ f"### Question 1 of 5\n\n**{q1['question']}**", # current_question_display
587
  f"💡 **Hint:** {q1.get('hint', 'Think about the key anatomical features.')}", # hint_display
588
  "", # Clear answer input
589
  "", # Clear feedback
590
  gr.update(interactive=True, value="Submit Answer"), # Enable submit button
591
  questions, # Store questions in state
592
+ audio_path, # Return audio path
593
+ student_name # Return student name to maintain in state
594
  )
595
 
596
+ # Wrapper to start VIVA with personalized greeting
597
+ def start_viva_with_name(name, topic, image):
598
+ viva_container_out, viva_status_out, viva_image_out, cur_q_disp, hint_disp, stu_ans, fb_disp, sub_btn, viva_q_state, q_audio, student_name_out = start_viva_mode(topic, image, name)
599
+ greeting = f"Doctor {name}, let's go to VIVA!"
600
+ # Add greeting as separate markdown component above question
601
+ viva_greeting_out = greeting
602
+ return viva_container_out, viva_status_out, viva_image_out, cur_q_disp, hint_disp, stu_ans, fb_disp, sub_btn, viva_q_state, q_audio, viva_greeting_out, student_name_out
603
+
604
 
605
+ def submit_viva_answer(answer, questions, current_q_idx, student_name=""):
606
  """Process student's answer and move to next question."""
607
  if not questions or current_q_idx >= len(questions):
608
+ return ("VIVA Complete!", "", "", gr.update(interactive=False), current_q_idx, None)
609
 
610
  q = questions[current_q_idx]
611
  feedback_text, emoji = evaluate_viva_answer(q['question'], answer, q.get('answer', ''))
 
618
  next_question = f"### Question {next_idx + 1} of 5\n\n**{next_q['question']}**"
619
  next_hint = f"💡 **Hint:** {next_q.get('hint', 'Think carefully about the anatomical relationships.')}"
620
 
621
+ # Generate audio for next question with student name
622
+ audio_path = generate_audio(next_q['question'], student_name if student_name else None)
623
 
624
  return (
625
  next_question, # Show next question
 
646
 
647
  # Create Gradio interface
648
  with gr.Blocks(title="AnatomyBot - MBBS Anatomy Tutor") as demo:
649
+ # State variables
650
+ student_name_state = gr.State("")
 
 
 
 
 
 
 
651
  viva_questions_state = gr.State([])
652
  current_question_idx = gr.State(0)
653
  current_topic = gr.State("")
654
  current_image_state = gr.State(None)
655
 
656
+ # Welcome Screen (shown first)
657
+ with gr.Column(visible=True) as welcome_screen:
658
+ gr.Markdown(
659
+ """
660
+ # 🩺 Welcome to AnatomyBot
661
+ ### Your Personal MBBS Anatomy Tutor
662
+
663
+ Master anatomy through AI-powered learning and interactive VIVA practice!
664
+ """
665
+ )
666
+ gr.Markdown("---")
667
+ gr.Markdown("## 👨‍⚕️ Let's Get Started!")
668
+ gr.Markdown("Please enter your name to begin your personalized learning journey.")
669
+
670
+ with gr.Row():
671
+ with gr.Column(scale=1):
672
+ pass # Empty column for centering
673
+ with gr.Column(scale=2):
674
+ welcome_name_input = gr.Textbox(
675
+ label="Your Name",
676
+ placeholder="Enter your name (e.g., Ahmed, Sarah, etc.)",
677
+ lines=1,
678
+ scale=1
679
+ )
680
+ welcome_submit_btn = gr.Button(
681
+ "🚀 Start Learning",
682
+ variant="primary",
683
+ size="lg"
684
+ )
685
+ with gr.Column(scale=1):
686
+ pass # Empty column for centering
687
+
688
+ # Main Application (hidden initially)
689
+ with gr.Column(visible=False) as main_app:
690
+ gr.Markdown(
691
+ """
692
+ # 🩺 AnatomyBot - Your MBBS Anatomy Tutor
693
+
694
+ Master anatomy through AI-powered learning and interactive VIVA practice!
695
+ """
696
+ )
697
+
698
+ # Display student name
699
+ student_name_display = gr.Markdown("")
700
+
701
+ with gr.Tabs(visible=False) as tabs:
702
  # LEARNING MODE TAB
703
  with gr.Tab("📚 Learning Mode"):
704
  # Search and examples at the top
 
749
  with gr.Tab("🎯 VIVA Training Mode") as viva_tab:
750
  viva_status = gr.Markdown("Click 'Start VIVA Training' from Learning Mode after studying a topic!")
751
 
752
+ # Additional greeting component (initially hidden)
753
+ viva_greeting = gr.Markdown("", visible=False)
754
+
755
  with gr.Column(visible=False) as viva_container:
756
  with gr.Row():
757
  with gr.Column(scale=1):
 
848
  outputs=[selected_page_image, analysis_output, current_book_topic, start_viva_book_btn]
849
  )
850
 
851
+ # Start VIVA from Book Mode - Use pre-collected name
852
+ start_viva_book_btn.click(
853
+ fn=lambda name, topic, image: start_viva_with_name(name, topic, image),
854
+ inputs=[student_name_state, current_book_topic, selected_page_image],
855
+ outputs=[
856
+ viva_container, viva_status, viva_image,
857
+ current_question_display, hint_display,
858
+ student_answer, feedback_display, submit_answer_btn,
859
+ viva_questions_state,
860
+ question_audio, viva_greeting, student_name_state
861
+ ]
862
+ ).then(
863
+ fn=lambda: gr.update(selected=1), # Switch to VIVA tab
864
+ outputs=[tabs]
865
+ ).then(
866
+ fn=lambda: 0,
867
+ outputs=[current_question_idx]
868
+ )
 
 
 
 
 
 
869
 
870
 
871
 
872
+ # Welcome Screen Handler
873
+ def handle_welcome_submit(name):
874
+ """Handle welcome screen submission."""
875
+ if not name or not name.strip():
876
+ return gr.update(), gr.update(), gr.update(), gr.update(), "" # Don't proceed if name is empty
877
+
878
+ greeting = f"**Welcome, Doctor {name}!** 👋"
879
+ return (
880
+ gr.update(visible=False), # Hide welcome screen
881
+ gr.update(visible=True), # Show main app
882
+ gr.update(visible=True), # Show tabs
883
+ greeting, # Display greeting
884
+ name # Store name in state
885
+ )
886
+
887
+ welcome_submit_btn.click(
888
+ fn=handle_welcome_submit,
889
+ inputs=[welcome_name_input],
890
+ outputs=[welcome_screen, main_app, tabs, student_name_display, student_name_state]
891
+ )
892
+
893
+ # Also allow Enter key to submit
894
+ welcome_name_input.submit(
895
+ fn=handle_welcome_submit,
896
+ inputs=[welcome_name_input],
897
+ outputs=[welcome_screen, main_app, tabs, student_name_display, student_name_state]
898
+ )
899
+
900
  # Event handlers for Learning Mode
901
  def handle_query(query):
902
  """Handle learning mode query and store topic/image."""
 
917
  outputs=[image_output, info_output, error_output, current_topic, current_image_state, start_viva_btn]
918
  )
919
 
920
+ # Start VIVA Mode - Directly start with pre-collected name
921
  start_viva_btn.click(
922
  fn=lambda: gr.update(value="⏳ Processing VIVA Question...", interactive=False),
923
  outputs=[start_viva_btn]
924
  ).then(
925
+ fn=lambda name, topic, image: start_viva_mode(topic, image, name),
926
+ inputs=[student_name_state, current_topic, current_image_state],
927
  outputs=[
928
  viva_container, viva_status, viva_image,
929
  current_question_display, hint_display,
930
  student_answer, feedback_display, submit_answer_btn,
931
  viva_questions_state,
932
+ question_audio, # Output audio
933
+ student_name_state # Return student name (unchanged)
934
  ]
935
  ).then(
936
  fn=lambda: gr.update(selected=1), # Switch to VIVA tab
 
938
  ).then(
939
  fn=lambda: gr.update(value="🎯 Start VIVA Training", interactive=True), # Reset button
940
  outputs=[start_viva_btn]
 
 
 
941
  ).then(
942
  fn=lambda: 0, # Reset question index
943
  outputs=[current_question_idx]
 
946
  # Submit VIVA Answer
947
  submit_answer_btn.click(
948
  fn=submit_viva_answer,
949
+ inputs=[student_answer, viva_questions_state, current_question_idx, student_name_state],
950
  outputs=[
951
  current_question_display, hint_display, student_answer,
952
  feedback_display, submit_answer_btn, current_question_idx,