Files
encoach_frontend/src/utils/evaluation.ts
2024-05-20 21:28:45 +01:00

161 lines
4.3 KiB
TypeScript

import {
Evaluation,
Exam,
InteractiveSpeakingExercise,
SpeakingExam,
SpeakingExercise,
UserSolution,
WritingExam,
WritingExercise,
} from "@/interfaces/exam";
import axios from "axios";
import {speakingReverseMarking, writingReverseMarking} from "./score";
export const evaluateWritingAnswer = async (
exercise: WritingExercise,
task: number,
solution: UserSolution,
id: string,
): Promise<UserSolution | undefined> => {
const response = await axios.post<Evaluation>("/api/evaluate/writing", {
question: `${exercise.prompt} ${exercise.attachment ? exercise.attachment.description : ""}`.replaceAll("\n", ""),
answer: solution.solutions[0].solution.trim().replaceAll("\n", " "),
task,
id,
});
if (response.status === 200) {
return {
...solution,
id,
score: {
correct: response.data ? writingReverseMarking[response.data.overall] : 0,
missing: 0,
total: 100,
},
solutions: [{id: exercise.id, solution: solution.solutions[0].solution, evaluation: response.data}],
isDisabled: true,
};
}
return undefined;
};
export const evaluateSpeakingAnswer = async (
exercise: SpeakingExercise | InteractiveSpeakingExercise,
solution: UserSolution,
id: string,
task: number,
): Promise<UserSolution | undefined> => {
switch (exercise?.type) {
case "speaking":
return {...(await evaluateSpeakingExercise(exercise, exercise.id, solution, id, task)), id} as UserSolution;
case "interactiveSpeaking":
return {...(await evaluateInteractiveSpeakingExercise(exercise.id, solution, id)), id} as UserSolution;
default:
return undefined;
}
};
export const downloadBlob = async (url: string): Promise<Buffer> => {
const blobResponse = await axios.get(url, {responseType: "arraybuffer"});
return Buffer.from(blobResponse.data, "binary");
};
const evaluateSpeakingExercise = async (
exercise: SpeakingExercise,
exerciseId: string,
solution: UserSolution,
id: string,
task: number,
): Promise<UserSolution | undefined> => {
const formData = new FormData();
const url = solution.solutions[0].solution.trim() as string;
const audioBlob = await downloadBlob(url);
const audioFile = new File([audioBlob], "audio.wav", {type: "audio/wav"});
if (url && !url.startsWith("blob")) await axios.post("/api/storage/delete", {path: url});
formData.append("audio", audioFile, "audio.wav");
const evaluationQuestion =
`${exercise.text.replaceAll("\n", "")}` + (exercise.prompts.length > 0 ? `You should talk about: ${exercise.prompts.join(", ")}` : "");
formData.append("question", evaluationQuestion);
formData.append("id", id);
formData.append("task", task.toString());
const config = {
headers: {
"Content-Type": "audio/wav",
},
};
const response = await axios.post("/api/evaluate/speaking", formData, config);
if (response.status === 200) {
return {
...solution,
id,
score: {
correct: 0,
missing: 0,
total: 100,
},
solutions: [{id: exerciseId, solution: response.data ? response.data.fullPath : null, evaluation: response.data}],
isDisabled: true,
};
}
return undefined;
};
const evaluateInteractiveSpeakingExercise = async (exerciseId: string, solution: UserSolution, id: string): Promise<UserSolution | undefined> => {
const promiseParts = solution.solutions.map(async (x: {prompt: string; blob: string}) => {
const blob = await downloadBlob(x.blob);
if (!x.blob.startsWith("blob")) await axios.post("/api/storage/delete", {path: x.blob});
return {
question: x.prompt,
answer: blob,
};
});
const body = await Promise.all(promiseParts);
const formData = new FormData();
body.forEach(({question, answer}) => {
const seed = Math.random().toString().replace("0.", "");
const audioFile = new File([answer], `${seed}.wav`, {type: "audio/wav"});
formData.append(`question_${seed}`, question);
formData.append(`answer_${seed}`, audioFile, `${seed}.wav`);
});
formData.append("id", id);
const config = {
headers: {
"Content-Type": "audio/mp3",
},
};
const response = await axios.post("/api/evaluate/interactiveSpeaking", formData, config);
if (response.status === 200) {
return {
...solution,
id,
score: {
correct: 0,
missing: 0,
total: 100,
},
module: "speaking",
solutions: [{id: exerciseId, solution: response.data ? response.data.answer : null, evaluation: response.data}],
isDisabled: true,
};
}
return undefined;
};