Updated the eval calls to the backend, passed the navigation logic of level to useExamNavigation hook
This commit is contained in:
@@ -1,165 +1,112 @@
|
||||
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 (
|
||||
userId: string,
|
||||
sessionId: string,
|
||||
exercise: WritingExercise,
|
||||
task: number,
|
||||
solution: UserSolution,
|
||||
id: string,
|
||||
): Promise<UserSolution | undefined> => {
|
||||
const response = await axios.post<Evaluation>("/api/evaluate/writing", {
|
||||
): Promise<void> => {
|
||||
await axios.post("/api/evaluate/writing", {
|
||||
question: `${exercise.prompt} ${exercise.attachment ? exercise.attachment.description : ""}`.replaceAll("\n", ""),
|
||||
answer: solution.solutions[0].solution.trim().replaceAll("\n", " "),
|
||||
task,
|
||||
id,
|
||||
userId,
|
||||
sessionId,
|
||||
exerciseId: exercise.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 (
|
||||
userId: string,
|
||||
sessionId: string,
|
||||
exercise: SpeakingExercise | InteractiveSpeakingExercise,
|
||||
solution: UserSolution,
|
||||
id: string,
|
||||
task: number,
|
||||
): Promise<UserSolution | undefined> => {
|
||||
): Promise<void> => {
|
||||
switch (exercise?.type) {
|
||||
case "speaking":
|
||||
return {...(await evaluateSpeakingExercise(exercise, exercise.id, solution, id, task)), id} as UserSolution;
|
||||
await evaluateSpeakingExercise(userId, sessionId, exercise, solution);
|
||||
case "interactiveSpeaking":
|
||||
return {...(await evaluateInteractiveSpeakingExercise(exercise.id, solution, id, task === 3 ? "final" : "initial")), id} as UserSolution;
|
||||
default:
|
||||
return undefined;
|
||||
await evaluateInteractiveSpeakingExercise(userId, sessionId, exercise.id, solution, task);
|
||||
}
|
||||
};
|
||||
|
||||
export const downloadBlob = async (url: string): Promise<Buffer> => {
|
||||
const blobResponse = await axios.get(url, {responseType: "arraybuffer"});
|
||||
const blobResponse = await axios.get(url, { responseType: "arraybuffer" });
|
||||
return Buffer.from(blobResponse.data, "binary");
|
||||
};
|
||||
|
||||
const evaluateSpeakingExercise = async (
|
||||
userId: string,
|
||||
sessionId: string,
|
||||
exercise: SpeakingExercise,
|
||||
exerciseId: string,
|
||||
solution: UserSolution,
|
||||
id: string,
|
||||
task: number,
|
||||
): Promise<UserSolution | undefined> => {
|
||||
): Promise<void> => {
|
||||
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"});
|
||||
const audioFile = new File([audioBlob], "audio.wav", { type: "audio/wav" });
|
||||
|
||||
if (url && !url.startsWith("blob")) await axios.post("/api/storage/delete", {path: url});
|
||||
if (url && !url.startsWith("blob")) {
|
||||
await axios.post("/api/storage/delete", { path: url });
|
||||
}
|
||||
|
||||
formData.append("audio", audioFile, "audio.wav");
|
||||
formData.append("userId", userId);
|
||||
formData.append("sessionId", sessionId);
|
||||
formData.append("exerciseId", exercise.id);
|
||||
|
||||
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());
|
||||
formData.append("question_1", evaluationQuestion);
|
||||
formData.append("audio_1", audioFile, "audio.wav");
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
"Content-Type": "audio/wav",
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
};
|
||||
|
||||
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;
|
||||
await axios.post(`/api/evaluate/speaking`, formData, config);
|
||||
};
|
||||
|
||||
const evaluateInteractiveSpeakingExercise = async (
|
||||
userId: string,
|
||||
sessionId: string,
|
||||
exerciseId: string,
|
||||
solution: UserSolution,
|
||||
id: string,
|
||||
variant?: "initial" | "final",
|
||||
): 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);
|
||||
|
||||
task: number,
|
||||
): Promise<void> => {
|
||||
const formData = new FormData();
|
||||
body.forEach(({question, answer}) => {
|
||||
const seed = Math.random().toString().replace("0.", "");
|
||||
formData.append("userId", userId);
|
||||
formData.append("sessionId", sessionId);
|
||||
formData.append("exerciseId", exerciseId);
|
||||
formData.append("task", task.toString());
|
||||
|
||||
const audioFile = new File([answer], `${seed}.wav`, {type: "audio/wav"});
|
||||
const promiseParts = solution.solutions.map(async (x: { prompt: string; blob: string }, index: number) => {
|
||||
const audioBlob = await downloadBlob(x.blob);
|
||||
if (!x.blob.startsWith("blob")) {
|
||||
await axios.post("/api/storage/delete", { path: x.blob });
|
||||
}
|
||||
const audioFile = new File([audioBlob], "audio.wav", { type: "audio/wav" });
|
||||
|
||||
formData.append(`question_${seed}`, question);
|
||||
formData.append(`answer_${seed}`, audioFile, `${seed}.wav`);
|
||||
formData.append(`question_${index + 1}`, x.prompt);
|
||||
formData.append(`audio_${index + 1}`, audioFile, "audio.wav");
|
||||
});
|
||||
formData.append("id", id);
|
||||
formData.append("variant", variant || "final");
|
||||
|
||||
await Promise.all(promiseParts);
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
"Content-Type": "audio/mp3",
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
};
|
||||
|
||||
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;
|
||||
await axios.post(`/api/evaluate/interactiveSpeaking`, formData, config);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user