mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 05:12:39 +00:00
Fix 4.8 node (#1370)
* perf: runtime props * fix: Plugin run faied in debug mode * perf: variable update * fix: ts * perf: variable ui
This commit is contained in:
2
packages/global/core/chat/type.d.ts
vendored
2
packages/global/core/chat/type.d.ts
vendored
@@ -155,6 +155,6 @@ export type ToolModuleResponseItemType = {
|
||||
|
||||
/* dispatch run time */
|
||||
export type RuntimeUserPromptType = {
|
||||
files?: UserChatItemValueItemType['file'][];
|
||||
files: UserChatItemValueItemType['file'][];
|
||||
text: string;
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { DispatchNodeResponseType } from '../workflow/runtime/type';
|
||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../workflow/node/constant';
|
||||
import { FlowNodeTypeEnum } from '../workflow/node/constant';
|
||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from './constants';
|
||||
import { ChatHistoryItemResType, ChatItemType } from './type.d';
|
||||
import { ChatHistoryItemResType, ChatItemType, UserChatItemValueItemType } from './type.d';
|
||||
|
||||
export const getChatTitleFromChatMessage = (message?: ChatItemType, defaultValue = '新对话') => {
|
||||
// @ts-ignore
|
||||
@@ -77,3 +77,15 @@ export const filterPublicNodeResponseData = ({
|
||||
return obj as ChatHistoryItemResType;
|
||||
});
|
||||
};
|
||||
|
||||
export const removeEmptyUserInput = (input: UserChatItemValueItemType[]) => {
|
||||
return input.filter((item) => {
|
||||
if (item.type === ChatItemValueTypeEnum.text && !item.text?.content?.trim()) {
|
||||
return false;
|
||||
}
|
||||
if (item.type === ChatItemValueTypeEnum.file && !item.file?.url) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
@@ -37,7 +37,6 @@ export enum NodeInputKeyEnum {
|
||||
welcomeText = 'welcomeText',
|
||||
switch = 'switch', // a trigger switch
|
||||
history = 'history',
|
||||
userChatInput = 'userChatInput',
|
||||
answerText = 'text',
|
||||
|
||||
// system config
|
||||
@@ -47,6 +46,10 @@ export enum NodeInputKeyEnum {
|
||||
variables = 'variables',
|
||||
scheduleTrigger = 'scheduleTrigger',
|
||||
|
||||
// entry
|
||||
userChatInput = 'userChatInput',
|
||||
inputFiles = 'inputFiles',
|
||||
|
||||
agents = 'agents', // cq agent key
|
||||
|
||||
// latest
|
||||
@@ -146,7 +149,7 @@ export enum VariableInputEnum {
|
||||
input = 'input',
|
||||
textarea = 'textarea',
|
||||
select = 'select',
|
||||
external = 'external'
|
||||
custom = 'custom'
|
||||
}
|
||||
export const variableMap = {
|
||||
[VariableInputEnum.input]: {
|
||||
@@ -164,10 +167,10 @@ export const variableMap = {
|
||||
title: 'core.module.variable.select type',
|
||||
desc: ''
|
||||
},
|
||||
[VariableInputEnum.external]: {
|
||||
[VariableInputEnum.custom]: {
|
||||
icon: 'core/app/variable/external',
|
||||
title: 'core.module.variable.External type',
|
||||
desc: '可以通过API接口或分享链接的Query传递变量。增加该类型变量的主要目的是用于变量提示。使用例子: 你可以通过分享链接Query中拼接Token,来实现内部系统身份鉴权。'
|
||||
title: 'core.module.variable.Custom type',
|
||||
desc: '可以定义一个无需用户填写的全局变量。\n该变量的值可以来自于 API 接口,分享链接的 Query 或通过【变量更新】模块进行赋值。'
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -5,6 +5,8 @@ import { StoreNodeItemType } from '../type';
|
||||
import { StoreEdgeItemType } from '../type/edge';
|
||||
import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
|
||||
import { VARIABLE_NODE_ID } from '../constants';
|
||||
import { isReferenceValue } from '../utils';
|
||||
import { ReferenceValueProps } from '../type/io';
|
||||
|
||||
export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeItemType[] => {
|
||||
return (
|
||||
@@ -138,16 +140,11 @@ export const getReferenceVariableValue = ({
|
||||
nodes,
|
||||
variables
|
||||
}: {
|
||||
value: [string, string];
|
||||
value: ReferenceValueProps;
|
||||
nodes: RuntimeNodeItemType[];
|
||||
variables: Record<string, any>;
|
||||
}) => {
|
||||
if (
|
||||
!Array.isArray(value) ||
|
||||
value.length !== 2 ||
|
||||
typeof value[0] !== 'string' ||
|
||||
typeof value[1] !== 'string'
|
||||
) {
|
||||
if (!isReferenceValue(value)) {
|
||||
return value;
|
||||
}
|
||||
const sourceNodeId = value[0];
|
||||
|
@@ -1,14 +1,9 @@
|
||||
import {
|
||||
FlowNodeInputTypeEnum,
|
||||
FlowNodeOutputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '../../node/constant';
|
||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
|
||||
import { FlowNodeTemplateType } from '../../type/index.d';
|
||||
import {
|
||||
WorkflowIOValueTypeEnum,
|
||||
NodeInputKeyEnum,
|
||||
FlowNodeTemplateTypeEnum,
|
||||
NodeOutputKeyEnum
|
||||
FlowNodeTemplateTypeEnum
|
||||
} from '../../constants';
|
||||
import { getHandleConfig } from '../utils';
|
||||
|
||||
@@ -26,7 +21,7 @@ export const AssignedAnswerModule: FlowNodeTemplateType = {
|
||||
{
|
||||
key: NodeInputKeyEnum.answerText,
|
||||
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
|
||||
valueType: WorkflowIOValueTypeEnum.string,
|
||||
valueType: WorkflowIOValueTypeEnum.any,
|
||||
label: 'core.module.input.label.Response content',
|
||||
description: 'core.module.input.description.Response content',
|
||||
placeholder: 'core.module.input.description.Response content'
|
||||
|
@@ -12,7 +12,7 @@ export const PluginInputModule: FlowNodeTemplateType = {
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
avatar: '/imgs/workflow/input.png',
|
||||
name: '定义插件输入',
|
||||
name: '自定义插件输入',
|
||||
intro: '自定义配置外部输入,使用插件时,仅暴露自定义配置的输入',
|
||||
showStatus: false,
|
||||
inputs: [],
|
||||
|
@@ -12,7 +12,7 @@ export const PluginOutputModule: FlowNodeTemplateType = {
|
||||
unique: true,
|
||||
forbidDelete: true,
|
||||
avatar: '/imgs/workflow/output.png',
|
||||
name: '定义插件输出',
|
||||
name: '自定义插件输出',
|
||||
intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出',
|
||||
showStatus: false,
|
||||
inputs: [],
|
||||
|
@@ -31,7 +31,8 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
|
||||
value: [
|
||||
{
|
||||
variable: ['', ''],
|
||||
value: '',
|
||||
value: ['', ''],
|
||||
valueType: WorkflowIOValueTypeEnum.string,
|
||||
renderType: FlowNodeInputTypeEnum.input
|
||||
}
|
||||
]
|
||||
|
@@ -1,7 +1,10 @@
|
||||
import { FlowNodeInputTypeEnum } from 'core/workflow/node/constant';
|
||||
import { FlowNodeInputTypeEnum } from '../../../node/constant';
|
||||
import { ReferenceValueProps } from '../../..//type/io';
|
||||
import { WorkflowIOValueTypeEnum } from '../../../constants';
|
||||
|
||||
export type TUpdateListItem = {
|
||||
variable?: ReferenceValueProps;
|
||||
value?: ReferenceValueProps;
|
||||
renderType?: FlowNodeInputTypeEnum.input | FlowNodeInputTypeEnum.reference;
|
||||
value: ReferenceValueProps;
|
||||
valueType?: WorkflowIOValueTypeEnum;
|
||||
renderType: FlowNodeInputTypeEnum.input | FlowNodeInputTypeEnum.reference;
|
||||
};
|
||||
|
@@ -133,7 +133,7 @@ export type ChatDispatchProps = {
|
||||
responseChatItemId?: string;
|
||||
histories: ChatItemType[];
|
||||
variables: Record<string, any>;
|
||||
inputFiles?: UserChatItemValueItemType['file'][];
|
||||
query: UserChatItemValueItemType[];
|
||||
stream: boolean;
|
||||
detail: boolean; // response detail
|
||||
maxRunTimes: number;
|
||||
|
@@ -132,3 +132,7 @@ export const formatEditorVariablePickerIcon = (
|
||||
icon: item.type ? variableMap[item.type]?.icon : variableMap['input'].icon
|
||||
}));
|
||||
};
|
||||
|
||||
export const isReferenceValue = (value: any): boolean => {
|
||||
return Array.isArray(value) && value.length === 2 && typeof value[0] === 'string';
|
||||
};
|
||||
|
@@ -25,6 +25,7 @@ import {
|
||||
} from '../../../../common/string/tiktoken/index';
|
||||
import {
|
||||
chats2GPTMessages,
|
||||
chatValue2RuntimePrompt,
|
||||
getSystemPrompt,
|
||||
GPTMessages2Chats,
|
||||
runtimePrompt2ChatsValue
|
||||
@@ -66,7 +67,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
||||
user,
|
||||
histories,
|
||||
node: { name },
|
||||
inputFiles = [],
|
||||
query,
|
||||
params: {
|
||||
model,
|
||||
temperature = 0,
|
||||
@@ -80,6 +81,8 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
||||
quotePrompt
|
||||
}
|
||||
} = props;
|
||||
const { files: inputFiles } = chatValue2RuntimePrompt(query);
|
||||
|
||||
if (!userChatInput && inputFiles.length === 0) {
|
||||
return Promise.reject('Question is empty');
|
||||
}
|
||||
|
@@ -289,7 +289,8 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
node,
|
||||
runtimeNodes,
|
||||
runtimeEdges,
|
||||
params
|
||||
params,
|
||||
mode: 'test'
|
||||
};
|
||||
|
||||
// run module
|
||||
@@ -357,7 +358,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
if (pluginOutputModule && props.mode !== 'debug') {
|
||||
await nodeRunWithActive(pluginOutputModule);
|
||||
}
|
||||
const { userChatInput, ...leftVariables } = variables;
|
||||
|
||||
return {
|
||||
flowResponses: chatResponses,
|
||||
flowUsages: chatNodeUsages,
|
||||
@@ -369,7 +370,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
||||
[DispatchNodeResponseKeyEnum.assistantResponses]:
|
||||
mergeAssistantResponseAnswerText(chatAssistantResponse),
|
||||
[DispatchNodeResponseKeyEnum.toolResponses]: toolRunResponse,
|
||||
newVariables: leftVariables
|
||||
newVariables: removeSystemVariable(variables)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -407,6 +408,18 @@ export function getSystemVariable({
|
||||
};
|
||||
}
|
||||
|
||||
/* remove system variable */
|
||||
const removeSystemVariable = (variables: Record<string, any>) => {
|
||||
const copyVariables = { ...variables };
|
||||
delete copyVariables.appId;
|
||||
delete copyVariables.chatId;
|
||||
delete copyVariables.responseChatItemId;
|
||||
delete copyVariables.histories;
|
||||
delete copyVariables.cTime;
|
||||
|
||||
return copyVariables;
|
||||
};
|
||||
|
||||
/* Merge consecutive text messages into one */
|
||||
export const mergeAssistantResponseAnswerText = (response: AIChatItemValueItemType[]) => {
|
||||
const result: AIChatItemValueItemType[] = [];
|
||||
|
@@ -1,15 +1,19 @@
|
||||
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||
import { UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
export type UserChatInputProps = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.userChatInput]: string;
|
||||
[NodeInputKeyEnum.inputFiles]: UserChatItemValueItemType['file'][];
|
||||
}>;
|
||||
|
||||
export const dispatchWorkflowStart = (props: Record<string, any>) => {
|
||||
const {
|
||||
variables: { userChatInput },
|
||||
params: { userChatInput: query }
|
||||
} = props as UserChatInputProps;
|
||||
const { query } = props as UserChatInputProps;
|
||||
|
||||
const { text, files } = chatValue2RuntimePrompt(query);
|
||||
|
||||
return {
|
||||
userChatInput: query || userChatInput
|
||||
[NodeInputKeyEnum.userChatInput]: text,
|
||||
[NodeInputKeyEnum.inputFiles]: files
|
||||
};
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import { dispatchWorkFlow } from '../index';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { getPluginRuntimeById } from '../../../plugin/controller';
|
||||
import { authPluginCanUse } from '../../../../support/permission/auth/plugin';
|
||||
|
@@ -35,7 +35,7 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
|
||||
stream,
|
||||
detail,
|
||||
histories,
|
||||
inputFiles,
|
||||
query,
|
||||
params: { userChatInput, history, app }
|
||||
} = props;
|
||||
let start = Date.now();
|
||||
@@ -71,7 +71,7 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
|
||||
runtimeNodes: storeNodes2RuntimeNodes(appData.modules, getDefaultEntryNodeIds(appData.modules)),
|
||||
runtimeEdges: initWorkflowEdgeStatus(appData.edges),
|
||||
histories: chatHistories,
|
||||
inputFiles,
|
||||
query,
|
||||
variables: {
|
||||
...props.variables,
|
||||
userChatInput
|
||||
@@ -81,10 +81,7 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
|
||||
const completeMessages = chatHistories.concat([
|
||||
{
|
||||
obj: ChatRoleEnum.Human,
|
||||
value: runtimePrompt2ChatsValue({
|
||||
files: inputFiles,
|
||||
text: userChatInput
|
||||
})
|
||||
value: query
|
||||
},
|
||||
{
|
||||
obj: ChatRoleEnum.AI,
|
||||
|
@@ -4,6 +4,7 @@ import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/ty
|
||||
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
|
||||
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||
import { valueTypeFormat } from '../utils';
|
||||
|
||||
type Props = ModuleDispatchProps<{
|
||||
[NodeInputKeyEnum.updateList]: TUpdateListItem[];
|
||||
@@ -22,26 +23,31 @@ export const dispatchUpdateVariable = async (
|
||||
if (!varNodeId || !varKey) {
|
||||
return;
|
||||
}
|
||||
let value = '';
|
||||
if (!item.value?.[0]) {
|
||||
value = item.value?.[1];
|
||||
} else {
|
||||
value = getReferenceVariableValue({
|
||||
value: item.value,
|
||||
variables,
|
||||
nodes: runtimeNodes
|
||||
});
|
||||
}
|
||||
|
||||
const value = (() => {
|
||||
if (!item.value?.[0]) {
|
||||
return valueTypeFormat(item.value?.[1], item.valueType);
|
||||
} else {
|
||||
return getReferenceVariableValue({
|
||||
value: item.value,
|
||||
variables,
|
||||
nodes: runtimeNodes
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
if (varNodeId === VARIABLE_NODE_ID) {
|
||||
// update global variable
|
||||
variables[varKey] = value;
|
||||
} else {
|
||||
const node = runtimeNodes.find((node) => node.nodeId === varNodeId);
|
||||
if (node) {
|
||||
const output = node.outputs.find((output) => output.id === varKey);
|
||||
if (output) {
|
||||
output.value = value;
|
||||
}
|
||||
}
|
||||
runtimeNodes
|
||||
.find((node) => node.nodeId === varNodeId)
|
||||
?.outputs?.find((output) => {
|
||||
if (output.id === varKey) {
|
||||
output.value = value;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user