capradeepgujaran commited on
Commit
43a4a57
1 Parent(s): fe4ed31

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -75
app.py CHANGED
@@ -24,92 +24,85 @@ class QuizFeedback:
24
  class QuizGenerator:
25
  def __init__(self, api_key: str):
26
  self.client = Groq(api_key=api_key)
27
-
28
  def generate_questions(self, text: str, num_questions: int) -> List[Question]:
29
- """Generate quiz questions from input text"""
30
  prompt = self._create_prompt(text, num_questions)
31
 
32
  try:
33
- # Make API request with improved error handling
34
  response = self.client.chat.completions.create(
35
  messages=[
36
  {
37
  "role": "system",
38
- "content": """You are a quiz generator. Generate multiple choice questions based on the given text.
39
- Each question must have exactly 4 options and one correct answer.
40
- Return ONLY a valid JSON array of questions in the specified format.
41
- Make questions clear, focused and directly related to the input text.
42
- Avoid subjective or ambiguous questions."""
43
  },
44
  {
45
  "role": "user",
46
  "content": prompt
47
  }
48
  ],
49
- model="llama-3.2-3b-preview", # Using a more capable model
50
- temperature=0.2, # Lower temperature for more consistent output
51
- max_tokens=2048,
52
- stop=None # Let the model complete its output
53
  )
54
 
55
- if not response or not response.choices or not response.choices[0].message.content:
56
- raise ValueError("Empty response from API")
57
-
58
- # Parse and validate response
59
- questions = self._parse_response(response.choices[0].message.content)
 
 
 
 
 
60
  validated = self._validate_questions(questions, num_questions)
61
 
62
  if not validated:
63
  raise ValueError("No valid questions generated")
64
-
65
  return validated
66
 
67
  except Exception as e:
68
  print(f"Error in generate_questions: {str(e)}")
69
- print(f"Full error details: ", {
70
- "error": str(e),
71
- "response": getattr(response, 'choices', [{}])[0].get('message', {}).get('content', 'No content')
72
- if 'response' in locals() else 'No response'
73
- })
74
  raise QuizGenerationError(f"Failed to generate questions: {str(e)}")
75
 
76
  def _create_prompt(self, text: str, num_questions: int) -> str:
77
- """Create a clear, structured prompt for question generation"""
78
- return f"""Generate exactly {num_questions} multiple choice questions based on this text. For each question:
79
-
80
- 1. Create a clear, specific question focusing on key information
81
- 2. Provide exactly 4 answer options
82
- 3. Ensure one and only one option is correct
83
- 4. Keep options concise (under 10 words each)
84
- 5. Avoid subjective or ambiguous questions
85
- 6. Make all options plausible but only one correct
86
-
87
- Return ONLY a JSON array in this exact format:
88
  [
89
- {{
90
- "question": "Question text here?",
91
- "options": [
92
- "Option 1",
93
- "Option 2",
94
- "Option 3",
95
- "Option 4"
96
- ],
97
- "correct_answer": 0
98
- }}
99
  ]
100
 
101
- The correct_answer should be the index (0-3) of the correct option.
102
- Return only the JSON array, no other text.
 
 
 
 
103
 
104
- Text to generate questions from:
105
  {text.strip()}"""
106
 
107
  def _parse_response(self, response_text: str) -> List[Dict]:
108
- """Parse API response with robust error handling"""
109
  try:
110
  # Clean up the response text
111
  cleaned = response_text.strip()
112
- # Remove any markdown code block markers
 
113
  cleaned = cleaned.replace('```json', '').replace('```', '').strip()
114
 
115
  # Find the JSON array
@@ -118,65 +111,71 @@ Text to generate questions from:
118
 
119
  if start == -1 or end == 0:
120
  raise ValueError("No JSON array found in response")
121
-
122
  json_str = cleaned[start:end]
123
 
124
- # Parse JSON
 
 
 
125
  try:
126
  questions = json.loads(json_str)
127
  except json.JSONDecodeError as e:
128
- print(f"JSON Parse Error: {str(e)}")
129
- print(f"Attempted to parse: {json_str}")
130
- raise
131
-
 
132
  if not isinstance(questions, list):
133
- raise ValueError("Response is not a list of questions")
134
-
135
  return questions
136
 
137
  except Exception as e:
138
- print(f"Error parsing response: {str(e)}")
139
- print(f"Original response: {response_text}")
140
- raise ValueError(f"Failed to parse questions: {str(e)}")
141
 
142
  def _validate_questions(self, questions: List[Dict], num_questions: int) -> List[Question]:
143
- """Validate and convert questions to Question objects"""
144
  validated = []
145
 
146
  for q in questions[:num_questions]:
147
  try:
148
- # Validate question structure
149
  if not isinstance(q, dict):
150
  continue
151
-
152
- required_keys = {"question", "options", "correct_answer"}
153
- if not all(key in q for key in required_keys):
154
  continue
155
-
156
- if not isinstance(q["options"], list) or len(q["options"]) != 4:
 
157
  continue
158
-
159
- # Convert correct_answer to int and validate
160
  try:
161
- correct_idx = int(q["correct_answer"])
162
- if not 0 <= correct_idx < 4:
163
  continue
164
  except (ValueError, TypeError):
165
  continue
166
 
167
- # Create Question object
168
  validated.append(Question(
169
- question=str(q["question"]).strip(),
170
- options=[str(opt).strip() for opt in q["options"]],
171
  correct_answer=correct_idx
172
  ))
173
 
174
  except Exception as e:
175
- print(f"Error validating question: {str(e)}")
176
  continue
177
 
178
  return validated
