Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
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
ai-tech
dify
Commits
3162227b
Commit
3162227b
authored
Mar 06, 2024
by
StyleZhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
features
parent
7e647cc6
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
289 additions
and
32 deletions
+289
-32
feature-modal.tsx
...components/base/features/feature-choose/feature-modal.tsx
+5
-6
config-param-modal.tsx
.../features/feature-panel/annotation/config-param-modal.tsx
+1
-1
index.tsx
web/app/components/base/features/feature-panel/index.tsx
+1
-1
index.tsx
...ents/base/features/feature-panel/text-to-speech/index.tsx
+32
-24
param-config-content.tsx
...res/feature-panel/text-to-speech/param-config-content.tsx
+203
-0
params-config.tsx
...e/features/feature-panel/text-to-speech/params-config.tsx
+46
-0
features.tsx
web/app/components/workflow/features.tsx
+1
-0
No files found.
web/app/components/base/features/feature-choose/feature-modal.tsx
View file @
3162227b
...
...
@@ -20,19 +20,18 @@ import {
MessageHeartCircle
,
}
from
'@/app/components/base/icons/src/vender/solid/communication'
import
{
FeatureEnum
}
from
'@/app/components/base/features/types'
import
{
useDefaultModel
}
from
'@/app/components/header/account-setting/model-provider-page/hooks'
export
type
FeatureModalProps
=
{
onChange
?:
OnFeaturesChange
showTextToSpeechItem
?:
boolean
showSpeechToTextItem
?:
boolean
}
const
FeatureModal
:
FC
<
FeatureModalProps
>
=
({
onChange
,
showTextToSpeechItem
,
showSpeechToTextItem
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
{
data
:
speech2textDefaultModel
}
=
useDefaultModel
(
4
)
const
{
data
:
text2speechDefaultModel
}
=
useDefaultModel
(
5
)
const
featuresStore
=
useFeaturesStore
()
const
setShowFeaturesModal
=
useFeatures
(
s
=>
s
.
setShowFeaturesModal
)
const
features
=
useFeatures
(
s
=>
s
.
features
)
...
...
@@ -90,7 +89,7 @@ const FeatureModal: FC<FeatureModalProps> = ({
type=
{
FeatureEnum
.
suggested
}
/>
{
showTextToSpeechItem
&&
(
!!
text2speechDefaultModel
&&
(
<
FeatureItem
icon=
{
<
Speaker
className=
'w-4 h-4 text-[#7839EE]'
/>
}
previewImgClassName=
'textToSpeechPreview'
...
...
@@ -103,7 +102,7 @@ const FeatureModal: FC<FeatureModalProps> = ({
)
}
{
showSpeechToTextItem
&&
(
!!
speech2textDefaultModel
&&
(
<
FeatureItem
icon=
{
<
Microphone01
className=
'w-4 h-4 text-[#7839EE]'
/>
}
previewImgClassName=
'speechToTextPreview'
...
...
web/app/components/base/features/feature-panel/annotation/config-param-modal.tsx
View file @
3162227b
...
...
@@ -3,7 +3,7 @@ import type { FC } from 'react'
import
React
,
{
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
ScoreSlider
from
'../score-slider'
import
{
Item
}
from
'./
config-param
'
import
{
Item
}
from
'./
index
'
import
Modal
from
'@/app/components/base/modal'
import
Button
from
'@/app/components/base/button'
import
Toast
from
'@/app/components/base/toast'
...
...
web/app/components/base/features/feature-panel/index.tsx
View file @
3162227b
...
...
@@ -63,7 +63,7 @@ const FeaturePanel = ({
}
{
features
.
text2speech
.
enabled
&&
(
<
TextToSpeech
/>
<
TextToSpeech
onChange=
{
onChange
}
/>
)
}
{
...
...
web/app/components/base/features/feature-panel/text-to-speech/index.tsx
View file @
3162227b
'use client'
import
useSWR
from
'swr'
import
React
,
{
type
FC
}
from
'react'
import
React
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
usePathname
}
from
'next/navigation'
import
{
useFeatures
}
from
'../../hooks'
import
Panel
from
'@/app/components/app/configuration/base/feature-panel'
import
type
{
OnFeaturesChange
}
from
'../../types'
import
ParamsConfig
from
'./params-config'
import
{
Speaker
}
from
'@/app/components/base/icons/src/vender/solid/mediaAndDevices'
import
{
languages
}
from
'@/i18n/language'
import
{
fetchAppVoices
}
from
'@/service/apps'
import
AudioBtn
from
'@/app/components/base/audio-btn'
const
TextToSpeech
:
FC
=
()
=>
{
type
TextToSpeechProps
=
{
onChange
?:
OnFeaturesChange
}
const
TextToSpeech
=
({
onChange
,
}:
TextToSpeechProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
textToSpeech
=
useFeatures
(
s
=>
s
.
features
.
text2speech
)
...
...
@@ -24,27 +30,29 @@ const TextToSpeech: FC = () => {
const
voiceItem
=
voiceItems
?.
find
(
item
=>
item
.
value
===
textToSpeech
.
voice
)
return
(
<
Panel
title=
{
<
div
className=
'flex items-center'
>
<
div
>
{
t
(
'appDebug.feature.textToSpeech.title'
)
}
</
div
>
</
div
>
}
headerIcon=
{
<
Speaker
className=
'w-4 h-4 text-[#7839EE]'
/>
}
headerRight=
{
<
div
className=
'text-xs text-gray-500 inline-flex items-center gap-2'
>
{
languageInfo
&&
(
`${languageInfo?.name} - `
)
}{
voiceItem
?.
name
??
t
(
'appDebug.voice.defaultDisplay'
)
}
{
languageInfo
?.
example
&&
(
<
AudioBtn
value=
{
languageInfo
?.
example
}
isAudition=
{
true
}
/>
)
}
</
div
>
}
noBodySpacing
isShowTextToSpeech=
{
true
}
/>
<
div
className=
'flex items-center px-3 h-12 bg-gray-50 rounded-xl overflow-hidden'
>
<
div
className=
'shrink-0 flex items-center justify-center mr-1 w-6 h-6'
>
<
Speaker
className=
'w-4 h-4 text-[#7839EE]'
/>
</
div
>
<
div
className=
'shrink-0 mr-2 whitespace-nowrap text-sm text-gray-800 font-semibold'
>
{
t
(
'appDebug.feature.textToSpeech.title'
)
}
</
div
>
<
div
className=
'grow '
>
</
div
>
<
div
className=
'shrink-0 text-xs text-gray-500 inline-flex items-center gap-2'
>
{
languageInfo
&&
(
`${languageInfo?.name} - `
)
}{
voiceItem
?.
name
??
t
(
'appDebug.voice.defaultDisplay'
)
}
{
languageInfo
?.
example
&&
(
<
AudioBtn
value=
{
languageInfo
?.
example
}
isAudition=
{
true
}
/>
)
}
</
div
>
<
div
className=
'shrink-0 flex items-center'
>
<
ParamsConfig
onChange=
{
onChange
}
/>
</
div
>
</
div
>
)
}
export
default
React
.
memo
(
TextToSpeech
)
web/app/components/base/features/feature-panel/text-to-speech/param-config-content.tsx
0 → 100644
View file @
3162227b
'use client'
import
useSWR
from
'swr'
import
produce
from
'immer'
import
React
,
{
Fragment
}
from
'react'
import
classNames
from
'classnames'
import
{
usePathname
}
from
'next/navigation'
import
{
useTranslation
}
from
'react-i18next'
import
{
Listbox
,
Transition
}
from
'@headlessui/react'
import
{
CheckIcon
,
ChevronDownIcon
}
from
'@heroicons/react/20/solid'
import
{
useFeatures
,
useFeaturesStore
,
}
from
'../../hooks'
import
type
{
OnFeaturesChange
}
from
'../../types'
import
type
{
Item
}
from
'@/app/components/base/select'
import
{
fetchAppVoices
}
from
'@/service/apps'
import
Tooltip
from
'@/app/components/base/tooltip'
import
{
HelpCircle
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
languages
}
from
'@/i18n/language'
type
VoiceParamConfigProps
=
{
onChange
?:
OnFeaturesChange
}
const
VoiceParamConfig
=
({
onChange
,
}:
VoiceParamConfigProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
pathname
=
usePathname
()
const
matched
=
pathname
.
match
(
/
\/
app
\/([^/]
+
)
/
)
const
appId
=
(
matched
?.
length
&&
matched
[
1
])
?
matched
[
1
]
:
''
const
text2speech
=
useFeatures
(
state
=>
state
.
features
.
text2speech
)
const
featuresStore
=
useFeaturesStore
()
const
languageItem
=
languages
.
find
(
item
=>
item
.
value
===
text2speech
.
language
)
const
localLanguagePlaceholder
=
languageItem
?.
name
||
t
(
'common.placeholder.select'
)
const
language
=
languageItem
?.
value
const
voiceItems
=
useSWR
({
appId
,
language
},
fetchAppVoices
).
data
const
voiceItem
=
voiceItems
?.
find
(
item
=>
item
.
value
===
text2speech
.
voice
)
const
localVoicePlaceholder
=
voiceItem
?.
name
||
t
(
'common.placeholder.select'
)
const
handleChange
=
(
value
:
Record
<
string
,
string
>
)
=>
{
const
{
features
,
setFeatures
,
}
=
featuresStore
!
.
getState
()
const
newFeatures
=
produce
(
features
,
(
draft
)
=>
{
draft
.
text2speech
=
{
...
draft
.
text2speech
,
...
value
,
}
})
setFeatures
(
newFeatures
)
if
(
onChange
)
onChange
(
newFeatures
)
}
return
(
<
div
>
<
div
>
<
div
className=
'leading-6 text-base font-semibold text-gray-800'
>
{
t
(
'appDebug.voice.voiceSettings.title'
)
}
</
div
>
<
div
className=
'pt-3 space-y-6'
>
<
div
>
<
div
className=
'mb-2 flex items-center space-x-1'
>
<
div
className=
'leading-[18px] text-[13px] font-semibold text-gray-800'
>
{
t
(
'appDebug.voice.voiceSettings.language'
)
}
</
div
>
<
Tooltip
htmlContent=
{
<
div
className=
'w-[180px]'
>
{
t
(
'appDebug.voice.voiceSettings.resolutionTooltip'
).
split
(
'
\
n'
).
map
(
item
=>
(
<
div
key=
{
item
}
>
{
item
}
</
div
>
))
}
</
div
>
}
selector=
'config-resolution-tooltip'
>
<
HelpCircle
className=
'w-[14px] h-[14px] text-gray-400'
/>
</
Tooltip
>
</
div
>
<
Listbox
value=
{
languageItem
}
onChange=
{
(
value
:
Item
)
=>
{
handleChange
({
language
:
String
(
value
.
value
),
})
}
}
>
<
div
className=
{
'relative h-9'
}
>
<
Listbox
.
Button
className=
{
'w-full h-full rounded-lg border-0 bg-gray-100 py-1.5 pl-3 pr-10 sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-gray-200 group-hover:bg-gray-200 cursor-pointer'
}
>
<
span
className=
{
classNames
(
'block truncate text-left'
,
!
languageItem
?.
name
&&
'text-gray-400'
)
}
>
{
languageItem
?.
name
?
t
(
`common.voice.language.${languageItem?.value.replace('-', '')}`
)
:
localLanguagePlaceholder
}
</
span
>
<
span
className=
"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"
>
<
ChevronDownIcon
className=
"h-5 w-5 text-gray-400"
aria
-
hidden=
"true"
/>
</
span
>
</
Listbox
.
Button
>
<
Transition
as=
{
Fragment
}
leave=
"transition ease-in duration-100"
leaveFrom=
"opacity-100"
leaveTo=
"opacity-0"
>
<
Listbox
.
Options
className=
"absolute z-10 mt-1 px-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg border-gray-200 border-[0.5px] focus:outline-none sm:text-sm"
>
{
languages
.
map
((
item
:
Item
)
=>
(
<
Listbox
.
Option
key=
{
item
.
value
}
className=
{
({
active
})
=>
`relative cursor-pointer select-none py-2 pl-3 pr-9 rounded-lg hover:bg-gray-100 text-gray-700 ${active ? 'bg-gray-100' : ''
}`
}
value=
{
item
}
disabled=
{
false
}
>
{
({
/* active, */
selected
})
=>
(
<>
<
span
className=
{
classNames
(
'block'
,
selected
&&
'font-normal'
)
}
>
{
t
(
`common.voice.language.${(item.value).toString().replace('-', '')}`
)
}
</
span
>
{
(
selected
||
item
.
value
===
text2speech
.
language
)
&&
(
<
span
className=
{
classNames
(
'absolute inset-y-0 right-0 flex items-center pr-4 text-gray-700'
,
)
}
>
<
CheckIcon
className=
"h-5 w-5"
aria
-
hidden=
"true"
/>
</
span
>
)
}
</>
)
}
</
Listbox
.
Option
>
))
}
</
Listbox
.
Options
>
</
Transition
>
</
div
>
</
Listbox
>
</
div
>
<
div
>
<
div
className=
'mb-2 leading-[18px] text-[13px] font-semibold text-gray-800'
>
{
t
(
'appDebug.voice.voiceSettings.voice'
)
}
</
div
>
<
Listbox
value=
{
voiceItem
}
disabled=
{
!
languageItem
}
onChange=
{
(
value
:
Item
)
=>
{
handleChange
({
voice
:
String
(
value
.
value
),
})
}
}
>
<
div
className=
{
'relative h-9'
}
>
<
Listbox
.
Button
className=
{
'w-full h-full rounded-lg border-0 bg-gray-100 py-1.5 pl-3 pr-10 sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-gray-200 group-hover:bg-gray-200 cursor-pointer'
}
>
<
span
className=
{
classNames
(
'block truncate text-left'
,
!
voiceItem
?.
name
&&
'text-gray-400'
)
}
>
{
voiceItem
?.
name
??
localVoicePlaceholder
}
</
span
>
<
span
className=
"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"
>
<
ChevronDownIcon
className=
"h-5 w-5 text-gray-400"
aria
-
hidden=
"true"
/>
</
span
>
</
Listbox
.
Button
>
<
Transition
as=
{
Fragment
}
leave=
"transition ease-in duration-100"
leaveFrom=
"opacity-100"
leaveTo=
"opacity-0"
>
<
Listbox
.
Options
className=
"absolute z-10 mt-1 px-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg border-gray-200 border-[0.5px] focus:outline-none sm:text-sm"
>
{
voiceItems
?.
map
((
item
:
Item
)
=>
(
<
Listbox
.
Option
key=
{
item
.
value
}
className=
{
({
active
})
=>
`relative cursor-pointer select-none py-2 pl-3 pr-9 rounded-lg hover:bg-gray-100 text-gray-700 ${active ? 'bg-gray-100' : ''
}`
}
value=
{
item
}
disabled=
{
false
}
>
{
({
/* active, */
selected
})
=>
(
<>
<
span
className=
{
classNames
(
'block'
,
selected
&&
'font-normal'
)
}
>
{
item
.
name
}
</
span
>
{
(
selected
||
item
.
value
===
text2speech
.
voice
)
&&
(
<
span
className=
{
classNames
(
'absolute inset-y-0 right-0 flex items-center pr-4 text-gray-700'
,
)
}
>
<
CheckIcon
className=
"h-5 w-5"
aria
-
hidden=
"true"
/>
</
span
>
)
}
</>
)
}
</
Listbox
.
Option
>
))
}
</
Listbox
.
Options
>
</
Transition
>
</
div
>
</
Listbox
>
</
div
>
</
div
>
</
div
>
</
div
>
)
}
export
default
React
.
memo
(
VoiceParamConfig
)
web/app/components/base/features/feature-panel/text-to-speech/params-config.tsx
0 → 100644
View file @
3162227b
'use client'
import
{
memo
,
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
cn
from
'classnames'
import
type
{
OnFeaturesChange
}
from
'../../types'
import
ParamConfigContent
from
'./param-config-content'
import
{
Settings01
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
PortalToFollowElem
,
PortalToFollowElemContent
,
PortalToFollowElemTrigger
,
}
from
'@/app/components/base/portal-to-follow-elem'
type
ParamsConfigProps
=
{
onChange
?:
OnFeaturesChange
}
const
ParamsConfig
=
({
onChange
,
}:
ParamsConfigProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
[
open
,
setOpen
]
=
useState
(
false
)
return
(
<
PortalToFollowElem
open=
{
open
}
onOpenChange=
{
setOpen
}
placement=
'bottom-end'
offset=
{
{
mainAxis
:
4
,
}
}
>
<
PortalToFollowElemTrigger
onClick=
{
()
=>
setOpen
(
v
=>
!
v
)
}
>
<
div
className=
{
cn
(
'flex items-center rounded-md h-7 px-3 space-x-1 text-gray-700 cursor-pointer hover:bg-gray-200'
,
open
&&
'bg-gray-200'
)
}
>
<
Settings01
className=
'w-3.5 h-3.5 '
/>
<
div
className=
'ml-1 leading-[18px] text-xs font-medium '
>
{
t
(
'appDebug.voice.settings'
)
}
</
div
>
</
div
>
</
PortalToFollowElemTrigger
>
<
PortalToFollowElemContent
style=
{
{
zIndex
:
50
}
}
>
<
div
className=
'w-80 sm:w-[412px] p-4 bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg space-y-3'
>
<
ParamConfigContent
onChange=
{
onChange
}
/>
</
div
>
</
PortalToFollowElemContent
>
</
PortalToFollowElem
>
)
}
export
default
memo
(
ParamsConfig
)
web/app/components/workflow/features.tsx
View file @
3162227b
...
...
@@ -37,6 +37,7 @@ const Features = () => {
</
div
>
<
div
className=
'p-4'
>
<
FeaturesPanel
onChange=
{
handleFeaturesChange
}
openingStatementProps=
{
{
onAutoAddPromptVariable
:
()
=>
{},
}
}
...
...
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