WindowsRegedit's picture
Duplicate from hf4all/bingo
2ea5479
raw
history blame contribute delete
No virus
2.11 kB
import { sleep } from './utils'
const synth = window.speechSynthesis
export class TTS {
currentText = ''
speakText = ''
private controller = new AbortController()
speaking = false
get isSpeaking() {
return this.speaking
}
finished = false
constructor() {}
abort = () => {
this.controller.abort()
}
reset = () => {
this.speaking = false
this.finished = true
this.currentText = ''
this.speakText = ''
this.abort()
}
speak = (text: string) => {
if (!synth || text?.trim()?.length < 2) {
return
}
this.currentText = text.replace(/[^\u4e00-\u9fa5_a-zA-Z0-9,。?,:;\.,:]+/g, '')
this.finished = false
this.loop()
}
private async doSpeek() {
return new Promise((resolve) => {
const endIndex = this.finished ? this.currentText.length :
Math.max(
this.currentText.lastIndexOf('。'),
this.currentText.lastIndexOf(';'),
this.currentText.lastIndexOf('、'),
this.currentText.lastIndexOf('?'),
this.currentText.lastIndexOf('\n')
)
const startIndex = this.speakText.length ? Math.max(0, this.currentText.lastIndexOf(this.speakText) + this.speakText.length) : 0
if (startIndex >= endIndex) {
return resolve(true)
}
const text = this.currentText.slice(startIndex, endIndex)
this.speakText = text
const utterThis = new SpeechSynthesisUtterance(text)
this.controller.signal.onabort = () => {
synth.cancel()
this.finished = true
resolve(false)
}
utterThis.onend = function (event) {
resolve(true)
}
utterThis.onerror = function (event) {
resolve(false)
}
const voice = synth.getVoices().find(v => v.name.includes('Microsoft Yunxi Online')) ?? null
utterThis.voice = voice
synth.speak(utterThis)
})
}
private async loop() {
if (this.speaking) return
this.speaking = true
while(!this.finished) {
await Promise.all([sleep(1000), this.doSpeek()])
}
this.speaking = false
}
}