mah-diaa commited on
Commit
ec833a4
Β·
1 Parent(s): 165d9b8

Remove right sidebar, add quiz popup modal, fix quiz generation

Browse files
Files changed (1) hide show
  1. app.py +190 -57
app.py CHANGED
@@ -15,7 +15,9 @@ user_state = {
15
  "key_points": [],
16
  "document_parsed": False,
17
  "learning_style": None,
18
- "parsed_data": None
 
 
19
  }
20
 
21
 
@@ -124,29 +126,24 @@ For example: "I want to learn about binary search" or "Teach me recursion" """
124
  try:
125
  questions = generate_quiz(
126
  concepts=user_state["concepts"],
127
- topics=user_state["topics"],
128
  num_questions=10,
129
  question_types=["mcq"],
130
  document_context=user_state.get("parsed_data", {}).get("text_preview", "")
131
  )
132
 
133
  if questions:
134
- quiz_text = f"# πŸ“ Quiz Generated! ({len(questions)} questions)\n\n"
135
- for i, q in enumerate(questions[:5], 1): # Show first 5
136
- quiz_text += f"**Q{i}:** {q.get('question', '')}\n"
137
- if q.get('type') == 'mcq' and 'options' in q:
138
- for j, opt in enumerate(q['options']):
139
- quiz_text += f" {chr(65+j)}. {opt}\n"
140
- quiz_text += f"\n*Answer: {q.get('explanation', '')[:100]}...*\n\n---\n\n"
141
 
142
- if len(questions) > 5:
143
- quiz_text += f"\n*... and {len(questions) - 5} more questions!*\n\n"
144
-
145
- response = quiz_text + "\n\nWould you like to:\n- See all questions?\n- Take the quiz interactively?\n- Generate more questions?"
146
  else:
147
  response = "⚠️ I had trouble generating questions. Could you try again or provide more specific concepts?"
148
  except Exception as e:
149
- response = f"❌ Error generating quiz: {str(e)}"
 
 
150
 
151
  elif any(word in message_lower for word in ["curriculum", "course", "path", "learn step", "progressive"]):
152
  if not user_state["concepts"]:
@@ -488,8 +485,8 @@ with gr.Blocks(title="Gnosis Tutor") as app:
488
  **Powered by MCP Server Integration**
489
  """)
490
 
