mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-27 03:00:28 +03:00
Merge branch 'main' into feature/Zapier
This commit is contained in:
@@ -124,7 +124,7 @@ class AzureChatOpenAI_ChatModels implements INode {
|
||||
const streaming = nodeData.inputs?.streaming as boolean
|
||||
|
||||
const obj: Partial<AzureOpenAIInput> & Partial<OpenAIBaseInput> = {
|
||||
temperature: parseInt(temperature, 10),
|
||||
temperature: parseFloat(temperature),
|
||||
modelName,
|
||||
azureOpenAIApiKey,
|
||||
azureOpenAIApiInstanceName,
|
||||
|
||||
@@ -120,7 +120,7 @@ class ChatAnthropic_ChatModels implements INode {
|
||||
const streaming = nodeData.inputs?.streaming as boolean
|
||||
|
||||
const obj: Partial<AnthropicInput> & { anthropicApiKey?: string } = {
|
||||
temperature: parseInt(temperature, 10),
|
||||
temperature: parseFloat(temperature),
|
||||
modelName,
|
||||
anthropicApiKey,
|
||||
streaming: streaming ?? true
|
||||
|
||||
@@ -89,7 +89,7 @@ class ChatHuggingFace_ChatModels implements INode {
|
||||
apiKey
|
||||
}
|
||||
|
||||
if (temperature) obj.temperature = parseInt(temperature, 10)
|
||||
if (temperature) obj.temperature = parseFloat(temperature)
|
||||
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
|
||||
if (topP) obj.topP = parseInt(topP, 10)
|
||||
if (hfTopK) obj.topK = parseInt(hfTopK, 10)
|
||||
|
||||
@@ -74,7 +74,7 @@ class ChatLocalAI_ChatModels implements INode {
|
||||
const basePath = nodeData.inputs?.basePath as string
|
||||
|
||||
const obj: Partial<OpenAIChatInput> & { openAIApiKey?: string } = {
|
||||
temperature: parseInt(temperature, 10),
|
||||
temperature: parseFloat(temperature),
|
||||
modelName,
|
||||
openAIApiKey: 'sk-'
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ class ChatOpenAI_ChatModels implements INode {
|
||||
const basePath = nodeData.inputs?.basepath as string
|
||||
|
||||
const obj: Partial<OpenAIChatInput> & { openAIApiKey?: string } = {
|
||||
temperature: parseInt(temperature, 10),
|
||||
temperature: parseFloat(temperature),
|
||||
modelName,
|
||||
openAIApiKey,
|
||||
streaming: streaming ?? true
|
||||
|
||||
@@ -179,7 +179,7 @@ class AzureOpenAI_LLMs implements INode {
|
||||
const streaming = nodeData.inputs?.streaming as boolean
|
||||
|
||||
const obj: Partial<AzureOpenAIInput> & Partial<OpenAIInput> = {
|
||||
temperature: parseInt(temperature, 10),
|
||||
temperature: parseFloat(temperature),
|
||||
modelName,
|
||||
azureOpenAIApiKey,
|
||||
azureOpenAIApiInstanceName,
|
||||
|
||||
@@ -87,7 +87,7 @@ class Cohere_LLMs implements INode {
|
||||
|
||||
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
|
||||
if (modelName) obj.model = modelName
|
||||
if (temperature) obj.temperature = parseInt(temperature, 10)
|
||||
if (temperature) obj.temperature = parseFloat(temperature)
|
||||
|
||||
const model = new Cohere(obj)
|
||||
return model
|
||||
|
||||
@@ -89,7 +89,7 @@ class HuggingFaceInference_LLMs implements INode {
|
||||
apiKey
|
||||
}
|
||||
|
||||
if (temperature) obj.temperature = parseInt(temperature, 10)
|
||||
if (temperature) obj.temperature = parseFloat(temperature)
|
||||
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
|
||||
if (topP) obj.topP = parseInt(topP, 10)
|
||||
if (hfTopK) obj.topK = parseInt(hfTopK, 10)
|
||||
|
||||
@@ -132,7 +132,7 @@ class OpenAI_LLMs implements INode {
|
||||
const basePath = nodeData.inputs?.basepath as string
|
||||
|
||||
const obj: Partial<OpenAIInput> & { openAIApiKey?: string } = {
|
||||
temperature: parseInt(temperature, 10),
|
||||
temperature: parseFloat(temperature),
|
||||
modelName,
|
||||
openAIApiKey,
|
||||
streaming: streaming ?? true
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { ICommonObject } from '../../../src'
|
||||
import { BufferMemory } from 'langchain/memory'
|
||||
import { RedisChatMessageHistory, RedisChatMessageHistoryInput } from 'langchain/stores/message/redis'
|
||||
import { createClient } from 'redis'
|
||||
|
||||
class RedisBackedChatMemory_Memory implements INode {
|
||||
label: string
|
||||
name: string
|
||||
description: string
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
baseClasses: string[]
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'Redis-Backed Chat Memory'
|
||||
this.name = 'RedisBackedChatMemory'
|
||||
this.type = 'RedisBackedChatMemory'
|
||||
this.icon = 'redis.svg'
|
||||
this.category = 'Memory'
|
||||
this.description = 'Summarizes the conversation and stores the memory in Redis server'
|
||||
this.baseClasses = [this.type, ...getBaseClasses(BufferMemory)]
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'Base URL',
|
||||
name: 'baseURL',
|
||||
type: 'string',
|
||||
default: 'redis://localhost:6379'
|
||||
},
|
||||
{
|
||||
label: 'Session Id',
|
||||
name: 'sessionId',
|
||||
type: 'string',
|
||||
description: 'if empty, chatId will be used automatically',
|
||||
default: '',
|
||||
additionalParams: true
|
||||
},
|
||||
{
|
||||
label: 'Session Timeouts',
|
||||
name: 'sessionTTL',
|
||||
type: 'number',
|
||||
description: 'Omit this parameter to make sessions never expire',
|
||||
optional: true
|
||||
},
|
||||
{
|
||||
label: 'Memory Key',
|
||||
name: 'memoryKey',
|
||||
type: 'string',
|
||||
default: 'chat_history'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
|
||||
const baseURL = nodeData.inputs?.baseURL as string
|
||||
const sessionId = nodeData.inputs?.sessionId as string
|
||||
const sessionTTL = nodeData.inputs?.sessionTTL as number
|
||||
const memoryKey = nodeData.inputs?.memoryKey as string
|
||||
|
||||
const chatId = options?.chatId as string
|
||||
|
||||
const redisClient = createClient({ url: baseURL })
|
||||
let obj: RedisChatMessageHistoryInput = {
|
||||
sessionId: sessionId ? sessionId : chatId,
|
||||
client: redisClient
|
||||
}
|
||||
|
||||
if (sessionTTL) {
|
||||
obj = {
|
||||
...obj,
|
||||
sessionTTL
|
||||
}
|
||||
}
|
||||
|
||||
let redisChatMessageHistory = new RedisChatMessageHistory(obj)
|
||||
let redis = new BufferMemory({ memoryKey, chatHistory: redisChatMessageHistory, returnMessages: true })
|
||||
|
||||
return redis
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: RedisBackedChatMemory_Memory }
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" id="redis"><path fill="#A41E11" d="M121.8 93.1c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.9-11.5 3.8-17.3 1s-42.7-17.6-49.4-20.8c-3.3-1.6-5-2.9-5-4.2v-12.7s48-10.5 55.8-13.2c7.8-2.8 10.4-2.9 17-.5s46.1 9.5 52.6 11.9v12.5c0 1.3-1.5 2.7-4.9 4.4z"></path><path fill="#D82C20" d="M121.8 80.5c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.9-11.5 3.8-17.3 1-5.8-2.8-42.7-17.7-49.4-20.9-6.6-3.2-6.8-5.4-.3-7.9 6.5-2.6 43.2-17 51-19.7 7.8-2.8 10.4-2.9 17-.5s41.1 16.1 47.6 18.5c6.7 2.4 6.9 4.4.2 7.9z"></path><path fill="#A41E11" d="M121.8 72.5c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.8-11.5 3.8-17.3 1-5.8-2.8-42.7-17.7-49.4-20.9-3.3-1.6-5-2.9-5-4.2v-12.7s48-10.5 55.8-13.2c7.8-2.8 10.4-2.9 17-.5s46.1 9.5 52.6 11.9v12.5c0 1.3-1.5 2.7-4.9 4.5z"></path><path fill="#D82C20" d="M121.8 59.8c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.8-11.5 3.8-17.3 1-5.8-2.8-42.7-17.7-49.4-20.9s-6.8-5.4-.3-7.9c6.5-2.6 43.2-17 51-19.7 7.8-2.8 10.4-2.9 17-.5s41.1 16.1 47.6 18.5c6.7 2.4 6.9 4.4.2 7.9z"></path><path fill="#A41E11" d="M121.8 51c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.8-11.5 3.8-17.3 1-5.8-2.7-42.7-17.6-49.4-20.8-3.3-1.6-5.1-2.9-5.1-4.2v-12.7s48-10.5 55.8-13.2c7.8-2.8 10.4-2.9 17-.5s46.1 9.5 52.6 11.9v12.5c.1 1.3-1.4 2.6-4.8 4.4z"></path><path fill="#D82C20" d="M121.8 38.3c-6.7 3.5-41.4 17.7-48.8 21.6-7.4 3.8-11.5 3.8-17.3 1s-42.7-17.6-49.4-20.8-6.8-5.4-.3-7.9c6.5-2.6 43.2-17 51-19.7 7.8-2.8 10.4-2.9 17-.5s41.1 16.1 47.6 18.5c6.7 2.4 6.9 4.4.2 7.8z"></path><path fill="#fff" d="M80.4 26.1l-10.8 1.2-2.5 5.8-3.9-6.5-12.5-1.1 9.3-3.4-2.8-5.2 8.8 3.4 8.2-2.7-2.2 5.4zM66.5 54.5l-20.3-8.4 29.1-4.4z"></path><ellipse cx="38.4" cy="35.4" fill="#fff" rx="15.5" ry="6"></ellipse><path fill="#7A0C00" d="M93.3 27.7l17.2 6.8-17.2 6.8z"></path><path fill="#AD2115" d="M74.3 35.3l19-7.6v13.6l-1.9.8z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1,5 +1,5 @@
|
||||
import { ICommonObject, INode, INodeData, INodeParams, PromptTemplate } from '../../../src/Interface'
|
||||
import { getBaseClasses, getInputVariables, returnJSONStr } from '../../../src/utils'
|
||||
import { getBaseClasses, getInputVariables } from '../../../src/utils'
|
||||
import { PromptTemplateInput } from 'langchain/prompts'
|
||||
|
||||
class PromptTemplate_Prompts implements INode {
|
||||
@@ -46,12 +46,11 @@ class PromptTemplate_Prompts implements INode {
|
||||
|
||||
async init(nodeData: INodeData): Promise<any> {
|
||||
const template = nodeData.inputs?.template as string
|
||||
let promptValuesStr = nodeData.inputs?.promptValues as string
|
||||
const promptValuesStr = nodeData.inputs?.promptValues as string
|
||||
|
||||
let promptValues: ICommonObject = {}
|
||||
if (promptValuesStr) {
|
||||
promptValuesStr = promptValuesStr.replace(/\s/g, '')
|
||||
promptValues = JSON.parse(returnJSONStr(promptValuesStr))
|
||||
promptValues = JSON.parse(promptValuesStr.replace(/\s/g, ''))
|
||||
}
|
||||
|
||||
const inputVariables = getInputVariables(template)
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"pdfjs-dist": "^3.7.107",
|
||||
"playwright": "^1.35.0",
|
||||
"puppeteer": "^20.7.1",
|
||||
"redis": "^4.6.7",
|
||||
"srt-parser-2": "^1.2.3",
|
||||
"vm2": "^3.9.19",
|
||||
"weaviate-ts-client": "^1.1.0",
|
||||
|
||||
@@ -3,4 +3,5 @@ PORT=3000
|
||||
# FLOWISE_PASSWORD=1234
|
||||
# DEBUG=true
|
||||
# DATABASE_PATH=/your_database_path/.flowise
|
||||
# APIKEY_PATH=/your_api_key_path/.flowise
|
||||
# EXECUTION_MODE=child or main
|
||||
@@ -9,10 +9,10 @@ export interface IChatFlow {
|
||||
id: string
|
||||
name: string
|
||||
flowData: string
|
||||
apikeyid: string
|
||||
deployed: boolean
|
||||
isPublic: boolean
|
||||
updatedDate: Date
|
||||
createdDate: Date
|
||||
apikeyid?: string
|
||||
chatbotConfig?: string
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface IChatMessage {
|
||||
content: string
|
||||
chatflowid: string
|
||||
createdDate: Date
|
||||
sourceDocuments: string
|
||||
sourceDocuments?: string
|
||||
}
|
||||
|
||||
export interface ITool {
|
||||
@@ -30,8 +30,8 @@ export interface ITool {
|
||||
name: string
|
||||
description: string
|
||||
color: string
|
||||
schema: string
|
||||
func: string
|
||||
schema?: string
|
||||
func?: string
|
||||
updatedDate: Date
|
||||
createdDate: Date
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ export class ChatFlow implements IChatFlow {
|
||||
@Column()
|
||||
flowData: string
|
||||
|
||||
@Column({ nullable: true })
|
||||
apikeyid: string
|
||||
|
||||
@Column()
|
||||
deployed: boolean
|
||||
isPublic: boolean
|
||||
|
||||
@Column({ nullable: true })
|
||||
apikeyid?: string
|
||||
|
||||
@Column({ nullable: true })
|
||||
chatbotConfig?: string
|
||||
|
||||
@@ -18,7 +18,7 @@ export class ChatMessage implements IChatMessage {
|
||||
content: string
|
||||
|
||||
@Column({ nullable: true })
|
||||
sourceDocuments: string
|
||||
sourceDocuments?: string
|
||||
|
||||
@CreateDateColumn()
|
||||
createdDate: Date
|
||||
|
||||
@@ -17,10 +17,10 @@ export class Tool implements ITool {
|
||||
color: string
|
||||
|
||||
@Column({ nullable: true })
|
||||
schema: string
|
||||
schema?: string
|
||||
|
||||
@Column({ nullable: true })
|
||||
func: string
|
||||
func?: string
|
||||
|
||||
@CreateDateColumn()
|
||||
createdDate: Date
|
||||
|
||||
@@ -211,6 +211,16 @@ export class App {
|
||||
return res.status(404).send(`Chatflow ${req.params.id} not found`)
|
||||
})
|
||||
|
||||
// Get specific chatflow via id (PUBLIC endpoint, used when sharing chatbot link)
|
||||
this.app.get('/api/v1/public-chatflows/:id', async (req: Request, res: Response) => {
|
||||
const chatflow = await this.AppDataSource.getRepository(ChatFlow).findOneBy({
|
||||
id: req.params.id
|
||||
})
|
||||
if (chatflow && chatflow.isPublic) return res.json(chatflow)
|
||||
else if (chatflow && !chatflow.isPublic) return res.status(401).send(`Unauthorized`)
|
||||
return res.status(404).send(`Chatflow ${req.params.id} not found`)
|
||||
})
|
||||
|
||||
// Save chatflow
|
||||
this.app.post('/api/v1/chatflows', async (req: Request, res: Response) => {
|
||||
const body = req.body
|
||||
|
||||
@@ -463,7 +463,7 @@ export const isSameOverrideConfig = (
|
||||
* @returns {string}
|
||||
*/
|
||||
export const getAPIKeyPath = (): string => {
|
||||
return path.join(__dirname, '..', '..', 'api.json')
|
||||
return process.env.APIKEY_PATH ? path.join(process.env.APIKEY_PATH, 'api.json') : path.join(__dirname, '..', '..', 'api.json')
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,8 @@ const getAllChatflows = () => client.get('/chatflows')
|
||||
|
||||
const getSpecificChatflow = (id) => client.get(`/chatflows/${id}`)
|
||||
|
||||
const getSpecificChatflowFromPublicEndpoint = (id) => client.get(`/public-chatflows/${id}`)
|
||||
|
||||
const createNewChatflow = (body) => client.post(`/chatflows`, body)
|
||||
|
||||
const updateChatflow = (id, body) => client.put(`/chatflows/${id}`, body)
|
||||
@@ -15,6 +17,7 @@ const getIsChatflowStreaming = (id) => client.get(`/chatflows-streaming/${id}`)
|
||||
export default {
|
||||
getAllChatflows,
|
||||
getSpecificChatflow,
|
||||
getSpecificChatflowFromPublicEndpoint,
|
||||
createNewChatflow,
|
||||
updateChatflow,
|
||||
deleteChatflow,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
// material-ui
|
||||
@@ -24,11 +24,13 @@ import useApi from 'hooks/useApi'
|
||||
// utils
|
||||
import { generateExportFlowData } from 'utils/genericHelper'
|
||||
import { uiBaseURL } from 'store/constant'
|
||||
import { SET_CHATFLOW } from 'store/actions'
|
||||
|
||||
// ==============================|| CANVAS HEADER ||============================== //
|
||||
|
||||
const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFlow }) => {
|
||||
const theme = useTheme()
|
||||
const dispatch = useDispatch()
|
||||
const navigate = useNavigate()
|
||||
const flowNameRef = useRef()
|
||||
const settingsRef = useRef()
|
||||
@@ -107,8 +109,7 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
|
||||
title: 'Embed in website or use as API',
|
||||
chatflowid: chatflow.id,
|
||||
chatflowApiKeyId: chatflow.apikeyid,
|
||||
isFormDataRequired,
|
||||
chatbotConfig: chatflow.chatbotConfig
|
||||
isFormDataRequired
|
||||
})
|
||||
setAPIDialogOpen(true)
|
||||
}
|
||||
@@ -126,6 +127,7 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
|
||||
useEffect(() => {
|
||||
if (updateChatflowApi.data) {
|
||||
setFlowName(updateChatflowApi.data.name)
|
||||
dispatch({ type: SET_CHATFLOW, chatflow: updateChatflowApi.data })
|
||||
}
|
||||
setEditingFlowName(false)
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ const Canvas = () => {
|
||||
if (!chatflow.id) {
|
||||
const newChatflowBody = {
|
||||
name: chatflowName,
|
||||
deployed: false,
|
||||
isPublic: false,
|
||||
flowData
|
||||
}
|
||||
createNewChatflowApi.request(newChatflowBody)
|
||||
|
||||
@@ -1,57 +1,107 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { baseURL } from 'store/constant'
|
||||
import axios from 'axios'
|
||||
import { FullPageChat } from 'flowise-embed-react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
// Project import
|
||||
import LoginDialog from 'ui-component/dialog/LoginDialog'
|
||||
|
||||
// API
|
||||
import chatflowsApi from 'api/chatflows'
|
||||
|
||||
// Hooks
|
||||
import useApi from 'hooks/useApi'
|
||||
|
||||
//Const
|
||||
import { baseURL } from 'store/constant'
|
||||
|
||||
// ==============================|| Chatbot ||============================== //
|
||||
|
||||
const fetchChatflow = async ({ chatflowId }) => {
|
||||
const username = localStorage.getItem('username')
|
||||
const password = localStorage.getItem('password')
|
||||
|
||||
let chatflow = await axios
|
||||
.get(`${baseURL}/api/v1/chatflows/${chatflowId}`, { auth: username && password ? { username, password } : undefined })
|
||||
.then(async function (response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error)
|
||||
})
|
||||
return chatflow
|
||||
}
|
||||
|
||||
const ChatbotFull = () => {
|
||||
const URLpath = document.location.pathname.toString().split('/')
|
||||
const chatflowId = URLpath[URLpath.length - 1] === 'chatbot' ? '' : URLpath[URLpath.length - 1]
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [chatflow, setChatflow] = useState(null)
|
||||
const [chatbotTheme, setChatbotTheme] = useState({})
|
||||
const [loginDialogOpen, setLoginDialogOpen] = useState(false)
|
||||
const [loginDialogProps, setLoginDialogProps] = useState({})
|
||||
const [isLoading, setLoading] = useState(true)
|
||||
|
||||
const getSpecificChatflowFromPublicApi = useApi(chatflowsApi.getSpecificChatflowFromPublicEndpoint)
|
||||
const getSpecificChatflowApi = useApi(chatflowsApi.getSpecificChatflow)
|
||||
|
||||
const onLoginClick = (username, password) => {
|
||||
localStorage.setItem('username', username)
|
||||
localStorage.setItem('password', password)
|
||||
navigate(0)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
;(async () => {
|
||||
const fetchData = async () => {
|
||||
let response = await fetchChatflow({ chatflowId })
|
||||
setChatflow(response)
|
||||
if (response.chatbotConfig) {
|
||||
try {
|
||||
setChatbotTheme(JSON.parse(response.chatbotConfig))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
setChatbotTheme({})
|
||||
}
|
||||
getSpecificChatflowFromPublicApi.request(chatflowId)
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (getSpecificChatflowFromPublicApi.error) {
|
||||
if (getSpecificChatflowFromPublicApi.error?.response?.status === 401) {
|
||||
if (localStorage.getItem('username') && localStorage.getItem('password')) {
|
||||
getSpecificChatflowApi.request(chatflowId)
|
||||
} else {
|
||||
setLoginDialogProps({
|
||||
title: 'Login',
|
||||
confirmButtonName: 'Login'
|
||||
})
|
||||
setLoginDialogOpen(true)
|
||||
}
|
||||
}
|
||||
fetchData()
|
||||
})()
|
||||
}, [chatflowId])
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [getSpecificChatflowFromPublicApi.error])
|
||||
|
||||
useEffect(() => {
|
||||
if (getSpecificChatflowApi.error) {
|
||||
if (getSpecificChatflowApi.error?.response?.status === 401) {
|
||||
setLoginDialogProps({
|
||||
title: 'Login',
|
||||
confirmButtonName: 'Login'
|
||||
})
|
||||
setLoginDialogOpen(true)
|
||||
}
|
||||
}
|
||||
}, [getSpecificChatflowApi.error])
|
||||
|
||||
useEffect(() => {
|
||||
if (getSpecificChatflowFromPublicApi.data || getSpecificChatflowApi.data) {
|
||||
const chatflowData = getSpecificChatflowFromPublicApi.data || getSpecificChatflowApi.data
|
||||
setChatflow(chatflowData)
|
||||
if (chatflowData.chatbotConfig) {
|
||||
try {
|
||||
setChatbotTheme(JSON.parse(chatflowData.chatbotConfig))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
setChatbotTheme({})
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [getSpecificChatflowFromPublicApi.data, getSpecificChatflowApi.data])
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(getSpecificChatflowFromPublicApi.loading || getSpecificChatflowApi.loading)
|
||||
}, [getSpecificChatflowFromPublicApi.loading, getSpecificChatflowApi.loading])
|
||||
|
||||
return (
|
||||
<>
|
||||
{!chatflow || chatflow.apikeyid ? (
|
||||
<p>Invalid Chatbot</p>
|
||||
) : (
|
||||
<FullPageChat chatflowid={chatflow.id} apiHost={baseURL} theme={{ chatWindow: chatbotTheme }} />
|
||||
)}
|
||||
{!isLoading ? (
|
||||
<>
|
||||
{!chatflow || chatflow.apikeyid ? (
|
||||
<p>Invalid Chatbot</p>
|
||||
) : (
|
||||
<FullPageChat chatflowid={chatflow.id} apiHost={baseURL} theme={{ chatWindow: chatbotTheme }} />
|
||||
)}
|
||||
<LoginDialog show={loginDialogOpen} dialogProps={loginDialogProps} onConfirm={onLoginClick} />
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -134,7 +134,6 @@ const APICodeDialog = ({ show, dialogProps, onCancel }) => {
|
||||
const [chatflowApiKeyId, setChatflowApiKeyId] = useState('')
|
||||
const [selectedApiKey, setSelectedApiKey] = useState({})
|
||||
const [checkboxVal, setCheckbox] = useState(false)
|
||||
const [chatbotConfig, setChatbotConfig] = useState(null)
|
||||
|
||||
const getAllAPIKeysApi = useApi(apiKeyApi.getAllAPIKeys)
|
||||
const updateChatflowApi = useApi(chatflowsApi.updateChatflow)
|
||||
@@ -491,12 +490,6 @@ query({
|
||||
setChatflowApiKeyId(dialogProps.chatflowApiKeyId)
|
||||
setSelectedApiKey(getAllAPIKeysApi.data.find((key) => key.id === dialogProps.chatflowApiKeyId))
|
||||
}
|
||||
|
||||
if (dialogProps.chatbotConfig) {
|
||||
setChatbotConfig(JSON.parse(dialogProps.chatbotConfig))
|
||||
} else {
|
||||
setChatbotConfig(null)
|
||||
}
|
||||
}
|
||||
}, [dialogProps, getAllAPIKeysApi.data])
|
||||
|
||||
@@ -601,9 +594,7 @@ query({
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{codeLang === 'Share Chatbot' && !chatflowApiKeyId && (
|
||||
<ShareChatbot chatflowid={dialogProps.chatflowid} chatbotConfig={chatbotConfig} />
|
||||
)}
|
||||
{codeLang === 'Share Chatbot' && !chatflowApiKeyId && <ShareChatbot />}
|
||||
</TabPanel>
|
||||
))}
|
||||
</DialogContent>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { useState } from 'react'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction } from 'store/actions'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions'
|
||||
import { SketchPicker } from 'react-color'
|
||||
|
||||
import { Box, Typography, Button, Switch, OutlinedInput, Popover, Stack, IconButton } from '@mui/material'
|
||||
@@ -9,6 +8,7 @@ import { useTheme } from '@mui/material/styles'
|
||||
|
||||
// Project import
|
||||
import { StyledButton } from 'ui-component/button/StyledButton'
|
||||
import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser'
|
||||
|
||||
// Icons
|
||||
import { IconX, IconCopy, IconArrowUpRightCircle } from '@tabler/icons'
|
||||
@@ -41,15 +41,20 @@ const defaultConfig = {
|
||||
}
|
||||
}
|
||||
|
||||
const ShareChatbot = ({ chatflowid, chatbotConfig }) => {
|
||||
const ShareChatbot = () => {
|
||||
const dispatch = useDispatch()
|
||||
const theme = useTheme()
|
||||
const chatflow = useSelector((state) => state.canvas.chatflow)
|
||||
const chatflowid = chatflow.id
|
||||
const chatbotConfig = chatflow.chatbotConfig ? JSON.parse(chatflow.chatbotConfig) : {}
|
||||
|
||||
useNotifier()
|
||||
|
||||
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
|
||||
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
|
||||
|
||||
const [isPublicChatflow, setChatflowIsPublic] = useState(chatflow.isPublic ?? false)
|
||||
|
||||
const [welcomeMessage, setWelcomeMessage] = useState(chatbotConfig?.welcomeMessage ?? '')
|
||||
const [backgroundColor, setBackgroundColor] = useState(chatbotConfig?.backgroundColor ?? defaultConfig.backgroundColor)
|
||||
const [fontSize, setFontSize] = useState(chatbotConfig?.fontSize ?? defaultConfig.fontSize)
|
||||
@@ -141,6 +146,44 @@ const ShareChatbot = ({ chatflowid, chatbotConfig }) => {
|
||||
)
|
||||
}
|
||||
})
|
||||
dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
|
||||
enqueueSnackbar({
|
||||
message: `Failed to save Chatbot Configuration: ${errorData}`,
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'error',
|
||||
persist: true,
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onSwitchChange = async (checked) => {
|
||||
try {
|
||||
const saveResp = await chatflowsApi.updateChatflow(chatflowid, { isPublic: checked })
|
||||
if (saveResp.data) {
|
||||
enqueueSnackbar({
|
||||
message: 'Chatbot Configuration Saved',
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'success',
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
@@ -328,6 +371,21 @@ const ShareChatbot = ({ chatflowid, chatbotConfig }) => {
|
||||
<IconButton title='Open New Tab' color='primary' onClick={() => window.open(`${baseURL}/chatbot/${chatflowid}`, '_blank')}>
|
||||
<IconArrowUpRightCircle />
|
||||
</IconButton>
|
||||
<div style={{ flex: 1 }} />
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Switch
|
||||
checked={isPublicChatflow}
|
||||
onChange={(event) => {
|
||||
setChatflowIsPublic(event.target.checked)
|
||||
onSwitchChange(event.target.checked)
|
||||
}}
|
||||
/>
|
||||
<Typography>Make Public</Typography>
|
||||
<TooltipWithParser
|
||||
style={{ marginLeft: 10 }}
|
||||
title={'Making public will allow anyone to access the chatbot without username & password'}
|
||||
/>
|
||||
</div>
|
||||
</Stack>
|
||||
{textField(welcomeMessage, 'welcomeMessage', 'Welcome Message', 'string', 'Hello! This is custom welcome message')}
|
||||
{colorField(backgroundColor, 'backgroundColor', 'Background Color')}
|
||||
@@ -412,9 +470,4 @@ const ShareChatbot = ({ chatflowid, chatbotConfig }) => {
|
||||
)
|
||||
}
|
||||
|
||||
ShareChatbot.propTypes = {
|
||||
chatflowid: PropTypes.string,
|
||||
chatbotConfig: PropTypes.object
|
||||
}
|
||||
|
||||
export default ShareChatbot
|
||||
|
||||
Reference in New Issue
Block a user