Abort TTS SSE when clicking the stop button
This commit is contained in:
parent
55b6be24df
commit
d42c096164
|
|
@ -266,7 +266,8 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
audio: null,
|
audio: null,
|
||||||
chunkQueue: [],
|
chunkQueue: [],
|
||||||
isBuffering: false,
|
isBuffering: false,
|
||||||
audioFormat: null
|
audioFormat: null,
|
||||||
|
abortController: null
|
||||||
})
|
})
|
||||||
|
|
||||||
const isFileAllowedForUpload = (file) => {
|
const isFileAllowedForUpload = (file) => {
|
||||||
|
|
@ -1590,6 +1591,28 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stopAllTTS = () => {
|
||||||
|
Object.keys(ttsAudio).forEach((messageId) => {
|
||||||
|
if (ttsAudio[messageId]) {
|
||||||
|
ttsAudio[messageId].pause()
|
||||||
|
ttsAudio[messageId].currentTime = 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setTtsAudio({})
|
||||||
|
|
||||||
|
if (ttsStreamingState.abortController) {
|
||||||
|
ttsStreamingState.abortController.abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ttsStreamingState.audio) {
|
||||||
|
ttsStreamingState.audio.pause()
|
||||||
|
cleanupTTSStreaming()
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsTTSPlaying({})
|
||||||
|
setIsTTSLoading({})
|
||||||
|
}
|
||||||
|
|
||||||
const handleTTSClick = async (messageId, messageText) => {
|
const handleTTSClick = async (messageId, messageText) => {
|
||||||
if (isTTSLoading[messageId]) return
|
if (isTTSLoading[messageId]) return
|
||||||
|
|
||||||
|
|
@ -1598,6 +1621,8 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopAllTTS()
|
||||||
|
|
||||||
handleTTSStart({ chatMessageId: messageId, format: 'mp3' })
|
handleTTSStart({ chatMessageId: messageId, format: 'mp3' })
|
||||||
try {
|
try {
|
||||||
let ttsConfig = null
|
let ttsConfig = null
|
||||||
|
|
@ -1631,6 +1656,9 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const abortController = new AbortController()
|
||||||
|
setTtsStreamingState((prev) => ({ ...prev, abortController }))
|
||||||
|
|
||||||
const response = await fetch('/api/v1/text-to-speech/generate', {
|
const response = await fetch('/api/v1/text-to-speech/generate', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -1638,6 +1666,7 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
'x-request-from': 'internal'
|
'x-request-from': 'internal'
|
||||||
},
|
},
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
|
signal: abortController.signal,
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
chatId: chatId,
|
chatId: chatId,
|
||||||
chatMessageId: messageId,
|
chatMessageId: messageId,
|
||||||
|
|
@ -1659,6 +1688,10 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
|
|
||||||
let done = false
|
let done = false
|
||||||
while (!done) {
|
while (!done) {
|
||||||
|
if (abortController.signal.aborted) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
const result = await reader.read()
|
const result = await reader.read()
|
||||||
done = result.done
|
done = result.done
|
||||||
if (done) {
|
if (done) {
|
||||||
|
|
@ -1679,12 +1712,14 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
case 'tts_start':
|
case 'tts_start':
|
||||||
break
|
break
|
||||||
case 'tts_data':
|
case 'tts_data':
|
||||||
handleTTSDataChunk(event.data.audioChunk)
|
if (!abortController.signal.aborted) {
|
||||||
|
handleTTSDataChunk(event.data.audioChunk)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'tts_end':
|
case 'tts_end':
|
||||||
handleTTSEnd()
|
if (!abortController.signal.aborted) {
|
||||||
break
|
handleTTSEnd()
|
||||||
default:
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1692,11 +1727,15 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error with TTS:', error)
|
if (error.name === 'AbortError') {
|
||||||
enqueueSnackbar({
|
console.error('TTS request was aborted')
|
||||||
message: `TTS failed: ${error.message}`,
|
} else {
|
||||||
options: { variant: 'error' }
|
console.error('Error with TTS:', error)
|
||||||
})
|
enqueueSnackbar({
|
||||||
|
message: `TTS failed: ${error.message}`,
|
||||||
|
options: { variant: 'error' }
|
||||||
|
})
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setIsTTSLoading((prev) => {
|
setIsTTSLoading((prev) => {
|
||||||
const newState = { ...prev }
|
const newState = { ...prev }
|
||||||
|
|
@ -1805,6 +1844,10 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
|
|
||||||
const cleanupTTSStreaming = () => {
|
const cleanupTTSStreaming = () => {
|
||||||
setTtsStreamingState((prevState) => {
|
setTtsStreamingState((prevState) => {
|
||||||
|
if (prevState.abortController) {
|
||||||
|
prevState.abortController.abort()
|
||||||
|
}
|
||||||
|
|
||||||
if (prevState.audio) {
|
if (prevState.audio) {
|
||||||
prevState.audio.pause()
|
prevState.audio.pause()
|
||||||
prevState.audio.removeAttribute('src')
|
prevState.audio.removeAttribute('src')
|
||||||
|
|
@ -1830,7 +1873,8 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
audio: null,
|
audio: null,
|
||||||
chunkQueue: [],
|
chunkQueue: [],
|
||||||
isBuffering: false,
|
isBuffering: false,
|
||||||
audioFormat: null
|
audioFormat: null,
|
||||||
|
abortController: null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -1870,30 +1914,14 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP
|
||||||
allMessages[allMessages.length - 1].id = data.chatMessageId
|
allMessages[allMessages.length - 1].id = data.chatMessageId
|
||||||
return allMessages
|
return allMessages
|
||||||
})
|
})
|
||||||
setTtsStreamingState((prevState) => {
|
setTtsStreamingState({
|
||||||
if (prevState.audio) {
|
mediaSource: null,
|
||||||
prevState.audio.pause()
|
sourceBuffer: null,
|
||||||
if (prevState.audio.src) {
|
audio: null,
|
||||||
URL.revokeObjectURL(prevState.audio.src)
|
chunkQueue: [],
|
||||||
}
|
isBuffering: false,
|
||||||
}
|
audioFormat: data.format,
|
||||||
|
abortController: null
|
||||||
if (prevState.mediaSource && prevState.mediaSource.readyState === 'open') {
|
|
||||||
try {
|
|
||||||
prevState.mediaSource.endOfStream()
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error stopping previous media source:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
mediaSource: null,
|
|
||||||
sourceBuffer: null,
|
|
||||||
audio: null,
|
|
||||||
chunkQueue: [],
|
|
||||||
isBuffering: false,
|
|
||||||
audioFormat: data.format
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(() => initializeTTSStreaming(data), 0)
|
setTimeout(() => initializeTTSStreaming(data), 0)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue