Merge branch 'main' into bugfix/VM2-Security

# Conflicts:
#	docker/docker-compose.yml
This commit is contained in:
Henry 2023-07-17 20:31:19 +01:00
commit 13622ba0ae
13 changed files with 212 additions and 111 deletions

View File

@ -128,7 +128,7 @@ FLOWISE_PASSWORD=1234
## 🌱 Env Variables ## 🌱 Env Variables
Flowise support different environment variables to configure your instance. You can specify the following variables in the `.env` file inside `packages/server` folder. Flowise support different environment variables to configure your instance. You can specify the following variables in the `.env` file inside `packages/server` folder. Read [more](https://docs.flowiseai.com/environment-variables)
| Variable | Description | Type | Default | | Variable | Description | Type | Default |
| -------------------------- | ---------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- | | -------------------------- | ---------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- |

View File

@ -1,10 +1,11 @@
PORT=3000 PORT=3000
DATABASE_PATH=/root/.flowise
APIKEY_PATH=/root/.flowise
LOG_PATH=/root/.flowise/logs
# FLOWISE_USERNAME=user # FLOWISE_USERNAME=user
# FLOWISE_PASSWORD=1234 # FLOWISE_PASSWORD=1234
# DEBUG=true # DEBUG=true
# DATABASE_PATH=/your_database_path/.flowise # LOG_LEVEL=debug (error | warn | info | verbose | debug)
# APIKEY_PATH=/your_api_key_path/.flowise
# LOG_PATH=/your_log_path/logs
# EXECUTION_MODE=child or main # EXECUTION_MODE=child or main
# TOOL_FUNCTION_BUILTIN_DEP=crypto,fs # TOOL_FUNCTION_BUILTIN_DEP=crypto,fs
# TOOL_FUNCTION_EXTERNAL_DEP=moment,lodash # TOOL_FUNCTION_EXTERNAL_DEP=moment,lodash

View File

@ -9,7 +9,7 @@ Starts Flowise from [DockerHub Image](https://hub.docker.com/repository/docker/f
3. Open [http://localhost:3000](http://localhost:3000) 3. Open [http://localhost:3000](http://localhost:3000)
4. You can bring the containers down by `docker-compose stop` 4. You can bring the containers down by `docker-compose stop`
## With Authrorization ## 🔒 Authrorization
1. Create `.env` file and specify the `PORT`, `FLOWISE_USERNAME`, and `FLOWISE_PASSWORD` (refer to `.env.example`) 1. Create `.env` file and specify the `PORT`, `FLOWISE_USERNAME`, and `FLOWISE_PASSWORD` (refer to `.env.example`)
2. Pass `FLOWISE_USERNAME` and `FLOWISE_PASSWORD` to the `docker-compose.yml` file: 2. Pass `FLOWISE_USERNAME` and `FLOWISE_PASSWORD` to the `docker-compose.yml` file:
@ -22,3 +22,27 @@ Starts Flowise from [DockerHub Image](https://hub.docker.com/repository/docker/f
3. `docker-compose up -d` 3. `docker-compose up -d`
4. Open [http://localhost:3000](http://localhost:3000) 4. Open [http://localhost:3000](http://localhost:3000)
5. You can bring the containers down by `docker-compose stop` 5. You can bring the containers down by `docker-compose stop`
## 🌱 Env Variables
If you like to persist your data (flows, logs, apikeys), set these variables in the `.env` file inside `docker` folder:
- DATABASE_PATH=/root/.flowise
- APIKEY_PATH=/root/.flowise
- LOG_PATH=/root/.flowise/logs
Flowise also support different environment variables to configure your instance. Read [more](https://docs.flowiseai.com/environment-variables)
| Variable | Description | Type | Default |
| -------------------------- | ---------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- |
| PORT | The HTTP port Flowise runs on | Number | 3000 |
| FLOWISE_USERNAME | Username to login | String |
| FLOWISE_PASSWORD | Password to login | String |
| DEBUG | Print logs onto terminal/console | Boolean |
| LOG_PATH | Location where log files are stored | String | `your-path/Flowise/packages/server` |
| LOG_LEVEL | Different log levels for loggers to be saved | Enum String: `error`, `info`, `verbose`, `debug` | `info` |
| DATABASE_PATH | Location where database is saved | String | `your-home-dir/.flowise` |
| APIKEY_PATH | Location where api keys are saved | String | `your-path/Flowise/packages/server` |
| EXECUTION_MODE | Whether predictions run in their own process or the main process | Enum String: `child`, `main` | `main` |
| TOOL_FUNCTION_BUILTIN_DEP | NodeJS built-in modules to be used for Tool Function | String | |
| TOOL_FUNCTION_EXTERNAL_DEP | External modules to be used for Tool Function | String | |

View File

@ -8,13 +8,12 @@ services:
- PORT=${PORT} - PORT=${PORT}
- FLOWISE_USERNAME=${FLOWISE_USERNAME} - FLOWISE_USERNAME=${FLOWISE_USERNAME}
- FLOWISE_PASSWORD=${FLOWISE_PASSWORD} - FLOWISE_PASSWORD=${FLOWISE_PASSWORD}
- DEBUG=${DEBUG}
- DATABASE_PATH=${DATABASE_PATH} - DATABASE_PATH=${DATABASE_PATH}
- APIKEY_PATH=${APIKEY_PATH} - APIKEY_PATH=${APIKEY_PATH}
- LOG_PATH=${LOG_PATH} - LOG_PATH=${LOG_PATH}
- LOG_LEVEL=${LOG_LEVEL}
- EXECUTION_MODE=${EXECUTION_MODE} - EXECUTION_MODE=${EXECUTION_MODE}
- DEBUG=${DEBUG}
- TOOL_FUNCTION_BUILTIN_DEP=${TOOL_FUNCTION_BUILTIN_DEP}
- TOOL_FUNCTION_EXTERNAL_DEP=${TOOL_FUNCTION_EXTERNAL_DEP}
ports: ports:
- '${PORT}:${PORT}' - '${PORT}:${PORT}'
volumes: volumes:

View File

@ -65,7 +65,18 @@ class DynamoDb_Memory implements INode {
} }
] ]
} }
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> { async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
return initalizeDynamoDB(nodeData, options)
}
async clearSessionMemory(nodeData: INodeData, options: ICommonObject): Promise<void> {
const dynamodbMemory = initalizeDynamoDB(nodeData, options)
dynamodbMemory.clear()
}
}
const initalizeDynamoDB = (nodeData: INodeData, options: ICommonObject): BufferMemory => {
const tableName = nodeData.inputs?.tableName as string const tableName = nodeData.inputs?.tableName as string
const partitionKey = nodeData.inputs?.partitionKey as string const partitionKey = nodeData.inputs?.partitionKey as string
const sessionId = nodeData.inputs?.sessionId as string const sessionId = nodeData.inputs?.sessionId as string
@ -95,7 +106,6 @@ class DynamoDb_Memory implements INode {
returnMessages: true returnMessages: true
}) })
return memory return memory
}
} }
module.exports = { nodeClass: DynamoDb_Memory } module.exports = { nodeClass: DynamoDb_Memory }

