mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 17:01:00 +03:00
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:
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -511,6 +511,7 @@ const Canvas = () => {
|
||||
onConnect={onConnect}
|
||||
onInit={setReactFlowInstance}
|
||||
fitView
|
||||
deleteKeyCode={canvas.canvasDialogShow ? null : ['Backspace', 'Delete']}
|
||||
minZoom={0.1}
|
||||
>
|
||||
<Controls
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user