Spaces:
Runtime error
Runtime error
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 | |
} | |
} | |