Skip to content

7. Auswertung einer Übung

Die Auswertung (evaluateUebung) ist der letzte Schritt im Übungsprozess. Die UebungenAPI kümmert sich um die komplexe Logik und gibt strukturierte Daten mit automatisch generiertem Feedback zurück.

7.1 Backend: Die evaluateUebung Methode

7.1.1 Minimale Implementierung

In /modules/Uebungen/UebungVokabeltrainer/app/Models/UebungVokabeltrainer.php:

php
public function evaluateUebung(?Request $request = null): mixed
{
    // Hole die Evaluation-Daten (automatisch von der API bereitgestellt)
    $EvaluationData = $this->getEvaluationData($request->input_data);
    
    // Belohne den Nutzer mit Gravitas
    $this->rewardUser($EvaluationData);
    
    // Speichere den Übungs-Datensatz
    $this->setAbsolved($EvaluationData);
    
    // Gib die Daten ans Frontend zurück
    return $EvaluationData;
}

7.1.2 Die reviewInput Methode

Diese Methode muss implementiert werden und vergleicht die Nutzereingaben:

php
public function reviewInput(array $input_data): Collection
{
    $InputDataCollection = collect($input_data);
    $ContentDataCollection = collect($this->content_data);
    
    return $InputDataCollection->map(function ($InputItem) use ($ContentDataCollection) {
        $ContentItem = $ContentDataCollection->firstWhere('value_given', $InputItem['value_given']);
        
        // Prüfe: 1 = richtig, 0 = falsch, null = nicht beantwortet
        $IsCorrect = ($InputItem['value_input'] === $ContentItem['value_expected']) ? 1 : 
                    (($InputItem['value_input'] === null || $InputItem['value_input'] === '') ? null : 0);
        
        return [
            "value_given" => $ContentItem['value_given'],
            "value_expected" => $ContentItem['value_expected'],
            "value_input" => $InputItem['value_input'],
            "correct" => $IsCorrect
        ];
    });
}

7.1.3 Die calculateCorrectRatio Methode (optional)

Falls Sie die Standard-Berechnung überschreiben möchten:

php
public function calculateCorrectRatio(Collection $reviewedInputData): float
{
    $CorrectAnswers = $reviewedInputData->where('correct', 1)->count();
    return round($CorrectAnswers / $reviewedInputData->count(), 2);
}

7.2 Was die UebungenAPI automatisch zurückgibt

Die getEvaluationData() Methode des Evaluable-Traits gibt ein komplexes Objekt zurück mit:

7.2.1 Die Hauptstruktur

json
{
  "scoreData": {
    "score_correct_ratio": 0.75,      // 75% richtig
    "score_time_ratio": 1.1,          // 10% schneller als Richtzeit
    "score_total_ratio": 0.83,        // Gesamtscore
    "score_total_points": 83,         // Punkte (score_total_ratio * 100)
    "score_gravitas": 25              // Erhaltene Gravitas
  },
  "feedbackData": {
    "generalFeedback": "Bene fecisti! Gut gemacht! Ad astra per aspera.",
    "correctnessFeedback": "Egregie! (75%) Sehr gut! Fast alles richtig.",
    "timeFeedback": "Bene et celeriter! Schneller als die Richtzeit!",
    "pointsFeedback": "Du hast insgesamt 83 Punkte erreicht.",
    "gravitasFeedback": "Für dieses Ergebnis erhältst du 25 Gravitas-Punkte."
  },
  "reviewData": {
    "ReviewedInputData": [
      {
        "value_given": "laudare",
        "value_expected": "loben",
        "value_input": "loben",
        "correct": 1
      },
      {
        "value_given": "amare",
        "value_expected": "lieben",
        "value_input": "mögen",
        "correct": 0
      }
    ],
    "ReviewStats": {
      "total_answers": 4,
      "total_answers_correct": 3,
      "total_answers_semi_correct": 0,
      "total_answers_incorrect": 1,
      "total_answers_unanswered": 0
    }
  }
}

7.2.2 Automatisches Feedback

Die UebungenAPIEvaluationData Klasse generiert automatisch Feedback basierend auf der Leistung:

  • 100%: "Optime! Hervorragende Arbeit!"
  • ≥70%: "Bene fecisti! Gut gemacht! Ad astra per aspera."
  • ≥50%: "Satis bene. Solide Leistung."
  • <50%: "Heu! Das war noch nicht ganz optimal. Repetitio est mater studiorum."

7.3 Frontend: Die Evaluate-Komponente

