'use client' import useSWR from 'swr' import produce from 'immer' import React, { Fragment } from 'react' import { usePathname } from 'next/navigation' import { useTranslation } from 'react-i18next' import { RiCloseLine } from '@remixicon/react' import { Listbox, Transition } from '@headlessui/react' import { CheckIcon, ChevronDownIcon } from '@heroicons/react/20/solid' import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks' import type { Item } from '@/app/components/base/select' import { fetchAppVoices } from '@/service/apps' import Tooltip from '@/app/components/base/tooltip' import Switch from '@/app/components/base/switch' import AudioBtn from '@/app/components/base/audio-btn' import { languages } from '@/i18n/language' import { TtsAutoPlay } from '@/types/app' import type { OnFeaturesChange } from '@/app/components/base/features/types' import classNames from '@/utils/classnames' type VoiceParamConfigProps = { onClose: () => void onChange?: OnFeaturesChange } const VoiceParamConfig = ({ onClose, 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() let languageItem = languages.find(item => item.value === text2speech?.language) if (languages && !languageItem) languageItem = languages[0] const localLanguagePlaceholder = languageItem?.name || t('common.placeholder.select') const language = languageItem?.value const voiceItems = useSWR({ appId, language }, fetchAppVoices).data let voiceItem = voiceItems?.find(item => item.value === text2speech?.voice) if (voiceItems && !voiceItem) voiceItem = voiceItems[0] 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() } return ( <>
{t('appDebug.voice.voiceSettings.title')}
{t('appDebug.voice.voiceSettings.language')} {t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
{item}
))}
} />
{ 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) && ( )} )} ))}
{languageItem?.example && (
)}
{t('appDebug.voice.voiceSettings.autoPlay')}
{ handleChange({ autoPlay: value ? TtsAutoPlay.enabled : TtsAutoPlay.disabled, }) }} />
) } export default React.memo(VoiceParamConfig)