mirror of https://github.com/FlowiseAI/Flowise.git
Compare commits
No commits in common. "main" and "flowise-components@1.8.6" have entirely different histories.
main
...
flowise-co
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "flowise",
|
"name": "flowise",
|
||||||
"version": "1.8.4",
|
"version": "1.8.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://flowiseai.com",
|
"homepage": "https://flowiseai.com",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class ChatHuggingFace_ChatModels implements INode {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.label = 'ChatHuggingFace'
|
this.label = 'ChatHuggingFace'
|
||||||
this.name = 'chatHuggingFace'
|
this.name = 'chatHuggingFace'
|
||||||
this.version = 3.0
|
this.version = 2.0
|
||||||
this.type = 'ChatHuggingFace'
|
this.type = 'ChatHuggingFace'
|
||||||
this.icon = 'HuggingFace.svg'
|
this.icon = 'HuggingFace.svg'
|
||||||
this.category = 'Chat Models'
|
this.category = 'Chat Models'
|
||||||
|
|
@ -96,16 +96,6 @@ class ChatHuggingFace_ChatModels implements INode {
|
||||||
description: 'Frequency Penalty parameter may not apply to certain model. Please check available model parameters',
|
description: 'Frequency Penalty parameter may not apply to certain model. Please check available model parameters',
|
||||||
optional: true,
|
optional: true,
|
||||||
additionalParams: true
|
additionalParams: true
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Stop Sequence',
|
|
||||||
name: 'stop',
|
|
||||||
type: 'string',
|
|
||||||
rows: 4,
|
|
||||||
placeholder: 'AI assistant:',
|
|
||||||
description: 'Sets the stop sequences to use. Use comma to seperate different sequences.',
|
|
||||||
optional: true,
|
|
||||||
additionalParams: true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +109,6 @@ class ChatHuggingFace_ChatModels implements INode {
|
||||||
const frequencyPenalty = nodeData.inputs?.frequencyPenalty as string
|
const frequencyPenalty = nodeData.inputs?.frequencyPenalty as string
|
||||||
const endpoint = nodeData.inputs?.endpoint as string
|
const endpoint = nodeData.inputs?.endpoint as string
|
||||||
const cache = nodeData.inputs?.cache as BaseCache
|
const cache = nodeData.inputs?.cache as BaseCache
|
||||||
const stop = nodeData.inputs?.stop as string
|
|
||||||
|
|
||||||
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
|
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
|
||||||
const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData)
|
const huggingFaceApiKey = getCredentialParam('huggingFaceApiKey', credentialData, nodeData)
|
||||||
|
|
@ -134,11 +123,7 @@ class ChatHuggingFace_ChatModels implements INode {
|
||||||
if (topP) obj.topP = parseFloat(topP)
|
if (topP) obj.topP = parseFloat(topP)
|
||||||
if (hfTopK) obj.topK = parseFloat(hfTopK)
|
if (hfTopK) obj.topK = parseFloat(hfTopK)
|
||||||
if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty)
|
if (frequencyPenalty) obj.frequencyPenalty = parseFloat(frequencyPenalty)
|
||||||
if (endpoint) obj.endpointUrl = endpoint
|
if (endpoint) obj.endpoint = endpoint
|
||||||
if (stop) {
|
|
||||||
const stopSequences = stop.split(',')
|
|
||||||
obj.stopSequences = stopSequences
|
|
||||||
}
|
|
||||||
|
|
||||||
const huggingFace = new HuggingFaceInference(obj)
|
const huggingFace = new HuggingFaceInference(obj)
|
||||||
if (cache) huggingFace.cache = cache
|
if (cache) huggingFace.cache = cache
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,32 @@
|
||||||
import { LLM, BaseLLMParams } from '@langchain/core/language_models/llms'
|
import { LLM, BaseLLMParams } from '@langchain/core/language_models/llms'
|
||||||
import { getEnvironmentVariable } from '../../../src/utils'
|
import { getEnvironmentVariable } from '../../../src/utils'
|
||||||
import { GenerationChunk } from '@langchain/core/outputs'
|
|
||||||
import { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager'
|
|
||||||
|
|
||||||
export interface HFInput {
|
export interface HFInput {
|
||||||
|
/** Model to use */
|
||||||
model: string
|
model: string
|
||||||
|
|
||||||
|
/** Sampling temperature to use */
|
||||||
temperature?: number
|
temperature?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of tokens to generate in the completion.
|
||||||
|
*/
|
||||||
maxTokens?: number
|
maxTokens?: number
|
||||||
stopSequences?: string[]
|
|
||||||
|
/** Total probability mass of tokens to consider at each step */
|
||||||
topP?: number
|
topP?: number
|
||||||
|
|
||||||
|
/** Integer to define the top tokens considered within the sample operation to create new text. */
|
||||||
topK?: number
|
topK?: number
|
||||||
|
|
||||||
|
/** Penalizes repeated tokens according to frequency */
|
||||||
frequencyPenalty?: number
|
frequencyPenalty?: number
|
||||||
|
|
||||||
|
/** API key to use. */
|
||||||
apiKey?: string
|
apiKey?: string
|
||||||
endpointUrl?: string
|
|
||||||
includeCredentials?: string | boolean
|
/** Private endpoint to use. */
|
||||||
|
endpoint?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HuggingFaceInference extends LLM implements HFInput {
|
export class HuggingFaceInference extends LLM implements HFInput {
|
||||||
|
|
@ -27,8 +40,6 @@ export class HuggingFaceInference extends LLM implements HFInput {
|
||||||
|
|
||||||
temperature: number | undefined = undefined
|
temperature: number | undefined = undefined
|
||||||
|
|
||||||
stopSequences: string[] | undefined = undefined
|
|
||||||
|
|
||||||
maxTokens: number | undefined = undefined
|
maxTokens: number | undefined = undefined
|
||||||
|
|
||||||
topP: number | undefined = undefined
|
topP: number | undefined = undefined
|
||||||
|
|
@ -39,9 +50,7 @@ export class HuggingFaceInference extends LLM implements HFInput {
|
||||||
|
|
||||||
apiKey: string | undefined = undefined
|
apiKey: string | undefined = undefined
|
||||||
|
|
||||||
endpointUrl: string | undefined = undefined
|
endpoint: string | undefined = undefined
|
||||||
|
|
||||||
includeCredentials: string | boolean | undefined = undefined
|
|
||||||
|
|
||||||
constructor(fields?: Partial<HFInput> & BaseLLMParams) {
|
constructor(fields?: Partial<HFInput> & BaseLLMParams) {
|
||||||
super(fields ?? {})
|
super(fields ?? {})
|
||||||
|
|
@ -49,13 +58,11 @@ export class HuggingFaceInference extends LLM implements HFInput {
|
||||||
this.model = fields?.model ?? this.model
|
this.model = fields?.model ?? this.model
|
||||||
this.temperature = fields?.temperature ?? this.temperature
|
this.temperature = fields?.temperature ?? this.temperature
|
||||||
this.maxTokens = fields?.maxTokens ?? this.maxTokens
|
this.maxTokens = fields?.maxTokens ?? this.maxTokens
|
||||||
this.stopSequences = fields?.stopSequences ?? this.stopSequences
|
|
||||||
this.topP = fields?.topP ?? this.topP
|
this.topP = fields?.topP ?? this.topP
|
||||||
this.topK = fields?.topK ?? this.topK
|
this.topK = fields?.topK ?? this.topK
|
||||||
this.frequencyPenalty = fields?.frequencyPenalty ?? this.frequencyPenalty
|
this.frequencyPenalty = fields?.frequencyPenalty ?? this.frequencyPenalty
|
||||||
|
this.endpoint = fields?.endpoint ?? ''
|
||||||
this.apiKey = fields?.apiKey ?? getEnvironmentVariable('HUGGINGFACEHUB_API_KEY')
|
this.apiKey = fields?.apiKey ?? getEnvironmentVariable('HUGGINGFACEHUB_API_KEY')
|
||||||
this.endpointUrl = fields?.endpointUrl
|
|
||||||
this.includeCredentials = fields?.includeCredentials
|
|
||||||
if (!this.apiKey) {
|
if (!this.apiKey) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Please set an API key for HuggingFace Hub in the environment variable HUGGINGFACEHUB_API_KEY or in the apiKey field of the HuggingFaceInference constructor.'
|
'Please set an API key for HuggingFace Hub in the environment variable HUGGINGFACEHUB_API_KEY or in the apiKey field of the HuggingFaceInference constructor.'
|
||||||
|
|
@ -67,65 +74,31 @@ export class HuggingFaceInference extends LLM implements HFInput {
|
||||||
return 'hf'
|
return 'hf'
|
||||||
}
|
}
|
||||||
|
|
||||||
invocationParams(options?: this['ParsedCallOptions']) {
|
/** @ignore */
|
||||||
return {
|
async _call(prompt: string, options: this['ParsedCallOptions']): Promise<string> {
|
||||||
model: this.model,
|
const { HfInference } = await HuggingFaceInference.imports()
|
||||||
|
const hf = new HfInference(this.apiKey)
|
||||||
|
const obj: any = {
|
||||||
parameters: {
|
parameters: {
|
||||||
// make it behave similar to openai, returning only the generated text
|
// make it behave similar to openai, returning only the generated text
|
||||||
return_full_text: false,
|
return_full_text: false,
|
||||||
temperature: this.temperature,
|
temperature: this.temperature,
|
||||||
max_new_tokens: this.maxTokens,
|
max_new_tokens: this.maxTokens,
|
||||||
stop: options?.stop ?? this.stopSequences,
|
|
||||||
top_p: this.topP,
|
top_p: this.topP,
|
||||||
top_k: this.topK,
|
top_k: this.topK,
|
||||||
repetition_penalty: this.frequencyPenalty
|
repetition_penalty: this.frequencyPenalty
|
||||||
}
|
},
|
||||||
|
inputs: prompt
|
||||||
}
|
}
|
||||||
}
|
if (this.endpoint) {
|
||||||
|
hf.endpoint(this.endpoint)
|
||||||
async *_streamResponseChunks(
|
} else {
|
||||||
prompt: string,
|
obj.model = this.model
|
||||||
options: this['ParsedCallOptions'],
|
|
||||||
runManager?: CallbackManagerForLLMRun
|
|
||||||
): AsyncGenerator<GenerationChunk> {
|
|
||||||
const hfi = await this._prepareHFInference()
|
|
||||||
const stream = await this.caller.call(async () =>
|
|
||||||
hfi.textGenerationStream({
|
|
||||||
...this.invocationParams(options),
|
|
||||||
inputs: prompt
|
|
||||||
})
|
|
||||||
)
|
|
||||||
for await (const chunk of stream) {
|
|
||||||
const token = chunk.token.text
|
|
||||||
yield new GenerationChunk({ text: token, generationInfo: chunk })
|
|
||||||
await runManager?.handleLLMNewToken(token ?? '')
|
|
||||||
|
|
||||||
// stream is done
|
|
||||||
if (chunk.generated_text)
|
|
||||||
yield new GenerationChunk({
|
|
||||||
text: '',
|
|
||||||
generationInfo: { finished: true }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
const res = await this.caller.callWithOptions({ signal: options.signal }, hf.textGeneration.bind(hf), obj)
|
||||||
|
|
||||||
/** @ignore */
|
|
||||||
async _call(prompt: string, options: this['ParsedCallOptions']): Promise<string> {
|
|
||||||
const hfi = await this._prepareHFInference()
|
|
||||||
const args = { ...this.invocationParams(options), inputs: prompt }
|
|
||||||
const res = await this.caller.callWithOptions({ signal: options.signal }, hfi.textGeneration.bind(hfi), args)
|
|
||||||
return res.generated_text
|
return res.generated_text
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @ignore */
|
|
||||||
private async _prepareHFInference() {
|
|
||||||
const { HfInference } = await HuggingFaceInference.imports()
|
|
||||||
const hfi = new HfInference(this.apiKey, {
|
|
||||||
includeCredentials: this.includeCredentials
|
|
||||||
})
|
|
||||||
return this.endpointUrl ? hfi.endpoint(this.endpointUrl) : hfi
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @ignore */
|
/** @ignore */
|
||||||
static async imports(): Promise<{
|
static async imports(): Promise<{
|
||||||
HfInference: typeof import('@huggingface/inference').HfInference
|
HfInference: typeof import('@huggingface/inference').HfInference
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "flowise-components",
|
"name": "flowise-components",
|
||||||
"version": "1.8.6",
|
"version": "1.8.5",
|
||||||
"description": "Flowiseai Components",
|
"description": "Flowiseai Components",
|
||||||
"main": "dist/src/index",
|
"main": "dist/src/index",
|
||||||
"types": "dist/src/index.d.ts",
|
"types": "dist/src/index.d.ts",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "flowise",
|
"name": "flowise",
|
||||||
"version": "1.8.4",
|
"version": "1.8.3",
|
||||||
"description": "Flowiseai Server",
|
"description": "Flowiseai Server",
|
||||||
"main": "dist/index",
|
"main": "dist/index",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { NextFunction, Request, Response } from 'express'
|
import { Request, Response, NextFunction } from 'express'
|
||||||
import { StatusCodes } from 'http-status-codes'
|
|
||||||
import { ChatFlow } from '../../database/entities/ChatFlow'
|
|
||||||
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
|
||||||
import { ChatflowType } from '../../Interface'
|
|
||||||
import chatflowsService from '../../services/chatflows'
|
import chatflowsService from '../../services/chatflows'
|
||||||
import { getApiKey } from '../../utils/apiKey'
|
import { ChatFlow } from '../../database/entities/ChatFlow'
|
||||||
import { createRateLimiter } from '../../utils/rateLimit'
|
import { createRateLimiter } from '../../utils/rateLimit'
|
||||||
|
import { getApiKey } from '../../utils/apiKey'
|
||||||
|
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
||||||
|
import { StatusCodes } from 'http-status-codes'
|
||||||
|
import { ChatflowType } from '../../Interface'
|
||||||
|
|
||||||
const checkIfChatflowIsValidForStreaming = async (req: Request, res: Response, next: NextFunction) => {
|
const checkIfChatflowIsValidForStreaming = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -105,16 +105,6 @@ const saveChatflow = async (req: Request, res: Response, next: NextFunction) =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const importChatflows = async (req: Request, res: Response, next: NextFunction) => {
|
|
||||||
try {
|
|
||||||
const chatflows: Partial<ChatFlow>[] = req.body.Chatflows
|
|
||||||
const apiResponse = await chatflowsService.importChatflows(chatflows)
|
|
||||||
return res.json(apiResponse)
|
|
||||||
} catch (error) {
|
|
||||||
next(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateChatflow = async (req: Request, res: Response, next: NextFunction) => {
|
const updateChatflow = async (req: Request, res: Response, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
if (typeof req.params === 'undefined' || !req.params.id) {
|
if (typeof req.params === 'undefined' || !req.params.id) {
|
||||||
|
|
@ -177,7 +167,6 @@ export default {
|
||||||
getChatflowByApiKey,
|
getChatflowByApiKey,
|
||||||
getChatflowById,
|
getChatflowById,
|
||||||
saveChatflow,
|
saveChatflow,
|
||||||
importChatflows,
|
|
||||||
updateChatflow,
|
updateChatflow,
|
||||||
getSinglePublicChatflow,
|
getSinglePublicChatflow,
|
||||||
getSinglePublicChatbotConfig
|
getSinglePublicChatbotConfig
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ const router = express.Router()
|
||||||
|
|
||||||
// CREATE
|
// CREATE
|
||||||
router.post('/', chatflowsController.saveChatflow)
|
router.post('/', chatflowsController.saveChatflow)
|
||||||
router.post('/importchatflows', chatflowsController.importChatflows)
|
|
||||||
|
|
||||||
// READ
|
// READ
|
||||||
router.get('/', chatflowsController.getAllChatflows)
|
router.get('/', chatflowsController.getAllChatflows)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import apikeyRouter from './apikey'
|
import apikeyRouter from './apikey'
|
||||||
import assistantsRouter from './assistants'
|
import assistantsRouter from './assistants'
|
||||||
import chatMessageRouter from './chat-messages'
|
|
||||||
import chatflowsRouter from './chatflows'
|
import chatflowsRouter from './chatflows'
|
||||||
import chatflowsStreamingRouter from './chatflows-streaming'
|
import chatflowsStreamingRouter from './chatflows-streaming'
|
||||||
import chatflowsUploadsRouter from './chatflows-uploads'
|
import chatflowsUploadsRouter from './chatflows-uploads'
|
||||||
|
import chatMessageRouter from './chat-messages'
|
||||||
import componentsCredentialsRouter from './components-credentials'
|
import componentsCredentialsRouter from './components-credentials'
|
||||||
import componentsCredentialsIconRouter from './components-credentials-icon'
|
import componentsCredentialsIconRouter from './components-credentials-icon'
|
||||||
import credentialsRouter from './credentials'
|
import credentialsRouter from './credentials'
|
||||||
|
|
@ -12,10 +12,10 @@ import documentStoreRouter from './documentstore'
|
||||||
import feedbackRouter from './feedback'
|
import feedbackRouter from './feedback'
|
||||||
import fetchLinksRouter from './fetch-links'
|
import fetchLinksRouter from './fetch-links'
|
||||||
import flowConfigRouter from './flow-config'
|
import flowConfigRouter from './flow-config'
|
||||||
import getUploadFileRouter from './get-upload-file'
|
|
||||||
import getUploadPathRouter from './get-upload-path'
|
|
||||||
import internalChatmessagesRouter from './internal-chat-messages'
|
import internalChatmessagesRouter from './internal-chat-messages'
|
||||||
import internalPredictionRouter from './internal-predictions'
|
import internalPredictionRouter from './internal-predictions'
|
||||||
|
import getUploadFileRouter from './get-upload-file'
|
||||||
|
import getUploadPathRouter from './get-upload-path'
|
||||||
import leadsRouter from './leads'
|
import leadsRouter from './leads'
|
||||||
import loadPromptRouter from './load-prompts'
|
import loadPromptRouter from './load-prompts'
|
||||||
import marketplacesRouter from './marketplaces'
|
import marketplacesRouter from './marketplaces'
|
||||||
|
|
@ -27,18 +27,18 @@ import nodesRouter from './nodes'
|
||||||
import openaiAssistantsRouter from './openai-assistants'
|
import openaiAssistantsRouter from './openai-assistants'
|
||||||
import openaiAssistantsFileRouter from './openai-assistants-files'
|
import openaiAssistantsFileRouter from './openai-assistants-files'
|
||||||
import openaiAssistantsVectorStoreRouter from './openai-assistants-vector-store'
|
import openaiAssistantsVectorStoreRouter from './openai-assistants-vector-store'
|
||||||
import pingRouter from './ping'
|
|
||||||
import predictionRouter from './predictions'
|
import predictionRouter from './predictions'
|
||||||
import promptListsRouter from './prompts-lists'
|
import promptListsRouter from './prompts-lists'
|
||||||
import publicChatbotRouter from './public-chatbots'
|
import publicChatbotRouter from './public-chatbots'
|
||||||
import publicChatflowsRouter from './public-chatflows'
|
import publicChatflowsRouter from './public-chatflows'
|
||||||
import statsRouter from './stats'
|
import statsRouter from './stats'
|
||||||
import toolsRouter from './tools'
|
import toolsRouter from './tools'
|
||||||
import upsertHistoryRouter from './upsert-history'
|
|
||||||
import variablesRouter from './variables'
|
import variablesRouter from './variables'
|
||||||
import vectorRouter from './vectors'
|
import vectorRouter from './vectors'
|
||||||
import verifyRouter from './verify'
|
import verifyRouter from './verify'
|
||||||
import versionRouter from './versions'
|
import versionRouter from './versions'
|
||||||
|
import upsertHistoryRouter from './upsert-history'
|
||||||
|
import pingRouter from './ping'
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
import { removeFolderFromStorage } from 'flowise-components'
|
|
||||||
import { StatusCodes } from 'http-status-codes'
|
import { StatusCodes } from 'http-status-codes'
|
||||||
import { ChatflowType, IChatFlow, IReactFlowObject } from '../../Interface'
|
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
||||||
|
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
||||||
|
import { ChatflowType, IChatFlow } from '../../Interface'
|
||||||
import { ChatFlow } from '../../database/entities/ChatFlow'
|
import { ChatFlow } from '../../database/entities/ChatFlow'
|
||||||
|
import { getAppVersion, getTelemetryFlowObj, isFlowValidForStream, constructGraphs, getEndingNodes } from '../../utils'
|
||||||
|
import logger from '../../utils/logger'
|
||||||
|
import { removeFolderFromStorage } from 'flowise-components'
|
||||||
|
import { IReactFlowObject } from '../../Interface'
|
||||||
|
import { utilGetUploadsConfig } from '../../utils/getUploadsConfig'
|
||||||
import { ChatMessage } from '../../database/entities/ChatMessage'
|
import { ChatMessage } from '../../database/entities/ChatMessage'
|
||||||
import { ChatMessageFeedback } from '../../database/entities/ChatMessageFeedback'
|
import { ChatMessageFeedback } from '../../database/entities/ChatMessageFeedback'
|
||||||
import { UpsertHistory } from '../../database/entities/UpsertHistory'
|
import { UpsertHistory } from '../../database/entities/UpsertHistory'
|
||||||
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
import { containsBase64File, updateFlowDataWithFilePaths } from '../../utils/fileRepository'
|
||||||
import { getErrorMessage } from '../../errors/utils'
|
import { getErrorMessage } from '../../errors/utils'
|
||||||
import documentStoreService from '../../services/documentstore'
|
import documentStoreService from '../../services/documentstore'
|
||||||
import { constructGraphs, getAppVersion, getEndingNodes, getTelemetryFlowObj, isFlowValidForStream } from '../../utils'
|
|
||||||
import { containsBase64File, updateFlowDataWithFilePaths } from '../../utils/fileRepository'
|
|
||||||
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
|
||||||
import { utilGetUploadsConfig } from '../../utils/getUploadsConfig'
|
|
||||||
import logger from '../../utils/logger'
|
|
||||||
|
|
||||||
// Check if chatflow valid for streaming
|
// Check if chatflow valid for streaming
|
||||||
const checkIfChatflowIsValidForStreaming = async (chatflowId: string): Promise<any> => {
|
const checkIfChatflowIsValidForStreaming = async (chatflowId: string): Promise<any> => {
|
||||||
|
|
@ -197,60 +198,6 @@ const saveChatflow = async (newChatFlow: ChatFlow): Promise<any> => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const importChatflows = async (newChatflows: Partial<ChatFlow>[]): Promise<any> => {
|
|
||||||
try {
|
|
||||||
const appServer = getRunningExpressApp()
|
|
||||||
|
|
||||||
// step 1 - check whether file chatflows array is zero
|
|
||||||
if (newChatflows.length == 0) throw new Error('No chatflows in this file.')
|
|
||||||
|
|
||||||
// step 2 - check whether ids are duplicate in database
|
|
||||||
let ids = '('
|
|
||||||
let count: number = 0
|
|
||||||
const lastCount = newChatflows.length - 1
|
|
||||||
newChatflows.forEach((newChatflow) => {
|
|
||||||
ids += `'${newChatflow.id}'`
|
|
||||||
if (lastCount != count) ids += ','
|
|
||||||
if (lastCount == count) ids += ')'
|
|
||||||
count += 1
|
|
||||||
})
|
|
||||||
|
|
||||||
const selectResponse = await appServer.AppDataSource.getRepository(ChatFlow)
|
|
||||||
.createQueryBuilder('cf')
|
|
||||||
.select('cf.id')
|
|
||||||
.where(`cf.id IN ${ids}`)
|
|
||||||
.getMany()
|
|
||||||
const foundIds = selectResponse.map((response) => {
|
|
||||||
return response.id
|
|
||||||
})
|
|
||||||
|
|
||||||
// step 3 - remove ids that are only duplicate
|
|
||||||
const prepChatflows: Partial<ChatFlow>[] = newChatflows.map((newChatflow) => {
|
|
||||||
let id: string = ''
|
|
||||||
if (newChatflow.id) id = newChatflow.id
|
|
||||||
let flowData: string = ''
|
|
||||||
if (newChatflow.flowData) flowData = newChatflow.flowData
|
|
||||||
if (foundIds.includes(id)) {
|
|
||||||
newChatflow.id = undefined
|
|
||||||
newChatflow.name += ' with new id'
|
|
||||||
}
|
|
||||||
newChatflow.type = 'CHATFLOW'
|
|
||||||
newChatflow.flowData = JSON.stringify(JSON.parse(flowData))
|
|
||||||
return newChatflow
|
|
||||||
})
|
|
||||||
|
|
||||||
// step 4 - transactional insert array of entities
|
|
||||||
const insertResponse = await appServer.AppDataSource.getRepository(ChatFlow).insert(prepChatflows)
|
|
||||||
|
|
||||||
return insertResponse
|
|
||||||
} catch (error) {
|
|
||||||
throw new InternalFlowiseError(
|
|
||||||
StatusCodes.INTERNAL_SERVER_ERROR,
|
|
||||||
`Error: chatflowsService.saveChatflows - ${getErrorMessage(error)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateChatflow = async (chatflow: ChatFlow, updateChatFlow: ChatFlow): Promise<any> => {
|
const updateChatflow = async (chatflow: ChatFlow, updateChatFlow: ChatFlow): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
const appServer = getRunningExpressApp()
|
const appServer = getRunningExpressApp()
|
||||||
|
|
@ -352,7 +299,6 @@ export default {
|
||||||
getChatflowByApiKey,
|
getChatflowByApiKey,
|
||||||
getChatflowById,
|
getChatflowById,
|
||||||
saveChatflow,
|
saveChatflow,
|
||||||
importChatflows,
|
|
||||||
updateChatflow,
|
updateChatflow,
|
||||||
getSinglePublicChatflow,
|
getSinglePublicChatflow,
|
||||||
getSinglePublicChatbotConfig
|
getSinglePublicChatbotConfig
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "flowise-ui",
|
"name": "flowise-ui",
|
||||||
"version": "1.8.4",
|
"version": "1.8.3",
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"homepage": "https://flowiseai.com",
|
"homepage": "https://flowiseai.com",
|
||||||
"author": {
|
"author": {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,6 @@ const getSpecificChatflowFromPublicEndpoint = (id) => client.get(`/public-chatfl
|
||||||
|
|
||||||
const createNewChatflow = (body) => client.post(`/chatflows`, body)
|
const createNewChatflow = (body) => client.post(`/chatflows`, body)
|
||||||
|
|
||||||
const importChatflows = (body) => client.post(`/chatflows/importchatflows`, body)
|
|
||||||
|
|
||||||
const updateChatflow = (id, body) => client.put(`/chatflows/${id}`, body)
|
const updateChatflow = (id, body) => client.put(`/chatflows/${id}`, body)
|
||||||
|
|
||||||
const deleteChatflow = (id) => client.delete(`/chatflows/${id}`)
|
const deleteChatflow = (id) => client.delete(`/chatflows/${id}`)
|
||||||
|
|
@ -26,7 +24,6 @@ export default {
|
||||||
getSpecificChatflow,
|
getSpecificChatflow,
|
||||||
getSpecificChatflowFromPublicEndpoint,
|
getSpecificChatflowFromPublicEndpoint,
|
||||||
createNewChatflow,
|
createNewChatflow,
|
||||||
importChatflows,
|
|
||||||
updateChatflow,
|
updateChatflow,
|
||||||
deleteChatflow,
|
deleteChatflow,
|
||||||
getIsChatflowStreaming,
|
getIsChatflowStreaming,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
import { closeSnackbar as closeSnackbarAction, enqueueSnackbar as enqueueSnackbarAction, MENU_OPEN, REMOVE_DIRTY } from '@/store/actions'
|
import { useState, useRef, useEffect } from 'react'
|
||||||
import { sanitizeChatflows } from '@/utils/genericHelper'
|
|
||||||
import useNotifier from '@/utils/useNotifier'
|
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useSelector } from 'react-redux'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
|
||||||
// material-ui
|
// material-ui
|
||||||
|
import { useTheme } from '@mui/material/styles'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
|
||||||
Box,
|
Box,
|
||||||
Button,
|
|
||||||
ButtonBase,
|
ButtonBase,
|
||||||
|
Avatar,
|
||||||
ClickAwayListener,
|
ClickAwayListener,
|
||||||
Divider,
|
Divider,
|
||||||
List,
|
List,
|
||||||
|
|
@ -20,27 +18,20 @@ import {
|
||||||
Popper,
|
Popper,
|
||||||
Typography
|
Typography
|
||||||
} from '@mui/material'
|
} from '@mui/material'
|
||||||
import { useTheme } from '@mui/material/styles'
|
|
||||||
|
|
||||||
// third-party
|
// third-party
|
||||||
import PerfectScrollbar from 'react-perfect-scrollbar'
|
import PerfectScrollbar from 'react-perfect-scrollbar'
|
||||||
|
|
||||||
// project imports
|
// project imports
|
||||||
import MainCard from '@/ui-component/cards/MainCard'
|
import MainCard from '@/ui-component/cards/MainCard'
|
||||||
import AboutDialog from '@/ui-component/dialog/AboutDialog'
|
|
||||||
import Transitions from '@/ui-component/extended/Transitions'
|
import Transitions from '@/ui-component/extended/Transitions'
|
||||||
|
import AboutDialog from '@/ui-component/dialog/AboutDialog'
|
||||||
|
|
||||||
// assets
|
// assets
|
||||||
import { IconFileExport, IconFileUpload, IconInfoCircle, IconLogout, IconSettings, IconX } from '@tabler/icons-react'
|
import { IconLogout, IconSettings, IconInfoCircle } from '@tabler/icons-react'
|
||||||
|
|
||||||
import './index.css'
|
import './index.css'
|
||||||
|
|
||||||
//API
|
|
||||||
import chatFlowsApi from '@/api/chatflows'
|
|
||||||
|
|
||||||
// Hooks
|
|
||||||
import useApi from '@/hooks/useApi'
|
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
|
|
||||||
// ==============================|| PROFILE MENU ||============================== //
|
// ==============================|| PROFILE MENU ||============================== //
|
||||||
|
|
||||||
const ProfileSection = ({ username, handleLogout }) => {
|
const ProfileSection = ({ username, handleLogout }) => {
|
||||||
|
|
@ -52,17 +43,6 @@ const ProfileSection = ({ username, handleLogout }) => {
|
||||||
const [aboutDialogOpen, setAboutDialogOpen] = useState(false)
|
const [aboutDialogOpen, setAboutDialogOpen] = useState(false)
|
||||||
|
|
||||||
const anchorRef = useRef(null)
|
const anchorRef = useRef(null)
|
||||||
const inputRef = useRef()
|
|
||||||
|
|
||||||
const navigate = useNavigate()
|
|
||||||
const location = useLocation()
|
|
||||||
|
|
||||||
// ==============================|| Snackbar ||============================== //
|
|
||||||
|
|
||||||
useNotifier()
|
|
||||||
const dispatch = useDispatch()
|
|
||||||
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
|
|
||||||
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
|
|
||||||
|
|
||||||
const handleClose = (event) => {
|
const handleClose = (event) => {
|
||||||
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
if (anchorRef.current && anchorRef.current.contains(event.target)) {
|
||||||
|
|
@ -75,106 +55,6 @@ const ProfileSection = ({ username, handleLogout }) => {
|
||||||
setOpen((prevOpen) => !prevOpen)
|
setOpen((prevOpen) => !prevOpen)
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorFailed = (message) => {
|
|
||||||
enqueueSnackbar({
|
|
||||||
message: message,
|
|
||||||
options: {
|
|
||||||
key: new Date().getTime() + Math.random(),
|
|
||||||
variant: 'error',
|
|
||||||
persist: true,
|
|
||||||
action: (key) => (
|
|
||||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
|
||||||
<IconX />
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const importChatflowsApi = useApi(chatFlowsApi.importChatflows)
|
|
||||||
const fileChange = (e) => {
|
|
||||||
if (!e.target.files) return
|
|
||||||
|
|
||||||
const file = e.target.files[0]
|
|
||||||
|
|
||||||
const reader = new FileReader()
|
|
||||||
reader.onload = (evt) => {
|
|
||||||
if (!evt?.target?.result) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const chatflows = JSON.parse(evt.target.result)
|
|
||||||
importChatflowsApi.request(chatflows)
|
|
||||||
}
|
|
||||||
reader.readAsText(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
const importChatflowsSuccess = () => {
|
|
||||||
dispatch({ type: REMOVE_DIRTY })
|
|
||||||
enqueueSnackbar({
|
|
||||||
message: `Import chatflows successful`,
|
|
||||||
options: {
|
|
||||||
key: new Date().getTime() + Math.random(),
|
|
||||||
variant: 'success',
|
|
||||||
action: (key) => (
|
|
||||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
|
||||||
<IconX />
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
useEffect(() => {
|
|
||||||
if (importChatflowsApi.error) errorFailed(`Failed to import chatflows: ${importChatflowsApi.error.response.data.message}`)
|
|
||||||
if (importChatflowsApi.data) {
|
|
||||||
importChatflowsSuccess()
|
|
||||||
// if current location is /chatflows, refresh the page
|
|
||||||
if (location.pathname === '/chatflows') navigate(0)
|
|
||||||
else {
|
|
||||||
// if not redirect to /chatflows
|
|
||||||
dispatch({ type: MENU_OPEN, id: 'chatflows' })
|
|
||||||
navigate('/chatflows')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [importChatflowsApi.error, importChatflowsApi.data])
|
|
||||||
const importAllChatflows = () => {
|
|
||||||
inputRef.current.click()
|
|
||||||
}
|
|
||||||
const getAllChatflowsApi = useApi(chatFlowsApi.getAllChatflows)
|
|
||||||
|
|
||||||
const exportChatflowsSuccess = () => {
|
|
||||||
dispatch({ type: REMOVE_DIRTY })
|
|
||||||
enqueueSnackbar({
|
|
||||||
message: `Export chatflows successful`,
|
|
||||||
options: {
|
|
||||||
key: new Date().getTime() + Math.random(),
|
|
||||||
variant: 'success',
|
|
||||||
action: (key) => (
|
|
||||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
|
||||||
<IconX />
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (getAllChatflowsApi.error) errorFailed(`Failed to export Chatflows: ${getAllChatflowsApi.error.response.data.message}`)
|
|
||||||
if (getAllChatflowsApi.data) {
|
|
||||||
const sanitizedChatflows = sanitizeChatflows(getAllChatflowsApi.data)
|
|
||||||
const dataStr = JSON.stringify({ Chatflows: sanitizedChatflows }, null, 2)
|
|
||||||
const dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr)
|
|
||||||
|
|
||||||
const exportFileDefaultName = 'AllChatflows.json'
|
|
||||||
|
|
||||||
const linkElement = document.createElement('a')
|
|
||||||
linkElement.setAttribute('href', dataUri)
|
|
||||||
linkElement.setAttribute('download', exportFileDefaultName)
|
|
||||||
linkElement.click()
|
|
||||||
exportChatflowsSuccess()
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [getAllChatflowsApi.error, getAllChatflowsApi.data])
|
|
||||||
|
|
||||||
const prevOpen = useRef(open)
|
const prevOpen = useRef(open)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (prevOpen.current === true && open === false) {
|
if (prevOpen.current === true && open === false) {
|
||||||
|
|
@ -255,29 +135,6 @@ const ProfileSection = ({ username, handleLogout }) => {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemButton
|
|
||||||
sx={{ borderRadius: `${customization.borderRadius}px` }}
|
|
||||||
onClick={() => {
|
|
||||||
getAllChatflowsApi.request()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ListItemIcon>
|
|
||||||
<IconFileExport stroke={1.5} size='1.3rem' />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={<Typography variant='body2'>Export Chatflows</Typography>} />
|
|
||||||
</ListItemButton>
|
|
||||||
<ListItemButton
|
|
||||||
sx={{ borderRadius: `${customization.borderRadius}px` }}
|
|
||||||
onClick={() => {
|
|
||||||
importAllChatflows()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ListItemIcon>
|
|
||||||
<IconFileUpload stroke={1.5} size='1.3rem' />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={<Typography variant='body2'>Import Chatflows</Typography>} />
|
|
||||||
</ListItemButton>
|
|
||||||
<input ref={inputRef} type='file' hidden onChange={fileChange} />
|
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
sx={{ borderRadius: `${customization.borderRadius}px` }}
|
sx={{ borderRadius: `${customization.borderRadius}px` }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -340,18 +340,6 @@ export const getFolderName = (base64ArrayStr) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sanitizeChatflows = (arrayChatflows) => {
|
|
||||||
const sanitizedChatflows = arrayChatflows.map((chatFlow) => {
|
|
||||||
const sanitizeFlowData = generateExportFlowData(JSON.parse(chatFlow.flowData))
|
|
||||||
return {
|
|
||||||
id: chatFlow.id,
|
|
||||||
name: chatFlow.name,
|
|
||||||
flowData: JSON.stringify(sanitizeFlowData, null, 2)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return sanitizedChatflows
|
|
||||||
}
|
|
||||||
|
|
||||||
export const generateExportFlowData = (flowData) => {
|
export const generateExportFlowData = (flowData) => {
|
||||||
const nodes = flowData.nodes
|
const nodes = flowData.nodes
|
||||||
const edges = flowData.edges
|
const edges = flowData.edges
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue