Skip to content

Commit

Permalink
feat: speech hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
liou666 committed Mar 31, 2023
1 parent adcbeae commit 0177d31
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 3 deletions.
6 changes: 4 additions & 2 deletions src/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,14 @@ declare global {
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
const useScroll: typeof import('@vueuse/core')['useScroll']
const useScroll: typeof import('./hooks/useScroll')['useScroll']
const useScrollLock: typeof import('@vueuse/core')['useScrollLock']
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
const useShare: typeof import('@vueuse/core')['useShare']
const useSlots: typeof import('vue')['useSlots']
const useSorted: typeof import('@vueuse/core')['useSorted']
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
const useSpeechService: typeof import('./hooks/useSpeechService')['useSpeechService']
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
const useStepper: typeof import('@vueuse/core')['useStepper']
const useStorage: typeof import('@vueuse/core')['useStorage']
Expand Down Expand Up @@ -499,13 +500,14 @@ declare module 'vue' {
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']>
readonly useScroll: UnwrapRef<typeof import('@vueuse/core')['useScroll']>
readonly useScroll: UnwrapRef<typeof import('./hooks/useScroll')['useScroll']>
readonly useScrollLock: UnwrapRef<typeof import('@vueuse/core')['useScrollLock']>
readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']>
readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']>
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
readonly useSorted: UnwrapRef<typeof import('@vueuse/core')['useSorted']>
readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']>
readonly useSpeechService: UnwrapRef<typeof import('./hooks/useSpeechService')['useSpeechService']>
readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']>
readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']>
readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']>
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.ts → src/hooks/useScroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ export function useScroll<T extends HTMLElement=HTMLElement>() {
scrollTo,
}
}

90 changes: 90 additions & 0 deletions src/hooks/useSpeechService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type { VoiceInfo } from 'microsoft-cognitiveservices-speech-sdk'
import {
AudioConfig,
SpeechConfig,
SpeechRecognizer,
SpeechSynthesizer,
} from 'microsoft-cognitiveservices-speech-sdk'

export const useSpeechService = (subscriptionKey: string, region: string) => {
const language = ref('en-US')
const voiceName = ref('en-US-GuyNeural')
const speechConfig = SpeechConfig.fromSubscription(subscriptionKey, region)
const isRecognizing = ref(false)

const audioConfig = AudioConfig.fromDefaultMicrophoneInput()
const recognizer = new SpeechRecognizer(speechConfig, audioConfig)
const synthesizer = new SpeechSynthesizer(speechConfig)

watch([language, voiceName], ([lang, voice]) => {
speechConfig.speechRecognitionLanguage = lang
speechConfig.speechSynthesisLanguage = lang
speechConfig.speechSynthesisVoiceName = voice
}, {
immediate: true,
})

// 语音识别
const startRecognizeSpeech = () => {
isRecognizing.value = true
recognizer.startContinuousRecognitionAsync()
}

// 停止语音识别
const stopRecognizeSpeech = (): Promise<string> => {
return new Promise((resolve, reject) => {
recognizer.recognized = (s, e) => {
recognizer.stopContinuousRecognitionAsync()
isRecognizing.value = false
resolve(e.result.text)
}
})
}

// 识别一次,无需取消
const recognizeSpeech = (): Promise<string> => {
isRecognizing.value = true
return new Promise((resolve, reject) => {
recognizer.recognizeOnceAsync((result) => {
if (result.text) {
isRecognizing.value = false
resolve(result.text)
}
else {
isRecognizing.value = false
reject(new Error('语音识别失败'),
)
}
})
})
}

// 语音合成
const textToSpeak = async (text: string, voice?: string) => {
speechConfig.speechSynthesisVoiceName = voice || speechConfig.speechSynthesisVoiceName
synthesizer.speakTextAsync(text)
}

// 停止语音合成
const stopTextToSpeak = () => {
synthesizer.close()
}

// 获取语音列表
const getVoices = async (): Promise<VoiceInfo[]> => {
const res = await synthesizer.getVoicesAsync()
return res.voices
}

return {
language,
voiceName,
isRecognizing,
startRecognizeSpeech,
stopRecognizeSpeech,
recognizeSpeech,
textToSpeak,
stopTextToSpeak,
getVoices,
}
}
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import './samples/node-api'
const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app
.use(pinia)
.mount('#app')
.$nextTick(() => {
postMessage({ payload: 'removeLoading' }, '*')
Expand Down
3 changes: 3 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ export default defineConfig(({ command }) => {
],
dts: 'src/auto-imports.d.ts',
vueTemplate: true,
dirs: [
'src/hooks',
],
}),
Unocss(),
// Use Node.js API in the Renderer-process
Expand Down

0 comments on commit 0177d31

Please sign in to comment.