File size: 2,768 Bytes
4dec878
 
013c0dc
669c0b8
013c0dc
 
 
f243d4f
 
 
6768aaa
013c0dc
 
 
f243d4f
 
 
 
 
013c0dc
4dec878
07bbfbd
 
 
 
 
4dec878
013c0dc
1dbd98a
f243d4f
07bbfbd
 
 
 
1dbd98a
f243d4f
 
1dbd98a
4dec878
07bbfbd
4dec878
 
 
 
1dbd98a
 
f243d4f
 
4dec878
f243d4f
 
 
013c0dc
 
07bbfbd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1dbd98a
f243d4f
013c0dc
4dec878
f243d4f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import typing

from django.contrib.postgres import fields
from django.db import models


class Quiz(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Question(models.Model):
    quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
    prompt = models.CharField(max_length=200)

    def __str__(self):
        return self.prompt

    def get_answer(self) -> typing.Union["Answer", None]:
        return (
            getattr(self, "multiplechoiceanswer", None)
            or getattr(self, "freetextanswer", None)
            or getattr(self, "llmgradedanswer", None)
        )


class Answer(models.Model):
    question = models.OneToOneField(Question, on_delete=models.CASCADE)
    correct_answer = models.CharField(max_length=200, default="")
    rubrics = models.TextField(
        blank=True, null=True, verbose_name="Grading Rubrics - For LLM-graded questions only. You can leave this empty."
    )

    class Meta:
        abstract = True

    def __str__(self) -> str:
        return self.correct_answer or self.rubrics or "No answer or rubrics provided"

    def is_correct(self, user_answer) -> bool:
        return user_answer == self.correct_answer


class FreeTextAnswer(Answer):
    case_sensitive = models.BooleanField(default=False)

    def is_correct(self, user_answer) -> bool:
        if not self.case_sensitive:
            return user_answer.lower() == self.correct_answer.lower()
        return user_answer == self.correct_answer


class LLMGradedAnswer(Answer):
    def grade(self, user_answer, rubrics) -> dict:
        import requests

        """
        Grades the user's answer by calling the grading API.
    
        Args:
            user_answer (str): The answer provided by the user.
            rubrics (str): The grading rubrics.
    
        Returns:
            bool: True if the user's answer is correct, False otherwise.
        """
        api_url = "http://localhost/api/grade"
        payload = {"user_answer": user_answer, "rubrics": rubrics}

        try:
            response = requests.post(api_url, json=payload)
            response.raise_for_status()  # Raise an error for bad status codes
            result = response.json()

            # Assuming the API returns a JSON object with a 'correct' field
            return result
        except requests.RequestException as e:
            # Handle any errors that occur during the request
            print(f"An error occurred: {e}")
            return {"result": "error", "message": str(e)}


class MultipleChoiceAnswer(Answer):
    choices = fields.ArrayField(models.CharField(max_length=200, blank=True))

    def __str__(self) -> str:
        return f"{self.correct_answer} from {self.choices}"