wujingjing
2025-04-02 a040c54c99825755c0b210c5dca39898b68e3db1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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;