feat: grade exercise with AI (#296)
* working on the UI of the grading * working on the grading function of the radio and checkboxes * ai grading fully implemented with dummy functions for generating scores * working on the openai response * working on the openai response * finished with the ai_grading * finished with the ai_grading * creating new migration file * working on reviews * updated the translations * improvements --------- Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import HtmlRender from '$lib/components/HTMLRender/HTMLRender.svelte';
|
||||
import Grade from '$lib/components/Question/Grade.svelte';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import ReasonBox from '../ReasonBox.svelte';
|
||||
|
||||
export let title = '';
|
||||
export let index = 1;
|
||||
@@ -22,6 +23,12 @@
|
||||
export let grade: number | undefined;
|
||||
export let gradeMax = 0;
|
||||
export let disableGrading = false;
|
||||
export let isGradeWithAI = false;
|
||||
export let reason;
|
||||
export let isLoading = false;
|
||||
export let hideGrading = false;
|
||||
|
||||
let gradeWithAI = false;
|
||||
|
||||
function getVal(form, name) {
|
||||
let values = [];
|
||||
@@ -59,6 +66,17 @@
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function acceptGrade() {
|
||||
gradeWithAI = false;
|
||||
}
|
||||
function rejectGrade() {
|
||||
gradeWithAI = false;
|
||||
grade = 0;
|
||||
}
|
||||
$: {
|
||||
gradeWithAI = isGradeWithAI;
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault={handleFormSubmit}>
|
||||
@@ -73,7 +91,9 @@
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
</HtmlRender>
|
||||
<Grade {gradeMax} bind:grade {disableGrading} />
|
||||
{#if !hideGrading}
|
||||
<Grade {gradeMax} bind:grade {disableGrading} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if code}
|
||||
@@ -99,6 +119,10 @@
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{#if gradeWithAI}
|
||||
<ReasonBox {reason} {isLoading} {acceptGrade} {rejectGrade} />
|
||||
{/if}
|
||||
|
||||
{#if !isPreview}
|
||||
<div class="mt-3 flex items-center justify-between w-full">
|
||||
<PrimaryButton
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
<script lang="ts">
|
||||
import TextField from '$lib/components/Form/TextField.svelte';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { snackbar } from '../Snackbar/store';
|
||||
|
||||
export let gradeMax = 0;
|
||||
export let disableGrading = false;
|
||||
export let grade: number | undefined;
|
||||
export let grade: number | undefined = 0;
|
||||
|
||||
$: if (grade && grade > gradeMax) {
|
||||
snackbar.error('grade cant be more than max value');
|
||||
grade = gradeMax;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if typeof grade !== 'undefined'}
|
||||
<div class="flex items-center">
|
||||
<TextField
|
||||
placeholder={$t('course.navItem.lessons.exercises.new_exercise_modal.points')}
|
||||
bind:value={grade}
|
||||
type="number"
|
||||
className="w-12"
|
||||
isDisabled={disableGrading}
|
||||
/>
|
||||
<p class="dark:text-white ml-2 text-lg flex items-center">
|
||||
<span class="mr-1">/</span> <span>{gradeMax}</span>
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex items-center font-semibold">
|
||||
<TextField
|
||||
placeholder={$t('course.navItem.lessons.exercises.new_exercise_modal.points')}
|
||||
bind:value={grade}
|
||||
max={gradeMax}
|
||||
type="number"
|
||||
className="w-12"
|
||||
inputClassName="h-10"
|
||||
isDisabled={disableGrading}
|
||||
/>
|
||||
|
||||
<p class="dark:text-white ml-2 text-base flex items-center font-semibold">
|
||||
<span class="mr-1">/</span> <span>{gradeMax}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import HtmlRender from '$lib/components/HTMLRender/HTMLRender.svelte';
|
||||
import Grade from '$lib/components/Question/Grade.svelte';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import ReasonBox from '../ReasonBox.svelte';
|
||||
|
||||
export let title = '';
|
||||
export let index = 1;
|
||||
@@ -24,6 +25,12 @@
|
||||
export let disableGrading = false;
|
||||
export let labelClassName = '';
|
||||
export let disableOptContainerMargin = false;
|
||||
export let isGradeWithAI = false;
|
||||
export let reason;
|
||||
export let isLoading = false;
|
||||
export let hideGrading = false;
|
||||
|
||||
let gradeWithAI = false;
|
||||
|
||||
function getRadioVal(form, name) {
|
||||
let val;
|
||||
@@ -61,6 +68,18 @@
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function acceptGrade() {
|
||||
gradeWithAI = false;
|
||||
}
|
||||
function rejectGrade() {
|
||||
gradeWithAI = false;
|
||||
grade = 0;
|
||||
}
|
||||
|
||||
$: {
|
||||
gradeWithAI = isGradeWithAI;
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault={handleFormSubmit}>
|
||||
@@ -73,14 +92,16 @@
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
</HtmlRender>
|
||||
<Grade {gradeMax} bind:grade {disableGrading} />
|
||||
{#if !hideGrading}
|
||||
<Grade {gradeMax} bind:grade {disableGrading} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if code}
|
||||
<CodeSnippet {code} />
|
||||
{/if}
|
||||
|
||||
<div class={!disableOptContainerMargin && 'ml-4'}>
|
||||
<div class={disableOptContainerMargin ? '' : 'ml-4'}>
|
||||
{#each options as option}
|
||||
<button
|
||||
class="cursor-pointer text-left my-2 border-2 border-gray-300 rounded-md hover:bg-gray-200 dark:hover:bg-neutral-800 w-full {getValidationClassName(
|
||||
@@ -99,6 +120,9 @@
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{#if gradeWithAI}
|
||||
<ReasonBox {reason} {isLoading} {acceptGrade} {rejectGrade} />
|
||||
{/if}
|
||||
|
||||
{#if !isPreview}
|
||||
<div class="mt-3 flex items-center justify-between w-full">
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<script>
|
||||
import { VARIANTS } from '../PrimaryButton/constants';
|
||||
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { SkeletonPlaceholder, SkeletonText } from 'carbon-components-svelte';
|
||||
|
||||
export let reason = '';
|
||||
export let isLoading = false;
|
||||
export let rejectGrade = () => {};
|
||||
export let acceptGrade = () => {};
|
||||
</script>
|
||||
|
||||
<div class="border rounded-md">
|
||||
{#if isLoading}
|
||||
<div class="flex w-full px-2 py-4">
|
||||
<div class="w-full flex flex-row items-start space-x-4">
|
||||
<img src="/ai.svg" alt="alt" class="animate-pulse" />
|
||||
<div class="w-full">
|
||||
<SkeletonText width="100%" paragraph lines={3} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<SkeletonPlaceholder style="height: 2rem; width: 5rem;" />
|
||||
<SkeletonPlaceholder style="height: 2rem; width: 5rem;" />
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex items-start justify-between px-2 py-4">
|
||||
<div class="flex items-center space-x-4">
|
||||
<img src="/ai.svg" alt="alt" />
|
||||
<p class="font-normal text-sm">
|
||||
{reason}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<PrimaryButton
|
||||
variant={VARIANTS.CONTAINED_SUCCESS}
|
||||
label={$t('course.navItem.submissions.grading_modal.accept_grade')}
|
||||
className="rounded-none py-1 px-2"
|
||||
disablePadding={true}
|
||||
onClick={acceptGrade}
|
||||
/>
|
||||
<PrimaryButton
|
||||
variant={VARIANTS.CONTAINED_DANGER}
|
||||
label={$t('course.navItem.submissions.grading_modal.reject_grade')}
|
||||
className="rounded-none py-1 px-2"
|
||||
disablePadding={true}
|
||||
onClick={rejectGrade}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -6,6 +6,7 @@
|
||||
import HtmlRender from '$lib/components/HTMLRender/HTMLRender.svelte';
|
||||
import Grade from '$lib/components/Question/Grade.svelte';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import ReasonBox from '../ReasonBox.svelte';
|
||||
|
||||
export let title = '';
|
||||
export let index = 1;
|
||||
@@ -21,6 +22,12 @@
|
||||
export let grade: number | undefined;
|
||||
export let gradeMax = 0;
|
||||
export let disableGrading = false;
|
||||
export let isGradeWithAI = false;
|
||||
export let reason;
|
||||
export let isLoading = false;
|
||||
export let hideGrading = false;
|
||||
|
||||
let gradeWithAI = false;
|
||||
|
||||
function handleFormSubmit(event) {
|
||||
if (isPreview) return;
|
||||
@@ -33,6 +40,18 @@
|
||||
event.preventDefault();
|
||||
onPrevious();
|
||||
}
|
||||
|
||||
function acceptGrade() {
|
||||
gradeWithAI = false;
|
||||
}
|
||||
function rejectGrade() {
|
||||
gradeWithAI = false;
|
||||
grade = 0;
|
||||
}
|
||||
|
||||
$: {
|
||||
gradeWithAI = isGradeWithAI;
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault={handleFormSubmit}>
|
||||
@@ -45,7 +64,9 @@
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
</HtmlRender>
|
||||
<Grade {gradeMax} bind:grade {disableGrading} />
|
||||
{#if !hideGrading}
|
||||
<Grade {gradeMax} bind:grade {disableGrading} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if code}
|
||||
@@ -54,9 +75,12 @@
|
||||
|
||||
<div class="ml-4">
|
||||
{#if disabled}
|
||||
<div class="bg-gray-200 dark:bg-gray-500 p-5 rounded-md mb-3">
|
||||
<div class="bg-gray-200 dark:bg-gray-500 py-3 px-5 rounded-md mb-3">
|
||||
{defaultValue}
|
||||
</div>
|
||||
{#if gradeWithAI}
|
||||
<ReasonBox {reason} {isLoading} {acceptGrade} {rejectGrade} />
|
||||
{/if}
|
||||
{:else}
|
||||
<TextArea
|
||||
bind:value={defaultValue}
|
||||
|
||||
Reference in New Issue
Block a user