Merge branch 'main' into feature/Credential

# Conflicts:
#	README.md
#	docker/.env.example
#	packages/components/nodes/documentloaders/Notion/NotionDB.ts
#	packages/components/nodes/memory/DynamoDb/DynamoDb.ts
#	packages/components/nodes/memory/MotorheadMemory/MotorheadMemory.ts
#	packages/components/nodes/memory/ZepMemory/ZepMemory.ts
#	packages/components/package.json
#	packages/components/src/utils.ts
#	packages/server/.env.example
#	packages/server/README.md
#	packages/server/marketplaces/chatflows/Conversational Retrieval QA Chain.json
#	packages/server/src/ChildProcess.ts
#	packages/server/src/DataSource.ts
#	packages/server/src/commands/start.ts
#	packages/server/src/index.ts
#	packages/server/src/utils/index.ts
#	packages/server/src/utils/logger.ts
This commit is contained in:
Henry
2023-07-27 11:26:34 +01:00
107 changed files with 4347 additions and 826 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "flowise-ui",
"version": "1.2.14",
"version": "1.2.15",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://flowiseai.com",
"author": {
+2
View File
@@ -11,6 +11,8 @@ export const SET_DARKMODE = '@customization/SET_DARKMODE'
export const SET_DIRTY = '@canvas/SET_DIRTY'
export const REMOVE_DIRTY = '@canvas/REMOVE_DIRTY'
export const SET_CHATFLOW = '@canvas/SET_CHATFLOW'
export const SHOW_CANVAS_DIALOG = '@canvas/SHOW_CANVAS_DIALOG'
export const HIDE_CANVAS_DIALOG = '@canvas/HIDE_CANVAS_DIALOG'
// action - notifier reducer
export const ENQUEUE_SNACKBAR = 'ENQUEUE_SNACKBAR'
@@ -3,7 +3,8 @@ import * as actionTypes from '../actions'
export const initialState = {
isDirty: false,
chatflow: null
chatflow: null,
canvasDialogShow: false
}
// ==============================|| CANVAS REDUCER ||============================== //
@@ -25,6 +26,16 @@ const canvasReducer = (state = initialState, action) => {
...state,
chatflow: action.chatflow
}
case actionTypes.SHOW_CANVAS_DIALOG:
return {
...state,
canvasDialogShow: true
}
case actionTypes.HIDE_CANVAS_DIALOG:
return {
...state,
canvasDialogShow: false
}
default:
return state
}
@@ -1,12 +1,15 @@
import { createPortal } from 'react-dom'
import { useDispatch } from 'react-redux'
import { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { Dialog, DialogContent } from '@mui/material'
import PerfectScrollbar from 'react-perfect-scrollbar'
import NodeInputHandler from 'views/canvas/NodeInputHandler'
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
const AdditionalParamsDialog = ({ show, dialogProps, onCancel }) => {
const portalElement = document.getElementById('portal')
const dispatch = useDispatch()
const [inputParams, setInputParams] = useState([])
const [data, setData] = useState({})
@@ -21,6 +24,11 @@ const AdditionalParamsDialog = ({ show, dialogProps, onCancel }) => {
}
}, [dialogProps])
useEffect(() => {
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
else dispatch({ type: HIDE_CANVAS_DIALOG })
}, [show, dispatch])
const component = show ? (
<Dialog
onClose={onCancel}
@@ -1,6 +1,6 @@
import { createPortal } from 'react-dom'
import { useState, useEffect } from 'react'
import { useSelector } from 'react-redux'
import { useSelector, useDispatch } from 'react-redux'
import PropTypes from 'prop-types'
import { Button, Dialog, DialogActions, DialogContent, Typography } from '@mui/material'
import { useTheme } from '@mui/material/styles'
@@ -8,6 +8,7 @@ import PerfectScrollbar from 'react-perfect-scrollbar'
import { StyledButton } from 'ui-component/button/StyledButton'
import { DarkCodeEditor } from 'ui-component/editor/DarkCodeEditor'
import { LightCodeEditor } from 'ui-component/editor/LightCodeEditor'
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
import './ExpandTextDialog.css'
@@ -15,6 +16,7 @@ const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
const portalElement = document.getElementById('portal')
const theme = useTheme()
const dispatch = useDispatch()
const customization = useSelector((state) => state.customization)
const languageType = 'json'
@@ -31,6 +33,11 @@ const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
}
}, [dialogProps])
useEffect(() => {
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
else dispatch({ type: HIDE_CANVAS_DIALOG })
}, [show, dispatch])
const component = show ? (
<Dialog open={show} fullWidth maxWidth='md' aria-labelledby='alert-dialog-title' aria-describedby='alert-dialog-description'>
<DialogContent>
@@ -1,13 +1,21 @@
import { useEffect } from 'react'
import { createPortal } from 'react-dom'
import { useSelector } from 'react-redux'
import { useSelector, useDispatch } from 'react-redux'
import PropTypes from 'prop-types'
import { Dialog, DialogContent, DialogTitle } from '@mui/material'
import PerfectScrollbar from 'react-perfect-scrollbar'
import { JsonEditorInput } from 'ui-component/json/JsonEditor'
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
const FormatPromptValuesDialog = ({ show, dialogProps, onChange, onCancel }) => {
const portalElement = document.getElementById('portal')
const customization = useSelector((state) => state.customization)
const dispatch = useDispatch()
useEffect(() => {
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
else dispatch({ type: HIDE_CANVAS_DIALOG })
}, [show, dispatch])
const component = show ? (
<Dialog
+1 -1
View File
@@ -61,7 +61,7 @@ export const Input = ({ inputParam, value, onChange, disabled = false, showDialo
Input.propTypes = {
inputParam: PropTypes.object,
value: PropTypes.string,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
onChange: PropTypes.func,
disabled: PropTypes.bool,
showDialog: PropTypes.bool,
+18 -2
View File
@@ -90,8 +90,8 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
}
const onAPIDialogClick = () => {
// If file type is file, isFormDataRequired = true
let isFormDataRequired = false
try {
const flowData = JSON.parse(chatflow.flowData)
const nodes = flowData.nodes
@@ -105,11 +105,27 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
console.error(e)
}
// If sessionId memory, isSessionMemory = true
let isSessionMemory = false
try {
const flowData = JSON.parse(chatflow.flowData)
const nodes = flowData.nodes
for (const node of nodes) {
if (node.data.inputParams.find((param) => param.name === 'sessionId')) {
isSessionMemory = true
break
}
}
} catch (e) {
console.error(e)
}
setAPIDialogProps({
title: 'Embed in website or use as API',
chatflowid: chatflow.id,
chatflowApiKeyId: chatflow.apikeyid,
isFormDataRequired
isFormDataRequired,
isSessionMemory
})
setAPIDialogOpen(true)
}
+1
View File
@@ -511,6 +511,7 @@ const Canvas = () => {
onConnect={onConnect}
onInit={setReactFlowInstance}
fitView
deleteKeyCode={canvas.canvasDialogShow ? null : ['Backspace', 'Delete']}
minZoom={0.1}
>
<Controls
+17 -2
View File
@@ -26,6 +26,7 @@ const ChatbotFull = () => {
const [loginDialogOpen, setLoginDialogOpen] = useState(false)
const [loginDialogProps, setLoginDialogProps] = useState({})
const [isLoading, setLoading] = useState(true)
const [chatbotOverrideConfig, setChatbotOverrideConfig] = useState({})
const getSpecificChatflowFromPublicApi = useApi(chatflowsApi.getSpecificChatflowFromPublicEndpoint)
const getSpecificChatflowApi = useApi(chatflowsApi.getSpecificChatflow)
@@ -77,10 +78,19 @@ const ChatbotFull = () => {
setChatflow(chatflowData)
if (chatflowData.chatbotConfig) {
try {
setChatbotTheme(JSON.parse(chatflowData.chatbotConfig))
const parsedConfig = JSON.parse(chatflowData.chatbotConfig)
setChatbotTheme(parsedConfig)
if (parsedConfig.overrideConfig) {
// Generate new sessionId
if (parsedConfig.overrideConfig.generateNewSession) {
parsedConfig.overrideConfig.sessionId = Date.now().toString()
}
setChatbotOverrideConfig(parsedConfig.overrideConfig)
}
} catch (e) {
console.error(e)
setChatbotTheme({})
setChatbotOverrideConfig({})
}
}
}
@@ -97,7 +107,12 @@ const ChatbotFull = () => {
{!chatflow || chatflow.apikeyid ? (
<p>Invalid Chatbot</p>
) : (
<FullPageChat chatflowid={chatflow.id} apiHost={baseURL} theme={{ chatWindow: chatbotTheme }} />
<FullPageChat
chatflowid={chatflow.id}
apiHost={baseURL}
chatflowConfig={chatbotOverrideConfig}
theme={{ chatWindow: chatbotTheme }}
/>
)}
<LoginDialog show={loginDialogOpen} dialogProps={loginDialogProps} onConfirm={onLoginClick} />
</>
@@ -190,7 +190,10 @@ output = query({
"${baseURL}/api/v1/prediction/${dialogProps.chatflowid}",
{
method: "POST",
body: data
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}
);
const result = await response.json();
@@ -204,7 +207,8 @@ query({"question": "Hey, how are you?"}).then((response) => {
} else if (codeLang === 'cURL') {
return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\
-X POST \\
-d '{"question": "Hey, how are you?"}'`
-d '{"question": "Hey, how are you?"}' \\
-H "Content-Type: application/json"`
}
return ''
}
@@ -229,9 +233,12 @@ output = query({
const response = await fetch(
"${baseURL}/api/v1/prediction/${dialogProps.chatflowid}",
{
headers: { Authorization: "Bearer ${selectedApiKey?.apiKey}" },
headers: {
Authorization: "Bearer ${selectedApiKey?.apiKey}",
"Content-Type": "application/json"
},
method: "POST",
body: data
body: JSON.stringify(data)
}
);
const result = await response.json();
@@ -246,6 +253,7 @@ query({"question": "Hey, how are you?"}).then((response) => {
return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\
-X POST \\
-d '{"question": "Hey, how are you?"}' \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer ${selectedApiKey?.apiKey}"`
}
return ''
@@ -316,7 +324,8 @@ query(formData).then((response) => {
`
} else if (codeLang === 'cURL') {
return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\
-X POST \\${getConfigExamplesForCurl(configData, 'formData')}`
-X POST \\${getConfigExamplesForCurl(configData, 'formData')} \\
-H "Content-Type: multipart/form-data"`
}
return ''
}
@@ -363,6 +372,7 @@ query(formData).then((response) => {
} else if (codeLang === 'cURL') {
return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\
-X POST \\${getConfigExamplesForCurl(configData, 'formData')} \\
-H "Content-Type: multipart/form-data" \\
-H "Authorization: Bearer ${selectedApiKey?.apiKey}"`
}
return ''
@@ -392,7 +402,10 @@ output = query({
"${baseURL}/api/v1/prediction/${dialogProps.chatflowid}",
{
method: "POST",
body: data
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}
);
const result = await response.json();
@@ -410,7 +423,8 @@ query({
} else if (codeLang === 'cURL') {
return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\
-X POST \\
-d '{"question": "Hey, how are you?", "overrideConfig": {${getConfigExamplesForCurl(configData, 'json')}}'`
-d '{"question": "Hey, how are you?", "overrideConfig": {${getConfigExamplesForCurl(configData, 'json')}}' \\
-H "Content-Type: application/json"`
}
return ''
}
@@ -439,9 +453,12 @@ output = query({
const response = await fetch(
"${baseURL}/api/v1/prediction/${dialogProps.chatflowid}",
{
headers: { Authorization: "Bearer ${selectedApiKey?.apiKey}" },
headers: {
Authorization: "Bearer ${selectedApiKey?.apiKey}",
"Content-Type": "application/json"
},
method: "POST",
body: data
body: JSON.stringify(data)
}
);
const result = await response.json();
@@ -460,6 +477,7 @@ query({
return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\
-X POST \\
-d '{"question": "Hey, how are you?", "overrideConfig": {${getConfigExamplesForCurl(configData, 'json')}}' \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer ${selectedApiKey?.apiKey}"`
}
return ''
@@ -594,7 +612,9 @@ query({
)}
</>
)}
{codeLang === 'Share Chatbot' && !chatflowApiKeyId && <ShareChatbot />}
{codeLang === 'Share Chatbot' && !chatflowApiKeyId && (
<ShareChatbot isSessionMemory={dialogProps.isSessionMemory} />
)}
</TabPanel>
))}
</DialogContent>
@@ -2,6 +2,7 @@ import { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions'
import { SketchPicker } from 'react-color'
import PropTypes from 'prop-types'
import { Box, Typography, Button, Switch, OutlinedInput, Popover, Stack, IconButton } from '@mui/material'
import { useTheme } from '@mui/material/styles'
@@ -41,7 +42,7 @@ const defaultConfig = {
}
}
const ShareChatbot = () => {
const ShareChatbot = ({ isSessionMemory }) => {
const dispatch = useDispatch()
const theme = useTheme()
const chatflow = useSelector((state) => state.canvas.chatflow)
@@ -54,6 +55,7 @@ const ShareChatbot = () => {
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
const [isPublicChatflow, setChatflowIsPublic] = useState(chatflow.isPublic ?? false)
const [generateNewSession, setGenerateNewSession] = useState(chatbotConfig?.generateNewSession ?? false)
const [welcomeMessage, setWelcomeMessage] = useState(chatbotConfig?.welcomeMessage ?? '')
const [backgroundColor, setBackgroundColor] = useState(chatbotConfig?.backgroundColor ?? defaultConfig.backgroundColor)
@@ -103,7 +105,8 @@ const ShareChatbot = () => {
userMessage: {
showAvatar: false
},
textInput: {}
textInput: {},
overrideConfig: {}
}
if (welcomeMessage) obj.welcomeMessage = welcomeMessage
if (backgroundColor) obj.backgroundColor = backgroundColor
@@ -125,6 +128,8 @@ const ShareChatbot = () => {
if (textInputPlaceholder) obj.textInput.placeholder = textInputPlaceholder
if (textInputSendButtonColor) obj.textInput.sendButtonColor = textInputSendButtonColor
if (isSessionMemory) obj.overrideConfig.generateNewSession = generateNewSession
return obj
}
@@ -273,6 +278,9 @@ const ShareChatbot = () => {
case 'userMessageShowAvatar':
setUserMessageShowAvatar(value)
break
case 'generateNewSession':
setGenerateNewSession(value)
break
}
}
@@ -431,6 +439,16 @@ const ShareChatbot = () => {
{textField(textInputPlaceholder, 'textInputPlaceholder', 'TextInput Placeholder', 'string', `Type question..`)}
{colorField(textInputSendButtonColor, 'textInputSendButtonColor', 'TextIntput Send Button Color')}
{/*Session Memory Input*/}
{isSessionMemory && (
<>
<Typography variant='h4' sx={{ mb: 1, mt: 2 }}>
Session Memory
</Typography>
{booleanField(generateNewSession, 'generateNewSession', 'Start new session when chatbot link is opened or refreshed')}
</>
)}
<StyledButton style={{ marginBottom: 10, marginTop: 10 }} variant='contained' onClick={() => onSave()}>
Save Changes
</StyledButton>
@@ -470,4 +488,8 @@ const ShareChatbot = () => {
)
}
ShareChatbot.propTypes = {
isSessionMemory: PropTypes.bool
}
export default ShareChatbot