capradeepgujaran commited on
Commit
5e2e371
1 Parent(s): 5be175f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +206 -130
app.py CHANGED
@@ -45,7 +45,7 @@ class QuizGenerator:
45
  }
46
  ],
47
  model="gemma2-9b-it",
48
- temperature=0.1,
49
  max_tokens=6000
50
  )
51
 
@@ -70,39 +70,29 @@ class QuizGenerator:
70
  raise QuizGenerationError(f"Failed to generate questions: {str(e)}")
71
 
72
  def _create_prompt(self, text: str, num_questions: int) -> str:
73
- """Create a simple, clear prompt optimized for gemma2-9b-it"""
74
- return f"""Create exactly {num_questions} multiple choice questions based on this text. Return your response in this exact JSON format with no additional text or formatting:
75
- [{{
76
- "question": "Write the first question here?",
77
- "options": [
78
- "First option",
79
- "Second option",
80
- "Third option",
81
- "Fourth option"
82
- ],
83
- "correct_answer": 0
84
- }},{{
85
- "question": "Write the second question here?",
86
- "options": [
87
- "First option",
88
- "Second option",
89
- "Third option",
90
- "Fourth option"
91
- ],
92
- "correct_answer": 0
93
- }}]
94
-
95
- Important formatting rules:
96
- 1. The JSON must start with [ and end with ]
97
- 2. Each question object must be wrapped in {{ }}
98
- 3. Questions must be separated by commas
99
- 4. No trailing commas after the last question
100
- 5. Each question must have exactly 4 options
101
- 6. correct_answer must be a number (0, 1, 2, or 3)
102
- 7. Return only the JSON with no other text
103
-
104
- Text to use:
105
- {text.strip()}"""
106
 
107
  def _parse_response(self, response_text: str) -> List[Dict]:
108
  """Parse response with improved error handling"""
@@ -110,7 +100,7 @@ class QuizGenerator:
110
  # Clean up the response text
111
  cleaned = response_text.strip()
112
 
113
- # Remove markdown formatting
114
  cleaned = cleaned.replace('```json', '').replace('```', '').strip()
115
 
116
  # Find the JSON array
@@ -122,40 +112,35 @@ class QuizGenerator:
122
 
123
  json_str = cleaned[start:end]
124
 
125
- # Fix common JSON formatting issues
126
- json_str = re.sub(r',(\s*})', r'\1', json_str) # Remove trailing commas in objects
127
- json_str = re.sub(r',(\s*])', r'\1', json_str) # Remove trailing commas in arrays
128
- json_str = re.sub(r'}\s*{', '},{', json_str) # Fix spacing between objects
129
- json_str = re.sub(r'\n\s*\n', '\n', json_str) # Remove extra newlines
130
-
131
- # Fix missing commas between objects
132
- json_str = re.sub(r'}\s*{', '},{', json_str)
133
-
134
- # Ensure array brackets
135
- if not json_str.startswith('['):
136
- json_str = '[' + json_str
137
- if not json_str.endswith(']'):
138
- json_str = json_str + ']'
139
 
 
140
  try:
141
  return json.loads(json_str)
142
  except json.JSONDecodeError:
143
- # Try fixing any remaining issues
144
- fixed_str = re.sub(r'(["\d\w])\s*}', r'\1}', json_str) # Fix spacing before closing braces
145
- fixed_str = re.sub(r'\[\s*{', '[{', fixed_str) # Fix spacing after opening bracket
146
- fixed_str = re.sub(r'}\s*]', '}]', fixed_str) # Fix spacing before closing bracket
147
 
148
- try:
149
- return json.loads(fixed_str)
150
- except:
151
- # Last resort: Try using ast.literal_eval
152
- import ast
153
- return ast.literal_eval(fixed_str)
154
-
155
  except Exception as e:
156
  print(f"Parse error details: {str(e)}")
157
  print(f"Attempted to parse: {response_text}")
