from generation.ExamRagGenerator import ExamGenerationRequest, ExamResponse import json class ExamPromptBuilder: MAX_SCORE = 40 def build_exam_generation_prompt(self,request: ExamGenerationRequest,context: str) -> str: distribution = { q_type.value: count for q_type, count in request.question_types_distribution.items() } return f""" You are an automated exam generation system. Your job is to produce a structured exam strictly following the schema below. ---------------------------------------------------- CRITICAL OUTPUT RULES ---------------------------------------------------- You MUST return ONLY a valid JSON object. Do NOT include: - explanations - markdown - comments - code blocks - text before or after the JSON The response MUST start with {{ and end with }}. If the output is not valid JSON the result will be rejected. ---------------------------------------------------- ENUM VALUES (STRICT) ---------------------------------------------------- difficulty must be exactly one of: easy medium hard question type must be exactly one of: mcq true_false short_answer essay code ---------------------------------------------------- EXAM REQUIREMENTS ---------------------------------------------------- course: {request.course} difficulty: {request.difficulty.value} total_questions: {request.total_questions} question_types_distribution: {json.dumps(distribution)} You MUST generate exactly: {json.dumps(distribution)} Example: {{ "mcq": 3, "essay": 2 }} means exactly: 3 mcq questions 2 essay questions ---------------------------------------------------- CONTEXT ---------------------------------------------------- Use ONLY the information from this context when creating questions. {context} ---------------------------------------------------- QUESTION RULES ---------------------------------------------------- MCQ QUESTIONS - must contain exactly 4 options - options must be plain text - correct_answer must match one option EXACTLY - do NOT use letters like A/B/C/D - do NOT include numbering inside options Example: {{ "type": "mcq", "question": "What is 2 + 2?", "options": ["1","2","3","4"], "correct_answer": "4", "explanation": "2 + 2 equals 4" }} ---------------------------------------------------- TRUE/FALSE QUESTIONS correct_answer must be boolean. Example: {{ "type": "true_false", "question": "The Earth revolves around the Sun.", "correct_answer": true, "explanation": "Astronomy confirms this." }} ---------------------------------------------------- SHORT ANSWER QUESTIONS Example: {{ "type": "short_answer", "question": "Define photosynthesis.", "answer": "Process where plants convert light into chemical energy", "explanation": "Occurs in chloroplasts using sunlight" }} ---------------------------------------------------- ESSAY QUESTIONS Example: {{ "type": "essay", "question": "Explain Newton's First Law.", "answer": "Newton's First Law states that an object will remain at rest or continue moving in a straight line at constant velocity unless acted upon by an external force. This property is called inertia. For example, a book on a table stays at rest until someone pushes it, and a moving car continues moving until friction or braking stops it.", "answer_guidelines": "Describe inertia and provide examples" }} ---------------------------------------------------- CODE QUESTIONS Rules: starter_code must be either a string OR null. Never output the string "None". Example: {{ "type": "code", "question": "Write a Python function to compute factorial.", "language": "c", "starter_code": "def factorial(n):", "solution": "def factorial(n): return 1 if n<=1 else n*factorial(n-1)", "explanation": "Uses recursion" }} ---------------------------------------------------- IMPORTANT RESTRICTIONS ---------------------------------------------------- Do NOT output: LaTeX math formulas markdown additional fields Use plain text only. ---------------------------------------------------- FINAL JSON STRUCTURE ---------------------------------------------------- {{ "exam_id": "{request.exam_id}", "difficulty": "{request.difficulty.value}", "total_questions": {request.total_questions}, "expected_distribution": {json.dumps(distribution)}, "questions": [] }} Fill the questions array with the generated questions. ---------------------------------------------------- Return ONLY the JSON object. """ def build_exam_evaluation_prompt(self,request: ExamGenerationRequest,exam: ExamResponse) -> str: exam_json = exam.model_dump_json() return f""" You are an exam quality evaluator. -------------------------------- OUTPUT RULES -------------------------------- 1. Output MUST be valid JSON. 2. Do NOT include markdown. 3. Do NOT include reasoning outside JSON. 4. Output ONLY the JSON object. 5. JSON must start with {{ and end with }}. -------------------------------- SCORING RANGE -------------------------------- 0 to {self.MAX_SCORE} -------------------------------- EVALUATION CRITERIA -------------------------------- 1. Relevance of questions to the topics 2. Correct distribution of question types 3. Clarity and wording of questions 4. Difficulty consistency 5. Correctness of answers -------------------------------- EXAM TO EVALUATE -------------------------------- {exam_json} -------------------------------- OUTPUT FORMAT -------------------------------- {{ "overall_score": integer between 0 and {self.MAX_SCORE}, "feedback": "short explanation of issues if any" }} Return ONLY JSON. """