vue
<template>
  <div v-if="evaluateData">
    <h2>Übung abgeschlossen!</h2>
    
    <!-- Automatisches Feedback -->
    <div>
      <p>{{ evaluateData.feedbackData.generalFeedback }}</p>
      <p>{{ evaluateData.feedbackData.correctnessFeedback }}</p>
      <p v-if="evaluateData.feedbackData.timeFeedback">
        {{ evaluateData.feedbackData.timeFeedback }}
      </p>
      <p>{{ evaluateData.feedbackData.gravitasFeedback }}</p>
    </div>
    
    <!-- Review der Antworten -->
    <h3>Deine Antworten:</h3>
    <div v-for="item in evaluateData.reviewData.ReviewedInputData">
      <div>
        <strong>{{ item.value_given }}</strong>
        <span v-if="item.correct === 1">✓ Richtig</span>
        <span v-else-if="item.correct === 0">✗ Falsch</span>
        <span v-else>- Nicht beantwortet</span>
      </div>
      <div>
        Deine Antwort: {{ item.value_input || '(keine Antwort)' }}
      </div>
      <div v-if="item.correct === 0">
        Richtige Antwort: {{ item.value_expected }}
      </div>
    </div>
    
    <!-- Statistik -->
    <div>
      <p>Richtig: {{ evaluateData.reviewData.ReviewStats.total_answers_correct }}</p>
      <p>Falsch: {{ evaluateData.reviewData.ReviewStats.total_answers_incorrect }}</p>
      <p>Gesamt: {{ evaluateData.reviewData.ReviewStats.total_answers }}</p>
    </div>
    
    <button @click="backToLibrary">Zurück zur Übungsbibliothek</button>
  </div>
</template>

<script>
export default {
  props: ['evaluate_data'],
  computed: {
    evaluateData() {
      return this.evaluate_data;
    }
  },
  methods: {
    backToLibrary() {
      EventBus.$emit('close-absolve-uebung-modal');
    }
  }
}
</script>

7.4 Frontend: Verwendung der Hermeneus-Komponenten

Für eine professionellere Darstellung können Sie die vorgefertigten Komponenten nutzen:

vue
<template>
  <div>
    <!-- Feedback Komponente (zeigt alle Feedback-Texte) -->
    <uebung-feedback-component 
      :feedback-data="evaluateData.feedbackData" 
      :config="config"
    />
    
    <!-- Score Komponente (zeigt Punkte und Gravitas) -->
    <uebung-score-component 
      :score-data="evaluateData.scoreData" 
      :feedback-data="evaluateData.feedbackData" 
      :config="config"
    />
  </div>
</template>

<script>
import UebungFeedbackComponent from "@/uebungen-library/components/EvaluationComponents/UebungFeedbackComponent.vue"
import UebungScoreComponent from "@/uebungen-library/components/EvaluationComponents/UebungScoreComponent.vue"

export default {
  components: {
    'uebung-feedback-component': UebungFeedbackComponent,
    'uebung-score-component': UebungScoreComponent
  },
  props: ['evaluate_data'],
  computed: {
    evaluateData() {
      return this.evaluate_data;
    },
    config() {
      return this.evaluate_data?.config || {};
    }
  }
}
</script>

7.5 Wichtige Punkte

  1. Sie müssen nur reviewInput() implementieren - alles andere macht die API
  2. Die Traits berechnen automatisch:
    • Score basierend auf richtigen Antworten
    • Zeitbonus/Malus (wenn cfg_avg_time_seconds gesetzt)
    • Gravitas basierend auf cfg_max_gravitas_level
  3. Feedback wird automatisch generiert in lateinischen Phrasen
  4. ReviewStats werden automatisch berechnet aus den ReviewedInputData

7.6 Erweiterte Anpassung: Hook-Methoden

Der Evaluable Trait bietet drei Hook-Methoden, die Sie überschreiben können, um die Evaluation komplett zu individualisieren. Dies ermöglicht es Ihnen, die drei Evaluations-Objekte (reviewData, scoreData, feedbackData) unabhängig voneinander anzupassen.

7.6.1 Übersicht der Hook-Methoden

php
// 1. buildReviewData() - Erstellt ReviewData aus Eingabedaten
protected function buildReviewData(mixed $DataToEvaluate): UebungenAPIReviewData

// 2. buildScoreData() - Erstellt ScoreData basierend auf ReviewData
protected function buildScoreData(UebungenAPIReviewData $reviewData, float|false $seconds_elapsed = false): UebungenAPIScoreData

// 3. buildFeedbackData() - Erstellt FeedbackData basierend auf ScoreData und ReviewData
protected function buildFeedbackData(UebungenAPIScoreData $scoreData, UebungenAPIReviewData $reviewData): UebungenAPIFeedbackData

