From 3162227b5422f20f72d9cf1cc1bb4317ad7b1561 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Wed, 6 Mar 2024 19:43:22 +0800 Subject: [PATCH] features --- .../features/feature-choose/feature-modal.tsx | 11 +- .../annotation/config-param-modal.tsx | 2 +- .../base/features/feature-panel/index.tsx | 2 +- .../feature-panel/text-to-speech/index.tsx | 56 ++--- .../text-to-speech/param-config-content.tsx | 203 ++++++++++++++++++ .../text-to-speech/params-config.tsx | 46 ++++ web/app/components/workflow/features.tsx | 1 + 7 files changed, 289 insertions(+), 32 deletions(-) create mode 100644 web/app/components/base/features/feature-panel/text-to-speech/param-config-content.tsx create mode 100644 web/app/components/base/features/feature-panel/text-to-speech/params-config.tsx diff --git a/web/app/components/base/features/feature-choose/feature-modal.tsx b/web/app/components/base/features/feature-choose/feature-modal.tsx index 5ff6d205ca..3b4e66b071 100644 --- a/web/app/components/base/features/feature-choose/feature-modal.tsx +++ b/web/app/components/base/features/feature-choose/feature-modal.tsx @@ -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 = ({ 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 = ({ type={FeatureEnum.suggested} /> { - showTextToSpeechItem && ( + !!text2speechDefaultModel && ( } previewImgClassName='textToSpeechPreview' @@ -103,7 +102,7 @@ const FeatureModal: FC = ({ ) } { - showSpeechToTextItem && ( + !!speech2textDefaultModel && ( } previewImgClassName='speechToTextPreview' diff --git a/web/app/components/base/features/feature-panel/annotation/config-param-modal.tsx b/web/app/components/base/features/feature-panel/annotation/config-param-modal.tsx index c4f449628e..999e0131c7 100644 --- a/web/app/components/base/features/feature-panel/annotation/config-param-modal.tsx +++ b/web/app/components/base/features/feature-panel/annotation/config-param-modal.tsx @@ -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' diff --git a/web/app/components/base/features/feature-panel/index.tsx b/web/app/components/base/features/feature-panel/index.tsx index 4aebf81964..2f0905bb05 100644 --- a/web/app/components/base/features/feature-panel/index.tsx +++ b/web/app/components/base/features/feature-panel/index.tsx @@ -63,7 +63,7 @@ const FeaturePanel = ({ } { features.text2speech.enabled && ( - + ) } { diff --git a/web/app/components/base/features/feature-panel/text-to-speech/index.tsx b/web/app/components/base/features/feature-panel/text-to-speech/index.tsx index 5cb9aaf513..6915fa1bcf 100644 --- a/web/app/components/base/features/feature-panel/text-to-speech/index.tsx +++ b/web/app/components/base/features/feature-panel/text-to-speech/index.tsx @@ -1,16 +1,22 @@ '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 ( - -
{t('appDebug.feature.textToSpeech.title')}
- - } - headerIcon={} - headerRight={ -
- {languageInfo && (`${languageInfo?.name} - `)}{voiceItem?.name ?? t('appDebug.voice.defaultDisplay')} - { languageInfo?.example && ( - - )} -
- } - noBodySpacing - isShowTextToSpeech={true} - /> +
+
+ +
+
+ {t('appDebug.feature.textToSpeech.title')} +
+
+
+
+ {languageInfo && (`${languageInfo?.name} - `)}{voiceItem?.name ?? t('appDebug.voice.defaultDisplay')} + { languageInfo?.example && ( + + )} +
+
+ +
+
) } export default React.memo(TextToSpeech) diff --git a/web/app/components/base/features/feature-panel/text-to-speech/param-config-content.tsx b/web/app/components/base/features/feature-panel/text-to-speech/param-config-content.tsx new file mode 100644 index 0000000000..f2f6bd9c5d --- /dev/null +++ b/web/app/components/base/features/feature-panel/text-to-speech/param-config-content.tsx @@ -0,0 +1,203 @@ +'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) => { + const { + features, + setFeatures, + } = featuresStore!.getState() + + const newFeatures = produce(features, (draft) => { + draft.text2speech = { + ...draft.text2speech, + ...value, + } + }) + + setFeatures(newFeatures) + if (onChange) + onChange(newFeatures) + } + + return ( +
+
+
{t('appDebug.voice.voiceSettings.title')}
+
+
+
+
{t('appDebug.voice.voiceSettings.language')}
+ + {t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => ( +
{item}
+ ))} +
} selector='config-resolution-tooltip'> + + +
+ { + handleChange({ + language: String(value.value), + }) + }} + > +
+ + + {languageItem?.name ? t(`common.voice.language.${languageItem?.value.replace('-', '')}`) : localLanguagePlaceholder} + + + + + + + + {languages.map((item: Item) => ( + + `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 }) => ( + <> + {t(`common.voice.language.${(item.value).toString().replace('-', '')}`)} + {(selected || item.value === text2speech.language) && ( + + + )} + + )} + + ))} + + +
+
+
+ +
+
{t('appDebug.voice.voiceSettings.voice')}
+ { + handleChange({ + voice: String(value.value), + }) + }} + > +
+ + {voiceItem?.name ?? localVoicePlaceholder} + + + + + + + {voiceItems?.map((item: Item) => ( + + `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 }) => ( + <> + {item.name} + {(selected || item.value === text2speech.voice) && ( + + + )} + + )} + + ))} + + +
+
+
+
+
+ + ) +} + +export default React.memo(VoiceParamConfig) diff --git a/web/app/components/base/features/feature-panel/text-to-speech/params-config.tsx b/web/app/components/base/features/feature-panel/text-to-speech/params-config.tsx new file mode 100644 index 0000000000..8e5baca297 --- /dev/null +++ b/web/app/components/base/features/feature-panel/text-to-speech/params-config.tsx @@ -0,0 +1,46 @@ +'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 ( + + setOpen(v => !v)}> +
+ +
{t('appDebug.voice.settings')}
+
+
+ +
+ +
+
+
+ ) +} +export default memo(ParamsConfig) diff --git a/web/app/components/workflow/features.tsx b/web/app/components/workflow/features.tsx index efb9de15cb..8602bbdba5 100644 --- a/web/app/components/workflow/features.tsx +++ b/web/app/components/workflow/features.tsx @@ -37,6 +37,7 @@ const Features = () => {
{}, }}