View File

@ -64,6 +64,16 @@ class MotorMemory_Memory implements INode {
} }
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> { async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
return initalizeMotorhead(nodeData, options)
}
async clearSessionMemory(nodeData: INodeData, options: ICommonObject): Promise<void> {
const motorhead = initalizeMotorhead(nodeData, options)
motorhead.clear()
}
}
const initalizeMotorhead = (nodeData: INodeData, options: ICommonObject): MotorheadMemory => {
const memoryKey = nodeData.inputs?.memoryKey as string const memoryKey = nodeData.inputs?.memoryKey as string
const baseURL = nodeData.inputs?.baseURL as string const baseURL = nodeData.inputs?.baseURL as string
const sessionId = nodeData.inputs?.sessionId as string const sessionId = nodeData.inputs?.sessionId as string
@ -92,7 +102,6 @@ class MotorMemory_Memory implements INode {
} }
return new MotorheadMemory(obj) return new MotorheadMemory(obj)
}
} }
module.exports = { nodeClass: MotorMemory_Memory } module.exports = { nodeClass: MotorMemory_Memory }

View File

@ -56,6 +56,16 @@ class RedisBackedChatMemory_Memory implements INode {
} }
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> { async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
return initalizeRedis(nodeData, options)
}
async clearSessionMemory(nodeData: INodeData, options: ICommonObject): Promise<void> {
const redis = initalizeRedis(nodeData, options)
redis.clear()
}
}
const initalizeRedis = (nodeData: INodeData, options: ICommonObject): BufferMemory => {
const baseURL = nodeData.inputs?.baseURL as string const baseURL = nodeData.inputs?.baseURL as string
const sessionId = nodeData.inputs?.sessionId as string const sessionId = nodeData.inputs?.sessionId as string
const sessionTTL = nodeData.inputs?.sessionTTL as number const sessionTTL = nodeData.inputs?.sessionTTL as number
@ -80,7 +90,6 @@ class RedisBackedChatMemory_Memory implements INode {
let redis = new BufferMemory({ memoryKey, chatHistory: redisChatMessageHistory, returnMessages: true }) let redis = new BufferMemory({ memoryKey, chatHistory: redisChatMessageHistory, returnMessages: true })
return redis return redis
}
} }
module.exports = { nodeClass: RedisBackedChatMemory_Memory } module.exports = { nodeClass: RedisBackedChatMemory_Memory }

