Turbiling commited on
Commit
b20e8a2
·
verified ·
1 Parent(s): b1825bd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -527
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py - Enhanced Test Generator for Hugging Face
2
  # Aligned with Pakistani National Curriculum (2006)
3
  # Developer: Najaf Ali Sharqi
4
 
@@ -9,8 +9,6 @@ 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
- from docx.oxml.ns import qn
13
- from docx.oxml import OxmlElement
14
  import re
15
  import json
16
 
@@ -25,7 +23,8 @@ client = Groq(api_key=GROQ_API_KEY)
25
  # ---------------------------
26
  # Configuration Constants
27
  # ---------------------------
28
- APP_VERSION = "2.5"
 
29
  MODEL_NAME = "llama-3.3-70b-versatile"
30
 
31
  # ---------------------------
@@ -116,257 +115,6 @@ chapters_by_subject_and_grade = {
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": [
279
- "Counting & Numbers",
280
- "Basic Addition",
281
- "Basic Subtraction",
282
- "Shapes",
283
- "Measurements"
284
- ],
285
- "English": [
286
- "Alphabet & Sounds",
287
- "Basic Words",
288
- "Simple Sentences",
289
- "Listening & Speaking",
290
- "Reading Short Texts"
291
- ],
292
- "Urdu": [
293
- "حروف",
294
- "الفاظ",
295
- "سادہ جملے",
296
- "پڑھنا",
297
- "لکھنا"
298
- ],
299
- "Islamiyat": [
300
- "Basic Beliefs",
301
- "Prophets Stories",
302
- "Good Manners",
303
- "Prayers & Worship"
304
- ],
305
- "General Knowledge": [
306
- "My Body",
307
- "My Home",
308
- "My School",
309
- "Seasons"
310
- ]
311
- },
312
- },
313
- "Grade 2": {
314
- "Mathematics": ["Place Value", "Addition & Subtraction", "Money", "Time", "Shapes"],
315
- "English": ["Parts of Speech Basics", "Simple Grammar", "Short Comprehension", "Vocabulary Building"],
316
- "Urdu": ["الفاظ و جملے", "مختصر کہانیاں", "حروفِ صحیح"],
317
- "Islamiyat": ["Prophets", "Good Deeds", "Mosque Etiquette"],
318
- "General Knowledge": ["Plants & Animals", "Local Community", "Transport"]
319
- },
320
- "Grade 3": {
321
- "Mathematics": ["Multiplication", "Division", "Fractions", "Geometry Basics", "Measurement"],
322
- "English": ["Tenses (simple)", "Comprehension Passages", "Vocabulary", "Sentence Formation"],
323
- "Urdu": ["کالم و مضامین", "قواعدِ اردو", "کہانیاں"],
324
- "Science": ["Plants", "Animals", "Human Body", "Materials"],
325
- "Islamiyat": ["Basics of Iman", "Seerat", "Manners"],
326
- "General Knowledge": ["Environment", "Community Helpers", "Safety"]
327
- },
328
- "Grade 4": {
329
- "Mathematics": ["Fractions & Decimals", "Geometry", "Data Handling", "Word Problems"],
330
- "English": ["Grammar (intermediate)", "Comprehension", "Writing Short Paragraphs"],
331
- "Urdu": ["نظم و نثر", "قواعد", "مفردات"],
332
- "Science": ["Ecosystems", "Forces", "Heat & Energy"],
333
- "Islamiyat": ["Pillars of Islam", "Seerah Stories"],
334
- "General Knowledge": ["Maps & Directions", "Cultural Heritage", "Technology"]
335
- },
336
- "Grade 5": {
337
- "Mathematics": ["Numbers & Operations", "Geometry", "Statistics", "Ratio & Proportion"],
338
- "English": ["Advanced Grammar Basics", "Paragraph Writing", "Comprehension"],
339
- "Urdu": ["ادبی مطالعہ", "تعبیر و تشریح"],
340
- "Science": ["Cells & Life", "Matter", "Energy"],
341
- "Islamiyat": ["Quranic Stories", "Akhlaq"],
342
- "Social Studies": ["Pakistan Geography", "History Basics", "Civics Introduction"]
343
- },
344
- "Grade 6": {
345
- "Mathematics": ["Number System", "Algebra Introduction", "Geometry", "Data Handling"],
346
- "English": ["Grammar (complex)", "Essay Writing", "Comprehension Skills"],
347
- "Urdu": ["ادب و نحو", "تحریر"],
348
- "Science": ["Atoms & Molecules", "Human Body", "Plants"],
349
- "Islamiyat": ["Seerah & Ahkam"],
350
- "Social Studies": ["World Geography", "Historical Events", "Government"]
351
- },
352
- "Grade 7": {
353
- "Mathematics": ["Algebra", "Geometry", "Mensuration", "Statistics"],
354
- "English": ["Poetry & Prose", "Grammar", "Comprehension"],
355
- "Urdu": ["نثر و شاعری", "قواعد"],
356
- "Science": ["Cell Biology", "Human Systems", "Electricity Basics"],
357
- "Islamiyat": ["Islamic History", "Moral Teachings"],
358
- "Social Studies": ["Geography Basics", "History", "Civics"],
359
- "Computer": ["Basic ICT", "Computer Hardware", "Introduction to Coding"]
360
- },
361
- "Grade 8": {
362
- "Mathematics": ["Linear Equations", "Geometry", "Pythagoras", "Graphs"],
363
- "English": ["Advanced Comprehension", "Composition", "Grammar"],
364
- "Urdu": ["تجزیہ ادب", "تحقیقِ مختصر"],
365
- "Science": ["Forces & Motion", "Heat", "Waves Basics"],
366
- "Islamiyat": ["Islamic Law Basics", "Seerah"],
367
- "Social Studies": ["Regional Geography", "Historical Events"],
368
- "Computer": ["Algorithms", "Basic Programming"]
369
- },
370
  "Grade 9": {
371
  "Mathematics": ["Number Systems & Algebra", "Coordinate Geometry", "Trigonometry", "Graphs"],
372
  "English": ["Advanced Grammar", "Comprehension", "Writing Skills"],
@@ -571,51 +319,61 @@ DIFFICULTY_LEVELS = {
571
  }
572
 
573
  # ---------------------------
574
- # Enhanced question generation with Bloom's Taxonomy distribution
575
  # ---------------------------
576
- def generate_questions_multi_level(grade, subject, chapter, test_type, school_name, question_type,
577
- bloom_distribution, total_questions):
578
- """Generate questions with mixed cognitive levels based on user distribution"""
579
-
580
- all_questions = []
581
- all_answers = []
582
-
583
- try:
584
- # Calculate number of questions per level
585
- for level, percentage in bloom_distribution.items():
586
- if percentage > 0:
587
- num_q = int((percentage / 100) * total_questions)
588
- if num_q > 0:
589
- questions, answers, error, q_type_code = generate_questions(
590
- grade, subject, chapter, level,
591
- num_q, test_type, school_name, question_type
592
- )
593
-
594
- if error:
595
- return [], [], error, "mcq"
596
-
597
- all_questions.extend(questions)
598
- all_answers.extend(answers)
599
-
600
- # Ensure we have the right number of questions
601
- if len(all_questions) < total_questions:
602
- # Generate additional questions at first non-zero level
603
- shortage = total_questions - len(all_questions)
604
- first_level = next((k for k, v in bloom_distribution.items() if v > 0), "Understanding")
605
-
606
- extra_q, extra_a, error, q_type_code = generate_questions(
607
- grade, subject, chapter, first_level,
608
- shortage, test_type, school_name, question_type
609
- )
610
-
611
- if not error:
612
- all_questions.extend(extra_q)
613
- all_answers.extend(extra_a)
614
-
615
- return all_questions[:total_questions], all_answers[:total_questions], None, q_type_code
616
-
617
- except Exception as e:
618
- return [], [], f"Error in multi-level generation: {str(e)}", "mcq"
 
 
 
 
 
 
 
 
 
 
619
 
620
  # ---------------------------
621
  # Enhanced question generation with proper item writing principles
@@ -884,9 +642,8 @@ def parse_match_column(text):
884
  return questions, answers
885
 
886
  def parse_short_response(text, expected_count):
887
- """Parse Short Response questions - separating questions from expected answers"""
888
- # Split by expected answers section
889
- parts = re.split(r'EXPECTED\s+ANSWERS?:?|MARKING\s+SCHEME:?', text, flags=re.IGNORECASE)
890
 
891
  questions = []
892
  answers = []
@@ -899,19 +656,18 @@ def parse_short_response(text, expected_count):
899
 
900
  if len(parts) >= 2:
901
  a_text = parts[1]
902
- # Extract expected answers/key points
903
  schemes = re.findall(r'\d+[\.\)]\s*(.+?)(?=\d+[\.\)]|$)', a_text, re.DOTALL)
904
  answers = [s.strip() for s in schemes[:expected_count]]
905
 
906
  if len(answers) < len(questions):
907
- answers.extend(['Key points: Provide comprehensive explanation with examples'] * (len(questions) - len(answers)))
908
 
909
  return questions, answers
910
 
911
  def parse_essay(text, expected_count):
912
- """Parse Essay questions - separating questions from expected answers"""
913
- # Split by expected answers section
914
- parts = re.split(r'EXPECTED\s+ANSWERS?:?|MARKING\s+CRITERIA:?', text, flags=re.IGNORECASE)
915
 
916
  questions = []
917
  answers = []
@@ -924,31 +680,15 @@ def parse_essay(text, expected_count):
924
 
925
  if len(parts) >= 2:
926
  a_text = parts[1]
927
- # Extract criteria/expected coverage
928
  criteria = re.findall(r'\d+[\.\)]\s*(.+?)(?=\d+[\.\)]|$)', a_text, re.DOTALL)
929
  answers = [c.strip() for c in criteria[:expected_count]]
930
 
931
  if len(answers) < len(questions):
932
- answers.extend(['Main points: Detailed analysis with evidence, examples, and logical argumentation'] * (len(questions) - len(answers)))
933
 
934
  return questions, answers
935
 
936
- def create_answer_table(doc, answers, num_cols=5):
937
- """Helper function to create formatted answer table"""
938
- num_rows = len(answers) + 1
939
- ans_table = doc.add_table(rows=num_rows, cols=num_cols)
940
- ans_table.style = 'Medium Grid 1 Accent 1'
941
-
942
- # Set column widths
943
- for row in ans_table.rows:
944
- for idx, cell in enumerate(row.cells):
945
- if idx == 0:
946
- cell.width = Inches(0.6)
947
- else:
948
- cell.width = Inches(1.2)
949
-
950
- return ans_table
951
-
952
  # ---------------------------
953
  # Enhanced DOCX export supporting all question types
954
  # ---------------------------
@@ -1045,9 +785,9 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
1045
  if question_type_code == "mcq":
1046
  for i, q in enumerate(questions, start=1):
1047
  q_para = doc.add_paragraph()
1048
- q_para.add_run(f"{i}. ").bold = True
1049
  q_para.add_run(q)
1050
- q_para.space_after = Pt(8)
1051
  doc.add_paragraph()
1052
 
1053
  elif question_type_code == "fill_blank":
@@ -1056,7 +796,6 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
1056
  q_para.add_run(f"{i}. ").bold = True
1057
  q_para.add_run(q)
1058
  q_para.space_after = Pt(8)
1059
- doc.add_paragraph()
1060
 
1061
  elif question_type_code == "match_column":
1062
  for q in questions:
@@ -1072,13 +811,13 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
1072
  doc.add_paragraph()
1073
  # Add space for answer
1074
  for _ in range(3 if question_type_code == "short_response" else 8):
1075
- doc.add_paragraph("_" * 85)
1076
  doc.add_paragraph()
1077
 
1078
  # Answer key (on separate page)
1079
  doc.add_page_break()
1080
 
1081
- ans_heading = doc.add_heading("ANSWER KEY", level=2)
1082
  ans_heading.alignment = WD_ALIGN_PARAGRAPH.CENTER
1083
  for run in ans_heading.runs:
1084
  run.font.color.rgb = RGBColor(153, 0, 0)
@@ -1089,7 +828,9 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
1089
  # Add answers based on type
1090
  if question_type_code == "mcq":
1091
  # Answer table for MCQs
1092
- ans_table = create_answer_table(doc, answers, 5)
 
 
1093
 
1094
  headers = ["Q#", "A", "B", "C", "D"]
1095
  for idx, header in enumerate(headers):
@@ -1112,33 +853,7 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
1112
  else:
1113
  cell.text = ""
1114
  cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
1115
-
1116
- elif question_type_code == "fill_blank":
1117
- # Tabular answer key for Fill in the Blanks
1118
- ans_table = create_answer_table(doc, answers, 2)
1119
-
1120
- # Headers
1121
- headers = ["Q#", "Correct Answer"]
1122
- for idx, header in enumerate(headers):
1123
- cell = ans_table.cell(0, idx)
1124
- cell.text = header
1125
- cell.paragraphs[0].runs[0].bold = True
1126
- cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
1127
-
1128
- # Fill answers
1129
- for r, ans in enumerate(answers, start=1):
1130
- ans_table.cell(r, 0).text = str(r)
1131
- ans_table.cell(r, 0).paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
1132
- ans_table.cell(r, 1).text = str(ans)
1133
-
1134
- elif question_type_code in ["short_response", "essay"]:
1135
- # Expected answers for subjective questions
1136
- for i, ans in enumerate(answers, start=1):
1137
- ans_para = doc.add_paragraph()
1138
- ans_para.add_run(f"Q{i}. Expected Answer:").bold = True
1139
- doc.add_paragraph(str(ans))
1140
- doc.add_paragraph()
1141
-
1142
  else:
1143
  # Text-based answers for other types
1144
  for i, ans in enumerate(answers, start=1):
@@ -1150,7 +865,7 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
1150
  # Footer
1151
  doc.add_paragraph()
1152
  footer = doc.add_paragraph()
1153
- 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
1154
  footer.runs[0].font.size = Pt(8)
1155
  footer.runs[0].font.color.rgb = RGBColor(128, 128, 128)
1156
  footer.alignment = WD_ALIGN_PARAGRAPH.CENTER
@@ -1168,61 +883,31 @@ def export_to_word(questions, answers, grade, subject, chapter, difficulty, test
1168
  return None, f"Error creating document: {str(e)}"
1169
 
1170
  # ---------------------------
1171
- # Main generation handler with Bloom's Taxonomy distribution
1172
  # ---------------------------
1173
- def on_generate(grade, subject, chapter, test_type, school_name, question_type,
1174
- use_bloom_mix, bloom_remember, bloom_understand, bloom_apply,
1175
- bloom_analyze, bloom_evaluate, bloom_create, num_questions):
1176
- """Handle question generation request with optional Bloom's distribution"""
1177
 
1178
  # Validation
1179
- if not all([grade, subject, chapter, question_type]):
1180
  return "⚠️ Please fill all required fields", None, None
1181
 
1182
  if not school_name or not school_name.strip():
1183
  school_name = "Educational Institution"
1184
 
1185
  try:
1186
- # Check if using Bloom's mix
1187
- if use_bloom_mix:
1188
- # Validate percentages
1189
- total_percent = bloom_remember + bloom_understand + bloom_apply + bloom_analyze + bloom_evaluate + bloom_create
1190
- if total_percent != 100:
1191
- return f"❌ Bloom's Taxonomy percentages must total 100% (currently {total_percent}%)", None, None
1192
-
1193
- bloom_distribution = {
1194
- "Remembering": bloom_remember,
1195
- "Understanding": bloom_understand,
1196
- "Applying": bloom_apply,
1197
- "Analyzing": bloom_analyze,
1198
- "Evaluating": bloom_evaluate,
1199
- "Creating": bloom_create
1200
- }
1201
-
1202
- # Show progress
1203
- status_msg = f"🔄 Generating {num_questions} {question_type} with mixed cognitive levels...\n"
1204
- status_msg += f"📊 Bloom's Distribution:\n"
1205
- for level, pct in bloom_distribution.items():
1206
- if pct > 0:
1207
- status_msg += f" • {level}: {pct}% ({int(pct * num_questions / 100)} questions)\n"
1208
-
1209
- # Generate with mixed levels
1210
- questions, answers, error, q_type_code = generate_questions_multi_level(
1211
- grade, subject, chapter, test_type, school_name, question_type,
1212
- bloom_distribution, num_questions
1213
- )
1214
- else:
1215
- # Single level generation (default to Understanding)
1216
- status_msg = f"🔄 Generating {num_questions} {question_type}...\n"
1217
- status_msg += f"📖 Grade: {grade} | Subject: {subject}\n"
1218
- status_msg += f"📚 Chapter: {chapter}\n"
1219
- status_msg += f"🎯 Cognitive Level: Understanding\n"
1220
- status_msg += "⏳ Please wait..."
1221
-
1222
- questions, answers, error, q_type_code = generate_questions(
1223
- grade, subject, chapter, "Understanding",
1224
- num_questions, test_type, school_name, question_type
1225
- )
1226
 
1227
  if error:
1228
  return f"❌ Error: {error}", None, None
@@ -1249,8 +934,7 @@ def on_generate(grade, subject, chapter, test_type, school_name, question_type,
1249
  # Export to Word
1250
  file_path, doc_error = export_to_word(
1251
  questions, answers, grade, subject, chapter,
1252
- "Mixed Cognitive Levels" if use_bloom_mix else "Understanding",
1253
- test_type, school_name, total_marks, q_type_code
1254
  )
1255
 
1256
  if doc_error:
@@ -1258,20 +942,15 @@ def on_generate(grade, subject, chapter, test_type, school_name, question_type,
1258
 
1259
  # Success message
1260
  success_msg = f"✅ Test generated successfully!\n\n"
1261
- success_msg += f"📊 Test Statistics:\n"
1262
  success_msg += f"• Question Type: {question_type}\n"
1263
  success_msg += f"• Total Questions: {len(questions)}\n"
1264
  success_msg += f"• Total Marks: {total_marks}\n"
1265
- success_msg += f"• Grade: {grade} | Subject: {subject}\n"
 
1266
  success_msg += f"• Chapter: {chapter}\n"
1267
-
1268
- if use_bloom_mix:
1269
- success_msg += f"\n🎯 Bloom's Taxonomy Distribution:\n"
1270
- for level, pct in bloom_distribution.items():
1271
- if pct > 0:
1272
- success_msg += f" • {level}: {pct}%\n"
1273
-
1274
- success_msg += f"\n📥 Download your test document below"
1275
 
1276
  # Preview
1277
  preview_count = min(3, len(questions))
@@ -1279,7 +958,7 @@ def on_generate(grade, subject, chapter, test_type, school_name, question_type,
1279
 
1280
  for i, q in enumerate(questions[:preview_count], 1):
1281
  if q_type_code == "mcq":
1282
- preview += f"{i}. {q[:200]}...\n\n" if len(q) > 200 else f"{i}. {q}\n\n"
1283
  else:
1284
  preview += f"{i}. {q[:200]}...\n\n" if len(q) > 200 else f"{i}. {q}\n\n"
1285
 
@@ -1310,18 +989,16 @@ def create_ui():
1310
  # Header
1311
  gr.Markdown(
1312
  """
1313
- # 📚 Test Generator
1314
- ### **Developer: Najaf Ali Sharqi**
1315
-
1316
- Professional Assessment Tool Aligned with Pakistani National Curriculum (2006)
1317
  """,
1318
  elem_classes="header"
1319
  )
1320
 
1321
  gr.Markdown(
1322
  """
1323
- Generate high-quality assessment questions with multiple formats and Bloom's Taxonomy integration.
1324
- Perfect for educators creating comprehensive tests for Grades 1-12.
1325
  """,
1326
  elem_classes="description"
1327
  )
@@ -1396,66 +1073,20 @@ def create_ui():
1396
  info="Select specific chapter or unit"
1397
  )
1398
 
1399
- # Bloom's Taxonomy Distribution Section
1400
- use_bloom_mix = gr.Checkbox(
1401
- label="📊 Use Mixed Bloom's Taxonomy Levels",
1402
- value=False,
1403
- info="Create tests with questions from multiple cognitive levels"
1404
  )
1405
 
1406
- bloom_percentages = gr.Column(visible=False)
1407
-
1408
- with bloom_percentages:
1409
- gr.Markdown("### Set Percentage for Each Cognitive Level")
1410
- gr.Markdown("*(Total must equal 100%)*")
1411
-
1412
- with gr.Row():
1413
- bloom_remember = gr.Slider(
1414
- minimum=0, maximum=100, value=30, step=5,
1415
- label="Remembering %",
1416
- info="Recall facts and basic concepts"
1417
- )
1418
- bloom_understand = gr.Slider(
1419
- minimum=0, maximum=100, value=30, step=5,
1420
- label="Understanding %",
1421
- info="Explain ideas and concepts"
1422
- )
1423
-
1424
- with gr.Row():
1425
- bloom_apply = gr.Slider(
1426
- minimum=0, maximum=100, value=20, step=5,
1427
- label="Applying %",
1428
- info="Use information in new situations"
1429
- )
1430
- bloom_analyze = gr.Slider(
1431
- minimum=0, maximum=100, value=10, step=5,
1432
- label="Analyzing %",
1433
- info="Draw connections and relationships"
1434
- )
1435
-
1436
- with gr.Row():
1437
- bloom_evaluate = gr.Slider(
1438
- minimum=0, maximum=100, value=10, step=5,
1439
- label="Evaluating %",
1440
- info="Justify decisions and make judgments"
1441
- )
1442
- bloom_create = gr.Slider(
1443
- minimum=0, maximum=100, value=0, step=5,
1444
- label="Creating %",
1445
- info="Produce new or original work"
1446
- )
1447
 
1448
- bloom_total = gr.Textbox(
1449
- label="Total Percentage",
1450
- value="100%",
1451
- interactive=False
1452
- )
1453
-
1454
- difficulty_dropdown = gr.Dropdown(
1455
- choices=list(DIFFICULTY_LEVELS.keys()),
1456
- value="Understanding",
1457
- label="Single Cognitive Level (if not using mix)",
1458
- info="Select one level for entire test",
1459
  visible=True
1460
  )
1461
 
@@ -1483,16 +1114,8 @@ def create_ui():
1483
  - **Match the Column**: Assesses relationships and connections
1484
  - **Short Response**: Evaluates understanding and explanation
1485
  - **Essay Questions**: Measures critical thinking and synthesis
1486
- - **Bloom's Mix**: Use for comprehensive assessment across cognitive levels
1487
  - Review generated questions before final use
1488
-
1489
- ### 📧 Custom App Development
1490
- **Need a customized assessment tool?**
1491
- Contact developer **Najaf Ali Sharqi** for:
1492
- - Custom question banks
1493
- - Institution-specific features
1494
- - Advanced analytics
1495
- - Integration with LMS platforms
1496
  """
1497
  )
1498
 
@@ -1535,12 +1158,12 @@ def create_ui():
1535
  """
1536
  ---
1537
  <div class="footer">
1538
- <strong>Test Generator Pro v2.5</strong><br>
1539
- Comprehensive Assessment Tool with 5 Question Types & Bloom's Taxonomy Integration<br>
1540
  Aligned with Pakistani National Curriculum (2006)<br>
1541
  Developer: <strong>Najaf Ali Sharqi</strong><br>
1542
- Based on Professional Item Writing Standards<br><br>
1543
- 📧 For custom app development or support: Contact Najaf Ali Sharqi
1544
  </div>
1545
  """,
1546
  elem_classes="footer"
@@ -1561,6 +1184,19 @@ def create_ui():
1561
  return gr.update(choices=chapters, value=None)
1562
  return gr.update(choices=[], value=None)
1563
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1564
  def update_question_type_info(q_type):
1565
  """Update question type description"""
1566
  if q_type in QUESTION_TYPES:
@@ -1574,16 +1210,6 @@ def create_ui():
1574
  """
1575
  return ""
1576
 
1577
- def toggle_bloom_sliders(use_mix):
1578
- """Show/hide Bloom's taxonomy sliders"""
1579
- return gr.update(visible=use_mix), gr.update(visible=not use_mix)
1580
-
1581
- def calculate_bloom_total(r, u, ap, an, e, c):
1582
- """Calculate total percentage"""
1583
- total = r + u + ap + an + e + c
1584
- color = "green" if total == 100 else "red"
1585
- return f'<span style="color:{color}; font-weight:bold;">{total}%</span>'
1586
-
1587
  # Connect event handlers
1588
  grade_dropdown.change(
1589
  update_subjects,
@@ -1603,43 +1229,29 @@ def create_ui():
1603
  outputs=[chapter_dropdown]
1604
  )
1605
 
 
 
 
 
 
 
1606
  question_type.change(
1607
  update_question_type_info,
1608
  inputs=[question_type],
1609
  outputs=[question_type_info]
1610
  )
1611
 
1612
- use_bloom_mix.change(
1613
- toggle_bloom_sliders,
1614
- inputs=[use_bloom_mix],
1615
- outputs=[bloom_percentages, difficulty_dropdown]
1616
- )
1617
-
1618
- # Update total when sliders change
1619
- for slider in [bloom_remember, bloom_understand, bloom_apply, bloom_analyze, bloom_evaluate, bloom_create]:
1620
- slider.change(
1621
- calculate_bloom_total,
1622
- inputs=[bloom_remember, bloom_understand, bloom_apply, bloom_analyze, bloom_evaluate, bloom_create],
1623
- outputs=[bloom_total]
1624
- )
1625
-
1626
  generate_btn.click(
1627
  on_generate,
1628
  inputs=[
1629
  grade_dropdown,
1630
  subject_dropdown,
1631
  chapter_dropdown,
 
 
1632
  test_type,
1633
  school_name,
1634
- question_type,
1635
- use_bloom_mix,
1636
- bloom_remember,
1637
- bloom_understand,
1638
- bloom_apply,
1639
- bloom_analyze,
1640
- bloom_evaluate,
1641
- bloom_create,
1642
- num_questions
1643
  ],
1644
  outputs=[output_text, output_file, file_status]
1645
  )
 
1
+ # app.py - Enhanced MCQ 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
  import re
13
  import json
14
 
 
23
  # ---------------------------
24
  # Configuration Constants
25
  # ---------------------------
26
+ APP_VERSION = "2.0"
27
+ MAX_MCQS = 20
28
  MODEL_NAME = "llama-3.3-70b-versatile"
29
 
30
  # ---------------------------
 
115
  "Social Studies": ["Regional Geography", "Historical Events"],
116
  "Computer": ["Algorithms", "Basic Programming"]
117
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  "Grade 9": {
119
  "Mathematics": ["Number Systems & Algebra", "Coordinate Geometry", "Trigonometry", "Graphs"],
120
  "English": ["Advanced Grammar", "Comprehension", "Writing Skills"],
 
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
  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
 
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
 
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
  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
  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
  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
  # 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
  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
  # 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
  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
  # 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
 
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
 
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
  # 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
  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
  - **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
  """
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
  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
  """
1211
  return ""
1212
 
 
 
 
 
 
 
 
 
 
 
1213
  # Connect event handlers
1214
  grade_dropdown.change(
1215
  update_subjects,
 
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
  )