Turbiling commited on
Commit
874653b
·
verified ·
1 Parent(s): 310cba4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +498 -139
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py - Enhanced MCQ Test Generator for Hugging Face
2
  # Aligned with Pakistani National Curriculum (2006)
3
  # Developer: Najaf Ali Sharqi
4
 
@@ -9,6 +9,8 @@ from datetime import datetime
9
  from docx import Document
10
  from docx.shared import Pt, RGBColor, Inches
11
  from docx.enum.text import WD_ALIGN_PARAGRAPH
 
 
12
  import re
13
  import json
14
 
@@ -23,8 +25,7 @@ client = Groq(api_key=GROQ_API_KEY)
23
  # ---------------------------
24
  # Configuration Constants
25
  # ---------------------------
26
- APP_VERSION = "2.0"
27
- MAX_MCQS = 20
28
  MODEL_NAME = "llama-3.3-70b-versatile"
29
 
30
  # ---------------------------
@@ -51,6 +52,228 @@ subjects_by_grade = {
51
  # Chapter mapping (National Curriculum 2006)
52
  # ---------------------------
53
  chapters_by_subject_and_grade = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  "Grade 1": {
55
  "Mathematics": ["Counting & Numbers", "Basic Addition", "Basic Subtraction", "Shapes", "Measurements"],
56
  "English": ["Alphabet & Sounds", "Basic Words", "Simple Sentences", "Listening & Speaking", "Reading Short Texts"],
@@ -319,61 +542,51 @@ chapters_by_subject_and_grade = {
319
  }
320
 
321
  # ---------------------------
322
- # Question types for comprehensive assessment
323
- # ---------------------------
324
- QUESTION_TYPES = {
325
- "Multiple Choice Questions (MCQs)": {
326
- "code": "mcq",
327
- "description": "Four-option questions testing recall and application",
328
- "format": "Question with options A, B, C, D"
329
- },
330
- "Fill in the Blanks": {
331
- "code": "fill_blank",
332
- "description": "Complete sentences with missing key terms",
333
- "format": "Sentences with underlined blanks"
334
- },
335
- "Match the Column": {
336
- "code": "match_column",
337
- "description": "Connect related items from two columns",
338
- "format": "Two columns with items to match"
339
- },
340
- "Short Response Questions": {
341
- "code": "short_response",
342
- "description": "Brief written answers (2-3 sentences)",
343
- "format": "Questions requiring concise explanations"
344
- },
345
- "Essay Type Questions": {
346
- "code": "essay",
347
- "description": "Extended written responses with detailed analysis",
348
- "format": "Open-ended questions requiring paragraphs"
349
- }
350
- }
351
-
352
- # ---------------------------
353
- # Cognitive levels for item writing (Bloom's Taxonomy adapted)
354
  # ---------------------------
355
- DIFFICULTY_LEVELS = {
356
- "Knowledge (Remembering)": {
357
- "description": "Recall facts, terms, basic concepts",
358
- "keywords": ["define", "list", "identify", "name", "state"]
359
- },
360
- "Understanding (Comprehension)": {
361
- "description": "Explain ideas or concepts",
362
- "keywords": ["explain", "describe", "summarize", "interpret"]
363
- },
364
- "Application (Applying)": {
365
- "description": "Use information in new situations",
366
- "keywords": ["apply", "demonstrate", "solve", "use", "calculate"]
367
- },
368
- "Analysis (Analyzing)": {
369
- "description": "Draw connections, examine relationships",
370
- "keywords": ["analyze", "compare", "contrast", "differentiate"]
371
- },
372
- "Evaluation & Synthesis": {
373
- "description": "Justify decisions, create new solutions",
374
- "keywords": ["evaluate", "justify", "critique", "synthesize", "design"]
375
- }
376
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
 
378
  # ---------------------------
379
  # Enhanced question generation with proper item writing principles
@@ -642,8 +855,9 @@ def parse_match_column(text):
642
  return questions, answers
643
 
644
  def parse_short_response(text, expected_count):
645
- """Parse Short Response questions"""
646
- parts = re.split(r'MARKING\s+SCHEME:?', text, flags=re.IGNORECASE)
 
647
 
648
  questions = []
649
  answers = []
@@ -656,18 +870,19 @@ def parse_short_response(text, expected_count):
656
 
657
  if len(parts) >= 2:
658
  a_text = parts[1]
659
- # Extract marking schemes
660
  schemes = re.findall(r'\d+[\.\)]\s*(.+?)(?=\d+[\.\)]|$)', a_text, re.DOTALL)
661
  answers = [s.strip() for s in schemes[:expected_count]]
662
 
663
  if len(answers) < len(questions):
664
- answers.extend(['Key points to cover'] * (len(questions) - len(answers)))
665
 
666
  return questions, answers
667
 
668
  def parse_essay(text, expected_count):
669
- """Parse Essay questions"""
670
- parts = re.split(r'MARKING\s+CRITERIA:?', text, flags=re.IGNORECASE)
 
671
 
672
  questions = []
673
  answers = []
@@ -680,15 +895,31 @@ def parse_essay(text, expected_count):
680
 
681
  if len(parts) >= 2:
682
  a_text = parts[1]
683
- # Extract criteria
684
  criteria = re.findall(r'\d+[\.\)]\s*(.+?)(?=\d+[\.\)]|$)', a_text, re.DOTALL)
685
  answers = [c.strip() for c in criteria[:expected_count]]
686
 
687
  if len(answers) < len(questions):
688
- answers.extend(['Expected coverage points'] * (len(questions) - len(answers)))
689
 
690
  return questions, answers
691
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
692
  # ---------------------------
693
  # Enhanced DOCX export supporting all question types
694
  # ---------------------------
@@ -785,9 +1016,9 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
785
  if question_type_code == "mcq":
786
  for i, q in enumerate(questions, start=1):
787
  q_para = doc.add_paragraph()
788
- q_para.add_run(f"Q{i}. ").bold = True
789
  q_para.add_run(q)
790
- q_para.space_after = Pt(6)
791
  doc.add_paragraph()
792
 
793
  elif question_type_code == "fill_blank":
@@ -796,6 +1027,7 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
796
  q_para.add_run(f"{i}. ").bold = True
797
  q_para.add_run(q)
798
  q_para.space_after = Pt(8)
 
799
 
800
  elif question_type_code == "match_column":
801
  for q in questions:
@@ -811,13 +1043,13 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
811
  doc.add_paragraph()
812
  # Add space for answer
813
  for _ in range(3 if question_type_code == "short_response" else 8):
814
- doc.add_paragraph("_" * 80)
815
  doc.add_paragraph()
816
 
817
  # Answer key (on separate page)
818
  doc.add_page_break()
819
 
820
- ans_heading = doc.add_heading("ANSWER KEY / MARKING SCHEME", level=2)
821
  ans_heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
822
  for run in ans_heading.runs:
823
  run.font.color.rgb = RGBColor(153, 0, 0)
@@ -828,9 +1060,7 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
828
  # Add answers based on type
829
  if question_type_code == "mcq":
830
  # Answer table for MCQs
831
- num_rows = len(answers) + 1
832
- ans_table = doc.add_table(rows=num_rows, cols=5)
833
- ans_table.style = 'Medium Grid 1 Accent 1'
834
 
835
  headers = ["Q#", "A", "B", "C", "D"]
836
  for idx, header in enumerate(headers):
@@ -853,7 +1083,33 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
853
  else:
854
  cell.text = ""
855
  cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
856
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
857
  else:
858
  # Text-based answers for other types
859
  for i, ans in enumerate(answers, start=1):
@@ -865,7 +1121,7 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
865
  # Footer
866
  doc.add_paragraph()
867
  footer = doc.add_paragraph()
868
- footer.add_run(f"Generated by MCQ Test Generator Pro v{APP_VERSION} | Developer: Najaf Ali Sharqi | {datetime.now().strftime('%d-%m-%Y %H:%M')}").italic = True
869
  footer.runs[0].font.size = Pt(8)
870
  footer.runs[0].font.color.rgb = RGBColor(128, 128, 128)
871
  footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
@@ -883,31 +1139,61 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
883
  return None, f"Error creating document: {str(e)}"
884
 
885
  # ---------------------------
886
- # Main generation handler
887
  # ---------------------------
888
- def on_generate(grade, subject, chapter, difficulty, num_questions, test_type, school_name, question_type):
889
- """Handle question generation request"""
 
 
890
 
891
  # Validation
892
- if not all([grade, subject, chapter, difficulty, question_type]):
893
  return "⚠️ Please fill all required fields", None, None
894
 
895
  if not school_name or not school_name.strip():
896
  school_name = "Educational Institution"
897
 
898
  try:
899
- # Show progress
900
- status_msg = f"🔄 Generating {num_questions} {question_type}...\n"
901
- status_msg += f"📖 Grade: {grade} | Subject: {subject}\n"
902
- status_msg += f"📚 Chapter: {chapter}\n"
903
- status_msg += f"🎯 Cognitive Level: {difficulty}\n"
904
- status_msg += " Please wait..."
905
-
906
- # Generate questions
907
- questions, answers, error, q_type_code = generate_questions(
908
- grade, subject, chapter, difficulty,
909
- num_questions, test_type, school_name, question_type
910
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
911
 
912
  if error:
913
  return f"❌ Error: {error}", None, None
@@ -934,7 +1220,8 @@ def on_generate(grade, subject, chapter, difficulty, num_questions, test_type, s
934
  # Export to Word
935
  file_path, doc_error = export_to_word(
936
  questions, answers, grade, subject, chapter,
937
- difficulty, test_type, school_name, total_marks, q_type_code
 
938
  )
939
 
940
  if doc_error:
@@ -942,15 +1229,20 @@ def on_generate(grade, subject, chapter, difficulty, num_questions, test_type, s
942
 
943
  # Success message
944
  success_msg = f"✅ Test generated successfully!\n\n"
945
- success_msg += f"📊 Statistics:\n"
946
  success_msg += f"• Question Type: {question_type}\n"
947
  success_msg += f"• Total Questions: {len(questions)}\n"
948
  success_msg += f"• Total Marks: {total_marks}\n"
949
- success_msg += f"• Grade Level: {grade}\n"
950
- success_msg += f"• Subject: {subject}\n"
951
  success_msg += f"• Chapter: {chapter}\n"
952
- success_msg += f"• Cognitive Level: {difficulty}\n\n"
953
- success_msg += f"📥 Download your test document below"
 
 
 
 
 
 
954
 
955
  # Preview
956
  preview_count = min(3, len(questions))
@@ -958,7 +1250,7 @@ def on_generate(grade, subject, chapter, difficulty, num_questions, test_type, s
958
 
959
  for i, q in enumerate(questions[:preview_count], 1):
960
  if q_type_code == "mcq":
961
- preview += f"Q{i}. {q[:200]}...\n\n" if len(q) > 200 else f"Q{i}. {q}\n\n"
962
  else:
963
  preview += f"{i}. {q[:200]}...\n\n" if len(q) > 200 else f"{i}. {q}\n\n"
964
 
@@ -989,16 +1281,18 @@ def create_ui():
989
  # Header
990
  gr.Markdown(
991
  """
992
- # 📚 MCQ Test Generator Pro
993
- ### Professional Assessment Tool Aligned with Pakistani National Curriculum (2006)
 
 
994
  """,
995
  elem_classes="header"
996
  )
997
 
998
  gr.Markdown(
999
  """
1000
- Generate high-quality Multiple Choice Questions for educational assessments.
1001
- Based on Bloom's Taxonomy and best practices in item writing.
1002
  """,
1003
  elem_classes="description"
1004
  )
@@ -1073,20 +1367,66 @@ def create_ui():
1073
  info="Select specific chapter or unit"
1074
  )
1075
 
1076
- difficulty_dropdown = gr.Dropdown(
1077
- choices=list(DIFFICULTY_LEVELS.keys()),
1078
- value="Understanding (Comprehension)",
1079
- label="Cognitive Level (Bloom's Taxonomy)",
1080
- info="Select cognitive complexity level"
1081
  )
1082
 
1083
- # Show description of selected difficulty
1084
- difficulty_info = gr.Markdown(
1085
- """
1086
- **Level Description:** Explain ideas or concepts
 
1087
 
1088
- **Keywords:** explain, describe, summarize, interpret
1089
- """,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1090
  visible=True
1091
  )
1092
 
@@ -1114,8 +1454,16 @@ def create_ui():
1114
  - **Match the Column**: Assesses relationships and connections
1115
  - **Short Response**: Evaluates understanding and explanation
1116
  - **Essay Questions**: Measures critical thinking and synthesis
1117
- - Select appropriate cognitive level for your students
1118
  - Review generated questions before final use
 
 
 
 
 
 
 
 
1119
  """
1120
  )
1121
 
@@ -1158,12 +1506,12 @@ def create_ui():
1158
  """
1159
  ---
1160
  <div class="footer">
1161
- <strong>MCQ Test Generator Pro v2.0</strong><br>
1162
- Comprehensive Assessment Tool with 5 Question Types<br>
1163
  Aligned with Pakistani National Curriculum (2006)<br>
1164
  Developer: <strong>Najaf Ali Sharqi</strong><br>
1165
- Based on Bloom's Taxonomy & Professional Item Writing Standards<br><br>
1166
- 📧 For support or feedback, please contact the developer
1167
  </div>
1168
  """,
1169
  elem_classes="footer"
@@ -1184,19 +1532,6 @@ def create_ui():
1184
  return gr.update(choices=chapters, value=None)
1185
  return gr.update(choices=[], value=None)
1186
 
1187
- def update_difficulty_info(difficulty):
1188
- """Update difficulty level description"""
1189
- if difficulty in DIFFICULTY_LEVELS:
1190
- info = DIFFICULTY_LEVELS[difficulty]
1191
- desc = info.get('description', '')
1192
- keywords = ', '.join(info.get('keywords', []))
1193
- return f"""
1194
- **Level Description:** {desc}
1195
-
1196
- **Keywords:** {keywords}
1197
- """
1198
- return ""
1199
-
1200
  def update_question_type_info(q_type):
1201
  """Update question type description"""
1202
  if q_type in QUESTION_TYPES:
@@ -1210,6 +1545,16 @@ def create_ui():
1210
  """
1211
  return ""
1212
 
 
 
 
 
 
 
 
 
 
 
1213
  # Connect event handlers
1214
  grade_dropdown.change(
1215
  update_subjects,
@@ -1229,29 +1574,43 @@ def create_ui():
1229
  outputs=[chapter_dropdown]
1230
  )
1231
 
1232
- difficulty_dropdown.change(
1233
- update_difficulty_info,
1234
- inputs=[difficulty_dropdown],
1235
- outputs=[difficulty_info]
1236
- )
1237
-
1238
  question_type.change(
1239
  update_question_type_info,
1240
  inputs=[question_type],
1241
  outputs=[question_type_info]
1242
  )
1243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1244
  generate_btn.click(
1245
  on_generate,
1246
  inputs=[
1247
  grade_dropdown,
1248
  subject_dropdown,
1249
  chapter_dropdown,
1250
- difficulty_dropdown,
1251
- num_questions,
1252
  test_type,
1253
  school_name,
1254
- question_type
 
 
 
 
 
 
 
 
1255
  ],
1256
  outputs=[output_text, output_file, file_status]
1257
  )
 
1
+ # app.py - Enhanced Test Generator for Hugging Face
2
  # Aligned with Pakistani National Curriculum (2006)
3
  # Developer: Najaf Ali Sharqi
4
 
 
9
  from docx import Document
10
  from docx.shared import Pt, RGBColor, Inches
11
  from docx.enum.text import WD_ALIGN_PARAGRAPH
12
+ from docx.oxml.ns import qn
13
+ from docx.oxml import OxmlElement
14
  import re
15
  import json
16
 
 
25
  # ---------------------------
26
  # Configuration Constants
27
  # ---------------------------
28
+ APP_VERSION = "2.5"
 
29
  MODEL_NAME = "llama-3.3-70b-versatile"
30
 
31
  # ---------------------------
 
52
  # Chapter mapping (National Curriculum 2006)
53
  # ---------------------------
54
  chapters_by_subject_and_grade = {
55
+ "Grade 1": {
56
+ "Mathematics": ["Counting & Numbers", "Basic Addition", "Basic Subtraction", "Shapes", "Measurements"],
57
+ "English": ["Alphabet & Sounds", "Basic Words", "Simple Sentences", "Listening & Speaking", "Reading Short Texts"],
58
+ "Urdu": ["حروف", "الفاظ", "سادہ جملے", "پڑھنا", "لکھنا"],
59
+ "Islamiyat": ["Basic Beliefs", "Prophets Stories", "Good Manners", "Prayers & Worship"],
60
+ "General Knowledge": ["My Body", "My Home", "My School", "Seasons"]
61
+ },
62
+ "Grade 2": {
63
+ "Mathematics": ["Place Value", "Addition & Subtraction", "Money", "Time", "Shapes"],
64
+ "English": ["Parts of Speech Basics", "Simple Grammar", "Short Comprehension", "Vocabulary Building"],
65
+ "Urdu": ["الفاظ و جملے", "مختصر کہانیاں", "حروفِ صحیح"],
66
+ "Islamiyat": ["Prophets", "Good Deeds", "Mosque Etiquette"],
67
+ "General Knowledge": ["Plants & Animals", "Local Community", "Transport"]
68
+ },
69
+ "Grade 3": {
70
+ "Mathematics": ["Multiplication", "Division", "Fractions", "Geometry Basics", "Measurement"],
71
+ "English": ["Tenses (simple)", "Comprehension Passages", "Vocabulary", "Sentence Formation"],
72
+ "Urdu": ["کالم و مضامین", "قواعدِ اردو", "کہانیاں"],
73
+ "Science": ["Plants", "Animals", "Human Body", "Materials"],
74
+ "Islamiyat": ["Basics of Iman", "Seerat", "Manners"],
75
+ "General Knowledge": ["Environment", "Community Helpers", "Safety"]
76
+ },
77
+ "Grade 4": {
78
+ "Mathematics": ["Fractions & Decimals", "Geometry", "Data Handling", "Word Problems"],
79
+ "English": ["Grammar (intermediate)", "Comprehension", "Writing Short Paragraphs"],
80
+ "Urdu": ["نظم و نثر", "قواعد", "مفردات"],
81
+ "Science": ["Ecosystems", "Forces", "Heat & Energy"],
82
+ "Islamiyat": ["Pillars of Islam", "Seerah Stories"],
83
+ "General Knowledge": ["Maps & Directions", "Cultural Heritage", "Technology"]
84
+ },
85
+ "Grade 5": {
86
+ "Mathematics": ["Numbers & Operations", "Geometry", "Statistics", "Ratio & Proportion"],
87
+ "English": ["Advanced Grammar Basics", "Paragraph Writing", "Comprehension"],
88
+ "Urdu": ["ادبی مطالعہ", "تعبیر و تشریح"],
89
+ "Science": ["Cells & Life", "Matter", "Energy"],
90
+ "Islamiyat": ["Quranic Stories", "Akhlaq"],
91
+ "Social Studies": ["Pakistan Geography", "History Basics", "Civics Introduction"]
92
+ },
93
+ "Grade 6": {
94
+ "Mathematics": ["Number System", "Algebra Introduction", "Geometry", "Data Handling"],
95
+ "English": ["Grammar (complex)", "Essay Writing", "Comprehension Skills"],
96
+ "Urdu": ["ادب و نحو", "تحریر"],
97
+ "Science": ["Atoms & Molecules", "Human Body", "Plants"],
98
+ "Islamiyat": ["Seerah & Ahkam"],
99
+ "Social Studies": ["World Geography", "Historical Events", "Government"]
100
+ },
101
+ "Grade 7": {
102
+ "Mathematics": ["Algebra", "Geometry", "Mensuration", "Statistics"],
103
+ "English": ["Poetry & Prose", "Grammar", "Comprehension"],
104
+ "Urdu": ["نثر و شاعری", "قواعد"],
105
+ "Science": ["Cell Biology", "Human Systems", "Electricity Basics"],
106
+ "Islamiyat": ["Islamic History", "Moral Teachings"],
107
+ "Social Studies": ["Geography Basics", "History", "Civics"],
108
+ "Computer": ["Basic ICT", "Computer Hardware", "Introduction to Coding"]
109
+ },
110
+ "Grade 8": {
111
+ "Mathematics": ["Linear Equations", "Geometry", "Pythagoras", "Graphs"],
112
+ "English": ["Advanced Comprehension", "Composition", "Grammar"],
113
+ "Urdu": ["تجزیہ ادب", "تحقیقِ مختصر"],
114
+ "Science": ["Forces & Motion", "Heat", "Waves Basics"],
115
+ "Islamiyat": ["Islamic Law Basics", "Seerah"],
116
+ "Social Studies": ["Regional Geography", "Historical Events"],
117
+ "Computer": ["Algorithms", "Basic Programming"]
118
+ },
119
+ "Grade 9": {
120
+ "Mathematics": ["Number Systems & Algebra", "Coordinate Geometry", "Trigonometry", "Graphs"],
121
+ "English": ["Advanced Grammar", "Comprehension", "Writing Skills"],
122
+ "Urdu": ["ادب اور نثر", "نظم", "مضامین"],
123
+ "Biology": [
124
+ "Introduction to Biology", "Solving a Biological Problem", "Biodiversity",
125
+ "Cells and Tissues", "Cell Cycle", "Enzymes", "Bioenergetics", "Nutrition", "Transport"
126
+ ],
127
+ "Chemistry": [
128
+ "Fundamentals of Chemistry", "Structure of Atoms", "Periodic Table and Periodicity of Properties",
129
+ "Structure of Molecules", "Physical States of Matter", "Solutions", "Electrochemistry", "Chemical Reactivity"
130
+ ],
131
+ "Physics": [
132
+ "Physical Quantities and Measurement", "Kinematics", "Dynamics", "Turning Effect of Forces",
133
+ "Gravitation", "Work and Energy", "Properties of Matter", "Thermal Properties of Matter", "Transfer of Heat"
134
+ ],
135
+ "Islamiyat": ["Seerat of Prophet", "Faith & Beliefs", "Worship Practices"],
136
+ "Pakistan Studies": ["Ideological Basis of Pakistan", "Making of Pakistan", "Land and Environment", "History of Pakistan"]
137
+ },
138
+ "Grade 10": {
139
+ "Mathematics": ["Advanced Algebra", "Trigonometry", "Geometry", "Probability"],
140
+ "English": ["Literature", "Advanced Composition", "Comprehension"],
141
+ "Urdu": ["ادبِ جدید", "تحقیقی مضمون"],
142
+ "Biology": [
143
+ "Gaseous Exchange", "Homeostasis", "Coordination", "Support and Movement",
144
+ "Reproduction", "Inheritance", "Man and His Environment", "Biotechnology", "Pharmacology"
145
+ ],
146
+ "Chemistry": [
147
+ "Chemical Equilibrium", "Acids, Bases and Salts", "Organic Chemistry", "Hydrocarbons",
148
+ "Biochemistry", "Environmental Chemistry I: The Atmosphere", "Environmental Chemistry II: Water", "Chemical Industries"
149
+ ],
150
+ "Physics": [
151
+ "Simple Harmonic Motion and Waves", "Sound", "Geometrical Optics", "Electrostatics",
152
+ "Current Electricity", "Electromagnetism", "Introductory Electronics",
153
+ "Information and Communication Technology", "Radioactivity"
154
+ ],
155
+ "Islamiyat": ["Islamic Studies II", "Ethics & Society", "Fiqh Basics"],
156
+ "Pakistan Studies": [
157
+ "History of Pakistan-II", "Pakistan in World Affairs", "Economic Developments",
158
+ "Population, Society and Culture of Pakistan"
159
+ ]
160
+ },
161
+ "Grade 11": {
162
+ "Mathematics": ["Advanced Algebra & Calculus Intro", "Coordinate Geometry", "Trigonometry", "Vectors"],
163
+ "English": ["Academic Writing", "Literature Studies", "Critical Reading"],
164
+ "Urdu": ["ادبی مطالعہ", "نظم و نثر کی تشریح"],
165
+ "Biology": [
166
+ "Cell Structure and Functions", "Biological Molecules", "Enzymes", "Bioenergetics",
167
+ "Acellular Life", "Prokaryotes", "Protists and Fungi", "Diversity among Plants",
168
+ "Diversity among Animals", "Form and Functions in Plants", "Digestion", "Circulation", "Immunity"
169
+ ],
170
+ "Chemistry": [
171
+ "Stoichiometry", "Atomic Structure", "Theories of Covalent Bonding and Shapes of Molecules",
172
+ "States of Matter I: Gases", "States of Matter II: Liquids", "States of Matter III: Solids",
173
+ "Chemical Equilibrium", "Acids, Bases and Salts", "Chemical Kinetics",
174
+ "Solutions and Colloids", "Thermochemistry", "Oxidation, Reduction and Electrochemistry"
175
+ ],
176
+ "Physics": [
177
+ "Measurement", "Vectors and Equilibrium", "Forces and Motion", "Work and Energy",
178
+ "Rotational and Circular Motion", "Fluid Dynamics", "Oscillations", "Waves",
179
+ "Physical Optics", "Thermodynamics", "Electrostatics", "Current Electricity"
180
+ ],
181
+ "Computer": ["Programming Fundamentals", "Data Structures Intro", "Databases"],
182
+ "Islamiyat": ["Advanced Seerah", "Comparative Religion"],
183
+ "Pakistan Studies": [
184
+ "Pakistan in Geographical Perspective", "Pakistan Resources", "Historical Perspective (Ancient to Modern)",
185
+ "Islam and Pakistan", "Administrative System", "Political and Constitutional Developments", "Human Rights"
186
+ ]
187
+ },
188
+ "Grade 12": {
189
+ "Mathematics": ["Calculus", "Advanced Algebra", "Statistics", "Analytical Geometry"],
190
+ "English": ["Research Writing", "Advanced Literature", "Critical Analysis"],
191
+ "Urdu": ["تحقیق و تنقید", "ادبی شخصیات"],
192
+ "Biology": [
193
+ "Respiration", "Homeostasis", "Support and Movement", "Nervous Coordination",
194
+ "Chemical Coordination", "Behavior", "Reproduction", "Development and Aging",
195
+ "Inheritance", "Chromosome and DNA", "Evolution", "Man and His Environment",
196
+ "Biotechnology", "Biology and Human Welfare"
197
+ ],
198
+ "Chemistry": [
199
+ "s and p Block Elements", "d-Block Elements", "Organic Compounds", "Hydrocarbons",
200
+ "Alkyl Halides and Amines", "Alcohols and Phenols", "Aldehydes and Ketones",
201
+ "Carboxylic Acids and Functional Derivatives", "Biochemistry", "Industrial Chemistry",
202
+ "Environmental Chemistry", "Analytical Chemistry"
203
+ ],
204
+ "Physics": [
205
+ "Electromagnetism", "Electromagnetic Induction", "Alternating Current", "Physics of Solids",
206
+ "Electronics", "Dawn of Modern Physics", "Atomic Spectra", "Nuclear Physics"
207
+ ],
208
+ "Computer": ["Web Technologies", "Advanced Programming Concepts"],
209
+ "Islamiyat": ["Advanced Islamic Thought", "Islamic Jurisprudence"],
210
+ "Pakistan Studies": [
211
+ "Society and Culture", "Foreign Relations of Pakistan", "Economic Development",
212
+ "Sports, Tourism and National Identity", "Contemporary Challenges and Policies"
213
+ ]
214
+ }
215
+ }
216
+
217
+ # ---------------------------
218
+ # Question types for comprehensive assessment
219
+ # ---------------------------
220
+ QUESTION_TYPES = {
221
+ "Multiple Choice Questions (MCQs)": {
222
+ "code": "mcq",
223
+ "description": "Four-option questions testing recall and application",
224
+ "format": "Question with options A, B, C, D"
225
+ },
226
+ "Fill in the Blanks": {
227
+ "code": "fill_blank",
228
+ "description": "Complete sentences with missing key terms",
229
+ "format": "Sentences with underlined blanks"
230
+ },
231
+ "Match the Column": {
232
+ "code": "match_column",
233
+ "description": "Connect related items from two columns",
234
+ "format": "Two columns with items to match"
235
+ },
236
+ "Short Response Questions": {
237
+ "code": "short_response",
238
+ "description": "Brief written answers (2-3 sentences)",
239
+ "format": "Questions requiring concise explanations"
240
+ },
241
+ "Essay Type Questions": {
242
+ "code": "essay",
243
+ "description": "Extended written responses with detailed analysis",
244
+ "format": "Open-ended questions requiring paragraphs"
245
+ }
246
+ }
247
+
248
+ # ---------------------------
249
+ # Cognitive levels for item writing (Bloom's Taxonomy)
250
+ # ---------------------------
251
+ DIFFICULTY_LEVELS = {
252
+ "Remembering": {
253
+ "description": "Recall facts, terms, basic concepts",
254
+ "keywords": ["define", "list", "identify", "name", "state", "recall"]
255
+ },
256
+ "Understanding": {
257
+ "description": "Explain ideas or concepts",
258
+ "keywords": ["explain", "describe", "summarize", "interpret", "paraphrase"]
259
+ },
260
+ "Applying": {
261
+ "description": "Use information in new situations",
262
+ "keywords": ["apply", "demonstrate", "solve", "use", "calculate", "implement"]
263
+ },
264
+ "Analyzing": {
265
+ "description": "Draw connections, examine relationships",
266
+ "keywords": ["analyze", "compare", "contrast", "differentiate", "examine"]
267
+ },
268
+ "Evaluating": {
269
+ "description": "Justify decisions, make judgments",
270
+ "keywords": ["evaluate", "justify", "critique", "assess", "judge"]
271
+ },
272
+ "Creating": {
273
+ "description": "Produce new or original work",
274
+ "keywords": ["create", "design", "construct", "develop", "formulate"]
275
+ }
276
+ }
277
  "Grade 1": {
278
  "Mathematics": ["Counting & Numbers", "Basic Addition", "Basic Subtraction", "Shapes", "Measurements"],
279
  "English": ["Alphabet & Sounds", "Basic Words", "Simple Sentences", "Listening & Speaking", "Reading Short Texts"],
 
542
  }
543
 
544
  # ---------------------------
545
+ # Enhanced question generation with Bloom's Taxonomy distribution
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
546
  # ---------------------------
547
+ def generate_questions_multi_level(grade, subject, chapter, test_type, school_name, question_type,
548
+ bloom_distribution, total_questions):
549
+ """Generate questions with mixed cognitive levels based on user distribution"""
550
+
551
+ all_questions = []
552
+ all_answers = []
553
+
554
+ try:
555
+ # Calculate number of questions per level
556
+ for level, percentage in bloom_distribution.items():
557
+ if percentage > 0:
558
+ num_q = int((percentage / 100) * total_questions)
559
+ if num_q > 0:
560
+ questions, answers, error, q_type_code = generate_questions(
561
+ grade, subject, chapter, level,
562
+ num_q, test_type, school_name, question_type
563
+ )
564
+
565
+ if error:
566
+ return [], [], error, "mcq"
567
+
568
+ all_questions.extend(questions)
569
+ all_answers.extend(answers)
570
+
571
+ # Ensure we have the right number of questions
572
+ if len(all_questions) < total_questions:
573
+ # Generate additional questions at first non-zero level
574
+ shortage = total_questions - len(all_questions)
575
+ first_level = next((k for k, v in bloom_distribution.items() if v > 0), "Understanding")
576
+
577
+ extra_q, extra_a, error, q_type_code = generate_questions(
578
+ grade, subject, chapter, first_level,
579
+ shortage, test_type, school_name, question_type
580
+ )
581
+
582
+ if not error:
583
+ all_questions.extend(extra_q)
584
+ all_answers.extend(extra_a)
585
+
586
+ return all_questions[:total_questions], all_answers[:total_questions], None, q_type_code
587
+
588
+ except Exception as e:
589
+ return [], [], f"Error in multi-level generation: {str(e)}", "mcq"
590
 
591
  # ---------------------------
592
  # Enhanced question generation with proper item writing principles
 
855
  return questions, answers
856
 
857
  def parse_short_response(text, expected_count):
858
+ """Parse Short Response questions - separating questions from expected answers"""
859
+ # Split by expected answers section
860
+ parts = re.split(r'EXPECTED\s+ANSWERS?:?|MARKING\s+SCHEME:?', text, flags=re.IGNORECASE)
861
 
862
  questions = []
863
  answers = []
 
870
 
871
  if len(parts) >= 2:
872
  a_text = parts[1]
873
+ # Extract expected answers/key points
874
  schemes = re.findall(r'\d+[\.\)]\s*(.+?)(?=\d+[\.\)]|$)', a_text, re.DOTALL)
875
  answers = [s.strip() for s in schemes[:expected_count]]
876
 
877
  if len(answers) < len(questions):
878
+ answers.extend(['Key points: Provide comprehensive explanation with examples'] * (len(questions) - len(answers)))
879
 
880
  return questions, answers
881
 
882
  def parse_essay(text, expected_count):
883
+ """Parse Essay questions - separating questions from expected answers"""
884
+ # Split by expected answers section
885
+ parts = re.split(r'EXPECTED\s+ANSWERS?:?|MARKING\s+CRITERIA:?', text, flags=re.IGNORECASE)
886
 
887
  questions = []
888
  answers = []
 
895
 
896
  if len(parts) >= 2:
897
  a_text = parts[1]
898
+ # Extract criteria/expected coverage
899
  criteria = re.findall(r'\d+[\.\)]\s*(.+?)(?=\d+[\.\)]|$)', a_text, re.DOTALL)
900
  answers = [c.strip() for c in criteria[:expected_count]]
901
 
902
  if len(answers) < len(questions):
903
+ answers.extend(['Main points: Detailed analysis with evidence, examples, and logical argumentation'] * (len(questions) - len(answers)))
904
 
905
  return questions, answers
906
 
907
+ def create_answer_table(doc, answers, num_cols=5):
908
+ """Helper function to create formatted answer table"""
909
+ num_rows = len(answers) + 1
910
+ ans_table = doc.add_table(rows=num_rows, cols=num_cols)
911
+ ans_table.style = 'Medium Grid 1 Accent 1'
912
+
913
+ # Set column widths
914
+ for row in ans_table.rows:
915
+ for idx, cell in enumerate(row.cells):
916
+ if idx == 0:
917
+ cell.width = Inches(0.6)
918
+ else:
919
+ cell.width = Inches(1.2)
920
+
921
+ return ans_table
922
+
923
  # ---------------------------
924
  # Enhanced DOCX export supporting all question types
925
  # ---------------------------
 
1016
  if question_type_code == "mcq":
1017
  for i, q in enumerate(questions, start=1):
1018
  q_para = doc.add_paragraph()
1019
+ q_para.add_run(f"{i}. ").bold = True
1020
  q_para.add_run(q)
1021
+ q_para.space_after = Pt(8)
1022
  doc.add_paragraph()
1023
 
1024
  elif question_type_code == "fill_blank":
 
1027
  q_para.add_run(f"{i}. ").bold = True
1028
  q_para.add_run(q)
1029
  q_para.space_after = Pt(8)
1030
+ doc.add_paragraph()
1031
 
1032
  elif question_type_code == "match_column":
1033
  for q in questions:
 
1043
  doc.add_paragraph()
1044
  # Add space for answer
1045
  for _ in range(3 if question_type_code == "short_response" else 8):
1046
+ doc.add_paragraph("_" * 85)
1047
  doc.add_paragraph()
1048
 
1049
  # Answer key (on separate page)
1050
  doc.add_page_break()
1051
 
1052
+ ans_heading = doc.add_heading("ANSWER KEY", level=2)
1053
  ans_heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
1054
  for run in ans_heading.runs:
1055
  run.font.color.rgb = RGBColor(153, 0, 0)
 
1060
  # Add answers based on type
1061
  if question_type_code == "mcq":
1062
  # Answer table for MCQs
1063
+ ans_table = create_answer_table(doc, answers, 5)
 
 
1064
 
1065
  headers = ["Q#", "A", "B", "C", "D"]
1066
  for idx, header in enumerate(headers):
 
1083
  else:
1084
  cell.text = ""
1085
  cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
1086
+
1087
+ elif question_type_code == "fill_blank":
1088
+ # Tabular answer key for Fill in the Blanks
1089
+ ans_table = create_answer_table(doc, answers, 2)
1090
+
1091
+ # Headers
1092
+ headers = ["Q#", "Correct Answer"]
1093
+ for idx, header in enumerate(headers):
1094
+ cell = ans_table.cell(0, idx)
1095
+ cell.text = header
1096
+ cell.paragraphs[0].runs[0].bold = True
1097
+ cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
1098
+
1099
+ # Fill answers
1100
+ for r, ans in enumerate(answers, start=1):
1101
+ ans_table.cell(r, 0).text = str(r)
1102
+ ans_table.cell(r, 0).paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
1103
+ ans_table.cell(r, 1).text = str(ans)
1104
+
1105
+ elif question_type_code in ["short_response", "essay"]:
1106
+ # Expected answers for subjective questions
1107
+ for i, ans in enumerate(answers, start=1):
1108
+ ans_para = doc.add_paragraph()
1109
+ ans_para.add_run(f"Q{i}. Expected Answer:").bold = True
1110
+ doc.add_paragraph(str(ans))
1111
+ doc.add_paragraph()
1112
+
1113
  else:
1114
  # Text-based answers for other types
1115
  for i, ans in enumerate(answers, start=1):
 
1121
  # Footer
1122
  doc.add_paragraph()
1123
  footer = doc.add_paragraph()
1124
+ footer.add_run(f"Generated by Test Generator Pro v{APP_VERSION} | Developer: Najaf Ali Sharqi | {datetime.now().strftime('%d-%m-%Y %H:%M')}").italic = True
1125
  footer.runs[0].font.size = Pt(8)
1126
  footer.runs[0].font.color.rgb = RGBColor(128, 128, 128)
1127
  footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
 
1139
  return None, f"Error creating document: {str(e)}"
1140
 
1141
  # ---------------------------
1142
+ # Main generation handler with Bloom's Taxonomy distribution
1143
  # ---------------------------
1144
+ def on_generate(grade, subject, chapter, test_type, school_name, question_type,
1145
+ use_bloom_mix, bloom_remember, bloom_understand, bloom_apply,
1146
+ bloom_analyze, bloom_evaluate, bloom_create, num_questions):
1147
+ """Handle question generation request with optional Bloom's distribution"""
1148
 
1149
  # Validation
1150
+ if not all([grade, subject, chapter, question_type]):
1151
  return "⚠️ Please fill all required fields", None, None
1152
 
1153
  if not school_name or not school_name.strip():
1154
  school_name = "Educational Institution"
1155
 
1156
  try:
1157
+ # Check if using Bloom's mix
1158
+ if use_bloom_mix:
1159
+ # Validate percentages
1160
+ total_percent = bloom_remember + bloom_understand + bloom_apply + bloom_analyze + bloom_evaluate + bloom_create
1161
+ if total_percent != 100:
1162
+ return f" Bloom's Taxonomy percentages must total 100% (currently {total_percent}%)", None, None
1163
+
1164
+ bloom_distribution = {
1165
+ "Remembering": bloom_remember,
1166
+ "Understanding": bloom_understand,
1167
+ "Applying": bloom_apply,
1168
+ "Analyzing": bloom_analyze,
1169
+ "Evaluating": bloom_evaluate,
1170
+ "Creating": bloom_create
1171
+ }
1172
+
1173
+ # Show progress
1174
+ status_msg = f"🔄 Generating {num_questions} {question_type} with mixed cognitive levels...\n"
1175
+ status_msg += f"📊 Bloom's Distribution:\n"
1176
+ for level, pct in bloom_distribution.items():
1177
+ if pct > 0:
1178
+ status_msg += f" • {level}: {pct}% ({int(pct * num_questions / 100)} questions)\n"
1179
+
1180
+ # Generate with mixed levels
1181
+ questions, answers, error, q_type_code = generate_questions_multi_level(
1182
+ grade, subject, chapter, test_type, school_name, question_type,
1183
+ bloom_distribution, num_questions
1184
+ )
1185
+ else:
1186
+ # Single level generation (default to Understanding)
1187
+ status_msg = f"🔄 Generating {num_questions} {question_type}...\n"
1188
+ status_msg += f"📖 Grade: {grade} | Subject: {subject}\n"
1189
+ status_msg += f"📚 Chapter: {chapter}\n"
1190
+ status_msg += f"🎯 Cognitive Level: Understanding\n"
1191
+ status_msg += "⏳ Please wait..."
1192
+
1193
+ questions, answers, error, q_type_code = generate_questions(
1194
+ grade, subject, chapter, "Understanding",
1195
+ num_questions, test_type, school_name, question_type
1196
+ )
1197
 
1198
  if error:
1199
  return f"❌ Error: {error}", None, None
 
1220
  # Export to Word
1221
  file_path, doc_error = export_to_word(
1222
  questions, answers, grade, subject, chapter,
1223
+ "Mixed Cognitive Levels" if use_bloom_mix else "Understanding",
1224
+ test_type, school_name, total_marks, q_type_code
1225
  )
1226
 
1227
  if doc_error:
 
1229
 
1230
  # Success message
1231
  success_msg = f"✅ Test generated successfully!\n\n"
1232
+ success_msg += f"📊 Test Statistics:\n"
1233
  success_msg += f"• Question Type: {question_type}\n"
1234
  success_msg += f"• Total Questions: {len(questions)}\n"
1235
  success_msg += f"• Total Marks: {total_marks}\n"
1236
+ success_msg += f"• Grade: {grade} | Subject: {subject}\n"
 
1237
  success_msg += f"• Chapter: {chapter}\n"
1238
+
1239
+ if use_bloom_mix:
1240
+ success_msg += f"\n🎯 Bloom's Taxonomy Distribution:\n"
1241
+ for level, pct in bloom_distribution.items():
1242
+ if pct > 0:
1243
+ success_msg += f" • {level}: {pct}%\n"
1244
+
1245
+ success_msg += f"\n📥 Download your test document below"
1246
 
1247
  # Preview
1248
  preview_count = min(3, len(questions))
 
1250
 
1251
  for i, q in enumerate(questions[:preview_count], 1):
1252
  if q_type_code == "mcq":
1253
+ preview += f"{i}. {q[:200]}...\n\n" if len(q) > 200 else f"{i}. {q}\n\n"
1254
  else:
1255
  preview += f"{i}. {q[:200]}...\n\n" if len(q) > 200 else f"{i}. {q}\n\n"
1256
 
 
1281
  # Header
1282
  gr.Markdown(
1283
  """
1284
+ # 📚 Test Generator
1285
+ ### **Developer: Najaf Ali Sharqi**
1286
+
1287
+ Professional Assessment Tool Aligned with Pakistani National Curriculum (2006)
1288
  """,
1289
  elem_classes="header"
1290
  )
1291
 
1292
  gr.Markdown(
1293
  """
1294
+ Generate high-quality assessment questions with multiple formats and Bloom's Taxonomy integration.
1295
+ Perfect for educators creating comprehensive tests for Grades 1-12.
1296
  """,
1297
  elem_classes="description"
1298
  )
 
1367
  info="Select specific chapter or unit"
1368
  )
1369
 
1370
+ # Bloom's Taxonomy Distribution Section
1371
+ use_bloom_mix = gr.Checkbox(
1372
+ label="📊 Use Mixed Bloom's Taxonomy Levels",
1373
+ value=False,
1374
+ info="Create tests with questions from multiple cognitive levels"
1375
  )
1376
 
1377
+ bloom_percentages = gr.Column(visible=False)
1378
+
1379
+ with bloom_percentages:
1380
+ gr.Markdown("### Set Percentage for Each Cognitive Level")
1381
+ gr.Markdown("*(Total must equal 100%)*")
1382
 
1383
+ with gr.Row():
1384
+ bloom_remember = gr.Slider(
1385
+ minimum=0, maximum=100, value=30, step=5,
1386
+ label="Remembering %",
1387
+ info="Recall facts and basic concepts"
1388
+ )
1389
+ bloom_understand = gr.Slider(
1390
+ minimum=0, maximum=100, value=30, step=5,
1391
+ label="Understanding %",
1392
+ info="Explain ideas and concepts"
1393
+ )
1394
+
1395
+ with gr.Row():
1396
+ bloom_apply = gr.Slider(
1397
+ minimum=0, maximum=100, value=20, step=5,
1398
+ label="Applying %",
1399
+ info="Use information in new situations"
1400
+ )
1401
+ bloom_analyze = gr.Slider(
1402
+ minimum=0, maximum=100, value=10, step=5,
1403
+ label="Analyzing %",
1404
+ info="Draw connections and relationships"
1405
+ )
1406
+
1407
+ with gr.Row():
1408
+ bloom_evaluate = gr.Slider(
1409
+ minimum=0, maximum=100, value=10, step=5,
1410
+ label="Evaluating %",
1411
+ info="Justify decisions and make judgments"
1412
+ )
1413
+ bloom_create = gr.Slider(
1414
+ minimum=0, maximum=100, value=0, step=5,
1415
+ label="Creating %",
1416
+ info="Produce new or original work"
1417
+ )
1418
+
1419
+ bloom_total = gr.Textbox(
1420
+ label="Total Percentage",
1421
+ value="100%",
1422
+ interactive=False
1423
+ )
1424
+
1425
+ difficulty_dropdown = gr.Dropdown(
1426
+ choices=list(DIFFICULTY_LEVELS.keys()),
1427
+ value="Understanding",
1428
+ label="Single Cognitive Level (if not using mix)",
1429
+ info="Select one level for entire test",
1430
  visible=True
1431
  )
1432
 
 
1454
  - **Match the Column**: Assesses relationships and connections
1455
  - **Short Response**: Evaluates understanding and explanation
1456
  - **Essay Questions**: Measures critical thinking and synthesis
1457
+ - **Bloom's Mix**: Use for comprehensive assessment across cognitive levels
1458
  - Review generated questions before final use
1459
+
1460
+ ### 📧 Custom App Development
1461
+ **Need a customized assessment tool?**
1462
+ Contact developer **Najaf Ali Sharqi** for:
1463
+ - Custom question banks
1464
+ - Institution-specific features
1465
+ - Advanced analytics
1466
+ - Integration with LMS platforms
1467
  """
1468
  )
1469
 
 
1506
  """
1507
  ---
1508
  <div class="footer">
1509
+ <strong>Test Generator Pro v2.5</strong><br>
1510
+ Comprehensive Assessment Tool with 5 Question Types & Bloom's Taxonomy Integration<br>
1511
  Aligned with Pakistani National Curriculum (2006)<br>
1512
  Developer: <strong>Najaf Ali Sharqi</strong><br>
1513
+ Based on Professional Item Writing Standards<br><br>
1514
+ 📧 For custom app development or support: Contact Najaf Ali Sharqi
1515
  </div>
1516
  """,
1517
  elem_classes="footer"
 
1532
  return gr.update(choices=chapters, value=None)
1533
  return gr.update(choices=[], value=None)
1534
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1535
  def update_question_type_info(q_type):
1536
  """Update question type description"""
1537
  if q_type in QUESTION_TYPES:
 
1545
  """
1546
  return ""
1547
 
1548
+ def toggle_bloom_sliders(use_mix):
1549
+ """Show/hide Bloom's taxonomy sliders"""
1550
+ return gr.update(visible=use_mix), gr.update(visible=not use_mix)
1551
+
1552
+ def calculate_bloom_total(r, u, ap, an, e, c):
1553
+ """Calculate total percentage"""
1554
+ total = r + u + ap + an + e + c
1555
+ color = "green" if total == 100 else "red"
1556
+ return f'<span style="color:{color}; font-weight:bold;">{total}%</span>'
1557
+
1558
  # Connect event handlers
1559
  grade_dropdown.change(
1560
  update_subjects,
 
1574
  outputs=[chapter_dropdown]
1575
  )
1576
 
 
 
 
 
 
 
1577
  question_type.change(
1578
  update_question_type_info,
1579
  inputs=[question_type],
1580
  outputs=[question_type_info]
1581
  )
1582
 
1583
+ use_bloom_mix.change(
1584
+ toggle_bloom_sliders,
1585
+ inputs=[use_bloom_mix],
1586
+ outputs=[bloom_percentages, difficulty_dropdown]
1587
+ )
1588
+
1589
+ # Update total when sliders change
1590
+ for slider in [bloom_remember, bloom_understand, bloom_apply, bloom_analyze, bloom_evaluate, bloom_create]:
1591
+ slider.change(
1592
+ calculate_bloom_total,
1593
+ inputs=[bloom_remember, bloom_understand, bloom_apply, bloom_analyze, bloom_evaluate, bloom_create],
1594
+ outputs=[bloom_total]
1595
+ )
1596
+
1597
  generate_btn.click(
1598
  on_generate,
1599
  inputs=[
1600
  grade_dropdown,
1601
  subject_dropdown,
1602
  chapter_dropdown,
 
 
1603
  test_type,
1604
  school_name,
1605
+ question_type,
1606
+ use_bloom_mix,
1607
+ bloom_remember,
1608
+ bloom_understand,
1609
+ bloom_apply,
1610
+ bloom_analyze,
1611
+ bloom_evaluate,
1612
+ bloom_create,
1613
+ num_questions
1614
  ],
1615
  outputs=[output_text, output_file, file_status]
1616
  )