158
- raise ValueError(f"Failed to parse response: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
  def _validate_questions(self, questions: List[Dict], num_questions: int) -> List[Question]:
161
  """Validate questions with strict checking"""
@@ -540,6 +525,88 @@ class QuizApp:
540
  self.quiz_generator = QuizGenerator(api_key)
541
  self.certificate_generator = CertificateGenerator()
542
  self.current_questions: List[Question] = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
543
 
544
  def generate_questions(self, text: str, num_questions: int) -> Tuple[bool, List[Question]]:
545
  """
@@ -720,7 +787,7 @@ def create_quiz_interface():
720
  # Header
721
  gr.Markdown("""
722
  <div style="text-align: center;">
723
- <h1>🎓 CertifyMe AI </h1>
724
  <h3>Transform Your Knowledge into Recognized Achievements</h3></p>
725
  </div>
726
 
@@ -728,14 +795,15 @@ def create_quiz_interface():
728
  <h4>Assessment Overview:</h4>
729
  <ul style="list-style-type: none; padding-left: 0;">
730
  <li>📌 <strong>Basic Level:</strong> 5 questions - Perfect for beginners</li>
731
- <li>📚 <strong>Intermediate Level:</strong> 10 questions - For gaining Intermediate Experience</li>
732
  <li>🎯 <strong>Advanced Level:</strong> 20 questions - Comprehensive assessment</li>
733
  <li>⏱️ <strong>Passing Score:</strong> 80% or higher</li>
734
  <li>🏆 <strong>Certificate:</strong> Awarded upon successful completion</li>
735
  </ul>
736
- <p style="margin-top: 15px;"><i>This assessment evaluates your understanding of the Learning Content that you pasted below:</i></p>
737
  </div>
738
- """, show_label=False)
 
739
  with gr.Tabs() as tabs:
740
  # Profile Setup Tab
741
  with gr.Tab(id=1, label="📋 Step 1: Profile Setup"):
@@ -745,20 +813,19 @@ def create_quiz_interface():
745
 
746
  text_input = gr.Textbox(
747
  label="Learning Content",
748
- placeholder="Enter the text content you want to be assessed on",
 
749
  lines=10
750
  )
751
 
752
- num_questions = gr.Slider(
753
- minimum=1,
754
- maximum=20,
755
- value=10,
756
- step=1,
757
- label="Number of Questions"
758
- )
759
 
760
  with gr.Row():
761
- company_logo = gr.Image(label="Company Logo (Optional)", type="filepath")
762
  participant_photo = gr.Image(label="Your Photo (Optional)", type="filepath")
763
 
764
  generate_btn = gr.Button("Generate Assessment", variant="primary", size="lg")
@@ -814,40 +881,33 @@ def create_quiz_interface():
814
  )
815
 
816
  # Certification Tab (Hidden by default)
 
817
  with gr.Tab(id=3, label="🎓 Step 3: Get Certified", visible=False) as cert_tab:
818
  score_display = gr.Number(label="Your Score", visible=False)
819
  course_name = gr.Textbox(
820
  label="Certification Title",
821
- value="Professional Assessment Certification",
822
- interactive=False # Make it non-editable
823
  )
824
- certificate_display = gr.Image(label="Your Certificate")
 
825
 
826
- # Update view_cert_btn click handler to show certification tab
827
  def show_certificate_tab():
828
  return [
829
  gr.update(visible=True), # Make cert_tab visible
 
 
 
830
  gr.update(selected=3) # Switch to cert_tab
831
  ]
832
 
833
 
834
  # Helper Functions
835
- def on_generate_questions(text, num_questions):
836
- if not text.strip():
837
- return [
838
- "",
839
- gr.update(visible=False),
840
- gr.update(choices=[], visible=False),
841
- "",
842
- [],
843
- 0,
844
- [None] * 5,
845
- gr.update(selected=1),
846
- gr.update(visible=False),
847
- gr.update(visible=False)
848
- ]
849
 
850
- success, questions = quiz_app.generate_questions(text, num_questions)
851
  if not success or not questions:
852
  return [
853
  "",
@@ -856,15 +916,14 @@ def create_quiz_interface():
856
  "",
857
  [],
858
  0,
859
- [None] * 5,
860
  gr.update(selected=1),
861
  gr.update(visible=False),
862
  gr.update(visible=False)
863
  ]
864
 
865
  question = questions[0]
866
- question_md = f"""### Question 1
867
- {question.question}"""
868
 
869
  return [
870
  question_md,
@@ -938,48 +997,62 @@ def create_quiz_interface():
938
  if 0 <= current_idx < len(final_answers):
939
  final_answers[current_idx] = current_answer
940
 
941
- # Check for unanswered questions
942
  if not all(a is not None for a in final_answers[:len(questions)]):
943
- # Find unanswered question numbers
944
  unanswered = [i+1 for i, a in enumerate(final_answers[:len(questions)]) if a is None]
945
  warning_content = f"""
946
- <div style="background-color: #fff3cd; padding: 20px; border-radius: 8px; border: 1px solid #ffeeba; margin: 10px 0;">
947
- <div style="display: flex; align-items: center; margin-bottom: 10px;">
948
- <span style="font-size: 24px; margin-right: 10px;">⚠️</span>
949
- <h3 style="color: #856404; margin: 0;">Please Complete All Questions</h3>
950
- </div>
951
- <p style="color: #856404; margin: 10px 0;">The following questions are unanswered:</p>
952
- <p style="color: #856404; font-weight: bold; margin: 5px 0;">Question(s) {', '.join(map(str, unanswered))}</p>
953
- <p style="color: #856404; margin: 10px 0;">Please answer all questions before submitting.</p>
954
  </div>
955
  """
956
  return [
957
- warning_content, # feedback_box
958
- gr.update(visible=True), # results_group
959
- 0, # score
960
- "⚠️ Incomplete Submission", # result_message
961
- gr.update(visible=True), # question_box
962
- gr.update(visible=True), # reset_btn
963
- gr.update(visible=False), # view_cert_btn
964
- gr.update(selected=2) # tabs
965
  ]
966
-
967
- # Rest of the original function remains the same...
968
  score, passed, feedback = quiz_app.calculate_score(final_answers[:len(questions)])
969
- feedback_content = f"""# Assessment Results\n\n**Score: {score:.1f}%**\n\n"""
 
 
 
 
 
 
970
 
971
  for i, (q, f) in enumerate(zip(questions, feedback)):
972
  icon = "✅" if f.is_correct else "❌"
973
  color = "green" if f.is_correct else "red"
 
 
974
  feedback_content += f"""### Question {i+1}
975
- {q.question}\n
976
- {icon} **Your answer:** {f.selected or 'No answer'}
977
- {'' if f.is_correct else f'**Correct answer:** {f.correct_answer}'}\n\n"""
 
 
 
978
 
 
979
  if passed:
980
- feedback_content += f"""\n---\n## 🎉 Congratulations!\nYou passed with a score of {score:.1f}%!"""
 
 
 
 
981
  else:
982
- feedback_content += f"""\n---\n## Need Improvement\nYou scored {score:.1f}%. You need 80% or higher to pass.\nPlease try again."""
 
 
 
 
 
983
 
984
  return [
985
  feedback_content, # feedback_box
@@ -991,11 +1064,10 @@ def create_quiz_interface():
991
  gr.update(visible=passed), # view_cert_btn
992
  gr.update(selected=2) # tabs
993
  ]
994
-
995
  # Event Handlers
996
  generate_btn.click(
997
  fn=on_generate_questions,
998
- inputs=[text_input, num_questions],
999
  outputs=[
1000
  question_display,
1001
  question_box,
@@ -1039,7 +1111,7 @@ def create_quiz_interface():
1039
 
1040
  reset_btn.click(
1041
  fn=on_generate_questions,
1042
- inputs=[text_input, num_questions],
1043
  outputs=[
1044
  question_display,
1045
  question_box,
@@ -1053,10 +1125,10 @@ def create_quiz_interface():
1053
  view_cert_btn
1054
  ]
1055
  )
1056
-
1057
  view_cert_btn.click(
1058
  fn=show_certificate_tab,
1059
- outputs=[cert_tab, tabs]
1060
  )
1061
 
1062
  current_options.change(
@@ -1066,11 +1138,15 @@ def create_quiz_interface():
1066
  )
1067
 
1068
  score_display.change(
1069
- fn=lambda s, n, c, l, p: quiz_app.certificate_generator.generate(s, n, c, l, p) or gr.update(value=None),
1070
- inputs=[score_display, name, course_name, company_logo, participant_photo],
 
 
 
 
1071
  outputs=certificate_display
1072
  )
1073
-
1074
  return demo
1075
 
1076
  if __name__ == "__main__":
 
45
  }
46
  ],
47
  model="gemma2-9b-it",
48
+ temperature=0,
49
  max_tokens=6000
50
  )
