Skip to content

Commit

Permalink
feat: 增加语音识别快捷键 (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
liou666 committed Apr 23, 2023
1 parent 7e51d57 commit 42a0d02
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 29 deletions.
37 changes: 26 additions & 11 deletions src/hooks/useSpeechService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { VoiceInfo } from 'microsoft-cognitiveservices-speech-sdk'
import {
AudioConfig,
CancellationErrorCode,
SpeakerAudioDestination,
SpeechConfig,
SpeechRecognizer,
Expand All @@ -23,7 +24,7 @@ export const useSpeechService = ({ langs = <const>['fr-FR', 'ja-JP', 'en-US', 'z
const isRecognizing = ref(false) // 语音识别中
const isSynthesizing = ref(false) // 语音合成中
const isSynthesError = ref(false) // 语音失败

const isRecognizReadying = ref(false) // 语音合成准备中
const isPlaying = ref(false) // 语音播放中
const isPlayend = ref(false) // 语音播放结束

Expand Down Expand Up @@ -51,11 +52,10 @@ export const useSpeechService = ({ langs = <const>['fr-FR', 'ja-JP', 'en-US', 'z
isPlayend.value = false
console.log('playback started')
}
console.log(player.isClosed)
player.onAudioEnd = function (_) {
console.log('playback finished')
isPlaying.value = false
isPlayend.value = true
console.log('playback finished')
}

const audioConfig = AudioConfig.fromDefaultMicrophoneInput()
Expand All @@ -68,8 +68,18 @@ export const useSpeechService = ({ langs = <const>['fr-FR', 'ja-JP', 'en-US', 'z

// 语音识别
const startRecognizeSpeech = () => {
isRecognizReadying.value = true
recognizer.value.canceled = (s, e) => {
if (e.errorCode === CancellationErrorCode.AuthenticationFailure)
console.error('Invalid or incorrect subscription key')
else
console.log(`Canceled: ${e.errorDetails}`)
isRecognizReadying.value = false
isRecognizing.value = false
}
recognizer.value.startContinuousRecognitionAsync(() => {
isRecognizing.value = true
isRecognizReadying.value = false
console.log('Recognize...')
},
(error) => {
Expand All @@ -80,14 +90,20 @@ export const useSpeechService = ({ langs = <const>['fr-FR', 'ja-JP', 'en-US', 'z
}

// 停止语音识别
const stopRecognizeSpeech = (): Promise<string> => {
const stopRecognizeSpeech = (cb?: (result: string) => unknown): Promise<void> => {
recognizer.value.canceled = () => {
console.log('Recognize canceled')
}
recognizer.value.recognized = (s, e) => {
console.log('Recognize result: ', e.result.text)
cb && cb(e.result.text)
}
return new Promise((resolve, reject) => {
recognizer.value.recognized = (s, e) => {
console.log('Recognize End')
recognizer.value.stopContinuousRecognitionAsync()
recognizer.value.stopContinuousRecognitionAsync(() => {
console.log('Recognize End:')
isRecognizing.value = false
resolve(e.result.text)
}
resolve()
})
})
}

Expand Down Expand Up @@ -161,8 +177,6 @@ export const useSpeechService = ({ langs = <const>['fr-FR', 'ja-JP', 'en-US', 'z
// 停止语音合成
function stopTextToSpeak() {
isSynthesizing.value = false
isPlaying.value = false
isPlayend.value = true
synthesizer.value.close()
count.value++ // 触发实例的重新创建
}
Expand Down Expand Up @@ -199,6 +213,7 @@ export const useSpeechService = ({ langs = <const>['fr-FR', 'ja-JP', 'en-US', 'z
isRecognizing,
isPlaying,
isPlayend,
isRecognizReadying,
startRecognizeSpeech,
stopRecognizeSpeech,
recognizeSpeech,
Expand Down
56 changes: 38 additions & 18 deletions src/pages/Home/components/Content.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,9 @@ const {
voiceName,
rate,
isRecognizing,
recognizeSpeech,
isPlaying,
isPlayend,
textToSpeak,
startRecognizeSpeech,
stopTextToSpeak,
isRecognizReadying,
stopRecognizeSpeech,
ssmlToSpeak,
isSynthesizing,
Expand All @@ -52,6 +49,22 @@ const currentRate = computed(() => store.getConversationsByCurrentProps('rate'))
useTitle(currentName)
// 设置空格快捷键
useEventListener(document, 'keydown', (e) => {
if (isRecognizing.value || isRecognizReadying.value || e.code !== 'Space') return
message.value = ''
startRecognizeSpeech()
})
useEventListener(document, 'keyup', async (e) => {
if ((!isRecognizing.value && !isRecognizReadying.value) || e.code !== 'Space') return
await stopRecognizeSpeech((textSlice) => {
message.value += textSlice || ''
})
onSubmit()
console.log('submit', message.value)
})
// effects
watch(messageLength, () => nextTick(() => scrollToBottom()))
watch(currentKey, () => {
Expand All @@ -74,7 +87,7 @@ const fetchResponse = async (key: string) => {
return res.choices[0].message.content
}
const onSubmit = async () => {
async function onSubmit() {
if (!verifyOpenKey(openKey.value)) return alert('请输入正确的API-KEY')
if (!message.value) return
Expand Down Expand Up @@ -103,6 +116,7 @@ const onSubmit = async () => {
}
function speak(content: string, index: number) {
console.log(isPlaying.value)
if (isPlaying.value) return
speakIndex.value = index
text.value = content
Expand All @@ -111,17 +125,19 @@ function speak(content: string, index: number) {
const recognize = async () => {
try {
isRecognizing.value = true
store.changeLoading(true)
const result = await recognizeSpeech()
isRecognizing.value = false
store.changeLoading(false)
message.value = result
onSubmit()
console.log('isRecognizing', isRecognizing.value)
if (isRecognizing.value) {
await stopRecognizeSpeech((textSlice) => {
message.value += textSlice || ''
})
onSubmit()
console.log('submit', message.value)
return
}
message.value = ''
startRecognizeSpeech()
}
catch (error) {
isRecognizing.value = false
store.changeLoading(false)
alert(error)
}
}
Expand Down Expand Up @@ -177,7 +193,6 @@ const translate = async (text: string, i: number) => {
<i icon-btn rotate-90 i-ic:sharp-wifi />
</span>
</template>
<span v-if="!isTranslating || translateIndex !== i" ml-1 class="chat-btn" @click="translate(item.content, i)">
<i icon-btn i-carbon:ibm-watson-language-translator />
</span>
Expand All @@ -198,14 +213,19 @@ const translate = async (text: string, i: number) => {
<div class="flex h-10 w-[-webkit-fill-available] mt-1">
<Button
mr-1
:disabled="isRecognizing || store.loading"
:disabled="isRecognizReadying"
@click="recognize()"
>
<i i-carbon:microphone />
<i v-if="isRecognizReadying" i-eos-icons:bubble-loading />
<i v-else i-carbon:microphone />
</Button>
<div v-if="isRecognizing" class="loading-btn">
isRecognizing
识别中,请讲话
<i icon-btn i-eos-icons:three-dots-loading />
</div>
<div v-else-if="isRecognizReadying" class="loading-btn">
录音设备准备中
<i icon-btn i-eos-icons:three-dots-loading />
</div>
<input
Expand Down

0 comments on commit 42a0d02

Please sign in to comment.