I'm using SpeechRecognition in the browser and I've created a speech service:
this.recognition.addEventListener('result', (e) => {
if (e.results) {
let result = e.results[e.resultIndex];
console.log('Final? ' result.isFinal);
let _transcript = result[0].transcript;
let _confidence = result[0].confidence;
if (result.isFinal) {
console.log('Final result: ' _transcript);
this.finalText = _transcript; // <---------------- FinalText updated
} else {
console.log('Confidence? ' _confidence);
if (_confidence > 0.6) {
this.finalText = _transcript; // <---------------- FinalText updated
}
}
}
});
Inside my service I have a start()
function that returns a promise with the finalText string
but my current method of checking if finalText
was updated is just not right.
return new Promise(async (resolve, reject) => {
let i = 0;
for (i = 0; i < 100; i ) {
// Keep checking for final text to update
if (this.finalText != null) {
console.log('Final text submitting response');
this.finalText = null;
return resolve('Success');
} else {
console.log('waiting');
if (this.isStoppedSpeech) { // True if we clicked stop() or if the 'end' event listener fires
return reject('Timeout');
}
}
await new Promise((r) => setTimeout(r, 500)); // sleep
}
}).catch((error) => {
console.error(error); // Timeout
this.stop();
});
All I want to do is return when this.FinalText
has text. I was thinking perhaps I should subscribe to it somehow and then await this.FinalText
. I just need the promise to work properly.
Example usage:
this.speech.start().then((s) => {
console.log('Done speaking');
if (this.speech.getLastPhrase() != null)
this.pushChat({
speak: this.speech.getLastPhrase()
});
});
I do not want to use setTimeout
or setInterval
. How can I await for this.FinalText
then return the value inside of my start() function promise
?
CodePudding user response:
This seems like a good use case for an RXJS subject
. It is an observable from which you can emit values on demand.
Instantiate final text as a Subject
and call .next()
when you want to emit a value.
finalText = new Subject<string>();
this.recognition.addEventListener('result', (e: any) => {
if (e.results) {
let result = e.results[e.resultIndex];
console.log('Final? ' result.isFinal);
let _transcript = result[0].transcript;
let _confidence = result[0].confidence;
if (result.isFinal) {
console.log('Final result: ' _transcript);
this.finalText.next(_transcript); // <---------------- FinalText updated
} else {
console.log('Confidence? ' _confidence);
if (_confidence > 0.6) {
this.finalText.next(_transcript); // <---------------- FinalText updated
}
}
}
});
You can subscribe to the Subject
to execute code on each .next()
call:
this.finalText.subscribe((text) => {
console.log('Done speaking');
if (text)
this.pushChat({
speak: text,
});
});
you can also use Angular's async
pipe to update the value in html automatically.
<p>{{ finalText | async }}</p>
You should definitely look into the rxjs library / observables. You basically made a primitive version of an observable with your start()
function.