Commit 38df065c authored by ali's avatar ali

fix: 优化相关异常处理

parent dff91c47
...@@ -50,10 +50,10 @@ onMounted(() => { ...@@ -50,10 +50,10 @@ onMounted(() => {
}) })
const errorSnackbar = ref<boolean>(false) const errorSnackbar = ref<boolean>(false)
const errorMsg = ref<string>(''); const errorMsg = ref<string>('')
const showError = (msg: string) => { const showError = (msg: string) => {
errorSnackbar.value = true; errorSnackbar.value = true
errorMsg.value = msg; errorMsg.value = msg
} }
function loadImg(): Promise<HTMLImageElement> { function loadImg(): Promise<HTMLImageElement> {
...@@ -77,17 +77,7 @@ async function init() { ...@@ -77,17 +77,7 @@ async function init() {
canvasEle.height = img.naturalHeight canvasEle.height = img.naturalHeight
const item = photo.list.find((i) => i.url === url) const item = photo.list.find((i) => i.url === url)
photoRole = new PhotoRole(settings.liveHost, `${item?.liveUrl}`, canvasEle) photoRole = new PhotoRole(settings.liveHost, `${item?.liveUrl}`, canvasEle)
photoRole.on('asyncAnswer', onAsyncAnswer)
photoRole.on('asyncAnswer', async (ans) => {
if (ans.playState === 'playing') {
microphoneState.value = 'reply'
return
}
if (microphoneState.value === 'reply' && ans.playState === 'pause' && (await checkSteps())) {
microphoneState.value = 'input'
}
})
// initPlayer(videoEle); // initPlayer(videoEle);
...@@ -112,6 +102,17 @@ async function init() { ...@@ -112,6 +102,17 @@ async function init() {
requestAnimationFrame(updateFrame) requestAnimationFrame(updateFrame)
} }
async function onAsyncAnswer(ans: PhotoAnswer) {
if (ans.playState === 'playing') {
microphoneState.value = 'reply'
return
}
if (microphoneState.value === 'reply' && ans.playState === 'pause' && (await checkSteps())) {
microphoneState.value = 'input'
}
}
function draw( function draw(
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,
img: HTMLImageElement, img: HTMLImageElement,
...@@ -273,7 +274,7 @@ async function startVoskWsAudioInput() { ...@@ -273,7 +274,7 @@ async function startVoskWsAudioInput() {
if (microphoneState.value === 'loading') return if (microphoneState.value === 'loading') return
if (microphoneState.value === 'input') { if (microphoneState.value === 'input') {
endAudioInput() await endAudioInput()
return return
} }
...@@ -378,6 +379,9 @@ async function endAudioInput() { ...@@ -378,6 +379,9 @@ async function endAudioInput() {
} }
inputContext.asrPartial = '' inputContext.asrPartial = ''
inputContext.answerArray.length = 0 inputContext.answerArray.length = 0
inputContext.steps.length = 0
// @ts-ignore
photoRole?.off('asyncAnswer', onAsyncAnswer)
await photoRole?.destroy() await photoRole?.destroy()
} }
...@@ -417,73 +421,80 @@ async function onQ(question: string) { ...@@ -417,73 +421,80 @@ async function onQ(question: string) {
microphoneState.value = 'loading' microphoneState.value = 'loading'
const ws = await initLLMSocket() try {
const { pose, stepResolve, stepReject } = createStep() const ws = await initLLMSocket()
const messageTimeout = setTimeout(async () => { const { pose, stepResolve, stepReject } = createStep()
showError('llm:timeout!') const messageTimeout = setTimeout(async () => {
await endAudioInput() showError('llm:timeout!')
microphoneState.value = 'waitInput' await endAudioInput()
}, 5000); microphoneState.value = 'waitInput'
}, 10000)
let sliceAnswer = ''
let answer = '' let sliceAnswer = ''
let isTime = true let answer = ''
let sliceAnswerLength = 10 let isTime = true
let sliceAnswerLength = 10
inputContext.ws = ws
inputContext.answerArray.length = 0 inputContext.ws = ws
inputContext.steps.length = 0 inputContext.answerArray.length = 0
inputContext.steps.push(pose) inputContext.steps.length = 0
photoRole!.answerArgs = new PhotoAnswer() inputContext.steps.push(pose)
photoRole!.answerArgs = new PhotoAnswer()
ws.onmessage = (message) => { photoRole!.on('asyncAnswer', onAsyncAnswer)
try {
const { text, event } = JSON.parse(message.data) as { ws.onmessage = (message) => {
event: string try {
message_num: number const { text, event } = JSON.parse(message.data) as {
text: string event: string
} message_num: number
text: string
if (event === 'stream_end') { }
inputContext.answerArray.push({ text: sliceAnswer, isLast: true })
sliceAnswer = ''
runTTSTask()
inputContext.ws?.close()
console.log('----------------> answer: ', answer)
stepResolve('chat')
return
}
answer += text if (event === 'stream_end') {
photoRole!.answerArgs!.answer += answer
photoRole!.answerArgs!._typingAnswer.push(answer)
isTime && console.time('sliceAnswer')
isTime = false
clearTimeout(messageTimeout);
const textArr = text.split('')
for (let i = 0; i < textArr.length; i++) {
const t = textArr[i]
sliceAnswer += t
if (/[。,?!;,.?!;]/.test(t) && sliceAnswer.length >= sliceAnswerLength) {
console.timeEnd('sliceAnswer')
sliceAnswerLength = settings.llmToTTSSliceLength
inputContext.answerArray.push({ text: sliceAnswer, isLast: true }) inputContext.answerArray.push({ text: sliceAnswer, isLast: true })
runTTSTask()
sliceAnswer = '' sliceAnswer = ''
isTime = true runTTSTask()
inputContext.ws?.close()
console.log('----------------> answer: ', answer)
stepResolve('chat')
return
} }
answer += text
photoRole!.answerArgs!.answer += answer
photoRole!.answerArgs!._typingAnswer.push(answer)
isTime && console.time('sliceAnswer')
isTime = false
clearTimeout(messageTimeout)
const textArr = text.split('')
for (let i = 0; i < textArr.length; i++) {
const t = textArr[i]
sliceAnswer += t
if (/[。,?!;,.?!;]/.test(t) && sliceAnswer.length >= sliceAnswerLength) {
console.timeEnd('sliceAnswer')
sliceAnswerLength = settings.llmToTTSSliceLength
inputContext.answerArray.push({ text: sliceAnswer, isLast: true })
runTTSTask()
sliceAnswer = ''
isTime = true
}
}
} catch (error) {
showError('llm:' + error)
endAudioInput().then(() => {
microphoneState.value = 'waitInput'
})
stepReject(JSON.stringify(error))
} }
} catch (error) {
showError('llm:'+ error)
endAudioInput().then(() => {
microphoneState.value = 'waitInput'
})
stepReject(JSON.stringify(error))
} }
}
ws.send(JSON.stringify({ prompt: question, historys_list: [] })) ws.send(JSON.stringify({ prompt: question, historys_list: [] }))
} catch (error) {
console.error(error)
microphoneState.value = 'input'
showError(`llm${JSON.stringify(error)}`)
}
} }
let isTTSRunning = false let isTTSRunning = false
...@@ -525,7 +536,7 @@ async function runTTSTask() { ...@@ -525,7 +536,7 @@ async function runTTSTask() {
}) })
} }
} catch (error) { } catch (error) {
showError('tts:'+ error) showError('tts:' + error)
endAudioInput().then(() => { endAudioInput().then(() => {
microphoneState.value = 'waitInput' microphoneState.value = 'waitInput'
}) })
...@@ -577,7 +588,7 @@ async function down() { ...@@ -577,7 +588,7 @@ async function down() {
try { try {
await startVoskWsAudioInput() await startVoskWsAudioInput()
} catch (error) { } catch (error) {
showError('start:'+ error) showError('start:' + error)
endAudioInput().then(() => { endAudioInput().then(() => {
microphoneState.value = 'waitInput' microphoneState.value = 'waitInput'
}) })
...@@ -631,22 +642,12 @@ async function down() { ...@@ -631,22 +642,12 @@ async function down() {
</v-btn> </v-btn>
</div> </div>
<v-snackbar <v-snackbar v-model="errorSnackbar" multi-line :timeout="3000">
v-model="errorSnackbar" {{ errorMsg }}
multi-line
:timeout="3000" <template #actions>
> <v-btn color="red" variant="text" @click="errorSnackbar = false"> Close </v-btn>
{{ errorMsg }} </template>
<template #actions>
<v-btn
color="red"
variant="text"
@click="errorSnackbar = false"
>
Close
</v-btn>
</template>
</v-snackbar> </v-snackbar>
</template> </template>
<style scoped> <style scoped>
......
...@@ -35,8 +35,10 @@ const inputContext: { ...@@ -35,8 +35,10 @@ const inputContext: {
voskWs?: WebSocket voskWs?: WebSocket
asrPartial: string asrPartial: string
playingAudio?: HTMLAudioElement playingAudio?: HTMLAudioElement
answerArray: string[]
} = { } = {
asrPartial: '' asrPartial: '',
answerArray: []
} }
onMounted(() => { onMounted(() => {
...@@ -48,10 +50,10 @@ router.beforeEach((g) => { ...@@ -48,10 +50,10 @@ router.beforeEach((g) => {
}) })
const errorSnackbar = ref<boolean>(false) const errorSnackbar = ref<boolean>(false)
const errorMsg = ref<string>(''); const errorMsg = ref<string>('')
const showError = (msg: string) => { const showError = (msg: string) => {
errorSnackbar.value = true; errorSnackbar.value = true
errorMsg.value = msg; errorMsg.value = msg
} }
async function initVosk({ async function initVosk({
...@@ -275,6 +277,7 @@ function endAudioInput() { ...@@ -275,6 +277,7 @@ function endAudioInput() {
videos[1].value?.pause() videos[1].value?.pause()
videos[0].value?.pause() videos[0].value?.pause()
isPlayRunning = false isPlayRunning = false
inputContext.answerArray.length = 0
} }
const canplay = () => { const canplay = () => {
...@@ -344,81 +347,82 @@ async function onQ(question: string) { ...@@ -344,81 +347,82 @@ async function onQ(question: string) {
} }
// 视频链接匹配不上,直接走大模型 // 视频链接匹配不上,直接走大模型
const ws = await initLLMSocket() try {
const answerArray: string[] = [] const ws = await initLLMSocket()
const messageTimeout = setTimeout(() => { const messageTimeout = setTimeout(() => {
showError('llm:timeout!') showError('llm:timeout!')
endAudioInput() endAudioInput()
microphoneState.value = 'waitInput' microphoneState.value = 'waitInput'
}, 5000); }, 10000)
let sliceAnswer = '' let sliceAnswer = ''
let answer = '' let answer = ''
let isTime = true let isTime = true
let sliceAnswerLength = 10 let sliceAnswerLength = 10
inputContext.ws = ws inputContext.ws = ws
ws.onmessage = (message) => {
ws.onmessage = (message) => { if (microphoneState.value === 'input') {
if (microphoneState.value === 'input') { return
return
}
try {
const { text, event } = JSON.parse(message.data) as {
event: string
message_num: number
text: string
} }
if (event === 'stream_end') { try {
answerArray.push(sliceAnswer) const { text, event } = JSON.parse(message.data) as {
runTTSTask(answerArray) event: string
sliceAnswer = '' message_num: number
text: string
}
answerArray.push(sliceAnswer) if (event === 'stream_end') {
sliceAnswer = '' inputContext.answerArray.push(sliceAnswer)
inputContext.ws?.close() runTTSTask()
console.log('----------------> answer: ', answer) sliceAnswer = ''
return
}
answer += text inputContext.answerArray.push(sliceAnswer)
isTime && console.time('sliceAnswer')
isTime = false
clearTimeout(messageTimeout);
const textArr = text.split('')
for (let i = 0; i < textArr.length; i++) {
const t = textArr[i]
sliceAnswer += t
if (/[。,?!;,.?!;]/.test(t) && sliceAnswer.length >= sliceAnswerLength) {
console.timeEnd('sliceAnswer')
sliceAnswerLength = settings.llmToTTSSliceLength
answerArray.push(sliceAnswer)
runTTSTask(answerArray)
sliceAnswer = '' sliceAnswer = ''
isTime = true inputContext.ws?.close()
console.log('----------------> answer: ', answer)
return
} }
answer += text
isTime && console.time('sliceAnswer')
isTime = false
clearTimeout(messageTimeout)
const textArr = text.split('')
for (let i = 0; i < textArr.length; i++) {
const t = textArr[i]
sliceAnswer += t
if (/[。,?!;,.?!;]/.test(t) && sliceAnswer.length >= sliceAnswerLength) {
console.timeEnd('sliceAnswer')
sliceAnswerLength = settings.llmToTTSSliceLength
inputContext.answerArray.push(sliceAnswer)
runTTSTask()
sliceAnswer = ''
isTime = true
}
}
} catch (error) {
console.error(error)
showError(`message:${error}`)
microphoneState.value = 'waitInput'
} }
} catch (error) {
console.error(error);
showError(`message:${error}`)
microphoneState.value = 'waitInput'
} }
ws.send(JSON.stringify({ prompt: question, historys_list: [] }))
} catch (error) {
console.error(error)
microphoneState.value = 'input'
showError(`llm:${JSON.stringify(error)}`)
} }
ws.send(JSON.stringify({ prompt: question, historys_list: [] }))
} }
let isTTSRunning = false let isTTSRunning = false
async function runTTSTask(tasks: string[]) { async function runTTSTask() {
if (isTTSRunning) return if (isTTSRunning) return
isTTSRunning = true isTTSRunning = true
microphoneState.value = 'loading'
try { try {
while (tasks.length) { while (inputContext.answerArray.length) {
const task = tasks.shift() const task = inputContext.answerArray.shift()
if (!task) break if (!task) break
if (task.trim().length < 1) continue if (task.trim().length < 1) continue
...@@ -560,22 +564,12 @@ async function down() { ...@@ -560,22 +564,12 @@ async function down() {
</v-chip> </v-chip>
</div> </div>
<v-snackbar <v-snackbar v-model="errorSnackbar" multi-line :timeout="3000">
v-model="errorSnackbar" {{ errorMsg }}
multi-line
:timeout="3000" <template #actions>
> <v-btn color="red" variant="text" @click="errorSnackbar = false"> Close </v-btn>
{{ errorMsg }} </template>
<template #actions>
<v-btn
color="red"
variant="text"
@click="errorSnackbar = false"
>
Close
</v-btn>
</template>
</v-snackbar> </v-snackbar>
</template> </template>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment