codeboosterstech commited on
Commit
cf60b98
Β·
verified Β·
1 Parent(s): 7cab185

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +377 -45
app.py CHANGED
@@ -95,22 +95,55 @@ def extract_units(syllabus_text, unit_range):
95
  def apply_MAANGO_BIG15_framework(base_prompt):
96
  maango_block = """
97
  === MAANGO BIG15 ADVANCED QUESTION ENGINE FRAMEWORK ===
 
98
  You MUST follow ALL 15 pillars while generating the question paper:
 
99
  1. M β€” Multi-Cognitive Bloom Alignment
100
- 2. A β€” Applyβ€”Analyze Weightage Boost
 
 
 
 
 
101
  3. A β€” Adaptive Difficulty Index
 
 
102
  4. N β€” Non-Repetitive Deep Coverage
 
 
103
  5. G β€” Granular Unit Balancing
 
 
104
  6. O β€” Outcome Mapping Discipline
 
 
105
  7. B β€” BIG15 Industry Integration
 
 
106
  8. I β€” Industry Application Layer
 
 
107
  9. G β€” GATE Layer Injection
 
 
108
  10. 1 β€” First-Half / Second-Half Coverage Integrity
 
 
109
  11. 5 β€” Five-Unit Symmetry
 
 
110
  12. S β€” Structured Output Discipline
 
 
111
  13. E β€” Exam-Mode Smart Switching
 
 
112
  14. T β€” Technical Depth Enforcement
 
 
113
  15. H β€” Holistic Coherence
 
 
114
  === END OF MAANGO BIG15 FRAMEWORK ===
115
  """
116
  return maango_block + "\n\n" + base_prompt
@@ -120,52 +153,263 @@ def build_question_prompt(subject, syllabus, numA, numB, numC, exam_mode):
120
  You are an exam generator for {exam_mode} mode. Output ONLY VALID JSON.
121
 
122
  STRICT JSON SCHEMA:
 
