chore: simplify grading for self paced course (#326)

* updated the grading flow for self paced course

* updated some logic and translations

* fix bug with newsfeed not opening for students and fix more bugs

* remove console

* add blog template route

* add doc page

---------

Co-authored-by: Rotimi Best <best@classroomio.com>
This commit is contained in:
Em_Dev
2024-05-25 05:50:14 +01:00
committed by GitHub
co-authored by Rotimi Best
parent 44087c458e
commit fc0b91a493
23 changed files with 144 additions and 176 deletions
@@ -4,6 +4,8 @@
import TextareaQuestion from '$lib/components/Question/TextareaQuestion/index.svelte';
import { QUESTION_TYPE } from '$lib/components/Question/constants';
import { getPropsForQuestion } from './functions';
import { course } from '$lib/components/Course/store';
import { COURSE_TYPE } from '$lib/utils/types';
export let questions = [];
export let questionnaireMetaData = {};
@@ -37,6 +39,7 @@
handleGrade={handleGrade(currentQuestion.id)}
{disableGrading}
disabled={true}
hideGrading={$course.type === COURSE_TYPE.SELF_PACED}
/>
{:else if QUESTION_TYPE.CHECKBOX === currentQuestion.question_type.id}
<CheckboxQuestion
@@ -57,6 +60,7 @@
handleGrade={handleGrade(currentQuestion.id)}
{disableGrading}
disabled={true}
hideGrading={$course.type === COURSE_TYPE.SELF_PACED}
/>
{:else if QUESTION_TYPE.TEXTAREA === currentQuestion.question_type.id}
<TextareaQuestion
@@ -77,6 +81,7 @@
handleGrade={handleGrade(currentQuestion.id)}
{disableGrading}
disabled={true}
hideGrading={$course.type === COURSE_TYPE.SELF_PACED}
/>
{/if}
{/each}
@@ -17,11 +17,7 @@
import { getPropsForQuestion, filterOutDeleted, wasCorrectAnswerSelected } from './functions';
import { formatAnswers, getGroupMemberId } from '$lib/components/Course/function';
import { submitExercise } from '$lib/utils/services/courses';
import {
fetchSubmission,
updateQuestionAnswer,
updateSubmission
} from '$lib/utils/services/submissions';
import { fetchSubmission } from '$lib/utils/services/submissions';
import { profile } from '$lib/utils/store/user';
import { currentOrg } from '$lib/utils/store/org';
import {
@@ -30,9 +26,8 @@
} from '$lib/utils/services/notification/notification';
import { lesson } from '../store/lessons';
import { browser } from '$app/environment';
import { useCompletion } from 'ai/svelte';
import { COURSE_TYPE } from '$lib/utils/types';
import GradingLoader from './GradingLoader.svelte';
import { t } from '$lib/utils/functions/translations';
export let preview: boolean = false;
export let exerciseId = '';
@@ -44,10 +39,7 @@
let hasSubmission = false;
let isLoadingAutoSavedData = false;
let alreadyCheckedAutoSavedData = false;
let gradedComment = true;
let isLoading = false;
let submissionResponse;
let submissionId;
function handleStart() {
$questionnaireMetaData.currentQuestionIndex += 1;
@@ -88,89 +80,7 @@
});
};
const { input, handleSubmit, completion } = useCompletion({
api: '/api/completion/gradingprompt',
onFinish: async () => {
try {
const responseData = $completion.replace('```json', '').replace('```', '');
let aiResponses = [];
try {
// Parse the modified response data as JSON
aiResponses = JSON.parse(responseData);
} catch (error) {
console.error('Error parsing AI response', error);
}
$questionnaire.questions.forEach((question) => {
const { id, points, question_type_id } = question;
let questionAnswer = submissionResponse?.res?.data.find(
(answer) => answer.question_id === id
);
console.log('this is the question answer', questionAnswer);
if (question_type_id !== QUESTION_TYPE.TEXTAREA) {
const answer = $questionnaireMetaData.answers[question.name];
let score = points / answer.length;
$questionnaireMetaData.grades = {
...$questionnaireMetaData.grades,
[id]: score
};
updateQuestionAnswer({ point: score }, { id: questionAnswer?.id });
} else if (aiResponses.length) {
const graded = aiResponses.find((res) => res.id === id);
$questionnaireMetaData.grades = {
...$questionnaireMetaData.grades,
[id]: graded.score
};
updateQuestionAnswer({ point: graded.score }, { id: questionAnswer?.id });
}
});
$questionnaireMetaData.finalTotalGrade = Object.values(
$questionnaireMetaData.grades
).reduce((acc, answer): number => {
return acc + answer;
}, 0);
updateSubmission({
id: submissionId,
status_id: STATUS.GRADED,
total: $questionnaireMetaData.finalTotalGrade
});
$questionnaireMetaData.status = STATUS.GRADED;
console.log('grade', $questionnaireMetaData.finalTotalGrade);
} catch (error) {
console.error('Error', error);
} finally {
isLoading = false;
}
}
});
function automaticGrading(answers, questions) {
const paragraphAiInput = questions
.filter((q) => q.question_type_id === QUESTION_TYPE.TEXTAREA)
.map((q) => {
const answer = answers?.answers[q.name]; // { open_answer: '' }
return {
id: q.id,
question: q.title,
answer: answer,
point: q.points
};
});
$input = JSON.stringify(paragraphAiInput);
handleSubmit({ preventDefault: () => {} });
}
async function onSubmit(id, value) {
if ($course.type === COURSE_TYPE.SELF_PACED) {
isLoading = true;
}
const { answers } = $questionnaireMetaData;
const { questions } = $questionnaire;
const prevAnswer = answers[id] || [];
@@ -220,11 +130,6 @@
);
if (response) {
submissionResponse = response;
submissionId = submissionResponse.submission[0]?.id;
}
if ($course.type === COURSE_TYPE.SELF_PACED) {
automaticGrading($questionnaireMetaData, $questionnaire.questions);
}
notifyEducator();
@@ -316,10 +221,6 @@
alreadyCheckedAutoSavedData = true;
}
const toggleComments = () => {
gradedComment = !gradedComment;
};
$: browser && !alreadyCheckedAutoSavedData && getAutoSavedData();
// Reactive code
@@ -406,42 +307,46 @@
</div>
</RoleBasedSecurity>
{:else if $questionnaireMetaData.isFinished}
{#if isLoading}
<GradingLoader />
{:else if !isLoading && !isLoadingAutoSavedData}
{#if !isLoadingAutoSavedData}
<div class="flex items-center justify-between">
<div class="flex flex-col lg:flex-row items-start lg:items-center lg:space-x-4 w-full">
<h2 class="text-xl font-normal">{$questionnaire.title}</h2>
{#if STATUS.GRADED === $questionnaireMetaData.status}
<span
class="status-text bg-green-700 text-white py-1 px-2 text-center"
title="Status: Pending Review"
title={$t('course.navItem.lessons.exercises.all_exercises.view_mode.status_graded')}
>
Graded
{$t('course.navItem.lessons.exercises.all_exercises.view_mode.graded')}
</span>
{:else if $course.type === COURSE_TYPE.SELF_PACED}
<span
class="status-text bg-green-700 text-white py-1 px-2 text-center"
title={$t('course.navItem.lessons.exercises.all_exercises.view_mode.status_submitted')}
>
{$t('course.navItem.lessons.exercises.all_exercises.view_mode.submitted')}
</span>
{:else}
<span
class="status-text bg-yellow-600 text-white py-1 px-2 text-center"
title="Status: Pending Review"
title={$t('course.navItem.lessons.exercises.all_exercises.view_mode.status_pending')}
>
Pending
{$t('course.navItem.lessons.exercises.all_exercises.view_mode.pending')}
</span>
{/if}
</div>
{#if STATUS.GRADED === $questionnaireMetaData.status}
{#if STATUS.GRADED === $questionnaireMetaData.status && $course.type !== COURSE_TYPE.SELF_PACED}
<span
class="p-6 border-2 border-gray-300 bg-[#F5F8FE] rounded-full h-10 w-10 flex items-center justify-center text-[#2751DA] text-sm font-semibold"
title="Status: Pending Review"
title={$t('course.navItem.lessons.exercises.all_exercises.view_mode.status_graded')}
>
{$questionnaireMetaData.finalTotalGrade}/{$questionnaireMetaData.totalPossibleGrade}
</span>
{/if}
</div>
{#if $questionnaireMetaData.status === STATUS.GRADED && $questionnaireMetaData.comment}
<div
class="flex items-center justify-between bg-primary-700 p-4 text-white font-semibold rounded-sm mt-3"
>
{#if $questionnaireMetaData.status === STATUS.GRADED && $questionnaireMetaData.comment && $course.type !== COURSE_TYPE.SELF_PACED}
<div class="flex items-center justify-between bg-primary-700 p-4 text-white rounded-sm mt-3">
<span> {$questionnaireMetaData.comment}</span>
</div>
{/if}