From 0c24a0857adda49f6b440c9fc0e46c76b23bbb44 Mon Sep 17 00:00:00 2001 From: Zhuojin Liu Date: Thu, 13 Feb 2025 16:55:50 -0800 Subject: [PATCH 1/2] Move the script in html to a seperate file --- demo/web/index.html | 396 +------------------------------------- demo/web/scripts/eagle.js | 393 +++++++++++++++++++++++++++++++++++++ 2 files changed, 394 insertions(+), 395 deletions(-) create mode 100644 demo/web/scripts/eagle.js diff --git a/demo/web/index.html b/demo/web/index.html index 4ad01df0..2818db3f 100644 --- a/demo/web/index.html +++ b/demo/web/index.html @@ -4,401 +4,7 @@ - +

Eagle Web Demo

diff --git a/demo/web/scripts/eagle.js b/demo/web/scripts/eagle.js new file mode 100644 index 00000000..5af2893e --- /dev/null +++ b/demo/web/scripts/eagle.js @@ -0,0 +1,393 @@ +let profiler = null; +let eagle = null; +let speakerProfiles = [] + +let timer = null; +let currentTimer = 0.0; +let audioData = []; +let audioContext = null; + +const ENABLE_AUDIO_DUMP = false; +let dumpAudio = []; + +window.onload = function () { + audioContext = new (window.AudioContext || window.webKitAudioContext)( + { sampleRate: 16000 } + ); + + document.getElementById("audioFile").addEventListener("change", async (event) => { + newEnrollmentUI(); + try { + await profiler.reset(); + } catch (e) { + writeMessage(`Failed to reset Eagle Profiler. Error: ${e}`); + return; + } + + writeMessage("Processing audio files..."); + const fileList = event.target.files; + let percentage = 0; + for (const f of fileList) { + let audioFrame; + try { + audioFrame = await getAudioFileData(f, audioContext); + } catch (e) { + writeMessage(`Failed to read audio file '${f.name}'. Error: ${e}`); + return; + } + + try { + const result = await profiler.enroll(audioFrame); + updateSpeakerProgress(speakerProfiles.length + 1, result.feedback, result.percentage) + percentage = result.percentage; + } catch (e) { + writeMessage(`Failed to enroll using '${f.name}'. Error: ${e}`); + return; + } + } + + if (percentage < 100) { + writeMessage(`Speaker is only ${percentage}% done enrollment. ` + + `Please choose a larger data set and try again.`); + enrollFailUI(); + return; + } + + try { + const profile = await profiler.export(); + speakerProfiles.push(profile); + enrollSuccessUI(); + writeMessage(`Enrollment for Speaker ${speakerProfiles.length} complete! ` + + `You can begin testing or enroll another speaker.`); + } catch (e) { + writeMessage(`Failed to enroll speaker. Error: ${e}`); + } + }); +} + +async function getAudioFileData(audioFile, audioContext) { + const dataBuffer = await audioFile.arrayBuffer(); + const audioBuffer = await audioContext.decodeAudioData(dataBuffer); + + const f32PCM = audioBuffer.getChannelData(0); + const i16PCM = new Int16Array(f32PCM.length); + + const INT16_MAX = 32767; + const INT16_MIN = -32768; + i16PCM.set( + f32PCM.map((f) => { + let i = Math.trunc(f * INT16_MAX); + if (f > INT16_MAX) i = INT16_MAX; + if (f < INT16_MIN) i = INT16_MIN; + return i; + }) + ); + return i16PCM; +} + +const micEnrollEngine = { + onmessage: async (event) => { + switch (event.data.command) { + case "process": + audioData.push(event.data.inputFrame); + + if (ENABLE_AUDIO_DUMP) { + dumpAudio = dumpAudio.concat(event.data.inputFrame); + } + + if (audioData.length * 512 >= profiler.minEnrollSamples) { + let result; + + try { + const frames = new Int16Array(audioData.length * 512); + for (let i = 0; i < audioData.length; i++) { + frames.set(audioData[i], i * 512); + } + audioData = []; + result = await profiler.enroll(frames); + } catch (e) { + writeMessage(`Failed to enroll. Error: ${e}`); + return; + } + + updateSpeakerProgress(speakerProfiles.length + 1, result.feedback, result.percentage); + if (result.percentage === 100) { + await window.WebVoiceProcessor.WebVoiceProcessor.unsubscribe(micEnrollEngine); + clearInterval(timer); + micEnrollStopUI(); + + try { + const profile = await profiler.export(); + speakerProfiles.push(profile); + enrollSuccessUI(); + writeMessage(`Enrollment for Speaker ${speakerProfiles.length} complete! ` + + `You can begin testing or enroll another speaker.`); + } catch (e) { + writeMessage(`Failed to enroll speaker. Error: ${e}`); + } + + if (ENABLE_AUDIO_DUMP) { + downloadDumpAudio("enroll.pcm"); + } + } + } + break; + } + } +} + +async function micEnrollStart() { + currentTimer = 0.0; + audioData = []; + micEnrollStartUI(); + newEnrollmentUI(); + try { + await profiler.reset(); + } catch (e) { + writeMessage(`Failed to reset Eagle Profiler. Error: ${e}`); + return; + } + + writeMessage("Keep speaking continuously until enrollment progress reaches 100%."); + try { + await window.WebVoiceProcessor.WebVoiceProcessor.subscribe(micEnrollEngine); + timer = setInterval(() => { + currentTimer += 0.1; + document.getElementById("displayTimer").innerText = `${currentTimer.toFixed(1)}`; + }, 100); + } catch (e) { + writeMessage(e); + } +} + +async function micEnrollStop() { + await window.WebVoiceProcessor.WebVoiceProcessor.unsubscribe(micEnrollEngine); + clearInterval(timer); + writeMessage(`Enrollment stopped`); + updateSpeakerTable(); + enrollFailUI(); + micEnrollStopUI(); +} + +function writeMessage(message) { + console.log(message); + document.getElementById("status").innerHTML = message; +} + +function updateSpeakerProgress(speakerId, feedback, progress) { + const feedbackMsg = getFeedbackMessage(feedback) + console.log(progress, feedbackMsg); + document.getElementById(`speaker${speakerId}Feedback`).innerHTML = ` ${feedbackMsg}`; + document.getElementById(`speaker${speakerId}Progress`).value = progress; +} + +function updateSpeakerScore(speakerId, score) { + document.getElementById(`speaker${speakerId}Progress`).value = score * 100; +} + +function getFeedbackMessage(feedback) { + switch (feedback) { + case EagleWeb.EagleProfilerEnrollFeedback.AUDIO_TOO_SHORT: + return "Insufficient audio length"; + case EagleWeb.EagleProfilerEnrollFeedback.UNKNOWN_SPEAKER: + return "Different speaker detected in audio"; + case EagleWeb.EagleProfilerEnrollFeedback.NO_VOICE_FOUND: + return "Unable to detect voice in audio"; + case EagleWeb.EagleProfilerEnrollFeedback.QUALITY_ISSUE: + return "Audio quality too low to use for enrollment"; + default: + return "Enrolling speaker..."; + } +} + +function updateSpeakerTable() { + const speakerTable = document.getElementById("speakersTable"); + while (speakerTable.lastElementChild) { + speakerTable.removeChild(speakerTable.lastElementChild); + } + for (let i = 0; i < speakerProfiles.length; i++) { + speakerTable.append(createSpeakerRow(i + 1, 100)); + speakerTable.append(document.createElement("br")) + } +} + +function createSpeakerRow(i, initialProgress) { + const div = document.createElement("div"); + div.textContent = `Speaker ${i} ` + const speakerProgress = document.createElement("progress"); + speakerProgress.max = 100; + speakerProgress.value = initialProgress; + speakerProgress.id = `speaker${i}Progress` + const speakerFeedback = document.createElement("span"); + speakerFeedback.id = `speaker${i}Feedback` + div.appendChild(speakerProgress); + div.appendChild(speakerFeedback); + return div; +} + +function newEnrollmentUI() { + updateSpeakerTable(); + document.getElementById("testContainer").style.display = "block"; + document.getElementById("feedbackText").innerHTML = ""; + document.getElementById("speakersTable").append(createSpeakerRow(speakerProfiles.length + 1, 0)); + document.getElementById("speakersTable").append(document.createElement("br")) + document.getElementById("testStartBtn").disabled = true; + document.getElementById("resetBtn").disabled = true; +} + +function enrollFailUI() { + document.getElementById("testStartBtn").disabled = speakerProfiles.length === 0; + document.getElementById("resetBtn").disabled = speakerProfiles.length === 0; +} + +function enrollSuccessUI() { + updateSpeakerTable(); + document.getElementById("testStartBtn").disabled = false; + document.getElementById("resetBtn").disabled = false; +} + +function micEnrollStartUI() { + document.getElementById("displayTimer").style.display = "inline"; + document.getElementById("micEnrollStartBtn").style.display = "none"; + document.getElementById("audioFile").disabled = true; + document.getElementById("micEnrollStopBtn").style.display = "inline"; +} + +function micEnrollStopUI() { + document.getElementById("displayTimer").style.display = "none"; + document.getElementById("micEnrollStartBtn").style.display = "inline"; + document.getElementById("audioFile").disabled = false; + document.getElementById("micEnrollStopBtn").style.display = "none"; + document.getElementById("displayTimer").innerText = `0.0`; +} + +function micTestStartUI() { + document.getElementById("micEnrollStartBtn").disabled = true; + document.getElementById("audioFile").disabled = true; + document.getElementById("resetBtn").disabled = true; + document.getElementById("testStartBtn").style.display = "none"; + document.getElementById("testStopBtn").style.display = "inline"; + document.getElementById("testStopBtn").disabled = true; +} + +function micTestStopUI() { + document.getElementById("micEnrollStartBtn").disabled = false; + document.getElementById("audioFile").disabled = false; + document.getElementById("resetBtn").disabled = false; + document.getElementById("testStartBtn").style.display = "inline"; + document.getElementById("testStopBtn").style.display = "none"; +} + +async function startEagleProfiler(accessKey) { + writeMessage("Eagle is loading. Please wait..."); + try { + profiler = await EagleWeb.EagleProfilerWorker.create( + accessKey, + { + base64: modelParams, + forceWrite: true + }); + writeMessage(""); + + document.getElementById('enrollContainer').style.display = "block"; + } catch (e) { + writeMessage(`Failed to initialize Eagle. Error: ${e}`); + } +} + +const micTestEngine = { + onmessage: async (event) => { + switch (event.data.command) { + case "process": + if (ENABLE_AUDIO_DUMP) { + dumpAudio = dumpAudio.concat(event.data.inputFrame); + } + let scores + try { + scores = await eagle.process(event.data.inputFrame); + } catch (e) { + writeMessage(`Failed to enroll. Error: ${e}`); + return; + } + + for (let i = 0; i < scores.length; i++) { + updateSpeakerScore(i + 1, scores[i]); + } + break; + } + } +} + +async function startEagle(accessKey) { + writeMessage("Eagle is loading. Please wait..."); + micTestStartUI(); + try { + eagle = await EagleWeb.EagleWorker.create( + accessKey, + { + base64: modelParams, + forceWrite: true + }, + speakerProfiles); + + } catch (e) { + writeMessage(`Failed to initialize Eagle. Error: ${e}`); + return; + } + try { + await profiler.reset(); + } catch (e) { + writeMessage(`Failed to reset Eagle Profiler. Error: ${e}`); + return; + } + + document.getElementById("testStopBtn").disabled = false; + for (let i = 0; i < speakerProfiles.length; i++) { + updateSpeakerScore(i + 1, 0); + } + writeMessage("Take turns speaking sentences and see if Eagle can recognize which speaker is talking"); + try { + await window.WebVoiceProcessor.WebVoiceProcessor.subscribe(micTestEngine); + } catch (e) { + writeMessage(e); + } +} + +async function stopEagle() { + try { + await window.WebVoiceProcessor.WebVoiceProcessor.unsubscribe(micTestEngine); + } catch (e) { + writeMessage(e); + } + + if (eagle) { + await eagle.terminate(); + eagle = null; + } + for (let i = 0; i < speakerProfiles.length; i++) { + updateSpeakerScore(i + 1, 100); + } + micTestStopUI(); + writeMessage(""); + + if (ENABLE_AUDIO_DUMP) { + downloadDumpAudio('test.pcm'); + } +} + +function resetSpeakers() { + document.getElementById("testContainer").style.display = "none"; + speakerProfiles = []; + updateSpeakerTable(); + writeMessage(""); +} + +function downloadDumpAudio(fileName) { + let blob = new Blob(dumpAudio); + dumpAudio = []; + let a = document.createElement('a'); + a.download = fileName; + a.href = window.URL.createObjectURL(blob); + a.click(); + document.removeChild(a); +} \ No newline at end of file From 1959a5b0c65bbeeca70a895d7ba1af44825e12f6 Mon Sep 17 00:00:00 2001 From: Zhuojin Liu Date: Thu, 13 Feb 2025 17:01:01 -0800 Subject: [PATCH 2/2] Add formatter --- demo/web/.prettierignore | 3 + demo/web/.prettierrc | 1 + demo/web/README.md | 2 +- demo/web/index.html | 62 ++++++------ demo/web/package.json | 3 +- demo/web/scripts/eagle.js | 203 +++++++++++++++++++++----------------- demo/web/yarn.lock | 5 + 7 files changed, 156 insertions(+), 123 deletions(-) create mode 100644 demo/web/.prettierignore create mode 100644 demo/web/.prettierrc diff --git a/demo/web/.prettierignore b/demo/web/.prettierignore new file mode 100644 index 00000000..1b8ac889 --- /dev/null +++ b/demo/web/.prettierignore @@ -0,0 +1,3 @@ +# Ignore artifacts: +build +coverage diff --git a/demo/web/.prettierrc b/demo/web/.prettierrc new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/demo/web/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/demo/web/README.md b/demo/web/README.md index 14bb3f48..8b4b5036 100644 --- a/demo/web/README.md +++ b/demo/web/README.md @@ -32,5 +32,5 @@ Available on: Hit CTRL-C to stop the server ``` -Enter your AccessKey and wait until Eagle and the WebVoiceProcessor have initialized. Record audio or upload an audio +Enter your AccessKey and wait until Eagle and the WebVoiceProcessor have initialized. Record audio or upload an audio file to enroll speakers. Test speaker recognition in real-time with a microphone. diff --git a/demo/web/index.html b/demo/web/index.html index 2818db3f..ddd357e8 100644 --- a/demo/web/index.html +++ b/demo/web/index.html @@ -1,4 +1,4 @@ - + @@ -10,21 +10,15 @@

Eagle Web Demo

This demo uses Eagle for Web and the WebVoiceProcessor to:

    +
  1. Create an instance of Eagle with the model file provided.
  2. - Create an instance of Eagle with the model file provided. -
  3. -
  4. - Select an audio file or acquire microphone data stream and convert to voice - processing format (16kHz 16-bit linear PCM). The downsampled audio is - forwarded to the Eagle engine. The audio does not leave the + Select an audio file or acquire microphone data stream and convert to + voice processing format (16kHz 16-bit linear PCM). The downsampled audio + is forwarded to the Eagle engine. The audio does not leave the browser: all processing is occurring via the Eagle WebAssembly code.
  5. -
  6. - Enroll multiple speakers with audio files or a microphone. -
  7. -
  8. - Recognize which speaker is talking in real-time. -
  9. +
  10. Enroll multiple speakers with audio files or a microphone.
  11. +
  12. Recognize which speaker is talking in real-time.
After entering the AccessKey, click the "Start Eagle" button.
@@ -39,46 +33,50 @@

Eagle Web Demo

value="Start Eagle" onclick="startEagleProfiler(document.getElementById('accessKey').value)" /> -
+
diff --git a/demo/web/package.json b/demo/web/package.json index fdb16b34..7dddb981 100644 --- a/demo/web/package.json +++ b/demo/web/package.json @@ -22,6 +22,7 @@ "@picovoice/web-voice-processor": "~4.0.8" }, "devDependencies": { - "http-server": "^14.0.0" + "http-server": "^14.0.0", + "prettier": "3.5.1" } } diff --git a/demo/web/scripts/eagle.js b/demo/web/scripts/eagle.js index 5af2893e..94016967 100644 --- a/demo/web/scripts/eagle.js +++ b/demo/web/scripts/eagle.js @@ -1,6 +1,6 @@ let profiler = null; let eagle = null; -let speakerProfiles = [] +let speakerProfiles = []; let timer = null; let currentTimer = 0.0; @@ -11,59 +11,69 @@ const ENABLE_AUDIO_DUMP = false; let dumpAudio = []; window.onload = function () { - audioContext = new (window.AudioContext || window.webKitAudioContext)( - { sampleRate: 16000 } - ); - - document.getElementById("audioFile").addEventListener("change", async (event) => { - newEnrollmentUI(); - try { - await profiler.reset(); - } catch (e) { - writeMessage(`Failed to reset Eagle Profiler. Error: ${e}`); - return; - } + audioContext = new (window.AudioContext || window.webKitAudioContext)({ + sampleRate: 16000, + }); - writeMessage("Processing audio files..."); - const fileList = event.target.files; - let percentage = 0; - for (const f of fileList) { - let audioFrame; + document + .getElementById("audioFile") + .addEventListener("change", async (event) => { + newEnrollmentUI(); try { - audioFrame = await getAudioFileData(f, audioContext); + await profiler.reset(); } catch (e) { - writeMessage(`Failed to read audio file '${f.name}'. Error: ${e}`); + writeMessage(`Failed to reset Eagle Profiler. Error: ${e}`); return; } - try { - const result = await profiler.enroll(audioFrame); - updateSpeakerProgress(speakerProfiles.length + 1, result.feedback, result.percentage) - percentage = result.percentage; - } catch (e) { - writeMessage(`Failed to enroll using '${f.name}'. Error: ${e}`); - return; + writeMessage("Processing audio files..."); + const fileList = event.target.files; + let percentage = 0; + for (const f of fileList) { + let audioFrame; + try { + audioFrame = await getAudioFileData(f, audioContext); + } catch (e) { + writeMessage(`Failed to read audio file '${f.name}'. Error: ${e}`); + return; + } + + try { + const result = await profiler.enroll(audioFrame); + updateSpeakerProgress( + speakerProfiles.length + 1, + result.feedback, + result.percentage, + ); + percentage = result.percentage; + } catch (e) { + writeMessage(`Failed to enroll using '${f.name}'. Error: ${e}`); + return; + } } - } - if (percentage < 100) { - writeMessage(`Speaker is only ${percentage}% done enrollment. ` + - `Please choose a larger data set and try again.`); - enrollFailUI(); - return; - } + if (percentage < 100) { + writeMessage( + `Speaker is only ${percentage}% done enrollment. ` + + `Please choose a larger data set and try again.`, + ); + enrollFailUI(); + return; + } - try { - const profile = await profiler.export(); - speakerProfiles.push(profile); - enrollSuccessUI(); - writeMessage(`Enrollment for Speaker ${speakerProfiles.length} complete! ` + - `You can begin testing or enroll another speaker.`); - } catch (e) { - writeMessage(`Failed to enroll speaker. Error: ${e}`); - } - }); -} + try { + const profile = await profiler.export(); + speakerProfiles.push(profile); + enrollSuccessUI(); + writeMessage( + `Enrollment for Speaker ${speakerProfiles.length} complete! ` + + `You can begin testing or enroll another speaker.`, + ); + } catch (e) { + writeMessage(`Failed to enroll speaker. Error: ${e}`); + } + }); +}; async function getAudioFileData(audioFile, audioContext) { const dataBuffer = await audioFile.arrayBuffer(); @@ -75,12 +85,12 @@ async function getAudioFileData(audioFile, audioContext) { const INT16_MAX = 32767; const INT16_MIN = -32768; i16PCM.set( - f32PCM.map((f) => { - let i = Math.trunc(f * INT16_MAX); - if (f > INT16_MAX) i = INT16_MAX; - if (f < INT16_MIN) i = INT16_MIN; - return i; - }) + f32PCM.map((f) => { + let i = Math.trunc(f * INT16_MAX); + if (f > INT16_MAX) i = INT16_MAX; + if (f < INT16_MIN) i = INT16_MIN; + return i; + }), ); return i16PCM; } @@ -110,9 +120,15 @@ const micEnrollEngine = { return; } - updateSpeakerProgress(speakerProfiles.length + 1, result.feedback, result.percentage); + updateSpeakerProgress( + speakerProfiles.length + 1, + result.feedback, + result.percentage, + ); if (result.percentage === 100) { - await window.WebVoiceProcessor.WebVoiceProcessor.unsubscribe(micEnrollEngine); + await window.WebVoiceProcessor.WebVoiceProcessor.unsubscribe( + micEnrollEngine, + ); clearInterval(timer); micEnrollStopUI(); @@ -120,8 +136,10 @@ const micEnrollEngine = { const profile = await profiler.export(); speakerProfiles.push(profile); enrollSuccessUI(); - writeMessage(`Enrollment for Speaker ${speakerProfiles.length} complete! ` + - `You can begin testing or enroll another speaker.`); + writeMessage( + `Enrollment for Speaker ${speakerProfiles.length} complete! ` + + `You can begin testing or enroll another speaker.`, + ); } catch (e) { writeMessage(`Failed to enroll speaker. Error: ${e}`); } @@ -133,8 +151,8 @@ const micEnrollEngine = { } break; } - } -} + }, +}; async function micEnrollStart() { currentTimer = 0.0; @@ -148,12 +166,15 @@ async function micEnrollStart() { return; } - writeMessage("Keep speaking continuously until enrollment progress reaches 100%."); + writeMessage( + "Keep speaking continuously until enrollment progress reaches 100%.", + ); try { await window.WebVoiceProcessor.WebVoiceProcessor.subscribe(micEnrollEngine); timer = setInterval(() => { currentTimer += 0.1; - document.getElementById("displayTimer").innerText = `${currentTimer.toFixed(1)}`; + document.getElementById("displayTimer").innerText = + `${currentTimer.toFixed(1)}`; }, 100); } catch (e) { writeMessage(e); @@ -175,9 +196,10 @@ function writeMessage(message) { } function updateSpeakerProgress(speakerId, feedback, progress) { - const feedbackMsg = getFeedbackMessage(feedback) + const feedbackMsg = getFeedbackMessage(feedback); console.log(progress, feedbackMsg); - document.getElementById(`speaker${speakerId}Feedback`).innerHTML = ` ${feedbackMsg}`; + document.getElementById(`speaker${speakerId}Feedback`).innerHTML = + ` ${feedbackMsg}`; document.getElementById(`speaker${speakerId}Progress`).value = progress; } @@ -207,19 +229,19 @@ function updateSpeakerTable() { } for (let i = 0; i < speakerProfiles.length; i++) { speakerTable.append(createSpeakerRow(i + 1, 100)); - speakerTable.append(document.createElement("br")) + speakerTable.append(document.createElement("br")); } } function createSpeakerRow(i, initialProgress) { const div = document.createElement("div"); - div.textContent = `Speaker ${i} ` + div.textContent = `Speaker ${i} `; const speakerProgress = document.createElement("progress"); speakerProgress.max = 100; speakerProgress.value = initialProgress; - speakerProgress.id = `speaker${i}Progress` + speakerProgress.id = `speaker${i}Progress`; const speakerFeedback = document.createElement("span"); - speakerFeedback.id = `speaker${i}Feedback` + speakerFeedback.id = `speaker${i}Feedback`; div.appendChild(speakerProgress); div.appendChild(speakerFeedback); return div; @@ -229,14 +251,17 @@ function newEnrollmentUI() { updateSpeakerTable(); document.getElementById("testContainer").style.display = "block"; document.getElementById("feedbackText").innerHTML = ""; - document.getElementById("speakersTable").append(createSpeakerRow(speakerProfiles.length + 1, 0)); - document.getElementById("speakersTable").append(document.createElement("br")) + document + .getElementById("speakersTable") + .append(createSpeakerRow(speakerProfiles.length + 1, 0)); + document.getElementById("speakersTable").append(document.createElement("br")); document.getElementById("testStartBtn").disabled = true; document.getElementById("resetBtn").disabled = true; } function enrollFailUI() { - document.getElementById("testStartBtn").disabled = speakerProfiles.length === 0; + document.getElementById("testStartBtn").disabled = + speakerProfiles.length === 0; document.getElementById("resetBtn").disabled = speakerProfiles.length === 0; } @@ -281,15 +306,13 @@ function micTestStopUI() { async function startEagleProfiler(accessKey) { writeMessage("Eagle is loading. Please wait..."); try { - profiler = await EagleWeb.EagleProfilerWorker.create( - accessKey, - { - base64: modelParams, - forceWrite: true - }); + profiler = await EagleWeb.EagleProfilerWorker.create(accessKey, { + base64: modelParams, + forceWrite: true, + }); writeMessage(""); - document.getElementById('enrollContainer').style.display = "block"; + document.getElementById("enrollContainer").style.display = "block"; } catch (e) { writeMessage(`Failed to initialize Eagle. Error: ${e}`); } @@ -302,7 +325,7 @@ const micTestEngine = { if (ENABLE_AUDIO_DUMP) { dumpAudio = dumpAudio.concat(event.data.inputFrame); } - let scores + let scores; try { scores = await eagle.process(event.data.inputFrame); } catch (e) { @@ -315,21 +338,21 @@ const micTestEngine = { } break; } - } -} + }, +}; async function startEagle(accessKey) { writeMessage("Eagle is loading. Please wait..."); micTestStartUI(); try { eagle = await EagleWeb.EagleWorker.create( - accessKey, - { - base64: modelParams, - forceWrite: true - }, - speakerProfiles); - + accessKey, + { + base64: modelParams, + forceWrite: true, + }, + speakerProfiles, + ); } catch (e) { writeMessage(`Failed to initialize Eagle. Error: ${e}`); return; @@ -345,7 +368,9 @@ async function startEagle(accessKey) { for (let i = 0; i < speakerProfiles.length; i++) { updateSpeakerScore(i + 1, 0); } - writeMessage("Take turns speaking sentences and see if Eagle can recognize which speaker is talking"); + writeMessage( + "Take turns speaking sentences and see if Eagle can recognize which speaker is talking", + ); try { await window.WebVoiceProcessor.WebVoiceProcessor.subscribe(micTestEngine); } catch (e) { @@ -371,7 +396,7 @@ async function stopEagle() { writeMessage(""); if (ENABLE_AUDIO_DUMP) { - downloadDumpAudio('test.pcm'); + downloadDumpAudio("test.pcm"); } } @@ -385,9 +410,9 @@ function resetSpeakers() { function downloadDumpAudio(fileName) { let blob = new Blob(dumpAudio); dumpAudio = []; - let a = document.createElement('a'); + let a = document.createElement("a"); a.download = fileName; a.href = window.URL.createObjectURL(blob); a.click(); document.removeChild(a); -} \ No newline at end of file +} diff --git a/demo/web/yarn.lock b/demo/web/yarn.lock index 27ab4dd6..3b1576dd 100644 --- a/demo/web/yarn.lock +++ b/demo/web/yarn.lock @@ -235,6 +235,11 @@ portfinder@^1.0.28: debug "^3.2.7" mkdirp "^0.5.6" +prettier@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.1.tgz#22fac9d0b18c0b92055ac8fb619ac1c7bef02fb7" + integrity sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw== + qs@^6.4.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"