diff --git a/src/components/Mechanism/WordsOrImage.jsx b/src/components/Mechanism/WordsOrImage.jsx index f8f4018f..c6ea0bc1 100644 --- a/src/components/Mechanism/WordsOrImage.jsx +++ b/src/components/Mechanism/WordsOrImage.jsx @@ -46,7 +46,7 @@ const WordsOrImage = ({ loading, setOpenMessageDialog, isNextButtonCalled, - setIsNextButtonCalled + setIsNextButtonCalled, }) => { const audioRef = createRef(null); const [duration, setDuration] = useState(0); @@ -90,7 +90,7 @@ const WordsOrImage = ({ livesData, gameOverData, loading, - setIsNextButtonCalled + setIsNextButtonCalled, }} > + display={"flex"} + mb={4} + sx={{ + width: "100%", + justifyContent: "center", + flexWrap: "wrap", + }} + > {highlightWords(words, matchedChar)} )} - + )} diff --git a/src/utils/AudioCompare.js b/src/utils/AudioCompare.js index 8caacbca..c4545242 100644 --- a/src/utils/AudioCompare.js +++ b/src/utils/AudioCompare.js @@ -39,6 +39,7 @@ const AudioRecorder = (props) => { recorderType: RecordRTC.StereoAudioRecorder, // Use StereoAudioRecorder for better compatibility numberOfAudioChannels: 1, // Match the same number of audio channels desiredSampRate: 16000, // Adjust the sample rate if necessary to match + disableLogs: true, }); recorderRef.current.startRecording(); @@ -116,33 +117,34 @@ const AudioRecorder = (props) => { }} className="game-action-button" > - {(!props.dontShowListen || props.recordedAudio) && ( - <> - {!props.pauseAudio ? ( -
{ - props.playAudio(true); - }} - > - - + {props?.originalText && + (!props.dontShowListen || props.recordedAudio) && ( + <> + {!props.pauseAudio ? ( +
{ + props.playAudio(true); + }} + > + + + +
+ ) : ( + { + props.playAudio(false); + }} + > + -
- ) : ( - { - props.playAudio(false); - }} - > - - - )} - - )} + )} + + )}
- {!props.showOnlyListen && ( + {props?.originalText && !props.showOnlyListen && ( { - if(props.isNextButtonCalled){ + useEffect(() => { + if (props.isNextButtonCalled) { if (recordedAudioBase64 !== "") { const lang = getLocalData("lang") || "ta"; fetchASROutput(lang, recordedAudioBase64); - setLoader(true) + setLoader(true); } } - },[props.isNextButtonCalled]) + }, [props.isNextButtonCalled]); useEffect(() => { if (recordedAudioBase64 !== "") { - if( props.setIsNextButtonCalled){ + if (props.setIsNextButtonCalled) { props.setIsNextButtonCalled(false); } } @@ -258,7 +258,7 @@ function VoiceAnalyser(props) { const { originalText, contentType, contentId, currentLine } = props; const responseStartTime = new Date().getTime(); let responseText = ""; - let profanityWord = "" + let profanityWord = ""; let newThresholdPercentage = 0; let data = {}; @@ -279,16 +279,21 @@ function VoiceAnalyser(props) { ); data = updateLearnerData; responseText = data.responseText; - profanityWord = await filterBadWords(data.responseText); + profanityWord = await filterBadWords(data.responseText); if (profanityWord !== data.responseText) { props?.setOpenMessageDialog({ message: "Please avoid using inappropriate language.", isError: true, }); - } + } newThresholdPercentage = data?.subsessionTargetsCount || 0; - if (contentType.toLowerCase() !== 'word') { - handlePercentageForLife(newThresholdPercentage, contentType, data?.subsessionFluency, lang); + if (contentType.toLowerCase() !== "word") { + handlePercentageForLife( + newThresholdPercentage, + contentType, + data?.subsessionFluency, + lang + ); } } @@ -360,8 +365,9 @@ function VoiceAnalyser(props) { var audioFileName = ""; if (process.env.REACT_APP_CAPTURE_AUDIO === "true" && false) { let getContentId = currentLine; - audioFileName = `${process.env.REACT_APP_CHANNEL - }/${sessionId}-${Date.now()}-${getContentId}.wav`; + audioFileName = `${ + process.env.REACT_APP_CHANNEL + }/${sessionId}-${Date.now()}-${getContentId}.wav`; const command = new PutObjectCommand({ Bucket: process.env.REACT_APP_AWS_S3_BUCKET_NAME, @@ -373,7 +379,7 @@ function VoiceAnalyser(props) { }); try { const response = await S3Client.send(command); - } catch (err) { } + } catch (err) {} } response( @@ -400,23 +406,23 @@ function VoiceAnalyser(props) { ); setApiResponse(callUpdateLearner ? data.status : "success"); - if(props.handleNext){ + if (props.handleNext) { props.handleNext(); - if(temp_audio !== null){ + if (temp_audio !== null) { temp_audio.pause(); setPauseAudio(false); } } setLoader(false); - if( props.setIsNextButtonCalled){ + if (props.setIsNextButtonCalled) { props.setIsNextButtonCalled(false); } } catch (error) { setLoader(false); - if(props.handleNext){ + if (props.handleNext) { props.handleNext(); } - if( props.setIsNextButtonCalled){ + if (props.setIsNextButtonCalled) { props.setIsNextButtonCalled(false); } setRecordedAudioBase64(""); @@ -425,92 +431,95 @@ function VoiceAnalyser(props) { } }; - const handlePercentageForLife = (percentage, contentType, fluencyScore, language) => { + const handlePercentageForLife = ( + percentage, + contentType, + fluencyScore, + language + ) => { try { - if (livesData) { - let totalSyllables = livesData.totalTargets; - if (language === "en") { - if (totalSyllables > 50) { - totalSyllables = 50; - } + if (livesData) { + let totalSyllables = livesData.totalTargets; + if (language === "en") { + if (totalSyllables > 50) { + totalSyllables = 50; } - // Calculate the current percentage based on total targets. - percentage = Math.round((percentage / totalSyllables) * 100); - - // Define the total number of lives and adjust the threshold based on syllables. - const totalLives = 5; - let threshold = 30; // Default threshold - - // Adjust the threshold based on total syllables. - if (totalSyllables <= 100) threshold = 30; - else if (totalSyllables > 100 && totalSyllables <= 150) threshold = 25; - else if (totalSyllables > 150 && totalSyllables <= 175) threshold = 20; - else if (totalSyllables > 175 && totalSyllables <= 250) threshold = 15; - else if (totalSyllables > 250 && totalSyllables <= 500) threshold = 10; - else if (totalSyllables > 500) threshold = 5; - - // Calculate lives lost based on percentage. - let livesLost = Math.floor(percentage / (threshold / totalLives)); - - // Check fluency criteria and adjust lives lost accordingly. - let meetsFluencyCriteria; - switch (contentType.toLowerCase()) { - case 'word': - meetsFluencyCriteria = fluencyScore < 2; - break; - case 'sentence': - meetsFluencyCriteria = fluencyScore < 6; - break; - case 'paragraph': - meetsFluencyCriteria = fluencyScore < 10; - break; - default: - meetsFluencyCriteria = true; // Assume criteria met if not specified. - } + } + // Calculate the current percentage based on total targets. + percentage = Math.round((percentage / totalSyllables) * 100); + + // Define the total number of lives and adjust the threshold based on syllables. + const totalLives = 5; + let threshold = 30; // Default threshold + + // Adjust the threshold based on total syllables. + if (totalSyllables <= 100) threshold = 30; + else if (totalSyllables > 100 && totalSyllables <= 150) threshold = 25; + else if (totalSyllables > 150 && totalSyllables <= 175) threshold = 20; + else if (totalSyllables > 175 && totalSyllables <= 250) threshold = 15; + else if (totalSyllables > 250 && totalSyllables <= 500) threshold = 10; + else if (totalSyllables > 500) threshold = 5; + + // Calculate lives lost based on percentage. + let livesLost = Math.floor(percentage / (threshold / totalLives)); + + // Check fluency criteria and adjust lives lost accordingly. + let meetsFluencyCriteria; + switch (contentType.toLowerCase()) { + case "word": + meetsFluencyCriteria = fluencyScore < 2; + break; + case "sentence": + meetsFluencyCriteria = fluencyScore < 6; + break; + case "paragraph": + meetsFluencyCriteria = fluencyScore < 10; + break; + default: + meetsFluencyCriteria = true; // Assume criteria met if not specified. + } - // If fluency criteria are not met, reduce an additional life, but ensure it doesn't exceed the total lives. - if (!meetsFluencyCriteria && livesLost < totalLives) { - livesLost = Math.min(livesLost + 1, totalLives); - } + // If fluency criteria are not met, reduce an additional life, but ensure it doesn't exceed the total lives. + if (!meetsFluencyCriteria && livesLost < totalLives) { + livesLost = Math.min(livesLost + 1, totalLives); + } - // Determine the number of red and black lives to show. - const redLivesToShow = totalLives - livesLost; - let blackLivesToShow = 5; - if(livesLost <= 5){ - blackLivesToShow = livesLost; - } + // Determine the number of red and black lives to show. + const redLivesToShow = totalLives - livesLost; + let blackLivesToShow = 5; + if (livesLost <= 5) { + blackLivesToShow = livesLost; + } - // Prepare the new lives data. - let newLivesData = { - ...livesData, - blackLivesToShow, - redLivesToShow, - meetsFluencyCriteria: meetsFluencyCriteria, - }; - - // Play audio based on the change in lives. - const HeartGaain = - livesData.redLivesToShow === undefined - ? 5 - newLivesData.redLivesToShow - : livesData.redLivesToShow - newLivesData.redLivesToShow; - let isLiveLost; - if (HeartGaain > 0) { - isLiveLost = true; - } else { - isLiveLost = false; - } - const audio = new Audio(isLiveLost ? livesCut : livesAdd); - audio.play(); + // Prepare the new lives data. + let newLivesData = { + ...livesData, + blackLivesToShow, + redLivesToShow, + meetsFluencyCriteria: meetsFluencyCriteria, + }; - // Update the state or data structure with the new lives data. - setLivesData(newLivesData); + // Play audio based on the change in lives. + const HeartGaain = + livesData.redLivesToShow === undefined + ? 5 - newLivesData.redLivesToShow + : livesData.redLivesToShow - newLivesData.redLivesToShow; + let isLiveLost; + if (HeartGaain > 0) { + isLiveLost = true; + } else { + isLiveLost = false; } + const audio = new Audio(isLiveLost ? livesCut : livesAdd); + audio.play(); + + // Update the state or data structure with the new lives data. + setLivesData(newLivesData); + } } catch (e) { - console.log("error", e); + console.log("error", e); } -}; - - + }; // const getpermision = () => { // navigator.getUserMedia = @@ -543,6 +552,7 @@ function VoiceAnalyser(props) { //alert("Microphone Permission Denied"); }); }; + return (
{loader ? ( @@ -557,6 +567,7 @@ function VoiceAnalyser(props) { <> { const TARGETS_PERCENTAGE = 0.3; const [openMessageDialog, setOpenMessageDialog] = useState(""); const lang = getLocalData("lang"); - const [totalSyllableCount, setTotalSyllableCount] = useState(''); - const [percentage, setPercentage] = useState(''); + const [totalSyllableCount, setTotalSyllableCount] = useState(""); + const [percentage, setPercentage] = useState(""); const [fluency, setFluency] = useState(false); const [isNextButtonCalled, setIsNextButtonCalled] = useState(false); const gameOver = (data, isUserPass) => { - let userWon = isUserPass ? true : false; - const meetsFluencyCriteria = livesData.meetsFluencyCriteria ? true : false; - setGameOverData({ gameOver: true, userWon, ...data, meetsFluencyCriteria}); - }; - - const isFirefox = () => { - return typeof navigator !== 'undefined' && navigator.userAgent.toLowerCase().includes('firefox'); + const userWon = isUserPass; + const meetsFluencyCriteria = livesData?.meetsFluencyCriteria; + setGameOverData({ gameOver: true, userWon, ...data, meetsFluencyCriteria }); }; useEffect(() => { @@ -73,6 +67,7 @@ const Practice = () => { setLivesData({ ...livesData, lives: LIVES }); } }, [startShowCase]); + const callConfettiAndPlay = () => { play(); callConfetti(); @@ -92,13 +87,9 @@ const Practice = () => { callConfettiAndPlay(); setTimeout(() => { - // alert( - // `You have successfully completed ${practiceSteps[currentPracticeStep].fullName} ` - // ); setOpenMessageDialog({ message: `You have successfully completed ${practiceSteps[currentPracticeStep].fullName} `, }); - // setDisableScreen(false); }, 1200); } }, [currentQuestion]); @@ -115,7 +106,6 @@ const Practice = () => { message: "Sorry I couldn't hear a voice. Could you please speak again?", isError: true, }); - // alert("Sorry I couldn't hear a voice. Could you please speak again?"); setVoiceText(""); setEnableNext(false); } @@ -128,7 +118,7 @@ const Practice = () => { }, [voiceText]); const send = (score) => { - if (process.env.REACT_APP_IS_APP_IFRAME === 'true') { + if (process.env.REACT_APP_IS_APP_IFRAME === "true") { window.parent.postMessage({ score: score, message: "all-test-rig-score", @@ -137,23 +127,23 @@ const Practice = () => { }; const checkFluency = (contentType, fluencyScore) => { - switch (contentType.toLowerCase()) { - case 'word': - setFluency(fluencyScore < 2); - break; - case 'sentence': - setFluency(fluencyScore < 6); - break; - case 'paragraph': - setFluency(fluencyScore < 10); - break; - default: - setFluency(true); - } - } + switch (contentType.toLowerCase()) { + case "word": + setFluency(fluencyScore < 2); + break; + case "sentence": + setFluency(fluencyScore < 6); + break; + case "paragraph": + setFluency(fluencyScore < 10); + break; + default: + setFluency(true); + } + }; const handleNext = async (isGameOver) => { - setIsNextButtonCalled(true) + setIsNextButtonCalled(true); setEnableNext(false); try { @@ -192,7 +182,7 @@ const Practice = () => { currentPracticeProgress = Math.round( ((currentQuestion + 1 + currentPracticeStep * limit) / (practiceSteps.length * limit)) * - 100 + 100 ); } @@ -244,22 +234,22 @@ const Practice = () => { Log(data, "practice", "ET"); setPercentage(getSetData?.data?.percentage); checkFluency(currentContentType, getSetData?.data?.fluency); - if(process.env.REACT_APP_POST_LEARNER_PROGRESS === "true"){ - await axios.post( - `${process.env.REACT_APP_LEARNER_AI_ORCHESTRATION_HOST}/${config.URLS.CREATE_LEARNER_PROGRESS}`, - { - userId: virtualId, - sessionId: sessionId, - subSessionId: sub_session_id, - milestoneLevel: getSetData?.data?.currentLevel, - totalSyllableCount: totalSyllableCount, - language: localStorage.getItem("lang"), - } - ); - } + if (process.env.REACT_APP_POST_LEARNER_PROGRESS === "true") { + await axios.post( + `${process.env.REACT_APP_LEARNER_AI_ORCHESTRATION_HOST}/${config.URLS.CREATE_LEARNER_PROGRESS}`, + { + userId: virtualId, + sessionId: sessionId, + subSessionId: sub_session_id, + milestoneLevel: getSetData?.data?.currentLevel, + totalSyllableCount: totalSyllableCount, + language: localStorage.getItem("lang"), + } + ); + } setLocalData("previous_level", getSetData.data.previous_level); if (getSetData.data.sessionResult === "pass") { - try{ + try { await axios.post( `${process.env.REACT_APP_LEARNER_AI_ORCHESTRATION_HOST}/${config.URLS.ADD_LESSON}`, { @@ -274,13 +264,10 @@ const Practice = () => { ); gameOver({ link: "/assesment-end" }, true); return; - } - catch(e){ + } catch (e) { // catch error } } - - // navigate("/assesment-end"); } let quesArr = []; @@ -310,20 +297,20 @@ const Practice = () => { if (newPracticeStep === 0 || newPracticeStep === 5 || isGameOver) { gameOver(); return; - // navigate("/assesment-end"); } const resGetContent = await axios.get( `${process.env.REACT_APP_LEARNER_AI_APP_HOST}/${config.URLS.GET_CONTENT}/${currentGetContent.criteria}/${virtualId}?language=${lang}&contentlimit=${limit}&gettargetlimit=${limit}` ); - setTotalSyllableCount(resGetContent?.data?.totalSyllableCount) + setTotalSyllableCount(resGetContent?.data?.totalSyllableCount); setLivesData({ ...livesData, totalTargets: resGetContent?.data?.totalSyllableCount, targetsForLives: resGetContent?.data?.subsessionTargetsCount * TARGETS_PERCENTAGE, targetPerLive: - (resGetContent?.data?.subsessionTargetsCount * TARGETS_PERCENTAGE) / LIVES, + (resGetContent?.data?.subsessionTargetsCount * TARGETS_PERCENTAGE) / + LIVES, }); let showcaseLevel = @@ -374,18 +361,13 @@ const Practice = () => { } }; - // const playAudio = () => { - // // const myAudio = localStorage.getItem("recordedAudio"); - // set_temp_audio(new Audio(recordedAudio)); - // }; - useEffect(() => { learnAudio(); }, [temp_audio]); const playTeacherAudio = () => { const contentId = questions[currentQuestion]?.contentId; - var audio = new Audio( + let audio = new Audio( `${process.env.REACT_APP_AWS_S3_BUCKET_CONTENT_URL}/all-audio-files/${lang}/${contentId}.wav` ); audio.addEventListener("canplaythrough", () => { @@ -405,9 +387,9 @@ const Practice = () => { const virtualId = getLocalData("virtualId"); let sessionId = getLocalData("sessionId"); - if (!sessionId){ + if (!sessionId) { sessionId = uniqueId(); - localStorage.setItem("sessionId", sessionId) + localStorage.setItem("sessionId", sessionId); } const getMilestoneDetails = await axios.get( @@ -455,11 +437,12 @@ const Practice = () => { const resWord = await axios.get( `${process.env.REACT_APP_LEARNER_AI_APP_HOST}/${config.URLS.GET_CONTENT}/${currentGetContent.criteria}/${virtualId}?language=${lang}&contentlimit=${limit}&gettargetlimit=${limit}` ); - setTotalSyllableCount(resWord?.data?.totalSyllableCount) + setTotalSyllableCount(resWord?.data?.totalSyllableCount); setLivesData({ ...livesData, totalTargets: resWord?.data?.totalSyllableCount, - targetsForLives: resWord?.data?.subsessionTargetsCount * TARGETS_PERCENTAGE, + targetsForLives: + resWord?.data?.subsessionTargetsCount * TARGETS_PERCENTAGE, targetPerLive: (resWord?.data?.subsessionTargetsCount * TARGETS_PERCENTAGE) / LIVES, }); @@ -544,11 +527,12 @@ const Practice = () => { const resWord = await axios.get( `${process.env.REACT_APP_LEARNER_AI_APP_HOST}/${config.URLS.GET_CONTENT}/${currentGetContent.criteria}/${virtualId}?language=${lang}&contentlimit=${limit}&gettargetlimit=${limit}` ); - setTotalSyllableCount(resWord?.data?.totalSyllableCount) + setTotalSyllableCount(resWord?.data?.totalSyllableCount); setLivesData({ ...livesData, totalTargets: resWord?.data?.totalSyllableCount, - targetsForLives: resWord?.data?.subsessionTargetsCount * TARGETS_PERCENTAGE, + targetsForLives: + resWord?.data?.subsessionTargetsCount * TARGETS_PERCENTAGE, targetPerLive: (resWord?.data?.subsessionTargetsCount * TARGETS_PERCENTAGE) / LIVES, }); @@ -565,10 +549,10 @@ const Practice = () => { setCurrentQuestion(practiceProgress[virtualId]?.currentQuestion || 0); setLocalData("practiceProgress", JSON.stringify(practiceProgress)); } else { - if (process.env.REACT_APP_IS_APP_IFRAME === 'true') { + if (process.env.REACT_APP_IS_APP_IFRAME === "true") { navigate("/"); - }else { - navigate("/discover-start") + } else { + navigate("/discover-start"); } } }; @@ -587,10 +571,6 @@ const Practice = () => { return str2.length - str1.length; }); - let fontSize = - questions[currentQuestion]?.contentType?.toLowerCase() === "paragraph" - ? 30 - : 40; let type = currentContentType?.toLowerCase(); if (type === "char" || type === "word") { const word = splitGraphemes(words[0].toLowerCase()).filter( @@ -611,7 +591,7 @@ const Practice = () => { variant="h5" component="h4" sx={{ - fontSize: `${fontSize}px`, + fontSize: "clamp(1.6rem, 2.5vw, 3.8rem)", fontWeight: 700, fontFamily: "Quicksand", lineHeight: "50px", @@ -635,7 +615,7 @@ const Practice = () => { component="h4" sx={{ color: "#333F61", - fontSize: `${fontSize}px`, + fontSize: "clamp(1.6rem, 2.5vw, 3.8rem)", fontWeight: 700, fontFamily: "Quicksand", lineHeight: "50px", @@ -661,7 +641,7 @@ const Practice = () => { component="h4" ml={1} sx={{ - fontSize: `${fontSize}px`, + fontSize: "clamp(1.6rem, 2.5vw, 3.8rem)", fontWeight: 700, fontFamily: "Quicksand", lineHeight: "50px", @@ -680,7 +660,7 @@ const Practice = () => { ml={1} sx={{ color: "#333F61", - fontSize: `${fontSize}px`, + fontSize: "clamp(1.6rem, 2.5vw, 3.8rem)", fontWeight: 700, fontFamily: "Quicksand", lineHeight: "50px", @@ -698,11 +678,12 @@ const Practice = () => { useEffect(() => { if (questions[currentQuestion]?.contentSourceData) { - if (process.env.REACT_APP_IS_APP_IFRAME === 'true') { - const contentSourceData = questions[currentQuestion]?.contentSourceData || []; - const stringLengths = contentSourceData.map(item => item.text.length); + if (process.env.REACT_APP_IS_APP_IFRAME === "true") { + const contentSourceData = + questions[currentQuestion]?.contentSourceData || []; + const stringLengths = contentSourceData.map((item) => item.text.length); const length = stringLengths[0]; - window.parent.postMessage({ type: 'stringLengths', length }); + window.parent.postMessage({ type: "stringLengths", length }); } } }, [questions[currentQuestion]]); @@ -755,7 +736,7 @@ const Practice = () => { setOpenMessageDialog, setEnableNext, isNextButtonCalled, - setIsNextButtonCalled + setIsNextButtonCalled, }} /> );