51
 
 
70
  raise QuizGenerationError(f"Failed to generate questions: {str(e)}")
71
 
72
  def _create_prompt(self, text: str, num_questions: int) -> str:
73
+ """Create a simple, clear prompt optimized for llama-3.2-3b-preview"""
74
+ return f"""Create {num_questions} multiple choice questions about this text. Return only the JSON array in this exact format:
75
+ [
76
+ {{
77
+ "question": "Write the question here?",
78
+ "options": [
79
+ "First option",
80
+ "Second option",
81
+ "Third option",
82
+ "Fourth option"
83
+ ],
84
+ "correct_answer": 0
85
+ }}
86
+ ]
87
+
88
+ Rules:
89
+ 1. Return only the JSON array
90
+ 2. Each question must have exactly 4 options
91
+ 3. correct_answer must be 0, 1, 2, or 3
92
+ 4. No explanations or additional text
93
+
94
+ Text to use:
95
+ {text.strip()}"""
 
 
 
 
 
 
 
 
 
 
96
 
97
  def _parse_response(self, response_text: str) -> List[Dict]:
98
  """Parse response with improved error handling"""
 
100
  # Clean up the response text
101
  cleaned = response_text.strip()
102
 
103
+ # Remove any markdown formatting
104
  cleaned = cleaned.replace('```json', '').replace('```', '').strip()
