import os from dotenv import load_dotenv import openai import json from .base_agent import BaseAgent load_dotenv() class BloomsAssessmentAgent(BaseAgent): def __init__(self): super().__init__("BloomsAssessmentAgent") api_key = os.getenv("OPENAI_API_KEY") self.client = openai.OpenAI(api_key=api_key) self.bloom_levels = [ "Remembering", "Understanding", "Applying", "Analyzing", "Evaluating", "Creating" ] def generate_bloom_question(self, chapter, bloom_level): system_prompt = ( f"You are an expert educator creating a {bloom_level} level question according to Bloom's Taxonomy. " f"Generate ONE question that tests the student's ability at the {bloom_level} level for the given chapter. " "The question should be clear, concise, and appropriate for the chapter content. " "Return ONLY the question text, no additional formatting or explanation." ) user_prompt = ( f"Chapter: {chapter.name}\n" f"Modules in this chapter: {[m.name for m in chapter.modules]}\n" f"Bloom's Level: {bloom_level}\n" f"Generate a {bloom_level} level question." ) response = self.client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt} ] ) return response.choices[0].message.content.strip() def evaluate_bloom_answer(self, question, user_answer, bloom_level, chapter): system_prompt = ( f"You are an expert educator evaluating a student's answer for a {bloom_level} level question. " "Evaluate the answer based on the specific cognitive skills required for this Bloom's level. " "Be STRICT about answer quality - vague, incomplete, or overly brief answers should receive low scores.\n\n" "**Evaluation Criteria:**\n" "- **Precision:** Is the answer specific and detailed enough for the Bloom's level?\n" "- **Relevance:** Does it directly address the question asked?\n" "- **Depth:** Does it demonstrate the expected cognitive complexity?\n" "- **Completeness:** Are all parts of the question addressed?\n\n" "**Automatic Penalties:**\n" "- Answers under 15 words: Maximum score of 3\n" "- Vague responses (yes/no, maybe, I think): Maximum score of 2\n" "- Off-topic or irrelevant answers: Score of 0-1\n\n" "You must respond with a JSON object containing:\n" "1. 'score': A number between 0 and 10\n" "2. 'feedback': Detailed explanation of the score and what was missing\n" "3. 'level_achieved': The Bloom's level the answer demonstrates\n" "4. 'hint': A subtle hint to guide toward better understanding (if score < 7)" ) user_prompt = ( f"Question (Bloom's Level: {bloom_level}): {question}\n" f"Student's Answer: {user_answer}\n" f"Chapter Context: {chapter.name}\n" "Evaluate this answer and provide the JSON response." ) response = self.client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt} ] ) return response.choices[0].message.content.strip() def process(self, chapter): print(f"\n{'='*60}") print(f"BLOOM'S TAXONOMY ASSESSMENT") print(f"Chapter: {chapter.name}") print(f"{'='*60}") print("You will be asked 2 questions for each of the 6 Bloom's levels.") print("This comprehensive assessment will evaluate your mastery of the chapter.") results = {} total_score = 0 questions_asked = 0 for bloom_level in self.bloom_levels: level_scores = [] print(f"\n--- {bloom_level.upper()} LEVEL (2 Questions) ---") for question_num in range(1, 3): # 2 questions per level print(f"\n[Question {question_num}/2 for {bloom_level}]") question = self.generate_bloom_question(chapter, bloom_level) print(f"Question: {question}") user_answer = input("Your answer: ") evaluation_json = self.evaluate_bloom_answer(question, user_answer, bloom_level, chapter) try: evaluation = json.loads(evaluation_json) score = evaluation.get('score', 0) feedback = evaluation.get('feedback', 'No feedback provided') level_achieved = evaluation.get('level_achieved', bloom_level) hint = evaluation.get('hint', '') print(f"Score: {score}/10") print(f"Feedback: {feedback}") print(f"Level Demonstrated: {level_achieved}") # If score is low, provide hint and offer retry if score < 7 and hint: print(f"šŸ’” Hint: {hint}") retry = input("\nYour answer needs improvement. Would you like to try again? (y/n): ").lower().strip() if retry == 'y': print("\nšŸ”„ Please provide a more detailed and specific answer.") retry_answer = input("Your revised answer: ") # Re-evaluate the retry answer retry_evaluation_json = self.evaluate_bloom_answer(question, retry_answer, bloom_level, chapter) try: retry_evaluation = json.loads(retry_evaluation_json) retry_score = retry_evaluation.get('score', 0) retry_feedback = retry_evaluation.get('feedback', 'No feedback provided') retry_level = retry_evaluation.get('level_achieved', bloom_level) print(f"\nRetry Score: {retry_score}/10") print(f"Retry Feedback: {retry_feedback}") print(f"Retry Level Demonstrated: {retry_level}") # Use the better of the two scores final_score = max(score, retry_score) level_scores.append(final_score) total_score += final_score questions_asked += 1 except json.JSONDecodeError: print("Error evaluating retry answer. Using original score.") level_scores.append(score) total_score += score questions_asked += 1 else: level_scores.append(score) total_score += score questions_asked += 1 else: level_scores.append(score) total_score += score questions_asked += 1 except json.JSONDecodeError: print("Error evaluating answer. Defaulting to score 5.") level_scores.append(5) total_score += 5 questions_asked += 1 # Store results for this Bloom's level results[bloom_level] = { 'scores': level_scores, 'average_score': sum(level_scores) / len(level_scores), 'total_score': sum(level_scores) } # Calculate overall results max_possible = questions_asked * 10 average_score = total_score / questions_asked percentage = (total_score / max_possible) * 100 print(f"\n{'='*60}") print("COMPREHENSIVE ASSESSMENT RESULTS") print(f"{'='*60}") print(f"Total Score: {total_score}/{max_possible}") print(f"Average Score: {average_score:.1f}/10") print(f"Percentage: {percentage:.1f}%") # Enhanced mastery determination if percentage >= 85: mastery = "Excellent Mastery" recommendation = "Ready to advance to next level" elif percentage >= 70: mastery = "Good Understanding" recommendation = "Ready to advance with some review" elif percentage >= 55: mastery = "Basic Understanding" recommendation = "Review weak areas before advancing" else: mastery = "Needs Significant Review" recommendation = "Revisit chapter content and retake assessment" print(f"Mastery Level: {mastery}") print(f"Recommendation: {recommendation}") print(f"\nDetailed Breakdown by Bloom's Level:") for level, result in results.items(): avg = result['average_score'] print(f" {level}: {avg:.1f}/10 (Scores: {result['scores']})") # Determine if student should advance or review should_advance = percentage >= 70 return { 'chapter': chapter.name, 'total_score': total_score, 'max_possible': max_possible, 'average_score': average_score, 'percentage': percentage, 'mastery_level': mastery, 'recommendation': recommendation, 'should_advance': should_advance, 'detailed_results': results }