feat:add tts-streaming config and future (#5492)
This commit is contained in:
parent
b29a36f461
commit
6ef401a9f0
44 changed files with 1280 additions and 358 deletions
|
|
@ -1,124 +1,78 @@
|
|||
'use client'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useRef, useState } from 'react'
|
||||
import { t } from 'i18next'
|
||||
import { useParams, usePathname } from 'next/navigation'
|
||||
import s from './style.module.css'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { randomString } from '@/utils'
|
||||
import { textToAudio } from '@/service/share'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
|
||||
|
||||
type AudioBtnProps = {
|
||||
value: string
|
||||
id?: string
|
||||
voice?: string
|
||||
value?: string
|
||||
className?: string
|
||||
isAudition?: boolean
|
||||
noCache: boolean
|
||||
noCache?: boolean
|
||||
}
|
||||
|
||||
type AudioState = 'initial' | 'loading' | 'playing' | 'paused' | 'ended'
|
||||
|
||||
const AudioBtn = ({
|
||||
value,
|
||||
id,
|
||||
voice,
|
||||
value,
|
||||
className,
|
||||
isAudition,
|
||||
noCache,
|
||||
}: AudioBtnProps) => {
|
||||
const audioRef = useRef<HTMLAudioElement | null>(null)
|
||||
const [audioState, setAudioState] = useState<AudioState>('initial')
|
||||
|
||||
const selector = useRef(`play-tooltip-${randomString(4)}`)
|
||||
const params = useParams()
|
||||
const pathname = usePathname()
|
||||
const removeCodeBlocks = (inputText: any) => {
|
||||
const codeBlockRegex = /```[\s\S]*?```/g
|
||||
if (inputText)
|
||||
return inputText.replace(codeBlockRegex, '')
|
||||
return ''
|
||||
}
|
||||
|
||||
const loadAudio = async () => {
|
||||
const formData = new FormData()
|
||||
formData.append('text', removeCodeBlocks(value))
|
||||
formData.append('voice', removeCodeBlocks(voice))
|
||||
|
||||
if (value !== '') {
|
||||
setAudioState('loading')
|
||||
|
||||
let url = ''
|
||||
let isPublic = false
|
||||
|
||||
if (params.token) {
|
||||
url = '/text-to-audio'
|
||||
isPublic = true
|
||||
}
|
||||
else if (params.appId) {
|
||||
if (pathname.search('explore/installed') > -1)
|
||||
url = `/installed-apps/${params.appId}/text-to-audio`
|
||||
else
|
||||
url = `/apps/${params.appId}/text-to-audio`
|
||||
}
|
||||
|
||||
try {
|
||||
const audioResponse = await textToAudio(url, isPublic, formData)
|
||||
const blob_bytes = Buffer.from(audioResponse.data, 'latin1')
|
||||
const blob = new Blob([blob_bytes], { type: 'audio/wav' })
|
||||
const audioUrl = URL.createObjectURL(blob)
|
||||
audioRef.current!.src = audioUrl
|
||||
}
|
||||
catch (error) {
|
||||
setAudioState('initial')
|
||||
console.error('Error playing audio:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleToggle = async () => {
|
||||
if (audioState === 'initial' || noCache) {
|
||||
await loadAudio()
|
||||
}
|
||||
else if (audioRef.current) {
|
||||
if (audioState === 'playing') {
|
||||
audioRef.current.pause()
|
||||
setAudioState('paused')
|
||||
}
|
||||
else {
|
||||
audioRef.current.play()
|
||||
const audio_finished_call = (event: string): any => {
|
||||
switch (event) {
|
||||
case 'ended':
|
||||
setAudioState('ended')
|
||||
break
|
||||
case 'paused':
|
||||
setAudioState('ended')
|
||||
break
|
||||
case 'loaded':
|
||||
setAudioState('loading')
|
||||
break
|
||||
case 'play':
|
||||
setAudioState('playing')
|
||||
}
|
||||
break
|
||||
case 'error':
|
||||
setAudioState('ended')
|
||||
break
|
||||
}
|
||||
}
|
||||
let url = ''
|
||||
let isPublic = false
|
||||
|
||||
useEffect(() => {
|
||||
const currentAudio = audioRef.current
|
||||
|
||||
const handleLoading = () => {
|
||||
if (params.token) {
|
||||
url = '/text-to-audio'
|
||||
isPublic = true
|
||||
}
|
||||
else if (params.appId) {
|
||||
if (pathname.search('explore/installed') > -1)
|
||||
url = `/installed-apps/${params.appId}/text-to-audio`
|
||||
else
|
||||
url = `/apps/${params.appId}/text-to-audio`
|
||||
}
|
||||
const handleToggle = async () => {
|
||||
if (audioState === 'playing' || audioState === 'loading') {
|
||||
setAudioState('paused')
|
||||
AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).pauseAudio()
|
||||
}
|
||||
else {
|
||||
setAudioState('loading')
|
||||
AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).playAudio()
|
||||
}
|
||||
|
||||
const handlePlay = () => {
|
||||
currentAudio?.play()
|
||||
setAudioState('playing')
|
||||
}
|
||||
|
||||
const handleEnded = () => {
|
||||
setAudioState('ended')
|
||||
}
|
||||
|
||||
currentAudio?.addEventListener('progress', handleLoading)
|
||||
currentAudio?.addEventListener('canplaythrough', handlePlay)
|
||||
currentAudio?.addEventListener('ended', handleEnded)
|
||||
|
||||
return () => {
|
||||
currentAudio?.removeEventListener('progress', handleLoading)
|
||||
currentAudio?.removeEventListener('canplaythrough', handlePlay)
|
||||
currentAudio?.removeEventListener('ended', handleEnded)
|
||||
URL.revokeObjectURL(currentAudio?.src || '')
|
||||
currentAudio?.pause()
|
||||
currentAudio?.setAttribute('src', '')
|
||||
}
|
||||
}, [])
|
||||
}
|
||||
|
||||
const tooltipContent = {
|
||||
initial: t('appApi.play'),
|
||||
|
|
@ -151,7 +105,6 @@ const AudioBtn = ({
|
|||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
<audio ref={audioRef} src='' className='hidden' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue