add custom tool

This commit is contained in:
Henry
2023-06-21 18:31:53 +01:00
parent 8c880199cd
commit 70da39629c
28 changed files with 1346 additions and 43 deletions
+25 -1
View File
@@ -1,5 +1,10 @@
import path from 'path'
import { IChildProcessMessage, IReactFlowNode, IReactFlowObject, IRunChatflowMessageValue, INodeData } from './Interface'
import { buildLangchain, constructGraphs, getEndingNode, getStartingNodes, resolveVariables } from './utils'
import { buildLangchain, constructGraphs, getEndingNode, getStartingNodes, getUserHome, resolveVariables } from './utils'
import { DataSource } from 'typeorm'
import { ChatFlow } from './entity/ChatFlow'
import { ChatMessage } from './entity/ChatMessage'
import { Tool } from './entity/Tool'
export class ChildProcess {
/**
@@ -22,6 +27,8 @@ export class ChildProcess {
await sendToParentProcess('start', '_')
const childAppDataSource = await initDB()
// Create a Queue and add our initial node in it
const { endingNodeData, chatflow, chatId, incomingInput, componentNodes } = messageValue
@@ -84,6 +91,7 @@ export class ChildProcess {
componentNodes,
incomingInput.question,
chatId,
childAppDataSource,
incomingInput?.overrideConfig
)
@@ -115,6 +123,22 @@ export class ChildProcess {
}
}
/**
* Initalize DB in child process
* @returns {DataSource}
*/
async function initDB() {
const homePath = path.join(getUserHome(), '.flowise')
const childAppDataSource = new DataSource({
type: 'sqlite',
database: path.resolve(homePath, 'database.sqlite'),
synchronize: true,
entities: [ChatFlow, ChatMessage, Tool],
migrations: []
})
return await childAppDataSource.initialize()
}
/**
* Send data back to parent process
* @param {string} key Key of message
+2 -1
View File
@@ -3,6 +3,7 @@ import path from 'path'
import { DataSource } from 'typeorm'
import { ChatFlow } from './entity/ChatFlow'
import { ChatMessage } from './entity/ChatMessage'
import { Tool } from './entity/Tool'
import { getUserHome } from './utils'
let appDataSource: DataSource
@@ -14,7 +15,7 @@ export const init = async (): Promise<void> => {
type: 'sqlite',
database: path.resolve(homePath, 'database.sqlite'),
synchronize: true,
entities: [ChatFlow, ChatMessage],
entities: [ChatFlow, ChatMessage, Tool],
migrations: []
})
}
+11
View File
@@ -24,6 +24,17 @@ export interface IChatMessage {
sourceDocuments: string
}
export interface ITool {
id: string
name: string
description: string
color: string
schema: string
func: string
updatedDate: Date
createdDate: Date
}
export interface IComponentNodes {
[key: string]: INode
}
+30
View File
@@ -0,0 +1,30 @@
/* eslint-disable */
import { Entity, Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn } from 'typeorm'
import { ITool } from '../Interface'
@Entity()
export class Tool implements ITool {
@PrimaryGeneratedColumn('uuid')
id: string
@Column()
name: string
@Column()
description: string
@Column()
color: string
@Column({ nullable: true })
schema: string
@Column({ nullable: true })
func: string
@CreateDateColumn()
createdDate: Date
@UpdateDateColumn()
updatedDate: Date
}
+85 -2
View File
@@ -35,7 +35,8 @@ import {
isSameOverrideConfig,
replaceAllAPIKeys,
isFlowValidForStream,
isVectorStoreFaiss
isVectorStoreFaiss,
databaseEntities
} from './utils'
import { cloneDeep } from 'lodash'
import { getDataSource } from './DataSource'
@@ -43,8 +44,9 @@ import { NodesPool } from './NodesPool'
import { ChatFlow } from './entity/ChatFlow'
import { ChatMessage } from './entity/ChatMessage'
import { ChatflowPool } from './ChatflowPool'
import { ICommonObject } from 'flowise-components'
import { ICommonObject, INodeOptionsValue } from 'flowise-components'
import { fork } from 'child_process'
import { Tool } from './entity/Tool'
export class App {
app: express.Application
@@ -142,6 +144,29 @@ export class App {
}
})
// load async options
this.app.post('/api/v1/node-load-method/:name', async (req: Request, res: Response) => {
const nodeData: INodeData = req.body
if (Object.prototype.hasOwnProperty.call(this.nodesPool.componentNodes, req.params.name)) {
try {
const nodeInstance = this.nodesPool.componentNodes[req.params.name]
const methodName = nodeData.loadMethod || ''
const returnOptions: INodeOptionsValue[] = await nodeInstance.loadMethods![methodName]!.call(nodeInstance, nodeData, {
appDataSource: this.AppDataSource,
databaseEntities: databaseEntities
})
return res.json(returnOptions)
} catch (error) {
return res.json([])
}
} else {
res.status(404).send(`Node ${req.params.name} not found`)
return
}
})
// ----------------------------------------
// Chatflows
// ----------------------------------------
@@ -257,6 +282,63 @@ export class App {
return res.json(results)
})
// ----------------------------------------
// Tools
// ----------------------------------------
// Get all tools
this.app.get('/api/v1/tools', async (req: Request, res: Response) => {
const tools = await this.AppDataSource.getRepository(Tool).find()
return res.json(tools)
})
// Get specific tool
this.app.get('/api/v1/tools/:id', async (req: Request, res: Response) => {
const tool = await this.AppDataSource.getRepository(Tool).findOneBy({
id: req.params.id
})
return res.json(tool)
})
// Add tool
this.app.post('/api/v1/tools', async (req: Request, res: Response) => {
const body = req.body
const newTool = new Tool()
Object.assign(newTool, body)
const tool = this.AppDataSource.getRepository(Tool).create(newTool)
const results = await this.AppDataSource.getRepository(Tool).save(tool)
return res.json(results)
})
// Update tool
this.app.put('/api/v1/tools/:id', async (req: Request, res: Response) => {
const tool = await this.AppDataSource.getRepository(Tool).findOneBy({
id: req.params.id
})
if (!tool) {
res.status(404).send(`Tool ${req.params.id} not found`)
return
}
const body = req.body
const updateTool = new Tool()
Object.assign(updateTool, body)
this.AppDataSource.getRepository(Tool).merge(tool, updateTool)
const result = await this.AppDataSource.getRepository(Tool).save(tool)
return res.json(result)
})
// Delete tool
this.app.delete('/api/v1/tools/:id', async (req: Request, res: Response) => {
const results = await this.AppDataSource.getRepository(Tool).delete({ id: req.params.id })
return res.json(results)
})
// ----------------------------------------
// Configuration
// ----------------------------------------
@@ -623,6 +705,7 @@ export class App {
this.nodesPool.componentNodes,
incomingInput.question,
chatId,
this.AppDataSource,
incomingInput?.overrideConfig
)
+12 -2
View File
@@ -15,10 +15,15 @@ import {
IOverrideConfig
} from '../Interface'
import { cloneDeep, get, omit, merge } from 'lodash'
import { ICommonObject, getInputVariables } from 'flowise-components'
import { ICommonObject, getInputVariables, IDatabaseEntity } from 'flowise-components'
import { scryptSync, randomBytes, timingSafeEqual } from 'crypto'
import { ChatFlow } from '../entity/ChatFlow'
import { ChatMessage } from '../entity/ChatMessage'
import { Tool } from '../entity/Tool'
import { DataSource } from 'typeorm'
const QUESTION_VAR_PREFIX = 'question'
export const databaseEntities: IDatabaseEntity = { ChatFlow: ChatFlow, ChatMessage: ChatMessage, Tool: Tool }
/**
* Returns the home folder path of the user if
@@ -183,6 +188,7 @@ export const buildLangchain = async (
componentNodes: IComponentNodes,
question: string,
chatId: string,
appDataSource: DataSource,
overrideConfig?: ICommonObject
) => {
const flowNodes = cloneDeep(reactFlowNodes)
@@ -215,7 +221,11 @@ export const buildLangchain = async (
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
const reactFlowNodeData: INodeData = resolveVariables(flowNodeData, flowNodes, question)
flowNodes[nodeIndex].data.instance = await newNodeInstance.init(reactFlowNodeData, question, { chatId })
flowNodes[nodeIndex].data.instance = await newNodeInstance.init(reactFlowNodeData, question, {
chatId,
appDataSource,
databaseEntities
})
} catch (e: any) {
console.error(e)
throw new Error(e)