View File

@ -104,31 +104,11 @@ class ZepMemory_Memory implements INode {
} }
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> { async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const baseURL = nodeData.inputs?.baseURL as string
const aiPrefix = nodeData.inputs?.aiPrefix as string
const humanPrefix = nodeData.inputs?.humanPrefix as string
const memoryKey = nodeData.inputs?.memoryKey as string
const inputKey = nodeData.inputs?.inputKey as string
const autoSummaryTemplate = nodeData.inputs?.autoSummaryTemplate as string const autoSummaryTemplate = nodeData.inputs?.autoSummaryTemplate as string
const autoSummary = nodeData.inputs?.autoSummary as boolean const autoSummary = nodeData.inputs?.autoSummary as boolean
const sessionId = nodeData.inputs?.sessionId as string
const apiKey = nodeData.inputs?.apiKey as string
const k = nodeData.inputs?.k as string const k = nodeData.inputs?.k as string
const chatId = options?.chatId as string let zep = initalizeZep(nodeData, options)
const obj: ZepMemoryInput = {
baseURL,
sessionId: sessionId ? sessionId : chatId,
aiPrefix,
humanPrefix,
returnMessages: true,
memoryKey,
inputKey
}
if (apiKey) obj.apiKey = apiKey
let zep = new ZepMemory(obj)
// hack to support summary // hack to support summary
let tmpFunc = zep.loadMemoryVariables let tmpFunc = zep.loadMemoryVariables
@ -153,6 +133,37 @@ class ZepMemory_Memory implements INode {
} }
return zep return zep
} }
async clearSessionMemory(nodeData: INodeData, options: ICommonObject): Promise<void> {
const zep = initalizeZep(nodeData, options)
zep.clear()
}
}
const initalizeZep = (nodeData: INodeData, options: ICommonObject) => {
const baseURL = nodeData.inputs?.baseURL as string
const aiPrefix = nodeData.inputs?.aiPrefix as string
const humanPrefix = nodeData.inputs?.humanPrefix as string
const memoryKey = nodeData.inputs?.memoryKey as string
const inputKey = nodeData.inputs?.inputKey as string
const sessionId = nodeData.inputs?.sessionId as string
const apiKey = nodeData.inputs?.apiKey as string
const chatId = options?.chatId as string
const obj: ZepMemoryInput = {
baseURL,
sessionId: sessionId ? sessionId : chatId,
aiPrefix,
humanPrefix,
returnMessages: true,
memoryKey,
inputKey
}
if (apiKey) obj.apiKey = apiKey
return new ZepMemory(obj)
} }
module.exports = { nodeClass: ZepMemory_Memory } module.exports = { nodeClass: ZepMemory_Memory }

View File