105
 
106
  # Find the JSON array
 
112
 
113
  json_str = cleaned[start:end]
114
 
115
+ # Remove any trailing commas before closing brackets
116
+ json_str = re.sub(r',(\s*})', r'\1', json_str)
117
+ json_str = re.sub(r',(\s*])', r'\1', json_str)
 
 
 
 
 
 
 
 
 
 
 
118
 
119
+ # Try to parse the cleaned JSON
120
  try:
121
  return json.loads(json_str)
122
  except json.JSONDecodeError:
123
+ # If that fails, try using ast.literal_eval as a fallback
124
+ import ast
125
+ return ast.literal_eval(json_str)
 
126
 
 
 
 
 
 
 
 
127
  except Exception as e:
128
  print(f"Parse error details: {str(e)}")
129
  print(f"Attempted to parse: {response_text}")
130
+
131
+ # Last resort: try to fix the JSON manually
132
+ try:
133
+ # Remove any trailing commas and fix newlines
134
+ fixed = re.sub(r',(\s*[}\]])', r'\1', response_text)
135
+ fixed = fixed.replace('}\n{', '},{')
136
+ fixed = fixed.strip()
137
+ if not fixed.startswith('['):
138
+ fixed = '[' + fixed
139
+ if not fixed.endswith(']'):
140
+ fixed = fixed + ']'
141
+ return json.loads(fixed)
142
+ except:
143
+ raise ValueError(f"Failed to parse response: {str(e)}")
144
 
145
  def _validate_questions(self, questions: List[Dict], num_questions: int) -> List[Question]:
146
  """Validate questions with strict checking"""
 
525
  self.quiz_generator = QuizGenerator(api_key)
526
  self.certificate_generator = CertificateGenerator()
527
  self.current_questions: List[Question] = []
528
+ self.logo_path = "atgc_logo.png"
529
+ self.selected_level = "Basic" # Default level
530
+
531
+ # Map difficulty levels to number of questions
532
+ self.difficulty_levels = {
533
+ "Basic": 5,
534
+ "Intermediate": 10,
535
+ "Advanced": 20
536
+ }
537
+
538
+ # Add fixed content here
539
+ self.fixed_content = """# Power BI: A Comprehensive Learning Guide
540
+
541
+ ## Introduction to Power BI
542
+
543
+ Power BI represents Microsoft's flagship business intelligence platform, offering a comprehensive suite of tools for data analysis and visualization. This guide will walk you through the essential concepts, from basic data connectivity to advanced implementations, helping you master this powerful platform.
544
+
545
+ ## Understanding Data Connectivity and Management
546
+
547
+ The foundation of any Power BI solution begins with data connectivity. Power BI offers two primary methods for connecting to data sources: Import mode and DirectQuery mode. Import mode loads data directly into Power BI's memory, providing faster performance and offline access capabilities. In contrast, DirectQuery maintains a live connection to your data source, ensuring real-time data access albeit with potentially slower performance due to query execution time.
548
+
549
+ When working with data sources, Power BI supports a vast array of connections including SQL Server databases, Excel spreadsheets, CSV files, web services, and SharePoint lists. Understanding how to effectively use these connections is crucial for building robust solutions. For instance, when working with Excel data, you can import not only basic tables but also Power Pivot Data Models and Power View Reports, providing flexibility in how you structure your data imports.
550
+
551
+ ## Mastering Data Modeling
552
+
553
+ Data modeling in Power BI follows best practices from dimensional modeling, with the star schema being a fundamental concept. In a star schema, you organize your data around a central fact table connected to multiple dimension tables. This structure optimizes query performance and creates clear, intuitive relationships between your data elements.
554
+
555
+ A critical distinction in Power BI modeling is understanding the difference between calculated columns and measures. Calculated columns compute values for each row and store them in memory, making them ideal for values that need to be filtered or grouped. Measures, on the other hand, calculate results at query time based on user interactions, making them perfect for aggregations and complex calculations that need to respond to different filter contexts.
556
+
557
+ ## DAX: The Language of Data Analysis
558
+
559
+ Data Analysis Expressions (DAX) serves as the formula language in Power BI, enabling you to create sophisticated calculations and data analyses. Beginning with basic functions, you'll learn to create fundamental calculations like total sales or year-to-date values. For example, a simple year-to-date sales calculation might look like:
560
+
561
+ ```
562
+ YTD Sales = TOTALYTD(SUM(Sales[Amount]), 'Date'[Date])
563
+ ```
564
+
565
+ As you advance, you'll encounter more complex scenarios requiring advanced DAX concepts. Time intelligence functions allow you to create period-over-period comparisons, while context transition helps you navigate between row and filter contexts effectively. Understanding these concepts becomes crucial when building sophisticated financial or sales analysis solutions.
566
+
567
+ ## Advanced Analysis and Visualization
568
+
569
+ Power BI's visualization capabilities extend far beyond basic charts and graphs. The platform offers a rich set of visualization tools, from standard bar and line charts to sophisticated custom visuals available through the marketplace. Learning to choose the right visualization for your data story becomes crucial for effective communication.
570
+
571
+ Consider a sales analysis scenario: you might combine a line chart showing trends over time with a map visualization displaying regional performance, while using drill-through capabilities to provide detailed product-level analysis. These interactive features allow users to explore data naturally, moving from high-level overviews to detailed insights seamlessly.
572
+
573
+ ## Security and Administration
574
+
575
+ Security in Power BI operates at multiple levels. Row-level security (RLS) allows you to control data access at a granular level, ensuring users see only the data they're authorized to view. For example, regional managers might only see sales data for their specific territories, while executive leadership sees all regions.
576
+
577
+ Administration extends beyond security to include workspace management, sharing permissions, and gateway configuration. The Enterprise Gateway facilitates secure data refresh from on-premises sources, while Personal Gateway serves individual users' needs. Understanding these components helps you build a secure and efficient BI environment.
578
+
579
+ ## Performance Optimization and Best Practices
580
+
581
+ Optimizing Power BI solutions requires attention to several key areas. Data model optimization involves choosing the right storage mode, implementing appropriate relationships, and creating efficient measures. Query performance can be enhanced through proper use of variables in DAX, implementing query folding in Power Query, and utilizing aggregations for large datasets.
582
+
583
+ For large-scale implementations, consider incremental refresh strategies to manage data loading efficiently. This might involve setting up refresh windows to load only the most recent data while maintaining historical information in a static form.
584
+
585
+ ## Real-World Implementation Scenarios
586
+
587
+ Practical application of Power BI often involves complex scenarios combining multiple concepts. Consider a financial reporting solution that requires:
588
+ - Integration with multiple data sources
589
+ - Implementation of security roles
590
+ - Automated refresh schedules
591
+ - Excel integration for detailed analysis
592
+
593
+ Or a sales performance dashboard featuring:
594
+ - Real-time data tracking
595
+ - Predictive analytics integration
596
+ - Mobile optimization
597
+ - Automated alerting systems
598
+
599
+ These scenarios require combining technical knowledge with business understanding to create effective solutions.
600
+
601
+ ## Conclusion
602
+
603
+ Mastering Power BI requires understanding not just individual components but how they work together to create effective business intelligence solutions. From basic data connectivity through advanced DAX calculations to security implementation, each element plays a crucial role in building robust, scalable BI systems. Regular practice with real-world scenarios helps reinforce these concepts and builds the experience needed to handle complex business requirements effectively.
604
+
605
+ Continue your learning journey by experimenting with different features, challenging yourself with complex scenarios, and staying updated with the platform's evolving capabilities. Remember that effective BI solutions balance technical capability with business needs, creating insights that drive meaningful business decisions."""
606
+
607
+ def get_certificate_title(self, base_title: str) -> str:
608
+ """Get certificate title with difficulty level"""
609
+ return f"{base_title} - {self.selected_level} Level"
610
 
