From 54c59024c5039eee801cc5fddfa2dd6fc55c54c6 Mon Sep 17 00:00:00 2001 From: Ilango Date: Tue, 5 Mar 2024 16:25:35 +0530 Subject: [PATCH 01/12] Add chatflow config dialog --- packages/ui/src/menu-items/settings.js | 19 +- .../dialog/ChatflowConfigurationDialog.js | 102 +++++++ .../ui-component/dialog/SpeechToTextDialog.js | 276 ++++++++---------- packages/ui/src/views/canvas/CanvasHeader.js | 28 +- .../ui/src/views/chatflows/APICodeDialog.js | 4 +- packages/ui/src/views/settings/index.js | 2 +- 6 files changed, 249 insertions(+), 182 deletions(-) create mode 100644 packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js diff --git a/packages/ui/src/menu-items/settings.js b/packages/ui/src/menu-items/settings.js index af45fba7..3e43d025 100644 --- a/packages/ui/src/menu-items/settings.js +++ b/packages/ui/src/menu-items/settings.js @@ -7,11 +7,20 @@ import { IconSearch, IconMessage, IconPictureInPictureOff, - IconMicrophone + IconAdjustmentsHorizontal } from '@tabler/icons' // constant -const icons = { IconTrash, IconFileUpload, IconFileExport, IconCopy, IconSearch, IconMessage, IconPictureInPictureOff, IconMicrophone } +const icons = { + IconTrash, + IconFileUpload, + IconFileExport, + IconCopy, + IconSearch, + IconMessage, + IconPictureInPictureOff, + IconAdjustmentsHorizontal +} // ==============================|| SETTINGS MENU ITEMS ||============================== // @@ -35,11 +44,11 @@ const settings = { icon: icons.IconMessage }, { - id: 'enableSpeechToText', - title: 'Speech to Text', + id: 'chatflowConfiguration', + title: 'Configuration', type: 'item', url: '', - icon: icons.IconMicrophone + icon: icons.IconAdjustmentsHorizontal }, { id: 'duplicateChatflow', diff --git a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js new file mode 100644 index 00000000..5f5b78a7 --- /dev/null +++ b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js @@ -0,0 +1,102 @@ +import PropTypes from 'prop-types' +import { useState } from 'react' +import { createPortal } from 'react-dom' +import { Box, Dialog, DialogContent, DialogTitle, Tabs, Tab } from '@mui/material' +import SpeechToText from './SpeechToTextDialog' +import Configuration from 'views/chatflows/Configuration' + +const CHATFLOW_CONFIGURATION_TABS = [ + { + label: 'Rate Limiting', + id: 'rateLimiting' + }, + { + label: 'Speech to Text', + id: 'speechToText' + }, + { + label: 'Chat Feedback', + id: 'chatFeedback' + }, + { + label: 'Allowed Domains', + id: 'allowedDomains' + } +] + +function TabPanel(props) { + const { children, value, index, ...other } = props + return ( + + ) +} + +TabPanel.propTypes = { + children: PropTypes.node, + index: PropTypes.number.isRequired, + value: PropTypes.number.isRequired +} + +function a11yProps(index) { + return { + id: `chatflow-config-tab-${index}`, + 'aria-controls': `chatflow-config-tabpanel-${index}` + } +} + +const ChatflowConfigurationDialog = ({ show, dialogProps, onCancel }) => { + const portalElement = document.getElementById('portal') + const [tabValue, setTabValue] = useState(0) + + const component = show ? ( + + +
{dialogProps.title}
+
+ + setTabValue(value)} + aria-label='tabs' + > + {CHATFLOW_CONFIGURATION_TABS.map((item, index) => ( + + ))} + + {CHATFLOW_CONFIGURATION_TABS.map((item, index) => ( + + {item.id === 'rateLimiting' && } + {item.id === 'speechToText' ? : null} + + ))} + +
+ ) : null + + return createPortal(component, portalElement) +} + +ChatflowConfigurationDialog.propTypes = { + show: PropTypes.bool, + dialogProps: PropTypes.object, + onCancel: PropTypes.func +} + +export default ChatflowConfigurationDialog diff --git a/packages/ui/src/ui-component/dialog/SpeechToTextDialog.js b/packages/ui/src/ui-component/dialog/SpeechToTextDialog.js index 489d4335..7199bf8c 100644 --- a/packages/ui/src/ui-component/dialog/SpeechToTextDialog.js +++ b/packages/ui/src/ui-component/dialog/SpeechToTextDialog.js @@ -1,25 +1,10 @@ -import { createPortal } from 'react-dom' import { useDispatch } from 'react-redux' import { useState, useEffect } from 'react' import PropTypes from 'prop-types' import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions' // material-ui -import { - Typography, - Box, - Button, - Dialog, - DialogContent, - DialogTitle, - DialogActions, - FormControl, - ListItem, - ListItemAvatar, - ListItemText, - MenuItem, - Select -} from '@mui/material' +import { Typography, Box, Button, FormControl, ListItem, ListItemAvatar, ListItemText, MenuItem, Select } from '@mui/material' import { IconX } from '@tabler/icons' // Project import @@ -33,7 +18,6 @@ import openAISVG from 'assets/images/openai.svg' import assemblyAIPng from 'assets/images/assemblyai.png' // store -import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' import useNotifier from 'utils/useNotifier' // API @@ -95,8 +79,7 @@ const speechToTextProviders = { } } -const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => { - const portalElement = document.getElementById('portal') +const SpeechToText = ({ dialogProps }) => { const dispatch = useDispatch() useNotifier() @@ -128,7 +111,6 @@ const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => { }) dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data }) } - onCancel() } catch (error) { const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` enqueueSnackbar({ @@ -199,150 +181,126 @@ const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => { } }, [dialogProps]) - useEffect(() => { - if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) - else dispatch({ type: HIDE_CANVAS_DIALOG }) - return () => dispatch({ type: HIDE_CANVAS_DIALOG }) - }, [show, dispatch]) - - const component = ( - - - Speech To Text Configuration - - - - Speech To Text Providers - - - - - {selectedProvider !== 'none' && ( - <> - - -
+ + Speech To Text Providers + + + + + {selectedProvider !== 'none' && ( + <> + + +
+ - AI -
-
- - {speechToTextProviders[selectedProvider].url} - - } - /> -
- {speechToTextProviders[selectedProvider].inputs.map((inputParam, index) => ( - -
- - {inputParam.label} - {!inputParam.optional &&  *} - {inputParam.description && ( - - )} - -
- {inputParam.type === 'credential' && ( - setValue(newValue, selectedProvider, 'credentialId')} - /> - )} - {inputParam.type === 'boolean' && ( - setValue(newValue, selectedProvider, inputParam.name)} - value={ - speechToText[selectedProvider] - ? speechToText[selectedProvider][inputParam.name] - : inputParam.default ?? false - } - /> - )} - {(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && ( - setValue(newValue, selectedProvider, inputParam.name)} - value={ - speechToText[selectedProvider] - ? speechToText[selectedProvider][inputParam.name] - : inputParam.default ?? '' - } - /> - )} + alt='AI' + src={speechToTextProviders[selectedProvider].icon} + /> +
+
+ + {speechToTextProviders[selectedProvider].url} + + } + /> +
+ {speechToTextProviders[selectedProvider].inputs.map((inputParam, index) => ( + +
+ + {inputParam.label} + {!inputParam.optional &&  *} + {inputParam.description && ( + + )} + +
+ {inputParam.type === 'credential' && ( + setValue(newValue, selectedProvider, 'credentialId')} + /> + )} + {inputParam.type === 'boolean' && ( + setValue(newValue, selectedProvider, inputParam.name)} + value={ + speechToText[selectedProvider] + ? speechToText[selectedProvider][inputParam.name] + : inputParam.default ?? false + } + /> + )} + {(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && ( + setValue(newValue, selectedProvider, inputParam.name)} + value={ + speechToText[selectedProvider] + ? speechToText[selectedProvider][inputParam.name] + : inputParam.default ?? '' + } + /> + )} - {inputParam.type === 'options' && ( - setValue(newValue, selectedProvider, inputParam.name)} - value={ - speechToText[selectedProvider] - ? speechToText[selectedProvider][inputParam.name] - : inputParam.default ?? 'choose an option' - } - /> - )} -
- ))} - - )} -
- - - Save - - -
+ {inputParam.type === 'options' && ( + setValue(newValue, selectedProvider, inputParam.name)} + value={ + speechToText[selectedProvider] + ? speechToText[selectedProvider][inputParam.name] + : inputParam.default ?? 'choose an option' + } + /> + )} + + ))} + + )} + + Save + + ) - - return createPortal(component, portalElement) } -SpeechToTextDialog.propTypes = { - show: PropTypes.bool, - dialogProps: PropTypes.object, - onCancel: PropTypes.func +SpeechToText.propTypes = { + dialogProps: PropTypes.object } -export default SpeechToTextDialog +export default SpeechToText diff --git a/packages/ui/src/views/canvas/CanvasHeader.js b/packages/ui/src/views/canvas/CanvasHeader.js index a8589f48..d9f54d19 100644 --- a/packages/ui/src/views/canvas/CanvasHeader.js +++ b/packages/ui/src/views/canvas/CanvasHeader.js @@ -28,7 +28,7 @@ import useApi from 'hooks/useApi' import { generateExportFlowData } from 'utils/genericHelper' import { uiBaseURL } from 'store/constant' import { SET_CHATFLOW } from 'store/actions' -import SpeechToTextDialog from '../../ui-component/dialog/SpeechToTextDialog' +import ChatflowConfigurationDialog from 'ui-component/dialog/ChatflowConfigurationDialog' // ==============================|| CANVAS HEADER ||============================== // @@ -47,12 +47,12 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl const [apiDialogProps, setAPIDialogProps] = useState({}) const [analyseDialogOpen, setAnalyseDialogOpen] = useState(false) const [analyseDialogProps, setAnalyseDialogProps] = useState({}) - const [speechToAudioDialogOpen, setSpeechToAudioDialogOpen] = useState(false) - const [speechToAudioDialogProps, setSpeechToAudioialogProps] = useState({}) const [conversationStartersDialogOpen, setConversationStartersDialogOpen] = useState(false) const [conversationStartersDialogProps, setConversationStartersDialogProps] = useState({}) const [viewMessagesDialogOpen, setViewMessagesDialogOpen] = useState(false) const [viewMessagesDialogProps, setViewMessagesDialogProps] = useState({}) + const [chatflowConfigurationDialogOpen, setChatflowConfigurationDialogOpen] = useState(false) + const [chatflowConfigurationDialogProps, setChatflowConfigurationDialogProps] = useState({}) const updateChatflowApi = useApi(chatflowsApi.updateChatflow) const canvas = useSelector((state) => state.canvas) @@ -74,18 +74,18 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl chatflow: chatflow }) setAnalyseDialogOpen(true) - } else if (setting === 'enableSpeechToText') { - setSpeechToAudioialogProps({ - title: 'Speech to Text', - chatflow: chatflow - }) - setSpeechToAudioDialogOpen(true) } else if (setting === 'viewMessages') { setViewMessagesDialogProps({ title: 'View Messages', chatflow: chatflow }) setViewMessagesDialogOpen(true) + } else if (setting === 'chatflowConfiguration') { + setChatflowConfigurationDialogProps({ + title: 'Chatflow Configuration', + chatflow: chatflow + }) + setChatflowConfigurationDialogOpen(true) } else if (setting === 'duplicateChatflow') { try { localStorage.setItem('duplicatedFlowData', chatflow.flowData) @@ -394,11 +394,6 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl /> setAPIDialogOpen(false)} /> setAnalyseDialogOpen(false)} /> - setSpeechToAudioDialogOpen(false)} - /> setViewMessagesDialogOpen(false)} /> + setChatflowConfigurationDialogOpen(false)} + /> ) } diff --git a/packages/ui/src/views/chatflows/APICodeDialog.js b/packages/ui/src/views/chatflows/APICodeDialog.js index 34c2281f..8889f4ee 100644 --- a/packages/ui/src/views/chatflows/APICodeDialog.js +++ b/packages/ui/src/views/chatflows/APICodeDialog.js @@ -23,7 +23,6 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import { Dropdown } from 'ui-component/dropdown/Dropdown' import ShareChatbot from './ShareChatbot' import EmbedChat from './EmbedChat' -import Configuration from './Configuration' // Const import { baseURL } from 'store/constant' @@ -84,7 +83,7 @@ const APICodeDialog = ({ show, dialogProps, onCancel }) => { const navigate = useNavigate() const dispatch = useDispatch() - const codes = ['Embed', 'Python', 'JavaScript', 'cURL', 'Share Chatbot', 'Configuration'] + const codes = ['Embed', 'Python', 'JavaScript', 'cURL', 'Share Chatbot'] const [value, setValue] = useState(0) const [keyOptions, setKeyOptions] = useState([]) const [apiKeys, setAPIKeys] = useState([]) @@ -721,7 +720,6 @@ formData.append("openAIApiKey[openAIEmbeddings_0]", "sk-my-openai-2nd-key")` {codeLang === 'Share Chatbot' && !chatflowApiKeyId && ( )} - {codeLang === 'Configuration' && } ))} diff --git a/packages/ui/src/views/settings/index.js b/packages/ui/src/views/settings/index.js index f7019b68..c5171d5e 100644 --- a/packages/ui/src/views/settings/index.js +++ b/packages/ui/src/views/settings/index.js @@ -65,7 +65,7 @@ const Settings = ({ chatflow, isSettingsOpen, anchorEl, onSettingsItemClick, onU width: customization.isOpen.findIndex((id) => id === menu?.id) > -1 ? 8 : 6, height: customization.isOpen.findIndex((id) => id === menu?.id) > -1 ? 8 : 6 }} - fontSize={level > 0 ? 'inherit' : 'medium'} + fontSize={'inherit'} /> ) return ( From 811a6a0f4105fce47284e595973b592dc90116fa Mon Sep 17 00:00:00 2001 From: Ilango Date: Tue, 5 Mar 2024 17:13:38 +0530 Subject: [PATCH 02/12] Update allowed domains help text --- packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js b/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js index f389aebc..cb0e9c8e 100644 --- a/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js +++ b/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js @@ -113,10 +113,7 @@ const AllowedDomains = ({ dialogProps }) => { flexDirection: 'column' }} > - - Your chatbot will only work when used from the following domains. When adding domains, exclude the{' '} -
http://
or
https://
part. -
+ Your chatbot will only work when used from the following domains. :not(style)': { m: 1 }, pt: 2 }}> From 7020974b5562a40bc71d0dca90a296fd10e94deb Mon Sep 17 00:00:00 2001 From: Ilango Date: Tue, 12 Mar 2024 00:43:11 +0530 Subject: [PATCH 03/12] Update chatflow configuration dialog - add starter prompts, analyse chatflow. Rename files. --- packages/ui/src/menu-items/settings.js | 27 +- ...owedDomainsDialog.js => AllowedDomains.js} | 0 .../ui/src/ui-component/dialog/AnalyseFlow.js | 325 ++++++++++++++++ .../ui-component/dialog/AnalyseFlowDialog.js | 358 ------------------ ...{ChatFeedbackDialog.js => ChatFeedback.js} | 2 +- .../dialog/ChatflowConfigurationDialog.js | 30 +- ...{SpeechToTextDialog.js => SpeechToText.js} | 7 +- .../src/ui-component/dialog/StarterPrompts.js | 215 +++++++++++ .../dialog/StarterPromptsDialog.js | 208 +--------- packages/ui/src/views/canvas/CanvasHeader.js | 25 -- 10 files changed, 576 insertions(+), 621 deletions(-) rename packages/ui/src/ui-component/dialog/{AllowedDomainsDialog.js => AllowedDomains.js} (100%) create mode 100644 packages/ui/src/ui-component/dialog/AnalyseFlow.js delete mode 100644 packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js rename packages/ui/src/ui-component/dialog/{ChatFeedbackDialog.js => ChatFeedback.js} (97%) rename packages/ui/src/ui-component/dialog/{SpeechToTextDialog.js => SpeechToText.js} (98%) create mode 100644 packages/ui/src/ui-component/dialog/StarterPrompts.js diff --git a/packages/ui/src/menu-items/settings.js b/packages/ui/src/menu-items/settings.js index 3e43d025..9b83aaa4 100644 --- a/packages/ui/src/menu-items/settings.js +++ b/packages/ui/src/menu-items/settings.js @@ -1,14 +1,5 @@ // assets -import { - IconTrash, - IconFileUpload, - IconFileExport, - IconCopy, - IconSearch, - IconMessage, - IconPictureInPictureOff, - IconAdjustmentsHorizontal -} from '@tabler/icons' +import { IconTrash, IconFileUpload, IconFileExport, IconCopy, IconMessage, IconAdjustmentsHorizontal } from '@tabler/icons' // constant const icons = { @@ -16,9 +7,7 @@ const icons = { IconFileUpload, IconFileExport, IconCopy, - IconSearch, IconMessage, - IconPictureInPictureOff, IconAdjustmentsHorizontal } @@ -29,13 +18,6 @@ const settings = { title: '', type: 'group', children: [ - { - id: 'conversationStarters', - title: 'Starter Prompts', - type: 'item', - url: '', - icon: icons.IconPictureInPictureOff - }, { id: 'viewMessages', title: 'View Messages', @@ -71,13 +53,6 @@ const settings = { url: '', icon: icons.IconFileExport }, - { - id: 'analyseChatflow', - title: 'Analyse Chatflow', - type: 'item', - url: '', - icon: icons.IconSearch - }, { id: 'deleteChatflow', title: 'Delete Chatflow', diff --git a/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js b/packages/ui/src/ui-component/dialog/AllowedDomains.js similarity index 100% rename from packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js rename to packages/ui/src/ui-component/dialog/AllowedDomains.js diff --git a/packages/ui/src/ui-component/dialog/AnalyseFlow.js b/packages/ui/src/ui-component/dialog/AnalyseFlow.js new file mode 100644 index 00000000..8bebea31 --- /dev/null +++ b/packages/ui/src/ui-component/dialog/AnalyseFlow.js @@ -0,0 +1,325 @@ +import { useDispatch } from 'react-redux' +import { useState, useEffect } from 'react' +import PropTypes from 'prop-types' +import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions' + +// material-ui +import { + Typography, + Box, + Button, + Accordion, + AccordionSummary, + AccordionDetails, + ListItem, + ListItemAvatar, + ListItemText +} from '@mui/material' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' +import { IconX } from '@tabler/icons' + +// Project import +import CredentialInputHandler from 'views/canvas/CredentialInputHandler' +import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser' +import { SwitchInput } from 'ui-component/switch/Switch' +import { Input } from 'ui-component/input/Input' +import { StyledButton } from 'ui-component/button/StyledButton' +import langsmithPNG from 'assets/images/langchain.png' +import langfuseSVG from 'assets/images/langfuse.svg' +import lunarySVG from 'assets/images/lunary.svg' + +// store +import useNotifier from 'utils/useNotifier' + +// API +import chatflowsApi from 'api/chatflows' + +const analyticProviders = [ + { + label: 'LangSmith', + name: 'langSmith', + icon: langsmithPNG, + url: 'https://smith.langchain.com', + inputs: [ + { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['langsmithApi'] + }, + { + label: 'Project Name', + name: 'projectName', + type: 'string', + optional: true, + description: 'If not provided, default will be used', + placeholder: 'default' + }, + { + label: 'On/Off', + name: 'status', + type: 'boolean', + optional: true + } + ] + }, + { + label: 'LangFuse', + name: 'langFuse', + icon: langfuseSVG, + url: 'https://langfuse.com', + inputs: [ + { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['langfuseApi'] + }, + { + label: 'Release', + name: 'release', + type: 'string', + optional: true, + description: 'The release number/hash of the application to provide analytics grouped by release' + }, + { + label: 'On/Off', + name: 'status', + type: 'boolean', + optional: true + } + ] + }, + { + label: 'Lunary', + name: 'lunary', + icon: lunarySVG, + url: 'https://lunary.ai', + inputs: [ + { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['lunaryApi'] + }, + { + label: 'On/Off', + name: 'status', + type: 'boolean', + optional: true + } + ] + } +] + +const AnalyseFlow = ({ dialogProps, onCancel }) => { + const dispatch = useDispatch() + + useNotifier() + + const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) + const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) + + const [analytic, setAnalytic] = useState({}) + const [providerExpanded, setProviderExpanded] = useState({}) + + const onSave = async () => { + try { + const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, { + analytic: JSON.stringify(analytic) + }) + if (saveResp.data) { + enqueueSnackbar({ + message: 'Analytic Configuration Saved', + options: { + key: new Date().getTime() + Math.random(), + variant: 'success', + action: (key) => ( + + ) + } + }) + dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data }) + } + onCancel() + } catch (error) { + const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` + enqueueSnackbar({ + message: `Failed to save Analytic Configuration: ${errorData}`, + options: { + key: new Date().getTime() + Math.random(), + variant: 'error', + persist: true, + action: (key) => ( + + ) + } + }) + } + } + + const setValue = (value, providerName, inputParamName) => { + let newVal = {} + if (!Object.prototype.hasOwnProperty.call(analytic, providerName)) { + newVal = { ...analytic, [providerName]: {} } + } else { + newVal = { ...analytic } + } + + newVal[providerName][inputParamName] = value + setAnalytic(newVal) + } + + const handleAccordionChange = (providerName) => (event, isExpanded) => { + const accordianProviders = { ...providerExpanded } + accordianProviders[providerName] = isExpanded + setProviderExpanded(accordianProviders) + } + + useEffect(() => { + if (dialogProps.chatflow && dialogProps.chatflow.analytic) { + try { + setAnalytic(JSON.parse(dialogProps.chatflow.analytic)) + } catch (e) { + setAnalytic({}) + console.error(e) + } + } + + return () => { + setAnalytic({}) + setProviderExpanded({}) + } + }, [dialogProps]) + + return ( + <> + {analyticProviders.map((provider, index) => ( + + } aria-controls={provider.name} id={provider.name}> + + +
+ AI +
+
+ + {provider.url} + + } + /> + {analytic[provider.name] && analytic[provider.name].status && ( +
+
+ ON +
+ )} + + + + {provider.inputs.map((inputParam, index) => ( + +
+ + {inputParam.label} + {!inputParam.optional &&  *} + {inputParam.description && ( + + )} + +
+ {providerExpanded[provider.name] && inputParam.type === 'credential' && ( + setValue(newValue, provider.name, 'credentialId')} + /> + )} + {providerExpanded[provider.name] && inputParam.type === 'boolean' && ( + setValue(newValue, provider.name, inputParam.name)} + value={ + analytic[provider.name] ? analytic[provider.name][inputParam.name] : inputParam.default ?? false + } + /> + )} + {providerExpanded[provider.name] && + (inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && ( + setValue(newValue, provider.name, inputParam.name)} + value={ + analytic[provider.name] + ? analytic[provider.name][inputParam.name] + : inputParam.default ?? '' + } + /> + )} +
+ ))} +
+ + ))} + + Save + + + ) +} + +AnalyseFlow.propTypes = { + show: PropTypes.bool, + dialogProps: PropTypes.object, + onCancel: PropTypes.func +} + +export default AnalyseFlow diff --git a/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js b/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js deleted file mode 100644 index a326db9a..00000000 --- a/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js +++ /dev/null @@ -1,358 +0,0 @@ -import { createPortal } from 'react-dom' -import { useDispatch } from 'react-redux' -import { useState, useEffect } from 'react' -import PropTypes from 'prop-types' -import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions' - -// material-ui -import { - Typography, - Box, - Button, - Dialog, - DialogContent, - DialogTitle, - DialogActions, - Accordion, - AccordionSummary, - AccordionDetails, - ListItem, - ListItemAvatar, - ListItemText -} from '@mui/material' -import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import { IconX } from '@tabler/icons' - -// Project import -import CredentialInputHandler from 'views/canvas/CredentialInputHandler' -import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser' -import { SwitchInput } from 'ui-component/switch/Switch' -import { Input } from 'ui-component/input/Input' -import { StyledButton } from 'ui-component/button/StyledButton' -import langsmithPNG from 'assets/images/langchain.png' -import langfuseSVG from 'assets/images/langfuse.svg' -import lunarySVG from 'assets/images/lunary.svg' - -// store -import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' -import useNotifier from 'utils/useNotifier' - -// API -import chatflowsApi from 'api/chatflows' - -const analyticProviders = [ - { - label: 'LangSmith', - name: 'langSmith', - icon: langsmithPNG, - url: 'https://smith.langchain.com', - inputs: [ - { - label: 'Connect Credential', - name: 'credential', - type: 'credential', - credentialNames: ['langsmithApi'] - }, - { - label: 'Project Name', - name: 'projectName', - type: 'string', - optional: true, - description: 'If not provided, default will be used', - placeholder: 'default' - }, - { - label: 'On/Off', - name: 'status', - type: 'boolean', - optional: true - } - ] - }, - { - label: 'LangFuse', - name: 'langFuse', - icon: langfuseSVG, - url: 'https://langfuse.com', - inputs: [ - { - label: 'Connect Credential', - name: 'credential', - type: 'credential', - credentialNames: ['langfuseApi'] - }, - { - label: 'Release', - name: 'release', - type: 'string', - optional: true, - description: 'The release number/hash of the application to provide analytics grouped by release' - }, - { - label: 'On/Off', - name: 'status', - type: 'boolean', - optional: true - } - ] - }, - { - label: 'Lunary', - name: 'lunary', - icon: lunarySVG, - url: 'https://lunary.ai', - inputs: [ - { - label: 'Connect Credential', - name: 'credential', - type: 'credential', - credentialNames: ['lunaryApi'] - }, - { - label: 'On/Off', - name: 'status', - type: 'boolean', - optional: true - } - ] - } -] - -const AnalyseFlowDialog = ({ show, dialogProps, onCancel }) => { - const portalElement = document.getElementById('portal') - const dispatch = useDispatch() - - useNotifier() - - const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) - const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) - - const [analytic, setAnalytic] = useState({}) - const [providerExpanded, setProviderExpanded] = useState({}) - - const onSave = async () => { - try { - const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, { - analytic: JSON.stringify(analytic) - }) - if (saveResp.data) { - enqueueSnackbar({ - message: 'Analytic Configuration Saved', - options: { - key: new Date().getTime() + Math.random(), - variant: 'success', - action: (key) => ( - - ) - } - }) - dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data }) - } - onCancel() - } catch (error) { - const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` - enqueueSnackbar({ - message: `Failed to save Analytic Configuration: ${errorData}`, - options: { - key: new Date().getTime() + Math.random(), - variant: 'error', - persist: true, - action: (key) => ( - - ) - } - }) - } - } - - const setValue = (value, providerName, inputParamName) => { - let newVal = {} - if (!Object.prototype.hasOwnProperty.call(analytic, providerName)) { - newVal = { ...analytic, [providerName]: {} } - } else { - newVal = { ...analytic } - } - - newVal[providerName][inputParamName] = value - setAnalytic(newVal) - } - - const handleAccordionChange = (providerName) => (event, isExpanded) => { - const accordianProviders = { ...providerExpanded } - accordianProviders[providerName] = isExpanded - setProviderExpanded(accordianProviders) - } - - useEffect(() => { - if (dialogProps.chatflow && dialogProps.chatflow.analytic) { - try { - setAnalytic(JSON.parse(dialogProps.chatflow.analytic)) - } catch (e) { - setAnalytic({}) - console.error(e) - } - } - - return () => { - setAnalytic({}) - setProviderExpanded({}) - } - }, [dialogProps]) - - useEffect(() => { - if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) - else dispatch({ type: HIDE_CANVAS_DIALOG }) - return () => dispatch({ type: HIDE_CANVAS_DIALOG }) - }, [show, dispatch]) - - const component = show ? ( - - - Analyse Chatflow - - - {analyticProviders.map((provider, index) => ( - - } aria-controls={provider.name} id={provider.name}> - - -
- AI -
-
- - {provider.url} - - } - /> - {analytic[provider.name] && analytic[provider.name].status && ( -
-
- ON -
- )} - - - - {provider.inputs.map((inputParam, index) => ( - -
- - {inputParam.label} - {!inputParam.optional &&  *} - {inputParam.description && ( - - )} - -
- {providerExpanded[provider.name] && inputParam.type === 'credential' && ( - setValue(newValue, provider.name, 'credentialId')} - /> - )} - {providerExpanded[provider.name] && inputParam.type === 'boolean' && ( - setValue(newValue, provider.name, inputParam.name)} - value={ - analytic[provider.name] - ? analytic[provider.name][inputParam.name] - : inputParam.default ?? false - } - /> - )} - {providerExpanded[provider.name] && - (inputParam.type === 'string' || - inputParam.type === 'password' || - inputParam.type === 'number') && ( - setValue(newValue, provider.name, inputParam.name)} - value={ - analytic[provider.name] - ? analytic[provider.name][inputParam.name] - : inputParam.default ?? '' - } - /> - )} -
- ))} -
- - ))} - - - - Save - - -
- ) : null - - return createPortal(component, portalElement) -} - -AnalyseFlowDialog.propTypes = { - show: PropTypes.bool, - dialogProps: PropTypes.object, - onCancel: PropTypes.func -} - -export default AnalyseFlowDialog diff --git a/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js b/packages/ui/src/ui-component/dialog/ChatFeedback.js similarity index 97% rename from packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js rename to packages/ui/src/ui-component/dialog/ChatFeedback.js index 493f1031..2ea2db38 100644 --- a/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js +++ b/packages/ui/src/ui-component/dialog/ChatFeedback.js @@ -93,7 +93,7 @@ const ChatFeedback = ({ dialogProps }) => { - + Save diff --git a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js index 13ca4a15..1c30aa0c 100644 --- a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js +++ b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js @@ -2,16 +2,22 @@ import PropTypes from 'prop-types' import { useState } from 'react' import { createPortal } from 'react-dom' import { Box, Dialog, DialogContent, DialogTitle, Tabs, Tab } from '@mui/material' -import SpeechToText from './SpeechToTextDialog' +import SpeechToText from './SpeechToText' import Configuration from 'views/chatflows/Configuration' -import AllowedDomains from './AllowedDomainsDialog' -import ChatFeedback from './ChatFeedbackDialog' +import AllowedDomains from './AllowedDomains' +import ChatFeedback from './ChatFeedback' +import AnalyseFlow from './AnalyseFlow' +import StarterPrompts from './StarterPrompts' const CHATFLOW_CONFIGURATION_TABS = [ { label: 'Rate Limiting', id: 'rateLimiting' }, + { + label: 'Starter Prompts', + id: 'conversationStarters' + }, { label: 'Speech to Text', id: 'speechToText' @@ -23,6 +29,10 @@ const CHATFLOW_CONFIGURATION_TABS = [ { label: 'Allowed Domains', id: 'allowedDomains' + }, + { + label: 'Analyse Chatflow', + id: 'analyseChatflow' } ] @@ -34,7 +44,7 @@ function TabPanel(props) { hidden={value !== index} id={`chatflow-config-tabpanel-${index}`} aria-labelledby={`chatflow-config-tab-${index}`} - style={{ paddingTop: '1rem' }} + style={{ width: '100%', paddingTop: '1rem' }} {...other} > {value === index && {children}} @@ -73,22 +83,28 @@ const ChatflowConfigurationDialog = ({ show, dialogProps, onCancel }) => { setTabValue(value)} aria-label='tabs' > {CHATFLOW_CONFIGURATION_TABS.map((item, index) => ( - + ))} {CHATFLOW_CONFIGURATION_TABS.map((item, index) => ( {item.id === 'rateLimiting' && } + {item.id === 'conversationStarters' ? : null} {item.id === 'speechToText' ? : null} {item.id === 'chatFeedback' ? : null} {item.id === 'allowedDomains' ? : null} + {item.id === 'analyseChatflow' ? : null} ))} diff --git a/packages/ui/src/ui-component/dialog/SpeechToTextDialog.js b/packages/ui/src/ui-component/dialog/SpeechToText.js similarity index 98% rename from packages/ui/src/ui-component/dialog/SpeechToTextDialog.js rename to packages/ui/src/ui-component/dialog/SpeechToText.js index 7199bf8c..eb5e5af6 100644 --- a/packages/ui/src/ui-component/dialog/SpeechToTextDialog.js +++ b/packages/ui/src/ui-component/dialog/SpeechToText.js @@ -183,8 +183,10 @@ const SpeechToText = ({ dialogProps }) => { return ( <> - - Speech To Text Providers + + + Providers + setValue(newValue, provider.name, inputParam.name)} - value={ - analytic[provider.name] - ? analytic[provider.name][inputParam.name] - : inputParam.default ?? '' - } - /> - )} - - ))} - - - ))} - - - - Save - - - - ) : null - - return createPortal(component, portalElement) -} - -AnalyseFlowDialog.propTypes = { - show: PropTypes.bool, - dialogProps: PropTypes.object, - onCancel: PropTypes.func -} - -export default AnalyseFlowDialog diff --git a/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx b/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx deleted file mode 100644 index 1706d624..00000000 --- a/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useDispatch } from 'react-redux' -import { useState, useEffect } from 'react' -import PropTypes from 'prop-types' - -// material-ui -import { Button, Box } from '@mui/material' -import { IconX } from '@tabler/icons' - -// Project import -import { StyledButton } from '@/ui-component/button/StyledButton' -import { SwitchInput } from '@/ui-component/switch/Switch' - -// store -import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from '@/store/actions' -import useNotifier from '@/utils/useNotifier' - -// API -import chatflowsApi from '@/api/chatflows' - -const ChatFeedback = ({ dialogProps }) => { - const dispatch = useDispatch() - - useNotifier() - - const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) - const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) - - const [chatFeedbackStatus, setChatFeedbackStatus] = useState(false) - const [chatbotConfig, setChatbotConfig] = useState({}) - - const handleChange = (value) => { - setChatFeedbackStatus(value) - } - - const onSave = async () => { - try { - let value = { - chatFeedback: { - status: chatFeedbackStatus - } - } - chatbotConfig.chatFeedback = value.chatFeedback - const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, { - chatbotConfig: JSON.stringify(chatbotConfig) - }) - if (saveResp.data) { - enqueueSnackbar({ - message: 'Chat Feedback Settings Saved', - options: { - key: new Date().getTime() + Math.random(), - variant: 'success', - action: (key) => ( - - ) - } - }) - dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data }) - } - } catch (error) { - const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` - enqueueSnackbar({ - message: `Failed to save Chat Feedback Settings: ${errorData}`, - options: { - key: new Date().getTime() + Math.random(), - variant: 'error', - persist: true, - action: (key) => ( - - ) - } - }) - } - } - - useEffect(() => { - if (dialogProps.chatflow && dialogProps.chatflow.chatbotConfig) { - let chatbotConfig = JSON.parse(dialogProps.chatflow.chatbotConfig) - setChatbotConfig(chatbotConfig || {}) - if (chatbotConfig.chatFeedback) { - setChatFeedbackStatus(chatbotConfig.chatFeedback.status) - } - } - - return () => {} - }, [dialogProps]) - - return ( - <> - - - - - Save - - - ) -} - -ChatFeedback.propTypes = { - dialogProps: PropTypes.object -} - -export default ChatFeedback diff --git a/packages/ui/src/ui-component/dialog/SpeechToTextDialog.jsx b/packages/ui/src/ui-component/dialog/SpeechToTextDialog.jsx deleted file mode 100644 index ef410ae6..00000000 --- a/packages/ui/src/ui-component/dialog/SpeechToTextDialog.jsx +++ /dev/null @@ -1,348 +0,0 @@ -import { createPortal } from 'react-dom' -import { useDispatch } from 'react-redux' -import { useState, useEffect } from 'react' -import PropTypes from 'prop-types' -import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from '@/store/actions' - -// material-ui -import { - Typography, - Box, - Button, - Dialog, - DialogContent, - DialogTitle, - DialogActions, - FormControl, - ListItem, - ListItemAvatar, - ListItemText, - MenuItem, - Select -} from '@mui/material' -import { IconX } from '@tabler/icons' - -// Project import -import CredentialInputHandler from '@/views/canvas/CredentialInputHandler' -import { TooltipWithParser } from '@/ui-component/tooltip/TooltipWithParser' -import { SwitchInput } from '@/ui-component/switch/Switch' -import { Input } from '@/ui-component/input/Input' -import { StyledButton } from '@/ui-component/button/StyledButton' -import { Dropdown } from '@/ui-component/dropdown/Dropdown' -import openAISVG from '@/assets/images/openai.svg' -import assemblyAIPng from '@/assets/images/assemblyai.png' - -// store -import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from '@/store/actions' -import useNotifier from '@/utils/useNotifier' - -// API -import chatflowsApi from '@/api/chatflows' - -const speechToTextProviders = { - openAIWhisper: { - label: 'OpenAI Whisper', - name: 'openAIWhisper', - icon: openAISVG, - url: 'https://platform.openai.com/docs/guides/speech-to-text', - inputs: [ - { - label: 'Connect Credential', - name: 'credential', - type: 'credential', - credentialNames: ['openAIApi'] - }, - { - label: 'Language', - name: 'language', - type: 'string', - description: - 'The language of the input audio. Supplying the input language in ISO-639-1 format will improve accuracy and latency.', - placeholder: 'en', - optional: true - }, - { - label: 'Prompt', - name: 'prompt', - type: 'string', - rows: 4, - description: `An optional text to guide the model's style or continue a previous audio segment. The prompt should match the audio language.`, - optional: true - }, - { - label: 'Temperature', - name: 'temperature', - type: 'number', - 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.`, - optional: true - } - ] - }, - assemblyAiTranscribe: { - label: 'Assembly AI', - name: 'assemblyAiTranscribe', - icon: assemblyAIPng, - url: 'https://www.assemblyai.com/', - inputs: [ - { - label: 'Connect Credential', - name: 'credential', - type: 'credential', - credentialNames: ['assemblyAIApi'] - } - ] - } -} - -const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => { - const portalElement = document.getElementById('portal') - const dispatch = useDispatch() - - useNotifier() - - const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) - const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) - - const [speechToText, setSpeechToText] = useState({}) - const [selectedProvider, setSelectedProvider] = useState('none') - - const onSave = async () => { - const speechToText = setValue(true, selectedProvider, 'status') - try { - const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, { - speechToText: JSON.stringify(speechToText) - }) - if (saveResp.data) { - enqueueSnackbar({ - message: 'Speech To Text Configuration Saved', - options: { - key: new Date().getTime() + Math.random(), - variant: 'success', - action: (key) => ( - - ) - } - }) - dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data }) - } - onCancel() - } catch (error) { - const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` - enqueueSnackbar({ - message: `Failed to save Speech To Text Configuration: ${errorData}`, - options: { - key: new Date().getTime() + Math.random(), - variant: 'error', - persist: true, - action: (key) => ( - - ) - } - }) - } - } - - const setValue = (value, providerName, inputParamName) => { - let newVal = {} - if (!Object.prototype.hasOwnProperty.call(speechToText, providerName)) { - newVal = { ...speechToText, [providerName]: {} } - } else { - newVal = { ...speechToText } - } - - newVal[providerName][inputParamName] = value - if (inputParamName === 'status' && value === true) { - // ensure that the others are turned off - Object.keys(speechToTextProviders).forEach((key) => { - const provider = speechToTextProviders[key] - if (provider.name !== providerName) { - newVal[provider.name] = { ...speechToText[provider.name], status: false } - } - }) - } - setSpeechToText(newVal) - return newVal - } - - const handleProviderChange = (event) => { - setSelectedProvider(event.target.value) - } - - useEffect(() => { - if (dialogProps.chatflow && dialogProps.chatflow.speechToText) { - try { - const speechToText = JSON.parse(dialogProps.chatflow.speechToText) - let selectedProvider = 'none' - Object.keys(speechToTextProviders).forEach((key) => { - const providerConfig = speechToText[key] - if (providerConfig && providerConfig.status) { - selectedProvider = key - } - }) - setSelectedProvider(selectedProvider) - setSpeechToText(speechToText) - } catch (e) { - setSpeechToText({}) - setSelectedProvider('none') - console.error(e) - } - } - - return () => { - setSpeechToText({}) - setSelectedProvider('none') - } - }, [dialogProps]) - - useEffect(() => { - if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) - else dispatch({ type: HIDE_CANVAS_DIALOG }) - return () => dispatch({ type: HIDE_CANVAS_DIALOG }) - }, [show, dispatch]) - - const component = ( - - - Speech To Text Configuration - - - - Speech To Text Providers - - - - - {selectedProvider !== 'none' && ( - <> - - -
- AI -
-
- - {speechToTextProviders[selectedProvider].url} - - } - /> -
- {speechToTextProviders[selectedProvider].inputs.map((inputParam, index) => ( - -
- - {inputParam.label} - {!inputParam.optional &&  *} - {inputParam.description && ( - - )} - -
- {inputParam.type === 'credential' && ( - setValue(newValue, selectedProvider, 'credentialId')} - /> - )} - {inputParam.type === 'boolean' && ( - setValue(newValue, selectedProvider, inputParam.name)} - value={ - speechToText[selectedProvider] - ? speechToText[selectedProvider][inputParam.name] - : inputParam.default ?? false - } - /> - )} - {(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && ( - setValue(newValue, selectedProvider, inputParam.name)} - value={ - speechToText[selectedProvider] - ? speechToText[selectedProvider][inputParam.name] - : inputParam.default ?? '' - } - /> - )} - - {inputParam.type === 'options' && ( - setValue(newValue, selectedProvider, inputParam.name)} - value={ - speechToText[selectedProvider] - ? speechToText[selectedProvider][inputParam.name] - : inputParam.default ?? 'choose an option' - } - /> - )} -
- ))} - - )} -
- - - Save - - -
- ) - - return createPortal(component, portalElement) -} - -SpeechToTextDialog.propTypes = { - show: PropTypes.bool, - dialogProps: PropTypes.object, - onCancel: PropTypes.func -} - -export default SpeechToTextDialog From 4a6e71058c40286cb8349ed53dfd9e0d7ab4c0ca Mon Sep 17 00:00:00 2001 From: Ilango Date: Tue, 12 Mar 2024 22:03:44 +0530 Subject: [PATCH 09/12] Refactor components related to chatflow configuration --- .../dialog/ChatflowConfigurationDialog.jsx | 10 +++++----- .../src/ui-component/dialog/StarterPromptsDialog.jsx | 2 +- .../{dialog => extended}/AllowedDomains.jsx | 0 .../ui-component/{dialog => extended}/AnalyseFlow.jsx | 0 .../ui-component/{dialog => extended}/ChatFeedback.jsx | 0 .../ui-component/{dialog => extended}/SpeechToText.jsx | 0 .../{dialog => extended}/StarterPrompts.jsx | 0 7 files changed, 6 insertions(+), 6 deletions(-) rename packages/ui/src/ui-component/{dialog => extended}/AllowedDomains.jsx (100%) rename packages/ui/src/ui-component/{dialog => extended}/AnalyseFlow.jsx (100%) rename packages/ui/src/ui-component/{dialog => extended}/ChatFeedback.jsx (100%) rename packages/ui/src/ui-component/{dialog => extended}/SpeechToText.jsx (100%) rename packages/ui/src/ui-component/{dialog => extended}/StarterPrompts.jsx (100%) diff --git a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx index 28ad7a70..67fd62bf 100644 --- a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx +++ b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx @@ -2,12 +2,12 @@ import PropTypes from 'prop-types' import { useState } from 'react' import { createPortal } from 'react-dom' import { Box, Dialog, DialogContent, DialogTitle, Tabs, Tab } from '@mui/material' -import SpeechToText from './SpeechToText' +import SpeechToText from '@/ui-component/extended/SpeechToText' import Configuration from '@/views/chatflows/Configuration' -import AllowedDomains from './AllowedDomains' -import ChatFeedback from './ChatFeedback' -import AnalyseFlow from './AnalyseFlow' -import StarterPrompts from './StarterPrompts' +import AllowedDomains from '@/ui-component/extended/AllowedDomains' +import ChatFeedback from '@/ui-component/extended/ChatFeedback' +import AnalyseFlow from '@/ui-component/extended/AnalyseFlow' +import StarterPrompts from '@/ui-component/extended/StarterPrompts' const CHATFLOW_CONFIGURATION_TABS = [ { diff --git a/packages/ui/src/ui-component/dialog/StarterPromptsDialog.jsx b/packages/ui/src/ui-component/dialog/StarterPromptsDialog.jsx index 142f9c44..2bfb2f23 100644 --- a/packages/ui/src/ui-component/dialog/StarterPromptsDialog.jsx +++ b/packages/ui/src/ui-component/dialog/StarterPromptsDialog.jsx @@ -11,7 +11,7 @@ import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from '@/store/actions' import useNotifier from '@/utils/useNotifier' // Project imports -import StarterPrompts from './StarterPrompts' +import StarterPrompts from '@/ui-component/extended/StarterPrompts' const StarterPromptsDialog = ({ show, dialogProps, onCancel }) => { const portalElement = document.getElementById('portal') diff --git a/packages/ui/src/ui-component/dialog/AllowedDomains.jsx b/packages/ui/src/ui-component/extended/AllowedDomains.jsx similarity index 100% rename from packages/ui/src/ui-component/dialog/AllowedDomains.jsx rename to packages/ui/src/ui-component/extended/AllowedDomains.jsx diff --git a/packages/ui/src/ui-component/dialog/AnalyseFlow.jsx b/packages/ui/src/ui-component/extended/AnalyseFlow.jsx similarity index 100% rename from packages/ui/src/ui-component/dialog/AnalyseFlow.jsx rename to packages/ui/src/ui-component/extended/AnalyseFlow.jsx diff --git a/packages/ui/src/ui-component/dialog/ChatFeedback.jsx b/packages/ui/src/ui-component/extended/ChatFeedback.jsx similarity index 100% rename from packages/ui/src/ui-component/dialog/ChatFeedback.jsx rename to packages/ui/src/ui-component/extended/ChatFeedback.jsx diff --git a/packages/ui/src/ui-component/dialog/SpeechToText.jsx b/packages/ui/src/ui-component/extended/SpeechToText.jsx similarity index 100% rename from packages/ui/src/ui-component/dialog/SpeechToText.jsx rename to packages/ui/src/ui-component/extended/SpeechToText.jsx diff --git a/packages/ui/src/ui-component/dialog/StarterPrompts.jsx b/packages/ui/src/ui-component/extended/StarterPrompts.jsx similarity index 100% rename from packages/ui/src/ui-component/dialog/StarterPrompts.jsx rename to packages/ui/src/ui-component/extended/StarterPrompts.jsx From a4a2fbb08ff1540546da4559ba061984d597a11a Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 13 Mar 2024 01:13:36 +0800 Subject: [PATCH 10/12] rename rate limit --- .../dialog/ChatflowConfigurationDialog.jsx | 4 ++-- .../extended/RateLimit.jsx} | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) rename packages/ui/src/{views/chatflows/Configuration.jsx => ui-component/extended/RateLimit.jsx} (96%) diff --git a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx index 67fd62bf..5fde038a 100644 --- a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx +++ b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx @@ -3,7 +3,7 @@ import { useState } from 'react' import { createPortal } from 'react-dom' import { Box, Dialog, DialogContent, DialogTitle, Tabs, Tab } from '@mui/material' import SpeechToText from '@/ui-component/extended/SpeechToText' -import Configuration from '@/views/chatflows/Configuration' +import RateLimit from '@/ui-component/extended/RateLimit' import AllowedDomains from '@/ui-component/extended/AllowedDomains' import ChatFeedback from '@/ui-component/extended/ChatFeedback' import AnalyseFlow from '@/ui-component/extended/AnalyseFlow' @@ -99,7 +99,7 @@ const ChatflowConfigurationDialog = ({ show, dialogProps, onCancel }) => { {CHATFLOW_CONFIGURATION_TABS.map((item, index) => ( - {item.id === 'rateLimiting' && } + {item.id === 'rateLimiting' && } {item.id === 'conversationStarters' ? : null} {item.id === 'speechToText' ? : null} {item.id === 'chatFeedback' ? : null} diff --git a/packages/ui/src/views/chatflows/Configuration.jsx b/packages/ui/src/ui-component/extended/RateLimit.jsx similarity index 96% rename from packages/ui/src/views/chatflows/Configuration.jsx rename to packages/ui/src/ui-component/extended/RateLimit.jsx index 13f7b388..5fc88cae 100644 --- a/packages/ui/src/views/chatflows/Configuration.jsx +++ b/packages/ui/src/ui-component/extended/RateLimit.jsx @@ -18,7 +18,7 @@ import chatflowsApi from '@/api/chatflows' import useNotifier from '@/utils/useNotifier' import { TooltipWithParser } from '@/ui-component/tooltip/TooltipWithParser' -const Configuration = () => { +const RateLimit = () => { const dispatch = useDispatch() const chatflow = useSelector((state) => state.canvas.chatflow) const chatflowid = chatflow.id @@ -59,7 +59,7 @@ const Configuration = () => { }) if (saveResp.data) { enqueueSnackbar({ - message: 'API Configuration Saved', + message: 'Rate Limit Configuration Saved', options: { key: new Date().getTime() + Math.random(), variant: 'success', @@ -78,7 +78,7 @@ const Configuration = () => { ? error.response.data || `${error.response.status}: ${error.response.statusText}` : error.message enqueueSnackbar({ - message: `Failed to save API Configuration: ${errorData}`, + message: `Failed to save Rate Limit Configuration: ${errorData}`, options: { key: new Date().getTime() + Math.random(), variant: 'error', @@ -151,8 +151,8 @@ const Configuration = () => { ) } -Configuration.propTypes = { +RateLimit.propTypes = { isSessionMemory: PropTypes.bool } -export default Configuration +export default RateLimit From 02963ce0d54852dece81cc45a0f07259133237c1 Mon Sep 17 00:00:00 2001 From: Ilango Date: Wed, 13 Mar 2024 05:57:10 +0530 Subject: [PATCH 11/12] Fix warnings --- packages/server/src/index.ts | 1 - packages/ui/src/views/canvas/CanvasHeader.jsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index a976e6a1..3828535e 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -24,7 +24,6 @@ import { IChatMessageFeedback, IDepthQueue, INodeDirectedGraph, - ChatMessageRatingType, IUploadFileSizeAndTypes } from './Interface' import { diff --git a/packages/ui/src/views/canvas/CanvasHeader.jsx b/packages/ui/src/views/canvas/CanvasHeader.jsx index 3833fdee..4728c6b0 100644 --- a/packages/ui/src/views/canvas/CanvasHeader.jsx +++ b/packages/ui/src/views/canvas/CanvasHeader.jsx @@ -179,7 +179,7 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl }) } } - }, [chatflow]) + }, [chatflow, chatflowConfigurationDialogOpen]) return ( <> From ad3d5032a58f98c271efe5fbee1d71ea1e155510 Mon Sep 17 00:00:00 2001 From: Ilango Date: Wed, 13 Mar 2024 10:17:31 +0530 Subject: [PATCH 12/12] Add chat feedback, allowed domains, and speech to text options to chatflow context menu in table view --- .../src/ui-component/button/FlowListMenu.jsx | 68 +++++++++++++++++-- .../dialog/AllowedDomainsDialog.jsx | 56 +++++++++++++++ .../dialog/ChatFeedbackDialog.jsx | 56 +++++++++++++++ .../dialog/SpeechToTextDialog.jsx | 56 +++++++++++++++ 4 files changed, 232 insertions(+), 4 deletions(-) create mode 100644 packages/ui/src/ui-component/dialog/AllowedDomainsDialog.jsx create mode 100644 packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx create mode 100644 packages/ui/src/ui-component/dialog/SpeechToTextDialog.jsx diff --git a/packages/ui/src/ui-component/button/FlowListMenu.jsx b/packages/ui/src/ui-component/button/FlowListMenu.jsx index e8c8786a..bfee4eb1 100644 --- a/packages/ui/src/ui-component/button/FlowListMenu.jsx +++ b/packages/ui/src/ui-component/button/FlowListMenu.jsx @@ -12,6 +12,9 @@ import FileDownloadIcon from '@mui/icons-material/Downloading' import FileDeleteIcon from '@mui/icons-material/Delete' import FileCategoryIcon from '@mui/icons-material/Category' import PictureInPictureAltIcon from '@mui/icons-material/PictureInPictureAlt' +import ThumbsUpDownOutlinedIcon from '@mui/icons-material/ThumbsUpDownOutlined' +import VpnLockOutlinedIcon from '@mui/icons-material/VpnLockOutlined' +import MicNoneOutlinedIcon from '@mui/icons-material/MicNoneOutlined' import Button from '@mui/material/Button' import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown' import { IconX } from '@tabler/icons' @@ -29,6 +32,9 @@ import StarterPromptsDialog from '@/ui-component/dialog/StarterPromptsDialog' import { generateExportFlowData } from '@/utils/genericHelper' import useNotifier from '@/utils/useNotifier' +import ChatFeedbackDialog from '../dialog/ChatFeedbackDialog' +import AllowedDomainsDialog from '../dialog/AllowedDomainsDialog' +import SpeechToTextDialog from '../dialog/SpeechToTextDialog' const StyledMenu = styled((props) => ( { setAnchorEl(event.currentTarget) @@ -105,9 +117,31 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { setConversationStartersDialogOpen(true) } - const saveFlowStarterPrompts = async () => { - setConversationStartersDialogOpen(false) - await updateFlowsApi.request() + const handleFlowChatFeedback = () => { + setAnchorEl(null) + setChatFeedbackDialogProps({ + title: 'Chat Feedback - ' + chatflow.name, + chatflow: chatflow + }) + setChatFeedbackDialogOpen(true) + } + + const handleAllowedDomains = () => { + setAnchorEl(null) + setAllowedDomainsDialogProps({ + title: 'Allowed Domains - ' + chatflow.name, + chatflow: chatflow + }) + setAllowedDomainsDialogOpen(true) + } + + const handleSpeechToText = () => { + setAnchorEl(null) + setSpeechToTextDialogProps({ + title: 'Speech To Text - ' + chatflow.name, + chatflow: chatflow + }) + setSpeechToTextDialogOpen(true) } const saveFlowRename = async (chatflowName) => { @@ -275,6 +309,18 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { Starter Prompts + + + Chat Feedback + + + + Allowed Domains + + + + Speech To Text + Update Category @@ -304,9 +350,23 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { setConversationStartersDialogOpen(false)} /> + setChatFeedbackDialogOpen(false)} + /> + setAllowedDomainsDialogOpen(false)} + /> + setSpeechToTextDialogOpen(false)} + />
) } diff --git a/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.jsx b/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.jsx new file mode 100644 index 00000000..6147c173 --- /dev/null +++ b/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.jsx @@ -0,0 +1,56 @@ +import { createPortal } from 'react-dom' +import { useDispatch } from 'react-redux' +import { useEffect } from 'react' +import PropTypes from 'prop-types' + +// material-ui +import { Dialog, DialogContent, DialogTitle } from '@mui/material' + +// store +import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from '@/store/actions' +import useNotifier from '@/utils/useNotifier' + +// Project imports +import AllowedDomains from '@/ui-component/extended/AllowedDomains' + +const AllowedDomainsDialog = ({ show, dialogProps, onCancel }) => { + const portalElement = document.getElementById('portal') + const dispatch = useDispatch() + + useNotifier() + + useEffect(() => { + if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) + else dispatch({ type: HIDE_CANVAS_DIALOG }) + return () => dispatch({ type: HIDE_CANVAS_DIALOG }) + }, [show, dispatch]) + + const component = show ? ( + + + {dialogProps.title || 'Allowed Domains'} + + + + + + ) : null + + return createPortal(component, portalElement) +} + +AllowedDomainsDialog.propTypes = { + show: PropTypes.bool, + dialogProps: PropTypes.object, + onCancel: PropTypes.func, + onConfirm: PropTypes.func +} + +export default AllowedDomainsDialog diff --git a/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx b/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx new file mode 100644 index 00000000..a57e8ce4 --- /dev/null +++ b/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.jsx @@ -0,0 +1,56 @@ +import { createPortal } from 'react-dom' +import { useDispatch } from 'react-redux' +import { useEffect } from 'react' +import PropTypes from 'prop-types' + +// material-ui +import { Dialog, DialogContent, DialogTitle } from '@mui/material' + +// store +import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from '@/store/actions' +import useNotifier from '@/utils/useNotifier' + +// Project imports +import ChatFeedback from '@/ui-component/extended/ChatFeedback' + +const ChatFeedbackDialog = ({ show, dialogProps, onCancel }) => { + const portalElement = document.getElementById('portal') + const dispatch = useDispatch() + + useNotifier() + + useEffect(() => { + if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) + else dispatch({ type: HIDE_CANVAS_DIALOG }) + return () => dispatch({ type: HIDE_CANVAS_DIALOG }) + }, [show, dispatch]) + + const component = show ? ( + + + {dialogProps.title || 'Allowed Domains'} + + + + + + ) : null + + return createPortal(component, portalElement) +} + +ChatFeedbackDialog.propTypes = { + show: PropTypes.bool, + dialogProps: PropTypes.object, + onCancel: PropTypes.func, + onConfirm: PropTypes.func +} + +export default ChatFeedbackDialog diff --git a/packages/ui/src/ui-component/dialog/SpeechToTextDialog.jsx b/packages/ui/src/ui-component/dialog/SpeechToTextDialog.jsx new file mode 100644 index 00000000..a01dafae --- /dev/null +++ b/packages/ui/src/ui-component/dialog/SpeechToTextDialog.jsx @@ -0,0 +1,56 @@ +import { createPortal } from 'react-dom' +import { useDispatch } from 'react-redux' +import { useEffect } from 'react' +import PropTypes from 'prop-types' + +// material-ui +import { Dialog, DialogContent, DialogTitle } from '@mui/material' + +// store +import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from '@/store/actions' +import useNotifier from '@/utils/useNotifier' + +// Project imports +import SpeechToText from '@/ui-component/extended/SpeechToText' + +const SpeechToTextDialog = ({ show, dialogProps, onCancel }) => { + const portalElement = document.getElementById('portal') + const dispatch = useDispatch() + + useNotifier() + + useEffect(() => { + if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) + else dispatch({ type: HIDE_CANVAS_DIALOG }) + return () => dispatch({ type: HIDE_CANVAS_DIALOG }) + }, [show, dispatch]) + + const component = show ? ( + + + {dialogProps.title || 'Allowed Domains'} + + + + + + ) : null + + return createPortal(component, portalElement) +} + +SpeechToTextDialog.propTypes = { + show: PropTypes.bool, + dialogProps: PropTypes.object, + onCancel: PropTypes.func, + onConfirm: PropTypes.func +} + +export default SpeechToTextDialog