observer / src /app /useStore.ts
jbilcke-hf's picture
jbilcke-hf HF staff
fixed some issues
1896b82
"use client"
import { getSpeechSynthesisVoice } from "@/lib/getSpeechSynthesisVoice"
import { create } from "zustand"
export const useStore = create<{
isSpeechSynthesisAvailable: boolean
speechSynthesis: SpeechSynthesis
speechSynthesisVoice: SpeechSynthesisVoice
isSpeaking: boolean
lastSpokenSentence: string
isHearing: boolean // robot is hearing
init: () => void,
loadVoice: () => void,
speak: (sentence: string) => void
setHearing: (isHearing: boolean) => void
}>((set, get) => ({
isSpeechSynthesisAvailable: false,
speechSynthesis: undefined as unknown as SpeechSynthesis,
speechSynthesisVoice: undefined as unknown as SpeechSynthesisVoice,
isSpeaking: false,
lastSpokenSentence: "",
isHearing: false, // robot is taking
init: () => {
if (!window?.speechSynthesis) {
console.error(`no speech synthesis engine available`)
return
}
const speechSynthesis = window.speechSynthesis
set({ speechSynthesis })
speechSynthesis.onvoiceschanged = () => { get().loadVoice() }
setTimeout(() => {
get().loadVoice()
}, 2000)
// due to the lack of event for the speaking state, we create our own polling system
// see https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis/speaking
setInterval(() => {
const { isSpeaking } = get()
if (!speechSynthesis.speaking && isSpeaking) {
set({ isSpeaking: false })
} else if (speechSynthesis.speaking && !isSpeaking) {
set({ isSpeaking: true })
}
}, 100)
},
loadVoice: () => {
let { speechSynthesis, speechSynthesisVoice } = get()
if (!speechSynthesis) {
console.error(`no speech synthesis engine available`)
return
}
try {
speechSynthesisVoice = getSpeechSynthesisVoice(speechSynthesis)
if (!speechSynthesisVoice?.name) {
throw new Error("no name for the voice")
}
} catch (err) {
console.error(`no speech synthesis voice available: ${err}`)
return
}
if (speechSynthesisVoice) {
set({ speechSynthesisVoice, isSpeechSynthesisAvailable: true })
}
},
speak: (sentence: string) => {
const { speechSynthesis, speechSynthesisVoice } = get()
if (!speechSynthesis || !speechSynthesisVoice) { return }
speechSynthesis.cancel()
const utterance = new SpeechSynthesisUtterance(sentence)
utterance.voice = speechSynthesisVoice
speechSynthesis.speak(utterance)
set({ lastSpokenSentence: sentence })
},
setHearing: (isHearing: boolean) => { set({ isHearing }) },
}))