mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-14 06:55:57 +08:00
parent
80b3871c55
commit
6b50bb0fe6
@ -114,7 +114,8 @@ class OpenAIText2SpeechModel(_CommonOpenAI, TTSModel):
|
|||||||
# doc: https://platform.openai.com/docs/guides/text-to-speech
|
# doc: https://platform.openai.com/docs/guides/text-to-speech
|
||||||
credentials_kwargs = self._to_credential_kwargs(credentials)
|
credentials_kwargs = self._to_credential_kwargs(credentials)
|
||||||
client = OpenAI(**credentials_kwargs)
|
client = OpenAI(**credentials_kwargs)
|
||||||
if not voice or voice not in self.get_tts_model_voices(model=model, credentials=credentials):
|
model_support_voice = [x.get("value") for x in self.get_tts_model_voices(model=model, credentials=credentials)]
|
||||||
|
if not voice or voice not in model_support_voice:
|
||||||
voice = self._get_model_default_voice(model, credentials)
|
voice = self._get_model_default_voice(model, credentials)
|
||||||
word_limit = self._get_model_word_limit(model, credentials)
|
word_limit = self._get_model_word_limit(model, credentials)
|
||||||
if len(content_text) > word_limit:
|
if len(content_text) > word_limit:
|
||||||
|
@ -31,12 +31,12 @@ const VoiceParamConfig: FC = () => {
|
|||||||
|
|
||||||
let languageItem = languages.find(item => item.value === textToSpeechConfig.language)
|
let languageItem = languages.find(item => item.value === textToSpeechConfig.language)
|
||||||
const localLanguagePlaceholder = languageItem?.name || t('common.placeholder.select')
|
const localLanguagePlaceholder = languageItem?.name || t('common.placeholder.select')
|
||||||
if (languages && !languageItem)
|
if (languages && !languageItem && languages.length > 0)
|
||||||
languageItem = languages[0]
|
languageItem = languages[0]
|
||||||
const language = languageItem?.value
|
const language = languageItem?.value
|
||||||
const voiceItems = useSWR({ appId, language }, fetchAppVoices).data
|
const voiceItems = useSWR({ appId, language }, fetchAppVoices).data
|
||||||
let voiceItem = voiceItems?.find(item => item.value === textToSpeechConfig.voice)
|
let voiceItem = voiceItems?.find(item => item.value === textToSpeechConfig.voice)
|
||||||
if (voiceItems && !voiceItem)
|
if (voiceItems && !voiceItem && voiceItems.length > 0)
|
||||||
voiceItem = voiceItems[0]
|
voiceItem = voiceItems[0]
|
||||||
|
|
||||||
const localVoicePlaceholder = voiceItem?.name || t('common.placeholder.select')
|
const localVoicePlaceholder = voiceItem?.name || t('common.placeholder.select')
|
||||||
@ -125,9 +125,11 @@ const VoiceParamConfig: FC = () => {
|
|||||||
<div
|
<div
|
||||||
className='mb-2 leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.voice.voiceSettings.voice')}</div>
|
className='mb-2 leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.voice.voiceSettings.voice')}</div>
|
||||||
<Listbox
|
<Listbox
|
||||||
value={voiceItem}
|
value={voiceItem ?? {}}
|
||||||
disabled={!languageItem}
|
disabled={!languageItem}
|
||||||
onChange={(value: Item) => {
|
onChange={(value: Item) => {
|
||||||
|
if (!value.value)
|
||||||
|
return
|
||||||
setTextToSpeechConfig({
|
setTextToSpeechConfig({
|
||||||
...textToSpeechConfig,
|
...textToSpeechConfig,
|
||||||
voice: String(value.value),
|
voice: String(value.value),
|
||||||
|
@ -41,6 +41,7 @@ const TextToSpeech: FC = () => {
|
|||||||
<AudioBtn
|
<AudioBtn
|
||||||
value={languageInfo?.example}
|
value={languageInfo?.example}
|
||||||
isAudition
|
isAudition
|
||||||
|
voice={textToSpeechConfig.voice}
|
||||||
noCache
|
noCache
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -29,6 +29,7 @@ import { useStore as useAppStore } from '@/app/components/app/store'
|
|||||||
import WorkflowProcessItem from '@/app/components/base/chat/chat/answer/workflow-process'
|
import WorkflowProcessItem from '@/app/components/base/chat/chat/answer/workflow-process'
|
||||||
import type { WorkflowProcess } from '@/app/components/base/chat/types'
|
import type { WorkflowProcess } from '@/app/components/base/chat/types'
|
||||||
import type { SiteInfo } from '@/models/share'
|
import type { SiteInfo } from '@/models/share'
|
||||||
|
import { useChatContext } from '@/app/components/base/chat/chat/context'
|
||||||
|
|
||||||
const MAX_DEPTH = 3
|
const MAX_DEPTH = 3
|
||||||
|
|
||||||
@ -127,6 +128,10 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
|||||||
const [childFeedback, setChildFeedback] = useState<Feedbacktype>({
|
const [childFeedback, setChildFeedback] = useState<Feedbacktype>({
|
||||||
rating: null,
|
rating: null,
|
||||||
})
|
})
|
||||||
|
const {
|
||||||
|
config,
|
||||||
|
} = useChatContext()
|
||||||
|
|
||||||
const setCurrentLogItem = useAppStore(s => s.setCurrentLogItem)
|
const setCurrentLogItem = useAppStore(s => s.setCurrentLogItem)
|
||||||
const setShowPromptLogModal = useAppStore(s => s.setShowPromptLogModal)
|
const setShowPromptLogModal = useAppStore(s => s.setShowPromptLogModal)
|
||||||
|
|
||||||
@ -430,6 +435,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({
|
|||||||
<AudioBtn
|
<AudioBtn
|
||||||
id={messageId!}
|
id={messageId!}
|
||||||
className={'mr-1'}
|
className={'mr-1'}
|
||||||
|
voice={config?.text_to_speech?.voice}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -41,7 +41,7 @@ export class AudioPlayerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.msgId = id
|
this.msgId = id
|
||||||
this.audioPlayers = new AudioPlayer(url, isPublic, id, msgContent, callback)
|
this.audioPlayers = new AudioPlayer(url, isPublic, id, msgContent, voice, callback)
|
||||||
return this.audioPlayers
|
return this.audioPlayers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,13 @@ export default class AudioPlayer {
|
|||||||
isPublic: boolean
|
isPublic: boolean
|
||||||
callback: ((event: string) => {}) | null
|
callback: ((event: string) => {}) | null
|
||||||
|
|
||||||
constructor(streamUrl: string, isPublic: boolean, msgId: string | undefined, msgContent: string | null | undefined, callback: ((event: string) => {}) | null) {
|
constructor(streamUrl: string, isPublic: boolean, msgId: string | undefined, msgContent: string | null | undefined, voice: string | undefined, callback: ((event: string) => {}) | null) {
|
||||||
this.audioContext = new AudioContext()
|
this.audioContext = new AudioContext()
|
||||||
this.msgId = msgId
|
this.msgId = msgId
|
||||||
this.msgContent = msgContent
|
this.msgContent = msgContent
|
||||||
this.url = streamUrl
|
this.url = streamUrl
|
||||||
this.isPublic = isPublic
|
this.isPublic = isPublic
|
||||||
|
this.voice = voice
|
||||||
this.callback = callback
|
this.callback = callback
|
||||||
|
|
||||||
// Compatible with iphone ios17 ManagedMediaSource
|
// Compatible with iphone ios17 ManagedMediaSource
|
||||||
@ -154,7 +155,6 @@ export default class AudioPlayer {
|
|||||||
this.mediaSource?.endOfStream()
|
this.mediaSource?.endOfStream()
|
||||||
clearInterval(endTimer)
|
clearInterval(endTimer)
|
||||||
}
|
}
|
||||||
console.log('finishStream endOfStream endTimer')
|
|
||||||
}, 10)
|
}, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,6 @@ export default class AudioPlayer {
|
|||||||
const arrayBuffer = this.cacheBuffers.shift()!
|
const arrayBuffer = this.cacheBuffers.shift()!
|
||||||
this.sourceBuffer?.appendBuffer(arrayBuffer)
|
this.sourceBuffer?.appendBuffer(arrayBuffer)
|
||||||
}
|
}
|
||||||
console.log('finishStream timer')
|
|
||||||
}, 10)
|
}, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,11 +65,11 @@ const AudioBtn = ({
|
|||||||
}
|
}
|
||||||
const handleToggle = async () => {
|
const handleToggle = async () => {
|
||||||
if (audioState === 'playing' || audioState === 'loading') {
|
if (audioState === 'playing' || audioState === 'loading') {
|
||||||
setAudioState('paused')
|
setTimeout(() => setAudioState('paused'), 1)
|
||||||
AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).pauseAudio()
|
AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).pauseAudio()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setAudioState('loading')
|
setTimeout(() => setAudioState('loading'), 1)
|
||||||
AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).playAudio()
|
AudioPlayerManager.getInstance().getAudioPlayer(url, isPublic, id, value, voice, audio_finished_call).playAudio()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@ const Operation: FC<OperationProps> = ({
|
|||||||
id={id}
|
id={id}
|
||||||
value={content}
|
value={content}
|
||||||
noCache={false}
|
noCache={false}
|
||||||
|
voice={config?.text_to_speech?.voice}
|
||||||
className='hidden group-hover:block'
|
className='hidden group-hover:block'
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -149,7 +149,7 @@ const VoiceParamConfig = ({
|
|||||||
<div
|
<div
|
||||||
className='mb-2 leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.voice.voiceSettings.voice')}</div>
|
className='mb-2 leading-[18px] text-[13px] font-semibold text-gray-800'>{t('appDebug.voice.voiceSettings.voice')}</div>
|
||||||
<Listbox
|
<Listbox
|
||||||
value={voiceItem}
|
value={voiceItem ?? {}}
|
||||||
disabled={!languageItem}
|
disabled={!languageItem}
|
||||||
onChange={(value: Item) => {
|
onChange={(value: Item) => {
|
||||||
handleChange({
|
handleChange({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user