From 07cebf1b006a0e58d70f9d53b9afef87afc5a0b2 Mon Sep 17 00:00:00 2001 From: Sy Traore Date: Wed, 1 Oct 2025 16:08:02 -0400 Subject: [PATCH 1/3] Comment out feedback logic in tray click handlers The text-to-speech feedback for correct and incorrect tray selections has been commented out in both TouchTrainingPage and basePage at the request of Dr. Koeum. --- apps/frontend/src/pages/TouchTrainingPage.jsx | 30 +++++++++---------- apps/frontend/src/pages/basePage.jsx | 30 +++++++++---------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/apps/frontend/src/pages/TouchTrainingPage.jsx b/apps/frontend/src/pages/TouchTrainingPage.jsx index 5dd76c9..ed1efe8 100644 --- a/apps/frontend/src/pages/TouchTrainingPage.jsx +++ b/apps/frontend/src/pages/TouchTrainingPage.jsx @@ -248,21 +248,21 @@ const TouchTrainingPage = () => { const handleTrayClick = (trayType) => { setSelectedTray(trayType); // if the correct tray has been clicked - if (trayType === "greenTray" && sectionTrainData.pages[currentPage].greenTray[0].biscuits.length === sectionTrainData.pages[currentPage].cookies.length) { - textToSpeech("Green is correct, Good job!"); - } - else if (trayType === "purpleTray" && sectionTrainData.pages[currentPage].purpleTray[0].biscuits.length === sectionTrainData.pages[currentPage].cookies.length){ - textToSpeech("Purple is correct, Well done!"); - } - // if the wrong tray has been clicked - else if (trayType === "greenTray" && sectionTrainData.pages[currentPage].greenTray[0].biscuits.length !== sectionTrainData.pages[currentPage].cookies.length) { - const explanation = `No, ${trayType} has ${sectionTrainData.pages[currentPage].greenTray[0].biscuits.length} cookies. Try again!`; - textToSpeech(explanation); - } - else{ - const explanation = `Wrong answer, ${trayType} has ${sectionTrainData.pages[currentPage].purpleTray[0].biscuits.length} cookies. Try again!`; - textToSpeech(explanation); - } + // if (trayType === "greenTray" && sectionTrainData.pages[currentPage].greenTray[0].biscuits.length === sectionTrainData.pages[currentPage].cookies.length) { + // textToSpeech("Green is correct, Good job!"); + // } + // else if (trayType === "purpleTray" && sectionTrainData.pages[currentPage].purpleTray[0].biscuits.length === sectionTrainData.pages[currentPage].cookies.length){ + // textToSpeech("Purple is correct, Well done!"); + // } + // // if the wrong tray has been clicked + // else if (trayType === "greenTray" && sectionTrainData.pages[currentPage].greenTray[0].biscuits.length !== sectionTrainData.pages[currentPage].cookies.length) { + // const explanation = `No, ${trayType} has ${sectionTrainData.pages[currentPage].greenTray[0].biscuits.length} cookies. Try again!`; + // textToSpeech(explanation); + // } + // else{ + // const explanation = `Wrong answer, ${trayType} has ${sectionTrainData.pages[currentPage].purpleTray[0].biscuits.length} cookies. Try again!`; + // textToSpeech(explanation); + // } storeAnswer(currentPage, trayType); }; diff --git a/apps/frontend/src/pages/basePage.jsx b/apps/frontend/src/pages/basePage.jsx index 615632b..bfc90bc 100644 --- a/apps/frontend/src/pages/basePage.jsx +++ b/apps/frontend/src/pages/basePage.jsx @@ -85,21 +85,21 @@ function basePage() { const handleTrayClick = (trayType) => { setSelectedTray(trayType); // if the correct tray has been clicked - if (trayType === "greenTray" && baseData.pages[currentPage].greenTray[0].biscuits.length === baseData.pages[currentPage].cookies.length) { - textToSpeech("Green is correct, Good job!"); - } - else if (trayType === "purpleTray" && baseData.pages[currentPage].purpleTray[0].biscuits.length === baseData.pages[currentPage].cookies.length){ - textToSpeech("Purple is correct, Well done!"); - } - // if the wrong tray has been clicked - else if (trayType === "greenTray" && baseData.pages[currentPage].greenTray[0].biscuits.length !== baseData.pages[currentPage].cookies.length) { - const explanation = `No, ${trayType} has ${baseData.pages[currentPage].greenTray[0].biscuits.length} cookies. Try again!`; - textToSpeech(explanation); - } - else{ - const explanation = `Wrong answer, ${trayType} has ${baseData.pages[currentPage].purpleTray[0].biscuits.length} cookies. Try again!`; - textToSpeech(explanation); - } + // if (trayType === "greenTray" && baseData.pages[currentPage].greenTray[0].biscuits.length === baseData.pages[currentPage].cookies.length) { + // textToSpeech("Green is correct, Good job!"); + // } + // else if (trayType === "purpleTray" && baseData.pages[currentPage].purpleTray[0].biscuits.length === baseData.pages[currentPage].cookies.length){ + // textToSpeech("Purple is correct, Well done!"); + // } + // // if the wrong tray has been clicked + // else if (trayType === "greenTray" && baseData.pages[currentPage].greenTray[0].biscuits.length !== baseData.pages[currentPage].cookies.length) { + // const explanation = `No, ${trayType} has ${baseData.pages[currentPage].greenTray[0].biscuits.length} cookies. Try again!`; + // textToSpeech(explanation); + // } + // else{ + // const explanation = `Wrong answer, ${trayType} has ${baseData.pages[currentPage].purpleTray[0].biscuits.length} cookies. Try again!`; + // textToSpeech(explanation); + // } storeAnswer(currentPage, trayType); }; From 6e5a9d4a45818bcb4a831a1ba4d3fc291bc85540 Mon Sep 17 00:00:00 2001 From: Sy <132951255+sytraore@users.noreply.github.com> Date: Wed, 8 Oct 2025 22:24:10 -0400 Subject: [PATCH 2/3] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 24a90a7..8b62fa9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -# +# Counting-App on NX - +✨ This is Virginia Tech's Echolab [Counting app research project](https://github.com/echo-lab/Counting-App) but within an [NX](https://nx.dev/getting-started/tutorials/react-monorepo-tutorial?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) workspace. -✨ Your new, shiny [Nx workspace](https://nx.dev) is almost ready ✨. + +shiny [Nx workspace](https://nx.dev) is almost ready ✨. [Learn more about this workspace setup and its capabilities](https://nx.dev/getting-started/tutorials/react-monorepo-tutorial?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) or run `npx nx graph` to visually explore what was created. Now, let's get you up to speed! From 902e82c950f28cc685f03d137acaaeb789ff9fa8 Mon Sep 17 00:00:00 2001 From: Sy Traore Date: Wed, 8 Oct 2025 22:31:09 -0400 Subject: [PATCH 3/3] Fixed iPads sound issue. Fixed the sound issue when users use the app on iPads. Also updated the app icon to be the lab icon. --- apps/backend/package.json | 3 + apps/backend/src/server.js | 8 +- apps/frontend/index.html | 4 +- apps/frontend/logoecholab.png | Bin 0 -> 15716 bytes apps/frontend/src/App.jsx | 17 +++ apps/frontend/src/helpers/textToSpeech.js | 132 ++++++++++++++-------- package-lock.json | 104 ++++++++++++++++- 7 files changed, 215 insertions(+), 53 deletions(-) create mode 100644 apps/frontend/logoecholab.png diff --git a/apps/backend/package.json b/apps/backend/package.json index 5a1d1e5..5661c02 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -30,5 +30,8 @@ } } } + }, + "dependencies": { + "wav": "^1.0.2" } } diff --git a/apps/backend/src/server.js b/apps/backend/src/server.js index d875226..3ab1440 100644 --- a/apps/backend/src/server.js +++ b/apps/backend/src/server.js @@ -12,6 +12,8 @@ import fetch from 'node-fetch'; import cors from 'cors'; import path from 'path'; import { fileURLToPath } from 'url'; +import { Writer } from 'wav'; +import { PassThrough } from 'stream'; //import { config } from 'dotenv'; // might move it before importing the db.js file // change from apps/backend/.env.local to .env.local to enable environment variables to be loaded on server @@ -245,7 +247,11 @@ app.post("/register", async (req, res) => { }); const data = await response.json(); - res.json(data); + //res.json(data); + const audioBuffer = Buffer.from(data.audioContent, 'base64'); + res.setHeader('Content-Type', 'audio/mpeg'); + res.end(audioBuffer); + } catch (error) { console.error('Server Error in Google Text-to-Speech:', error); res.status(500).json({ message: error.toString() }); diff --git a/apps/frontend/index.html b/apps/frontend/index.html index 6232af6..04ddf5a 100644 --- a/apps/frontend/index.html +++ b/apps/frontend/index.html @@ -2,14 +2,14 @@ - + - + Counting App diff --git a/apps/frontend/logoecholab.png b/apps/frontend/logoecholab.png new file mode 100644 index 0000000000000000000000000000000000000000..eea2f15deb903d6b0be6fed722d497086bd6e2bb GIT binary patch literal 15716 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 literal 0 HcmV?d00001 diff --git a/apps/frontend/src/App.jsx b/apps/frontend/src/App.jsx index 7987c75..dabbe98 100644 --- a/apps/frontend/src/App.jsx +++ b/apps/frontend/src/App.jsx @@ -33,6 +33,23 @@ function App() { document.removeEventListener("contextmenu", handleContextMenu); }; }, []); + + + useEffect(() => { + const unlockAudio = () => { + const silent = new Audio('data:audio/mp3;base64,SUQzBAAAAAABEVRYWFgAAAAtAAADY29tbWVudABCaWdTb3VuZEJhbmsuY29tIC8gTGFTb25vdGhlcXVlLm9yZwBURU5DAAAAHQAAA1N3aXRjaCBQbHVzIMHumPMHBgAAA'); + silent.play().catch(() => {}); + document.body.removeEventListener('click', unlockAudio); + document.body.removeEventListener('touchend', unlockAudio); + }; + document.body.addEventListener('click', unlockAudio); + document.body.addEventListener('touchend', unlockAudio); + return () => { + document.body.removeEventListener('click', unlockAudio); + document.body.removeEventListener('touchend', unlockAudio); + }; + }, []); + return (
diff --git a/apps/frontend/src/helpers/textToSpeech.js b/apps/frontend/src/helpers/textToSpeech.js index f1de9bb..77c6ca6 100644 --- a/apps/frontend/src/helpers/textToSpeech.js +++ b/apps/frontend/src/helpers/textToSpeech.js @@ -8,6 +8,11 @@ export async function textToSpeech(utterance, onSpeechEnd) { return; } + if (currentAudio) { + currentAudio.pause(); // Stop any currently playing audio + currentAudio = null; + } + try { const requestData = { text: utterance, @@ -27,64 +32,95 @@ export async function textToSpeech(utterance, onSpeechEnd) { }); console.log('Response status:', response.status); + + // expected response is a blob + const audioBlob = await response.blob(); + const audioUrl = URL.createObjectURL(audioBlob); + const audio = new Audio(audioUrl); + currentAudio = audio; + + audio.addEventListener('ended', () => { + currentAudio = null; + // Clean up the temporary URL to release memory + URL.revokeObjectURL(audioUrl); + if (typeof onSpeechEnd === 'function') { + onSpeechEnd(); + } + }); - if (!response.ok) { - const errorText = await response.text(); - console.error('Server error response:', { - status: response.status, - statusText: response.statusText, - errorText - }); - return; - } + audio.addEventListener('error', (e) => { + console.error('Audio element error:', e); + URL.revokeObjectURL(audioUrl); // Also clean up on error + }); + + try { + await audio.play(); + console.log('Playback started successfully'); + } catch (playError){ + console.error('Playback failed:', { + name: playError.name, + message: playError.message + }); + URL.revokeObjectURL(audioUrl); + } + + // if (!response.ok) { + // const errorText = await response.text(); + // console.error('Server error response:', { + // status: response.status, + // statusText: response.statusText, + // errorText + // }); + // return; + // } - const data = await response.json(); - if (currentAudio) { - currentAudio.pause(); - currentAudio = null; - } + // const data = await response.json(); + // if (currentAudio) { + // currentAudio.pause(); + // currentAudio = null; + // } - console.log('Parsed response data:', data); + // console.log('Parsed response data:', data); - // Validate audio content - if (!data || !data.audioContent) { - console.error('No audio content in response', data); - return; - } + // // Validate audio content + // if (!data || !data.audioContent) { + // console.error('No audio content in response', data); + // return; + // } - // Stop any currently playing audio - if (currentAudio) { - currentAudio.pause(); - currentAudio = null; - } + // // Stop any currently playing audio + // if (currentAudio) { + // currentAudio.pause(); + // currentAudio = null; + // } - const audioSrc = `data:audio/mp3;base64,${data.audioContent}`; + // const audioSrc = `data:audio/mp3;base64,${data.audioContent}`; - const audio = new Audio(audioSrc); - currentAudio = audio; + // const audio = new Audio(audioSrc); + // currentAudio = audio; - // Set up event listeners - audio.addEventListener('error', (e) => { - console.error('Audio element error:', e); - currentAudio = null; - }); + // // Set up event listeners + // audio.addEventListener('error', (e) => { + // console.error('Audio element error:', e); + // currentAudio = null; + // }); - audio.addEventListener('ended', () => { - currentAudio = null; - if (typeof onSpeechEnd === 'function') { - onSpeechEnd(); - } - }); + // audio.addEventListener('ended', () => { + // currentAudio = null; + // if (typeof onSpeechEnd === 'function') { + // onSpeechEnd(); + // } + // }); - try { - await audio.play(); - console.log('Playback started successfully'); - } catch (playError) { - console.error('Playback failed:', { - name: playError.name, - message: playError.message - }); - } + // try { + // await audio.play(); + // console.log('Playback started successfully'); + // } catch (playError) { + // console.error('Playback failed:', { + // name: playError.name, + // message: playError.message + // }); + // } } catch (error) { console.error('Comprehensive error in Text-to-Speech:', { diff --git a/package-lock.json b/package-lock.json index aadb3aa..75dc1f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -98,7 +98,10 @@ } }, "apps/backend": { - "version": "0.0.1" + "version": "0.0.1", + "dependencies": { + "wav": "^1.0.2" + } }, "apps/backend-e2e": { "version": "0.0.1" @@ -11155,6 +11158,22 @@ "ieee754": "^1.2.1" } }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "license": "MIT", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "license": "MIT" + }, "node_modules/buffer-builder": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", @@ -11178,11 +11197,16 @@ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "license": "MIT" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, "license": "MIT" }, "node_modules/buffer-xor": { @@ -23687,6 +23711,30 @@ "readable-stream": "^3.5.0" } }, + "node_modules/stream-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", + "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", + "license": "MIT", + "dependencies": { + "debug": "2" + } + }, + "node_modules/stream-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/stream-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/streamroller": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", @@ -25761,6 +25809,58 @@ "node": ">=10.13.0" } }, + "node_modules/wav": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wav/-/wav-1.0.2.tgz", + "integrity": "sha512-viHtz3cDd/Tcr/HbNqzQCofKdF6kWUymH9LGDdskfWFoIy/HJ+RTihgjEcHfnsy1PO4e9B+y4HwgTwMrByquhg==", + "license": "MIT", + "dependencies": { + "buffer-alloc": "^1.1.0", + "buffer-from": "^1.0.0", + "debug": "^2.2.0", + "readable-stream": "^1.1.14", + "stream-parser": "^0.3.1" + } + }, + "node_modules/wav/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/wav/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, + "node_modules/wav/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/wav/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/wav/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT" + }, "node_modules/wbuf": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",