7.6.2 Beispiel 1: Nur ScoreData anpassen (Gewichtete Bewertung)

Wenn Sie eine eigene Score-Berechnung benötigen (z.B. schwierige Fragen zählen doppelt):

php
protected function buildScoreData(UebungenAPIReviewData $reviewData, float|false $seconds_elapsed = false): UebungenAPIScoreData
{
    // Eigene Logik: Schwierige Fragen zählen doppelt
    $scoreData = new UebungenAPIScoreData($reviewData);

    $weightedCorrect = 0;
    $totalWeight = 0;

    foreach ($reviewData->ReviewedInputData as $item) {
        $weight = $item['difficulty'] ?? 1; // Standard-Gewicht = 1
        $totalWeight += $weight;

        if ($item['correct'] === 1) {
            $weightedCorrect += $weight;
        }
    }

    // Eigene Berechnung
    $scoreData->setScoreCorrectRatio($weightedCorrect / $totalWeight);
    $scoreData->setScoreTimeRatio(1.0); // Keine Zeitwertung
    $scoreData->setScoreTotalRatio($scoreData->score_correct_ratio);
    $scoreData->setScoreTotalPoints((int)round($scoreData->score_total_ratio * 100));
    $scoreData->setScoreGravitas((int)round($scoreData->score_total_ratio * 50));

    return $scoreData;
}

7.6.3 Beispiel 2: Nur FeedbackData anpassen (Spezifisches Feedback)

Wenn Sie eigene Feedback-Texte mit spezifischen Hinweisen generieren möchten:

php
protected function buildFeedbackData(UebungenAPIScoreData $scoreData, UebungenAPIReviewData $reviewData): UebungenAPIFeedbackData
{
    // Standard-Feedback erstellen
    $feedbackData = new UebungenAPIFeedbackData($scoreData, true, true);
    $feedbackData->generateDefaultFeedback();

    // Zusätzliche spezifische Hinweise basierend auf falschen Antworten
    $wrongAnswers = $reviewData->ReviewedInputData->filter(fn($item) => $item['correct'] === 0);

    if ($wrongAnswers->count() > 0) {
        $hints = $this->generateGrammarHints($wrongAnswers);
        $feedbackData->setCorrectnessFeedback(
            $feedbackData->correctnessFeedback . "\n\nHinweise: " . $hints
        );
    }

    return $feedbackData;
}

private function generateGrammarHints(Collection $wrongAnswers): string
{
    // Analysiere falsche Antworten und gib Grammatik-Tipps
    return "Wiederhole die Deklinationen der a-Deklination.";
}

7.6.4 Beispiel 3: ReviewData komplett neu implementieren

Wenn Sie eine komplett eigene Review-Logik benötigen (z.B. mit KI-Bewertung):

php
protected function buildReviewData(mixed $DataToEvaluate): UebungenAPIReviewData
{
    // Komplett eigene Review-Logik mit KI-Bewertung
    $aiReviewResults = $this->evaluateWithAI($DataToEvaluate);

    $reviewData = new UebungenAPIReviewData(collect($aiReviewResults));
    $reviewData->setStatTotalAnswers(count($aiReviewResults));
    $reviewData->setStatTotalAnswersCorrect($this->countCorrect($aiReviewResults));
    $reviewData->setStatTotalAnswersIncorrect($this->countIncorrect($aiReviewResults));
    $reviewData->setStatTotalAnswersUnanswered($this->countUnanswered($aiReviewResults));

    return $reviewData;
}

private function evaluateWithAI(array $data): array
{
    // Ihre KI-Bewertungslogik hier
    // ...
}

7.6.5 Wichtige Punkte zu Hook-Methoden

  1. Bestehende Module funktionieren weiterhin: Sie müssen nur reviewInput() implementieren - die Hook-Methoden sind optional
  2. Selektives Überschreiben: Sie können nur die Hook-Methode überschreiben, die Sie anpassen möchten
  3. Unabhängige Objekte: Jede Hook-Methode kann unabhängig überschrieben werden
  4. Kontext verfügbar: buildScoreData() erhält ReviewData, buildFeedbackData() erhält beide Objekte als Kontext
  5. Rückgabetypen beachten: Die Hook-Methoden müssen die entsprechenden DataObjects zurückgeben

7.7 Die config.json Komponente

Vergessen Sie nicht, die Evaluate-Komponente zu registrieren:

json
"components": {
  "evaluate": {
    "path": "resources/vue/UebungVokabeltrainerEvaluateComponent.vue",
    "alias": "uebung-vokabeltrainer-evaluate-component",
    "title": "Vokabeltrainer: Auswertung"
  }
}