491
- # Center - Main Chat Area
492
- with gr.Column(scale=3):
493
  gr.Markdown("""
494
  <div class="main-chat-area">
495
  <h2 style="margin-top: 0; color: #667eea; text-align: center;">πŸ’¬ Chat with Gnosis</h2>
@@ -512,47 +509,36 @@ with gr.Blocks(title="Gnosis Tutor") as app:
512
  textbox=gr.MultimodalTextbox(file_types=[".pdf"])
513
  )
514
 
515
- # Right Sidebar - Learning Resources & Help
516
- with gr.Column(scale=1):
517
- with gr.Tabs():
518
- with gr.Tab("πŸ“š Resources"):
519
- gr.Markdown("**Learning Resources:**")
520
- resource_concept = gr.Textbox(
521
- label="Search for:",
522
- placeholder="e.g., binary search"
523
- )
524
- resource_btn = gr.Button("πŸ” Search", variant="primary")
525
- resource_output = gr.Markdown(label="Resources")
526
 
527
- with gr.Tab("πŸ“– Curriculum"):
528
- gr.Markdown("**Create Learning Path:**")
529
- curriculum_concept = gr.Textbox(
530
- label="Concept:",
531
- placeholder="e.g., recursion"
532
- )
533
- curriculum_lang = gr.Dropdown(
534
- choices=["python", "javascript", "typescript"],
535
- value="python",
536
- label="Language"
537
- )
538
- curriculum_btn = gr.Button("πŸš€ Generate", variant="primary")
539
- curriculum_output = gr.Markdown(label="Curriculum")
540
 
541
- with gr.Tab("πŸ’‘ Tips"):
542
- gr.Markdown("""
543
- **πŸ’‘ Tips for best results:**
544
-
545
- 1. Upload clear PDF documents
546
- 2. Be specific about concepts
547
- 3. Ask follow-up questions
548
- 4. Use the quick actions for fast results
549
-
550
- **🎯 Try saying:**
551
- - "Generate a quiz"
552
- - "Create a curriculum"
553
- - "Find resources about X"
554
- - "Explain [concept]"
555
- """)
 
 
556
 
557
  # Handle file upload separately to update sidebars
558
  def handle_file_upload(file):
@@ -670,6 +656,120 @@ with gr.Blocks(title="Gnosis Tutor") as app:
670
  except Exception as e:
671
  return f"❌ Error: {str(e)}"
672
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
673
  # Connect file upload to update sidebars
674
  file_upload.change(
675
  handle_file_upload,
@@ -677,12 +777,45 @@ with gr.Blocks(title="Gnosis Tutor") as app:
677
  outputs=[concepts_display, topics_display, key_points_display]
678
  )
679
 
 
680
  quick_quiz_btn.click(quick_generate_quiz, None, [quick_output])
681
  quick_curriculum_btn.click(quick_generate_curriculum, None, [quick_output])
682
  quick_resources_btn.click(quick_find_resources, None, [quick_output])
683
 
684
- resource_btn.click(search_resources, [resource_concept], [resource_output])
685
- curriculum_btn.click(generate_curriculum_side, [curriculum_concept, curriculum_lang], [curriculum_output])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
686
 
687
 
688
  if __name__ == "__main__":
 
15
  "key_points": [],
16
  "document_parsed": False,
17
  "learning_style": None,
18
+ "parsed_data": None,
19
+ "current_quiz": None, # Store generated quiz
20
+ "show_quiz_modal": False # Control quiz popup visibility
21
  }
22
 
23
 
 
126
  try:
127
  questions = generate_quiz(
128
  concepts=user_state["concepts"],
129
+ topics=user_state.get("topics", []),
130
  num_questions=10,
131
  question_types=["mcq"],
132
  document_context=user_state.get("parsed_data", {}).get("text_preview", "")
133
  )
134
 
135
  if questions:
136
+ # Store quiz in state
137
+ user_state["current_quiz"] = questions
138
+ user_state["show_quiz_modal"] = True
 
 
 
 
139
 
140
+ response = f"βœ… **Quiz Generated!** ({len(questions)} questions)\n\nI've created a quiz based on your concepts. Check the quiz panel on the right! πŸ“\n\nYou can:\n- Take the quiz interactively\n- Review all questions\n- Generate more questions"
 
 
 
141
  else:
142
  response = "⚠️ I had trouble generating questions. Could you try again or provide more specific concepts?"
143
  except Exception as e:
144
+ import traceback
145
+ error_details = traceback.format_exc()
146
+ response = f"❌ Error generating quiz: {str(e)}\n\nDebug info: {error_details[:200]}"
147
 
148
  elif any(word in message_lower for word in ["curriculum", "course", "path", "learn step", "progressive"]):
149
  if not user_state["concepts"]:
 
485
  **Powered by MCP Server Integration**
486
  """)
487
 