@ -96,6 +96,7 @@ export interface INode extends INodeProperties {
} }
init?(nodeData: INodeData, input: string, options?: ICommonObject): Promise<any> init?(nodeData: INodeData, input: string, options?: ICommonObject): Promise<any>
run?(nodeData: INodeData, input: string, options?: ICommonObject): Promise<string | ICommonObject> run?(nodeData: INodeData, input: string, options?: ICommonObject): Promise<string | ICommonObject>
clearSessionMemory?(nodeData: INodeData, options?: ICommonObject): Promise<void>
} }
export interface INodeData extends INodeProperties { export interface INodeData extends INodeProperties {

View File

@ -4,7 +4,7 @@ PORT=3000
# DEBUG=true # DEBUG=true
# DATABASE_PATH=/your_database_path/.flowise # DATABASE_PATH=/your_database_path/.flowise
# APIKEY_PATH=/your_api_key_path/.flowise # APIKEY_PATH=/your_api_key_path/.flowise
# LOG_PATH=/your_log_path/logs # LOG_PATH=/your_log_path/.flowise/logs
# LOG_LEVEL=debug (error | warn | info | verbose | debug) # LOG_LEVEL=debug (error | warn | info | verbose | debug)
# EXECUTION_MODE=main (child | main) # EXECUTION_MODE=main (child | main)
# TOOL_FUNCTION_BUILTIN_DEP=crypto,fs # TOOL_FUNCTION_BUILTIN_DEP=crypto,fs

View File

@ -31,7 +31,7 @@ FLOWISE_PASSWORD=1234
## 🌱 Env Variables ## 🌱 Env Variables
Flowise support different environment variables to configure your instance. You can specify the following variables in the `.env` file inside `packages/server` folder. Flowise support different environment variables to configure your instance. You can specify the following variables in the `.env` file inside `packages/server` folder. Read [more](https://docs.flowiseai.com/environment-variables)
| Variable | Description | Type | Default | | Variable | Description | Type | Default |
| -------------------------- | ---------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- | | -------------------------- | ---------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- |

View File

@ -39,7 +39,8 @@ import {
isFlowValidForStream, isFlowValidForStream,
isVectorStoreFaiss, isVectorStoreFaiss,
databaseEntities, databaseEntities,
getApiKey getApiKey,
clearSessionMemory
} from './utils' } from './utils'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import { getDataSource } from './DataSource' import { getDataSource } from './DataSource'
@ -331,6 +332,19 @@ export class App {
// Delete all chatmessages from chatflowid // Delete all chatmessages from chatflowid
this.app.delete('/api/v1/chatmessage/:id', async (req: Request, res: Response) => { this.app.delete('/api/v1/chatmessage/:id', async (req: Request, res: Response) => {
const chatflow = await this.AppDataSource.getRepository(ChatFlow).findOneBy({
id: req.params.id
})
if (!chatflow) {
res.status(404).send(`Chatflow ${req.params.id} not found`)
return
}
const flowData = chatflow.flowData
const parsedFlowData: IReactFlowObject = JSON.parse(flowData)
const nodes = parsedFlowData.nodes
let chatId = await getChatId(chatflow.id)
if (!chatId) chatId = chatflow.id
clearSessionMemory(nodes, this.nodesPool.componentNodes, chatId, req.query.sessionId as string)
const results = await this.AppDataSource.getRepository(ChatMessage).delete({ chatflowid: req.params.id }) const results = await this.AppDataSource.getRepository(ChatMessage).delete({ chatflowid: req.params.id })
return res.json(results) return res.json(results)
}) })
@ -673,7 +687,7 @@ export class App {
if (!chatflow) return res.status(404).send(`Chatflow ${chatflowid} not found`) if (!chatflow) return res.status(404).send(`Chatflow ${chatflowid} not found`)
let chatId = await getChatId(chatflow.id) let chatId = await getChatId(chatflow.id)
if (!chatId) chatId = Date.now().toString() if (!chatId) chatId = chatflowid
if (!isInternal) { if (!isInternal) {
await this.validateKey(req, res, chatflow) await this.validateKey(req, res, chatflow)

View File

@ -273,6 +273,29 @@ export const buildLangchain = async (
return flowNodes return flowNodes
} }
/**
* Clear memory
* @param {IReactFlowNode[]} reactFlowNodes
* @param {IComponentNodes} componentNodes
* @param {string} chatId
* @param {string} sessionId
*/
export const clearSessionMemory = async (
reactFlowNodes: IReactFlowNode[],
componentNodes: IComponentNodes,
chatId: string,
sessionId?: string
) => {
for (const node of reactFlowNodes) {
if (node.data.category !== 'Memory') continue
const nodeInstanceFilePath = componentNodes[node.data.name].filePath as string
const nodeModule = await import(nodeInstanceFilePath)
const newNodeInstance = new nodeModule.nodeClass()
if (sessionId && node.data.inputs) node.data.inputs.sessionId = sessionId
if (newNodeInstance.clearSessionMemory) await newNodeInstance?.clearSessionMemory(node.data, { chatId })
}
}
/** /**
* Get variable value from outputResponses.output * Get variable value from outputResponses.output
* @param {string} paramValue * @param {string} paramValue