611
  def generate_questions(self, text: str, num_questions: int) -> Tuple[bool, List[Question]]:
612
  """
 
787
  # Header
788
  gr.Markdown("""
789
  <div style="text-align: center;">
790
+ <h1>🎓 Power BI Assessment Certification </h1>
791
  <h3>Transform Your Knowledge into Recognized Achievements</h3></p>
792
  </div>
793
 
 
795
  <h4>Assessment Overview:</h4>
796
  <ul style="list-style-type: none; padding-left: 0;">
797
  <li>📌 <strong>Basic Level:</strong> 5 questions - Perfect for beginners</li>
798
+ <li>📚 <strong>Intermediate Level:</strong> 10 questions - For those with HR experience</li>
799
  <li>🎯 <strong>Advanced Level:</strong> 20 questions - Comprehensive assessment</li>
800
  <li>⏱️ <strong>Passing Score:</strong> 80% or higher</li>
801
  <li>🏆 <strong>Certificate:</strong> Awarded upon successful completion</li>
802
  </ul>
803
+ <p style="margin-top: 15px;"><i>This assessment evaluates your understanding of Power BI.</i></p>
804
  </div>
805
+ """, show_label=False)
806
+
807
  with gr.Tabs() as tabs:
808
  # Profile Setup Tab
809
  with gr.Tab(id=1, label="📋 Step 1: Profile Setup"):
 
813
 
814
  text_input = gr.Textbox(
815
  label="Learning Content",
816
+ value=quiz_app.fixed_content, # Set the fixed content
817
+ interactive=False, # Make it non-editable
818
  lines=10
819
  )
820
 
821
+ difficulty_level = gr.Radio(
822
+ choices=["Basic", "Intermediate", "Advanced"],
823
+ value="Basic",
824
+ label="Select Difficulty Level",
825
+ info="Basic: 5 questions | Intermediate: 10 questions | Advanced: 20 questions")
826
+
 
827
 
828
  with gr.Row():
 
829
  participant_photo = gr.Image(label="Your Photo (Optional)", type="filepath")
830
 
831
  generate_btn = gr.Button("Generate Assessment", variant="primary", size="lg")
 
881
  )
882
 
883
  # Certification Tab (Hidden by default)
884
+
885
  with gr.Tab(id=3, label="🎓 Step 3: Get Certified", visible=False) as cert_tab:
886
  score_display = gr.Number(label="Your Score", visible=False)
887
  course_name = gr.Textbox(
888
  label="Certification Title",
889
+ value=lambda: f"Power BI Assessment Certification", # Dynamic title with level
890
+ interactive=False
891
  )
892
+ certificate_display = gr.Image(label="Your Certificate")
893
+
894
 
 
895
  def show_certificate_tab():
896
  return [
897
  gr.update(visible=True), # Make cert_tab visible
898
+ gr.update(
899
+ value=f"Power BI Assessment Certification" # Update title with level
900
+ ),
901
  gr.update(selected=3) # Switch to cert_tab
902
  ]
903
 
904
 
905
  # Helper Functions
906
+ def on_generate_questions(text, level):
907
+ quiz_app.selected_level = level # Store selected level
908
+ num_questions = quiz_app.difficulty_levels[level] # Get number of questions for level
 
 
 
 
 
 
 
 
 
 
 
909
 
910
+ success, questions = quiz_app.generate_questions(quiz_app.fixed_content, num_questions)
911
  if not success or not questions:
912
  return [
913
  "",
 
916
  "",
917
  [],
918
  0,
919
+ [None] * num_questions, # Updated to use dynamic size
920
  gr.update(selected=1),
921
  gr.update(visible=False),
922
  gr.update(visible=False)
923
  ]
924
 
925
  question = questions[0]
926
+ question_md = f"""### Question 1\n{question.question}"""
 
