SilverStarShadow's picture
Duplicate from hf4all/bingo
15bfa8d
// @ts-ignore
const SpeechRecognitionPolyfill: typeof webkitSpeechRecognition = typeof window !== 'undefined' ? (
// @ts-ignore
window.SpeechRecognition ||
window.webkitSpeechRecognition ||
// @ts-ignore
window.mozSpeechRecognition ||
// @ts-ignore
window.msSpeechRecognition ||
// @ts-ignore
window.oSpeechRecognition
) as typeof webkitSpeechRecognition : undefined
type subscriber = (msg: string, command?: string) => void
export class SR {
recognition?: SpeechRecognition
onchange?: subscriber
transcript: boolean = false
listening: boolean = false
private commandsRe?: RegExp
constructor(commands: string[]) {
this.recognition = SpeechRecognitionPolyfill ? new SpeechRecognitionPolyfill() : undefined
if (!this.recognition) {
return
}
this.configuration('zh-CN')
if (commands.length) {
this.commandsRe = new RegExp(`^(${commands.join('|')})。?$`)
}
this.recognition.onresult = this.speechRecognition
this.recognition.onerror = (err) => {
console.log('err', err.error)
this.stop()
}
this.recognition.onend = () => {
if (this.recognition && this.listening) {
this.recognition.start()
}
}
}
speechRecognition = (event: SpeechRecognitionEvent) => {
if (!this.listening) return
for (var i = event.resultIndex; i < event.results.length; i++) {
let result = event.results[i]
if (result.isFinal) {
var alt = result[0]
const text = alt.transcript.trim()
if (this.commandsRe && this.commandsRe.test(text)) {
return this.onchange?.('', RegExp.$1)
}
if (!this.transcript) return
this.onchange?.(text)
}
}
}
private configuration = async (lang: string = 'zh-CN') => {
return new Promise((resolve) => {
if (this.recognition) {
this.recognition.continuous = true
this.recognition.lang = lang
this.recognition.onstart = resolve
}
})
}
start = async () => {
if (this.recognition && !this.listening) {
await this.recognition.start()
this.transcript = true
this.listening = true
}
}
stop = () => {
if (this.recognition) {
this.recognition.stop()
this.transcript = false
this.listening = false
}
}
pause = () => {
if (this.recognition) {
this.transcript = false
}
}
resume = () => {
if (this.recognition) {
this.transcript = true
}
}
abort = () => {
if (this.recognition && this.transcript) {
this.recognition.abort()
this.transcript = false
this.listening = false
}
}
}