diff --git a/frontend/src/components/VerbalPronunciationExercise.tsx b/frontend/src/components/VerbalPronunciationExercise.tsx new file mode 100644 index 0000000..fe1699a --- /dev/null +++ b/frontend/src/components/VerbalPronunciationExercise.tsx @@ -0,0 +1,115 @@ +import { useLocation, useNavigate } from 'react-router-dom'; +import { Icon } from '@iconify/react'; +import CharacterBadge from '../components/CharacterBadge'; +import { useState, useEffect, useRef, useCallback } from 'react'; +import { speechToText, getAIMarking } from '../logic/sdk'; +import ClipLoader from "react-spinners/ClipLoader"; + +interface VerbalPronunciationProps { + question: string; + expected: string; + chapter: string; + language: string; + onQuestionSubmit: Function; + } + +export default function VerbalPronunciationExercise({question, expected, chapter, language, onQuestionSubmit}: VerbalPronunciationProps) { + const location = useLocation(); + const navigate = useNavigate(); + const [answered, setAnswered] = useState(false); + const [loading, setLoading] = useState(false); + const [correct, setCorrect] = useState(""); + const [reason, setReason] = useState(""); + + const handleSubmit = () => { + if (answered) { + setAnswered(false); + onQuestionSubmit(); + } + } + + type Message = { text: string, sender: string }; + const [isRecording, setIsRecording] = useState(false); + + let chunks = [] as any; + const mediaRecorder = useRef(null); + + useEffect(() => { + navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => { + mediaRecorder.current = new MediaRecorder(stream); + mediaRecorder.current.ondataavailable = (e) => { + chunks.push(e.data); + } + + mediaRecorder.current.onstop = async (e) => { + setIsRecording(false); + setLoading(true); + const blob = new Blob(chunks, { type: 'audio/wav' }); + chunks = []; + + const audioFile = new File([blob], "audio.wav", { type: 'audio/wav' }); + + const text = await speechToText(audioFile); + const aiMark = await getAIMarking(question, text.toLowerCase(), expected.toLowerCase(), chapter, language); + setAnswered(true); + setCorrect(aiMark.correct); + setReason(aiMark.reason); + } + }); + }, []); + + const handleRecord = useCallback(() => { + if (!isRecording) { + if (mediaRecorder.current) { + mediaRecorder.current.start(); + } + setIsRecording(true); + } else { + if (mediaRecorder.current) { + mediaRecorder.current.stop(); + } + } + }, [isRecording]); + + const ResponseSection = (correct: string | null, reason: string | null) => { + if (!answered) { + return ( +
+ + +
+ + ) + } else { + return ( +
+

{correct}

+

{reason}

+ +
+ ) + } + } + + return ( +
+
+

Say the following

+
+ {question} +
+ {ResponseSection(correct, reason)} +
+
+ ) +} \ No newline at end of file