123
  {{
124
- "metadata": {{"subject": "{subject}", "date": "{datetime.now().strftime('%Y-%m-%d')}"}},
125
- "partA": [{{"question_text": "string", "marks": 2, "unit": 1, "bloom_level": "Remember", "company_tag": "Generic"}}],
126
- "partB": [{{"either": {{"question_text": "string", "marks": 10, "unit": 1, "bloom_level": "Analyze", "company_tag": "TCS"}}, "or": {{"question_text": "string", "marks": 10, "unit": 1, "bloom_level": "Analyze", "company_tag": "TCS"}}}}],
127
- "partC": [{{"either": {{"question_text": "string", "marks": 15, "unit": 1, "bloom_level": "Create", "company_tag": "Infosys"}}, "or": {{"question_text": "string", "marks": 15, "unit": 1, "bloom_level": "Create", "company_tag": "Infosys"}}}}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  }}
129
 
130
- Generate EXACTLY {numA} questions in partA, {numB} pairs in partB, {numC} pairs in partC.
131
- Syllabus: {syllabus}
 
 
 
 
 
 
 
 
 
132
  Return ONLY pure JSON. No commentary.
133
  """
134
  return apply_MAANGO_BIG15_framework(base_prompt)
135
 
136
- def build_answer_prompt(questions_json):
137
- return f"""
138
- Generate answers in VALID JSON format for these questions:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  {{
141
- "partA": [{{"question_text": "string", "answer": "detailed answer", "marks": 2}}],
142
- "partB": [{{"question_text": "string", "answer": "model answer", "marks": 10}}],
143
- "partC": [{{"question_text": "string", "answer": "comprehensive answer", "marks": 15}}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  }}
145
 
146
- Questions: {json.dumps(questions_json)}
147
- Return ONLY pure JSON.
 
 
 
 
 
 
148
  """
 
149
 
150
  def create_question_paper(code, name, partA, partB, partC, output_path):
151
  doc = Document()
152
  doc.add_heading("SNS College of Technology", level=1)
153
  doc.add_paragraph(f"Subject Code: {code} Subject: {name}")
154
- doc.add_paragraph(f"Date: {datetime.now().strftime('%Y-%m-%d')}\n")
 
155
 
156
  doc.add_heading("Part A (Short Answer)", level=2)
157
  for idx, q in enumerate(partA, 1):
158
- doc.add_paragraph(f"{idx}. {q.get('question_text','')} (Marks: {q.get('marks',2)})")
 
159
 
160
  doc.add_heading("Part B (Either/Or Questions)", level=2)
161
- for idx, pair in enumerate(partB, len(partA)+1):
162
- doc.add_paragraph(f"{idx}. Either: {pair['either']['question_text']} (10 marks)")
163
- doc.add_paragraph(f" Or: {pair['or']['question_text']} (10 marks)")
 
 
 
164
 
165
  doc.add_heading("Part C (Case/Design Questions)", level=2)
166
- for idx, pair in enumerate(partC, len(partA)+len(partB)+1):
167
- doc.add_paragraph(f"{idx}. Either: {pair['either']['question_text']} (15 marks)")
168
- doc.add_paragraph(f" Or: {pair['or']['question_text']} (15 marks)")
 
 
 
169
 
170
  doc.save(output_path)
171
 
@@ -176,16 +420,73 @@ def create_answer_key(code, name, answers, output_path):
176
 
177
  doc.add_heading("Part A Answers", level=2)
178
  for idx, a in enumerate(answers.get("partA", []), 1):
179
- doc.add_paragraph(f"{idx}. {a.get('answer','N/A')}")
180
 
181
- doc.add_heading("Part B Answers", level=2)
182
- for idx, a in enumerate(answers.get("partB", []), len(answers.get("partA",[]))+1):
183
- doc.add_paragraph(f"{idx}. {a.get('answer','N/A')}")
 
184
 
185
- doc.add_heading("Part C Answers", level=2)
186
- start = len(answers.get("partA",[]))+len(answers.get("partB",[]))+1
187
- for idx, a in enumerate(answers.get("partC", []), start):
188
- doc.add_paragraph(f"{idx}. {a.get('answer','N/A')}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
  doc.save(output_path)
191
 
@@ -198,26 +499,53 @@ def generate_exam(exam_mode, subject, code, units, numA, numB, numC, syllabus_fi
198
  syllabus_text = extract_text(syllabus_file.name)
199
  selected_syllabus = extract_units(syllabus_text, units)
200
 
 
 
 
 
201
  q_prompt = build_question_prompt(subject, selected_syllabus, numA, numB, numC, exam_mode)
202
  q_raw = model_q.invoke([HumanMessage(content=q_prompt)]).content
203
  q_json = sanitize_json(q_raw)
204
 
205
- a_prompt = build_answer_prompt(q_json)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  a_raw = model_a.invoke([HumanMessage(content=a_prompt)]).content
207
  a_json = sanitize_json(a_raw)
208
 
 
209
  qp_file = f"{code}_QuestionPaper.docx"
210
  ak_file = f"{code}_AnswerKey.docx"
 
211
 
212
- create_question_paper(code, subject, q_json["partA"], q_json["partB"], q_json["partC"], qp_file)
213
  create_answer_key(code, subject, a_json, ak_file)
 
214
 
215
  zip_file = f"{code}_ExamPackage.zip"
216
  with zipfile.ZipFile(zip_file, 'w') as zipf:
217
  zipf.write(qp_file)
218
  zipf.write(ak_file)
 
219
 
220
- return zip_file, f"βœ… Successfully generated exam package for {subject}!"
221
 
222
  except Exception as e:
223
  return None, f"❌ Error: {str(e)}"
@@ -296,9 +624,9 @@ with gr.Blocks() as demo:
296
  }
297
  </style>
298
  <div class="header-gradient">
299
- <h1>SNS Tech - Q&A Agent x Codeboosters Tech</h1>
300
- <p><strong>AI-Powered Question Paper & Answer Key Generator</strong></p>
301
- <p>Powered by Advanced LLM Technology | Industry-Standard Framework | Developed by Codeboosters Tech Team</p>
302
  </div>
303
  """)
304
 
@@ -326,22 +654,25 @@ with gr.Blocks() as demo:
326
 
327
  gr.HTML("""
328
  <div class="feature-card">
329
- <h4>✨ Key Features</h4>
330
  <ul>
331
- <li>🎯 Bloom's Taxonomy Alignment</li>
332
  <li>🏒 Industry Tag Integration (TCS/Infosys/Wipro)</li>
333
- <li>πŸ“ˆ Balanced Unit Coverage</li>
334
- <li>πŸ” GATE-Style Question Design</li>
335
  <li>πŸ“ Automatic Answer Key Generation</li>
 
 
 
336
  </ul>
337
  </div>
338
  """)
339
 
340
- generate_btn = gr.Button("πŸš€ Generate Exam Package", variant="primary", size="lg")
341
 
342
  with gr.Row():
343
- output_file = gr.File(label="πŸ“¦ Download Package")
344
- status_msg = gr.Textbox(label="Status", lines=2)
345
 
346
  generate_btn.click(
347
  fn=generate_exam,
@@ -351,7 +682,8 @@ with gr.Blocks() as demo:
351
 
352
  gr.HTML("""
353
  <footer>
354
- <p>Developed with ❀️ by Veerakumar C B | © 2024</p>
 
355
  </footer>
356
  """)
357
 
 
95
  def apply_MAANGO_BIG15_framework(base_prompt):
96
  maango_block = """
97
  === MAANGO BIG15 ADVANCED QUESTION ENGINE FRAMEWORK ===
98
+
99
  You MUST follow ALL 15 pillars while generating the question paper:
100
+
101
  1. M β€” Multi-Cognitive Bloom Alignment
102
+ – Strict distribution of Remember/Understand/Apply/Analyze/Evaluate/Create.
103
+ – 40% minimum higher-order (Apply/Analyze/Evaluate/Create).
104
+
105
+ 2. A β€” Apply–Analyze Weightage Boost
106
+ – At least 2 questions in Part B and 1 in Part C MUST be scenario/analytical.
107
+
108
  3. A β€” Adaptive Difficulty Index
109
+ – Maintain difficulty index between 1.8 and 2.5 for every question.
110
+
111
  4. N β€” Non-Repetitive Deep Coverage
112
+ – No overlap in concepts, no repeated phrasing.
113
+
114
  5. G β€” Granular Unit Balancing
115
+ – Ensure questions cover all units proportionately.
116
+
117
  6. O β€” Outcome Mapping Discipline
118
+ – Every question must be CO-aligned using strong engineering verbs.
119
+
120
  7. B β€” BIG15 Industry Integration
121
+ – Each question must include TCS/Infosys/Wipro/Accenture/Generic relevance.
122
+
123
  8. I β€” Industry Application Layer
124
+ – At least 20% questions include real-world industry scenarios.
125
+
126
  9. G β€” GATE Layer Injection
127
+ – Higher-order questions must reflect GATE-style design/analysis depth.
128
+
129
  10. 1 β€” First-Half / Second-Half Coverage Integrity
130
+ – Early questions from Unit 1–2, later from Unit 3–5.
131
+
132
  11. 5 β€” Five-Unit Symmetry
133
+ – Maintain balance across all parts (A/B/C).
134
+
135
  12. S β€” Structured Output Discipline
136
+ – Follow exact JSON schema, no deviations.
137
+
138
  13. E β€” Exam-Mode Smart Switching
139
+ – Auto-adjust tone depending on CA / ESE / GATE mode.
140
+
141
  14. T β€” Technical Depth Enforcement
142
+ – Strong technical keywords, no vague verbs.
143
+
144
  15. H β€” Holistic Coherence
145
+ – Ensure clarity, correctness, industry relevance, and zero ambiguity.
146
+
147
  === END OF MAANGO BIG15 FRAMEWORK ===
148
  """
149
  return maango_block + "\n\n" + base_prompt
 
153
  You are an exam generator for {exam_mode} mode. Output ONLY VALID JSON.
154
 
155
  STRICT JSON SCHEMA:
156
+
157
  {{
158
+ "metadata": {{
159
+ "subject": "{subject}",
160
+ "date": "{datetime.now().strftime('%Y-%m-%d')}"
161
+ }},
162
+ "partA": [
163
+ {{
164
+ "question_text": "string",
165
+ "marks": 2 or 3,
166
+ "unit": "number",
167
+ "bloom_level": "Remember/Understand/Apply/Analyze/Evaluate/Create",
168
+ "company_tag": "TCS/Infosys/Wipro/Generic"
169
+ }}
170
+ ],
171
+ "partB": [
172
+ {{
173
+ "either": {{
174
+ "question_text": "string",
175
+ "marks": 10,
176
+ "unit": "number",
177
+ "bloom_level": "Analyze/Evaluate/Create",
178
+ "company_tag": "TCS/Infosys/Wipro/Generic"
179
+ }},
180
+ "or": {{
181
+ "question_text": "string",
182
+ "marks": 10,
183
+ "unit": "number",
184
+ "bloom_level": "Analyze/Evaluate/Create",
185
+ "company_tag": "TCS/Infosys/Wipro/Generic"
186
+ }}
187
+ }}
188
+ ],
189
+ "partC": [
190
+ {{
191
+ "either": {{
192
+ "question_text": "string",
193
+ "marks": 15,
194
+ "unit": "number",
195
+ "bloom_level": "Create/Evaluate",
196
+ "company_tag": "TCS/Infosys/Wipro/Generic"
197
+ }},
198
+ "or": {{
199
+ "question_text": "string",
200
+ "marks": 15,
201
+ "unit": "number",
202
+ "bloom_level": "Create/Evaluate",
203
+ "company_tag": "TCS/Infosys/Wipro/Generic"
204
+ }}
205
+ }}
206
+ ]
207
  }}
208
 
209
+ REQUIREMENTS:
210
+ - Generate EXACTLY {numA} questions in partA.
211
+ - Generate EXACTLY {numB} pairs in partB.
212
+ - Generate EXACTLY {numC} pairs in partC.
213
+ - All questions must map correctly to the syllabus.
214
+ - Maintain unit coverage balance.
215
+ - Use industry relevance when appropriate.
216
+
217
+ Syllabus:
218
+ {syllabus}
219
+
220
  Return ONLY pure JSON. No commentary.
221
  """
222
  return apply_MAANGO_BIG15_framework(base_prompt)
223
 
224
+ def apply_MAANGO_BIG15_answerkey(base_prompt):
225
+ maango_key_block = """
226
+ === MAANGO BIG15 ADVANCED ANSWER-KEY FRAMEWORK ===
227
+
228
+ All answers MUST follow the 15 MAANGO pillars. Specifically:
229
+
230
+ 1. Bloom Alignment
231
+ – Answer must match Bloom level of the original question.
232
+ – Higher-order – include reasoning, evaluation, derivation, design logic.
233
+
234
+ 2. Industry Integration
235
+ – Wherever possible, include short 1–2 line relevance to TCS/Infosys/Wipro/Accenture/Generic IT.
236
+
237
+ 3. Correctness & Precision
238
+ – No vague words. Use technical definitions only.
239
+
240
+ 4. Depth Control
241
+ – Part A: concise (3–6 lines)
242
+ – Part B: structured multi-step reasoning
243
+ – Part C: full analytical/creative design solution
244
+
245
+ 5. Non-Repetition
246
+ – Do not reuse the same explanation style across answers.
247
+
248
+ 6. Difficulty Index Match
249
+ – Keep answer complexity aligned with the question's difficulty.
250
+
251
+ 7. Structured JSON Schema Enforcement
252
+ – Must follow the answer-key schema EXACTLY.
253
+
254
+ 8. GATE Style Reinforcement
255
+ – For higher-order questions, include formulas, assumptions, models.
256
+
257
+ 9. Holistic Clarity
258
+ – Avoid ambiguities. Provide crisp, exam-ready answers.
259
+
260
+ === END OF MAANGO BIG15 ANSWER-KEY FRAMEWORK ===
261
+ """
262
+ return maango_key_block + "\n\n" + base_prompt
263
+
264
+ def build_answer_prompt(syllabus, questions_json):
265
+ base_prompt = f"""
266
+ You are an expert answer key generator.
267
+
268
+ Generate ANSWERS ONLY IN VALID JSON.
269
+
270
+ STRICT JSON FORMAT:
271
+
272
+ {{
273
+ "partA": [
274
+ {{
275
+ "question_text": "same as input",
276
+ "answer": "detailed but concise answer",
277
+ "marks": number
278
+ }}
279
+ ],
280
+ "partB": [
281
+ {{
282
+ "question_text": "either OR question merged or handled individually",
283
+ "answer": "model answer",
284
+ "marks": 10
285
+ }}
286
+ ],
287
+ "partC": [
288
+ {{
289
+ "question_text": "either OR question merged or handled individually",
290
+ "answer": "model answer",
291
+ "marks": 15
292
+ }}
293
+ ]
294
+ }}
295
+
296
+ INPUT QUESTIONS:
297
+ {json.dumps(questions_json, indent=2)}
298
+
299
+ RULES:
300
+ - DO NOT change question text.
301
+ - Provide complete, correct answers.
302
+ - Return ONLY CLEAN JSON.
303
+ """
304
+ return apply_MAANGO_BIG15_answerkey(base_prompt)
305
+
306
+ def apply_MAANGO_BIG15_trendanalysis(base_prompt):
307
+ maango_trend_block = """
308
+ === MAANGO BIG15 TREND ANALYSIS FRAMEWORK ===
309
+
310
+ All analysis MUST follow:
311
+
312
+ 1. Bloom Pattern Extraction
313
+ – Count and percentage across all levels.
314
+
315
+ 2. Difficulty Distribution Mapping
316
+ – Detect imbalance or deviations from DI = 1.8–2.5.
317
+
318
+ 3. Unit Coverage Analysis
319
+ – Identify over-covered / under-covered units.
320
+
321
+ 4. Industry Relevance Analysis
322
+ – Evaluate TCS/Infosys/Wipro/Generic tag distribution.
323
+
324
+ 5. Question-Type Distribution
325
+ – Short-answer vs descriptive vs design-oriented.
326
+
327
+ 6. MAANGO Compliance Scoring
328
+ – Compute 0–100% MAANGO BIG15 alignment score.
329
+
330
+ 7. Improvement Suggestions
331
+ – Provide actionable, unit-wise refinements.
332
+
333
+ 8. GATE/ESE Competency Mapping
334
+ – Rate analytical & application strength.
335
 
336
+ 9. Holistic Insights
337
+ – Detect patterns indicating strong or weak syllabus areas.
338
+
339
+ === END OF MAANGO BIG15 TREND ANALYSIS FRAMEWORK ===
340
+ """
341
+ return maango_trend_block + "\n\n" + base_prompt
342
+
343
+ def build_trend_prompt(subject, q_json):
344
+ base_prompt = f"""
345
+ You are an exam trend analyzer. Output ONLY VALID JSON.
346
+
347
+ STRICT SCHEMA:
348
  {{
349
+ "bloom_distribution": {{
350
+ "Remember": 0,
351
+ "Understand": 0,
352
+ "Apply": 0,
353
+ "Analyze": 0,
354
+ "Evaluate": 0,
355
+ "Create": 0
356
+ }},
357
+ "difficulty_insights": "string",
358
+ "industry_tag_stats": {{
359
+ "TCS": 0,
360
+ "Infosys": 0,
361
+ "Wipro": 0,
362
+ "Generic": 0
363
+ }},
364
+ "unit_coverage": {{
365
+ "unit1": 0,
366
+ "unit2": 0,
367
+ "unit3": 0,
368
+ "unit4": 0,
369
+ "unit5": 0
370
+ }},
371
+ "maango_score": "0-100",
372
+ "improvement_suggestions": "string"
373
  }}
374
 
375
+ RULE:
376
+ Use the "unit" field inside every question object to compute unit_coverage. DO NOT guess.
377
+
378
+ SUBJECT:
379
+ {subject}
380
+
381
+ QUESTIONS FOR ANALYSIS:
382
+ {json.dumps(q_json, indent=2)}
383
  """
384
+ return apply_MAANGO_BIG15_trendanalysis(base_prompt)
385
 
386
  def create_question_paper(code, name, partA, partB, partC, output_path):
387
  doc = Document()
388
  doc.add_heading("SNS College of Technology", level=1)
389
  doc.add_paragraph(f"Subject Code: {code} Subject: {name}")
390
+ doc.add_paragraph(f"Date: {datetime.now().strftime('%Y-%m-%d')}")
391
+ doc.add_paragraph("Instructions: Answer as per parts and marks specified.\n")
392
 
393
  doc.add_heading("Part A (Short Answer)", level=2)
394
  for idx, q in enumerate(partA, 1):
395
+ text = f"{idx}. {q.get('question_text','')}\nMarks: {q.get('marks',0)} | Unit: {q.get('unit','')} | Bloom: {q.get('bloom_level','')} | Tag: {q.get('company_tag','')}"
396
+ doc.add_paragraph(text)
397
 
398
  doc.add_heading("Part B (Either/Or Questions)", level=2)
399
+ start_idx = len(partA)+1
400
+ for idx, pair in enumerate(partB, start_idx):
401
+ either = pair.get("either", {})
402
+ orq = pair.get("or", {})
403
+ doc.add_paragraph(f"{idx}. Either: {either.get('question_text','')}\nMarks: {either.get('marks',0)} | Unit: {either.get('unit','')} | Bloom: {either.get('bloom_level','')} | Tag: {either.get('company_tag','')}")
404
+ doc.add_paragraph(f" Or: {orq.get('question_text','')}\nMarks: {orq.get('marks',0)} | Unit: {orq.get('unit','')} | Bloom: {orq.get('bloom_level','')} | Tag: {orq.get('company_tag','')}")
405
 
406
  doc.add_heading("Part C (Case/Design Questions)", level=2)
407
+ start_idx = start_idx + len(partB)
408
+ for idx, pair in enumerate(partC, start_idx):
409
+ either = pair.get("either", {})
410
+ orq = pair.get("or", {})
411
+ doc.add_paragraph(f"{idx}. Either: {either.get('question_text','')}\nMarks: {either.get('marks',0)} | Unit: {either.get('unit','')} | Bloom: {either.get('bloom_level','')} | Tag: {either.get('company_tag','')}")
412
+ doc.add_paragraph(f" Or: {orq.get('question_text','')}\nMarks: {orq.get('marks',0)} | Unit: {orq.get('unit','')} | Bloom: {orq.get('bloom_level','')} | Tag: {orq.get('company_tag','')}")
413
 
414
  doc.save(output_path)
415
 
 
420
 
421
  doc.add_heading("Part A Answers", level=2)
422
  for idx, a in enumerate(answers.get("partA", []), 1):
423
+ doc.add_paragraph(f"{idx}. {a.get('question_text','')}\nAnswer: {a.get('answer','')}")
424
 
425
+ doc.add_heading("Part B Answers (Either option)", level=2)
426
+ start_idx = len(answers.get("partA", []))+1
427
+ for idx, a in enumerate(answers.get("partB", []), start_idx):
428
+ doc.add_paragraph(f"{idx}. {a.get('question_text','')}\nAnswer: {a.get('answer','')}")
429
 
430
+ doc.add_heading("Part C Answers (Either option)", level=2)
431
+ start_idx += len(answers.get("partB", []))
432
+ for idx, a in enumerate(answers.get("partC", []), start_idx):
433
+ doc.add_paragraph(f"{idx}. {a.get('question_text','')}\nAnswer: {a.get('answer','')}")
434
+
435
+ doc.save(output_path)
436
+
437
+ def create_trend_report(code, name, trend_json, serp_data, output_path):
438
+ doc = Document()
439
+ doc.add_heading(f"{name} - Trend Analysis Report", level=1)
440
+ doc.add_paragraph(f"Subject Code: {code}")
441
+ doc.add_paragraph(f"Date: {datetime.now().strftime('%Y-%m-%d')}\n")
442
+
443
+ bd = trend_json.get("bloom_distribution", {})
444
+ doc.add_heading("Bloom Distribution", level=2)
445
+ if bd:
446
+ for k, v in bd.items():
447
+ doc.add_paragraph(f"- {k}: {v}", style='List Bullet')
448
+ else:
449
+ doc.add_paragraph("No bloom distribution data found.")
450
+
451
+ doc.add_heading("Difficulty Insights", level=2)
452
+ diff = trend_json.get("difficulty_insights", "")
453
+ doc.add_paragraph(diff if diff else "No difficulty insights provided.")
454
+
455
+ doc.add_heading("Industry Tag Statistics", level=2)
456
+ its = trend_json.get("industry_tag_stats", {})
457
+ if its:
458
+ for k, v in its.items():
459
+ doc.add_paragraph(f"- {k}: {v}", style='List Bullet')
460
+ else:
461
+ doc.add_paragraph("No industry tag stats found.")
462
+
463
+ doc.add_heading("Unit Coverage", level=2)
464
+ uc = trend_json.get("unit_coverage", {})
465
+ if uc:
466
+ for k, v in uc.items():
467
+ doc.add_paragraph(f"- {k}: {v}", style='List Bullet')
468
+ else:
469
+ doc.add_paragraph("No unit coverage data found.")
470
+
471
+ doc.add_heading("MAANGO BIG15 Compliance Score", level=2)
472
+ maango = trend_json.get("maango_score", "")
473
+ doc.add_paragraph(f"Score: {maango if maango else 'N/A'}")
474
+
475
+ doc.add_heading("Improvement Suggestions", level=2)
476
+ sugg = trend_json.get("improvement_suggestions", "")
477
+ doc.add_paragraph(sugg if sugg else "No suggestions provided.")
478
+
479
+ if serp_data:
480
+ doc.add_heading("SERP / Reference Data (summary)", level=2)
481
+ try:
482
+ serp_text = json.dumps(serp_data, indent=2) if not isinstance(serp_data, str) else serp_data
483
+ except Exception:
484
+ serp_text = str(serp_data)
485
+ max_chars = 6000
486
+ if len(serp_text) > max_chars:
487
+ serp_text = serp_text[:max_chars] + "\n\n[Truncated for brevity]"
488
+ for line in serp_text.splitlines():
489
+ doc.add_paragraph(line)
490
 
491
  doc.save(output_path)
492
 
 
499
  syllabus_text = extract_text(syllabus_file.name)
500
  selected_syllabus = extract_units(syllabus_text, units)
501
 
502
+ if not selected_syllabus.strip():
503
+ return None, "❌ No syllabus found for given units."
504
+
505
+ # STEP 1: Generate Questions
506
  q_prompt = build_question_prompt(subject, selected_syllabus, numA, numB, numC, exam_mode)
507
  q_raw = model_q.invoke([HumanMessage(content=q_prompt)]).content
508
  q_json = sanitize_json(q_raw)
509
 
510
+ partA = q_json.get("partA", [])
511
+ partB = q_json.get("partB", [])
512
+ partC = q_json.get("partC", [])
513
+
514
+ if not (partA or partB or partC):
515
+ return None, "❌ Generated question JSON missing required parts."
516
+
517
+ # STEP 2: Fetch SERP data
518
+ try:
519
+ serp_data = serp.run(f"{subject} latest industry syllabus questions trends")
520
+ except Exception as e:
521
+ serp_data = f"SERP fetch failed: {e}"
522
+
523
+ # STEP 3: Analyze trends
524
+ t_prompt = build_trend_prompt(subject, q_json)
525
+ t_raw = model_t.invoke([HumanMessage(content=t_prompt)]).content
526
+ t_json = sanitize_json(t_raw)
527
+
528
+ # STEP 4: Generate Answer Key
529
+ a_prompt = build_answer_prompt(selected_syllabus, q_json)
530
  a_raw = model_a.invoke([HumanMessage(content=a_prompt)]).content
531
  a_json = sanitize_json(a_raw)
532
 
533
+ # STEP 5: Create DOCX files
534
  qp_file = f"{code}_QuestionPaper.docx"
535
  ak_file = f"{code}_AnswerKey.docx"
536
+ ta_file = f"{code}_TrendAnalysis.docx"
537
 
538
+ create_question_paper(code, subject, partA, partB, partC, qp_file)
539
  create_answer_key(code, subject, a_json, ak_file)
540
+ create_trend_report(code, subject, t_json, serp_data, ta_file)
541
 
542
  zip_file = f"{code}_ExamPackage.zip"
543
  with zipfile.ZipFile(zip_file, 'w') as zipf:
544
  zipf.write(qp_file)
545
  zipf.write(ak_file)
546
+ zipf.write(ta_file)
547
 
548
+ return zip_file, f"βœ… Successfully generated exam package for {subject}!\nπŸ“Š MAANGO Score: {t_json.get('maango_score', 'N/A')}"
549
 
550
  except Exception as e:
551
  return None, f"❌ Error: {str(e)}"
 
624
  }
625
  </style>
626
  <div class="header-gradient">
627
+ <h1>πŸŽ“ SNS Tech - Q&A Agent x Codeboosters Tech</h1>
628
+ <p><strong>AI-Powered Question Paper & Answer Key Generator with Trend Analysis</strong></p>
629
+ <p>Powered by MAANGO BIG15 Framework | Advanced LLM Technology | Developed by Codeboosters Tech Team</p>
630
  </div>
631
  """)
632
 
 
654
 
655
  gr.HTML("""
656
  <div class="feature-card">
657
+ <h4>✨ MAANGO BIG15 Features</h4>
658
  <ul>
659
+ <li>🎯 Multi-Cognitive Bloom Alignment</li>
660
  <li>🏒 Industry Tag Integration (TCS/Infosys/Wipro)</li>
661
+ <li>πŸ“ˆ Granular Unit Balancing</li>
662
+ <li>πŸ” GATE Layer Injection</li>
663
  <li>πŸ“ Automatic Answer Key Generation</li>
664
+ <li>πŸ“Š Advanced Trend Analysis with SERP Data</li>
665
+ <li>πŸŽ“ MAANGO Compliance Scoring (0-100)</li>
666
+ <li>πŸ’‘ AI-Powered Improvement Suggestions</li>
667
  </ul>
668
  </div>
669
  """)
670
 
671
+ generate_btn = gr.Button("πŸš€ Generate Complete Exam Package", variant="primary", size="lg")
672
 
673
  with gr.Row():
674
+ output_file = gr.File(label="πŸ“¦ Download Package (Question Paper + Answer Key + Trend Analysis)")
675
+ status_msg = gr.Textbox(label="Status", lines=3)
676
 
677
  generate_btn.click(
678
  fn=generate_exam,
 
682
 
683
  gr.HTML("""
684
  <footer>
685
+ <p><strong>MAANGO BIG15 Framework</strong> - 15 Pillars of Excellence in Question Paper Generation</p>
686
+ <p>Developed with ❀️ by Veerakumar C B | Codeboosters Tech | © 2024</p>
687
  </footer>
688
  """)
689