Update UI of speech to text dialog

This commit is contained in:
Ilango 2024-02-19 11:49:01 +05:30
parent 10fc1bf08d
commit 81c07dc8c1
3 changed files with 145 additions and 158 deletions

View File

@ -13,14 +13,13 @@ import {
DialogContent, DialogContent,
DialogTitle, DialogTitle,
DialogActions, DialogActions,
Accordion, FormControl,
AccordionSummary,
AccordionDetails,
ListItem, ListItem,
ListItemAvatar, ListItemAvatar,
ListItemText ListItemText,
MenuItem,
Select
} from '@mui/material' } from '@mui/material'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import { IconX } from '@tabler/icons' import { IconX } from '@tabler/icons'
// Project import // Project import
@ -40,8 +39,8 @@ import useNotifier from 'utils/useNotifier'
// API // API
import chatflowsApi from 'api/chatflows' import chatflowsApi from 'api/chatflows'
const speechToTextProviders = [ const speechToTextProviders = {
{ openAIWhisper: {
label: 'OpenAI Whisper', label: 'OpenAI Whisper',
name: 'openAIWhisper', name: 'openAIWhisper',
icon: openAISVG, icon: openAISVG,
@ -77,16 +76,10 @@ const speechToTextProviders = [
step: 0.1, step: 0.1,
description: `The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.`, description: `The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.`,
optional: true optional: true
},
{
label: 'On/Off',
name: 'status',
type: 'boolean',
optional: true
} }
] ]
}, },
{ assemblyAiTranscribe: {
label: 'Assembly AI', label: 'Assembly AI',
name: 'assemblyAiTranscribe', name: 'assemblyAiTranscribe',
icon: assemblyAIPng, icon: assemblyAIPng,
@ -97,16 +90,10 @@ const speechToTextProviders = [
name: 'credential', name: 'credential',
type: 'credential', type: 'credential',
credentialNames: ['assemblyAIApi'] credentialNames: ['assemblyAIApi']
},
{
label: 'On/Off',
name: 'status',
type: 'boolean',
optional: true
} }
] ]
} }
] }
const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => { const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => {
const portalElement = document.getElementById('portal') const portalElement = document.getElementById('portal')
@ -118,7 +105,7 @@ const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => {
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
const [speechToText, setSpeechToText] = useState({}) const [speechToText, setSpeechToText] = useState({})
const [providerExpanded, setProviderExpanded] = useState({}) const [selectedProvider, setSelectedProvider] = useState('openAIWhisper')
const onSave = async () => { const onSave = async () => {
try { try {
@ -169,8 +156,9 @@ const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => {
newVal[providerName][inputParamName] = value newVal[providerName][inputParamName] = value
if (inputParamName === 'status' && value === true) { if (inputParamName === 'status' && value === true) {
//ensure that the others are turned off // ensure that the others are turned off
speechToTextProviders.forEach((provider) => { Object.keys(speechToTextProviders).forEach((key) => {
const provider = speechToTextProviders[key]
if (provider.name !== providerName) { if (provider.name !== providerName) {
newVal[provider.name] = { ...speechToText[provider.name], status: false } newVal[provider.name] = { ...speechToText[provider.name], status: false }
} }
@ -179,10 +167,9 @@ const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => {
setSpeechToText(newVal) setSpeechToText(newVal)
} }
const handleAccordionChange = (providerName) => (event, isExpanded) => { const handleProviderChange = (event) => {
const accordionProviders = { ...providerExpanded } setSelectedProvider(event.target.value)
accordionProviders[providerName] = isExpanded setValue(true, event.target.value, 'status')
setProviderExpanded(accordionProviders)
} }
useEffect(() => { useEffect(() => {
@ -197,7 +184,6 @@ const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => {
return () => { return () => {
setSpeechToText({}) setSpeechToText({})
setProviderExpanded({})
} }
}, [dialogProps]) }, [dialogProps])
@ -220,136 +206,129 @@ const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => {
Speech To Text Configuration Speech To Text Configuration
</DialogTitle> </DialogTitle>
<DialogContent> <DialogContent>
{speechToTextProviders.map((provider, index) => ( <Box fullWidth sx={{ my: 2, display: 'flex', flexDirection: 'column', gap: 1 }}>
<Accordion <Typography>Speech To Text Providers</Typography>
expanded={providerExpanded[provider.name] || false} <FormControl fullWidth>
onChange={handleAccordionChange(provider.name)} <Select value={selectedProvider} onChange={handleProviderChange}>
disableGutters <MenuItem value='openAIWhisper'>OpenAI Whisper</MenuItem>
key={index} <MenuItem value='assemblyAiTranscribe'>Assembly AI</MenuItem>
> </Select>
<AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls={provider.name} id={provider.name}> </FormControl>
<ListItem style={{ padding: 0, margin: 0 }} alignItems='center'> </Box>
<ListItemAvatar> <>
<div <ListItem style={{ padding: 0, margin: 0 }} alignItems='center'>
style={{ <ListItemAvatar>
width: 50, <div
height: 50, style={{
borderRadius: '50%', width: 50,
backgroundColor: 'white' height: 50,
}} borderRadius: '50%',
> backgroundColor: 'white'
<img }}
style={{ >
width: '100%', <img
height: '100%', style={{
padding: 10, width: '100%',
objectFit: 'contain' height: '100%',
}} padding: 10,
alt='AI' objectFit: 'contain'
src={provider.icon} }}
/> alt='AI'
</div> src={speechToTextProviders[selectedProvider].icon}
</ListItemAvatar> />
<ListItemText </div>
sx={{ ml: 1 }} </ListItemAvatar>
primary={provider.label} <ListItemText
secondary={ sx={{ ml: 1 }}
<a target='_blank' rel='noreferrer' href={provider.url}> primary={speechToTextProviders[selectedProvider].label}
{provider.url} secondary={
</a> <a target='_blank' rel='noreferrer' href={speechToTextProviders[selectedProvider].url}>
{speechToTextProviders[selectedProvider].url}
</a>
}
/>
{speechToText[selectedProvider] && speechToText[selectedProvider].status && (
<div
style={{
display: 'flex',
flexDirection: 'row',
alignContent: 'center',
alignItems: 'center',
background: '#d8f3dc',
borderRadius: 15,
padding: 5,
paddingLeft: 7,
paddingRight: 7,
marginRight: 10
}}
>
<div
style={{
width: 15,
height: 15,
borderRadius: '50%',
backgroundColor: '#70e000'
}}
/>
<span style={{ color: '#006400', marginLeft: 10 }}>ON</span>
</div>
)}
</ListItem>
{speechToTextProviders[selectedProvider].inputs.map((inputParam, index) => (
<Box key={index} sx={{ p: 2 }}>
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Typography>
{inputParam.label}
{!inputParam.optional && <span style={{ color: 'red' }}>&nbsp;*</span>}
{inputParam.description && (
<TooltipWithParser style={{ marginLeft: 10 }} title={inputParam.description} />
)}
</Typography>
</div>
{inputParam.type === 'credential' && (
<CredentialInputHandler
data={speechToText[selectedProvider] ? { credential: speechToText[selectedProvider].credentialId } : {}}
inputParam={inputParam}
onSelect={(newValue) => setValue(newValue, selectedProvider, 'credentialId')}
/>
)}
{inputParam.type === 'boolean' && (
<SwitchInput
onChange={(newValue) => setValue(newValue, selectedProvider, inputParam.name)}
value={
speechToText[selectedProvider]
? speechToText[selectedProvider][inputParam.name]
: inputParam.default ?? false
} }
/> />
{speechToText[provider.name] && speechToText[provider.name].status && ( )}
<div {(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && (
style={{ <Input
display: 'flex', inputParam={inputParam}
flexDirection: 'row', onChange={(newValue) => setValue(newValue, selectedProvider, inputParam.name)}
alignContent: 'center', value={
alignItems: 'center', speechToText[selectedProvider]
background: '#d8f3dc', ? speechToText[selectedProvider][inputParam.name]
borderRadius: 15, : inputParam.default ?? ''
padding: 5, }
paddingLeft: 7, />
paddingRight: 7, )}
marginRight: 10
}}
>
<div
style={{
width: 15,
height: 15,
borderRadius: '50%',
backgroundColor: '#70e000'
}}
/>
<span style={{ color: '#006400', marginLeft: 10 }}>ON</span>
</div>
)}
</ListItem>
</AccordionSummary>
<AccordionDetails>
{provider.inputs.map((inputParam, index) => (
<Box key={index} sx={{ p: 2 }}>
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Typography>
{inputParam.label}
{!inputParam.optional && <span style={{ color: 'red' }}>&nbsp;*</span>}
{inputParam.description && (
<TooltipWithParser style={{ marginLeft: 10 }} title={inputParam.description} />
)}
</Typography>
</div>
{providerExpanded[provider.name] && inputParam.type === 'credential' && (
<CredentialInputHandler
data={
speechToText[provider.name] ? { credential: speechToText[provider.name].credentialId } : {}
}
inputParam={inputParam}
onSelect={(newValue) => setValue(newValue, provider.name, 'credentialId')}
/>
)}
{inputParam.type === 'boolean' && (
<SwitchInput
onChange={(newValue) => setValue(newValue, provider.name, inputParam.name)}
value={
speechToText[provider.name]
? speechToText[provider.name][inputParam.name]
: inputParam.default ?? false
}
/>
)}
{providerExpanded[provider.name] &&
(inputParam.type === 'string' ||
inputParam.type === 'password' ||
inputParam.type === 'number') && (
<Input
inputParam={inputParam}
onChange={(newValue) => setValue(newValue, provider.name, inputParam.name)}
value={
speechToText[provider.name]
? speechToText[provider.name][inputParam.name]
: inputParam.default ?? ''
}
/>
)}
{providerExpanded[provider.name] && inputParam.type === 'options' && ( {inputParam.type === 'options' && (
<Dropdown <Dropdown
name={inputParam.name} name={inputParam.name}
options={inputParam.options} options={inputParam.options}
onSelect={(newValue) => setValue(newValue, provider.name, inputParam.name)} onSelect={(newValue) => setValue(newValue, selectedProvider, inputParam.name)}
value={ value={
speechToText[provider.name] speechToText[selectedProvider]
? speechToText[provider.name][inputParam.name] ? speechToText[selectedProvider][inputParam.name]
: inputParam.default ?? 'choose an option' : inputParam.default ?? 'choose an option'
} }
/> />
)} )}
</Box> </Box>
))} ))}
</AccordionDetails> </>
</Accordion>
))}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<StyledButton variant='contained' onClick={onSave}> <StyledButton variant='contained' onClick={onSave}>

View File

@ -105,7 +105,11 @@ export const AsyncDropdown = ({
})() })()
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []) }, [credentialNames])
useEffect(() => {
setInternalValue(value)
}, [value])
return ( return (
<> <>

View File

@ -1,5 +1,5 @@
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
// material-ui // material-ui
import { IconButton } from '@mui/material' import { IconButton } from '@mui/material'
@ -88,6 +88,10 @@ const CredentialInputHandler = ({ inputParam, data, onSelect, disabled = false }
setShowSpecificCredentialDialog(true) setShowSpecificCredentialDialog(true)
} }
useEffect(() => {
setCredentialId(data?.credential ?? '')
}, [data])
return ( return (
<div ref={ref}> <div ref={ref}>
{inputParam && ( {inputParam && (