mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 17:01:00 +03:00
Merge branch 'main' into feature/DynamoDb-Integration
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
<!-- markdownlint-disable MD030 -->
|
<!-- markdownlint-disable MD030 -->
|
||||||
|
|
||||||
# Flowise - LangchainJS UI
|
# Flowise - Low-Code LLM apps builder
|
||||||
|
|
||||||
<a href="https://github.com/FlowiseAI/Flowise">
|
<a href="https://github.com/FlowiseAI/Flowise">
|
||||||
<img width="100%" src="https://github.com/FlowiseAI/Flowise/blob/main/images/flowise.gif?raw=true"></a>
|
<img width="100%" src="https://github.com/FlowiseAI/Flowise/blob/main/images/flowise.gif?raw=true"></a>
|
||||||
|
|
||||||
Drag & drop UI to build your customized LLM flow using [LangchainJS](https://github.com/hwchase17/langchainjs)
|
Drag & drop UI to build your customized LLM flow
|
||||||
|
|
||||||
## ⚡Quick Start
|
## ⚡Quick Start
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class AzureChatOpenAI_ChatModels implements INode {
|
|||||||
const streaming = nodeData.inputs?.streaming as boolean
|
const streaming = nodeData.inputs?.streaming as boolean
|
||||||
|
|
||||||
const obj: Partial<AzureOpenAIInput> & Partial<OpenAIBaseInput> = {
|
const obj: Partial<AzureOpenAIInput> & Partial<OpenAIBaseInput> = {
|
||||||
temperature: parseInt(temperature, 10),
|
temperature: parseFloat(temperature),
|
||||||
modelName,
|
modelName,
|
||||||
azureOpenAIApiKey,
|
azureOpenAIApiKey,
|
||||||
azureOpenAIApiInstanceName,
|
azureOpenAIApiInstanceName,
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class ChatAnthropic_ChatModels implements INode {
|
|||||||
const streaming = nodeData.inputs?.streaming as boolean
|
const streaming = nodeData.inputs?.streaming as boolean
|
||||||
|
|
||||||
const obj: Partial<AnthropicInput> & { anthropicApiKey?: string } = {
|
const obj: Partial<AnthropicInput> & { anthropicApiKey?: string } = {
|
||||||
temperature: parseInt(temperature, 10),
|
temperature: parseFloat(temperature),
|
||||||
modelName,
|
modelName,
|
||||||
anthropicApiKey,
|
anthropicApiKey,
|
||||||
streaming: streaming ?? true
|
streaming: streaming ?? true
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class ChatHuggingFace_ChatModels implements INode {
|
|||||||
apiKey
|
apiKey
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temperature) obj.temperature = parseInt(temperature, 10)
|
if (temperature) obj.temperature = parseFloat(temperature)
|
||||||
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
|
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
|
||||||
if (topP) obj.topP = parseInt(topP, 10)
|
if (topP) obj.topP = parseInt(topP, 10)
|
||||||
if (hfTopK) obj.topK = parseInt(hfTopK, 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 basePath = nodeData.inputs?.basePath as string
|
||||||
|
|
||||||
const obj: Partial<OpenAIChatInput> & { openAIApiKey?: string } = {
|
const obj: Partial<OpenAIChatInput> & { openAIApiKey?: string } = {
|
||||||
temperature: parseInt(temperature, 10),
|
temperature: parseFloat(temperature),
|
||||||
modelName,
|
modelName,
|
||||||
openAIApiKey: 'sk-'
|
openAIApiKey: 'sk-'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class ChatOpenAI_ChatModels implements INode {
|
|||||||
const basePath = nodeData.inputs?.basepath as string
|
const basePath = nodeData.inputs?.basepath as string
|
||||||
|
|
||||||
const obj: Partial<OpenAIChatInput> & { openAIApiKey?: string } = {
|
const obj: Partial<OpenAIChatInput> & { openAIApiKey?: string } = {
|
||||||
temperature: parseInt(temperature, 10),
|
temperature: parseFloat(temperature),
|
||||||
modelName,
|
modelName,
|
||||||
openAIApiKey,
|
openAIApiKey,
|
||||||
streaming: streaming ?? true
|
streaming: streaming ?? true
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class AzureOpenAI_LLMs implements INode {
|
|||||||
const streaming = nodeData.inputs?.streaming as boolean
|
const streaming = nodeData.inputs?.streaming as boolean
|
||||||
|
|
||||||
const obj: Partial<AzureOpenAIInput> & Partial<OpenAIInput> = {
|
const obj: Partial<AzureOpenAIInput> & Partial<OpenAIInput> = {
|
||||||
temperature: parseInt(temperature, 10),
|
temperature: parseFloat(temperature),
|
||||||
modelName,
|
modelName,
|
||||||
azureOpenAIApiKey,
|
azureOpenAIApiKey,
|
||||||
azureOpenAIApiInstanceName,
|
azureOpenAIApiInstanceName,
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class Cohere_LLMs implements INode {
|
|||||||
|
|
||||||
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
|
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
|
||||||
if (modelName) obj.model = modelName
|
if (modelName) obj.model = modelName
|
||||||
if (temperature) obj.temperature = parseInt(temperature, 10)
|
if (temperature) obj.temperature = parseFloat(temperature)
|
||||||
|
|
||||||
const model = new Cohere(obj)
|
const model = new Cohere(obj)
|
||||||
return model
|
return model
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class HuggingFaceInference_LLMs implements INode {
|
|||||||
apiKey
|
apiKey
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temperature) obj.temperature = parseInt(temperature, 10)
|
if (temperature) obj.temperature = parseFloat(temperature)
|
||||||
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
|
if (maxTokens) obj.maxTokens = parseInt(maxTokens, 10)
|
||||||
if (topP) obj.topP = parseInt(topP, 10)
|
if (topP) obj.topP = parseInt(topP, 10)
|
||||||
if (hfTopK) obj.topK = parseInt(hfTopK, 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 basePath = nodeData.inputs?.basepath as string
|
||||||
|
|
||||||
const obj: Partial<OpenAIInput> & { openAIApiKey?: string } = {
|
const obj: Partial<OpenAIInput> & { openAIApiKey?: string } = {
|
||||||
temperature: parseInt(temperature, 10),
|
temperature: parseFloat(temperature),
|
||||||
modelName,
|
modelName,
|
||||||
openAIApiKey,
|
openAIApiKey,
|
||||||
streaming: streaming ?? true
|
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 { 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'
|
import { PromptTemplateInput } from 'langchain/prompts'
|
||||||
|
|
||||||
class PromptTemplate_Prompts implements INode {
|
class PromptTemplate_Prompts implements INode {
|
||||||
@@ -46,12 +46,11 @@ class PromptTemplate_Prompts implements INode {
|
|||||||
|
|
||||||
async init(nodeData: INodeData): Promise<any> {
|
async init(nodeData: INodeData): Promise<any> {
|
||||||
const template = nodeData.inputs?.template as string
|
const template = nodeData.inputs?.template as string
|
||||||
let promptValuesStr = nodeData.inputs?.promptValues as string
|
const promptValuesStr = nodeData.inputs?.promptValues as string
|
||||||
|
|
||||||
let promptValues: ICommonObject = {}
|
let promptValues: ICommonObject = {}
|
||||||
if (promptValuesStr) {
|
if (promptValuesStr) {
|
||||||
promptValuesStr = promptValuesStr.replace(/\s/g, '')
|
promptValues = JSON.parse(promptValuesStr.replace(/\s/g, ''))
|
||||||
promptValues = JSON.parse(returnJSONStr(promptValuesStr))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputVariables = getInputVariables(template)
|
const inputVariables = getInputVariables(template)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
"d3-dsv": "2",
|
"d3-dsv": "2",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"express": "^4.17.3",
|
"express": "^4.17.3",
|
||||||
"faiss-node": "^0.2.1",
|
"faiss-node": "^0.2.2",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
"html-to-text": "^9.0.5",
|
"html-to-text": "^9.0.5",
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
"pdfjs-dist": "^3.7.107",
|
"pdfjs-dist": "^3.7.107",
|
||||||
"playwright": "^1.35.0",
|
"playwright": "^1.35.0",
|
||||||
"puppeteer": "^20.7.1",
|
"puppeteer": "^20.7.1",
|
||||||
|
"redis": "^4.6.7",
|
||||||
"srt-parser-2": "^1.2.3",
|
"srt-parser-2": "^1.2.3",
|
||||||
"vm2": "^3.9.19",
|
"vm2": "^3.9.19",
|
||||||
"weaviate-ts-client": "^1.1.0",
|
"weaviate-ts-client": "^1.1.0",
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ PORT=3000
|
|||||||
# FLOWISE_PASSWORD=1234
|
# FLOWISE_PASSWORD=1234
|
||||||
# DEBUG=true
|
# DEBUG=true
|
||||||
# DATABASE_PATH=/your_database_path/.flowise
|
# DATABASE_PATH=/your_database_path/.flowise
|
||||||
|
# APIKEY_PATH=/your_api_key_path/.flowise
|
||||||
# EXECUTION_MODE=child or main
|
# EXECUTION_MODE=child or main
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<!-- markdownlint-disable MD030 -->
|
<!-- markdownlint-disable MD030 -->
|
||||||
|
|
||||||
# Flowise - LangchainJS UI
|
# Flowise - Low-Code LLM apps builder
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Drag & drop UI to build your customized LLM flow using [LangchainJS](https://github.com/hwchase17/langchainjs)
|
Drag & drop UI to build your customized LLM flow
|
||||||
|
|
||||||
## ⚡Quick Start
|
## ⚡Quick Start
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ export interface IChatFlow {
|
|||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
flowData: string
|
flowData: string
|
||||||
apikeyid: string
|
isPublic: boolean
|
||||||
deployed: boolean
|
|
||||||
updatedDate: Date
|
updatedDate: Date
|
||||||
createdDate: Date
|
createdDate: Date
|
||||||
|
apikeyid?: string
|
||||||
|
chatbotConfig?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IChatMessage {
|
export interface IChatMessage {
|
||||||
@@ -21,7 +22,7 @@ export interface IChatMessage {
|
|||||||
content: string
|
content: string
|
||||||
chatflowid: string
|
chatflowid: string
|
||||||
createdDate: Date
|
createdDate: Date
|
||||||
sourceDocuments: string
|
sourceDocuments?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITool {
|
export interface ITool {
|
||||||
@@ -29,8 +30,8 @@ export interface ITool {
|
|||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
color: string
|
color: string
|
||||||
schema: string
|
schema?: string
|
||||||
func: string
|
func?: string
|
||||||
updatedDate: Date
|
updatedDate: Date
|
||||||
createdDate: Date
|
createdDate: Date
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,14 @@ export class ChatFlow implements IChatFlow {
|
|||||||
@Column()
|
@Column()
|
||||||
flowData: string
|
flowData: string
|
||||||
|
|
||||||
@Column({ nullable: true })
|
|
||||||
apikeyid: string
|
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
deployed: boolean
|
isPublic: boolean
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
apikeyid?: string
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
chatbotConfig?: string
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdDate: Date
|
createdDate: Date
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class ChatMessage implements IChatMessage {
|
|||||||
content: string
|
content: string
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
sourceDocuments: string
|
sourceDocuments?: string
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdDate: Date
|
createdDate: Date
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ export class Tool implements ITool {
|
|||||||
color: string
|
color: string
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
schema: string
|
schema?: string
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
func: string
|
func?: string
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdDate: Date
|
createdDate: Date
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ import {
|
|||||||
replaceAllAPIKeys,
|
replaceAllAPIKeys,
|
||||||
isFlowValidForStream,
|
isFlowValidForStream,
|
||||||
isVectorStoreFaiss,
|
isVectorStoreFaiss,
|
||||||
databaseEntities
|
databaseEntities,
|
||||||
|
getApiKey
|
||||||
} from './utils'
|
} from './utils'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import { getDataSource } from './DataSource'
|
import { getDataSource } from './DataSource'
|
||||||
@@ -92,7 +93,7 @@ export class App {
|
|||||||
const basicAuthMiddleware = basicAuth({
|
const basicAuthMiddleware = basicAuth({
|
||||||
users: { [username]: password }
|
users: { [username]: password }
|
||||||
})
|
})
|
||||||
const whitelistURLs = ['/api/v1/prediction/', '/api/v1/node-icon/', '/api/v1/chatflows-streaming']
|
const whitelistURLs = ['/api/v1/public-chatflows', '/api/v1/prediction/', '/api/v1/node-icon/', '/api/v1/chatflows-streaming']
|
||||||
this.app.use((req, res, next) => {
|
this.app.use((req, res, next) => {
|
||||||
if (req.url.includes('/api/v1/')) {
|
if (req.url.includes('/api/v1/')) {
|
||||||
whitelistURLs.some((url) => req.url.includes(url)) ? next() : basicAuthMiddleware(req, res, next)
|
whitelistURLs.some((url) => req.url.includes(url)) ? next() : basicAuthMiddleware(req, res, next)
|
||||||
@@ -177,6 +178,24 @@ export class App {
|
|||||||
return res.json(chatflows)
|
return res.json(chatflows)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Get specific chatflow via api key
|
||||||
|
this.app.get('/api/v1/chatflows/apikey/:apiKey', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const apiKey = await getApiKey(req.params.apiKey)
|
||||||
|
if (!apiKey) return res.status(401).send('Unauthorized')
|
||||||
|
const chatflows = await this.AppDataSource.getRepository(ChatFlow)
|
||||||
|
.createQueryBuilder('cf')
|
||||||
|
.where('cf.apikeyid = :apikeyid', { apikeyid: apiKey.id })
|
||||||
|
.orWhere('cf.apikeyid IS NULL')
|
||||||
|
.orderBy('cf.name', 'ASC')
|
||||||
|
.getMany()
|
||||||
|
if (chatflows.length >= 1) return res.status(200).send(chatflows)
|
||||||
|
return res.status(404).send('Chatflow not found')
|
||||||
|
} catch (err: any) {
|
||||||
|
return res.status(500).send(err?.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Get specific chatflow via id
|
// Get specific chatflow via id
|
||||||
this.app.get('/api/v1/chatflows/:id', async (req: Request, res: Response) => {
|
this.app.get('/api/v1/chatflows/:id', async (req: Request, res: Response) => {
|
||||||
const chatflow = await this.AppDataSource.getRepository(ChatFlow).findOneBy({
|
const chatflow = await this.AppDataSource.getRepository(ChatFlow).findOneBy({
|
||||||
@@ -186,6 +205,16 @@ export class App {
|
|||||||
return res.status(404).send(`Chatflow ${req.params.id} not found`)
|
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
|
// Save chatflow
|
||||||
this.app.post('/api/v1/chatflows', async (req: Request, res: Response) => {
|
this.app.post('/api/v1/chatflows', async (req: Request, res: Response) => {
|
||||||
const body = req.body
|
const body = req.body
|
||||||
@@ -472,6 +501,17 @@ export class App {
|
|||||||
return res.json(keys)
|
return res.json(keys)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Verify api key
|
||||||
|
this.app.get('/api/v1/apikey/:apiKey', async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const apiKey = await getApiKey(req.params.apiKey)
|
||||||
|
if (!apiKey) return res.status(401).send('Unauthorized')
|
||||||
|
return res.status(200).send('OK')
|
||||||
|
} catch (err: any) {
|
||||||
|
return res.status(500).send(err?.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// Serve UI static
|
// Serve UI static
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|||||||
@@ -463,7 +463,7 @@ export const isSameOverrideConfig = (
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export const getAPIKeyPath = (): 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')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -547,6 +547,18 @@ export const addAPIKey = async (keyName: string): Promise<ICommonObject[]> => {
|
|||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get API Key details
|
||||||
|
* @param {string} apiKey
|
||||||
|
* @returns {Promise<ICommonObject[]>}
|
||||||
|
*/
|
||||||
|
export const getApiKey = async (apiKey: string) => {
|
||||||
|
const existingAPIKeys = await getAPIKeys()
|
||||||
|
const keyIndex = existingAPIKeys.findIndex((key) => key.apiKey === apiKey)
|
||||||
|
if (keyIndex < 0) return undefined
|
||||||
|
return existingAPIKeys[keyIndex]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update existing API key
|
* Update existing API key
|
||||||
* @param {string} keyIdToUpdate
|
* @param {string} keyIdToUpdate
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
module.exports = {
|
||||||
|
webpack: {
|
||||||
|
configure: {
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.m?js$/,
|
||||||
|
resolve: {
|
||||||
|
fullySpecified: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
"@mui/x-data-grid": "^6.8.0",
|
"@mui/x-data-grid": "^6.8.0",
|
||||||
"@tabler/icons": "^1.39.1",
|
"@tabler/icons": "^1.39.1",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
|
"flowise-embed": "*",
|
||||||
|
"flowise-embed-react": "*",
|
||||||
"formik": "^2.2.6",
|
"formik": "^2.2.6",
|
||||||
"framer-motion": "^4.1.13",
|
"framer-motion": "^4.1.13",
|
||||||
"history": "^5.0.0",
|
"history": "^5.0.0",
|
||||||
@@ -27,6 +29,7 @@
|
|||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-code-blocks": "^0.0.9-0",
|
"react-code-blocks": "^0.0.9-0",
|
||||||
|
"react-color": "^2.19.3",
|
||||||
"react-datepicker": "^4.8.0",
|
"react-datepicker": "^4.8.0",
|
||||||
"react-device-detect": "^1.17.0",
|
"react-device-detect": "^1.17.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@@ -47,11 +50,11 @@
|
|||||||
"yup": "^0.32.9"
|
"yup": "^0.32.9"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "craco start",
|
||||||
"dev": "react-scripts start",
|
"dev": "craco start",
|
||||||
"build": "react-scripts build",
|
"build": "craco build",
|
||||||
"test": "react-scripts test",
|
"test": "craco test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "craco eject"
|
||||||
},
|
},
|
||||||
"babel": {
|
"babel": {
|
||||||
"presets": [
|
"presets": [
|
||||||
@@ -72,6 +75,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/eslint-parser": "^7.15.8",
|
"@babel/eslint-parser": "^7.15.8",
|
||||||
|
"@craco/craco": "^7.1.0",
|
||||||
"@testing-library/jest-dom": "^5.11.10",
|
"@testing-library/jest-dom": "^5.11.10",
|
||||||
"@testing-library/react": "^14.0.0",
|
"@testing-library/react": "^14.0.0",
|
||||||
"@testing-library/user-event": "^12.8.3",
|
"@testing-library/user-event": "^12.8.3",
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ const getAllChatflows = () => client.get('/chatflows')
|
|||||||
|
|
||||||
const getSpecificChatflow = (id) => client.get(`/chatflows/${id}`)
|
const getSpecificChatflow = (id) => client.get(`/chatflows/${id}`)
|
||||||
|
|
||||||
|
const getSpecificChatflowFromPublicEndpoint = (id) => client.get(`/public-chatflows/${id}`)
|
||||||
|
|
||||||
const createNewChatflow = (body) => client.post(`/chatflows`, body)
|
const createNewChatflow = (body) => client.post(`/chatflows`, body)
|
||||||
|
|
||||||
const updateChatflow = (id, body) => client.put(`/chatflows/${id}`, body)
|
const updateChatflow = (id, body) => client.put(`/chatflows/${id}`, body)
|
||||||
@@ -15,6 +17,7 @@ const getIsChatflowStreaming = (id) => client.get(`/chatflows-streaming/${id}`)
|
|||||||
export default {
|
export default {
|
||||||
getAllChatflows,
|
getAllChatflows,
|
||||||
getSpecificChatflow,
|
getSpecificChatflow,
|
||||||
|
getSpecificChatflowFromPublicEndpoint,
|
||||||
createNewChatflow,
|
createNewChatflow,
|
||||||
updateChatflow,
|
updateChatflow,
|
||||||
deleteChatflow,
|
deleteChatflow,
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,23 @@
|
|||||||
|
import { lazy } from 'react'
|
||||||
|
|
||||||
|
// project imports
|
||||||
|
import Loadable from 'ui-component/loading/Loadable'
|
||||||
|
import MinimalLayout from 'layout/MinimalLayout'
|
||||||
|
|
||||||
|
// canvas routing
|
||||||
|
const ChatbotFull = Loadable(lazy(() => import('views/chatbot')))
|
||||||
|
|
||||||
|
// ==============================|| CANVAS ROUTING ||============================== //
|
||||||
|
|
||||||
|
const ChatbotRoutes = {
|
||||||
|
path: '/',
|
||||||
|
element: <MinimalLayout />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/chatbot/:id',
|
||||||
|
element: <ChatbotFull />
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChatbotRoutes
|
||||||
@@ -3,10 +3,11 @@ import { useRoutes } from 'react-router-dom'
|
|||||||
// routes
|
// routes
|
||||||
import MainRoutes from './MainRoutes'
|
import MainRoutes from './MainRoutes'
|
||||||
import CanvasRoutes from './CanvasRoutes'
|
import CanvasRoutes from './CanvasRoutes'
|
||||||
|
import ChatbotRoutes from './ChatbotRoutes'
|
||||||
import config from 'config'
|
import config from 'config'
|
||||||
|
|
||||||
// ==============================|| ROUTING RENDER ||============================== //
|
// ==============================|| ROUTING RENDER ||============================== //
|
||||||
|
|
||||||
export default function ThemeRoutes() {
|
export default function ThemeRoutes() {
|
||||||
return useRoutes([MainRoutes, CanvasRoutes], config.basename)
|
return useRoutes([MainRoutes, CanvasRoutes, ChatbotRoutes], config.basename)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector, useDispatch } from 'react-redux'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
// material-ui
|
// material-ui
|
||||||
@@ -13,7 +13,7 @@ import { IconSettings, IconChevronLeft, IconDeviceFloppy, IconPencil, IconCheck,
|
|||||||
// project imports
|
// project imports
|
||||||
import Settings from 'views/settings'
|
import Settings from 'views/settings'
|
||||||
import SaveChatflowDialog from 'ui-component/dialog/SaveChatflowDialog'
|
import SaveChatflowDialog from 'ui-component/dialog/SaveChatflowDialog'
|
||||||
import APICodeDialog from 'ui-component/dialog/APICodeDialog'
|
import APICodeDialog from 'views/chatflows/APICodeDialog'
|
||||||
|
|
||||||
// API
|
// API
|
||||||
import chatflowsApi from 'api/chatflows'
|
import chatflowsApi from 'api/chatflows'
|
||||||
@@ -24,11 +24,13 @@ import useApi from 'hooks/useApi'
|
|||||||
// utils
|
// utils
|
||||||
import { generateExportFlowData } from 'utils/genericHelper'
|
import { generateExportFlowData } from 'utils/genericHelper'
|
||||||
import { uiBaseURL } from 'store/constant'
|
import { uiBaseURL } from 'store/constant'
|
||||||
|
import { SET_CHATFLOW } from 'store/actions'
|
||||||
|
|
||||||
// ==============================|| CANVAS HEADER ||============================== //
|
// ==============================|| CANVAS HEADER ||============================== //
|
||||||
|
|
||||||
const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFlow }) => {
|
const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFlow }) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const dispatch = useDispatch()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const flowNameRef = useRef()
|
const flowNameRef = useRef()
|
||||||
const settingsRef = useRef()
|
const settingsRef = useRef()
|
||||||
@@ -125,6 +127,7 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (updateChatflowApi.data) {
|
if (updateChatflowApi.data) {
|
||||||
setFlowName(updateChatflowApi.data.name)
|
setFlowName(updateChatflowApi.data.name)
|
||||||
|
dispatch({ type: SET_CHATFLOW, chatflow: updateChatflowApi.data })
|
||||||
}
|
}
|
||||||
setEditingFlowName(false)
|
setEditingFlowName(false)
|
||||||
|
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ const Canvas = () => {
|
|||||||
if (!chatflow.id) {
|
if (!chatflow.id) {
|
||||||
const newChatflowBody = {
|
const newChatflowBody = {
|
||||||
name: chatflowName,
|
name: chatflowName,
|
||||||
deployed: false,
|
isPublic: false,
|
||||||
flowData
|
flowData
|
||||||
}
|
}
|
||||||
createNewChatflowApi.request(newChatflowBody)
|
createNewChatflowApi.request(newChatflowBody)
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
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 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(() => {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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 (
|
||||||
|
<>
|
||||||
|
{!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}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChatbotFull
|
||||||
+56
-141
@@ -9,6 +9,8 @@ import { CopyBlock, atomOneDark } from 'react-code-blocks'
|
|||||||
|
|
||||||
// Project import
|
// Project import
|
||||||
import { Dropdown } from 'ui-component/dropdown/Dropdown'
|
import { Dropdown } from 'ui-component/dropdown/Dropdown'
|
||||||
|
import ShareChatbot from './ShareChatbot'
|
||||||
|
import EmbedChat from './EmbedChat'
|
||||||
|
|
||||||
// Const
|
// Const
|
||||||
import { baseURL } from 'store/constant'
|
import { baseURL } from 'store/constant'
|
||||||
@@ -19,6 +21,7 @@ import pythonSVG from 'assets/images/python.svg'
|
|||||||
import javascriptSVG from 'assets/images/javascript.svg'
|
import javascriptSVG from 'assets/images/javascript.svg'
|
||||||
import cURLSVG from 'assets/images/cURL.svg'
|
import cURLSVG from 'assets/images/cURL.svg'
|
||||||
import EmbedSVG from 'assets/images/embed.svg'
|
import EmbedSVG from 'assets/images/embed.svg'
|
||||||
|
import ShareChatbotSVG from 'assets/images/sharing.png'
|
||||||
|
|
||||||
// API
|
// API
|
||||||
import apiKeyApi from 'api/apikey'
|
import apiKeyApi from 'api/apikey'
|
||||||
@@ -119,77 +122,18 @@ const getConfigExamplesForCurl = (configData, bodyType) => {
|
|||||||
return finalStr
|
return finalStr
|
||||||
}
|
}
|
||||||
|
|
||||||
const embedCode = (chatflowid) => {
|
|
||||||
return `<script type="module">
|
|
||||||
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
|
|
||||||
Chatbot.init({
|
|
||||||
chatflowid: "${chatflowid}",
|
|
||||||
apiHost: "${baseURL}",
|
|
||||||
})
|
|
||||||
</script>`
|
|
||||||
}
|
|
||||||
|
|
||||||
const embedCodeCustomization = (chatflowid) => {
|
|
||||||
return `<script type="module">
|
|
||||||
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
|
|
||||||
Chatbot.init({
|
|
||||||
chatflowid: "${chatflowid}",
|
|
||||||
apiHost: "${baseURL}",
|
|
||||||
chatflowConfig: {
|
|
||||||
// topK: 2
|
|
||||||
},
|
|
||||||
theme: {
|
|
||||||
button: {
|
|
||||||
backgroundColor: "#3B81F6",
|
|
||||||
right: 20,
|
|
||||||
bottom: 20,
|
|
||||||
size: "medium",
|
|
||||||
iconColor: "white",
|
|
||||||
customIconSrc: "https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg",
|
|
||||||
},
|
|
||||||
chatWindow: {
|
|
||||||
welcomeMessage: "Hello! This is custom welcome message",
|
|
||||||
backgroundColor: "#ffffff",
|
|
||||||
height: 700,
|
|
||||||
width: 400,
|
|
||||||
fontSize: 16,
|
|
||||||
poweredByTextColor: "#303235",
|
|
||||||
botMessage: {
|
|
||||||
backgroundColor: "#f7f8ff",
|
|
||||||
textColor: "#303235",
|
|
||||||
showAvatar: true,
|
|
||||||
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png",
|
|
||||||
},
|
|
||||||
userMessage: {
|
|
||||||
backgroundColor: "#3B81F6",
|
|
||||||
textColor: "#ffffff",
|
|
||||||
showAvatar: true,
|
|
||||||
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png",
|
|
||||||
},
|
|
||||||
textInput: {
|
|
||||||
placeholder: "Type your question",
|
|
||||||
backgroundColor: "#ffffff",
|
|
||||||
textColor: "#303235",
|
|
||||||
sendButtonColor: "#3B81F6",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>`
|
|
||||||
}
|
|
||||||
|
|
||||||
const APICodeDialog = ({ show, dialogProps, onCancel }) => {
|
const APICodeDialog = ({ show, dialogProps, onCancel }) => {
|
||||||
const portalElement = document.getElementById('portal')
|
const portalElement = document.getElementById('portal')
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const codes = ['Embed', 'Python', 'JavaScript', 'cURL']
|
|
||||||
|
const codes = ['Embed', 'Python', 'JavaScript', 'cURL', 'Share Chatbot']
|
||||||
const [value, setValue] = useState(0)
|
const [value, setValue] = useState(0)
|
||||||
const [keyOptions, setKeyOptions] = useState([])
|
const [keyOptions, setKeyOptions] = useState([])
|
||||||
const [apiKeys, setAPIKeys] = useState([])
|
const [apiKeys, setAPIKeys] = useState([])
|
||||||
const [chatflowApiKeyId, setChatflowApiKeyId] = useState('')
|
const [chatflowApiKeyId, setChatflowApiKeyId] = useState('')
|
||||||
const [selectedApiKey, setSelectedApiKey] = useState({})
|
const [selectedApiKey, setSelectedApiKey] = useState({})
|
||||||
const [checkboxVal, setCheckbox] = useState(false)
|
const [checkboxVal, setCheckbox] = useState(false)
|
||||||
const [embedChatCheckboxVal, setEmbedChatCheckbox] = useState(false)
|
|
||||||
|
|
||||||
const getAllAPIKeysApi = useApi(apiKeyApi.getAllAPIKeys)
|
const getAllAPIKeysApi = useApi(apiKeyApi.getAllAPIKeys)
|
||||||
const updateChatflowApi = useApi(chatflowsApi.updateChatflow)
|
const updateChatflowApi = useApi(chatflowsApi.updateChatflow)
|
||||||
@@ -203,10 +147,6 @@ const APICodeDialog = ({ show, dialogProps, onCancel }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onCheckBoxEmbedChatChanged = (newVal) => {
|
|
||||||
setEmbedChatCheckbox(newVal)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onApiKeySelected = (keyValue) => {
|
const onApiKeySelected = (keyValue) => {
|
||||||
if (keyValue === 'addnewkey') {
|
if (keyValue === 'addnewkey') {
|
||||||
navigate('/apikey')
|
navigate('/apikey')
|
||||||
@@ -265,8 +205,6 @@ query({"question": "Hey, how are you?"}).then((response) => {
|
|||||||
return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\
|
return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\
|
||||||
-X POST \\
|
-X POST \\
|
||||||
-d '{"question": "Hey, how are you?"}'`
|
-d '{"question": "Hey, how are you?"}'`
|
||||||
} else if (codeLang === 'Embed') {
|
|
||||||
return embedCode(dialogProps.chatflowid)
|
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
@@ -309,8 +247,6 @@ query({"question": "Hey, how are you?"}).then((response) => {
|
|||||||
-X POST \\
|
-X POST \\
|
||||||
-d '{"question": "Hey, how are you?"}' \\
|
-d '{"question": "Hey, how are you?"}' \\
|
||||||
-H "Authorization: Bearer ${selectedApiKey?.apiKey}"`
|
-H "Authorization: Bearer ${selectedApiKey?.apiKey}"`
|
||||||
} else if (codeLang === 'Embed') {
|
|
||||||
return embedCode(dialogProps.chatflowid)
|
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
@@ -318,7 +254,7 @@ query({"question": "Hey, how are you?"}).then((response) => {
|
|||||||
const getLang = (codeLang) => {
|
const getLang = (codeLang) => {
|
||||||
if (codeLang === 'Python') {
|
if (codeLang === 'Python') {
|
||||||
return 'python'
|
return 'python'
|
||||||
} else if (codeLang === 'JavaScript' || codeLang === 'Embed') {
|
} else if (codeLang === 'JavaScript') {
|
||||||
return 'javascript'
|
return 'javascript'
|
||||||
} else if (codeLang === 'cURL') {
|
} else if (codeLang === 'cURL') {
|
||||||
return 'bash'
|
return 'bash'
|
||||||
@@ -335,6 +271,8 @@ query({"question": "Hey, how are you?"}).then((response) => {
|
|||||||
return EmbedSVG
|
return EmbedSVG
|
||||||
} else if (codeLang === 'cURL') {
|
} else if (codeLang === 'cURL') {
|
||||||
return cURLSVG
|
return cURLSVG
|
||||||
|
} else if (codeLang === 'Share Chatbot') {
|
||||||
|
return ShareChatbotSVG
|
||||||
}
|
}
|
||||||
return pythonSVG
|
return pythonSVG
|
||||||
}
|
}
|
||||||
@@ -593,93 +531,70 @@ query({
|
|||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
{value !== 0 && (
|
<div style={{ flex: 20 }}>
|
||||||
<div style={{ flex: 20 }}>
|
<Dropdown
|
||||||
<Dropdown
|
name='SelectKey'
|
||||||
name='SelectKey'
|
disableClearable={true}
|
||||||
disableClearable={true}
|
options={keyOptions}
|
||||||
options={keyOptions}
|
onSelect={(newValue) => onApiKeySelected(newValue)}
|
||||||
onSelect={(newValue) => onApiKeySelected(newValue)}
|
value={dialogProps.chatflowApiKeyId ?? chatflowApiKeyId ?? 'Choose an API key'}
|
||||||
value={dialogProps.chatflowApiKeyId ?? chatflowApiKeyId ?? 'Choose an API key'}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginTop: 10 }}></div>
|
<div style={{ marginTop: 10 }}></div>
|
||||||
{codes.map((codeLang, index) => (
|
{codes.map((codeLang, index) => (
|
||||||
<TabPanel key={index} value={value} index={index}>
|
<TabPanel key={index} value={value} index={index}>
|
||||||
{value === 0 && (
|
{(codeLang === 'Embed' || codeLang === 'Share Chatbot') && chatflowApiKeyId && (
|
||||||
<>
|
<>
|
||||||
<span>
|
<p>You cannot use API key while embedding/sharing chatbot.</p>
|
||||||
Paste this anywhere in the <code>{`<body>`}</code> tag of your html file.
|
<p>
|
||||||
<p>
|
Please select <b>"No Authorization"</b> from the dropdown at the top right corner.
|
||||||
You can also specify a
|
</p>
|
||||||
<a
|
|
||||||
rel='noreferrer'
|
|
||||||
target='_blank'
|
|
||||||
href='https://www.npmjs.com/package/flowise-embed?activeTab=versions'
|
|
||||||
>
|
|
||||||
version
|
|
||||||
</a>
|
|
||||||
: <code>{`https://cdn.jsdelivr.net/npm/flowise-embed@<version>/dist/web.js`}</code>
|
|
||||||
</p>
|
|
||||||
</span>
|
|
||||||
<div style={{ height: 10 }}></div>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<CopyBlock
|
{codeLang === 'Embed' && !chatflowApiKeyId && <EmbedChat chatflowid={dialogProps.chatflowid} />}
|
||||||
theme={atomOneDark}
|
{codeLang !== 'Embed' && codeLang !== 'Share Chatbot' && (
|
||||||
text={chatflowApiKeyId ? getCodeWithAuthorization(codeLang) : getCode(codeLang)}
|
|
||||||
language={getLang(codeLang)}
|
|
||||||
showLineNumbers={false}
|
|
||||||
wrapLines
|
|
||||||
/>
|
|
||||||
{value !== 0 && <CheckboxInput label='Show Input Config' value={checkboxVal} onChange={onCheckBoxChanged} />}
|
|
||||||
{value !== 0 && checkboxVal && getConfigApi.data && getConfigApi.data.length > 0 && (
|
|
||||||
<>
|
<>
|
||||||
<TableViewOnly rows={getConfigApi.data} columns={Object.keys(getConfigApi.data[0])} />
|
|
||||||
<CopyBlock
|
<CopyBlock
|
||||||
theme={atomOneDark}
|
theme={atomOneDark}
|
||||||
text={
|
text={chatflowApiKeyId ? getCodeWithAuthorization(codeLang) : getCode(codeLang)}
|
||||||
chatflowApiKeyId
|
|
||||||
? dialogProps.isFormDataRequired
|
|
||||||
? getConfigCodeWithFormDataWithAuth(codeLang, getConfigApi.data)
|
|
||||||
: getConfigCodeWithAuthorization(codeLang, getConfigApi.data)
|
|
||||||
: dialogProps.isFormDataRequired
|
|
||||||
? getConfigCodeWithFormData(codeLang, getConfigApi.data)
|
|
||||||
: getConfigCode(codeLang, getConfigApi.data)
|
|
||||||
}
|
|
||||||
language={getLang(codeLang)}
|
language={getLang(codeLang)}
|
||||||
showLineNumbers={false}
|
showLineNumbers={false}
|
||||||
wrapLines
|
wrapLines
|
||||||
/>
|
/>
|
||||||
|
<CheckboxInput label='Show Input Config' value={checkboxVal} onChange={onCheckBoxChanged} />
|
||||||
|
{checkboxVal && getConfigApi.data && getConfigApi.data.length > 0 && (
|
||||||
|
<>
|
||||||
|
<TableViewOnly rows={getConfigApi.data} columns={Object.keys(getConfigApi.data[0])} />
|
||||||
|
<CopyBlock
|
||||||
|
theme={atomOneDark}
|
||||||
|
text={
|
||||||
|
chatflowApiKeyId
|
||||||
|
? dialogProps.isFormDataRequired
|
||||||
|
? getConfigCodeWithFormDataWithAuth(codeLang, getConfigApi.data)
|
||||||
|
: getConfigCodeWithAuthorization(codeLang, getConfigApi.data)
|
||||||
|
: dialogProps.isFormDataRequired
|
||||||
|
? getConfigCodeWithFormData(codeLang, getConfigApi.data)
|
||||||
|
: getConfigCode(codeLang, getConfigApi.data)
|
||||||
|
}
|
||||||
|
language={getLang(codeLang)}
|
||||||
|
showLineNumbers={false}
|
||||||
|
wrapLines
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{getIsChatflowStreamingApi.data?.isStreaming && (
|
||||||
|
<p>
|
||||||
|
Read
|
||||||
|
<a rel='noreferrer' target='_blank' href='https://docs.flowiseai.com/how-to-use#streaming'>
|
||||||
|
here
|
||||||
|
</a>
|
||||||
|
on how to stream response back to application
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{value === 0 && (
|
{codeLang === 'Share Chatbot' && !chatflowApiKeyId && <ShareChatbot />}
|
||||||
<CheckboxInput
|
|
||||||
label='Show Embed Chat Config'
|
|
||||||
value={embedChatCheckboxVal}
|
|
||||||
onChange={onCheckBoxEmbedChatChanged}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{value === 0 && embedChatCheckboxVal && (
|
|
||||||
<CopyBlock
|
|
||||||
theme={atomOneDark}
|
|
||||||
text={embedCodeCustomization(dialogProps.chatflowid)}
|
|
||||||
language={getLang('Embed')}
|
|
||||||
showLineNumbers={false}
|
|
||||||
wrapLines
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{value !== 0 && getIsChatflowStreamingApi.data?.isStreaming && (
|
|
||||||
<p>
|
|
||||||
Read
|
|
||||||
<a rel='noreferrer' target='_blank' href='https://docs.flowiseai.com/how-to-use#streaming'>
|
|
||||||
here
|
|
||||||
</a>
|
|
||||||
on how to stream response back to application
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
))}
|
))}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
import { Tabs, Tab, Box } from '@mui/material'
|
||||||
|
import { CopyBlock, atomOneDark } from 'react-code-blocks'
|
||||||
|
|
||||||
|
// Project import
|
||||||
|
import { CheckboxInput } from 'ui-component/checkbox/Checkbox'
|
||||||
|
|
||||||
|
// Const
|
||||||
|
import { baseURL } from 'store/constant'
|
||||||
|
|
||||||
|
function TabPanel(props) {
|
||||||
|
const { children, value, index, ...other } = props
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role='tabpanel'
|
||||||
|
hidden={value !== index}
|
||||||
|
id={`attachment-tabpanel-${index}`}
|
||||||
|
aria-labelledby={`attachment-tab-${index}`}
|
||||||
|
{...other}
|
||||||
|
>
|
||||||
|
{value === index && <Box sx={{ p: 1 }}>{children}</Box>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TabPanel.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
index: PropTypes.number.isRequired,
|
||||||
|
value: PropTypes.number.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
function a11yProps(index) {
|
||||||
|
return {
|
||||||
|
id: `attachment-tab-${index}`,
|
||||||
|
'aria-controls': `attachment-tabpanel-${index}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const embedPopupHtmlCode = (chatflowid) => {
|
||||||
|
return `<script type="module">
|
||||||
|
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
|
||||||
|
Chatbot.init({
|
||||||
|
chatflowid: "${chatflowid}",
|
||||||
|
apiHost: "${baseURL}",
|
||||||
|
})
|
||||||
|
</script>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const embedPopupReactCode = (chatflowid) => {
|
||||||
|
return `import { BubbleChat } from 'flowise-embed-react'
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<BubbleChat chatflowid="${chatflowid}" apiHost="${baseURL}" />
|
||||||
|
);
|
||||||
|
};`
|
||||||
|
}
|
||||||
|
|
||||||
|
const embedFullpageHtmlCode = (chatflowid) => {
|
||||||
|
return `<flowise-fullchatbot></flowise-fullchatbot>
|
||||||
|
<script type="module">
|
||||||
|
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
|
||||||
|
Chatbot.initFull({
|
||||||
|
chatflowid: "${chatflowid}",
|
||||||
|
apiHost: "${baseURL}",
|
||||||
|
})
|
||||||
|
</script>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const embedFullpageReactCode = (chatflowid) => {
|
||||||
|
return `import { FullPageChat } from "flowise-embed-react"
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<FullPageChat
|
||||||
|
chatflowid="${chatflowid}"
|
||||||
|
apiHost="${baseURL}"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};`
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonConfig = (isReact = false) => {
|
||||||
|
return isReact
|
||||||
|
? `button: {
|
||||||
|
backgroundColor: "#3B81F6",
|
||||||
|
right: 20,
|
||||||
|
bottom: 20,
|
||||||
|
size: "medium",
|
||||||
|
iconColor: "white",
|
||||||
|
customIconSrc: "https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg",
|
||||||
|
}`
|
||||||
|
: `button: {
|
||||||
|
backgroundColor: "#3B81F6",
|
||||||
|
right: 20,
|
||||||
|
bottom: 20,
|
||||||
|
size: "medium",
|
||||||
|
iconColor: "white",
|
||||||
|
customIconSrc: "https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg",
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const chatwindowConfig = (isReact = false) => {
|
||||||
|
return isReact
|
||||||
|
? `chatWindow: {
|
||||||
|
welcomeMessage: "Hello! This is custom welcome message",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
height: 700,
|
||||||
|
width: 400,
|
||||||
|
fontSize: 16,
|
||||||
|
poweredByTextColor: "#303235",
|
||||||
|
botMessage: {
|
||||||
|
backgroundColor: "#f7f8ff",
|
||||||
|
textColor: "#303235",
|
||||||
|
showAvatar: true,
|
||||||
|
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png",
|
||||||
|
},
|
||||||
|
userMessage: {
|
||||||
|
backgroundColor: "#3B81F6",
|
||||||
|
textColor: "#ffffff",
|
||||||
|
showAvatar: true,
|
||||||
|
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png",
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
placeholder: "Type your question",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
textColor: "#303235",
|
||||||
|
sendButtonColor: "#3B81F6",
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
: `chatWindow: {
|
||||||
|
welcomeMessage: "Hello! This is custom welcome message",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
height: 700,
|
||||||
|
width: 400,
|
||||||
|
fontSize: 16,
|
||||||
|
poweredByTextColor: "#303235",
|
||||||
|
botMessage: {
|
||||||
|
backgroundColor: "#f7f8ff",
|
||||||
|
textColor: "#303235",
|
||||||
|
showAvatar: true,
|
||||||
|
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png",
|
||||||
|
},
|
||||||
|
userMessage: {
|
||||||
|
backgroundColor: "#3B81F6",
|
||||||
|
textColor: "#ffffff",
|
||||||
|
showAvatar: true,
|
||||||
|
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png",
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
placeholder: "Type your question",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
textColor: "#303235",
|
||||||
|
sendButtonColor: "#3B81F6",
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const embedPopupHtmlCodeCustomization = (chatflowid) => {
|
||||||
|
return `<script type="module">
|
||||||
|
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
|
||||||
|
Chatbot.init({
|
||||||
|
chatflowid: "${chatflowid}",
|
||||||
|
apiHost: "${baseURL}",
|
||||||
|
chatflowConfig: {
|
||||||
|
// topK: 2
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
${buttonConfig()},
|
||||||
|
${chatwindowConfig()}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const embedPopupReactCodeCustomization = (chatflowid) => {
|
||||||
|
return `import { BubbleChat } from 'flowise-embed-react'
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<BubbleChat
|
||||||
|
chatflowid="${chatflowid}"
|
||||||
|
apiHost="${baseURL}"
|
||||||
|
theme={{
|
||||||
|
${buttonConfig(true)},
|
||||||
|
${chatwindowConfig(true)}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};`
|
||||||
|
}
|
||||||
|
|
||||||
|
const embedFullpageHtmlCodeCustomization = (chatflowid) => {
|
||||||
|
return `<flowise-fullchatbot></flowise-fullchatbot>
|
||||||
|
<script type="module">
|
||||||
|
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
|
||||||
|
Chatbot.initFull({
|
||||||
|
chatflowid: "${chatflowid}",
|
||||||
|
apiHost: "${baseURL}",
|
||||||
|
theme: {
|
||||||
|
${chatwindowConfig()}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const embedFullpageReactCodeCustomization = (chatflowid) => {
|
||||||
|
return `import { FullPageChat } from "flowise-embed-react"
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<FullPageChat
|
||||||
|
chatflowid="${chatflowid}"
|
||||||
|
apiHost="${baseURL}"
|
||||||
|
theme={{
|
||||||
|
${chatwindowConfig(true)}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};`
|
||||||
|
}
|
||||||
|
|
||||||
|
const EmbedChat = ({ chatflowid }) => {
|
||||||
|
const codes = ['Popup Html', 'Fullpage Html', 'Popup React', 'Fullpage React']
|
||||||
|
const [value, setValue] = useState(0)
|
||||||
|
const [embedChatCheckboxVal, setEmbedChatCheckbox] = useState(false)
|
||||||
|
|
||||||
|
const onCheckBoxEmbedChatChanged = (newVal) => {
|
||||||
|
setEmbedChatCheckbox(newVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = (event, newValue) => {
|
||||||
|
setValue(newValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCode = (codeLang) => {
|
||||||
|
switch (codeLang) {
|
||||||
|
case 'Popup Html':
|
||||||
|
return embedPopupHtmlCode(chatflowid)
|
||||||
|
case 'Fullpage Html':
|
||||||
|
return embedFullpageHtmlCode(chatflowid)
|
||||||
|
case 'Popup React':
|
||||||
|
return embedPopupReactCode(chatflowid)
|
||||||
|
case 'Fullpage React':
|
||||||
|
return embedFullpageReactCode(chatflowid)
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCodeCustomization = (codeLang) => {
|
||||||
|
switch (codeLang) {
|
||||||
|
case 'Popup Html':
|
||||||
|
return embedPopupHtmlCodeCustomization(chatflowid)
|
||||||
|
case 'Fullpage Html':
|
||||||
|
return embedFullpageHtmlCodeCustomization(chatflowid)
|
||||||
|
case 'Popup React':
|
||||||
|
return embedPopupReactCodeCustomization(chatflowid)
|
||||||
|
case 'Fullpage React':
|
||||||
|
return embedFullpageReactCodeCustomization(chatflowid)
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
|
||||||
|
<div style={{ flex: 80 }}>
|
||||||
|
<Tabs value={value} onChange={handleChange} aria-label='tabs'>
|
||||||
|
{codes.map((codeLang, index) => (
|
||||||
|
<Tab key={index} label={codeLang} {...a11yProps(index)}></Tab>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ marginTop: 10 }}></div>
|
||||||
|
{codes.map((codeLang, index) => (
|
||||||
|
<TabPanel key={index} value={value} index={index}>
|
||||||
|
{(value === 0 || value === 1) && (
|
||||||
|
<>
|
||||||
|
<span>
|
||||||
|
Paste this anywhere in the <code>{`<body>`}</code> tag of your html file.
|
||||||
|
<p>
|
||||||
|
You can also specify a
|
||||||
|
<a
|
||||||
|
rel='noreferrer'
|
||||||
|
target='_blank'
|
||||||
|
href='https://www.npmjs.com/package/flowise-embed?activeTab=versions'
|
||||||
|
>
|
||||||
|
version
|
||||||
|
</a>
|
||||||
|
: <code>{`https://cdn.jsdelivr.net/npm/flowise-embed@<version>/dist/web.js`}</code>
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
<div style={{ height: 10 }}></div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<CopyBlock theme={atomOneDark} text={getCode(codeLang)} language='javascript' showLineNumbers={false} wrapLines />
|
||||||
|
|
||||||
|
<CheckboxInput label='Show Embed Chat Config' value={embedChatCheckboxVal} onChange={onCheckBoxEmbedChatChanged} />
|
||||||
|
|
||||||
|
{embedChatCheckboxVal && (
|
||||||
|
<CopyBlock
|
||||||
|
theme={atomOneDark}
|
||||||
|
text={getCodeCustomization(codeLang)}
|
||||||
|
language='javascript'
|
||||||
|
showLineNumbers={false}
|
||||||
|
wrapLines
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</TabPanel>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
EmbedChat.propTypes = {
|
||||||
|
chatflowid: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EmbedChat
|
||||||
@@ -0,0 +1,473 @@
|
|||||||
|
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 { Box, Typography, Button, Switch, OutlinedInput, Popover, Stack, IconButton } from '@mui/material'
|
||||||
|
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'
|
||||||
|
|
||||||
|
// API
|
||||||
|
import chatflowsApi from 'api/chatflows'
|
||||||
|
|
||||||
|
// utils
|
||||||
|
import useNotifier from 'utils/useNotifier'
|
||||||
|
|
||||||
|
// Const
|
||||||
|
import { baseURL } from 'store/constant'
|
||||||
|
|
||||||
|
const defaultConfig = {
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
fontSize: 16,
|
||||||
|
poweredByTextColor: '#303235',
|
||||||
|
botMessage: {
|
||||||
|
backgroundColor: '#f7f8ff',
|
||||||
|
textColor: '#303235'
|
||||||
|
},
|
||||||
|
userMessage: {
|
||||||
|
backgroundColor: '#3B81F6',
|
||||||
|
textColor: '#ffffff'
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
textColor: '#303235',
|
||||||
|
sendButtonColor: '#3B81F6'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
const [poweredByTextColor, setPoweredByTextColor] = useState(chatbotConfig?.poweredByTextColor ?? defaultConfig.poweredByTextColor)
|
||||||
|
|
||||||
|
const [botMessageBackgroundColor, setBotMessageBackgroundColor] = useState(
|
||||||
|
chatbotConfig?.botMessage?.backgroundColor ?? defaultConfig.botMessage.backgroundColor
|
||||||
|
)
|
||||||
|
const [botMessageTextColor, setBotMessageTextColor] = useState(
|
||||||
|
chatbotConfig?.botMessage?.textColor ?? defaultConfig.botMessage.textColor
|
||||||
|
)
|
||||||
|
const [botMessageAvatarSrc, setBotMessageAvatarSrc] = useState(chatbotConfig?.botMessage?.avatarSrc ?? '')
|
||||||
|
const [botMessageShowAvatar, setBotMessageShowAvatar] = useState(chatbotConfig?.botMessage?.showAvatar ?? false)
|
||||||
|
|
||||||
|
const [userMessageBackgroundColor, setUserMessageBackgroundColor] = useState(
|
||||||
|
chatbotConfig?.userMessage?.backgroundColor ?? defaultConfig.userMessage.backgroundColor
|
||||||
|
)
|
||||||
|
const [userMessageTextColor, setUserMessageTextColor] = useState(
|
||||||
|
chatbotConfig?.userMessage?.textColor ?? defaultConfig.userMessage.textColor
|
||||||
|
)
|
||||||
|
const [userMessageAvatarSrc, setUserMessageAvatarSrc] = useState(chatbotConfig?.userMessage?.avatarSrc ?? '')
|
||||||
|
const [userMessageShowAvatar, setUserMessageShowAvatar] = useState(chatbotConfig?.userMessage?.showAvatar ?? false)
|
||||||
|
|
||||||
|
const [textInputBackgroundColor, setTextInputBackgroundColor] = useState(
|
||||||
|
chatbotConfig?.textInput?.backgroundColor ?? defaultConfig.textInput.backgroundColor
|
||||||
|
)
|
||||||
|
const [textInputTextColor, setTextInputTextColor] = useState(chatbotConfig?.textInput?.textColor ?? defaultConfig.textInput.textColor)
|
||||||
|
const [textInputPlaceholder, setTextInputPlaceholder] = useState(chatbotConfig?.textInput?.placeholder ?? '')
|
||||||
|
const [textInputSendButtonColor, setTextInputSendButtonColor] = useState(
|
||||||
|
chatbotConfig?.textInput?.sendButtonColor ?? defaultConfig.textInput.sendButtonColor
|
||||||
|
)
|
||||||
|
|
||||||
|
const [colorAnchorEl, setColorAnchorEl] = useState(null)
|
||||||
|
const [selectedColorConfig, setSelectedColorConfig] = useState('')
|
||||||
|
const [sketchPickerColor, setSketchPickerColor] = useState('')
|
||||||
|
const openColorPopOver = Boolean(colorAnchorEl)
|
||||||
|
|
||||||
|
const [copyAnchorEl, setCopyAnchorEl] = useState(null)
|
||||||
|
const openCopyPopOver = Boolean(copyAnchorEl)
|
||||||
|
|
||||||
|
const formatObj = () => {
|
||||||
|
const obj = {
|
||||||
|
botMessage: {
|
||||||
|
showAvatar: false
|
||||||
|
},
|
||||||
|
userMessage: {
|
||||||
|
showAvatar: false
|
||||||
|
},
|
||||||
|
textInput: {}
|
||||||
|
}
|
||||||
|
if (welcomeMessage) obj.welcomeMessage = welcomeMessage
|
||||||
|
if (backgroundColor) obj.backgroundColor = backgroundColor
|
||||||
|
if (fontSize) obj.fontSize = fontSize
|
||||||
|
if (poweredByTextColor) obj.poweredByTextColor = poweredByTextColor
|
||||||
|
|
||||||
|
if (botMessageBackgroundColor) obj.botMessage.backgroundColor = botMessageBackgroundColor
|
||||||
|
if (botMessageTextColor) obj.botMessage.textColor = botMessageTextColor
|
||||||
|
if (botMessageAvatarSrc) obj.botMessage.avatarSrc = botMessageAvatarSrc
|
||||||
|
if (botMessageShowAvatar) obj.botMessage.showAvatar = botMessageShowAvatar
|
||||||
|
|
||||||
|
if (userMessageBackgroundColor) obj.userMessage.backgroundColor = userMessageBackgroundColor
|
||||||
|
if (userMessageTextColor) obj.userMessage.textColor = userMessageTextColor
|
||||||
|
if (userMessageAvatarSrc) obj.userMessage.avatarSrc = userMessageAvatarSrc
|
||||||
|
if (userMessageShowAvatar) obj.userMessage.showAvatar = userMessageShowAvatar
|
||||||
|
|
||||||
|
if (textInputBackgroundColor) obj.textInput.backgroundColor = textInputBackgroundColor
|
||||||
|
if (textInputTextColor) obj.textInput.textColor = textInputTextColor
|
||||||
|
if (textInputPlaceholder) obj.textInput.placeholder = textInputPlaceholder
|
||||||
|
if (textInputSendButtonColor) obj.textInput.sendButtonColor = textInputSendButtonColor
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSave = async () => {
|
||||||
|
try {
|
||||||
|
const saveResp = await chatflowsApi.updateChatflow(chatflowid, {
|
||||||
|
chatbotConfig: JSON.stringify(formatObj())
|
||||||
|
})
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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 handleClosePopOver = () => {
|
||||||
|
setColorAnchorEl(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCloseCopyPopOver = () => {
|
||||||
|
setCopyAnchorEl(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onColorSelected = (hexColor) => {
|
||||||
|
switch (selectedColorConfig) {
|
||||||
|
case 'backgroundColor':
|
||||||
|
setBackgroundColor(hexColor)
|
||||||
|
break
|
||||||
|
case 'poweredByTextColor':
|
||||||
|
setPoweredByTextColor(hexColor)
|
||||||
|
break
|
||||||
|
case 'botMessageBackgroundColor':
|
||||||
|
setBotMessageBackgroundColor(hexColor)
|
||||||
|
break
|
||||||
|
case 'botMessageTextColor':
|
||||||
|
setBotMessageTextColor(hexColor)
|
||||||
|
break
|
||||||
|
case 'userMessageBackgroundColor':
|
||||||
|
setUserMessageBackgroundColor(hexColor)
|
||||||
|
break
|
||||||
|
case 'userMessageTextColor':
|
||||||
|
setUserMessageTextColor(hexColor)
|
||||||
|
break
|
||||||
|
case 'textInputBackgroundColor':
|
||||||
|
setTextInputBackgroundColor(hexColor)
|
||||||
|
break
|
||||||
|
case 'textInputTextColor':
|
||||||
|
setTextInputTextColor(hexColor)
|
||||||
|
break
|
||||||
|
case 'textInputSendButtonColor':
|
||||||
|
setTextInputSendButtonColor(hexColor)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
setSketchPickerColor(hexColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onTextChanged = (value, fieldName) => {
|
||||||
|
switch (fieldName) {
|
||||||
|
case 'welcomeMessage':
|
||||||
|
setWelcomeMessage(value)
|
||||||
|
break
|
||||||
|
case 'fontSize':
|
||||||
|
setFontSize(value)
|
||||||
|
break
|
||||||
|
case 'botMessageAvatarSrc':
|
||||||
|
setBotMessageAvatarSrc(value)
|
||||||
|
break
|
||||||
|
case 'userMessageAvatarSrc':
|
||||||
|
setUserMessageAvatarSrc(value)
|
||||||
|
break
|
||||||
|
case 'textInputPlaceholder':
|
||||||
|
setTextInputPlaceholder(value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBooleanChanged = (value, fieldName) => {
|
||||||
|
switch (fieldName) {
|
||||||
|
case 'botMessageShowAvatar':
|
||||||
|
setBotMessageShowAvatar(value)
|
||||||
|
break
|
||||||
|
case 'userMessageShowAvatar':
|
||||||
|
setUserMessageShowAvatar(value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const colorField = (color, fieldName, fieldLabel) => {
|
||||||
|
return (
|
||||||
|
<Box sx={{ pt: 2, pb: 2 }}>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
|
||||||
|
<Typography sx={{ mb: 1 }}>{fieldLabel}</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
cursor: 'pointer',
|
||||||
|
width: '30px',
|
||||||
|
height: '30px',
|
||||||
|
border: '1px solid #616161',
|
||||||
|
marginRight: '10px',
|
||||||
|
backgroundColor: color ?? '#ffffff',
|
||||||
|
borderRadius: '5px'
|
||||||
|
}}
|
||||||
|
onClick={(event) => {
|
||||||
|
setSelectedColorConfig(fieldName)
|
||||||
|
setSketchPickerColor(color ?? '#ffffff')
|
||||||
|
setColorAnchorEl(event.currentTarget)
|
||||||
|
}}
|
||||||
|
></Box>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const booleanField = (value, fieldName, fieldLabel) => {
|
||||||
|
return (
|
||||||
|
<Box sx={{ pt: 2, pb: 2 }}>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
|
||||||
|
<Typography sx={{ mb: 1 }}>{fieldLabel}</Typography>
|
||||||
|
<Switch
|
||||||
|
id={fieldName}
|
||||||
|
checked={value}
|
||||||
|
onChange={(event) => {
|
||||||
|
onBooleanChanged(event.target.checked, fieldName)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const textField = (message, fieldName, fieldLabel, fieldType = 'string', placeholder = '') => {
|
||||||
|
return (
|
||||||
|
<Box sx={{ pt: 2, pb: 2 }}>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
|
||||||
|
<Typography sx={{ mb: 1 }}>{fieldLabel}</Typography>
|
||||||
|
<OutlinedInput
|
||||||
|
id={fieldName}
|
||||||
|
type={fieldType}
|
||||||
|
fullWidth
|
||||||
|
value={message}
|
||||||
|
placeholder={placeholder}
|
||||||
|
name={fieldName}
|
||||||
|
onChange={(e) => {
|
||||||
|
onTextChanged(e.target.value, fieldName)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Stack direction='row'>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
p: 1,
|
||||||
|
borderRadius: 10,
|
||||||
|
backgroundColor: theme.palette.primary.light,
|
||||||
|
width: 'max-content',
|
||||||
|
height: 'max-content'
|
||||||
|
}}
|
||||||
|
variant='h5'
|
||||||
|
>
|
||||||
|
{`${baseURL}/chatbot/${chatflowid}`}
|
||||||
|
</Typography>
|
||||||
|
<IconButton
|
||||||
|
title='Copy Link'
|
||||||
|
color='success'
|
||||||
|
onClick={(event) => {
|
||||||
|
navigator.clipboard.writeText(`${baseURL}/chatbot/${chatflowid}`)
|
||||||
|
setCopyAnchorEl(event.currentTarget)
|
||||||
|
setTimeout(() => {
|
||||||
|
handleCloseCopyPopOver()
|
||||||
|
}, 1500)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconCopy />
|
||||||
|
</IconButton>
|
||||||
|
<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')}
|
||||||
|
{textField(fontSize, 'fontSize', 'Font Size', 'number')}
|
||||||
|
{colorField(poweredByTextColor, 'poweredByTextColor', 'PoweredBy TextColor')}
|
||||||
|
|
||||||
|
{/*BOT Message*/}
|
||||||
|
<Typography variant='h4' sx={{ mb: 1, mt: 2 }}>
|
||||||
|
Bot Message
|
||||||
|
</Typography>
|
||||||
|
{colorField(botMessageBackgroundColor, 'botMessageBackgroundColor', 'Background Color')}
|
||||||
|
{colorField(botMessageTextColor, 'botMessageTextColor', 'Text Color')}
|
||||||
|
{textField(
|
||||||
|
botMessageAvatarSrc,
|
||||||
|
'botMessageAvatarSrc',
|
||||||
|
'Avatar Link',
|
||||||
|
'string',
|
||||||
|
`https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png`
|
||||||
|
)}
|
||||||
|
{booleanField(botMessageShowAvatar, 'botMessageShowAvatar', 'Show Avatar')}
|
||||||
|
|
||||||
|
{/*USER Message*/}
|
||||||
|
<Typography variant='h4' sx={{ mb: 1, mt: 2 }}>
|
||||||
|
User Message
|
||||||
|
</Typography>
|
||||||
|
{colorField(userMessageBackgroundColor, 'userMessageBackgroundColor', 'Background Color')}
|
||||||
|
{colorField(userMessageTextColor, 'userMessageTextColor', 'Text Color')}
|
||||||
|
{textField(
|
||||||
|
userMessageAvatarSrc,
|
||||||
|
'userMessageAvatarSrc',
|
||||||
|
'Avatar Link',
|
||||||
|
'string',
|
||||||
|
`https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png`
|
||||||
|
)}
|
||||||
|
{booleanField(userMessageShowAvatar, 'userMessageShowAvatar', 'Show Avatar')}
|
||||||
|
|
||||||
|
{/*TEXT Input*/}
|
||||||
|
<Typography variant='h4' sx={{ mb: 1, mt: 2 }}>
|
||||||
|
Text Input
|
||||||
|
</Typography>
|
||||||
|
{colorField(textInputBackgroundColor, 'textInputBackgroundColor', 'Background Color')}
|
||||||
|
{colorField(textInputTextColor, 'textInputTextColor', 'Text Color')}
|
||||||
|
{textField(textInputPlaceholder, 'textInputPlaceholder', 'TextInput Placeholder', 'string', `Type question..`)}
|
||||||
|
{colorField(textInputSendButtonColor, 'textInputSendButtonColor', 'TextIntput Send Button Color')}
|
||||||
|
|
||||||
|
<StyledButton style={{ marginBottom: 10, marginTop: 10 }} variant='contained' onClick={() => onSave()}>
|
||||||
|
Save Changes
|
||||||
|
</StyledButton>
|
||||||
|
<Popover
|
||||||
|
open={openColorPopOver}
|
||||||
|
anchorEl={colorAnchorEl}
|
||||||
|
onClose={handleClosePopOver}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'right'
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'left'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SketchPicker color={sketchPickerColor} onChange={(color) => onColorSelected(color.hex)} />
|
||||||
|
</Popover>
|
||||||
|
<Popover
|
||||||
|
open={openCopyPopOver}
|
||||||
|
anchorEl={copyAnchorEl}
|
||||||
|
onClose={handleCloseCopyPopOver}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'right'
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'left'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant='h6' sx={{ pl: 1, pr: 1, color: 'white', background: theme.palette.success.dark }}>
|
||||||
|
Copied!
|
||||||
|
</Typography>
|
||||||
|
</Popover>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ShareChatbot
|
||||||
Reference in New Issue
Block a user