from pathlib import Path import PyPDF2 from typing import Dict, List, Optional from pydantic import BaseModel from modules.pdf_utils import PDFUtils class TestAnalysis(BaseModel): overall_score: float section_scores: Dict[str, float] feedback: str recommendations: List[str] detailed_analysis: Optional[Dict] = None class TestAnalyzer: def __init__(self, api_key: str): self.api_key = api_key def extract_text_from_pdf(self, pdf_file: Path) -> str: """ Extract text content from a PDF file """ if not pdf_file.exists(): raise FileNotFoundError(f"PDF file not found: {pdf_file}") text = "" with open(pdf_file, 'rb') as file: pdf_reader = PyPDF2.PdfReader(file) for page in pdf_reader.pages: text += page.extract_text() + "\n" return text def analyze_test(self, pdf_content: str, marks_data: Dict, mode: str = 'detailed') -> TestAnalysis: """ Analyze a test and generate feedback based on marks data """ # Calculate overall score total_marks = sum(marks_data.values()) max_marks = len(marks_data) * 100 # Assuming each question is out of 100 overall_score = (total_marks / max_marks) * 100 # Calculate section scores (group by first part of question number) section_scores = {} for question, marks in marks_data.items(): section = question.split('.')[0] if section not in section_scores: section_scores[section] = [] section_scores[section].append(marks) # Calculate average for each section for section, marks in section_scores.items(): section_scores[section] = sum(marks) / len(marks) # Generate feedback feedback = self._generate_feedback(overall_score, section_scores) # Generate recommendations recommendations = self._generate_recommendations(section_scores) # Create detailed analysis if requested detailed_analysis = None if mode == 'detailed': detailed_analysis = { 'question_analysis': self._analyze_questions(pdf_content, marks_data), 'strengths': self._identify_strengths(section_scores), 'weaknesses': self._identify_weaknesses(section_scores) } return TestAnalysis( overall_score=overall_score, section_scores=section_scores, feedback=feedback, recommendations=recommendations, detailed_analysis=detailed_analysis ) def _generate_feedback(self, overall_score: float, section_scores: Dict[str, float]) -> str: """ Generate feedback based on overall score and section scores """ if overall_score >= 90: return "Excellent performance! You have demonstrated a strong understanding of the material." elif overall_score >= 80: return "Very good performance. You have a solid grasp of most concepts." elif overall_score >= 70: return "Good performance. You understand the main concepts but could improve in some areas." elif overall_score >= 60: return "Satisfactory performance. You have a basic understanding but need to work on several areas." else: return "Needs improvement. Focus on understanding the fundamental concepts better." def _generate_recommendations(self, section_scores: Dict[str, float]) -> List[str]: """ Generate recommendations based on section scores """ recommendations = [] for section, score in section_scores.items(): if score < 70: recommendations.append(f"Focus on improving your understanding of Section {section}") elif score < 80: recommendations.append(f"Review Section {section} to strengthen your knowledge") if not recommendations: recommendations.append("Continue practicing to maintain your strong performance") return recommendations def _analyze_questions(self, pdf_content: str, marks_data: Dict) -> Dict: """ Analyze individual questions """ question_analysis = {} for question, marks in marks_data.items(): question_analysis[question] = { 'score': marks, 'performance': 'excellent' if marks >= 90 else 'good' if marks >= 70 else 'needs_improvement' } return question_analysis def _identify_strengths(self, section_scores: Dict[str, float]) -> List[str]: """ Identify strong sections """ return [f"Section {section}" for section, score in section_scores.items() if score >= 80] def _identify_weaknesses(self, section_scores: Dict[str, float]) -> List[str]: """ Identify weak sections """ return [f"Section {section}" for section, score in section_scores.items() if score < 70]