927
 
928
  return [
929
  question_md,
 
997
  if 0 <= current_idx < len(final_answers):
998
  final_answers[current_idx] = current_answer
999
 
 
1000
  if not all(a is not None for a in final_answers[:len(questions)]):
1001
+ # Create list of unanswered question numbers
1002
  unanswered = [i+1 for i, a in enumerate(final_answers[:len(questions)]) if a is None]
1003
  warning_content = f"""
1004
+ <div style="background-color: #fff3cd; padding: 20px; border-radius: 10px; border-left: 5px solid #ffa000;">
1005
+ <h3 style="color: #ff6b6b; margin: 0;">⚠️ Please Complete All Questions</h3>
1006
+ <p style="margin: 10px 0;">Unanswered Questions: {', '.join(map(str, unanswered))}</p>
 
 
 
 
 
1007
  </div>
1008
  """
1009
  return [
1010
+ warning_content, # feedback_box
1011
+ gr.update(visible=True), # results_group
1012
+ 0, # score
1013
+ "", # result_message
1014
+ gr.update(visible=True), # question_box
1015
+ gr.update(visible=True), # reset_btn
1016
+ gr.update(visible=False), # view_cert_btn
1017
+ gr.update(selected=2) # tabs
1018
  ]
1019
+
 
1020
  score, passed, feedback = quiz_app.calculate_score(final_answers[:len(questions)])
1021
+
1022
+ # Create feedback content using proper Markdown with emojis
1023
+ feedback_content = f"""# Assessment Results
1024
+
1025
+ **Score: {score:.1f}%**
1026
+
1027
+ """
1028
 
1029
  for i, (q, f) in enumerate(zip(questions, feedback)):
1030
  icon = "✅" if f.is_correct else "❌"
1031
  color = "green" if f.is_correct else "red"
1032
+
1033
+ # Using markdown syntax with color formatting
1034
  feedback_content += f"""### Question {i+1}
1035
+ {q.question}
1036
+
1037
+ {icon} **Your answer:** {f.selected or 'No answer'}
1038
+ {'' if f.is_correct else f'**Correct answer:** {f.correct_answer}'}
1039
+
1040
+ """
1041
 
1042
+ # Add summary box
1043
  if passed:
1044
+ feedback_content += f"""
1045
+ ---
1046
+ ## 🎉 Congratulations!
1047
+ You passed with a score of {score:.1f}%!
1048
+ """
1049
  else:
1050
+ feedback_content += f"""
1051
+ ---
1052
+ ## Need Improvement
1053
+ You scored {score:.1f}%. You need 80% or higher to pass.
1054
+ Please try again.
1055
+ """
1056
 
1057
  return [
1058
  feedback_content, # feedback_box
 
1064
  gr.update(visible=passed), # view_cert_btn
1065
  gr.update(selected=2) # tabs
1066
  ]
 
1067
  # Event Handlers
1068
  generate_btn.click(
1069
  fn=on_generate_questions,
1070
+ inputs=[text_input, difficulty_level], # Replace num_questions with difficulty_level
1071
  outputs=[
1072
  question_display,
1073
  question_box,
 
1111
 
1112
  reset_btn.click(
1113
  fn=on_generate_questions,
1114
+ inputs=[text_input, difficulty_level], # Replace num_questions with difficulty_level
1115
  outputs=[
1116
  question_display,
1117
  question_box,
 
1125
  view_cert_btn
1126
  ]
1127
  )
1128
+
1129
  view_cert_btn.click(
1130
  fn=show_certificate_tab,
1131
+ outputs=[cert_tab, course_name, tabs] # Add course_name to outputs
1132
  )
1133
 
1134
  current_options.change(
 
1138
  )
1139
 
1140
  score_display.change(
1141
+ fn=lambda s, n, c, p: quiz_app.certificate_generator.generate(
1142
+ s, n,
1143
+ quiz_app.get_certificate_title(c), # Add difficulty level to title
1144
+ quiz_app.logo_path, p
1145
+ ) or gr.update(value=None),
1146
+ inputs=[score_display, name, course_name, participant_photo],
1147
  outputs=certificate_display
1148
  )
1149
+
1150
  return demo
1151
 
1152
  if __name__ == "__main__":