diff --git a/package.json b/package.json index d0ac9b0d2..210a95c49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.3.5", + "version": "1.3.6", "private": true, "homepage": "https://flowiseai.com", "workspaces": [ diff --git a/packages/components/credentials/LLMonitorApi.credential.ts b/packages/components/credentials/LLMonitorApi.credential.ts new file mode 100644 index 000000000..e5ecc8aba --- /dev/null +++ b/packages/components/credentials/LLMonitorApi.credential.ts @@ -0,0 +1,32 @@ +import { INodeParams, INodeCredential } from '../src/Interface' + +class LLMonitorApi implements INodeCredential { + label: string + name: string + version: number + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'LLMonitor API' + this.name = 'llmonitorApi' + this.version = 1.0 + this.description = 'Refer to official guide to get APP ID' + this.inputs = [ + { + label: 'APP ID', + name: 'llmonitorAppId', + type: 'password', + placeholder: '' + }, + { + label: 'Endpoint', + name: 'llmonitorEndpoint', + type: 'string', + default: 'https://app.llmonitor.com' + } + ] + } +} + +module.exports = { credClass: LLMonitorApi } diff --git a/packages/components/nodes/analytic/LLMonitor/LLMonitor.ts b/packages/components/nodes/analytic/LLMonitor/LLMonitor.ts new file mode 100644 index 000000000..a1ae317c4 --- /dev/null +++ b/packages/components/nodes/analytic/LLMonitor/LLMonitor.ts @@ -0,0 +1,33 @@ +import { INode, INodeParams } from '../../../src/Interface' + +class LLMonitor_Analytic implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs?: INodeParams[] + credential: INodeParams + + constructor() { + this.label = 'LLMonitor' + this.name = 'llmonitor' + this.version = 1.0 + this.type = 'LLMonitor' + this.icon = 'llmonitor.png' + this.category = 'Analytic' + this.baseClasses = [this.type] + this.inputs = [] + this.credential = { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['llmonitorApi'] + } + } +} + +module.exports = { nodeClass: LLMonitor_Analytic } diff --git a/packages/components/nodes/analytic/LLMonitor/llmonitor.png b/packages/components/nodes/analytic/LLMonitor/llmonitor.png new file mode 100644 index 000000000..d50a70443 Binary files /dev/null and b/packages/components/nodes/analytic/LLMonitor/llmonitor.png differ diff --git a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts index 5d270fd8e..ba9cd7f81 100644 --- a/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts +++ b/packages/components/nodes/chains/SqlDatabaseChain/SqlDatabaseChain.ts @@ -43,7 +43,7 @@ class SqlDatabaseChain_Chains implements INode { constructor() { this.label = 'Sql Database Chain' this.name = 'sqlDatabaseChain' - this.version = 3.0 + this.version = 4.0 this.type = 'SqlDatabaseChain' this.icon = 'sqlchain.svg' this.category = 'Chains' @@ -89,7 +89,8 @@ class SqlDatabaseChain_Chains implements INode { label: 'Include Tables', name: 'includesTables', type: 'string', - description: 'Tables to include for queries.', + description: 'Tables to include for queries, seperated by comma. Can only use Include Tables or Ignore Tables', + placeholder: 'table1, table2', additionalParams: true, optional: true }, @@ -97,7 +98,8 @@ class SqlDatabaseChain_Chains implements INode { label: 'Ignore Tables', name: 'ignoreTables', type: 'string', - description: 'Tables to ignore for queries.', + description: 'Tables to ignore for queries, seperated by comma. Can only use Ignore Tables or Include Tables', + placeholder: 'table1, table2', additionalParams: true, optional: true }, diff --git a/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts new file mode 100644 index 000000000..cfcac863b --- /dev/null +++ b/packages/components/nodes/chatmodels/Bittensor/Bittensor.ts @@ -0,0 +1,46 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import { NIBittensorChatModel, BittensorInput } from 'langchain/experimental/chat_models/bittensor' + +class Bittensor_ChatModels implements INode { + label: string + name: string + version: number + type: string + icon: string + category: string + description: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'NIBittensorChat' + this.name = 'NIBittensorChatModel' + this.version = 1.0 + this.type = 'BittensorChat' + this.icon = 'logo.png' + this.category = 'Chat Models' + this.description = 'Wrapper around Bittensor subnet 1 large language models' + this.baseClasses = [this.type, ...getBaseClasses(NIBittensorChatModel)] + this.inputs = [ + { + label: 'System prompt', + name: 'system_prompt', + type: 'string', + additionalParams: true, + optional: true + } + ] + } + + async init(nodeData: INodeData, _: string): Promise { + const system_prompt = nodeData.inputs?.system_prompt as string + const obj: Partial = { + systemPrompt: system_prompt + } + const model = new NIBittensorChatModel(obj) + return model + } +} + +module.exports = { nodeClass: Bittensor_ChatModels } diff --git a/packages/components/nodes/chatmodels/Bittensor/logo.png b/packages/components/nodes/chatmodels/Bittensor/logo.png new file mode 100644 index 000000000..ad51774d5 Binary files /dev/null and b/packages/components/nodes/chatmodels/Bittensor/logo.png differ diff --git a/packages/components/nodes/llms/Bittensor/Bittensor.ts b/packages/components/nodes/llms/Bittensor/Bittensor.ts new file mode 100644 index 000000000..a87a7e480 --- /dev/null +++ b/packages/components/nodes/llms/Bittensor/Bittensor.ts @@ -0,0 +1,57 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' +import { NIBittensorLLM, BittensorInput } from 'langchain/experimental/llms/bittensor' + +class Bittensor_LLMs implements INode { + label: string + name: string + version: number + type: string + icon: string + category: string + description: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'NIBittensorLLM' + this.name = 'NIBittensorLLM' + this.version = 1.0 + this.type = 'Bittensor' + this.icon = 'logo.png' + this.category = 'LLMs' + this.description = 'Wrapper around Bittensor subnet 1 large language models' + this.baseClasses = [this.type, ...getBaseClasses(NIBittensorLLM)] + this.inputs = [ + { + label: 'System prompt', + name: 'system_prompt', + type: 'string', + additionalParams: true, + optional: true + }, + { + label: 'Top Responses', + name: 'topResponses', + type: 'number', + step: 1, + optional: true, + additionalParams: true + } + ] + } + + async init(nodeData: INodeData, _: string): Promise { + const system_prompt = nodeData.inputs?.system_prompt as string + const topResponses = Number(nodeData.inputs?.topResponses as number) + const obj: Partial = { + systemPrompt: system_prompt, + topResponses: topResponses + } + + const model = new NIBittensorLLM(obj) + return model + } +} + +module.exports = { nodeClass: Bittensor_LLMs } diff --git a/packages/components/nodes/llms/Bittensor/logo.png b/packages/components/nodes/llms/Bittensor/logo.png new file mode 100644 index 000000000..ad51774d5 Binary files /dev/null and b/packages/components/nodes/llms/Bittensor/logo.png differ diff --git a/packages/components/nodes/vectorstores/Chroma/core.ts b/packages/components/nodes/vectorstores/Chroma/core.ts index 8277c58ef..b1bf9cc79 100644 --- a/packages/components/nodes/vectorstores/Chroma/core.ts +++ b/packages/components/nodes/vectorstores/Chroma/core.ts @@ -30,7 +30,7 @@ export class ChromaExtended extends Chroma { if (this.chromaApiKey) { obj.fetchOptions = { headers: { - 'X-Api-Key': this.chromaApiKey + Authorization: `Bearer ${this.chromaApiKey}` } } } diff --git a/packages/components/package.json b/packages/components/package.json index 94dcbdce4..936091062 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "flowise-components", - "version": "1.3.6", + "version": "1.3.7", "description": "Flowiseai Components", "main": "dist/src/index", "types": "dist/src/index.d.ts", @@ -46,6 +46,7 @@ "langfuse-langchain": "^1.0.14-alpha.0", "langsmith": "^0.0.32", "linkifyjs": "^4.1.1", + "llmonitor": "^0.5.5", "mammoth": "^1.5.1", "moment": "^2.29.3", "mysql2": "^3.5.1", diff --git a/packages/components/src/handler.ts b/packages/components/src/handler.ts index f13719ce6..10f9a2141 100644 --- a/packages/components/src/handler.ts +++ b/packages/components/src/handler.ts @@ -4,6 +4,7 @@ import { Logger } from 'winston' import { Server } from 'socket.io' import { Client } from 'langsmith' import { LangChainTracer } from 'langchain/callbacks' +import { LLMonitorHandler } from 'langchain/callbacks/handlers/llmonitor' import { getCredentialData, getCredentialParam } from './utils' import { ICommonObject, INodeData } from './Interface' import CallbackHandler from 'langfuse-langchain' @@ -194,11 +195,11 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO for (const provider in analytic) { const providerStatus = analytic[provider].status as boolean if (providerStatus) { + const credentialId = analytic[provider].credentialId as string + const credentialData = await getCredentialData(credentialId ?? '', options) if (provider === 'langSmith') { - const credentialId = analytic[provider].credentialId as string const langSmithProject = analytic[provider].projectName as string - const credentialData = await getCredentialData(credentialId ?? '', options) const langSmithApiKey = getCredentialParam('langSmithApiKey', credentialData, nodeData) const langSmithEndpoint = getCredentialParam('langSmithEndpoint', credentialData, nodeData) @@ -214,13 +215,11 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO }) callbacks.push(tracer) } else if (provider === 'langFuse') { - const credentialId = analytic[provider].credentialId as string const flushAt = analytic[provider].flushAt as string const flushInterval = analytic[provider].flushInterval as string const requestTimeout = analytic[provider].requestTimeout as string const release = analytic[provider].release as string - const credentialData = await getCredentialData(credentialId ?? '', options) const langFuseSecretKey = getCredentialParam('langFuseSecretKey', credentialData, nodeData) const langFusePublicKey = getCredentialParam('langFusePublicKey', credentialData, nodeData) const langFuseEndpoint = getCredentialParam('langFuseEndpoint', credentialData, nodeData) @@ -237,6 +236,17 @@ export const additionalCallbacks = async (nodeData: INodeData, options: ICommonO const handler = new CallbackHandler(langFuseOptions) callbacks.push(handler) + } else if (provider === 'llmonitor') { + const llmonitorAppId = getCredentialParam('llmonitorAppId', credentialData, nodeData) + const llmonitorEndpoint = getCredentialParam('llmonitorEndpoint', credentialData, nodeData) + + const llmonitorFields: ICommonObject = { + appId: llmonitorAppId, + apiUrl: llmonitorEndpoint ?? 'https://app.llmonitor.com' + } + + const handler = new LLMonitorHandler(llmonitorFields) + callbacks.push(handler) } } } diff --git a/packages/server/marketplaces/chatflows/SQL DB Chain.json b/packages/server/marketplaces/chatflows/SQL DB Chain.json index acec5432e..646db5d42 100644 --- a/packages/server/marketplaces/chatflows/SQL DB Chain.json +++ b/packages/server/marketplaces/chatflows/SQL DB Chain.json @@ -167,7 +167,7 @@ "data": { "id": "sqlDatabaseChain_0", "label": "Sql Database Chain", - "version": 2, + "version": 4, "name": "sqlDatabaseChain", "type": "SqlDatabaseChain", "baseClasses": ["SqlDatabaseChain", "BaseChain", "Runnable"], @@ -206,6 +206,46 @@ "placeholder": "1270.0.0.1:5432/chinook", "id": "sqlDatabaseChain_0-input-url-string" }, + { + "label": "Include Tables", + "name": "includesTables", + "type": "string", + "description": "Tables to include for queries, seperated by comma. Can only use Include Tables or Ignore Tables", + "placeholder": "table1, table2", + "additionalParams": true, + "optional": true, + "id": "sqlDatabaseChain_0-input-includesTables-string" + }, + { + "label": "Ignore Tables", + "name": "ignoreTables", + "type": "string", + "description": "Tables to ignore for queries, seperated by comma. Can only use Ignore Tables or Include Tables", + "placeholder": "table1, table2", + "additionalParams": true, + "optional": true, + "id": "sqlDatabaseChain_0-input-ignoreTables-string" + }, + { + "label": "Sample table's rows info", + "name": "sampleRowsInTableInfo", + "type": "number", + "description": "Number of sample row for tables to load for info.", + "placeholder": "3", + "additionalParams": true, + "optional": true, + "id": "sqlDatabaseChain_0-input-sampleRowsInTableInfo-number" + }, + { + "label": "Top Keys", + "name": "topK", + "type": "number", + "description": "If you are querying for several rows of a table you can select the maximum number of results you want to get by using the top_k parameter (default is 10). This is useful for avoiding query results that exceed the prompt max length or consume tokens unnecessarily.", + "placeholder": "10", + "additionalParams": true, + "optional": true, + "id": "sqlDatabaseChain_0-input-topK-number" + }, { "label": "Custom Prompt", "name": "customPrompt", diff --git a/packages/server/package.json b/packages/server/package.json index 46ef7ef9c..ffd6b111f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "flowise", - "version": "1.3.5", + "version": "1.3.6", "description": "Flowiseai Server", "main": "dist/index", "types": "dist/index.d.ts", diff --git a/packages/server/src/commands/start.ts b/packages/server/src/commands/start.ts index b9ea970d5..6bf7d6993 100644 --- a/packages/server/src/commands/start.ts +++ b/packages/server/src/commands/start.ts @@ -27,6 +27,7 @@ export default class Start extends Command { LOG_LEVEL: Flags.string(), TOOL_FUNCTION_BUILTIN_DEP: Flags.string(), TOOL_FUNCTION_EXTERNAL_DEP: Flags.string(), + NUMBER_OF_PROXIES: Flags.string(), DATABASE_TYPE: Flags.string(), DATABASE_PATH: Flags.string(), DATABASE_PORT: Flags.string(), @@ -72,6 +73,7 @@ export default class Start extends Command { if (flags.PORT) process.env.PORT = flags.PORT if (flags.DEBUG) process.env.DEBUG = flags.DEBUG + if (flags.NUMBER_OF_PROXIES) process.env.NUMBER_OF_PROXIES = flags.NUMBER_OF_PROXIES // Authorization if (flags.FLOWISE_USERNAME) process.env.FLOWISE_USERNAME = flags.FLOWISE_USERNAME diff --git a/packages/server/src/utils/rateLimit.ts b/packages/server/src/utils/rateLimit.ts index b1cd1819d..68b5b693b 100644 --- a/packages/server/src/utils/rateLimit.ts +++ b/packages/server/src/utils/rateLimit.ts @@ -12,7 +12,7 @@ async function addRateLimiter(id: string, duration: number, limit: number, messa rateLimiters[id] = rateLimit({ windowMs: duration * 1000, max: limit, - handler: (req, res) => { + handler: (_, res) => { res.status(429).send(message) } }) @@ -33,15 +33,19 @@ export function getRateLimiter(req: Request, res: Response, next: NextFunction) export async function createRateLimiter(chatFlow: IChatFlow) { if (!chatFlow.apiConfig) return - const apiConfig: any = JSON.parse(chatFlow.apiConfig) + const apiConfig = JSON.parse(chatFlow.apiConfig) + const rateLimit: { limitDuration: number; limitMax: number; limitMsg: string } = apiConfig.rateLimit if (!rateLimit) return + const { limitDuration, limitMax, limitMsg } = rateLimit if (limitMax && limitDuration && limitMsg) await addRateLimiter(chatFlow.id, limitDuration, limitMax, limitMsg) } export async function initializeRateLimiter(chatFlowPool: IChatFlow[]) { - await chatFlowPool.map(async (chatFlow) => { - await createRateLimiter(chatFlow) - }) + await Promise.all( + chatFlowPool.map(async (chatFlow) => { + await createRateLimiter(chatFlow) + }) + ) } diff --git a/packages/ui/package.json b/packages/ui/package.json index 71a8dccad..f0101d2ce 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "flowise-ui", - "version": "1.3.3", + "version": "1.3.4", "license": "SEE LICENSE IN LICENSE.md", "homepage": "https://flowiseai.com", "author": { diff --git a/packages/ui/src/assets/images/llmonitor.png b/packages/ui/src/assets/images/llmonitor.png new file mode 100644 index 000000000..d50a70443 Binary files /dev/null and b/packages/ui/src/assets/images/llmonitor.png differ diff --git a/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js b/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js index 1ed68fb58..2d9a7d91f 100644 --- a/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js +++ b/packages/ui/src/ui-component/dialog/AnalyseFlowDialog.js @@ -31,6 +31,7 @@ import { Input } from 'ui-component/input/Input' import { StyledButton } from 'ui-component/button/StyledButton' import langsmithPNG from 'assets/images/langchain.png' import langfusePNG from 'assets/images/langfuse.png' +import llmonitorPNG from 'assets/images/llmonitor.png' // store import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' @@ -115,6 +116,26 @@ const analyticProviders = [ optional: true } ] + }, + { + label: 'LLMonitor', + name: 'llmonitor', + icon: llmonitorPNG, + url: 'https://llmonitor.com', + inputs: [ + { + label: 'Connect Credential', + name: 'credential', + type: 'credential', + credentialNames: ['llmonitorApi'] + }, + { + label: 'On/Off', + name: 'status', + type: 'boolean', + optional: true + } + ] } ] diff --git a/packages/ui/src/views/chatflows/Configuration.js b/packages/ui/src/views/chatflows/Configuration.js index 51b8d61c8..d569020b4 100644 --- a/packages/ui/src/views/chatflows/Configuration.js +++ b/packages/ui/src/views/chatflows/Configuration.js @@ -136,7 +136,7 @@ const Configuration = () => { Rate Limit Setup Guide to set up Rate Limit correctly in your hosting environment.' + 'Visit Rate Limit Setup Guide to set up Rate Limit correctly in your hosting environment.' } />