mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 15:00:57 +03:00
add custom tool
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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: []
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user