Refactor feedback image handling and enhance sample answers display in exam scores user template

This commit is contained in:
Ross
2025-09-08 10:16:53 +01:00
parent 214b531757
commit 5270d5cd36
3 changed files with 108 additions and 26 deletions
+2 -1
View File
@@ -485,10 +485,11 @@ class Rapid(QuestionBase):
images = [] images = []
annotations_list = [] annotations_list = []
feedback_images = [] feedback_images = []
i: RapidImage
for i in self.images.all(): for i in self.images.all():
# TODO: add anotations # TODO: add anotations
if i.feedback_image == True: if i.feedback_image:
if feedback: if feedback:
annotations_list.append(i.image_annotations) annotations_list.append(i.image_annotations)
if based: if based:
+71
View File
@@ -34,6 +34,17 @@ from django.utils.html import format_html
from helpers.images import combine_dicom_images_side_by_side from helpers.images import combine_dicom_images_side_by_side
from django.core.files import File from django.core.files import File
import tempfile import tempfile
from typing import List, TypedDict, Required, NotRequired
class QuestionData(TypedDict):
images: Required[list[str]]
annotations: Required[List[str]]
type: Required[str]
history: NotRequired[str]
answers: NotRequired[List[str]]
feedback: NotRequired[str]
feedback_images: NotRequired[List[str]]
def image_directory_path(instance, filename): def image_directory_path(instance, filename):
@@ -215,6 +226,66 @@ class Question(QuestionBase):
examinations = self.examination.all().values_list("examination", flat=True) examinations = self.examination.all().values_list("examination", flat=True)
return ", ".join(examinations) return ", ".join(examinations)
def get_sample_answers(self):
return self.sample_answers.all().order_by("-score")
def get_question_json(
self,
based: bool = True,
feedback: bool = False,
answers: bool = True,
history: bool = False,
annotations: bool = False,
) -> QuestionData:
"""Returns a json representation of the question"""
# Loop through rapidimage associations
images = []
annotations_list = []
feedback_images = []
i: QuestionImage
for i in self.images.all():
# TODO: add anotations
if i.feedback_image:
if feedback:
#annotations_list.append(i.image_annotations)
if based:
feedback_images.append(image_as_base64(i.image))
else:
feedback_images.append(
"{}/{}".format(settings.REMOTE_URL, i.image.url)
)
# feedback_images.append("{}/{}".format(settings.REMOTE_URL, i.image.url))
else:
#annotations_list.append(i.image_annotations)
if based:
images.append(image_as_base64(i.image))
else:
images.append("{}/{}".format(settings.REMOTE_URL, i.image.url))
json = {
"images": images,
# "feedback_image": [],
"type": "shorts",
}
#if annotations:
# json["annotations"] = annotations_list
if history:
json["history"] = self.history
if answers:
sample_answers = list(self.get_sample_answers().values_list("answer", "score"))
json["answers"] = sample_answers
if feedback:
json["feedback_images"] = feedback_images
json["feedback"] = self.feedback
return json
class QuestionImage(models.Model): class QuestionImage(models.Model):
question = models.ForeignKey( question = models.ForeignKey(
+34 -24
View File
@@ -10,7 +10,9 @@
<div class="feedback"></div> <div class="feedback"></div>
<div> <div>
<details> <details>
<summary>Answers:</summary><span class="answers"></span> <summary>Sample Answers:</summary>
<span class="answers">
</span>
</details> </details>
</div> </div>
</div> </div>
@@ -59,30 +61,39 @@
}) })
// $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly // $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
.done(function (data) { .done(function (data) {
console.log(data); console.log(data);
let images = data.images let images = data.images
if ("feedback_images" in data) { if ("feedback_images" in data) {
images.push(...data.feedback_images) images.push(...data.feedback_images)
} }
let event = new CustomEvent('loadDicomViewerUrls', { let event = new CustomEvent('loadDicomViewerUrls', {
"detail": { "images": images, "annotations": data.annotations } "detail": { "images": images, "annotations": data.annotations }
}); });
window.dispatchEvent(event); window.dispatchEvent(event);
$(".question-display-block .answers").empty().append(data.answers.toString()); console.log(data)
n = parseInt(question_number) + 1 if (data.answers && data.answers.length > 0) {
$(".question-display-block .question-number").empty().append(n); // Format: [[answer, score], ...]
$(".question-display-block .feedback").empty().append(`Feedback: ${data.feedback}<br />`); let formattedAnswers = data.answers.map(
ans => `<div class="sample-answer-block"><span class="sample-answer-text">${ans[0]}</span> <span class="sample-answer-score badge badge-info">Score: ${ans[1]}</span></div>`
).join('');
$(".question-display-block .answers").empty().append(`${formattedAnswers}`);
} else {
$(".question-display-block .answers").empty().append("No sample answers available");
}
n = parseInt(question_number) + 1
$(".question-display-block .question-number").empty().append(n);
$(".question-display-block .feedback").empty().append(`Feedback: ${data.feedback}<br />`);
// show some message according to the response. // show some message according to the response.
// For eg. A message box showing that the status has been changed // For eg. A message box showing that the status has been changed
$(".inner-display-block").show(); $(".inner-display-block").show();
}) })
.always(function () { .always(function () {
console.log('[Done]'); console.log('[Done]');
}) })
}) })
$(".view-question-link").first().click(); $(".view-question-link").first().click();
@@ -93,11 +104,10 @@
{% block css %} {% block css %}
<style> <style>
.answer-score { .answer-score {
float: right; float: right;
} }
</style> </style>
{% endblock css %} {% endblock css %}