UNPKG

@ng-web-apis/speech

Version:
193 lines (176 loc) 8.53 kB
import * as i0 from '@angular/core'; import { inject, EventEmitter, Directive, Input, Output, Pipe, InjectionToken, LOCALE_ID, NgZone, Injectable } from '@angular/core'; import { SPEECH_SYNTHESIS, WA_SPEECH_RECOGNITION, SPEECH_RECOGNITION } from '@ng-web-apis/common'; import { filter, scan, map, pipe, skipWhile, takeWhile, Observable, fromEvent, startWith } from 'rxjs'; class WaTextToSpeech { speechSynthesisRef = inject(SPEECH_SYNTHESIS); paused = false; onerror = new EventEmitter(); onend = new EventEmitter(); onmark = new EventEmitter(); onboundary = new EventEmitter(); set waTextToSpeech(utterance) { this.speechSynthesisRef.cancel(); this.speechSynthesisRef.pause(); utterance.onerror = (e) => this.onerror.emit(e); utterance.onend = (e) => this.onend.emit(e); utterance.onmark = (e) => this.onmark.emit(e); utterance.onboundary = (e) => this.onboundary.emit(e); this.speechSynthesisRef.speak(utterance); } ngOnChanges() { if (this.paused) { this.speechSynthesisRef.pause(); } else { this.speechSynthesisRef.resume(); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WaTextToSpeech, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: WaTextToSpeech, isStandalone: true, selector: "[waTextToSpeech]", inputs: { paused: ["waTextToSpeechPaused", "paused"], waTextToSpeech: "waTextToSpeech" }, outputs: { onerror: "waTextToSpeechError", onend: "waTextToSpeechEnd", onmark: "waTextToSpeechMark", onboundary: "waTextToSpeechBoundary" }, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: WaTextToSpeech, decorators: [{ type: Directive, args: [{ standalone: true, selector: '[waTextToSpeech]', }] }], propDecorators: { paused: [{ type: Input, args: ['waTextToSpeechPaused'] }], onerror: [{ type: Output, args: ['waTextToSpeechError'] }], onend: [{ type: Output, args: ['waTextToSpeechEnd'] }], onmark: [{ type: Output, args: ['waTextToSpeechMark'] }], onboundary: [{ type: Output, args: ['waTextToSpeechBoundary'] }], waTextToSpeech: [{ type: Input }] } }); /** * @deprecated: use {@link WaTextToSpeech} */ const TextToSpeechDirective = WaTextToSpeech; class UtterancePipe { transform(text, { lang = '', pitch = 1, rate = 1, volume = 1, voice = null, } = {}) { const utterance = new SpeechSynthesisUtterance(text); utterance.lang = lang; utterance.pitch = pitch; utterance.rate = rate; utterance.volume = volume; utterance.voice = voice; // Strange TS issue will not allow null here return utterance; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtterancePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: UtterancePipe, isStandalone: true, name: "waUtterance" }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UtterancePipe, decorators: [{ type: Pipe, args: [{ standalone: true, name: 'waUtterance', }] }] }); function confidenceAbove(threshold) { return filter(({ confidence }) => confidence > threshold); } function continuous() { return scan((result, current) => [ ...result.filter(({ isFinal }) => isFinal), ...current, ], []); } function final() { return map((results) => results.filter(({ isFinal }) => isFinal)); } function firstAlternative() { // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain return map((result) => result[0]?.[0]); } function isSaid(phrase) { const lowercased = phrase.toLowerCase().trim(); return (results) => !!results.find((result) => result.isFinal && result[0]?.transcript.toLowerCase().trim() === lowercased); } function skipUntilSaid(text) { const predicate = isSaid(text); return pipe(skipWhile((results) => !predicate(results)), map((value, index) => (index ? value : []))); } function takeUntilSaid(text) { const predicate = isSaid(text); return takeWhile((results) => !predicate(results)); } const WA_SPEECH_RECOGNITION_MAX_ALTERNATIVES = new InjectionToken('[WA_SPEECH_RECOGNITION_MAX_ALTERNATIVES]', { factory: () => 1, }); /** * @deprecated: drop in v5.0, use {@link WA_SPEECH_RECOGNITION_MAX_ALTERNATIVES} */ const SPEECH_RECOGNITION_MAX_ALTERNATIVES = WA_SPEECH_RECOGNITION_MAX_ALTERNATIVES; class SpeechRecognitionService extends Observable { classRef = inject(WA_SPEECH_RECOGNITION); lang = inject(LOCALE_ID, { optional: true }); maxAlternatives = inject(WA_SPEECH_RECOGNITION_MAX_ALTERNATIVES); ngZone = inject(NgZone); constructor() { super((subscriber) => { if (!this.classRef) { subscriber.error(new Error('SpeechRecognition is not supported')); return () => { }; } // eslint-disable-next-line new-cap const speechRecognition = new this.classRef(); speechRecognition.maxAlternatives = this.maxAlternatives; speechRecognition.lang = this.lang ?? ''; speechRecognition.interimResults = true; speechRecognition.onerror = (error) => subscriber.error(error); speechRecognition.onend = () => subscriber.complete(); speechRecognition.onresult = ({ results }) => this.ngZone.run(() => subscriber.next(Array.from({ length: results.length }, (_, i) => results[i]))); speechRecognition.start(); return () => speechRecognition.abort(); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpeechRecognitionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpeechRecognitionService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpeechRecognitionService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: function () { return []; } }); const WA_SPEECH_RECOGNITION_SUPPORT = new InjectionToken('[WA_SPEECH_RECOGNITION_SUPPORT]', { factory: () => !!inject(SPEECH_RECOGNITION), }); /** * @deprecated: drop in v5.0, use {@link WA_SPEECH_RECOGNITION_SUPPORT} */ const SPEECH_RECOGNITION_SUPPORT = WA_SPEECH_RECOGNITION_SUPPORT; const WA_SPEECH_SYNTHESIS_SUPPORT = new InjectionToken('[WA_SPEECH_SYNTHESIS_SUPPORT]', { factory: () => !!inject(SPEECH_SYNTHESIS), }); /** * @deprecated: drop in v5.0, use {@link WA_SPEECH_SYNTHESIS_SUPPORT} */ const SPEECH_SYNTHESIS_SUPPORT = WA_SPEECH_SYNTHESIS_SUPPORT; const WA_SPEECH_SYNTHESIS_VOICES = new InjectionToken('[WA_SPEECH_SYNTHESIS_VOICES]', { factory: () => { const speechSynthesisRef = inject(SPEECH_SYNTHESIS); return fromEvent(speechSynthesisRef, 'voiceschanged').pipe(startWith(null), map(() => speechSynthesisRef.getVoices())); }, }); /** * @deprecated: drop in v5.0, use {@link WA_SPEECH_SYNTHESIS_VOICES} */ const SPEECH_SYNTHESIS_VOICES = WA_SPEECH_SYNTHESIS_VOICES; /** * Generated bundle index. Do not edit. */ export { SPEECH_RECOGNITION_MAX_ALTERNATIVES, SPEECH_RECOGNITION_SUPPORT, SPEECH_SYNTHESIS_SUPPORT, SPEECH_SYNTHESIS_VOICES, SpeechRecognitionService, TextToSpeechDirective, UtterancePipe, WA_SPEECH_RECOGNITION_MAX_ALTERNATIVES, WA_SPEECH_RECOGNITION_SUPPORT, WA_SPEECH_SYNTHESIS_SUPPORT, WA_SPEECH_SYNTHESIS_VOICES, WaTextToSpeech, confidenceAbove, continuous, final, firstAlternative, isSaid, skipUntilSaid, takeUntilSaid }; //# sourceMappingURL=ng-web-apis-speech.mjs.map