Reputation: 5045
I am trying to use SpeechSynthesis and SpeechRecognition to create a mini version of a chatbot. Basically what I want is to start text to speech. Once that is done, I want to listen to what the user says ( speech to text ) and then speak the users text back. This is the code I have:
speak("Say something");
var spokenWord=hear();
speak(spokenWord);
function speak(message) {
var synth = window.speechSynthesis;
var utterThis = new SpeechSynthesisUtterance(message);
synth.speak(utterThis);
utterThis.onend = function (event) {
console.log('Utterance has finished being spoken after ' + event.elapsedTime + ' milliseconds.');
}
}
function hear() {
var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
var recognition = new SpeechRecognition();
recognition.start();
recognition.onresult = function (event) {
var current = event.resultIndex;
var transcript = event.results[current][0].transcript;
console.log(transcript);
recognition.stop();
return transcript;
}
}
Since these methods are asynchronous, it is not working the way I expect it to work. The second speak runs before hear completes. Any suggestions how to fix this?
Upvotes: 3
Views: 2339
Reputation: 1305
The trick is wrapping it up in promises and using await and async.
main();
async function main() {
await speak("Say something");
var spokenWord = await hear();
await speak(spokenWord);
}
async function speak(message) {
return new Promise((resolve, reject) => {
var synth = window.speechSynthesis;
var utterThis = new SpeechSynthesisUtterance(message);
synth.speak(utterThis);
utterThis.onend = resolve;
});
}
async function hear() {
return new Promise((resolve, reject) => {
var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
var recognition = new SpeechRecognition();
recognition.start();
recognition.onresult = function (event) {
var current = event.resultIndex;
var transcript = event.results[current][0].transcript;
console.log(transcript);
recognition.stop();
resolve(transcript);
}
});
}
Upvotes: 2
Reputation: 12808
In my case, window.speechSynthesis.speaking
stayed true long after the speech was done. I noticed this is only a problem with voices that have localService: true
. So if you can avoid those - your onend
will be called.
Upvotes: 0
Reputation: 2285
async function waitUntil(check: () => boolean, intervalPeriodMs = 300): Promise<void> {
if (check()) {
return
}
return new Promise((resolve, reject) => {
const wait = setInterval(() => {
try {
if (check()) {
clearInterval(wait)
resolve()
}
} catch (err) {
clearInterval(wait)
reject(err)
}
}, intervalPeriodMs)
})
}
await waitUntil(() => !window.speechSynthesis.speaking, 300)
Upvotes: 0