api/modules/test_analyzer.py
2025-07-11 13:52:19 +00:00

130 lines
5.0 KiB
Python

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]