Skip to content

Commit 9dfacd1

Browse files
authored
Merge pull request FlowiseAI#666 from FlowiseAI/feature/MultiConfig
Feature/Multi Config
2 parents 3be16a3 + f75d986 commit 9dfacd1

File tree

4 files changed

+166
-6
lines changed

4 files changed

+166
-6
lines changed

packages/server/src/Interface.ts

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ export interface IActiveChatflows {
157157

158158
export interface IOverrideConfig {
159159
node: string
160+
nodeId: string
160161
label: string
161162
name: string
162163
type: string

packages/server/src/utils/index.ts

+12
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,14 @@ export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig:
445445

446446
const getParamValues = (paramsObj: ICommonObject) => {
447447
for (const config in overrideConfig) {
448+
// If overrideConfig[key] is object
449+
if (overrideConfig[config] && typeof overrideConfig[config] === 'object') {
450+
const nodeIds = Object.keys(overrideConfig[config])
451+
if (!nodeIds.includes(flowNodeData.id)) continue
452+
else paramsObj[config] = overrideConfig[config][flowNodeData.id]
453+
continue
454+
}
455+
448456
let paramValue = overrideConfig[config] ?? paramsObj[config]
449457
// Check if boolean
450458
if (paramValue === 'true') paramValue = true
@@ -695,13 +703,15 @@ export const findAvailableConfigs = (reactFlowNodes: IReactFlowNode[], component
695703
if (inputParam.type === 'file') {
696704
obj = {
697705
node: flowNode.data.label,
706+
nodeId: flowNode.data.id,
698707
label: inputParam.label,
699708
name: 'files',
700709
type: inputParam.fileType ?? inputParam.type
701710
}
702711
} else if (inputParam.type === 'options') {
703712
obj = {
704713
node: flowNode.data.label,
714+
nodeId: flowNode.data.id,
705715
label: inputParam.label,
706716
name: inputParam.name,
707717
type: inputParam.options
@@ -720,6 +730,7 @@ export const findAvailableConfigs = (reactFlowNodes: IReactFlowNode[], component
720730
for (const input of inputs) {
721731
obj = {
722732
node: flowNode.data.label,
733+
nodeId: flowNode.data.id,
723734
label: input.label,
724735
name: input.name,
725736
type: input.type === 'password' ? 'string' : input.type
@@ -732,6 +743,7 @@ export const findAvailableConfigs = (reactFlowNodes: IReactFlowNode[], component
732743
} else {
733744
obj = {
734745
node: flowNode.data.label,
746+
nodeId: flowNode.data.id,
735747
label: inputParam.label,
736748
name: inputParam.name,
737749
type: inputParam.type === 'password' ? 'string' : inputParam.type

packages/ui/src/ui-component/table/Table.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ export const TableViewOnly = ({ columns, rows }) => {
1616
<TableBody>
1717
{rows.map((row, index) => (
1818
<TableRow key={index} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
19-
{Object.keys(row).map((key, index) => (
20-
<TableCell key={index}>{row[key]}</TableCell>
21-
))}
19+
{Object.keys(row)
20+
.slice(-3)
21+
.map((key, index) => (
22+
<TableCell key={index}>{row[key]}</TableCell>
23+
))}
2224
</TableRow>
2325
))}
2426
</TableBody>

packages/ui/src/views/chatflows/APICodeDialog.js

+148-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,20 @@ import { useState, useEffect } from 'react'
44
import { useDispatch } from 'react-redux'
55
import PropTypes from 'prop-types'
66

7-
import { Tabs, Tab, Dialog, DialogContent, DialogTitle, Box } from '@mui/material'
7+
import {
8+
Tabs,
9+
Tab,
10+
Dialog,
11+
DialogContent,
12+
DialogTitle,
13+
Box,
14+
Accordion,
15+
AccordionSummary,
16+
AccordionDetails,
17+
Typography
18+
} from '@mui/material'
819
import { CopyBlock, atomOneDark } from 'react-code-blocks'
20+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
921

1022
// Project import
1123
import { Dropdown } from 'ui-component/dropdown/Dropdown'
@@ -33,6 +45,8 @@ import useApi from 'hooks/useApi'
3345
import { CheckboxInput } from 'ui-component/checkbox/Checkbox'
3446
import { TableViewOnly } from 'ui-component/table/Table'
3547

48+
import { IconBulb } from '@tabler/icons'
49+
3650
function TabPanel(props) {
3751
const { children, value, index, ...other } = props
3852
return (
@@ -82,7 +96,7 @@ const getConfigExamplesForJS = (configData, bodyType) => {
8296
else if (config.type === 'number') exampleVal = `1`
8397
else if (config.name === 'files') exampleVal = `input.files[0]`
8498
finalStr += bodyType === 'json' ? `\n "${config.name}": ${exampleVal},` : `formData.append("${config.name}", ${exampleVal})\n`
85-
if (i === loop - 1 && bodyType !== 'json') `formData.append("question", "Hey, how are you?")\n`
99+
if (i === loop - 1 && bodyType !== 'json') finalStr += `formData.append("question", "Hey, how are you?")\n`
86100
}
87101
return finalStr
88102
}
@@ -134,6 +148,8 @@ const APICodeDialog = ({ show, dialogProps, onCancel }) => {
134148
const [chatflowApiKeyId, setChatflowApiKeyId] = useState('')
135149
const [selectedApiKey, setSelectedApiKey] = useState({})
136150
const [checkboxVal, setCheckbox] = useState(false)
151+
const [nodeConfig, setNodeConfig] = useState({})
152+
const [nodeConfigExpanded, setNodeConfigExpanded] = useState({})
137153

138154
const getAllAPIKeysApi = useApi(apiKeyApi.getAllAPIKeys)
139155
const updateChatflowApi = useApi(chatflowsApi.updateChatflow)
@@ -160,12 +176,36 @@ const APICodeDialog = ({ show, dialogProps, onCancel }) => {
160176
updateChatflowApi.request(dialogProps.chatflowid, updateBody)
161177
}
162178

179+
const groupByNodeLabel = (nodes, isFilter = false) => {
180+
const accordianNodes = {}
181+
const result = nodes.reduce(function (r, a) {
182+
r[a.node] = r[a.node] || []
183+
r[a.node].push(a)
184+
accordianNodes[a.node] = isFilter ? true : false
185+
return r
186+
}, Object.create(null))
187+
setNodeConfig(result)
188+
setNodeConfigExpanded(accordianNodes)
189+
}
190+
191+
const handleAccordionChange = (nodeLabel) => (event, isExpanded) => {
192+
const accordianNodes = { ...nodeConfigExpanded }
193+
accordianNodes[nodeLabel] = isExpanded
194+
setNodeConfigExpanded(accordianNodes)
195+
}
196+
163197
useEffect(() => {
164198
if (updateChatflowApi.data) {
165199
dispatch({ type: SET_CHATFLOW, chatflow: updateChatflowApi.data })
166200
}
167201
}, [updateChatflowApi.data, dispatch])
168202

203+
useEffect(() => {
204+
if (getConfigApi.data) {
205+
groupByNodeLabel(getConfigApi.data)
206+
}
207+
}, [getConfigApi.data])
208+
169209
const handleChange = (event, newValue) => {
170210
setValue(newValue)
171211
}
@@ -493,6 +533,32 @@ query({
493533
return ''
494534
}
495535

536+
const getMultiConfigCodeWithFormData = (codeLang) => {
537+
if (codeLang === 'Python') {
538+
return `body_data = {
539+
"openAIApiKey[chatOpenAI_0]": "sk-my-openai-1st-key",
540+
"openAIApiKey[openAIEmbeddings_0]": "sk-my-openai-2nd-key"
541+
}`
542+
} else if (codeLang === 'JavaScript') {
543+
return `formData.append("openAIApiKey[chatOpenAI_0]", "sk-my-openai-1st-key")
544+
formData.append("openAIApiKey[openAIEmbeddings_0]", "sk-my-openai-2nd-key")`
545+
} else if (codeLang === 'cURL') {
546+
return `-F "openAIApiKey[chatOpenAI_0]=sk-my-openai-1st-key" \\
547+
-F "openAIApiKey[openAIEmbeddings_0]=sk-my-openai-2nd-key" \\`
548+
}
549+
}
550+
551+
const getMultiConfigCode = () => {
552+
return `{
553+
"overrideConfig": {
554+
"openAIApiKey": {
555+
"chatOpenAI_0": "sk-my-openai-1st-key",
556+
"openAIEmbeddings_0": "sk-my-openai-2nd-key"
557+
}
558+
}
559+
}`
560+
}
561+
496562
useEffect(() => {
497563
if (getAllAPIKeysApi.data) {
498564
const options = [
@@ -593,7 +659,49 @@ query({
593659
<CheckboxInput label='Show Input Config' value={checkboxVal} onChange={onCheckBoxChanged} />
594660
{checkboxVal && getConfigApi.data && getConfigApi.data.length > 0 && (
595661
<>
596-
<TableViewOnly rows={getConfigApi.data} columns={Object.keys(getConfigApi.data[0])} />
662+
{Object.keys(nodeConfig)
663+
.sort()
664+
.map((nodeLabel) => (
665+
<Accordion
666+
expanded={nodeConfigExpanded[nodeLabel] || false}
667+
onChange={handleAccordionChange(nodeLabel)}
668+
key={nodeLabel}
669+
disableGutters
670+
>
671+
<AccordionSummary
672+
expandIcon={<ExpandMoreIcon />}
673+
aria-controls={`nodes-accordian-${nodeLabel}`}
674+
id={`nodes-accordian-header-${nodeLabel}`}
675+
>
676+
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
677+
<Typography variant='h5'>{nodeLabel}</Typography>
678+
<div
679+
style={{
680+
display: 'flex',
681+
flexDirection: 'row',
682+
width: 'max-content',
683+
borderRadius: 15,
684+
background: 'rgb(254,252,191)',
685+
padding: 5,
686+
paddingLeft: 10,
687+
paddingRight: 10,
688+
marginLeft: 10
689+
}}
690+
>
691+
<span style={{ color: 'rgb(116,66,16)', fontSize: '0.825rem' }}>
692+
{nodeConfig[nodeLabel][0].nodeId}
693+
</span>
694+
</div>
695+
</div>
696+
</AccordionSummary>
697+
<AccordionDetails>
698+
<TableViewOnly
699+
rows={nodeConfig[nodeLabel]}
700+
columns={Object.keys(nodeConfig[nodeLabel][0]).slice(-3)}
701+
/>
702+
</AccordionDetails>
703+
</Accordion>
704+
))}
597705
<CopyBlock
598706
theme={atomOneDark}
599707
text={
@@ -609,6 +717,43 @@ query({
609717
showLineNumbers={false}
610718
wrapLines
611719
/>
720+
<div
721+
style={{
722+
display: 'flex',
723+
flexDirection: 'column',
724+
borderRadius: 10,
725+
background: '#d8f3dc',
726+
padding: 10,
727+
marginTop: 10,
728+
marginBottom: 10
729+
}}
730+
>
731+
<div
732+
style={{
733+
display: 'flex',
734+
flexDirection: 'row',
735+
alignItems: 'center'
736+
}}
737+
>
738+
<IconBulb size={30} color='#2d6a4f' />
739+
<span style={{ color: '#2d6a4f', marginLeft: 10, fontWeight: 500 }}>
740+
You can also specify multiple values for a config parameter by specifying the node id
741+
</span>
742+
</div>
743+
<div style={{ padding: 10 }}>
744+
<CopyBlock
745+
theme={atomOneDark}
746+
text={
747+
dialogProps.isFormDataRequired
748+
? getMultiConfigCodeWithFormData(codeLang)
749+
: getMultiConfigCode()
750+
}
751+
language={getLang(codeLang)}
752+
showLineNumbers={false}
753+
wrapLines
754+
/>
755+
</div>
756+
</div>
612757
</>
613758
)}
614759
{getIsChatflowStreamingApi.data?.isStreaming && (

0 commit comments

Comments
 (0)