File size: 7,241 Bytes
78e8dd4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0cfa3a6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
"""

Question Generation Module

Generates multiple-choice questions based on Bloom's taxonomy

"""
import json
from typing import Dict, List
from openai import OpenAI


class QuestionGenerator:
    """Generates educational questions based on Bloom's taxonomy"""
    
    def __init__(self, client: OpenAI, rag_query_engine):
        self.client = client
        self.rag_query_engine = rag_query_engine
        
        self.blooms_levels = {
            "remember": "generate questions that test basic recall of facts and information",
            "understand": "generate questions that test explanation and interpretation of concepts",
            "apply": "generate questions that test application of knowledge in practical situations",
            "analyze": "generate questions that test analysis of relationships and structure",
            "evaluate": "generate questions that test evaluation and judgment based on criteria",
            "create": "generate questions that test creation of new ideas or solutions"
        }
    
    def generate_questions(self, topic_file: str) -> Dict[str, Dict]:
        """

        Generate multiple-choice questions for all Bloom's taxonomy levels

        

        Args:

            topic_file: Name of the topic file (PDF)

            

        Returns:

            Dictionary mapping Bloom's level to question data

        """
        topic_clean = topic_file.replace('.pdf', '')
        
        # Get content about this topic
        file_content_query = f"What are the key points covered in the document '{topic_clean}'?"
        content_response, _ = self.rag_query_engine.query(file_content_query)
        
        # Build prompt
        prompt = self._build_question_prompt(topic_clean, content_response)
        
        try:
            response = self.client.chat.completions.create(
                model="gpt-4o",
                messages=[
                    {"role": "system", "content": "You are an expert in creating educational assessment materials for automotive systems."},
                    {"role": "user", "content": prompt}
                ],
                temperature=0.4,
                response_format={"type": "json_object"}
            )
            
            response_text = response.choices[0].message.content
            
            try:
                questions_data = json.loads(response_text)
                question_dict = self._validate_and_format_questions(questions_data, topic_clean)
                return question_dict
            except json.JSONDecodeError as e:
                print(f"⚠️ Error parsing JSON: {e}")
                return self._create_fallback_questions(topic_clean)
        except Exception as e:
            print(f"❌ Error generating questions: {e}")
            return self._create_fallback_questions(topic_clean)
    
    def _build_question_prompt(self, topic_clean: str, content_response: str) -> str:
        """Build the prompt for question generation"""
        prompt = f"""You are a tester trying to come up with multiple choice questions from system users based on the input car manuals.

You are trying to make it not tricky, but at the same time not too easy. However, users' understanding of the system is your utmost priority.



Create 1 multiple choice question based on the manual file about '{topic_clean}' for each of the following levels of Bloom's taxonomy:

- Remember: {self.blooms_levels['remember']}

- Understand: {self.blooms_levels['understand']}

- Apply: {self.blooms_levels['apply']}

- Analyze: {self.blooms_levels['analyze']}

- Evaluate: {self.blooms_levels['evaluate']}

- Create: {self.blooms_levels['create']}



Try to find the most important and insightful content for each question. Do note where the right answer in the manual file is located.

Separate the questions and explanations (i.e., only write all the explanations at the end).

Please do not generate questions that give varying numbers as answers. Test users' concepts and understanding of the vehicle system.

Make sure there are no questions with possibility of two correct answers.



Try to have a definitive right answer. Be slow and steady.



Here is the content from the manual:

{content_response}



Output your response as a clean JSON object with these fields for each question:

- level (string): the Bloom's taxonomy level

- question_text (string): the full question text

- options (array): four answer choices as strings

- correct_option_index (integer): index of the correct answer (0-3)

- explanation (string): explanation of why the correct answer is right



Example JSON format:

{{

  "questions": [

    {{

      "level": "remember",

      "question_text": "What does DISTRONIC stand for?",

      "options": ["Distance Control", "Dynamic Intelligent Speed Tronic", "Direct Intelligence Control", "Digital Road Navigation Intelligence Control"],

      "correct_option_index": 1,

      "explanation": "DISTRONIC stands for Dynamic Intelligent Speed Tronic as stated in section 3.2 of the manual."

    }}

  ]

}}

"""
        return prompt
    
    def _validate_and_format_questions(self, questions_data: Dict, topic_clean: str) -> Dict[str, Dict]:
        """Validate and format questions, ensuring all levels are present"""
        expected_levels = ["remember", "understand", "apply", "analyze", "evaluate", "create"]
        question_dict = {}
        
        for q in questions_data.get("questions", []):
            level = q.get("level", "").lower()
            if level in expected_levels:
                question_dict[level] = q
        
        # Fill missing levels with fallback questions
        for level in expected_levels:
            if level not in question_dict:
                print(f"⚠️ Missing question for level: {level}")
                question_dict[level] = {
                    "level": level,
                    "question_text": f"Question for {level} level could not be generated.",
                    "options": ["Option A", "Option B", "Option C", "Option D"],
                    "correct_option_index": 0,
                    "explanation": "Please try again or select a different topic."
                }
        
        return question_dict
    
    def _create_fallback_questions(self, topic_name: str) -> Dict[str, Dict]:
        """Create fallback questions when generation fails"""
        fallback = {}
        for level in ["remember", "understand", "apply", "analyze", "evaluate", "create"]:
            fallback[level] = {
                "level": level,
                "question_text": f"What is a key feature of {topic_name}?",
                "options": [
                    f"Option A about {topic_name}",
                    f"Option B about {topic_name}",
                    f"Option C about {topic_name}",
                    f"Option D about {topic_name}"
                ],
                "correct_option_index": 0,
                "explanation": f"This is a fallback question for the {level} level. Please try again or select a different topic."
            }
        return fallback