Files
breakpilot-lehrer/backend-lehrer/correction_helpers.py
Benjamin Admin b4613e26f3 [split-required] Split 500-850 LOC files (batch 2)
backend-lehrer (10 files):
- game/database.py (785 → 5), correction_api.py (683 → 4)
- classroom_engine/antizipation.py (676 → 5)
- llm_gateway schools/edu_search already done in prior batch

klausur-service (12 files):
- orientation_crop_api.py (694 → 5), pdf_export.py (677 → 4)
- zeugnis_crawler.py (676 → 5), grid_editor_api.py (671 → 5)
- eh_templates.py (658 → 5), mail/api.py (651 → 5)
- qdrant_service.py (638 → 5), training_api.py (625 → 4)

website (6 pages):
- middleware (696 → 8), mail (733 → 6), consent (628 → 8)
- compliance/risks (622 → 5), export (502 → 5), brandbook (629 → 7)

studio-v2 (3 components):
- B2BMigrationWizard (848 → 3), CleanupPanel (765 → 2)
- dashboard-experimental (739 → 2)

admin-lehrer (4 files):
- uebersetzungen (769 → 4), manager (670 → 2)
- ChunkBrowserQA (675 → 6), dsfa/page (674 → 5)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 08:24:01 +02:00

135 lines
4.2 KiB
Python

"""
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