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 => { 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 => { 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 => { 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 => { 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 => { 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, }; };