Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
C
CharIP-Electron
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ali
CharIP-Electron
Commits
38df065c
Commit
38df065c
authored
Dec 27, 2023
by
ali
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: 优化相关异常处理
parent
dff91c47
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
167 additions
and
172 deletions
+167
-172
ShowPhoto.vue
src/renderer/screens/ShowPhoto.vue
+94
-93
ShowVideo.vue
src/renderer/screens/ShowVideo.vue
+73
-79
No files found.
src/renderer/screens/ShowPhoto.vue
View file @
38df065c
...
@@ -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
>
...
...
src/renderer/screens/ShowVideo.vue
View file @
38df065c
...
@@ -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>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment