150 lines
3.8 KiB
TypeScript
150 lines
3.8 KiB
TypeScript
import {
|
|
InteractiveSpeakingExercise,
|
|
SpeakingExercise,
|
|
UserSolution,
|
|
WritingExercise,
|
|
} from "@/interfaces/exam";
|
|
import axios from "axios";
|
|
import { v4 } from "uuid";
|
|
|
|
export const evaluateWritingAnswer = async (
|
|
userId: string,
|
|
sessionId: string,
|
|
exercise: WritingExercise,
|
|
task: number,
|
|
solution: UserSolution,
|
|
attachment?: string,
|
|
): Promise<UserSolution> => {
|
|
await axios.post("/api/evaluate/writing", {
|
|
question: `${exercise.prompt}`.replaceAll("\n", ""),
|
|
answer: solution.solutions[0].solution.trim().replaceAll("\n", " "),
|
|
task,
|
|
userId,
|
|
sessionId,
|
|
exerciseId: exercise.id,
|
|
attachment,
|
|
});
|
|
|
|
return {
|
|
...solution,
|
|
id: v4(),
|
|
score: {
|
|
correct: 0,
|
|
missing: 0,
|
|
total: 100,
|
|
},
|
|
solutions: [{id: exercise.id, solution: solution.solutions[0].solution}],
|
|
isDisabled: true,
|
|
};
|
|
};
|
|
|
|
export const evaluateSpeakingAnswer = async (
|
|
userId: string,
|
|
sessionId: string,
|
|
exercise: SpeakingExercise | InteractiveSpeakingExercise,
|
|
solution: UserSolution,
|
|
task: number,
|
|
): Promise<UserSolution> => {
|
|
switch (exercise?.type) {
|
|
case "speaking":
|
|
return await evaluateSpeakingExercise(userId, sessionId, exercise, solution);
|
|
case "interactiveSpeaking":
|
|
return await evaluateInteractiveSpeakingExercise(userId, sessionId, exercise.id, solution, task);
|
|
}
|
|
};
|
|
|
|
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 (
|
|
userId: string,
|
|
sessionId: string,
|
|
exercise: SpeakingExercise,
|
|
solution: UserSolution,
|
|
): Promise<UserSolution> => {
|
|
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("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("audio", audioFile, "audio.wav");
|
|
|
|
const config = {
|
|
headers: {
|
|
"Content-Type": "multipart/form-data",
|
|
},
|
|
};
|
|
|
|
await axios.post(`/api/evaluate/speaking`, formData, config);
|
|
return {
|
|
...solution,
|
|
id: v4(),
|
|
score: {
|
|
correct: 0,
|
|
missing: 0,
|
|
total: 100,
|
|
},
|
|
solutions: [{id: exercise.id, solution: null}],
|
|
isDisabled: true,
|
|
};
|
|
};
|
|
|
|
const evaluateInteractiveSpeakingExercise = async (
|
|
userId: string,
|
|
sessionId: string,
|
|
exerciseId: string,
|
|
solution: UserSolution,
|
|
task: number,
|
|
): Promise<UserSolution> => {
|
|
const formData = new FormData();
|
|
formData.append("userId", userId);
|
|
formData.append("sessionId", sessionId);
|
|
formData.append("exerciseId", exerciseId);
|
|
formData.append("task", task.toString());
|
|
|
|
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_${index + 1}`, x.prompt);
|
|
formData.append(`audio_${index + 1}`, audioFile, "audio.wav");
|
|
});
|
|
|
|
await Promise.all(promiseParts);
|
|
|
|
const config = {
|
|
headers: {
|
|
"Content-Type": "multipart/form-data",
|
|
},
|
|
};
|
|
|
|
await axios.post(`/api/evaluate/interactiveSpeaking`, formData, config);
|
|
return {
|
|
...solution,
|
|
id: v4(),
|
|
score: {
|
|
correct: 0,
|
|
missing: 0,
|
|
total: 100,
|
|
},
|
|
solutions: [{id: exerciseId, solution: null}],
|
|
isDisabled: true,
|
|
};
|
|
};
|