import { defaults } from 'lodash-es';
|
|
type SpeechSynthesisOptions = {
|
/** Language code for speech synthesis (e.g. 'en-US', 'zh-CN') */
|
lang?: string;
|
/** Pitch of the speaking voice (between 0 and 2, default is 1) */
|
pitch?: number;
|
/** Speed rate of speech (between 0.1 and 10, default is 1) */
|
rate?: number;
|
/** Volume of speech (between 0 and 1, default is 1) */
|
volume?: number;
|
};
|
|
class BrowserSpeechSynthesis {
|
private static instance: BrowserSpeechSynthesis;
|
private synthesis: SpeechSynthesisUtterance;
|
private synth: typeof window.speechSynthesis;
|
|
private constructor() {
|
if (!window.speechSynthesis || !window.SpeechSynthesisUtterance) {
|
throw new Error('Speech synthesis is not supported in this browser');
|
}
|
this.synthesis = new SpeechSynthesisUtterance();
|
this.synth = window.speechSynthesis;
|
}
|
|
public static getInstance(): BrowserSpeechSynthesis {
|
if (!BrowserSpeechSynthesis.instance) {
|
BrowserSpeechSynthesis.instance = new BrowserSpeechSynthesis();
|
}
|
return BrowserSpeechSynthesis.instance;
|
}
|
|
public speak(text: string, options?: SpeechSynthesisOptions): void {
|
if (options) {
|
const { lang, pitch, rate, volume } = defaults(options, {
|
lang: 'zh-CN',
|
pitch: 1,
|
rate: 1,
|
volume: 1,
|
});
|
this.synthesis.lang = lang;
|
this.synthesis.pitch = pitch;
|
this.synthesis.rate = rate;
|
this.synthesis.volume = volume;
|
}
|
|
this.synthesis.text = text;
|
this.synth.speak(this.synthesis);
|
}
|
|
public onEnd(callback: () => void): void {
|
this.synthesis.addEventListener('end', callback);
|
}
|
|
// 移除事件监听
|
public off(callback: () => void): void {
|
this.synth.removeEventListener('end', callback);
|
}
|
|
public pause(): void {
|
this.synth.pause();
|
}
|
|
public resume(): void {
|
this.synth.resume();
|
}
|
|
public cancel(): void {
|
this.synth.cancel();
|
}
|
|
public getVoices(): SpeechSynthesisVoice[] {
|
return this.synth.getVoices();
|
}
|
}
|
|
export default BrowserSpeechSynthesis;
|