179
 
 
180
  class FontManager:
181
  """Manages font installation and loading for the certificate generator"""
182
 
 
24
  class QuizGenerator:
25
  def __init__(self, api_key: str):
26
  self.client = Groq(api_key=api_key)
27
+
28
  def generate_questions(self, text: str, num_questions: int) -> List[Question]:
29
+ """Generate quiz questions using llama-3.2-3b-preview model"""
30
  prompt = self._create_prompt(text, num_questions)
31
 
32
  try:
33
+ # API call with simplified parameters for llama-3.2-3b-preview
34
  response = self.client.chat.completions.create(
35
  messages=[
36
  {
37
  "role": "system",
38
+ "content": "You are a quiz generator. Generate multiple choice questions that are clear and focused."
 
 
 
 
39
  },
40
  {
41
  "role": "user",
42
  "content": prompt
43
  }
44
  ],
45
+ model="llama-3.2-3b-preview",
46
+ temperature=0.1, # Very low temperature for consistent output
47
+ max_tokens=1024
 
48
  )
49
 
50
+ # Extract content safely
51
+ if not response or not hasattr(response.choices[0], 'message'):
52
+ raise ValueError("Invalid API response structure")
53
+
54
+ content = response.choices[0].message.content
55
+ if not content:
56
+ raise ValueError("Empty response content")
57
+
58
+ # Parse and validate questions
59
+ questions = self._parse_response(content)
60
  validated = self._validate_questions(questions, num_questions)
61
 
62
  if not validated:
63
  raise ValueError("No valid questions generated")
64
+
65
  return validated
66
 
67
  except Exception as e:
68
  print(f"Error in generate_questions: {str(e)}")
69
+ if 'response' in locals():
70
+ print("Response content:", getattr(response.choices[0], 'message', {}).content if hasattr(response, 'choices') else None)
 
 
 
71
  raise QuizGenerationError(f"Failed to generate questions: {str(e)}")
72
 
73
  def _create_prompt(self, text: str, num_questions: int) -> str:
74
+ """Create a simple, clear prompt optimized for llama-3.2-3b-preview"""
75
+ return f"""Create {num_questions} multiple choice questions about this text. Use this exact JSON format and nothing else:
 
 
 
 
 
 
 
 
 
76
  [
77
+ {{
78
+ "question": "Write the question here?",
79
+ "options": [
80
+ "First option",
81
+ "Second option",
82
+ "Third option",
83
+ "Fourth option"
84
+ ],
85
+ "correct_answer": 0
86
+ }}
87
  ]
88
 
89
+ Rules:
90
+ 1. Return only the JSON array
91
+ 2. Each question must have exactly 4 options
92
+ 3. correct_answer must be 0, 1, 2, or 3
93
+ 4. No explanations or additional text
94
+ 5. Keep options short and clear
95
 
96
+ Text to use:
97
  {text.strip()}"""
98
 
99
  def _parse_response(self, response_text: str) -> List[Dict]:
100
+ """Parse response with improved error handling"""
101
  try:
102
  # Clean up the response text
103
  cleaned = response_text.strip()
104
+
105
+ # Remove any markdown or additional text
106
  cleaned = cleaned.replace('```json', '').replace('```', '').strip()
107
 
108
  # Find the JSON array
 
111
 
112
  if start == -1 or end == 0:
113
  raise ValueError("No JSON array found in response")
114
+
115
  json_str = cleaned[start:end]
116
 
117
+ # Basic JSON structure validation before parsing
118
+ if not (json_str.startswith('[') and json_str.endswith(']')):
119
+ raise ValueError("Invalid JSON structure")
120
+
121
  try:
122
  questions = json.loads(json_str)
123
  except json.JSONDecodeError as e:
124
+ # Try to fix common JSON formatting issues
125
+ fixed_json = json_str.replace('}\n{', '},{') # Fix line breaks between objects
126
+ fixed_json = fixed_json.replace(',]', ']') # Fix trailing commas
127
+ questions = json.loads(fixed_json)
128
+
129
  if not isinstance(questions, list):
130
+ raise ValueError("Parsed JSON is not a list")
131
+
132
  return questions
133
 
134
  except Exception as e:
135
+ print(f"Parse error details: {str(e)}")
136
+ print(f"Attempted to parse: {response_text}")
137
+ raise
138
 
139
  def _validate_questions(self, questions: List[Dict], num_questions: int) -> List[Question]:
140
+ """Validate questions with strict checking"""
141
  validated = []
142
 
143
  for q in questions[:num_questions]:
144
  try:
145
+ # Skip invalid questions
146
  if not isinstance(q, dict):
147
  continue
148
+
149
+ # Check required fields
150
+ if not all(key in q for key in ['question', 'options', 'correct_answer']):
151
  continue
152
+
153
+ # Validate options
154
+ if not isinstance(q['options'], list) or len(q['options']) != 4:
155
  continue
156
+
157
+ # Validate correct_answer
158
  try:
159
+ correct_idx = int(q['correct_answer'])
160
+ if not 0 <= correct_idx <= 3:
161
  continue
162
  except (ValueError, TypeError):
163
  continue
164
 
165
+ # Create validated Question object
166
  validated.append(Question(
167
+ question=str(q['question']).strip(),
168
+ options=[str(opt).strip() for opt in q['options']],
169
  correct_answer=correct_idx
170
  ))
171
 
172
  except Exception as e:
173
+ print(f"Validation error: {str(e)}")
174
  continue
175
 
176
  return validated
177
 
178
+
179
  class FontManager:
180
  """Manages font installation and loading for the certificate generator"""
181