""" Correction API - Helper functions for grading, feedback, and OCR processing. """ import logging from typing import List, Dict from correction_models import AnswerEvaluation, CorrectionStatus, Correction logger = logging.getLogger(__name__) # FileProcessor requires OpenCV with libGL - make optional for CI try: from services.file_processor import FileProcessor, ProcessingResult _ocr_available = True except (ImportError, OSError): FileProcessor = None # type: ignore ProcessingResult = None # type: ignore _ocr_available = False # PDF service requires WeasyPrint with system libraries - make optional for CI try: from services.pdf_service import PDFService, CorrectionData, StudentInfo _pdf_available = True except (ImportError, OSError): PDFService = None # type: ignore CorrectionData = None # type: ignore StudentInfo = None # type: ignore _pdf_available = False # ============================================================================ # In-Memory Storage (spaeter durch DB ersetzen) # ============================================================================ corrections_store: Dict[str, Correction] = {} # ============================================================================ # Helper Functions # ============================================================================ def calculate_grade(percentage: float) -> str: """Berechnet Note aus Prozent (deutsches System).""" if percentage >= 92: return "1" elif percentage >= 81: return "2" elif percentage >= 67: return "3" elif percentage >= 50: return "4" elif percentage >= 30: return "5" else: return "6" def generate_ai_feedback( evaluations: List[AnswerEvaluation], total_points: float, max_points: float, subject: str ) -> str: """Generiert KI-Feedback basierend auf Bewertung.""" # Ohne LLM: Einfaches Template-basiertes Feedback percentage = (total_points / max_points * 100) if max_points > 0 else 0 correct_count = sum(1 for e in evaluations if e.is_correct) total_count = len(evaluations) if percentage >= 90: intro = "Hervorragende Leistung!" elif percentage >= 75: intro = "Gute Arbeit!" elif percentage >= 60: intro = "Insgesamt eine solide Leistung." elif percentage >= 50: intro = "Die Arbeit zeigt Grundkenntnisse, aber es gibt Verbesserungsbedarf." else: intro = "Es sind deutliche Wissensluecken erkennbar." # Finde Verbesserungsbereiche weak_areas = [e for e in evaluations if not e.is_correct] strengths = [e for e in evaluations if e.is_correct and e.confidence > 0.8] feedback_parts = [intro] if strengths: feedback_parts.append( f"Besonders gut geloest: Aufgabe(n) {', '.join(str(s.question_number) for s in strengths[:3])}." ) if weak_areas: feedback_parts.append( f"Uebungsbedarf bei: Aufgabe(n) {', '.join(str(w.question_number) for w in weak_areas[:3])}." ) feedback_parts.append( f"Ergebnis: {correct_count} von {total_count} Aufgaben korrekt ({percentage:.1f}%)." ) return " ".join(feedback_parts) async def process_ocr(correction_id: str, file_path: str): """Background Task fuer OCR-Verarbeitung.""" from datetime import datetime correction = corrections_store.get(correction_id) if not correction: return try: correction.status = CorrectionStatus.PROCESSING corrections_store[correction_id] = correction # OCR durchfuehren processor = FileProcessor() result = processor.process_file(file_path) if result.success and result.text: correction.extracted_text = result.text correction.status = CorrectionStatus.OCR_COMPLETE else: correction.status = CorrectionStatus.ERROR correction.updated_at = datetime.utcnow() corrections_store[correction_id] = correction except Exception as e: logger.error(f"OCR error for {correction_id}: {e}") correction.status = CorrectionStatus.ERROR correction.updated_at = datetime.utcnow() corrections_store[correction_id] = correction