Made it so the Speaking is sent to the backend and saved to Firebase
This commit is contained in:
@@ -1,14 +1,10 @@
|
||||
import {errorButtonStyle, infoButtonStyle} from "@/constants/buttonStyles";
|
||||
import {SpeakingExercise, WritingExercise} from "@/interfaces/exam";
|
||||
import {mdiArrowLeft, mdiArrowRight} from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import clsx from "clsx";
|
||||
import {SpeakingExercise} from "@/interfaces/exam";
|
||||
import {CommonProps} from ".";
|
||||
import {Fragment, useEffect, useState} from "react";
|
||||
import {toast} from "react-toastify";
|
||||
import {BsCheckCircleFill, BsMicFill, BsPauseCircle, BsPlayCircle, BsTrashFill} from "react-icons/bs";
|
||||
import dynamic from "next/dynamic";
|
||||
import Button from "../Low/Button";
|
||||
import axios from "axios";
|
||||
|
||||
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
|
||||
const ReactMediaRecorder = dynamic(() => import("react-media-recorder").then((mod) => mod.ReactMediaRecorder), {
|
||||
@@ -33,6 +29,30 @@ export default function Speaking({id, title, text, type, prompts, onNext, onBack
|
||||
};
|
||||
}, [isRecording]);
|
||||
|
||||
useEffect(() => {
|
||||
const uploadFile = () => {
|
||||
if (mediaBlob) {
|
||||
axios.get(mediaBlob, {responseType: "arraybuffer"}).then((response) => {
|
||||
const audioBlob = Buffer.from(response.data, "binary");
|
||||
const audioFile = new File([audioBlob], "audio.wav", {type: "audio/wav"});
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("audio", audioFile, "audio.wav");
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
"Content-Type": "audio/mp3",
|
||||
},
|
||||
};
|
||||
|
||||
axios.post("/api/evaluate/speaking", formData, config);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (mediaBlob) uploadFile();
|
||||
}, [mediaBlob]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full w-full gap-9">
|
||||
<div className="flex flex-col w-full gap-14 bg-mti-gray-smoke rounded-xl py-8 pb-12 px-16">
|
||||
|
||||
46
src/pages/api/evaluate/speaking.ts
Normal file
46
src/pages/api/evaluate/speaking.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
import type {NextApiRequest, NextApiResponse} from "next";
|
||||
import {getFirestore, doc, getDoc} from "firebase/firestore";
|
||||
import {withIronSessionApiRoute} from "iron-session/next";
|
||||
import {sessionOptions} from "@/lib/session";
|
||||
import axios from "axios";
|
||||
import formidable from "formidable";
|
||||
import PersistentFile from "formidable/PersistentFile";
|
||||
import {getStorage, ref, uploadBytes} from "firebase/storage";
|
||||
import fs from "fs";
|
||||
|
||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!req.session.user) {
|
||||
res.status(401).json({ok: false});
|
||||
return;
|
||||
}
|
||||
|
||||
const storage = getStorage();
|
||||
|
||||
const form = formidable({keepExtensions: true, uploadDir: "./"});
|
||||
form.parse(req, (err, fields, files) => {
|
||||
const audioFile = (files.audio as unknown as PersistentFile[])[0];
|
||||
const audioFileRef = ref(storage, `speaking_recordings/${(audioFile as any).newFilename}`);
|
||||
|
||||
const binary = fs.readFileSync((audioFile as any).filepath).buffer;
|
||||
uploadBytes(audioFileRef, binary).then(async (snapshot) => {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/writing_task2`, req.body as Body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
});
|
||||
|
||||
fs.rmSync((audioFile as any).filepath);
|
||||
});
|
||||
});
|
||||
|
||||
res.status(200).json({ok: true});
|
||||
}
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
@@ -18,19 +18,11 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {module} = req.query as {module: string};
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/writing_task2`, req.body as Body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (module === "writing") {
|
||||
const backendRequest = await axios.post(`${process.env.BACKEND_URL}/writing_task2`, req.body as Body, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.BACKEND_JWT}`,
|
||||
},
|
||||
});
|
||||
|
||||
res.status(backendRequest.status).json(backendRequest.data);
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(404).json({ok: false});
|
||||
return;
|
||||
res.status(backendRequest.status).json(backendRequest.data);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ export default function Page() {
|
||||
const writingExam = exams.find((x) => x.id === examId)!;
|
||||
const exercise = writingExam.exercises.find((x) => x.id === exerciseId)! as WritingExercise;
|
||||
|
||||
const response = await axios.post<WritingEvaluation>("/api/exam/writing/evaluate", {
|
||||
const response = await axios.post<WritingEvaluation>("/api/evaluate/writing", {
|
||||
question: `${exercise.prompt} ${exercise.attachment ? exercise.attachment.description : ""}`.replaceAll("\n", ""),
|
||||
answer: solution.solutions[0].solution.trim().replaceAll("\n", " "),
|
||||
});
|
||||
|
||||
@@ -126,7 +126,7 @@ export default function Page() {
|
||||
const writingExam = exams.find((x) => x.id === examId)!;
|
||||
const exercise = writingExam.exercises.find((x) => x.id === exerciseId)! as WritingExercise;
|
||||
|
||||
const response = await axios.post<WritingEvaluation>("/api/exam/writing/evaluate", {
|
||||
const response = await axios.post<WritingEvaluation>("/api/evaluate/writing", {
|
||||
question: `${exercise.prompt} ${exercise.attachment ? exercise.attachment.description : ""}`.replaceAll("\n", ""),
|
||||
answer: solution.solutions[0].solution.trim().replaceAll("\n", " "),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user