488
+ # Center - Main Chat Area (full width now)
489
+ with gr.Column(scale=4):
490
  gr.Markdown("""
491
  <div class="main-chat-area">
492
  <h2 style="margin-top: 0; color: #667eea; text-align: center;">πŸ’¬ Chat with Gnosis</h2>
 
509
  textbox=gr.MultimodalTextbox(file_types=[".pdf"])
510
  )
511
 
512
+ # Quiz Popup Modal (shown when quiz is generated) - positioned as floating panel
513
+ quiz_data_state = gr.State(value=None)
514
+ current_question_idx = gr.State(value=0)
515
+ quiz_score_state = gr.State(value={"correct": 0, "total": 0})
516
+
517
+ with gr.Column(visible=True) as quiz_modal:
518
+ with gr.Box(elem_classes="quiz-modal", elem_id="quiz-modal-box"):
519
+ with gr.Row():
520
+ gr.Markdown("## πŸ“ Interactive Quiz", elem_id="quiz-title")
521
+ quiz_close_btn = gr.Button("βœ• Close", variant="stop", size="sm", scale=0)
 
522
 
523
+ quiz_status = gr.Markdown("**No quiz available yet. Ask me to generate a quiz!**")
 
 
 
 
 
 
 
 
 
 
 
 
524
 
525
+ with gr.Row():
526
+ quiz_question_num = gr.Markdown("**Question 1 of 10**")
527
+ quiz_score_display = gr.Markdown("**Score: 0/0**")
528
+
529
+ quiz_question_text = gr.Markdown("", label="")
530
+ quiz_options = gr.Radio(label="Select your answer", choices=[], interactive=True, visible=False)
531
+ quiz_submit_btn = gr.Button("Submit Answer", variant="primary", visible=False)
532
+
533
+ quiz_feedback = gr.Markdown(label="", visible=False)
534
+ quiz_explanation = gr.Markdown(label="", visible=False)
535
+
536
+ with gr.Row():
537
+ quiz_prev_btn = gr.Button("← Previous", variant="secondary", visible=False)
538
+ quiz_next_btn = gr.Button("Next β†’", variant="secondary", visible=False)
539
+
540
+ quiz_complete = gr.Markdown(label="", visible=False)
541
+ quiz_restart_btn = gr.Button("πŸ”„ Start Over", variant="primary", visible=False)
542
 
543
  # Handle file upload separately to update sidebars
544
  def handle_file_upload(file):
 
656
  except Exception as e:
657
  return f"❌ Error: {str(e)}"
658
 
659
+ # Quiz modal functions
660
+ def load_quiz_to_modal():
661
+ """Load quiz from state into modal."""
662
+ quiz = user_state.get("current_quiz")
663
+ if not quiz:
664
+ return (
665
+ gr.update(visible=True, value="**No quiz available yet. Ask me to generate a quiz!**"),
666
+ gr.update(visible=False),
667
+ gr.update(visible=False),
668
+ gr.update(visible=False),
669
+ gr.update(visible=False),
670
+ gr.update(visible=False),
671
+ gr.update(visible=False),
672
+ gr.update(visible=False),
673
+ gr.update(visible=False),
674
+ gr.update(visible=False),
675
+ gr.update(value=0),
676
+ gr.update(value={"correct": 0, "total": 0}),
677
+ gr.update(value=quiz)
678
+ )
679
+
680
+ # Show first question
681
+ return display_question(quiz, 0, {"correct": 0, "total": 0}, quiz)
682
+
683
+ def display_question(quiz_data, idx, score, _):
684
+ """Display a question in the quiz modal."""
685
+ if not quiz_data or idx >= len(quiz_data):
686
+ return (
687
+ gr.update(visible=True, value="**Quiz complete!**"),
688
+ gr.update(visible=False),
689
+ gr.update(visible=False),
690
+ gr.update(visible=False),
691
+ gr.update(visible=False),
692
+ gr.update(visible=False),
693
+ gr.update(visible=False),
694
+ gr.update(visible=False),
695
+ gr.update(visible=False),
696
+ gr.update(visible=False),
697
+ gr.update(value=idx),
698
+ gr.update(value=score),
699
+ gr.update(value=quiz_data)
700
+ )
701
+
702
+ q = quiz_data[idx]
703
+ question_text = f"**{q.get('question', '')}**"
704
+ question_num = f"**Question {idx + 1} of {len(quiz_data)}**"
705
+ score_text = f"**Score: {score['correct']}/{score['total']}**"
706
+
707
+ options = []
708
+ if q.get('type') == 'mcq' and 'options' in q:
709
+ options = q['options']
710
+
711
+ return (
712
+ gr.update(visible=True, value=question_text),
713
+ gr.update(visible=True, value=question_num),
714
+ gr.update(visible=True, value=score_text),
715
+ gr.update(visible=True, value=question_text),
716
+ gr.update(visible=len(options) > 0, choices=options, value=None),
717
+ gr.update(visible=len(options) > 0),
718
+ gr.update(visible=False),
719
+ gr.update(visible=False),
720
+ gr.update(visible=idx > 0),
721
+ gr.update(visible=idx < len(quiz_data) - 1),
722
+ gr.update(visible=False),
723
+ gr.update(visible=False),
724
+ gr.update(value=idx),
725
+ gr.update(value=score),
726
+ gr.update(value=quiz_data)
727
+ )
728
+
729
+ def submit_answer(selected, quiz_data, idx, score):
730
+ """Handle answer submission."""
731
+ if not quiz_data or idx >= len(quiz_data):
732
+ return display_question(quiz_data, idx, score, quiz_data)
733
+
734
+ q = quiz_data[idx]
735
+ correct_idx = q.get('correct_answer', 0)
736
+ is_correct = False
737
+
738
+ if q.get('type') == 'mcq':
739
+ is_correct = (selected == correct_idx) if selected is not None else False
740
+ elif q.get('type') == 'true_false':
741
+ is_correct = (selected == correct_idx)
742
+
743
+ new_score = {
744
+ "correct": score["correct"] + (1 if is_correct else 0),
745
+ "total": score["total"] + 1
746
+ }
747
+
748
+ feedback = "βœ… **Correct!**" if is_correct else "❌ **Incorrect**"
749
+ explanation = f"**Explanation:** {q.get('explanation', 'No explanation available.')}"
750
+
751
+ return (
752
+ gr.update(visible=True, value=feedback),
753
+ gr.update(visible=True, value=explanation),
754
+ gr.update(visible=False),
755
+ gr.update(visible=idx < len(quiz_data) - 1),
756
+ gr.update(value=idx),
757
+ gr.update(value=new_score),
758
+ gr.update(value=quiz_data)
759
+ )
760
+
761
+ def next_question(quiz_data, idx, score):
762
+ """Move to next question."""
763
+ return display_question(quiz_data, idx + 1, score, quiz_data)
764
+
765
+ def prev_question(quiz_data, idx, score):
766
+ """Move to previous question."""
767
+ return display_question(quiz_data, idx - 1, score, quiz_data)
768
+
769
+ def close_quiz_modal():
770
+ """Close quiz modal."""
771
+ return gr.update(visible=False)
772
+
773
  # Connect file upload to update sidebars
774
  file_upload.change(
775
  handle_file_upload,
 
777
  outputs=[concepts_display, topics_display, key_points_display]
778
  )
779
 
780
+ # Connect quick action buttons
781
  quick_quiz_btn.click(quick_generate_quiz, None, [quick_output])
782
  quick_curriculum_btn.click(quick_generate_curriculum, None, [quick_output])
783
  quick_resources_btn.click(quick_find_resources, None, [quick_output])
784
 
785
+ # Quiz modal interactions
786
+ chatbot_interface.chatbot.load(load_quiz_to_modal, None, [
787
+ quiz_status, quiz_question_num, quiz_score_display, quiz_question_text,
788
+ quiz_options, quiz_submit_btn, quiz_feedback, quiz_explanation,
789
+ quiz_prev_btn, quiz_next_btn, quiz_complete, quiz_restart_btn,
790
+ current_question_idx, quiz_score_state, quiz_data_state
791
+ ])
792
+
793
+ quiz_submit_btn.click(
794
+ submit_answer,
795
+ inputs=[quiz_options, quiz_data_state, current_question_idx, quiz_score_state],
796
+ outputs=[quiz_feedback, quiz_explanation, quiz_submit_btn, quiz_next_btn,
797
+ current_question_idx, quiz_score_state, quiz_data_state]
798
+ )
799
+
800
+ quiz_next_btn.click(
801
+ next_question,
802
+ inputs=[quiz_data_state, current_question_idx, quiz_score_state],
803
+ outputs=[quiz_status, quiz_question_num, quiz_score_display, quiz_question_text,
804
+ quiz_options, quiz_submit_btn, quiz_feedback, quiz_explanation,
805
+ quiz_prev_btn, quiz_next_btn, quiz_complete, quiz_restart_btn,
806
+ current_question_idx, quiz_score_state, quiz_data_state]
807
+ )
808
+
809
+ quiz_prev_btn.click(
810
+ prev_question,
811
+ inputs=[quiz_data_state, current_question_idx, quiz_score_state],
812
+ outputs=[quiz_status, quiz_question_num, quiz_score_display, quiz_question_text,
813
+ quiz_options, quiz_submit_btn, quiz_feedback, quiz_explanation,
814
+ quiz_prev_btn, quiz_next_btn, quiz_complete, quiz_restart_btn,
815
+ current_question_idx, quiz_score_state, quiz_data_state]
816
+ )
817
+
818
+ quiz_close_btn.click(close_quiz_modal, None, [quiz_modal])
819
 
820
 
821
  if __name__ == "__main__":