Compare commits
18 Commits
v4.8-previ
...
v4.8-alpha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
917e4e9262 | ||
|
|
3c6e5a6e00 | ||
|
|
7b75a99ba2 | ||
|
|
2e468fc8ca | ||
|
|
caa0755d9a | ||
|
|
fef1a1702b | ||
|
|
2a99e46353 | ||
|
|
8f9203c053 | ||
|
|
2053bbdb1b | ||
|
|
9e192c6d11 | ||
|
|
eef609a063 | ||
|
|
5bb9c550f6 | ||
|
|
db1c27cdc7 | ||
|
|
8863337606 | ||
|
|
59bd2a47b6 | ||
|
|
d057ba29f0 | ||
|
|
b500631a4d | ||
|
|
bf6084da69 |
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -6,10 +6,10 @@
|
|||||||
"i18n-ally.localesPaths": [
|
"i18n-ally.localesPaths": [
|
||||||
"projects/app/i18n",
|
"projects/app/i18n",
|
||||||
],
|
],
|
||||||
"i18n-ally.enabledParsers": ["json"],
|
"i18n-ally.enabledParsers": ["json", "yaml", "js", "ts"],
|
||||||
"i18n-ally.keystyle": "nested",
|
"i18n-ally.keystyle": "nested",
|
||||||
"i18n-ally.sortKeys": true,
|
"i18n-ally.sortKeys": true,
|
||||||
"i18n-ally.keepFulfilled": true,
|
"i18n-ally.keepFulfilled": false,
|
||||||
"i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译其他语言文件的变量和内容
|
"i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译其他语言文件的变量和内容
|
||||||
"i18n-ally.displayLanguage": "zh", // 显示语言
|
"i18n-ally.displayLanguage": "zh" // 显示语言
|
||||||
}
|
}
|
||||||
@@ -17,8 +17,6 @@ images: []
|
|||||||
4. 无法解决时,可以找找[Issue](https://github.com/labring/FastGPT/issues),或新提 Issue,私有部署错误,务必提供详细的日志,否则很难排查。
|
4. 无法解决时,可以找找[Issue](https://github.com/labring/FastGPT/issues),或新提 Issue,私有部署错误,务必提供详细的日志,否则很难排查。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 二、通用问题
|
## 二、通用问题
|
||||||
|
|
||||||
### 能否纯本地运行
|
### 能否纯本地运行
|
||||||
@@ -47,7 +45,7 @@ images: []
|
|||||||
|
|
||||||
### 模型响应为空(core.chat.Chat API is error or undefined)
|
### 模型响应为空(core.chat.Chat API is error or undefined)
|
||||||
|
|
||||||
1. 检查 key 问题。
|
1. 检查 key 问题。curl 请求看是否正常。务必用 stream=true 模式。并且 maxToken 等相关参数尽量一致。
|
||||||
2. 如果是国内模型,可能是命中风控了。
|
2. 如果是国内模型,可能是命中风控了。
|
||||||
3. 查看模型请求日志,检查出入参数是否异常。
|
3. 查看模型请求日志,检查出入参数是否异常。
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 'V4.8(进行中)'
|
title: 'V4.8(开发中)'
|
||||||
description: 'FastGPT V4.8 更新说明'
|
description: 'FastGPT V4.8 更新说明'
|
||||||
icon: 'upgrade'
|
icon: 'upgrade'
|
||||||
draft: false
|
draft: false
|
||||||
@@ -18,10 +18,14 @@ FastGPT workflow V2上线,支持更加简洁的工作流模式。
|
|||||||
## V4.8 更新说明
|
## V4.8 更新说明
|
||||||
|
|
||||||
1. 重构 - 工作流
|
1. 重构 - 工作流
|
||||||
2. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流。
|
2. 新增 - 判断器。支持 if elseIf else 判断。
|
||||||
3. 新增 - 定时执行应用。可轻松实现定时任务。
|
3. 新增 - 变量更新节点。支持更新运行中工作流输出变量,或更新全局变量。
|
||||||
4. 新增 - 插件自定义输入优化,可以渲染输入组件。
|
4. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流。
|
||||||
6. 优化 - 工作流连线,可以四向连接,方便构建循环工作流。
|
5. 新增 - 定时执行应用。可轻松实现定时任务。
|
||||||
7. 优化 - 工作流上下文传递,性能🚀。
|
6. 新增 - 插件自定义输入优化,可以渲染输入组件。
|
||||||
8. 优化 - 简易模式,更新配置后自动更新调试框内容,无需保存。
|
7. 优化 - 工作流连线,可以四向连接,方便构建循环工作流。
|
||||||
9. 优化 - worker进程管理,并将计算 Token 任务分配给 worker 进程。
|
8. 优化 - 工作流上下文传递,性能🚀。
|
||||||
|
9. 优化 - 简易模式,更新配置后自动更新调试框内容,无需保存。
|
||||||
|
10. 优化 - worker进程管理,并将计算 Token 任务分配给 worker 进程。
|
||||||
|
11. 修复 - 工具调用时候,name不能是数字开头(随机数有概率数字开头)
|
||||||
|
12. 修复 - 分享链接, query 全局变量会被缓存。
|
||||||
@@ -2,7 +2,7 @@ import { ErrType } from '../errorCode';
|
|||||||
|
|
||||||
/* dataset: 502000 */
|
/* dataset: 502000 */
|
||||||
export enum AppErrEnum {
|
export enum AppErrEnum {
|
||||||
unExist = 'unExist',
|
unExist = 'appUnExist',
|
||||||
unAuthApp = 'unAuthApp'
|
unAuthApp = 'unAuthApp'
|
||||||
}
|
}
|
||||||
const appErrList = [
|
const appErrList = [
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { ErrType } from '../errorCode';
|
|||||||
|
|
||||||
/* dataset: 506000 */
|
/* dataset: 506000 */
|
||||||
export enum OpenApiErrEnum {
|
export enum OpenApiErrEnum {
|
||||||
unExist = 'unExist',
|
unExist = 'openapiUnExist',
|
||||||
unAuth = 'unAuth'
|
unAuth = 'openapiUnAuth'
|
||||||
}
|
}
|
||||||
const errList = [
|
const errList = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ErrType } from '../errorCode';
|
|||||||
|
|
||||||
/* dataset: 505000 */
|
/* dataset: 505000 */
|
||||||
export enum OutLinkErrEnum {
|
export enum OutLinkErrEnum {
|
||||||
unExist = 'unExist',
|
unExist = 'outlinkUnExist',
|
||||||
unAuthLink = 'unAuthLink',
|
unAuthLink = 'unAuthLink',
|
||||||
linkUnInvalid = 'linkUnInvalid',
|
linkUnInvalid = 'linkUnInvalid',
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { ErrType } from '../errorCode';
|
|||||||
|
|
||||||
/* dataset: 507000 */
|
/* dataset: 507000 */
|
||||||
export enum PluginErrEnum {
|
export enum PluginErrEnum {
|
||||||
unExist = 'unExist',
|
unExist = 'pluginUnExist',
|
||||||
unAuth = 'unAuth'
|
unAuth = 'pluginUnAuth'
|
||||||
}
|
}
|
||||||
const errList = [
|
const errList = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,8 +50,18 @@ export const replaceSensitiveText = (text: string) => {
|
|||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Make sure the first letter is definitely lowercase */
|
||||||
export const getNanoid = (size = 12) => {
|
export const getNanoid = (size = 12) => {
|
||||||
return customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', size)();
|
const firstChar = customAlphabet('abcdefghijklmnopqrstuvwxyz', 1)();
|
||||||
|
|
||||||
|
if (size === 1) return firstChar;
|
||||||
|
|
||||||
|
const randomsStr = customAlphabet(
|
||||||
|
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
|
||||||
|
size - 1
|
||||||
|
)();
|
||||||
|
|
||||||
|
return `${firstChar}${randomsStr}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const replaceRegChars = (text: string) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
export const replaceRegChars = (text: string) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
|
|||||||
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
|
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
|
||||||
const {
|
const {
|
||||||
welcomeText,
|
welcomeText,
|
||||||
variableModules,
|
variableNodes,
|
||||||
questionGuide,
|
questionGuide,
|
||||||
ttsConfig,
|
ttsConfig,
|
||||||
whisperConfig,
|
whisperConfig,
|
||||||
@@ -114,7 +114,7 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
|
|||||||
|
|
||||||
defaultAppForm.userGuide = {
|
defaultAppForm.userGuide = {
|
||||||
welcomeText: welcomeText,
|
welcomeText: welcomeText,
|
||||||
variables: variableModules,
|
variables: variableNodes,
|
||||||
questionGuide: questionGuide,
|
questionGuide: questionGuide,
|
||||||
tts: ttsConfig,
|
tts: ttsConfig,
|
||||||
whisper: whisperConfig,
|
whisper: whisperConfig,
|
||||||
|
|||||||
10
packages/global/core/chat/type.d.ts
vendored
10
packages/global/core/chat/type.d.ts
vendored
@@ -10,7 +10,7 @@ import {
|
|||||||
import { FlowNodeTypeEnum } from '../workflow/node/constant';
|
import { FlowNodeTypeEnum } from '../workflow/node/constant';
|
||||||
import { NodeOutputKeyEnum } from '../workflow/constants';
|
import { NodeOutputKeyEnum } from '../workflow/constants';
|
||||||
import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
|
||||||
import { AppSchema } from '../app/type';
|
import { AppSchema, VariableItemType } from '../app/type';
|
||||||
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
|
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
|
||||||
import { DatasetSearchModeEnum } from '../dataset/constants';
|
import { DatasetSearchModeEnum } from '../dataset/constants';
|
||||||
import { ChatBoxInputType } from '../../../../projects/app/src/components/ChatBox/type';
|
import { ChatBoxInputType } from '../../../../projects/app/src/components/ChatBox/type';
|
||||||
@@ -27,11 +27,13 @@ export type ChatSchema = {
|
|||||||
title: string;
|
title: string;
|
||||||
customTitle: string;
|
customTitle: string;
|
||||||
top: boolean;
|
top: boolean;
|
||||||
variables: Record<string, any>;
|
|
||||||
source: `${ChatSourceEnum}`;
|
source: `${ChatSourceEnum}`;
|
||||||
shareId?: string;
|
shareId?: string;
|
||||||
outLinkUid?: string;
|
outLinkUid?: string;
|
||||||
content: ChatItemType[];
|
|
||||||
|
variableList?: VariableItemType[];
|
||||||
|
welcomeText?: string;
|
||||||
|
variables: Record<string, any>;
|
||||||
metadata?: Record<string, any>;
|
metadata?: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -155,6 +157,6 @@ export type ToolModuleResponseItemType = {
|
|||||||
|
|
||||||
/* dispatch run time */
|
/* dispatch run time */
|
||||||
export type RuntimeUserPromptType = {
|
export type RuntimeUserPromptType = {
|
||||||
files?: UserChatItemValueItemType['file'][];
|
files: UserChatItemValueItemType['file'][];
|
||||||
text: string;
|
text: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { DispatchNodeResponseType } from '../workflow/runtime/type';
|
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 { ChatItemValueTypeEnum, ChatRoleEnum } from './constants';
|
||||||
import { ChatHistoryItemResType, ChatItemType } from './type.d';
|
import { ChatHistoryItemResType, ChatItemType, UserChatItemValueItemType } from './type.d';
|
||||||
|
|
||||||
export const getChatTitleFromChatMessage = (message?: ChatItemType, defaultValue = '新对话') => {
|
export const getChatTitleFromChatMessage = (message?: ChatItemType, defaultValue = '新对话') => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -77,3 +77,15 @@ export const filterPublicNodeResponseData = ({
|
|||||||
return obj as ChatHistoryItemResType;
|
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',
|
welcomeText = 'welcomeText',
|
||||||
switch = 'switch', // a trigger switch
|
switch = 'switch', // a trigger switch
|
||||||
history = 'history',
|
history = 'history',
|
||||||
userChatInput = 'userChatInput',
|
|
||||||
answerText = 'text',
|
answerText = 'text',
|
||||||
|
|
||||||
// system config
|
// system config
|
||||||
@@ -47,6 +46,10 @@ export enum NodeInputKeyEnum {
|
|||||||
variables = 'variables',
|
variables = 'variables',
|
||||||
scheduleTrigger = 'scheduleTrigger',
|
scheduleTrigger = 'scheduleTrigger',
|
||||||
|
|
||||||
|
// entry
|
||||||
|
userChatInput = 'userChatInput',
|
||||||
|
inputFiles = 'inputFiles',
|
||||||
|
|
||||||
agents = 'agents', // cq agent key
|
agents = 'agents', // cq agent key
|
||||||
|
|
||||||
// latest
|
// latest
|
||||||
@@ -101,7 +104,10 @@ export enum NodeInputKeyEnum {
|
|||||||
|
|
||||||
// if else
|
// if else
|
||||||
condition = 'condition',
|
condition = 'condition',
|
||||||
ifElseList = 'ifElseList'
|
ifElseList = 'ifElseList',
|
||||||
|
|
||||||
|
// variable update
|
||||||
|
updateList = 'updateList'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum NodeOutputKeyEnum {
|
export enum NodeOutputKeyEnum {
|
||||||
@@ -135,15 +141,14 @@ export enum NodeOutputKeyEnum {
|
|||||||
// plugin
|
// plugin
|
||||||
pluginStart = 'pluginStart',
|
pluginStart = 'pluginStart',
|
||||||
|
|
||||||
if = 'IF',
|
ifElseResult = 'ifElseResult'
|
||||||
else = 'ELSE'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum VariableInputEnum {
|
export enum VariableInputEnum {
|
||||||
input = 'input',
|
input = 'input',
|
||||||
textarea = 'textarea',
|
textarea = 'textarea',
|
||||||
select = 'select',
|
select = 'select',
|
||||||
external = 'external'
|
custom = 'custom'
|
||||||
}
|
}
|
||||||
export const variableMap = {
|
export const variableMap = {
|
||||||
[VariableInputEnum.input]: {
|
[VariableInputEnum.input]: {
|
||||||
@@ -161,10 +166,10 @@ export const variableMap = {
|
|||||||
title: 'core.module.variable.select type',
|
title: 'core.module.variable.select type',
|
||||||
desc: ''
|
desc: ''
|
||||||
},
|
},
|
||||||
[VariableInputEnum.external]: {
|
[VariableInputEnum.custom]: {
|
||||||
icon: 'core/app/variable/external',
|
icon: 'core/app/variable/external',
|
||||||
title: 'core.module.variable.External type',
|
title: 'core.module.variable.Custom type',
|
||||||
desc: '可以通过API接口或分享链接的Query传递变量。增加该类型变量的主要目的是用于变量提示。使用例子: 你可以通过分享链接Query中拼接Token,来实现内部系统身份鉴权。'
|
desc: '可以定义一个无需用户填写的全局变量。\n该变量的值可以来自于 API 接口,分享链接的 Query 或通过【变量更新】模块进行赋值。'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ export enum FlowNodeTypeEnum {
|
|||||||
tools = 'tools',
|
tools = 'tools',
|
||||||
stopTool = 'stopTool',
|
stopTool = 'stopTool',
|
||||||
lafModule = 'lafModule',
|
lafModule = 'lafModule',
|
||||||
ifElseNode = 'ifElseNode'
|
ifElseNode = 'ifElseNode',
|
||||||
|
variableUpdate = 'variableUpdate'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EDGE_TYPE = 'default';
|
export const EDGE_TYPE = 'default';
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ export enum SseResponseEventEnum {
|
|||||||
toolCall = 'toolCall', // tool start
|
toolCall = 'toolCall', // tool start
|
||||||
toolParams = 'toolParams', // tool params return
|
toolParams = 'toolParams', // tool params return
|
||||||
toolResponse = 'toolResponse', // tool response return
|
toolResponse = 'toolResponse', // tool response return
|
||||||
flowResponses = 'flowResponses' // sse response request
|
flowResponses = 'flowResponses', // sse response request
|
||||||
|
updateVariables = 'updateVariables'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DispatchNodeResponseKeyEnum {
|
export enum DispatchNodeResponseKeyEnum {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export type DispatchNodeResponseType = {
|
|||||||
pluginDetail?: ChatHistoryItemResType[];
|
pluginDetail?: ChatHistoryItemResType[];
|
||||||
|
|
||||||
// if-else
|
// if-else
|
||||||
ifElseResult?: 'IF' | 'ELSE';
|
ifElseResult?: string;
|
||||||
|
|
||||||
// tool
|
// tool
|
||||||
toolCallTokens?: number;
|
toolCallTokens?: number;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { StoreNodeItemType } from '../type';
|
|||||||
import { StoreEdgeItemType } from '../type/edge';
|
import { StoreEdgeItemType } from '../type/edge';
|
||||||
import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
|
import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
|
||||||
import { VARIABLE_NODE_ID } from '../constants';
|
import { VARIABLE_NODE_ID } from '../constants';
|
||||||
|
import { isReferenceValue } from '../utils';
|
||||||
|
import { ReferenceValueProps } from '../type/io';
|
||||||
|
|
||||||
export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeItemType[] => {
|
export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeItemType[] => {
|
||||||
return (
|
return (
|
||||||
@@ -138,16 +140,11 @@ export const getReferenceVariableValue = ({
|
|||||||
nodes,
|
nodes,
|
||||||
variables
|
variables
|
||||||
}: {
|
}: {
|
||||||
value: [string, string];
|
value: ReferenceValueProps;
|
||||||
nodes: RuntimeNodeItemType[];
|
nodes: RuntimeNodeItemType[];
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
}) => {
|
}) => {
|
||||||
if (
|
if (!isReferenceValue(value)) {
|
||||||
!Array.isArray(value) ||
|
|
||||||
value.length !== 2 ||
|
|
||||||
typeof value[0] !== 'string' ||
|
|
||||||
typeof value[1] !== 'string'
|
|
||||||
) {
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
const sourceNodeId = value[0];
|
const sourceNodeId = value[0];
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ import { PluginOutputModule } from './system/pluginOutput';
|
|||||||
import { RunPluginModule } from './system/runPlugin';
|
import { RunPluginModule } from './system/runPlugin';
|
||||||
import { AiQueryExtension } from './system/queryExtension';
|
import { AiQueryExtension } from './system/queryExtension';
|
||||||
|
|
||||||
import type { FlowNodeTemplateType, nodeTemplateListType } from '../type';
|
import type { FlowNodeTemplateType } from '../type';
|
||||||
import { FlowNodeTemplateTypeEnum } from '../../workflow/constants';
|
import { LafModule } from './system/laf';
|
||||||
import { lafModule } from './system/laf';
|
import { IfElseNode } from './system/ifElse/index';
|
||||||
import { ifElseNode } from './system/ifElse/index';
|
import { VariableUpdateNode } from './system/variableUpdate';
|
||||||
|
|
||||||
/* app flow module templates */
|
/* app flow module templates */
|
||||||
export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
|
export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
|
||||||
@@ -38,8 +38,9 @@ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
|
|||||||
ContextExtractModule,
|
ContextExtractModule,
|
||||||
HttpModule468,
|
HttpModule468,
|
||||||
AiQueryExtension,
|
AiQueryExtension,
|
||||||
lafModule,
|
LafModule,
|
||||||
ifElseNode
|
IfElseNode,
|
||||||
|
VariableUpdateNode
|
||||||
];
|
];
|
||||||
/* plugin flow module templates */
|
/* plugin flow module templates */
|
||||||
export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
|
export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
|
||||||
@@ -56,8 +57,9 @@ export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
|
|||||||
ContextExtractModule,
|
ContextExtractModule,
|
||||||
HttpModule468,
|
HttpModule468,
|
||||||
AiQueryExtension,
|
AiQueryExtension,
|
||||||
lafModule,
|
LafModule,
|
||||||
ifElseNode
|
IfElseNode,
|
||||||
|
VariableUpdateNode
|
||||||
];
|
];
|
||||||
|
|
||||||
/* all module */
|
/* all module */
|
||||||
@@ -80,6 +82,7 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
|
|||||||
PluginOutputModule,
|
PluginOutputModule,
|
||||||
RunPluginModule,
|
RunPluginModule,
|
||||||
AiQueryExtension,
|
AiQueryExtension,
|
||||||
lafModule,
|
LafModule,
|
||||||
ifElseNode
|
IfElseNode,
|
||||||
|
VariableUpdateNode
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ export const Input_Template_History: FlowNodeInputItemType = {
|
|||||||
renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference],
|
renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference],
|
||||||
valueType: WorkflowIOValueTypeEnum.chatHistory,
|
valueType: WorkflowIOValueTypeEnum.chatHistory,
|
||||||
label: 'core.module.input.label.chat history',
|
label: 'core.module.input.label.chat history',
|
||||||
|
description: '最多携带多少轮对话记录',
|
||||||
required: true,
|
required: true,
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 30,
|
max: 50,
|
||||||
value: 6
|
value: 6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
import {
|
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
|
||||||
FlowNodeInputTypeEnum,
|
|
||||||
FlowNodeOutputTypeEnum,
|
|
||||||
FlowNodeTypeEnum
|
|
||||||
} from '../../node/constant';
|
|
||||||
import { FlowNodeTemplateType } from '../../type/index.d';
|
import { FlowNodeTemplateType } from '../../type/index.d';
|
||||||
import {
|
import {
|
||||||
WorkflowIOValueTypeEnum,
|
WorkflowIOValueTypeEnum,
|
||||||
NodeInputKeyEnum,
|
NodeInputKeyEnum,
|
||||||
FlowNodeTemplateTypeEnum,
|
FlowNodeTemplateTypeEnum
|
||||||
NodeOutputKeyEnum
|
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
import { getHandleConfig } from '../utils';
|
import { getHandleConfig } from '../utils';
|
||||||
|
|
||||||
@@ -26,7 +21,7 @@ export const AssignedAnswerModule: FlowNodeTemplateType = {
|
|||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.answerText,
|
key: NodeInputKeyEnum.answerText,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
|
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
|
||||||
valueType: WorkflowIOValueTypeEnum.string,
|
valueType: WorkflowIOValueTypeEnum.any,
|
||||||
label: 'core.module.input.label.Response content',
|
label: 'core.module.input.label.Response content',
|
||||||
description: 'core.module.input.description.Response content',
|
description: 'core.module.input.description.Response content',
|
||||||
placeholder: 'core.module.input.description.Response content'
|
placeholder: 'core.module.input.description.Response content'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { FlowNodeTemplateTypeEnum, WorkflowIOValueTypeEnum } from '../../constants';
|
import { FlowNodeTemplateTypeEnum, WorkflowIOValueTypeEnum } from '../../constants';
|
||||||
import { getHandleConfig } from '../utils';
|
import { getHandleConfig } from '../utils';
|
||||||
import { FlowNodeTypeEnum } from '../../node/constant';
|
import { FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
|
||||||
import { VariableItemType } from '../../../app/type';
|
import { VariableItemType } from '../../../app/type';
|
||||||
import { FlowNodeTemplateType } from '../../type';
|
import { FlowNodeTemplateType } from '../../type';
|
||||||
|
|
||||||
@@ -25,6 +25,7 @@ export const getGlobalVariableNode = ({
|
|||||||
id: item.key,
|
id: item.key,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
valueType: WorkflowIOValueTypeEnum.string,
|
valueType: WorkflowIOValueTypeEnum.string,
|
||||||
|
type: FlowNodeOutputTypeEnum.static,
|
||||||
label: item.label
|
label: item.label
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ export enum VariableConditionEnum {
|
|||||||
lengthLessThan = 'lengthLessThan',
|
lengthLessThan = 'lengthLessThan',
|
||||||
lengthLessThanOrEqualTo = 'lengthLessThanOrEqualTo'
|
lengthLessThanOrEqualTo = 'lengthLessThanOrEqualTo'
|
||||||
}
|
}
|
||||||
|
export enum IfElseResultEnum {
|
||||||
|
IF = 'IF',
|
||||||
|
ELSE = 'ELSE',
|
||||||
|
ELSE_IF = 'ELSE IF'
|
||||||
|
}
|
||||||
|
|
||||||
export const stringConditionList = [
|
export const stringConditionList = [
|
||||||
{ label: '为空', value: VariableConditionEnum.isEmpty },
|
{ label: '为空', value: VariableConditionEnum.isEmpty },
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
import { FlowNodeTemplateType } from '../../../type';
|
import { FlowNodeTemplateType } from '../../../type';
|
||||||
import { getHandleConfig } from '../../utils';
|
import { getHandleConfig } from '../../utils';
|
||||||
|
|
||||||
export const ifElseNode: FlowNodeTemplateType = {
|
export const IfElseNode: FlowNodeTemplateType = {
|
||||||
id: FlowNodeTypeEnum.ifElseNode,
|
id: FlowNodeTypeEnum.ifElseNode,
|
||||||
templateType: FlowNodeTemplateTypeEnum.tools,
|
templateType: FlowNodeTemplateTypeEnum.tools,
|
||||||
flowNodeType: FlowNodeTypeEnum.ifElseNode,
|
flowNodeType: FlowNodeTypeEnum.ifElseNode,
|
||||||
@@ -23,14 +23,6 @@ export const ifElseNode: FlowNodeTemplateType = {
|
|||||||
intro: '根据一定的条件,执行不同的分支。',
|
intro: '根据一定的条件,执行不同的分支。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
|
||||||
key: NodeInputKeyEnum.condition,
|
|
||||||
valueType: WorkflowIOValueTypeEnum.string,
|
|
||||||
label: '',
|
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
|
||||||
required: false,
|
|
||||||
value: 'AND' // AND, OR
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.ifElseList,
|
key: NodeInputKeyEnum.ifElseList,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
@@ -38,27 +30,25 @@ export const ifElseNode: FlowNodeTemplateType = {
|
|||||||
label: '',
|
label: '',
|
||||||
value: [
|
value: [
|
||||||
{
|
{
|
||||||
variable: undefined,
|
condition: 'AND', // AND, OR
|
||||||
condition: undefined,
|
list: [
|
||||||
value: undefined
|
{
|
||||||
|
variable: undefined,
|
||||||
|
condition: undefined,
|
||||||
|
value: undefined
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
outputs: [
|
outputs: [
|
||||||
{
|
{
|
||||||
id: NodeOutputKeyEnum.if,
|
id: NodeOutputKeyEnum.ifElseResult,
|
||||||
key: NodeOutputKeyEnum.if,
|
key: NodeOutputKeyEnum.ifElseResult,
|
||||||
label: 'IF',
|
label: '判断结果',
|
||||||
valueType: WorkflowIOValueTypeEnum.any,
|
valueType: WorkflowIOValueTypeEnum.string,
|
||||||
type: FlowNodeOutputTypeEnum.source
|
type: FlowNodeOutputTypeEnum.static
|
||||||
},
|
|
||||||
{
|
|
||||||
id: NodeOutputKeyEnum.else,
|
|
||||||
key: NodeOutputKeyEnum.else,
|
|
||||||
label: 'ELSE',
|
|
||||||
valueType: WorkflowIOValueTypeEnum.any,
|
|
||||||
type: FlowNodeOutputTypeEnum.source
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,8 +2,12 @@ import { ReferenceValueProps } from 'core/workflow/type/io';
|
|||||||
import { VariableConditionEnum } from './constant';
|
import { VariableConditionEnum } from './constant';
|
||||||
|
|
||||||
export type IfElseConditionType = 'AND' | 'OR';
|
export type IfElseConditionType = 'AND' | 'OR';
|
||||||
export type IfElseListItemType = {
|
export type ConditionListItemType = {
|
||||||
variable?: ReferenceValueProps;
|
variable?: ReferenceValueProps;
|
||||||
condition?: VariableConditionEnum;
|
condition?: VariableConditionEnum;
|
||||||
value?: string;
|
value?: string;
|
||||||
};
|
};
|
||||||
|
export type IfElseListItemType = {
|
||||||
|
condition: IfElseConditionType;
|
||||||
|
list: ConditionListItemType[];
|
||||||
|
};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { Input_Template_DynamicInput } from '../input';
|
|||||||
import { Output_Template_AddOutput } from '../output';
|
import { Output_Template_AddOutput } from '../output';
|
||||||
import { getHandleConfig } from '../utils';
|
import { getHandleConfig } from '../utils';
|
||||||
|
|
||||||
export const lafModule: FlowNodeTemplateType = {
|
export const LafModule: FlowNodeTemplateType = {
|
||||||
id: FlowNodeTypeEnum.lafModule,
|
id: FlowNodeTypeEnum.lafModule,
|
||||||
templateType: FlowNodeTemplateTypeEnum.externalCall,
|
templateType: FlowNodeTemplateTypeEnum.externalCall,
|
||||||
flowNodeType: FlowNodeTypeEnum.lafModule,
|
flowNodeType: FlowNodeTypeEnum.lafModule,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const PluginInputModule: FlowNodeTemplateType = {
|
|||||||
unique: true,
|
unique: true,
|
||||||
forbidDelete: true,
|
forbidDelete: true,
|
||||||
avatar: '/imgs/workflow/input.png',
|
avatar: '/imgs/workflow/input.png',
|
||||||
name: '定义插件输入',
|
name: '自定义插件输入',
|
||||||
intro: '自定义配置外部输入,使用插件时,仅暴露自定义配置的输入',
|
intro: '自定义配置外部输入,使用插件时,仅暴露自定义配置的输入',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
inputs: [],
|
inputs: [],
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const PluginOutputModule: FlowNodeTemplateType = {
|
|||||||
unique: true,
|
unique: true,
|
||||||
forbidDelete: true,
|
forbidDelete: true,
|
||||||
avatar: '/imgs/workflow/output.png',
|
avatar: '/imgs/workflow/output.png',
|
||||||
name: '定义插件输出',
|
name: '自定义插件输出',
|
||||||
intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出',
|
intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
inputs: [],
|
inputs: [],
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export const ToolModule: FlowNodeTemplateType = {
|
|||||||
sourceHandle: getHandleConfig(true, true, false, true),
|
sourceHandle: getHandleConfig(true, true, false, true),
|
||||||
targetHandle: getHandleConfig(true, true, false, true),
|
targetHandle: getHandleConfig(true, true, false, true),
|
||||||
avatar: '/imgs/workflow/tool.svg',
|
avatar: '/imgs/workflow/tool.svg',
|
||||||
name: '工具调用(实验)',
|
name: '工具调用(实验)',
|
||||||
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
inputs: [
|
inputs: [
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../../node/constant';
|
||||||
|
import { FlowNodeTemplateType } from '../../../type/index.d';
|
||||||
|
import {
|
||||||
|
FlowNodeTemplateTypeEnum,
|
||||||
|
NodeInputKeyEnum,
|
||||||
|
WorkflowIOValueTypeEnum
|
||||||
|
} from '../../../constants';
|
||||||
|
import { getHandleConfig } from '../../utils';
|
||||||
|
|
||||||
|
export const VariableUpdateNode: FlowNodeTemplateType = {
|
||||||
|
id: FlowNodeTypeEnum.variableUpdate,
|
||||||
|
templateType: FlowNodeTemplateTypeEnum.tools,
|
||||||
|
flowNodeType: FlowNodeTypeEnum.variableUpdate,
|
||||||
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
|
avatar: '/imgs/workflow/variable.png',
|
||||||
|
name: '变量更新',
|
||||||
|
intro: '可以更新指定节点的输出值或更新全局变量',
|
||||||
|
showStatus: true,
|
||||||
|
isTool: false,
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
key: NodeInputKeyEnum.updateList,
|
||||||
|
valueType: WorkflowIOValueTypeEnum.any,
|
||||||
|
label: '',
|
||||||
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
|
editField: {
|
||||||
|
key: true,
|
||||||
|
valueType: true
|
||||||
|
},
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
variable: ['', ''],
|
||||||
|
value: ['', ''],
|
||||||
|
valueType: WorkflowIOValueTypeEnum.string,
|
||||||
|
renderType: FlowNodeInputTypeEnum.input
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
outputs: []
|
||||||
|
};
|
||||||
10
packages/global/core/workflow/template/system/variableUpdate/type.d.ts
vendored
Normal file
10
packages/global/core/workflow/template/system/variableUpdate/type.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { FlowNodeInputTypeEnum } from '../../../node/constant';
|
||||||
|
import { ReferenceValueProps } from '../../..//type/io';
|
||||||
|
import { WorkflowIOValueTypeEnum } from '../../../constants';
|
||||||
|
|
||||||
|
export type TUpdateListItem = {
|
||||||
|
variable?: ReferenceValueProps;
|
||||||
|
value: ReferenceValueProps;
|
||||||
|
valueType?: WorkflowIOValueTypeEnum;
|
||||||
|
renderType: FlowNodeInputTypeEnum.input | FlowNodeInputTypeEnum.reference;
|
||||||
|
};
|
||||||
@@ -40,7 +40,7 @@ export type FlowNodeCommonType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type FlowNodeTemplateType = FlowNodeCommonType & {
|
export type FlowNodeTemplateType = FlowNodeCommonType & {
|
||||||
id: string; // module id, unique
|
id: string; // node id, unique
|
||||||
templateType: `${FlowNodeTemplateTypeEnum}`;
|
templateType: `${FlowNodeTemplateTypeEnum}`;
|
||||||
|
|
||||||
// show handle
|
// show handle
|
||||||
@@ -132,11 +132,12 @@ export type ChatDispatchProps = {
|
|||||||
chatId?: string;
|
chatId?: string;
|
||||||
responseChatItemId?: string;
|
responseChatItemId?: string;
|
||||||
histories: ChatItemType[];
|
histories: ChatItemType[];
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>; // global variable
|
||||||
inputFiles?: UserChatItemValueItemType['file'][];
|
query: UserChatItemValueItemType[]; // trigger query
|
||||||
stream: boolean;
|
stream: boolean;
|
||||||
detail: boolean; // response detail
|
detail: boolean; // response detail
|
||||||
maxRunTimes: number;
|
maxRunTimes: number;
|
||||||
|
isToolCall?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ModuleDispatchProps<T> = ChatDispatchProps & {
|
export type ModuleDispatchProps<T> = ChatDispatchProps & {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import type {
|
|||||||
} from '../app/type';
|
} from '../app/type';
|
||||||
import { EditorVariablePickerType } from '../../../web/components/common/Textarea/PromptEditor/type';
|
import { EditorVariablePickerType } from '../../../web/components/common/Textarea/PromptEditor/type';
|
||||||
import { defaultWhisperConfig } from '../app/constants';
|
import { defaultWhisperConfig } from '../app/constants';
|
||||||
|
import { IfElseResultEnum } from './template/system/ifElse/constant';
|
||||||
|
|
||||||
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
|
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
|
||||||
return `${nodeId}-${type}-${key}`;
|
return `${nodeId}-${type}-${key}`;
|
||||||
@@ -35,13 +36,17 @@ export const checkInputIsReference = (input: FlowNodeInputItemType) => {
|
|||||||
|
|
||||||
/* node */
|
/* node */
|
||||||
export const getGuideModule = (modules: StoreNodeItemType[]) =>
|
export const getGuideModule = (modules: StoreNodeItemType[]) =>
|
||||||
modules.find((item) => item.flowNodeType === FlowNodeTypeEnum.systemConfig);
|
modules.find(
|
||||||
|
(item) =>
|
||||||
|
item.flowNodeType === FlowNodeTypeEnum.systemConfig ||
|
||||||
|
// @ts-ignore (adapt v1)
|
||||||
|
item.flowType === FlowNodeTypeEnum.systemConfig
|
||||||
|
);
|
||||||
export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
|
export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
|
||||||
const welcomeText: string =
|
const welcomeText: string =
|
||||||
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.welcomeText)?.value || '';
|
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.welcomeText)?.value || '';
|
||||||
|
|
||||||
const variableModules: VariableItemType[] =
|
const variableNodes: VariableItemType[] =
|
||||||
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value || [];
|
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value || [];
|
||||||
|
|
||||||
const questionGuide: boolean =
|
const questionGuide: boolean =
|
||||||
@@ -62,13 +67,43 @@ export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
welcomeText,
|
welcomeText,
|
||||||
variableModules,
|
variableNodes,
|
||||||
questionGuide,
|
questionGuide,
|
||||||
ttsConfig,
|
ttsConfig,
|
||||||
whisperConfig,
|
whisperConfig,
|
||||||
scheduledTriggerConfig
|
scheduledTriggerConfig
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
export const replaceAppChatConfig = ({
|
||||||
|
node,
|
||||||
|
variableList,
|
||||||
|
welcomeText
|
||||||
|
}: {
|
||||||
|
node?: StoreNodeItemType;
|
||||||
|
variableList?: VariableItemType[];
|
||||||
|
welcomeText?: string;
|
||||||
|
}): StoreNodeItemType | undefined => {
|
||||||
|
if (!node) return;
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
inputs: node.inputs.map((input) => {
|
||||||
|
if (input.key === NodeInputKeyEnum.variables && variableList) {
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
value: variableList
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (input.key === NodeInputKeyEnum.welcomeText && welcomeText) {
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
value: welcomeText
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const getOrInitModuleInputValue = (input: FlowNodeInputItemType) => {
|
export const getOrInitModuleInputValue = (input: FlowNodeInputItemType) => {
|
||||||
if (input.value !== undefined || !input.valueType) return input.value;
|
if (input.value !== undefined || !input.valueType) return input.value;
|
||||||
@@ -132,3 +167,11 @@ export const formatEditorVariablePickerIcon = (
|
|||||||
icon: item.type ? variableMap[item.type]?.icon : variableMap['input'].icon
|
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';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getElseIFLabel = (i: number) => {
|
||||||
|
return i === 0 ? IfElseResultEnum.IF : `${IfElseResultEnum.ELSE_IF} ${i}`;
|
||||||
|
};
|
||||||
|
|||||||
@@ -28,6 +28,6 @@ try {
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MongoRwaTextBuffer: Model<RawTextBufferSchemaType> =
|
export const MongoRawTextBuffer: Model<RawTextBufferSchemaType> =
|
||||||
models[collectionName] || model(collectionName, RawTextBufferSchema);
|
models[collectionName] || model(collectionName, RawTextBufferSchema);
|
||||||
MongoRwaTextBuffer.syncIndexes();
|
MongoRawTextBuffer.syncIndexes();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { DatasetFileSchema } from '@fastgpt/global/core/dataset/type';
|
|||||||
import { MongoFileSchema } from './schema';
|
import { MongoFileSchema } from './schema';
|
||||||
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
||||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||||
import { MongoRwaTextBuffer } from '../../buffer/rawText/schema';
|
import { MongoRawTextBuffer } from '../../buffer/rawText/schema';
|
||||||
import { readFileRawContent } from '../read/utils';
|
import { readFileRawContent } from '../read/utils';
|
||||||
import { PassThrough } from 'stream';
|
import { PassThrough } from 'stream';
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ export const readFileContentFromMongo = async ({
|
|||||||
filename: string;
|
filename: string;
|
||||||
}> => {
|
}> => {
|
||||||
// read buffer
|
// read buffer
|
||||||
const fileBuffer = await MongoRwaTextBuffer.findOne({ sourceId: fileId }).lean();
|
const fileBuffer = await MongoRawTextBuffer.findOne({ sourceId: fileId }).lean();
|
||||||
if (fileBuffer) {
|
if (fileBuffer) {
|
||||||
return {
|
return {
|
||||||
rawText: fileBuffer.rawText,
|
rawText: fileBuffer.rawText,
|
||||||
@@ -208,7 +208,7 @@ export const readFileContentFromMongo = async ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (rawText.trim()) {
|
if (rawText.trim()) {
|
||||||
MongoRwaTextBuffer.create({
|
MongoRawTextBuffer.create({
|
||||||
sourceId: fileId,
|
sourceId: fileId,
|
||||||
rawText,
|
rawText,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { addLog } from '../../../common/system/log';
|
||||||
import { POST } from '../../../common/api/serverRequest';
|
import { POST } from '../../../common/api/serverRequest';
|
||||||
|
|
||||||
type PostReRankResponse = {
|
type PostReRankResponse = {
|
||||||
@@ -38,7 +39,11 @@ export function reRankRecall({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
console.log('rerank time:', Date.now() - start);
|
addLog.info('ReRank finish:', { time: Date.now() - start });
|
||||||
|
|
||||||
|
if (!data?.results || data?.results?.length === 0) {
|
||||||
|
addLog.error('ReRank error, empty result', data);
|
||||||
|
}
|
||||||
|
|
||||||
return data?.results?.map((item) => ({
|
return data?.results?.map((item) => ({
|
||||||
id: documents[item.index].id,
|
id: documents[item.index].id,
|
||||||
@@ -46,7 +51,7 @@ export function reRankRecall({
|
|||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log('rerank error:', err);
|
addLog.error('rerank error', err);
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -61,7 +61,15 @@ const ChatSchema = new Schema({
|
|||||||
outLinkUid: {
|
outLinkUid: {
|
||||||
type: String
|
type: String
|
||||||
},
|
},
|
||||||
|
|
||||||
|
variableList: {
|
||||||
|
type: Array
|
||||||
|
},
|
||||||
|
welcomeText: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
variables: {
|
variables: {
|
||||||
|
// variable value
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {}
|
default: {}
|
||||||
},
|
},
|
||||||
|
|||||||
1
packages/service/core/plugin/type.d.ts
vendored
1
packages/service/core/plugin/type.d.ts
vendored
@@ -1,5 +1,6 @@
|
|||||||
import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
|
import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
var communityPluginsV1: PluginTemplateType[];
|
||||||
var communityPlugins: PluginTemplateType[];
|
var communityPlugins: PluginTemplateType[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ export const runToolWithFunctionCall = async (
|
|||||||
|
|
||||||
const toolRunResponse = await dispatchWorkFlow({
|
const toolRunResponse = await dispatchWorkFlow({
|
||||||
...props,
|
...props,
|
||||||
|
isToolCall: true,
|
||||||
runtimeNodes: runtimeNodes.map((item) =>
|
runtimeNodes: runtimeNodes.map((item) =>
|
||||||
item.nodeId === toolNode.nodeId
|
item.nodeId === toolNode.nodeId
|
||||||
? {
|
? {
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ export const runToolWithPromptCall = async (
|
|||||||
|
|
||||||
const moduleRunResponse = await dispatchWorkFlow({
|
const moduleRunResponse = await dispatchWorkFlow({
|
||||||
...props,
|
...props,
|
||||||
|
isToolCall: true,
|
||||||
runtimeNodes: runtimeNodes.map((item) =>
|
runtimeNodes: runtimeNodes.map((item) =>
|
||||||
item.nodeId === toolNode.nodeId
|
item.nodeId === toolNode.nodeId
|
||||||
? {
|
? {
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ export const runToolWithToolChoice = async (
|
|||||||
|
|
||||||
const toolRunResponse = await dispatchWorkFlow({
|
const toolRunResponse = await dispatchWorkFlow({
|
||||||
...props,
|
...props,
|
||||||
|
isToolCall: true,
|
||||||
runtimeNodes: runtimeNodes.map((item) =>
|
runtimeNodes: runtimeNodes.map((item) =>
|
||||||
item.nodeId === toolNode.nodeId
|
item.nodeId === toolNode.nodeId
|
||||||
? {
|
? {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
} from '../../../../common/string/tiktoken/index';
|
} from '../../../../common/string/tiktoken/index';
|
||||||
import {
|
import {
|
||||||
chats2GPTMessages,
|
chats2GPTMessages,
|
||||||
|
chatValue2RuntimePrompt,
|
||||||
getSystemPrompt,
|
getSystemPrompt,
|
||||||
GPTMessages2Chats,
|
GPTMessages2Chats,
|
||||||
runtimePrompt2ChatsValue
|
runtimePrompt2ChatsValue
|
||||||
@@ -66,7 +67,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
user,
|
user,
|
||||||
histories,
|
histories,
|
||||||
node: { name },
|
node: { name },
|
||||||
inputFiles = [],
|
query,
|
||||||
params: {
|
params: {
|
||||||
model,
|
model,
|
||||||
temperature = 0,
|
temperature = 0,
|
||||||
@@ -80,6 +81,8 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
quotePrompt
|
quotePrompt
|
||||||
}
|
}
|
||||||
} = props;
|
} = props;
|
||||||
|
const { files: inputFiles } = chatValue2RuntimePrompt(query);
|
||||||
|
|
||||||
if (!userChatInput && inputFiles.length === 0) {
|
if (!userChatInput && inputFiles.length === 0) {
|
||||||
return Promise.reject('Question is empty');
|
return Promise.reject('Question is empty');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ import { dispatchLafRequest } from './tools/runLaf';
|
|||||||
import { dispatchIfElse } from './tools/runIfElse';
|
import { dispatchIfElse } from './tools/runIfElse';
|
||||||
import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||||
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { dispatchSystemConfig } from './init/systemConfiig';
|
import { dispatchSystemConfig } from './init/systemConfig';
|
||||||
|
import { dispatchUpdateVariable } from './tools/runUpdateVar';
|
||||||
|
|
||||||
const callbackMap: Record<`${FlowNodeTypeEnum}`, Function> = {
|
const callbackMap: Record<`${FlowNodeTypeEnum}`, Function> = {
|
||||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||||
@@ -62,6 +63,7 @@ const callbackMap: Record<`${FlowNodeTypeEnum}`, Function> = {
|
|||||||
[FlowNodeTypeEnum.stopTool]: dispatchStopToolCall,
|
[FlowNodeTypeEnum.stopTool]: dispatchStopToolCall,
|
||||||
[FlowNodeTypeEnum.lafModule]: dispatchLafRequest,
|
[FlowNodeTypeEnum.lafModule]: dispatchLafRequest,
|
||||||
[FlowNodeTypeEnum.ifElseNode]: dispatchIfElse,
|
[FlowNodeTypeEnum.ifElseNode]: dispatchIfElse,
|
||||||
|
[FlowNodeTypeEnum.variableUpdate]: dispatchUpdateVariable,
|
||||||
|
|
||||||
// none
|
// none
|
||||||
[FlowNodeTypeEnum.systemConfig]: dispatchSystemConfig,
|
[FlowNodeTypeEnum.systemConfig]: dispatchSystemConfig,
|
||||||
@@ -69,21 +71,25 @@ const callbackMap: Record<`${FlowNodeTypeEnum}`, Function> = {
|
|||||||
[FlowNodeTypeEnum.globalVariable]: () => Promise.resolve()
|
[FlowNodeTypeEnum.globalVariable]: () => Promise.resolve()
|
||||||
};
|
};
|
||||||
|
|
||||||
/* running */
|
type Props = ChatDispatchProps & {
|
||||||
export async function dispatchWorkFlow({
|
|
||||||
res,
|
|
||||||
runtimeNodes = [],
|
|
||||||
runtimeEdges = [],
|
|
||||||
histories = [],
|
|
||||||
variables = {},
|
|
||||||
user,
|
|
||||||
stream = false,
|
|
||||||
detail = false,
|
|
||||||
...props
|
|
||||||
}: ChatDispatchProps & {
|
|
||||||
runtimeNodes: RuntimeNodeItemType[];
|
runtimeNodes: RuntimeNodeItemType[];
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
}): Promise<DispatchFlowResponse> {
|
};
|
||||||
|
|
||||||
|
/* running */
|
||||||
|
export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowResponse> {
|
||||||
|
let {
|
||||||
|
res,
|
||||||
|
runtimeNodes = [],
|
||||||
|
runtimeEdges = [],
|
||||||
|
histories = [],
|
||||||
|
variables = {},
|
||||||
|
user,
|
||||||
|
stream = false,
|
||||||
|
detail = false,
|
||||||
|
...props
|
||||||
|
} = data;
|
||||||
|
|
||||||
// set sse response headers
|
// set sse response headers
|
||||||
if (stream && res) {
|
if (stream && res) {
|
||||||
res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');
|
res.setHeader('Content-Type', 'text/event-stream;charset=utf-8');
|
||||||
@@ -93,7 +99,7 @@ export async function dispatchWorkFlow({
|
|||||||
}
|
}
|
||||||
|
|
||||||
variables = {
|
variables = {
|
||||||
...getSystemVariable({ timezone: user.timezone }),
|
...getSystemVariable(data),
|
||||||
...variables
|
...variables
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -283,7 +289,8 @@ export async function dispatchWorkFlow({
|
|||||||
node,
|
node,
|
||||||
runtimeNodes,
|
runtimeNodes,
|
||||||
runtimeEdges,
|
runtimeEdges,
|
||||||
params
|
params,
|
||||||
|
mode: props.mode === 'debug' ? 'test' : props.mode
|
||||||
};
|
};
|
||||||
|
|
||||||
// run module
|
// run module
|
||||||
@@ -362,7 +369,8 @@ export async function dispatchWorkFlow({
|
|||||||
},
|
},
|
||||||
[DispatchNodeResponseKeyEnum.assistantResponses]:
|
[DispatchNodeResponseKeyEnum.assistantResponses]:
|
||||||
mergeAssistantResponseAnswerText(chatAssistantResponse),
|
mergeAssistantResponseAnswerText(chatAssistantResponse),
|
||||||
[DispatchNodeResponseKeyEnum.toolResponses]: toolRunResponse
|
[DispatchNodeResponseKeyEnum.toolResponses]: toolRunResponse,
|
||||||
|
newVariables: removeSystemVariable(variables)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,12 +392,34 @@ export function responseStatus({
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* get system variable */
|
/* get system variable */
|
||||||
export function getSystemVariable({ timezone }: { timezone: string }) {
|
export function getSystemVariable({
|
||||||
|
user,
|
||||||
|
appId,
|
||||||
|
chatId,
|
||||||
|
responseChatItemId,
|
||||||
|
histories = []
|
||||||
|
}: Props) {
|
||||||
return {
|
return {
|
||||||
cTime: getSystemTime(timezone)
|
appId,
|
||||||
|
chatId,
|
||||||
|
responseChatItemId,
|
||||||
|
histories,
|
||||||
|
cTime: getSystemTime(user.timezone)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
/* Merge consecutive text messages into one */
|
||||||
export const mergeAssistantResponseAnswerText = (response: AIChatItemValueItemType[]) => {
|
export const mergeAssistantResponseAnswerText = (response: AIChatItemValueItemType[]) => {
|
||||||
const result: AIChatItemValueItemType[] = [];
|
const result: AIChatItemValueItemType[] = [];
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export const dispatchSystemConfig = (props: Record<string, any>) => {
|
||||||
|
const { variables } = props;
|
||||||
|
return variables;
|
||||||
|
};
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
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;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export const dispatchSystemConfig = (props: Record<string, any>) => {
|
|
||||||
const { variables } = props as UserChatInputProps;
|
|
||||||
return variables;
|
|
||||||
};
|
|
||||||
@@ -1,15 +1,22 @@
|
|||||||
|
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 { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||||
export type UserChatInputProps = ModuleDispatchProps<{
|
export type UserChatInputProps = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.userChatInput]: string;
|
[NodeInputKeyEnum.userChatInput]: string;
|
||||||
|
[NodeInputKeyEnum.inputFiles]: UserChatItemValueItemType['file'][];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export const dispatchWorkflowStart = (props: Record<string, any>) => {
|
export const dispatchWorkflowStart = (props: Record<string, any>) => {
|
||||||
const {
|
const {
|
||||||
variables: { userChatInput },
|
query,
|
||||||
params: { userChatInput: query }
|
params: { userChatInput }
|
||||||
} = props as UserChatInputProps;
|
} = props as UserChatInputProps;
|
||||||
|
|
||||||
|
const { text, files } = chatValue2RuntimePrompt(query);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userChatInput: query || userChatInput
|
[NodeInputKeyEnum.userChatInput]: text || userChatInput,
|
||||||
|
[NodeInputKeyEnum.inputFiles]: files
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type/index.d';
|
||||||
import { dispatchWorkFlow } from '../index';
|
import { dispatchWorkFlow } from '../index';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
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 { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { getPluginRuntimeById } from '../../../plugin/controller';
|
import { getPluginRuntimeById } from '../../../plugin/controller';
|
||||||
import { authPluginCanUse } from '../../../../support/permission/auth/plugin';
|
import { authPluginCanUse } from '../../../../support/permission/auth/plugin';
|
||||||
|
|||||||
@@ -45,10 +45,12 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
|||||||
detail,
|
detail,
|
||||||
appId,
|
appId,
|
||||||
chatId,
|
chatId,
|
||||||
|
stream,
|
||||||
responseChatItemId,
|
responseChatItemId,
|
||||||
variables,
|
variables,
|
||||||
node: { outputs },
|
node: { outputs },
|
||||||
histories,
|
histories,
|
||||||
|
isToolCall,
|
||||||
params: {
|
params: {
|
||||||
system_httpMethod: httpMethod = 'POST',
|
system_httpMethod: httpMethod = 'POST',
|
||||||
system_httpReqUrl: httpReqUrl,
|
system_httpReqUrl: httpReqUrl,
|
||||||
@@ -131,7 +133,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
|||||||
results[key] = valueTypeFormat(formatResponse[key], output.valueType);
|
results[key] = valueTypeFormat(formatResponse[key], output.valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof formatResponse[NodeOutputKeyEnum.answerText] === 'string') {
|
if (stream && typeof formatResponse[NodeOutputKeyEnum.answerText] === 'string') {
|
||||||
responseWrite({
|
responseWrite({
|
||||||
res,
|
res,
|
||||||
event: detail ? SseResponseEventEnum.fastAnswer : undefined,
|
event: detail ? SseResponseEventEnum.fastAnswer : undefined,
|
||||||
@@ -156,17 +158,21 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
|||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addLog.error('Http request error', error);
|
addLog.error('Http request error', error);
|
||||||
return {
|
|
||||||
[NodeOutputKeyEnum.failed]: true,
|
if (isToolCall) {
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
return {
|
||||||
totalPoints: 0,
|
[NodeOutputKeyEnum.failed]: true,
|
||||||
params: Object.keys(params).length > 0 ? params : undefined,
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
body: Object.keys(requestBody).length > 0 ? requestBody : undefined,
|
totalPoints: 0,
|
||||||
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
params: Object.keys(params).length > 0 ? params : undefined,
|
||||||
httpResult: { error: formatHttpError(error) }
|
body: Object.keys(requestBody).length > 0 ? requestBody : undefined,
|
||||||
},
|
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
||||||
[NodeOutputKeyEnum.httpRawResponse]: getErrText(error)
|
httpResult: { error: formatHttpError(error) }
|
||||||
};
|
},
|
||||||
|
[NodeOutputKeyEnum.httpRawResponse]: getErrText(error)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
|
|||||||
stream,
|
stream,
|
||||||
detail,
|
detail,
|
||||||
histories,
|
histories,
|
||||||
inputFiles,
|
query,
|
||||||
params: { userChatInput, history, app }
|
params: { userChatInput, history, app }
|
||||||
} = props;
|
} = props;
|
||||||
let start = Date.now();
|
let start = Date.now();
|
||||||
@@ -71,7 +71,7 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
|
|||||||
runtimeNodes: storeNodes2RuntimeNodes(appData.modules, getDefaultEntryNodeIds(appData.modules)),
|
runtimeNodes: storeNodes2RuntimeNodes(appData.modules, getDefaultEntryNodeIds(appData.modules)),
|
||||||
runtimeEdges: initWorkflowEdgeStatus(appData.edges),
|
runtimeEdges: initWorkflowEdgeStatus(appData.edges),
|
||||||
histories: chatHistories,
|
histories: chatHistories,
|
||||||
inputFiles,
|
query,
|
||||||
variables: {
|
variables: {
|
||||||
...props.variables,
|
...props.variables,
|
||||||
userChatInput
|
userChatInput
|
||||||
@@ -81,10 +81,7 @@ export const dispatchAppRequest = async (props: Props): Promise<Response> => {
|
|||||||
const completeMessages = chatHistories.concat([
|
const completeMessages = chatHistories.concat([
|
||||||
{
|
{
|
||||||
obj: ChatRoleEnum.Human,
|
obj: ChatRoleEnum.Human,
|
||||||
value: runtimePrompt2ChatsValue({
|
value: query
|
||||||
files: inputFiles,
|
|
||||||
text: userChatInput
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
obj: ChatRoleEnum.AI,
|
obj: ChatRoleEnum.AI,
|
||||||
|
|||||||
@@ -1,34 +1,76 @@
|
|||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { VariableConditionEnum } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
|
||||||
import {
|
import {
|
||||||
|
IfElseResultEnum,
|
||||||
|
VariableConditionEnum
|
||||||
|
} from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
||||||
|
import {
|
||||||
|
ConditionListItemType,
|
||||||
IfElseConditionType,
|
IfElseConditionType,
|
||||||
IfElseListItemType
|
IfElseListItemType
|
||||||
} from '@fastgpt/global/core/workflow/template/system/ifElse/type';
|
} from '@fastgpt/global/core/workflow/template/system/ifElse/type';
|
||||||
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
import { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
import { getElseIFLabel, getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
|
|
||||||
type Props = ModuleDispatchProps<{
|
type Props = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.condition]: IfElseConditionType;
|
[NodeInputKeyEnum.condition]: IfElseConditionType;
|
||||||
[NodeInputKeyEnum.ifElseList]: IfElseListItemType[];
|
[NodeInputKeyEnum.ifElseList]: IfElseListItemType[];
|
||||||
}>;
|
}>;
|
||||||
|
type Response = DispatchNodeResultType<{
|
||||||
|
[NodeOutputKeyEnum.ifElseResult]: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
function isEmpty(value: any) {
|
||||||
|
return (
|
||||||
|
// 检查未定义或null值
|
||||||
|
value === undefined ||
|
||||||
|
value === null ||
|
||||||
|
// 检查空字符串
|
||||||
|
(typeof value === 'string' && value.trim() === '') ||
|
||||||
|
// 检查NaN
|
||||||
|
(typeof value === 'number' && isNaN(value)) ||
|
||||||
|
// 检查空数组
|
||||||
|
(Array.isArray(value) && value.length === 0) ||
|
||||||
|
// 检查空对象
|
||||||
|
(typeof value === 'object' && Object.keys(value).length === 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInclude(value: any, target: any) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((item: any) => String(item)).includes(target);
|
||||||
|
} else if (typeof value === 'string') {
|
||||||
|
return value.includes(target);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkCondition(condition: VariableConditionEnum, variableValue: any, value: string) {
|
function checkCondition(condition: VariableConditionEnum, variableValue: any, value: string) {
|
||||||
const operations = {
|
const operations = {
|
||||||
[VariableConditionEnum.isEmpty]: () => !variableValue,
|
[VariableConditionEnum.isEmpty]: () => isEmpty(variableValue),
|
||||||
[VariableConditionEnum.isNotEmpty]: () => !!variableValue,
|
[VariableConditionEnum.isNotEmpty]: () => !isEmpty(variableValue),
|
||||||
[VariableConditionEnum.equalTo]: () => variableValue === value,
|
|
||||||
[VariableConditionEnum.notEqual]: () => variableValue !== value,
|
[VariableConditionEnum.equalTo]: () => String(variableValue) === value,
|
||||||
|
[VariableConditionEnum.notEqual]: () => String(variableValue) !== value,
|
||||||
|
|
||||||
|
// number
|
||||||
[VariableConditionEnum.greaterThan]: () => Number(variableValue) > Number(value),
|
[VariableConditionEnum.greaterThan]: () => Number(variableValue) > Number(value),
|
||||||
[VariableConditionEnum.lessThan]: () => Number(variableValue) < Number(value),
|
[VariableConditionEnum.lessThan]: () => Number(variableValue) < Number(value),
|
||||||
[VariableConditionEnum.greaterThanOrEqualTo]: () => Number(variableValue) >= Number(value),
|
[VariableConditionEnum.greaterThanOrEqualTo]: () => Number(variableValue) >= Number(value),
|
||||||
[VariableConditionEnum.lessThanOrEqualTo]: () => Number(variableValue) <= Number(value),
|
[VariableConditionEnum.lessThanOrEqualTo]: () => Number(variableValue) <= Number(value),
|
||||||
[VariableConditionEnum.include]: () => variableValue?.includes(value),
|
|
||||||
[VariableConditionEnum.notInclude]: () => !variableValue?.includes(value),
|
// array or string
|
||||||
|
[VariableConditionEnum.include]: () => isInclude(variableValue, value),
|
||||||
|
[VariableConditionEnum.notInclude]: () => !isInclude(variableValue, value),
|
||||||
|
|
||||||
|
// string
|
||||||
[VariableConditionEnum.startWith]: () => variableValue?.startsWith(value),
|
[VariableConditionEnum.startWith]: () => variableValue?.startsWith(value),
|
||||||
[VariableConditionEnum.endWith]: () => variableValue?.endsWith(value),
|
[VariableConditionEnum.endWith]: () => variableValue?.endsWith(value),
|
||||||
|
|
||||||
|
// array
|
||||||
[VariableConditionEnum.lengthEqualTo]: () => variableValue?.length === Number(value),
|
[VariableConditionEnum.lengthEqualTo]: () => variableValue?.length === Number(value),
|
||||||
[VariableConditionEnum.lengthNotEqualTo]: () => variableValue?.length !== Number(value),
|
[VariableConditionEnum.lengthNotEqualTo]: () => variableValue?.length !== Number(value),
|
||||||
[VariableConditionEnum.lengthGreaterThan]: () => variableValue?.length > Number(value),
|
[VariableConditionEnum.lengthGreaterThan]: () => variableValue?.length > Number(value),
|
||||||
@@ -41,15 +83,13 @@ function checkCondition(condition: VariableConditionEnum, variableValue: any, va
|
|||||||
return (operations[condition] || (() => false))();
|
return (operations[condition] || (() => false))();
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dispatchIfElse = async (props: Props): Promise<DispatchNodeResultType<{}>> => {
|
function getResult(
|
||||||
const {
|
condition: IfElseConditionType,
|
||||||
params,
|
list: ConditionListItemType[],
|
||||||
runtimeNodes,
|
variables: any,
|
||||||
variables,
|
runtimeNodes: any[]
|
||||||
node: { nodeId }
|
) {
|
||||||
} = props;
|
const listResult = list.map((item) => {
|
||||||
const { condition, ifElseList } = params;
|
|
||||||
const listResult = ifElseList.map((item) => {
|
|
||||||
const { variable, condition: variableCondition, value } = item;
|
const { variable, condition: variableCondition, value } = item;
|
||||||
|
|
||||||
const variableValue = getReferenceVariableValue({
|
const variableValue = getReferenceVariableValue({
|
||||||
@@ -61,15 +101,41 @@ export const dispatchIfElse = async (props: Props): Promise<DispatchNodeResultTy
|
|||||||
return checkCondition(variableCondition as VariableConditionEnum, variableValue, value || '');
|
return checkCondition(variableCondition as VariableConditionEnum, variableValue, value || '');
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = condition === 'AND' ? listResult.every(Boolean) : listResult.some(Boolean);
|
return condition === 'AND' ? listResult.every(Boolean) : listResult.some(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dispatchIfElse = async (props: Props): Promise<Response> => {
|
||||||
|
const {
|
||||||
|
params,
|
||||||
|
runtimeNodes,
|
||||||
|
variables,
|
||||||
|
node: { nodeId }
|
||||||
|
} = props;
|
||||||
|
const { ifElseList } = params;
|
||||||
|
|
||||||
|
let res = IfElseResultEnum.ELSE as string;
|
||||||
|
for (let i = 0; i < ifElseList.length; i++) {
|
||||||
|
const item = ifElseList[i];
|
||||||
|
const result = getResult(item.condition, item.list, variables, runtimeNodes);
|
||||||
|
if (result) {
|
||||||
|
res = getElseIFLabel(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resArray = Array.from({ length: ifElseList.length + 1 }, (_, index) => {
|
||||||
|
const label = index < ifElseList.length ? getElseIFLabel(index) : IfElseResultEnum.ELSE;
|
||||||
|
return getHandleId(nodeId, 'source', label);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
[NodeOutputKeyEnum.ifElseResult]: res,
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
totalPoints: 0,
|
totalPoints: 0,
|
||||||
ifElseResult: result ? 'IF' : 'ELSE'
|
ifElseResult: res
|
||||||
},
|
},
|
||||||
[DispatchNodeResponseKeyEnum.skipHandleId]: result
|
[DispatchNodeResponseKeyEnum.skipHandleId]: resArray.filter(
|
||||||
? [getHandleId(nodeId, 'source', 'ELSE')]
|
(item) => item !== getHandleId(nodeId, 'source', res)
|
||||||
: [getHandleId(nodeId, 'source', 'IF')]
|
)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { NodeInputKeyEnum, VARIABLE_NODE_ID } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
|
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
|
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[];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export const dispatchUpdateVariable = async (
|
||||||
|
props: Props
|
||||||
|
): Promise<DispatchNodeResultType<any>> => {
|
||||||
|
const { params, variables, runtimeNodes } = props;
|
||||||
|
|
||||||
|
const { updateList } = params;
|
||||||
|
updateList.forEach((item) => {
|
||||||
|
const varNodeId = item.variable?.[0];
|
||||||
|
const varKey = item.variable?.[1];
|
||||||
|
|
||||||
|
if (!varNodeId || !varKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
runtimeNodes
|
||||||
|
.find((node) => node.nodeId === varNodeId)
|
||||||
|
?.outputs?.find((output) => {
|
||||||
|
if (output.id === varKey) {
|
||||||
|
output.value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
|
totalPoints: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -19,4 +19,5 @@ export type DispatchFlowResponse = {
|
|||||||
};
|
};
|
||||||
[DispatchNodeResponseKeyEnum.toolResponses]: ToolRunResponseItemType;
|
[DispatchNodeResponseKeyEnum.toolResponses]: ToolRunResponseItemType;
|
||||||
[DispatchNodeResponseKeyEnum.assistantResponses]: AIChatItemValueItemType[];
|
[DispatchNodeResponseKeyEnum.assistantResponses]: AIChatItemValueItemType[];
|
||||||
|
newVariables: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export const filterToolNodeIdByEdges = ({
|
|||||||
|
|
||||||
export const getHistories = (history?: ChatItemType[] | number, histories: ChatItemType[] = []) => {
|
export const getHistories = (history?: ChatItemType[] | number, histories: ChatItemType[] = []) => {
|
||||||
if (!history) return [];
|
if (!history) return [];
|
||||||
if (typeof history === 'number') return histories.slice(-history);
|
if (typeof history === 'number') return histories.slice(-(history * 2));
|
||||||
if (Array.isArray(history)) return history;
|
if (Array.isArray(history)) return history;
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ export async function dispatchWorkFlowV1({
|
|||||||
)?.targets?.length;
|
)?.targets?.length;
|
||||||
|
|
||||||
return moduleOutput(module, {
|
return moduleOutput(module, {
|
||||||
[NodeOutputKeyEnum.finish]: true,
|
finish: true,
|
||||||
[NodeOutputKeyEnum.userChatInput]: hasUserChatInputTarget
|
[NodeOutputKeyEnum.userChatInput]: hasUserChatInputTarget
|
||||||
? params[NodeOutputKeyEnum.userChatInput]
|
? params[NodeOutputKeyEnum.userChatInput]
|
||||||
: undefined,
|
: undefined,
|
||||||
@@ -295,7 +295,7 @@ export async function dispatchWorkFlowV1({
|
|||||||
modules.forEach((item) => {
|
modules.forEach((item) => {
|
||||||
item.isEntry = false;
|
item.isEntry = false;
|
||||||
});
|
});
|
||||||
|
// console.log(JSON.stringify(runningModules, null, 2));
|
||||||
initModules.map((module) =>
|
initModules.map((module) =>
|
||||||
moduleInput(module, {
|
moduleInput(module, {
|
||||||
...startParams,
|
...startParams,
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/type';
|
||||||
import { dispatchWorkFlowV1 } from '../index';
|
import { dispatchWorkFlowV1 } from '../index';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import {
|
||||||
|
FlowNodeTemplateTypeEnum,
|
||||||
|
NodeInputKeyEnum
|
||||||
|
} from '@fastgpt/global/core/workflow/constants';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { getPluginRuntimeById } from '../../../plugin/controller';
|
import { splitCombinePluginId } from '../../../plugin/controller';
|
||||||
import { authPluginCanUse } from '../../../../support/permission/auth/plugin';
|
import { authPluginCanUse } from '../../../../support/permission/auth/plugin';
|
||||||
import { setEntryEntries, DYNAMIC_INPUT_KEY } from '../utils';
|
import { setEntryEntries, DYNAMIC_INPUT_KEY } from '../utils';
|
||||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
|
import { PluginRuntimeType, PluginTemplateType } from '@fastgpt/global/core/plugin/type';
|
||||||
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
|
import { MongoPlugin } from '../../../plugin/schema';
|
||||||
|
|
||||||
type RunPluginProps = ModuleDispatchProps<{
|
type RunPluginProps = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.pluginId]: string;
|
[NodeInputKeyEnum.pluginId]: string;
|
||||||
@@ -15,6 +22,45 @@ type RunPluginProps = ModuleDispatchProps<{
|
|||||||
}>;
|
}>;
|
||||||
type RunPluginResponse = DispatchNodeResultType<{}>;
|
type RunPluginResponse = DispatchNodeResultType<{}>;
|
||||||
|
|
||||||
|
const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> => {
|
||||||
|
const { source, pluginId } = await splitCombinePluginId(id);
|
||||||
|
if (source === PluginSourceEnum.community) {
|
||||||
|
const item = global.communityPluginsV1?.find((plugin) => plugin.id === pluginId);
|
||||||
|
|
||||||
|
if (!item) return Promise.reject('plugin not found');
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
if (source === PluginSourceEnum.personal) {
|
||||||
|
const item = await MongoPlugin.findById(id).lean();
|
||||||
|
if (!item) return Promise.reject('plugin not found');
|
||||||
|
return {
|
||||||
|
id: String(item._id),
|
||||||
|
teamId: String(item.teamId),
|
||||||
|
name: item.name,
|
||||||
|
avatar: item.avatar,
|
||||||
|
intro: item.intro,
|
||||||
|
showStatus: true,
|
||||||
|
source: PluginSourceEnum.personal,
|
||||||
|
modules: item.modules,
|
||||||
|
templateType: FlowNodeTemplateTypeEnum.personalPlugin
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Promise.reject('plugin not found');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPluginRuntimeById = async (id: string): Promise<PluginRuntimeType> => {
|
||||||
|
const plugin = await getPluginTemplateById(id);
|
||||||
|
|
||||||
|
return {
|
||||||
|
teamId: plugin.teamId,
|
||||||
|
name: plugin.name,
|
||||||
|
avatar: plugin.avatar,
|
||||||
|
showStatus: plugin.showStatus,
|
||||||
|
modules: plugin.modules
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPluginResponse> => {
|
export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPluginResponse> => {
|
||||||
const {
|
const {
|
||||||
mode,
|
mode,
|
||||||
@@ -31,7 +77,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
|||||||
const plugin = await getPluginRuntimeById(pluginId);
|
const plugin = await getPluginRuntimeById(pluginId);
|
||||||
|
|
||||||
// concat dynamic inputs
|
// concat dynamic inputs
|
||||||
const inputModule = plugin.nodes.find((item) => item.flowType === FlowNodeTypeEnum.pluginInput);
|
const inputModule = plugin.modules.find((item) => item.flowType === FlowNodeTypeEnum.pluginInput);
|
||||||
if (!inputModule) return Promise.reject('Plugin error, It has no set input.');
|
if (!inputModule) return Promise.reject('Plugin error, It has no set input.');
|
||||||
const hasDynamicInput = inputModule.inputs.find((input) => input.key === DYNAMIC_INPUT_KEY);
|
const hasDynamicInput = inputModule.inputs.find((input) => input.key === DYNAMIC_INPUT_KEY);
|
||||||
|
|
||||||
@@ -56,7 +102,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
|||||||
|
|
||||||
const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlowV1({
|
const { flowResponses, flowUsages, assistantResponses } = await dispatchWorkFlowV1({
|
||||||
...props,
|
...props,
|
||||||
modules: setEntryEntries(plugin.nodes).map((module) => ({
|
modules: setEntryEntries(plugin.modules).map((module) => ({
|
||||||
...module,
|
...module,
|
||||||
showStatus: false
|
showStatus: false
|
||||||
})),
|
})),
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ export const dispatchAnswer = (props: Record<string, any>): AnswerResponse => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[NodeOutputKeyEnum.answerText]: formatText
|
[NodeOutputKeyEnum.answerText]: `\n${formatText}`
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,4 +12,5 @@ export type DispatchFlowResponse = {
|
|||||||
flowUsages: ChatNodeUsageType[];
|
flowUsages: ChatNodeUsageType[];
|
||||||
[DispatchNodeResponseKeyEnum.toolResponses]: ToolRunResponseItemType;
|
[DispatchNodeResponseKeyEnum.toolResponses]: ToolRunResponseItemType;
|
||||||
[DispatchNodeResponseKeyEnum.assistantResponses]: AIChatItemValueItemType[];
|
[DispatchNodeResponseKeyEnum.assistantResponses]: AIChatItemValueItemType[];
|
||||||
|
newVariables: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ export async function getUserDetail({
|
|||||||
}): Promise<UserType> {
|
}): Promise<UserType> {
|
||||||
const tmb = await (async () => {
|
const tmb = await (async () => {
|
||||||
if (tmbId) {
|
if (tmbId) {
|
||||||
return getTmbInfoByTmbId({ tmbId });
|
try {
|
||||||
|
const result = await getTmbInfoByTmbId({ tmbId });
|
||||||
|
return result;
|
||||||
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
if (userId) {
|
if (userId) {
|
||||||
return getUserDefaultTeam({ userId });
|
return getUserDefaultTeam({ userId });
|
||||||
|
|||||||
@@ -44,9 +44,13 @@ const parsePowerPoint = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returning an array of all the xml contents read using fs.readFileSync
|
// Returning an array of all the xml contents read using fs.readFileSync
|
||||||
const xmlContentArray = files.map((file) =>
|
const xmlContentArray = files.map((file) => {
|
||||||
fs.readFileSync(`${decompressPath}/${file.path}`, encoding)
|
try {
|
||||||
);
|
return fs.readFileSync(`${decompressPath}/${file.path}`, encoding);
|
||||||
|
} catch (err) {
|
||||||
|
return fs.readFileSync(`${decompressPath}/${file.path}`, 'utf-8');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let responseArr: string[] = [];
|
let responseArr: string[] = [];
|
||||||
|
|
||||||
@@ -95,9 +99,15 @@ export const parseOffice = async ({
|
|||||||
// const decompressPath = `${DEFAULTDECOMPRESSSUBLOCATION}/test`;
|
// const decompressPath = `${DEFAULTDECOMPRESSSUBLOCATION}/test`;
|
||||||
|
|
||||||
// write new file
|
// write new file
|
||||||
fs.writeFileSync(filepath, buffer, {
|
try {
|
||||||
encoding
|
fs.writeFileSync(filepath, buffer, {
|
||||||
});
|
encoding
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
fs.writeFileSync(filepath, buffer, {
|
||||||
|
encoding: 'utf-8'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const text = await (async () => {
|
const text = await (async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
14
packages/web/components/common/DndDrag/DragIcon.tsx
Normal file
14
packages/web/components/common/DndDrag/DragIcon.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { DragHandleIcon } from '@chakra-ui/icons';
|
||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { DraggableProvided } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
|
const DragIcon = ({ provided }: { provided: DraggableProvided }) => {
|
||||||
|
return (
|
||||||
|
<Box {...provided.dragHandleProps}>
|
||||||
|
<DragHandleIcon color={'myGray.500'} _hover={{ color: 'primary.600' }} />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DragIcon;
|
||||||
61
packages/web/components/common/DndDrag/index.tsx
Normal file
61
packages/web/components/common/DndDrag/index.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
DragDropContext,
|
||||||
|
DroppableProps,
|
||||||
|
Droppable,
|
||||||
|
DraggableChildrenFn,
|
||||||
|
DragStart,
|
||||||
|
DropResult
|
||||||
|
} from 'react-beautiful-dnd';
|
||||||
|
|
||||||
|
type Props<T = any> = {
|
||||||
|
onDragEndCb: (result: T[]) => void;
|
||||||
|
renderClone?: DraggableChildrenFn;
|
||||||
|
children: DroppableProps['children'];
|
||||||
|
dataList: T[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function DndDrag<T>({ children, renderClone, onDragEndCb, dataList }: Props<T>) {
|
||||||
|
const [draggingItemHeight, setDraggingItemHeight] = useState(0);
|
||||||
|
|
||||||
|
const onDragStart = (start: DragStart) => {
|
||||||
|
const draggingNode = document.querySelector(`[data-rbd-draggable-id="${start.draggableId}"]`);
|
||||||
|
setDraggingItemHeight(draggingNode?.getBoundingClientRect().height || 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDragEnd = (result: DropResult) => {
|
||||||
|
if (!result.destination) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setDraggingItemHeight(0);
|
||||||
|
|
||||||
|
const startIndex = result.source.index;
|
||||||
|
const endIndex = result.destination.index;
|
||||||
|
|
||||||
|
const list = Array.from(dataList);
|
||||||
|
const [removed] = list.splice(startIndex, 1);
|
||||||
|
list.splice(endIndex, 0, removed);
|
||||||
|
|
||||||
|
onDragEndCb(list);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
|
||||||
|
<Droppable droppableId="droppable" renderClone={renderClone}>
|
||||||
|
{(provided, snapshot) => {
|
||||||
|
return (
|
||||||
|
<Box {...provided.droppableProps} ref={provided.innerRef}>
|
||||||
|
{children(provided, snapshot)}
|
||||||
|
{snapshot.isDraggingOver && <Box height={draggingItemHeight} />}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Droppable>
|
||||||
|
</DragDropContext>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DndDrag;
|
||||||
|
|
||||||
|
export * from 'react-beautiful-dnd';
|
||||||
@@ -8,13 +8,15 @@ export const useBeforeunload = (props?: { callback?: () => any; tip?: string })
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const listen =
|
const listen =
|
||||||
process.env.NODE_ENV !== 'production'
|
process.env.NODE_ENV === 'production'
|
||||||
? (e: any) => {
|
? (e: any) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.returnValue = tip;
|
e.returnValue = tip;
|
||||||
callback?.();
|
callback?.();
|
||||||
}
|
}
|
||||||
: () => {};
|
: () => {
|
||||||
|
callback?.();
|
||||||
|
};
|
||||||
window.addEventListener('beforeunload', listen);
|
window.addEventListener('beforeunload', listen);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -92,9 +92,9 @@ export const useEditTextarea = ({
|
|||||||
closeBtnText?: string;
|
closeBtnText?: string;
|
||||||
}) => (
|
}) => (
|
||||||
<MyModal isOpen={isOpen} onClose={onClose} iconSrc={iconSrc} title={title} maxW={'500px'}>
|
<MyModal isOpen={isOpen} onClose={onClose} iconSrc={iconSrc} title={title} maxW={'500px'}>
|
||||||
<ModalBody>
|
<ModalBody pt={tip ? '3 !important' : '5 !important'}>
|
||||||
{!!tip && (
|
{!!tip && (
|
||||||
<Box mb={2} color={'myGray.500'} fontSize={'sm'}>
|
<Box mb={3} color={'myGray.500'} fontSize={'sm'}>
|
||||||
{tip}
|
{tip}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -31,12 +31,14 @@
|
|||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-day-picker": "^8.7.1",
|
"react-day-picker": "^8.7.1",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-i18next": "13.5.0"
|
"react-i18next": "13.5.0",
|
||||||
|
"react-beautiful-dnd": "^13.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash": "^4.14.191",
|
"@types/lodash": "^4.14.191",
|
||||||
"@types/papaparse": "^5.3.7",
|
"@types/papaparse": "^5.3.7",
|
||||||
"@types/react": "18.2.0",
|
"@types/react": "18.2.0",
|
||||||
"@types/react-dom": "18.2.0"
|
"@types/react-dom": "18.2.0",
|
||||||
|
"@types/react-beautiful-dnd": "^13.1.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
120
pnpm-lock.yaml
generated
120
pnpm-lock.yaml
generated
@@ -292,6 +292,9 @@ importers:
|
|||||||
react:
|
react:
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
|
react-beautiful-dnd:
|
||||||
|
specifier: ^13.1.1
|
||||||
|
version: 13.1.1(react-dom@18.2.0)(react@18.2.0)
|
||||||
react-day-picker:
|
react-day-picker:
|
||||||
specifier: ^8.7.1
|
specifier: ^8.7.1
|
||||||
version: 8.7.1(date-fns@2.30.0)(react@18.2.0)
|
version: 8.7.1(date-fns@2.30.0)(react@18.2.0)
|
||||||
@@ -311,6 +314,9 @@ importers:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
|
'@types/react-beautiful-dnd':
|
||||||
|
specifier: ^13.1.8
|
||||||
|
version: 13.1.8
|
||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
@@ -3065,6 +3071,7 @@ packages:
|
|||||||
|
|
||||||
/@emotion/memoize@0.7.4:
|
/@emotion/memoize@0.7.4:
|
||||||
resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==}
|
resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -3682,6 +3689,7 @@ packages:
|
|||||||
/@mapbox/node-pre-gyp@1.0.11(encoding@0.1.13):
|
/@mapbox/node-pre-gyp@1.0.11(encoding@0.1.13):
|
||||||
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
|
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
detect-libc: 2.0.3
|
detect-libc: 2.0.3
|
||||||
https-proxy-agent: 5.0.1
|
https-proxy-agent: 5.0.1
|
||||||
@@ -4741,12 +4749,27 @@ packages:
|
|||||||
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/react-beautiful-dnd@13.1.8:
|
||||||
|
resolution: {integrity: sha512-E3TyFsro9pQuK4r8S/OL6G99eq7p8v29sX0PM7oT8Z+PJfZvSQTx4zTQbUJ+QZXioAF0e7TGBEcA1XhYhCweyQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.2.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/react-dom@18.2.0:
|
/@types/react-dom@18.2.0:
|
||||||
resolution: {integrity: sha512-8yQrvS6sMpSwIovhPOwfyNf2Wz6v/B62LFSVYQ85+Rq3tLsBIG7rP5geMxaijTUxSkrO6RzN/IRuIAADYQsleA==}
|
resolution: {integrity: sha512-8yQrvS6sMpSwIovhPOwfyNf2Wz6v/B62LFSVYQ85+Rq3tLsBIG7rP5geMxaijTUxSkrO6RzN/IRuIAADYQsleA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 18.2.0
|
'@types/react': 18.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/react-redux@7.1.33:
|
||||||
|
resolution: {integrity: sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg==}
|
||||||
|
dependencies:
|
||||||
|
'@types/hoist-non-react-statics': 3.3.5
|
||||||
|
'@types/react': 18.2.0
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
redux: 4.2.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/react-syntax-highlighter@15.5.6:
|
/@types/react-syntax-highlighter@15.5.6:
|
||||||
resolution: {integrity: sha512-i7wFuLbIAFlabTeD2I1cLjEOrG/xdMa/rpx2zwzAoGHuXJDhSqp9BSfDlMHSh9JSuNfxHk9eEmMX6D55GiyjGg==}
|
resolution: {integrity: sha512-i7wFuLbIAFlabTeD2I1cLjEOrG/xdMa/rpx2zwzAoGHuXJDhSqp9BSfDlMHSh9JSuNfxHk9eEmMX6D55GiyjGg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5005,6 +5028,7 @@ packages:
|
|||||||
|
|
||||||
/abbrev@1.1.1:
|
/abbrev@1.1.1:
|
||||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -5047,6 +5071,7 @@ packages:
|
|||||||
/agent-base@6.0.2:
|
/agent-base@6.0.2:
|
||||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||||
engines: {node: '>= 6.0.0'}
|
engines: {node: '>= 6.0.0'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -5170,12 +5195,14 @@ packages:
|
|||||||
|
|
||||||
/aproba@2.0.0:
|
/aproba@2.0.0:
|
||||||
resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
|
resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/are-we-there-yet@2.0.0:
|
/are-we-there-yet@2.0.0:
|
||||||
resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
|
resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
delegates: 1.0.0
|
delegates: 1.0.0
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
@@ -5791,6 +5818,7 @@ packages:
|
|||||||
/chownr@2.0.0:
|
/chownr@2.0.0:
|
||||||
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -5903,6 +5931,7 @@ packages:
|
|||||||
/color-support@1.1.3:
|
/color-support@1.1.3:
|
||||||
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -5975,6 +6004,7 @@ packages:
|
|||||||
|
|
||||||
/console-control-strings@1.1.0:
|
/console-control-strings@1.1.0:
|
||||||
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
|
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -6540,6 +6570,7 @@ packages:
|
|||||||
/decompress-response@4.2.1:
|
/decompress-response@4.2.1:
|
||||||
resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==}
|
resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
mimic-response: 2.1.0
|
mimic-response: 2.1.0
|
||||||
dev: false
|
dev: false
|
||||||
@@ -6644,6 +6675,7 @@ packages:
|
|||||||
|
|
||||||
/delegates@1.0.0:
|
/delegates@1.0.0:
|
||||||
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
|
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -6671,6 +6703,7 @@ packages:
|
|||||||
/detect-libc@2.0.3:
|
/detect-libc@2.0.3:
|
||||||
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
|
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -7877,6 +7910,7 @@ packages:
|
|||||||
/fs-minipass@2.1.0:
|
/fs-minipass@2.1.0:
|
||||||
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
|
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
minipass: 3.3.6
|
minipass: 3.3.6
|
||||||
dev: false
|
dev: false
|
||||||
@@ -7912,6 +7946,7 @@ packages:
|
|||||||
/gauge@3.0.2:
|
/gauge@3.0.2:
|
||||||
resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
|
resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
aproba: 2.0.0
|
aproba: 2.0.0
|
||||||
color-support: 1.1.3
|
color-support: 1.1.3
|
||||||
@@ -8089,6 +8124,7 @@ packages:
|
|||||||
|
|
||||||
/has-unicode@2.0.1:
|
/has-unicode@2.0.1:
|
||||||
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
|
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -8246,6 +8282,7 @@ packages:
|
|||||||
/https-proxy-agent@5.0.1:
|
/https-proxy-agent@5.0.1:
|
||||||
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 6.0.2
|
agent-base: 6.0.2
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
@@ -9088,6 +9125,7 @@ packages:
|
|||||||
/make-dir@3.1.0:
|
/make-dir@3.1.0:
|
||||||
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
|
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
semver: 6.3.1
|
semver: 6.3.1
|
||||||
dev: false
|
dev: false
|
||||||
@@ -9289,8 +9327,13 @@ packages:
|
|||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/memoize-one@5.2.1:
|
||||||
|
resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/memory-pager@1.5.0:
|
/memory-pager@1.5.0:
|
||||||
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -9647,6 +9690,7 @@ packages:
|
|||||||
/mimic-response@2.1.0:
|
/mimic-response@2.1.0:
|
||||||
resolution: {integrity: sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==}
|
resolution: {integrity: sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -9669,6 +9713,7 @@ packages:
|
|||||||
/minipass@3.3.6:
|
/minipass@3.3.6:
|
||||||
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
|
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
yallist: 4.0.0
|
yallist: 4.0.0
|
||||||
dev: false
|
dev: false
|
||||||
@@ -9677,12 +9722,14 @@ packages:
|
|||||||
/minipass@5.0.0:
|
/minipass@5.0.0:
|
||||||
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
|
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/minizlib@2.1.2:
|
/minizlib@2.1.2:
|
||||||
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
|
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
minipass: 3.3.6
|
minipass: 3.3.6
|
||||||
yallist: 4.0.0
|
yallist: 4.0.0
|
||||||
@@ -9700,6 +9747,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
|
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -9981,6 +10029,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
|
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
abbrev: 1.1.1
|
abbrev: 1.1.1
|
||||||
dev: false
|
dev: false
|
||||||
@@ -9999,6 +10048,7 @@ packages:
|
|||||||
|
|
||||||
/npmlog@5.0.1:
|
/npmlog@5.0.1:
|
||||||
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
|
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
are-we-there-yet: 2.0.0
|
are-we-there-yet: 2.0.0
|
||||||
console-control-strings: 1.1.0
|
console-control-strings: 1.1.0
|
||||||
@@ -10309,6 +10359,7 @@ packages:
|
|||||||
/path2d@0.1.1:
|
/path2d@0.1.1:
|
||||||
resolution: {integrity: sha512-/+S03c8AGsDYKKBtRDqieTJv2GlkMb0bWjnqOgtF6MkjdUQ9a8ARAtxWf9NgKLGm2+WQr6+/tqJdU8HNGsIDoA==}
|
resolution: {integrity: sha512-/+S03c8AGsDYKKBtRDqieTJv2GlkMb0bWjnqOgtF6MkjdUQ9a8ARAtxWf9NgKLGm2+WQr6+/tqJdU8HNGsIDoA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -10587,6 +10638,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/raf-schd@4.0.3:
|
||||||
|
resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/randombytes@2.1.0:
|
/randombytes@2.1.0:
|
||||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -10614,6 +10669,25 @@ packages:
|
|||||||
unpipe: 1.0.0
|
unpipe: 1.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-beautiful-dnd@13.1.1(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.5 || ^17.0.0 || ^18.0.0
|
||||||
|
react-dom: ^16.8.5 || ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.1
|
||||||
|
css-box-model: 1.2.1
|
||||||
|
memoize-one: 5.2.1
|
||||||
|
raf-schd: 4.0.3
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
react-redux: 7.2.9(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
redux: 4.2.1
|
||||||
|
use-memo-one: 1.1.3(react@18.2.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- react-native
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-clientside-effect@1.2.6(react@18.2.0):
|
/react-clientside-effect@1.2.6(react@18.2.0):
|
||||||
resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==}
|
resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -10706,6 +10780,10 @@ packages:
|
|||||||
/react-is@16.13.1:
|
/react-is@16.13.1:
|
||||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||||
|
|
||||||
|
/react-is@17.0.2:
|
||||||
|
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-is@18.2.0:
|
/react-is@18.2.0:
|
||||||
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -10737,6 +10815,28 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-redux@7.2.9(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.3 || ^17 || ^18
|
||||||
|
react-dom: '*'
|
||||||
|
react-native: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
react-dom:
|
||||||
|
optional: true
|
||||||
|
react-native:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.1
|
||||||
|
'@types/react-redux': 7.1.33
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
react-is: 17.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-remove-scroll-bar@2.3.6(@types/react@18.2.0)(react@18.2.0):
|
/react-remove-scroll-bar@2.3.6(@types/react@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==}
|
resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -10858,6 +10958,12 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
/redux@4.2.1:
|
||||||
|
resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/reflect.getprototypeof@1.0.6:
|
/reflect.getprototypeof@1.0.6:
|
||||||
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
|
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -11262,6 +11368,7 @@ packages:
|
|||||||
|
|
||||||
/set-blocking@2.0.0:
|
/set-blocking@2.0.0:
|
||||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -11331,11 +11438,13 @@ packages:
|
|||||||
|
|
||||||
/simple-concat@1.0.1:
|
/simple-concat@1.0.1:
|
||||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/simple-get@3.1.1:
|
/simple-get@3.1.1:
|
||||||
resolution: {integrity: sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==}
|
resolution: {integrity: sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
decompress-response: 4.2.1
|
decompress-response: 4.2.1
|
||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
@@ -11417,6 +11526,7 @@ packages:
|
|||||||
|
|
||||||
/sparse-bitfield@3.0.3:
|
/sparse-bitfield@3.0.3:
|
||||||
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
|
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
memory-pager: 1.5.0
|
memory-pager: 1.5.0
|
||||||
dev: false
|
dev: false
|
||||||
@@ -11685,6 +11795,7 @@ packages:
|
|||||||
/tar@6.2.1:
|
/tar@6.2.1:
|
||||||
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
|
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
chownr: 2.0.0
|
chownr: 2.0.0
|
||||||
fs-minipass: 2.1.0
|
fs-minipass: 2.1.0
|
||||||
@@ -12182,6 +12293,14 @@ packages:
|
|||||||
scheduler: 0.23.0
|
scheduler: 0.23.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/use-memo-one@1.1.3(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/use-sidecar@1.1.2(@types/react@18.2.0)(react@18.2.0):
|
/use-sidecar@1.1.2(@types/react@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -12539,6 +12658,7 @@ packages:
|
|||||||
|
|
||||||
/wide-align@1.1.5:
|
/wide-align@1.1.5:
|
||||||
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
|
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
string-width: 4.2.3
|
string-width: 4.2.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|||||||
@@ -7,336 +7,227 @@
|
|||||||
"showStatus": false,
|
"showStatus": false,
|
||||||
"isTool": false,
|
"isTool": false,
|
||||||
"weight": 0,
|
"weight": 0,
|
||||||
"modules": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
"moduleId": "w90mfp",
|
"nodeId": "lmpb9v2lo2lk",
|
||||||
"name": "定义插件输入",
|
"name": "自定义插件输入",
|
||||||
"flowType": "pluginInput",
|
"intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入",
|
||||||
|
"avatar": "/imgs/workflow/input.png",
|
||||||
|
"flowNodeType": "pluginInput",
|
||||||
"showStatus": false,
|
"showStatus": false,
|
||||||
"position": {
|
"position": {
|
||||||
"x": 515.1887815471657,
|
"x": 616.4226348688949,
|
||||||
"y": -169.04905809653783
|
"y": -165.05298493910115
|
||||||
},
|
},
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"key": "defaultFeedback",
|
"key": "system_addInputParam",
|
||||||
"valueType": "string",
|
"valueType": "dynamic",
|
||||||
"label": "默认反馈内容",
|
"label": "动态外部数据",
|
||||||
"type": "textarea",
|
"renderTypeList": ["addInputParam"],
|
||||||
"required": false,
|
"required": false,
|
||||||
"description": "",
|
"description": "",
|
||||||
"edit": true,
|
"canEdit": true,
|
||||||
|
"value": "",
|
||||||
"editField": {
|
"editField": {
|
||||||
"key": true,
|
"key": true
|
||||||
"name": true,
|
|
||||||
"description": true,
|
|
||||||
"required": true,
|
|
||||||
"dataType": true,
|
|
||||||
"inputType": true
|
|
||||||
},
|
},
|
||||||
"connected": true
|
"dynamicParamDefaultValue": {
|
||||||
|
"inputType": "reference",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "customFeedback",
|
"key": "反馈内容",
|
||||||
"valueType": "string",
|
"valueType": "string",
|
||||||
"label": "自定义反馈内容",
|
"label": "反馈内容",
|
||||||
"type": "target",
|
"renderTypeList": ["textarea"],
|
||||||
"required": false,
|
|
||||||
"description": "",
|
"description": "",
|
||||||
"edit": true,
|
"canEdit": true,
|
||||||
|
"value": "",
|
||||||
"editField": {
|
"editField": {
|
||||||
"key": true,
|
"key": true
|
||||||
"name": true,
|
|
||||||
"description": true,
|
|
||||||
"required": true,
|
|
||||||
"dataType": true,
|
|
||||||
"inputType": true
|
|
||||||
},
|
},
|
||||||
"connected": true
|
"maxLength": "",
|
||||||
|
"dynamicParamDefaultValue": {
|
||||||
|
"inputType": "reference",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"key": "defaultFeedback",
|
"id": "ILc8GS7iU53M",
|
||||||
|
"key": "反馈内容",
|
||||||
"valueType": "string",
|
"valueType": "string",
|
||||||
"label": "默认反馈内容",
|
"label": "反馈内容",
|
||||||
"type": "source",
|
"type": "static"
|
||||||
"edit": true,
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"moduleId": "49de3g",
|
|
||||||
"key": "defaultFeedback"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "customFeedback",
|
"id": "2LCxDnOSculb",
|
||||||
"valueType": "string",
|
"key": "system_addInputParam",
|
||||||
"label": "自定义反馈内容",
|
"valueType": "dynamic",
|
||||||
"type": "source",
|
"label": "动态外部数据",
|
||||||
"edit": true,
|
"type": "static"
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"moduleId": "49de3g",
|
|
||||||
"key": "customFeedback"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"moduleId": "49de3g",
|
"nodeId": "i7uow4wj2wdp",
|
||||||
"name": "HTTP模块",
|
"name": "自定义插件输出",
|
||||||
"flowType": "httpRequest468",
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
"showStatus": true,
|
"avatar": "/imgs/workflow/output.png",
|
||||||
|
"flowNodeType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
"position": {
|
"position": {
|
||||||
"x": 1086.8929621216014,
|
"x": 1607.7142331269126,
|
||||||
"y": -451.7550009773506
|
"y": -151.8669210746189
|
||||||
},
|
},
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"key": "switch",
|
"key": "text",
|
||||||
"type": "target",
|
|
||||||
"label": "core.module.input.label.switch",
|
|
||||||
"description": "core.module.input.description.Trigger",
|
|
||||||
"valueType": "any",
|
|
||||||
"showTargetInApp": true,
|
|
||||||
"showTargetInPlugin": true,
|
|
||||||
"connected": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "system_httpMethod",
|
|
||||||
"type": "custom",
|
|
||||||
"valueType": "string",
|
"valueType": "string",
|
||||||
"label": "",
|
"label": "text",
|
||||||
"value": "POST",
|
"renderTypeList": ["reference"],
|
||||||
"list": [
|
|
||||||
{
|
|
||||||
"label": "GET",
|
|
||||||
"value": "GET"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "POST",
|
|
||||||
"value": "POST"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"required": true,
|
|
||||||
"showTargetInApp": false,
|
|
||||||
"showTargetInPlugin": false,
|
|
||||||
"connected": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "system_httpReqUrl",
|
|
||||||
"type": "hidden",
|
|
||||||
"valueType": "string",
|
|
||||||
"label": "",
|
|
||||||
"description": "core.module.input.description.Http Request Url",
|
|
||||||
"placeholder": "https://api.ai.com/getInventory",
|
|
||||||
"required": false,
|
|
||||||
"showTargetInApp": false,
|
|
||||||
"showTargetInPlugin": false,
|
|
||||||
"value": "/api/plugins/customFeedback",
|
|
||||||
"connected": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "system_httpHeader",
|
|
||||||
"type": "custom",
|
|
||||||
"valueType": "any",
|
|
||||||
"value": "",
|
|
||||||
"label": "",
|
|
||||||
"description": "core.module.input.description.Http Request Header",
|
|
||||||
"placeholder": "core.module.input.description.Http Request Header",
|
|
||||||
"required": false,
|
|
||||||
"showTargetInApp": false,
|
|
||||||
"showTargetInPlugin": false,
|
|
||||||
"connected": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "system_httpParams",
|
|
||||||
"type": "hidden",
|
|
||||||
"valueType": "any",
|
|
||||||
"value": [],
|
|
||||||
"label": "",
|
|
||||||
"required": false,
|
|
||||||
"showTargetInApp": false,
|
|
||||||
"showTargetInPlugin": false,
|
|
||||||
"connected": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "system_httpJsonBody",
|
|
||||||
"type": "hidden",
|
|
||||||
"valueType": "any",
|
|
||||||
"value": "{\r\n \"appId\": \"{{appId}}\",\r\n \"chatId\": \"{{chatId}}\",\r\n \"responseChatItemId\": \"{{responseChatItemId}}\",\r\n \"defaultFeedback\": \"{{defaultFeedback}}\",\r\n \"customFeedback\": \"{{customFeedback}}\"\r\n}",
|
|
||||||
"label": "",
|
|
||||||
"required": false,
|
|
||||||
"showTargetInApp": false,
|
|
||||||
"showTargetInPlugin": false,
|
|
||||||
"connected": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "DYNAMIC_INPUT_KEY",
|
|
||||||
"type": "target",
|
|
||||||
"valueType": "any",
|
|
||||||
"label": "core.workflow.inputType.dynamicTargetInput",
|
|
||||||
"description": "core.module.input.description.dynamic input",
|
|
||||||
"required": false,
|
|
||||||
"showTargetInApp": false,
|
|
||||||
"showTargetInPlugin": true,
|
|
||||||
"hideInApp": true,
|
|
||||||
"connected": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"valueType": "string",
|
|
||||||
"label": "defaultFeedback",
|
|
||||||
"type": "target",
|
|
||||||
"required": true,
|
|
||||||
"description": "",
|
"description": "",
|
||||||
"edit": true,
|
"canEdit": true,
|
||||||
"editField": {
|
"editField": {
|
||||||
"key": true,
|
"key": true,
|
||||||
"name": true,
|
|
||||||
"description": true,
|
"description": true,
|
||||||
"required": true,
|
"valueType": true
|
||||||
"dataType": true
|
|
||||||
},
|
},
|
||||||
"connected": true,
|
"value": ["CRT7oIEU8v2P", "pYKS0LB9gAr3"]
|
||||||
"key": "defaultFeedback"
|
}
|
||||||
|
],
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "CRT7oIEU8v2P",
|
||||||
|
"name": "HTTP 请求",
|
||||||
|
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||||
|
"avatar": "/imgs/workflow/http.png",
|
||||||
|
"flowNodeType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1070.8458389994719,
|
||||||
|
"y": -415.09022555407836
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"renderTypeList": ["addInputParam"],
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.HTTP Dynamic Input",
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"valueType": true
|
||||||
|
},
|
||||||
|
"value": ["lmpb9v2lo2lk", "2LCxDnOSculb"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "customFeedback",
|
"key": "customFeedback",
|
||||||
"valueType": "string",
|
"valueType": "string",
|
||||||
"label": "customFeedback",
|
"label": "customFeedback",
|
||||||
"type": "target",
|
"renderTypeList": ["reference"],
|
||||||
"required": true,
|
|
||||||
"description": "",
|
"description": "",
|
||||||
"edit": true,
|
"canEdit": true,
|
||||||
"editField": {
|
"editField": {
|
||||||
"key": true,
|
"key": true,
|
||||||
"name": true,
|
"valueType": true
|
||||||
"description": true,
|
|
||||||
"required": true,
|
|
||||||
"dataType": true
|
|
||||||
},
|
},
|
||||||
"connected": true
|
"value": ["lmpb9v2lo2lk", "ILc8GS7iU53M"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "system_addInputParam",
|
"key": "system_httpMethod",
|
||||||
"type": "addInputParam",
|
"renderTypeList": ["custom"],
|
||||||
"valueType": "any",
|
"valueType": "string",
|
||||||
"label": "",
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
"required": false,
|
"required": false,
|
||||||
"showTargetInApp": false,
|
"value": "/api/plugins/customFeedback/v2"
|
||||||
"showTargetInPlugin": false,
|
},
|
||||||
"editField": {
|
{
|
||||||
"key": true,
|
"key": "system_httpHeader",
|
||||||
"name": true,
|
"renderTypeList": ["custom"],
|
||||||
"description": true,
|
"valueType": "any",
|
||||||
"required": true,
|
"value": [],
|
||||||
"dataType": true
|
"label": "",
|
||||||
},
|
"description": "core.module.input.description.Http Request Header",
|
||||||
"defaultEditField": {
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
"label": "",
|
"required": false
|
||||||
"key": "",
|
},
|
||||||
"description": "",
|
{
|
||||||
"inputType": "target",
|
"key": "system_httpParams",
|
||||||
"valueType": "string",
|
"renderTypeList": ["hidden"],
|
||||||
"required": true
|
"valueType": "any",
|
||||||
},
|
"value": [],
|
||||||
"connected": false
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\r\n \"customFeedback\":\"{{customFeedback}}\",\r\n \"system_addInputParam\": {{system_addInputParam}}\r\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"key": "finish",
|
"id": "system_addOutputParam",
|
||||||
"label": "core.module.output.label.running done",
|
|
||||||
"description": "core.module.output.description.running done",
|
|
||||||
"valueType": "boolean",
|
|
||||||
"type": "hidden",
|
|
||||||
"targets": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "system_addOutputParam",
|
"key": "system_addOutputParam",
|
||||||
"type": "addOutputParam",
|
"type": "dynamic",
|
||||||
"valueType": "any",
|
"valueType": "dynamic",
|
||||||
"label": "",
|
"label": "",
|
||||||
"targets": [],
|
|
||||||
"editField": {
|
"editField": {
|
||||||
"key": true,
|
"key": true,
|
||||||
"name": true,
|
"valueType": true
|
||||||
"description": true,
|
|
||||||
"dataType": true
|
|
||||||
},
|
|
||||||
"defaultEditField": {
|
|
||||||
"label": "",
|
|
||||||
"key": "",
|
|
||||||
"description": "",
|
|
||||||
"outputType": "source",
|
|
||||||
"valueType": "string"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "source",
|
"id": "httpRawResponse",
|
||||||
"valueType": "string",
|
"key": "httpRawResponse",
|
||||||
"label": "response",
|
"label": "原始响应",
|
||||||
"description": "",
|
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||||
"edit": true,
|
|
||||||
"editField": {
|
|
||||||
"key": true,
|
|
||||||
"name": true,
|
|
||||||
"description": true,
|
|
||||||
"dataType": true
|
|
||||||
},
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"moduleId": "s15f3v",
|
|
||||||
"key": "text"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"key": "response"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleId": "s15f3v",
|
|
||||||
"name": "指定回复",
|
|
||||||
"flowType": "answerNode",
|
|
||||||
"position": {
|
|
||||||
"x": 1705.6337348182756,
|
|
||||||
"y": -37.53826066726282
|
|
||||||
},
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"key": "switch",
|
|
||||||
"type": "target",
|
|
||||||
"label": "core.module.input.label.switch",
|
|
||||||
"description": "core.module.input.description.Trigger",
|
|
||||||
"valueType": "any",
|
"valueType": "any",
|
||||||
"showTargetInApp": true,
|
"type": "static"
|
||||||
"showTargetInPlugin": true,
|
|
||||||
"connected": false
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "pYKS0LB9gAr3",
|
||||||
|
"type": "dynamic",
|
||||||
"key": "text",
|
"key": "text",
|
||||||
"type": "textarea",
|
"valueType": "string",
|
||||||
"valueType": "any",
|
"label": "text"
|
||||||
"label": "core.module.input.label.Response content",
|
|
||||||
"description": "core.module.input.description.Response content",
|
|
||||||
"placeholder": "core.module.input.description.Response content",
|
|
||||||
"showTargetInApp": true,
|
|
||||||
"showTargetInPlugin": true,
|
|
||||||
"connected": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"key": "finish",
|
|
||||||
"label": "core.module.output.label.running done",
|
|
||||||
"description": "core.module.output.description.running done",
|
|
||||||
"valueType": "boolean",
|
|
||||||
"type": "hidden",
|
|
||||||
"targets": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"source": "lmpb9v2lo2lk",
|
||||||
|
"target": "CRT7oIEU8v2P",
|
||||||
|
"sourceHandle": "lmpb9v2lo2lk-source-right",
|
||||||
|
"targetHandle": "CRT7oIEU8v2P-target-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "CRT7oIEU8v2P",
|
||||||
|
"target": "i7uow4wj2wdp",
|
||||||
|
"sourceHandle": "CRT7oIEU8v2P-source-right",
|
||||||
|
"targetHandle": "i7uow4wj2wdp-target-left"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
"nodeId": "lmpb9v2lo2lk",
|
"nodeId": "lmpb9v2lo2lk",
|
||||||
"name": "定义插件输入",
|
"name": "自定义插件输入",
|
||||||
"intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入",
|
"intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入",
|
||||||
"avatar": "/imgs/workflow/input.png",
|
"avatar": "/imgs/workflow/input.png",
|
||||||
"flowNodeType": "pluginInput",
|
"flowNodeType": "pluginInput",
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nodeId": "i7uow4wj2wdp",
|
"nodeId": "i7uow4wj2wdp",
|
||||||
"name": "定义插件输出",
|
"name": "自定义插件输出",
|
||||||
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
"avatar": "/imgs/workflow/output.png",
|
"avatar": "/imgs/workflow/output.png",
|
||||||
"flowNodeType": "pluginOutput",
|
"flowNodeType": "pluginOutput",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
"nodeId": "lmpb9v2lo2lk",
|
"nodeId": "lmpb9v2lo2lk",
|
||||||
"name": "定义插件输入",
|
"name": "自定义插件输入",
|
||||||
"intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入",
|
"intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入",
|
||||||
"avatar": "/imgs/workflow/input.png",
|
"avatar": "/imgs/workflow/input.png",
|
||||||
"flowNodeType": "pluginInput",
|
"flowNodeType": "pluginInput",
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nodeId": "i7uow4wj2wdp",
|
"nodeId": "i7uow4wj2wdp",
|
||||||
"name": "定义插件输出",
|
"name": "自定义插件输出",
|
||||||
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
"avatar": "/imgs/workflow/output.png",
|
"avatar": "/imgs/workflow/output.png",
|
||||||
"flowNodeType": "pluginOutput",
|
"flowNodeType": "pluginOutput",
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
"description": "core.module.input.description.Http Request Url",
|
"description": "core.module.input.description.Http Request Url",
|
||||||
"placeholder": "https://api.ai.com/getInventory",
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
"required": false,
|
"required": false,
|
||||||
"value": "/api/plugins/textEditor"
|
"value": "/api/plugins/textEditor/v2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "system_httpHeader",
|
"key": "system_httpHeader",
|
||||||
|
|||||||
342
projects/app/data/pluginTemplates/v1/customFeedback.json
Normal file
342
projects/app/data/pluginTemplates/v1/customFeedback.json
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
{
|
||||||
|
"author": "FastGPT Team",
|
||||||
|
"templateType": "other",
|
||||||
|
"name": "自定义反馈",
|
||||||
|
"avatar": "/imgs/module/customFeedback.svg",
|
||||||
|
"intro": "该模块被触发时,会给当前的对话记录增加一条反馈。可用于自动记录对话效果等。",
|
||||||
|
"showStatus": false,
|
||||||
|
"isTool": false,
|
||||||
|
"weight": 0,
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"moduleId": "w90mfp",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"flowType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 515.1887815471657,
|
||||||
|
"y": -169.04905809653783
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "defaultFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "默认反馈内容",
|
||||||
|
"type": "textarea",
|
||||||
|
"required": false,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "customFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "自定义反馈内容",
|
||||||
|
"type": "target",
|
||||||
|
"required": false,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "defaultFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "默认反馈内容",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"key": "defaultFeedback"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "customFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "自定义反馈内容",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"key": "customFeedback"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"name": "HTTP模块",
|
||||||
|
"flowType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1086.8929621216014,
|
||||||
|
"y": -451.7550009773506
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.switch",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"label": "GET",
|
||||||
|
"value": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "POST",
|
||||||
|
"value": "POST"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required": true,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"value": "/api/plugins/customFeedback",
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\r\n \"appId\": \"{{appId}}\",\r\n \"chatId\": \"{{chatId}}\",\r\n \"responseChatItemId\": \"{{responseChatItemId}}\",\r\n \"defaultFeedback\": \"{{defaultFeedback}}\",\r\n \"customFeedback\": \"{{customFeedback}}\"\r\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"type": "target",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.inputType.dynamicTargetInput",
|
||||||
|
"description": "core.module.input.description.dynamic input",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"hideInApp": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "defaultFeedback",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true,
|
||||||
|
"key": "defaultFeedback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "customFeedback",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "customFeedback",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "core.module.output.label.running done",
|
||||||
|
"description": "core.module.output.description.running done",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "addOutputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"targets": [],
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"outputType": "source",
|
||||||
|
"valueType": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "response",
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "s15f3v",
|
||||||
|
"key": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"key": "response"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "s15f3v",
|
||||||
|
"name": "指定回复",
|
||||||
|
"flowType": "answerNode",
|
||||||
|
"position": {
|
||||||
|
"x": 1705.6337348182756,
|
||||||
|
"y": -37.53826066726282
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.switch",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"type": "textarea",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.input.label.Response content",
|
||||||
|
"description": "core.module.input.description.Response content",
|
||||||
|
"placeholder": "core.module.input.description.Response content",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "core.module.output.label.running done",
|
||||||
|
"description": "core.module.output.description.running done",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
195
projects/app/data/pluginTemplates/v1/getCurrentTime.json
Normal file
195
projects/app/data/pluginTemplates/v1/getCurrentTime.json
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
{
|
||||||
|
"author": "FastGPT Team",
|
||||||
|
"templateType": "tools",
|
||||||
|
"name": "获取当前时间",
|
||||||
|
"avatar": "/imgs/module/getCurrentTime.svg",
|
||||||
|
"intro": "获取用户当前时区的时间。",
|
||||||
|
"showStatus": false,
|
||||||
|
"isTool": true,
|
||||||
|
"weight": 10,
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"moduleId": "m8dupj",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"intro": "自定义配置外部输入,使用插件时,仅暴露自定义配置的输入",
|
||||||
|
"avatar": "/imgs/module/input.png",
|
||||||
|
"flowType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 187.94161749205568,
|
||||||
|
"y": 179.78772129776746
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "pluginStart",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "插件开始运行",
|
||||||
|
"description": "插件开始运行时,会输出一个 True 的标识。有时候,插件不会有额外的的输入,为了顺利的进入下一个阶段,你可以将该值连接到下一个节点的触发器中。",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "pluginStart",
|
||||||
|
"label": "插件开始运行",
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "cv13yt",
|
||||||
|
"key": "switch"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "bjsa7r",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
|
"avatar": "/imgs/module/output.png",
|
||||||
|
"flowType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1176.9471084832217,
|
||||||
|
"y": 138.94098316727695
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "time",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "time",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": false,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "time",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "time",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "cv13yt",
|
||||||
|
"name": "文本加工",
|
||||||
|
"intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
|
||||||
|
"avatar": "/imgs/module/textEditor.svg",
|
||||||
|
"flowType": "pluginModule",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 600.7190079155914,
|
||||||
|
"y": 1.4754510232677944
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "pluginId",
|
||||||
|
"type": "hidden",
|
||||||
|
"label": "",
|
||||||
|
"value": "community-textEditor",
|
||||||
|
"valueType": "string",
|
||||||
|
"connected": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "triggerAndFinish",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "textarea",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "文本内容",
|
||||||
|
"type": "textarea",
|
||||||
|
"required": true,
|
||||||
|
"description": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。",
|
||||||
|
"edit": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": false,
|
||||||
|
"placeholder": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。",
|
||||||
|
"value": "{{cTime}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "需要加工的输入",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"required": false,
|
||||||
|
"description": "可动态的添加字符串类型变量,在文本编辑中通过 {{key}} 使用变量。非字符串类型,会自动转成字符串类型。",
|
||||||
|
"edit": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.output.label.text",
|
||||||
|
"type": "source",
|
||||||
|
"edit": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "bjsa7r",
|
||||||
|
"key": "time"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "",
|
||||||
|
"description": "",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
331
projects/app/data/pluginTemplates/v1/textEditor.json
Normal file
331
projects/app/data/pluginTemplates/v1/textEditor.json
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
{
|
||||||
|
"author": "FastGPT Team",
|
||||||
|
"templateType": "tools",
|
||||||
|
"name": "文本加工",
|
||||||
|
"avatar": "/imgs/module/textEditor.svg",
|
||||||
|
"intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
|
||||||
|
"showStatus": false,
|
||||||
|
"isTool": false,
|
||||||
|
"weight": 100,
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"moduleId": "w90mfp",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"flowType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 616.4226348688949,
|
||||||
|
"y": -165.05298493910115
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "textarea",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "文本内容",
|
||||||
|
"type": "textarea",
|
||||||
|
"required": true,
|
||||||
|
"description": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "需要加工的输入",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"required": false,
|
||||||
|
"description": "可动态的添加字符串类型变量,在文本编辑中通过 {{key}} 使用变量。非字符串类型,会自动转成字符串类型。",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "textarea",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "文本内容",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"key": "text"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "需要加工的输入",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"key": "DYNAMIC_INPUT_KEY"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"flowType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1607.7142331269126,
|
||||||
|
"y": -145.93201540017395
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.output.label.text",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": false,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.output.label.text",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "49de3g",
|
||||||
|
"name": "HTTP模块",
|
||||||
|
"flowType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1086.8929621216014,
|
||||||
|
"y": -451.7550009773506
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.switch",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"label": "GET",
|
||||||
|
"value": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "POST",
|
||||||
|
"value": "POST"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required": true,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"value": "/api/plugins/textEditor",
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\r\n \"text\": \"{{text}}\"\r\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"type": "target",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.inputType.dynamicTargetInput",
|
||||||
|
"description": "core.module.input.description.dynamic input",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"hideInApp": true,
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "text",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "text",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "core.module.output.label.running done",
|
||||||
|
"description": "core.module.output.description.running done",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "addOutputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"targets": [],
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"outputType": "source",
|
||||||
|
"valueType": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "text",
|
||||||
|
"label": "core.module.output.label.text",
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"key": "text"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
369
projects/app/data/pluginTemplates/v1/tfSwitch.json
Normal file
369
projects/app/data/pluginTemplates/v1/tfSwitch.json
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
{
|
||||||
|
"abandon": true,
|
||||||
|
"author": "FastGPT Team",
|
||||||
|
"templateType": "tools",
|
||||||
|
"name": "判断器",
|
||||||
|
"avatar": "/imgs/module/tfSwitch.svg",
|
||||||
|
"intro": "根据传入的内容进行 True False 输出。默认情况下,当传入的内容为 false, undefined, null, 0, none 时,会输出 false。你也可以增加一些自定义的字符串来补充输出 false 的内容。非字符、非数字、非布尔类型,直接输出 True。",
|
||||||
|
"showStatus": false,
|
||||||
|
"isTool": false,
|
||||||
|
"weight": 10,
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"moduleId": "w90mfp",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"flowType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 616.4226348688949,
|
||||||
|
"y": -165.05298493910115
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "input",
|
||||||
|
"valueType": "any",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.TFSwitch input tip",
|
||||||
|
"required": true,
|
||||||
|
"edit": true,
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "rule",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.input.label.TFSwitch textarea",
|
||||||
|
"type": "textarea",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.TFSwitch textarea",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "input",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.input.label.TFSwitch input tip",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "8kld99",
|
||||||
|
"key": "input"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "rule",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "core.module.input.label.TFSwitch textarea",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "8kld99",
|
||||||
|
"key": "rule"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"flowType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1985.3791673445353,
|
||||||
|
"y": -144.90535546692078
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "true",
|
||||||
|
"type": "target",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "True",
|
||||||
|
"required": true,
|
||||||
|
"edit": true,
|
||||||
|
"connected": true,
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "false",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "False",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": false,
|
||||||
|
"dataType": true,
|
||||||
|
"inputType": false
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "true",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "True",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "false",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"label": "False",
|
||||||
|
"type": "source",
|
||||||
|
"edit": true,
|
||||||
|
"targets": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "8kld99",
|
||||||
|
"name": "HTTP模块",
|
||||||
|
"flowType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1210.560012858087,
|
||||||
|
"y": -387.62433050951756
|
||||||
|
},
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "switch",
|
||||||
|
"type": "target",
|
||||||
|
"label": "core.module.input.label.switch",
|
||||||
|
"description": "core.module.input.description.Trigger",
|
||||||
|
"valueType": "any",
|
||||||
|
"showTargetInApp": true,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"label": "GET",
|
||||||
|
"value": "GET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "POST",
|
||||||
|
"value": "POST"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required": true,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"value": "/api/plugins/TFSwitch",
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"type": "custom",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"type": "hidden",
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\r\n \"input\": \"{{input}}\",\r\n \"rule\": \"{{rule}}\"\r\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DYNAMIC_INPUT_KEY",
|
||||||
|
"type": "target",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "core.module.inputType.dynamicTargetInput",
|
||||||
|
"description": "core.module.input.description.dynamic input",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": true,
|
||||||
|
"hideInApp": true,
|
||||||
|
"connected": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "input",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "input",
|
||||||
|
"type": "target",
|
||||||
|
"required": true,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "rule",
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "rule",
|
||||||
|
"type": "target",
|
||||||
|
"required": false,
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"connected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"type": "addInputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"showTargetInApp": false,
|
||||||
|
"showTargetInPlugin": false,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"required": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"inputType": "target",
|
||||||
|
"valueType": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"connected": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"key": "finish",
|
||||||
|
"label": "core.module.output.label.running done",
|
||||||
|
"description": "core.module.output.description.running done",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "hidden",
|
||||||
|
"targets": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "addOutputParam",
|
||||||
|
"valueType": "any",
|
||||||
|
"label": "",
|
||||||
|
"targets": [],
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"defaultEditField": {
|
||||||
|
"label": "",
|
||||||
|
"key": "",
|
||||||
|
"description": "",
|
||||||
|
"outputType": "source",
|
||||||
|
"valueType": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"key": "true",
|
||||||
|
"label": "true",
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"key": "true"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "source",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"key": "false",
|
||||||
|
"label": "false",
|
||||||
|
"description": "",
|
||||||
|
"edit": true,
|
||||||
|
"editField": {
|
||||||
|
"key": true,
|
||||||
|
"name": true,
|
||||||
|
"description": true,
|
||||||
|
"dataType": true
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"moduleId": "tze1ju",
|
||||||
|
"key": "false"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,11 @@
|
|||||||
{
|
{
|
||||||
"App": "应用",
|
"App": "应用",
|
||||||
"Create New": "",
|
|
||||||
"Export": "导出",
|
"Export": "导出",
|
||||||
"Folder": "文件夹",
|
"Folder": "文件夹",
|
||||||
"Move": "移动",
|
"Move": "移动",
|
||||||
"Name": "名称",
|
"Name": "名称",
|
||||||
"Rename": "重命名",
|
"Rename": "重命名",
|
||||||
"Running": "运行中",
|
"Running": "运行中",
|
||||||
"Select value is empty": "选择的内容为空",
|
|
||||||
"UnKnow": "未知",
|
"UnKnow": "未知",
|
||||||
"Warning": "提示",
|
"Warning": "提示",
|
||||||
"app": {
|
"app": {
|
||||||
@@ -646,8 +644,7 @@
|
|||||||
"success": "开始同步"
|
"success": "开始同步"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"training": {
|
"training": {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"Auxiliary Data": "辅助数据",
|
"Auxiliary Data": "辅助数据",
|
||||||
@@ -922,7 +919,7 @@
|
|||||||
"AppId": "应用的ID",
|
"AppId": "应用的ID",
|
||||||
"ChatId": "当前对话ID",
|
"ChatId": "当前对话ID",
|
||||||
"Current time": "当前时间",
|
"Current time": "当前时间",
|
||||||
"Histories": "历史记录,最多取10条",
|
"Histories": "最近10条聊天记录",
|
||||||
"Key already exists": "Key 已经存在",
|
"Key already exists": "Key 已经存在",
|
||||||
"Key cannot be empty": "参数名不能为空",
|
"Key cannot be empty": "参数名不能为空",
|
||||||
"Props name": "参数名",
|
"Props name": "参数名",
|
||||||
@@ -939,6 +936,7 @@
|
|||||||
"Add Input": "添加入参",
|
"Add Input": "添加入参",
|
||||||
"Input Number": "入参: {{length}}",
|
"Input Number": "入参: {{length}}",
|
||||||
"add": "添加条件",
|
"add": "添加条件",
|
||||||
|
"Add Branch": "添加分支",
|
||||||
"description": {
|
"description": {
|
||||||
"Background": "你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。",
|
"Background": "你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。",
|
||||||
"HTTP Dynamic Input": "接收前方节点的输出值作为变量,这些变量可以被HTTP请求参数使用。",
|
"HTTP Dynamic Input": "接收前方节点的输出值作为变量,这些变量可以被HTTP请求参数使用。",
|
||||||
@@ -975,6 +973,17 @@
|
|||||||
"Classify background": "例如: \n1. AIGC(人工智能生成内容)是指使用人工智能技术自动或半自动地生成数字内容,如文本、图像、音乐、视频等。\n2. AIGC技术包括但不限于自然语言处理、计算机视觉、机器学习和深度学习。这些技术可以创建新内容或修改现有内容,以满足特定的创意、教育、娱乐或信息需求。"
|
"Classify background": "例如: \n1. AIGC(人工智能生成内容)是指使用人工智能技术自动或半自动地生成数字内容,如文本、图像、音乐、视频等。\n2. AIGC技术包括但不限于自然语言处理、计算机视觉、机器学习和深度学习。这些技术可以创建新内容或修改现有内容,以满足特定的创意、教育、娱乐或信息需求。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"inputType": {
|
||||||
|
"chat history": "",
|
||||||
|
"dynamicTargetInput": "",
|
||||||
|
"input": "",
|
||||||
|
"selectApp": "",
|
||||||
|
"selectDataset": "",
|
||||||
|
"selectLLMModel": "",
|
||||||
|
"switch": "",
|
||||||
|
"target": "",
|
||||||
|
"textarea": ""
|
||||||
|
},
|
||||||
"laf": {
|
"laf": {
|
||||||
"Select laf function": "选择laf函数"
|
"Select laf function": "选择laf函数"
|
||||||
},
|
},
|
||||||
@@ -1069,7 +1078,7 @@
|
|||||||
"tools": "工具调用"
|
"tools": "工具调用"
|
||||||
},
|
},
|
||||||
"variable": {
|
"variable": {
|
||||||
"External type": "外部传入",
|
"Custom type": "自定义变量",
|
||||||
"add option": "添加选项",
|
"add option": "添加选项",
|
||||||
"input type": "文本",
|
"input type": "文本",
|
||||||
"key": "变量 key",
|
"key": "变量 key",
|
||||||
@@ -1120,6 +1129,9 @@
|
|||||||
"Stop debug": "停止调试",
|
"Stop debug": "停止调试",
|
||||||
"Success": "运行成功",
|
"Success": "运行成功",
|
||||||
"Value type": "数据类型",
|
"Value type": "数据类型",
|
||||||
|
"Variable": {
|
||||||
|
"Variable type": "变量类型"
|
||||||
|
},
|
||||||
"Variable outputs": "全局变量",
|
"Variable outputs": "全局变量",
|
||||||
"chat": {
|
"chat": {
|
||||||
"Quote prompt": "引用提示词"
|
"Quote prompt": "引用提示词"
|
||||||
@@ -1154,13 +1166,15 @@
|
|||||||
},
|
},
|
||||||
"publish": {
|
"publish": {
|
||||||
"OnRevert version": "点击回退到该版本",
|
"OnRevert version": "点击回退到该版本",
|
||||||
"OnRevert version confirm": "确认回退该版本?",
|
"OnRevert version confirm": "确认回退至该版本?会为您保存编辑中版本的配置,并为回退版本创建一个新的发布版本。",
|
||||||
"histories": "发布记录"
|
"histories": "发布记录"
|
||||||
},
|
},
|
||||||
"tool": {
|
"tool": {
|
||||||
"Handle": "工具连接器",
|
"Handle": "工具连接器",
|
||||||
"Select Tool": "选择工具"
|
"Select Tool": "选择工具"
|
||||||
}
|
},
|
||||||
|
"value": "值",
|
||||||
|
"variable": "变量"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dataset": {
|
"dataset": {
|
||||||
@@ -1189,7 +1203,6 @@
|
|||||||
"Select Dataset": "选择该知识库",
|
"Select Dataset": "选择该知识库",
|
||||||
"Select Dataset Tips": "仅能选择同一个索引模型的知识库",
|
"Select Dataset Tips": "仅能选择同一个索引模型的知识库",
|
||||||
"Select Folder": "进入文件夹",
|
"Select Folder": "进入文件夹",
|
||||||
"System Data Queue": "排队长度",
|
|
||||||
"Training Name": "数据训练",
|
"Training Name": "数据训练",
|
||||||
"Upload Time": "上传时间",
|
"Upload Time": "上传时间",
|
||||||
"collections": {
|
"collections": {
|
||||||
|
|||||||
@@ -357,9 +357,16 @@ const MessageInput = ({
|
|||||||
// enter send.(pc or iframe && enter and unPress shift)
|
// enter send.(pc or iframe && enter and unPress shift)
|
||||||
const isEnter = e.keyCode === 13;
|
const isEnter = e.keyCode === 13;
|
||||||
if (isEnter && TextareaDom.current && (e.ctrlKey || e.altKey)) {
|
if (isEnter && TextareaDom.current && (e.ctrlKey || e.altKey)) {
|
||||||
TextareaDom.current.value += '\n';
|
// Add a new line
|
||||||
|
const index = TextareaDom.current.selectionStart;
|
||||||
|
const val = TextareaDom.current.value;
|
||||||
|
TextareaDom.current.value = `${val.slice(0, index)}\n${val.slice(index)}`;
|
||||||
|
TextareaDom.current.selectionStart = index + 1;
|
||||||
|
TextareaDom.current.selectionEnd = index + 1;
|
||||||
|
|
||||||
TextareaDom.current.style.height = textareaMinH;
|
TextareaDom.current.style.height = textareaMinH;
|
||||||
TextareaDom.current.style.height = `${TextareaDom.current.scrollHeight}px`;
|
TextareaDom.current.style.height = `${TextareaDom.current.scrollHeight}px`;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { ChatSiteItemType } from '@fastgpt/global/core/chat/type';
|
|||||||
|
|
||||||
type useChatStoreType = OutLinkChatAuthProps & {
|
type useChatStoreType = OutLinkChatAuthProps & {
|
||||||
welcomeText: string;
|
welcomeText: string;
|
||||||
variableModules: VariableItemType[];
|
variableNodes: VariableItemType[];
|
||||||
questionGuide: boolean;
|
questionGuide: boolean;
|
||||||
ttsConfig: AppTTSConfigType;
|
ttsConfig: AppTTSConfigType;
|
||||||
whisperConfig: AppWhisperConfigType;
|
whisperConfig: AppWhisperConfigType;
|
||||||
@@ -41,7 +41,7 @@ type useChatStoreType = OutLinkChatAuthProps & {
|
|||||||
};
|
};
|
||||||
const StateContext = createContext<useChatStoreType>({
|
const StateContext = createContext<useChatStoreType>({
|
||||||
welcomeText: '',
|
welcomeText: '',
|
||||||
variableModules: [],
|
variableNodes: [],
|
||||||
questionGuide: false,
|
questionGuide: false,
|
||||||
ttsConfig: {
|
ttsConfig: {
|
||||||
type: 'none',
|
type: 'none',
|
||||||
@@ -110,7 +110,7 @@ const Provider = ({
|
|||||||
}: ChatProviderProps) => {
|
}: ChatProviderProps) => {
|
||||||
const [chatHistories, setChatHistories] = useState<ChatSiteItemType[]>([]);
|
const [chatHistories, setChatHistories] = useState<ChatSiteItemType[]>([]);
|
||||||
|
|
||||||
const { welcomeText, variableModules, questionGuide, ttsConfig, whisperConfig } = useMemo(
|
const { welcomeText, variableNodes, questionGuide, ttsConfig, whisperConfig } = useMemo(
|
||||||
() => splitGuideModule(userGuideModule),
|
() => splitGuideModule(userGuideModule),
|
||||||
[userGuideModule]
|
[userGuideModule]
|
||||||
);
|
);
|
||||||
@@ -150,7 +150,7 @@ const Provider = ({
|
|||||||
teamId,
|
teamId,
|
||||||
teamToken,
|
teamToken,
|
||||||
welcomeText,
|
welcomeText,
|
||||||
variableModules,
|
variableNodes,
|
||||||
questionGuide,
|
questionGuide,
|
||||||
ttsConfig,
|
ttsConfig,
|
||||||
whisperConfig,
|
whisperConfig,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
import { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import { UseFormReturn } from 'react-hook-form';
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { Box, Button, Card, Input, Textarea } from '@chakra-ui/react';
|
import { Box, Button, Card, Input, Textarea } from '@chakra-ui/react';
|
||||||
@@ -12,21 +12,19 @@ import { ChatBoxInputFormType } from '../type.d';
|
|||||||
|
|
||||||
const VariableInput = ({
|
const VariableInput = ({
|
||||||
appAvatar,
|
appAvatar,
|
||||||
variableModules,
|
variableNodes,
|
||||||
variableIsFinish,
|
|
||||||
chatForm,
|
chatForm,
|
||||||
onSubmitVariables
|
onSubmitVariables
|
||||||
}: {
|
}: {
|
||||||
appAvatar?: string;
|
appAvatar?: string;
|
||||||
variableModules: VariableItemType[];
|
variableNodes: VariableItemType[];
|
||||||
variableIsFinish: boolean;
|
|
||||||
onSubmitVariables: (e: Record<string, any>) => void;
|
onSubmitVariables: (e: Record<string, any>) => void;
|
||||||
chatForm: UseFormReturn<ChatBoxInputFormType>;
|
chatForm: UseFormReturn<ChatBoxInputFormType>;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [refresh, setRefresh] = useState(false);
|
|
||||||
const { register, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
|
const { register, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
|
||||||
const variables = watch('variables');
|
const variables = watch('variables');
|
||||||
|
const chatStarted = watch('chatStarted');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={3}>
|
<Box py={3}>
|
||||||
@@ -42,7 +40,7 @@ const VariableInput = ({
|
|||||||
bg={'white'}
|
bg={'white'}
|
||||||
boxShadow={'0 0 8px rgba(0,0,0,0.15)'}
|
boxShadow={'0 0 8px rgba(0,0,0,0.15)'}
|
||||||
>
|
>
|
||||||
{variableModules.map((item) => (
|
{variableNodes.map((item) => (
|
||||||
<Box key={item.id} mb={4}>
|
<Box key={item.id} mb={4}>
|
||||||
<Box as={'label'} display={'inline-block'} position={'relative'} mb={1}>
|
<Box as={'label'} display={'inline-block'} position={'relative'} mb={1}>
|
||||||
{item.label}
|
{item.label}
|
||||||
@@ -60,7 +58,6 @@ const VariableInput = ({
|
|||||||
</Box>
|
</Box>
|
||||||
{item.type === VariableInputEnum.input && (
|
{item.type === VariableInputEnum.input && (
|
||||||
<Input
|
<Input
|
||||||
isDisabled={variableIsFinish}
|
|
||||||
bg={'myWhite.400'}
|
bg={'myWhite.400'}
|
||||||
{...register(`variables.${item.key}`, {
|
{...register(`variables.${item.key}`, {
|
||||||
required: item.required
|
required: item.required
|
||||||
@@ -69,7 +66,6 @@ const VariableInput = ({
|
|||||||
)}
|
)}
|
||||||
{item.type === VariableInputEnum.textarea && (
|
{item.type === VariableInputEnum.textarea && (
|
||||||
<Textarea
|
<Textarea
|
||||||
isDisabled={variableIsFinish}
|
|
||||||
bg={'myWhite.400'}
|
bg={'myWhite.400'}
|
||||||
{...register(`variables.${item.key}`, {
|
{...register(`variables.${item.key}`, {
|
||||||
required: item.required
|
required: item.required
|
||||||
@@ -81,7 +77,6 @@ const VariableInput = ({
|
|||||||
{item.type === VariableInputEnum.select && (
|
{item.type === VariableInputEnum.select && (
|
||||||
<MySelect
|
<MySelect
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
isDisabled={variableIsFinish}
|
|
||||||
list={(item.enums || []).map((item) => ({
|
list={(item.enums || []).map((item) => ({
|
||||||
label: item.value,
|
label: item.value,
|
||||||
value: item.value
|
value: item.value
|
||||||
@@ -92,13 +87,12 @@ const VariableInput = ({
|
|||||||
value={variables[item.key]}
|
value={variables[item.key]}
|
||||||
onchange={(e) => {
|
onchange={(e) => {
|
||||||
setValue(`variables.${item.key}`, e);
|
setValue(`variables.${item.key}`, e);
|
||||||
setRefresh((state) => !state);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
{!variableIsFinish && (
|
{!chatStarted && (
|
||||||
<Button
|
<Button
|
||||||
leftIcon={<MyIcon name={'core/chat/chatFill'} w={'16px'} />}
|
leftIcon={<MyIcon name={'core/chat/chatFill'} w={'16px'} />}
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
@@ -116,4 +110,4 @@ const VariableInput = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(VariableInput);
|
export default VariableInput;
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ import ChatProvider, { useChatProviderStore } from './Provider';
|
|||||||
import ChatItem from './components/ChatItem';
|
import ChatItem from './components/ChatItem';
|
||||||
|
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
import { useCreation, useUpdateEffect } from 'ahooks';
|
||||||
|
|
||||||
const ResponseTags = dynamic(() => import('./ResponseTags'));
|
const ResponseTags = dynamic(() => import('./ResponseTags'));
|
||||||
const FeedbackModal = dynamic(() => import('./FeedbackModal'));
|
const FeedbackModal = dynamic(() => import('./FeedbackModal'));
|
||||||
const ReadFeedbackModal = dynamic(() => import('./ReadFeedbackModal'));
|
const ReadFeedbackModal = dynamic(() => import('./ReadFeedbackModal'));
|
||||||
@@ -91,6 +93,7 @@ type Props = OutLinkChatAuthProps & {
|
|||||||
onStartChat?: (e: StartChatFnProps) => Promise<{
|
onStartChat?: (e: StartChatFnProps) => Promise<{
|
||||||
responseText: string;
|
responseText: string;
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: ChatHistoryItemResType[];
|
[DispatchNodeResponseKeyEnum.nodeResponse]: ChatHistoryItemResType[];
|
||||||
|
newVariables?: Record<string, any>;
|
||||||
isNewChat?: boolean;
|
isNewChat?: boolean;
|
||||||
}>;
|
}>;
|
||||||
onDelMessage?: (e: { contentId: string }) => void;
|
onDelMessage?: (e: { contentId: string }) => void;
|
||||||
@@ -146,7 +149,7 @@ const ChatBox = (
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
welcomeText,
|
welcomeText,
|
||||||
variableModules,
|
variableNodes,
|
||||||
questionGuide,
|
questionGuide,
|
||||||
startSegmentedAudio,
|
startSegmentedAudio,
|
||||||
finishSegmentedAudio,
|
finishSegmentedAudio,
|
||||||
@@ -157,12 +160,6 @@ const ChatBox = (
|
|||||||
isChatting
|
isChatting
|
||||||
} = useChatProviderStore();
|
} = useChatProviderStore();
|
||||||
|
|
||||||
/* variable */
|
|
||||||
const filterVariableModules = useMemo(
|
|
||||||
() => variableModules.filter((item) => item.type !== VariableInputEnum.external),
|
|
||||||
[variableModules]
|
|
||||||
);
|
|
||||||
|
|
||||||
// compute variable input is finish.
|
// compute variable input is finish.
|
||||||
const chatForm = useForm<ChatBoxInputFormType>({
|
const chatForm = useForm<ChatBoxInputFormType>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -173,21 +170,13 @@ const ChatBox = (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
const { setValue, watch, handleSubmit } = chatForm;
|
const { setValue, watch, handleSubmit } = chatForm;
|
||||||
const variables = watch('variables');
|
|
||||||
const chatStarted = watch('chatStarted');
|
const chatStarted = watch('chatStarted');
|
||||||
const variableIsFinish = useMemo(() => {
|
|
||||||
if (!filterVariableModules || filterVariableModules.length === 0 || chatHistories.length > 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
for (let i = 0; i < filterVariableModules.length; i++) {
|
/* variable */
|
||||||
const item = filterVariableModules[i];
|
const filterVariableNodes = useCreation(
|
||||||
if (item.required && !variables[item.key]) {
|
() => variableNodes.filter((item) => item.type !== VariableInputEnum.custom),
|
||||||
return false;
|
[variableNodes]
|
||||||
}
|
);
|
||||||
}
|
|
||||||
|
|
||||||
return chatStarted;
|
|
||||||
}, [filterVariableModules, chatHistories.length, chatStarted, variables]);
|
|
||||||
|
|
||||||
// 滚动到底部
|
// 滚动到底部
|
||||||
const scrollToBottom = (behavior: 'smooth' | 'auto' = 'smooth') => {
|
const scrollToBottom = (behavior: 'smooth' | 'auto' = 'smooth') => {
|
||||||
@@ -359,6 +348,12 @@ const ChatBox = (
|
|||||||
[questionGuide, shareId, outLinkUid, teamId, teamToken]
|
[questionGuide, shareId, outLinkUid, teamId, teamToken]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* Abort chat completions, questionGuide */
|
||||||
|
const abortRequest = useCallback(() => {
|
||||||
|
chatController.current?.abort('stop');
|
||||||
|
questionGuideController.current?.abort('stop');
|
||||||
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* user confirm send prompt
|
* user confirm send prompt
|
||||||
*/
|
*/
|
||||||
@@ -372,171 +367,188 @@ const ChatBox = (
|
|||||||
autoTTSResponse?: boolean;
|
autoTTSResponse?: boolean;
|
||||||
history?: ChatSiteItemType[];
|
history?: ChatSiteItemType[];
|
||||||
}) => {
|
}) => {
|
||||||
handleSubmit(async ({ variables }) => {
|
handleSubmit(
|
||||||
if (!onStartChat) return;
|
async ({ variables }) => {
|
||||||
if (isChatting) {
|
if (!onStartChat) return;
|
||||||
toast({
|
if (isChatting) {
|
||||||
title: '正在聊天中...请等待结束',
|
toast({
|
||||||
status: 'warning'
|
title: '正在聊天中...请等待结束',
|
||||||
});
|
status: 'warning'
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
text = text.trim();
|
|
||||||
|
|
||||||
if (!text && files.length === 0) {
|
|
||||||
toast({
|
|
||||||
title: '内容为空',
|
|
||||||
status: 'warning'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const responseChatId = getNanoid(24);
|
|
||||||
questionGuideController.current?.abort('stop');
|
|
||||||
|
|
||||||
// set auto audio playing
|
|
||||||
if (autoTTSResponse) {
|
|
||||||
await startSegmentedAudio();
|
|
||||||
setAudioPlayingChatId(responseChatId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newChatList: ChatSiteItemType[] = [
|
|
||||||
...history,
|
|
||||||
{
|
|
||||||
dataId: getNanoid(24),
|
|
||||||
obj: ChatRoleEnum.Human,
|
|
||||||
value: [
|
|
||||||
...files.map((file) => ({
|
|
||||||
type: ChatItemValueTypeEnum.file,
|
|
||||||
file: {
|
|
||||||
type: file.type,
|
|
||||||
name: file.name,
|
|
||||||
url: file.url || ''
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
...(text
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
: [])
|
|
||||||
] as UserChatItemValueItemType[],
|
|
||||||
status: 'finish'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataId: responseChatId,
|
|
||||||
obj: ChatRoleEnum.AI,
|
|
||||||
value: [
|
|
||||||
{
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
status: 'loading'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 插入内容
|
|
||||||
setChatHistories(newChatList);
|
|
||||||
|
|
||||||
// 清空输入内容
|
|
||||||
resetInputVal({});
|
|
||||||
setQuestionGuide([]);
|
|
||||||
setTimeout(() => {
|
|
||||||
scrollToBottom();
|
|
||||||
}, 100);
|
|
||||||
try {
|
|
||||||
// create abort obj
|
|
||||||
const abortSignal = new AbortController();
|
|
||||||
chatController.current = abortSignal;
|
|
||||||
|
|
||||||
const messages = chats2GPTMessages({ messages: newChatList, reserveId: true });
|
|
||||||
|
|
||||||
const {
|
|
||||||
responseData,
|
|
||||||
responseText,
|
|
||||||
isNewChat = false
|
|
||||||
} = await onStartChat({
|
|
||||||
chatList: newChatList,
|
|
||||||
messages,
|
|
||||||
controller: abortSignal,
|
|
||||||
generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }),
|
|
||||||
variables
|
|
||||||
});
|
|
||||||
|
|
||||||
isNewChatReplace.current = isNewChat;
|
|
||||||
|
|
||||||
// set finish status
|
|
||||||
setChatHistories((state) =>
|
|
||||||
state.map((item, index) => {
|
|
||||||
if (index !== state.length - 1) return item;
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
status: 'finish',
|
|
||||||
responseData
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
setTimeout(() => {
|
|
||||||
createQuestionGuide({
|
|
||||||
history: newChatList.map((item, i) =>
|
|
||||||
i === newChatList.length - 1
|
|
||||||
? {
|
|
||||||
...item,
|
|
||||||
value: [
|
|
||||||
{
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: responseText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
: item
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
generatingScroll();
|
return;
|
||||||
isPc && TextareaDom.current?.focus();
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
// tts audio
|
|
||||||
autoTTSResponse && splitText2Audio(responseText, true);
|
|
||||||
} catch (err: any) {
|
|
||||||
toast({
|
|
||||||
title: t(getErrText(err, 'core.chat.error.Chat error')),
|
|
||||||
status: 'error',
|
|
||||||
duration: 5000,
|
|
||||||
isClosable: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!err?.responseText) {
|
|
||||||
resetInputVal({ text, files });
|
|
||||||
setChatHistories(newChatList.slice(0, newChatList.length - 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set finish status
|
abortRequest();
|
||||||
setChatHistories((state) =>
|
|
||||||
state.map((item, index) => {
|
|
||||||
if (index !== state.length - 1) return item;
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
status: 'finish'
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
autoTTSResponse && finishSegmentedAudio();
|
text = text.trim();
|
||||||
})();
|
|
||||||
|
if (!text && files.length === 0) {
|
||||||
|
toast({
|
||||||
|
title: '内容为空',
|
||||||
|
status: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete invalid variables, 只保留在 variableNodes 中的变量
|
||||||
|
const requestVariables: Record<string, any> = {};
|
||||||
|
variableNodes?.forEach((item) => {
|
||||||
|
requestVariables[item.key] = variables[item.key] || '';
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseChatId = getNanoid(24);
|
||||||
|
questionGuideController.current?.abort('stop');
|
||||||
|
|
||||||
|
// set auto audio playing
|
||||||
|
if (autoTTSResponse) {
|
||||||
|
await startSegmentedAudio();
|
||||||
|
setAudioPlayingChatId(responseChatId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newChatList: ChatSiteItemType[] = [
|
||||||
|
...history,
|
||||||
|
{
|
||||||
|
dataId: getNanoid(24),
|
||||||
|
obj: ChatRoleEnum.Human,
|
||||||
|
value: [
|
||||||
|
...files.map((file) => ({
|
||||||
|
type: ChatItemValueTypeEnum.file,
|
||||||
|
file: {
|
||||||
|
type: file.type,
|
||||||
|
name: file.name,
|
||||||
|
url: file.url || ''
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
...(text
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: [])
|
||||||
|
] as UserChatItemValueItemType[],
|
||||||
|
status: 'finish'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataId: responseChatId,
|
||||||
|
obj: ChatRoleEnum.AI,
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
status: 'loading'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// 插入内容
|
||||||
|
setChatHistories(newChatList);
|
||||||
|
|
||||||
|
// 清空输入内容
|
||||||
|
resetInputVal({});
|
||||||
|
setQuestionGuide([]);
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
}, 100);
|
||||||
|
try {
|
||||||
|
// create abort obj
|
||||||
|
const abortSignal = new AbortController();
|
||||||
|
chatController.current = abortSignal;
|
||||||
|
|
||||||
|
const messages = chats2GPTMessages({ messages: newChatList, reserveId: true });
|
||||||
|
|
||||||
|
const {
|
||||||
|
responseData,
|
||||||
|
responseText,
|
||||||
|
newVariables,
|
||||||
|
isNewChat = false
|
||||||
|
} = await onStartChat({
|
||||||
|
chatList: newChatList,
|
||||||
|
messages,
|
||||||
|
controller: abortSignal,
|
||||||
|
generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }),
|
||||||
|
variables: requestVariables
|
||||||
|
});
|
||||||
|
|
||||||
|
newVariables && setValue('variables', newVariables);
|
||||||
|
|
||||||
|
isNewChatReplace.current = isNewChat;
|
||||||
|
|
||||||
|
// set finish status
|
||||||
|
setChatHistories((state) =>
|
||||||
|
state.map((item, index) => {
|
||||||
|
if (index !== state.length - 1) return item;
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
status: 'finish',
|
||||||
|
responseData
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setTimeout(() => {
|
||||||
|
createQuestionGuide({
|
||||||
|
history: newChatList.map((item, i) =>
|
||||||
|
i === newChatList.length - 1
|
||||||
|
? {
|
||||||
|
...item,
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: responseText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
: item
|
||||||
|
)
|
||||||
|
});
|
||||||
|
generatingScroll();
|
||||||
|
isPc && TextareaDom.current?.focus();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// tts audio
|
||||||
|
autoTTSResponse && splitText2Audio(responseText, true);
|
||||||
|
} catch (err: any) {
|
||||||
|
toast({
|
||||||
|
title: t(getErrText(err, 'core.chat.error.Chat error')),
|
||||||
|
status: 'error',
|
||||||
|
duration: 5000,
|
||||||
|
isClosable: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!err?.responseText) {
|
||||||
|
resetInputVal({ text, files });
|
||||||
|
setChatHistories(newChatList.slice(0, newChatList.length - 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set finish status
|
||||||
|
setChatHistories((state) =>
|
||||||
|
state.map((item, index) => {
|
||||||
|
if (index !== state.length - 1) return item;
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
status: 'finish'
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
autoTTSResponse && finishSegmentedAudio();
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.log(err?.variables);
|
||||||
|
}
|
||||||
|
)();
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
abortRequest,
|
||||||
chatHistories,
|
chatHistories,
|
||||||
createQuestionGuide,
|
createQuestionGuide,
|
||||||
finishSegmentedAudio,
|
finishSegmentedAudio,
|
||||||
@@ -549,10 +561,12 @@ const ChatBox = (
|
|||||||
resetInputVal,
|
resetInputVal,
|
||||||
setAudioPlayingChatId,
|
setAudioPlayingChatId,
|
||||||
setChatHistories,
|
setChatHistories,
|
||||||
|
setValue,
|
||||||
splitText2Audio,
|
splitText2Audio,
|
||||||
startSegmentedAudio,
|
startSegmentedAudio,
|
||||||
t,
|
t,
|
||||||
toast
|
toast,
|
||||||
|
variableNodes
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -616,7 +630,7 @@ const ChatBox = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[onDelMessage]
|
[onDelMessage, setChatHistories]
|
||||||
);
|
);
|
||||||
// admin mark
|
// admin mark
|
||||||
const onMark = useCallback(
|
const onMark = useCallback(
|
||||||
@@ -706,7 +720,7 @@ const ChatBox = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[appId, chatId, feedbackType, teamId, teamToken]
|
[appId, chatId, feedbackType, setChatHistories, teamId, teamToken]
|
||||||
);
|
);
|
||||||
const onADdUserDislike = useCallback(
|
const onADdUserDislike = useCallback(
|
||||||
(chat: ChatSiteItemType) => {
|
(chat: ChatSiteItemType) => {
|
||||||
@@ -743,7 +757,7 @@ const ChatBox = (
|
|||||||
return () => setFeedbackId(chat.dataId);
|
return () => setFeedbackId(chat.dataId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[appId, chatId, feedbackType, outLinkUid, shareId, teamId, teamToken]
|
[appId, chatId, feedbackType, outLinkUid, setChatHistories, shareId, teamId, teamToken]
|
||||||
);
|
);
|
||||||
const onReadUserDislike = useCallback(
|
const onReadUserDislike = useCallback(
|
||||||
(chat: ChatSiteItemType) => {
|
(chat: ChatSiteItemType) => {
|
||||||
@@ -782,7 +796,19 @@ const ChatBox = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[appId, chatId]
|
[appId, chatId, setChatHistories]
|
||||||
|
);
|
||||||
|
|
||||||
|
const resetVariables = useCallback(
|
||||||
|
(e: Record<string, any> = {}) => {
|
||||||
|
const value: Record<string, any> = { ...e };
|
||||||
|
filterVariableNodes?.forEach((item) => {
|
||||||
|
value[item.key] = e[item.key] || '';
|
||||||
|
});
|
||||||
|
|
||||||
|
setValue('variables', value);
|
||||||
|
},
|
||||||
|
[filterVariableNodes, setValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const showEmpty = useMemo(
|
const showEmpty = useMemo(
|
||||||
@@ -790,13 +816,13 @@ const ChatBox = (
|
|||||||
feConfigs?.show_emptyChat &&
|
feConfigs?.show_emptyChat &&
|
||||||
showEmptyIntro &&
|
showEmptyIntro &&
|
||||||
chatHistories.length === 0 &&
|
chatHistories.length === 0 &&
|
||||||
!filterVariableModules?.length &&
|
!filterVariableNodes?.length &&
|
||||||
!welcomeText,
|
!welcomeText,
|
||||||
[
|
[
|
||||||
chatHistories.length,
|
chatHistories.length,
|
||||||
feConfigs?.show_emptyChat,
|
feConfigs?.show_emptyChat,
|
||||||
showEmptyIntro,
|
showEmptyIntro,
|
||||||
filterVariableModules?.length,
|
filterVariableNodes?.length,
|
||||||
welcomeText
|
welcomeText
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -855,15 +881,9 @@ const ChatBox = (
|
|||||||
// output data
|
// output data
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
getChatHistories: () => chatHistories,
|
getChatHistories: () => chatHistories,
|
||||||
resetVariables(e) {
|
resetVariables,
|
||||||
const defaultVal: Record<string, any> = {};
|
|
||||||
filterVariableModules?.forEach((item) => {
|
|
||||||
defaultVal[item.key] = '';
|
|
||||||
});
|
|
||||||
|
|
||||||
setValue('variables', e || defaultVal);
|
|
||||||
},
|
|
||||||
resetHistory(e) {
|
resetHistory(e) {
|
||||||
|
abortRequest();
|
||||||
setValue('chatStarted', e.length > 0);
|
setValue('chatStarted', e.length > 0);
|
||||||
setChatHistories(e);
|
setChatHistories(e);
|
||||||
},
|
},
|
||||||
@@ -876,7 +896,7 @@ const ChatBox = (
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex flexDirection={'column'} h={'100%'}>
|
<Flex flexDirection={'column'} h={'100%'} position={'relative'}>
|
||||||
<Script src="/js/html2pdf.bundle.min.js" strategy="lazyOnload"></Script>
|
<Script src="/js/html2pdf.bundle.min.js" strategy="lazyOnload"></Script>
|
||||||
{/* chat box container */}
|
{/* chat box container */}
|
||||||
<Box ref={ChatBoxRef} flex={'1 0 0'} h={0} w={'100%'} overflow={'overlay'} px={[4, 0]} pb={3}>
|
<Box ref={ChatBoxRef} flex={'1 0 0'} h={0} w={'100%'} overflow={'overlay'} px={[4, 0]} pb={3}>
|
||||||
@@ -884,11 +904,10 @@ const ChatBox = (
|
|||||||
{showEmpty && <Empty />}
|
{showEmpty && <Empty />}
|
||||||
{!!welcomeText && <WelcomeBox appAvatar={appAvatar} welcomeText={welcomeText} />}
|
{!!welcomeText && <WelcomeBox appAvatar={appAvatar} welcomeText={welcomeText} />}
|
||||||
{/* variable input */}
|
{/* variable input */}
|
||||||
{!!filterVariableModules?.length && (
|
{!!filterVariableNodes?.length && (
|
||||||
<VariableInput
|
<VariableInput
|
||||||
appAvatar={appAvatar}
|
appAvatar={appAvatar}
|
||||||
variableModules={filterVariableModules}
|
variableNodes={filterVariableNodes}
|
||||||
variableIsFinish={variableIsFinish}
|
|
||||||
chatForm={chatForm}
|
chatForm={chatForm}
|
||||||
onSubmitVariables={(data) => {
|
onSubmitVariables={(data) => {
|
||||||
setValue('chatStarted', true);
|
setValue('chatStarted', true);
|
||||||
@@ -980,7 +999,7 @@ const ChatBox = (
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{/* message input */}
|
{/* message input */}
|
||||||
{onStartChat && variableIsFinish && active && (
|
{onStartChat && (chatStarted || filterVariableNodes.length === 0) && active && (
|
||||||
<MessageInput
|
<MessageInput
|
||||||
onSendMessage={sendPrompt}
|
onSendMessage={sendPrompt}
|
||||||
onStop={() => chatController.current?.abort('stop')}
|
onStop={() => chatController.current?.abort('stop')}
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
|||||||
import { getFileAndOpen } from '@/web/core/dataset/utils';
|
import { getFileAndOpen } from '@/web/core/dataset/utils';
|
||||||
import { MARKDOWN_QUOTE_SIGN } from '@fastgpt/global/core/chat/constants';
|
import { MARKDOWN_QUOTE_SIGN } from '@fastgpt/global/core/chat/constants';
|
||||||
|
|
||||||
const CodeLight = dynamic(() => import('./CodeLight'));
|
const CodeLight = dynamic(() => import('./CodeLight'), { ssr: false });
|
||||||
const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock'));
|
const MermaidCodeBlock = dynamic(() => import('./img/MermaidCodeBlock'), { ssr: false });
|
||||||
const MdImage = dynamic(() => import('./img/Image'));
|
const MdImage = dynamic(() => import('./img/Image'), { ssr: false });
|
||||||
const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock'));
|
const EChartsCodeBlock = dynamic(() => import('./img/EChartsCodeBlock'), { ssr: false });
|
||||||
|
|
||||||
const ChatGuide = dynamic(() => import('./chat/Guide'));
|
const ChatGuide = dynamic(() => import('./chat/Guide'), { ssr: false });
|
||||||
const QuestionGuide = dynamic(() => import('./chat/QuestionGuide'));
|
const QuestionGuide = dynamic(() => import('./chat/QuestionGuide'), { ssr: false });
|
||||||
|
|
||||||
export enum CodeClassName {
|
export enum CodeClassName {
|
||||||
guide = 'guide',
|
guide = 'guide',
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ const VariableEdit = ({
|
|||||||
maxW={['90vw', '500px']}
|
maxW={['90vw', '500px']}
|
||||||
>
|
>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
{variableType !== VariableInputEnum.external && (
|
{variableType !== VariableInputEnum.custom && (
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<Box w={'70px'}>{t('common.Require Input')}</Box>
|
<Box w={'70px'}>{t('common.Require Input')}</Box>
|
||||||
<Switch {...registerEdit('variable.required')} />
|
<Switch {...registerEdit('variable.required')} />
|
||||||
@@ -197,7 +197,7 @@ const VariableEdit = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Box mt={5} mb={2}>
|
<Box mt={5} mb={2}>
|
||||||
{t('core.module.Field Type')}
|
{t('core.workflow.Variable.Variable type')}
|
||||||
</Box>
|
</Box>
|
||||||
<MyRadio
|
<MyRadio
|
||||||
gridGap={4}
|
gridGap={4}
|
||||||
|
|||||||
@@ -34,11 +34,13 @@ export type ChatTestComponentRef = {
|
|||||||
const ChatTest = (
|
const ChatTest = (
|
||||||
{
|
{
|
||||||
app,
|
app,
|
||||||
|
isOpen,
|
||||||
nodes = [],
|
nodes = [],
|
||||||
edges = [],
|
edges = [],
|
||||||
onClose
|
onClose
|
||||||
}: {
|
}: {
|
||||||
app: AppSchema;
|
app: AppSchema;
|
||||||
|
isOpen: boolean;
|
||||||
nodes?: StoreNodeItemType[];
|
nodes?: StoreNodeItemType[];
|
||||||
edges?: StoreEdgeItemType[];
|
edges?: StoreEdgeItemType[];
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@@ -48,7 +50,6 @@ const ChatTest = (
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const ChatBoxRef = useRef<ComponentRef>(null);
|
const ChatBoxRef = useRef<ComponentRef>(null);
|
||||||
const { userInfo } = useUserStore();
|
const { userInfo } = useUserStore();
|
||||||
const isOpen = useMemo(() => nodes && nodes.length > 0, [nodes]);
|
|
||||||
|
|
||||||
const startChat = useCallback(
|
const startChat = useCallback(
|
||||||
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {
|
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {
|
||||||
@@ -65,10 +66,10 @@ const ChatTest = (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const history = chatList.slice(-historyMaxLen - 2, -2);
|
const history = chatList.slice(-(historyMaxLen * 2) - 2, -2);
|
||||||
|
|
||||||
// 流请求,获取数据
|
// 流请求,获取数据
|
||||||
const { responseText, responseData } = await streamFetch({
|
const { responseText, responseData, newVariables } = await streamFetch({
|
||||||
url: '/api/core/chat/chatTest',
|
url: '/api/core/chat/chatTest',
|
||||||
data: {
|
data: {
|
||||||
history,
|
history,
|
||||||
@@ -84,7 +85,7 @@ const ChatTest = (
|
|||||||
abortCtrl: controller
|
abortCtrl: controller
|
||||||
});
|
});
|
||||||
|
|
||||||
return { responseText, responseData };
|
return { responseText, responseData, newVariables };
|
||||||
},
|
},
|
||||||
[app._id, app.name, edges, nodes]
|
[app._id, app.name, edges, nodes]
|
||||||
);
|
);
|
||||||
@@ -99,7 +100,7 @@ const ChatTest = (
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Flex
|
<Flex
|
||||||
zIndex={3}
|
zIndex={101}
|
||||||
flexDirection={'column'}
|
flexDirection={'column'}
|
||||||
position={'absolute'}
|
position={'absolute'}
|
||||||
top={5}
|
top={5}
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
|||||||
<NodeSimple {...data} minW={'100px'} maxW={'300px'} />
|
<NodeSimple {...data} minW={'100px'} maxW={'300px'} />
|
||||||
),
|
),
|
||||||
[FlowNodeTypeEnum.lafModule]: dynamic(() => import('./nodes/NodeLaf')),
|
[FlowNodeTypeEnum.lafModule]: dynamic(() => import('./nodes/NodeLaf')),
|
||||||
[FlowNodeTypeEnum.ifElseNode]: dynamic(() => import('./nodes/NodeIfElse'))
|
[FlowNodeTypeEnum.ifElseNode]: dynamic(() => import('./nodes/NodeIfElse')),
|
||||||
|
[FlowNodeTypeEnum.variableUpdate]: dynamic(() => import('./nodes/NodeVariableUpdate'))
|
||||||
};
|
};
|
||||||
const edgeTypes = {
|
const edgeTypes = {
|
||||||
[EDGE_TYPE]: ButtonEdge
|
[EDGE_TYPE]: ButtonEdge
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
</Box>
|
</Box>
|
||||||
<Box flex={'1 0 0'} />
|
<Box flex={'1 0 0'} />
|
||||||
<Button
|
<Button
|
||||||
variant={'transparentBase'}
|
variant={'whitePrimary'}
|
||||||
leftIcon={<SmallAddIcon />}
|
leftIcon={<SmallAddIcon />}
|
||||||
iconSpacing={1}
|
iconSpacing={1}
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
|
|||||||
@@ -1,381 +0,0 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
|
||||||
import NodeCard from './render/NodeCard';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
|
||||||
import { Box, Button, Flex, background } from '@chakra-ui/react';
|
|
||||||
import { SmallAddIcon } from '@chakra-ui/icons';
|
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
|
||||||
import RenderOutput from './render/RenderOutput';
|
|
||||||
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
|
||||||
import { NodeProps } from 'reactflow';
|
|
||||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
|
|
||||||
import {
|
|
||||||
IfElseConditionType,
|
|
||||||
IfElseListItemType
|
|
||||||
} from '@fastgpt/global/core/workflow/template/system/ifElse/type';
|
|
||||||
import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
|
|
||||||
import { ReferSelector, useReference } from './render/RenderInput/templates/Reference';
|
|
||||||
import {
|
|
||||||
VariableConditionEnum,
|
|
||||||
allConditionList,
|
|
||||||
arrayConditionList,
|
|
||||||
booleanConditionList,
|
|
||||||
numberConditionList
|
|
||||||
} from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
|
||||||
import { stringConditionList } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
|
||||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
|
||||||
import MyInput from '@/components/MyInput';
|
|
||||||
import { useContextSelector } from 'use-context-selector';
|
|
||||||
import { WorkflowContext } from '../../context';
|
|
||||||
|
|
||||||
const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { nodeId, inputs = [], outputs } = data;
|
|
||||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
|
||||||
|
|
||||||
const condition = useMemo(
|
|
||||||
() =>
|
|
||||||
(inputs.find((input) => input.key === NodeInputKeyEnum.condition)
|
|
||||||
?.value as IfElseConditionType) || 'OR',
|
|
||||||
[inputs]
|
|
||||||
);
|
|
||||||
const ifElseList = useMemo(
|
|
||||||
() =>
|
|
||||||
(inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList)
|
|
||||||
?.value as IfElseListItemType[]) || [],
|
|
||||||
[inputs]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onUpdateIfElseList = useCallback(
|
|
||||||
(value: IfElseListItemType[]) => {
|
|
||||||
const ifElseListInput = inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList);
|
|
||||||
if (!ifElseListInput) return;
|
|
||||||
|
|
||||||
onChangeNode({
|
|
||||||
nodeId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: NodeInputKeyEnum.ifElseList,
|
|
||||||
value: {
|
|
||||||
...ifElseListInput,
|
|
||||||
value
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[inputs, nodeId, onChangeNode]
|
|
||||||
);
|
|
||||||
|
|
||||||
const RenderAddCondition = useMemo(() => {
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
onUpdateIfElseList([
|
|
||||||
...ifElseList,
|
|
||||||
{
|
|
||||||
variable: undefined,
|
|
||||||
condition: undefined,
|
|
||||||
value: undefined
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}}
|
|
||||||
variant={'whiteBase'}
|
|
||||||
leftIcon={<SmallAddIcon />}
|
|
||||||
my={3}
|
|
||||||
w={'full'}
|
|
||||||
>
|
|
||||||
{t('core.module.input.add')}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
}, [ifElseList, onUpdateIfElseList, t]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NodeCard selected={selected} maxW={'1000px'} {...data}>
|
|
||||||
<Box px={6}>
|
|
||||||
<RenderOutput nodeId={nodeId} flowOutputList={[outputs[0]]} />
|
|
||||||
</Box>
|
|
||||||
<Box py={3} px={4}>
|
|
||||||
<Box className="nowheel">
|
|
||||||
{ifElseList.map((item, i) => {
|
|
||||||
return (
|
|
||||||
<Box key={i}>
|
|
||||||
{/* border */}
|
|
||||||
{i !== 0 && (
|
|
||||||
<Flex alignItems={'center'} w={'full'} py={'5px'}>
|
|
||||||
<Box
|
|
||||||
w={'auto'}
|
|
||||||
flex={1}
|
|
||||||
height={'1px'}
|
|
||||||
style={{
|
|
||||||
background:
|
|
||||||
'linear-gradient(90deg, rgba(232, 235, 240, 0.00) 0%, #E8EBF0 100%)'
|
|
||||||
}}
|
|
||||||
></Box>
|
|
||||||
<Flex
|
|
||||||
px={'2.5'}
|
|
||||||
color={'primary.600'}
|
|
||||||
fontWeight={'medium'}
|
|
||||||
alignItems={'center'}
|
|
||||||
cursor={'pointer'}
|
|
||||||
rounded={'md'}
|
|
||||||
onClick={() => {
|
|
||||||
const conditionInput = inputs.find(
|
|
||||||
(input) => input.key === NodeInputKeyEnum.condition
|
|
||||||
);
|
|
||||||
if (!conditionInput) return;
|
|
||||||
|
|
||||||
onChangeNode({
|
|
||||||
nodeId,
|
|
||||||
type: 'updateInput',
|
|
||||||
key: NodeInputKeyEnum.condition,
|
|
||||||
value: {
|
|
||||||
...conditionInput,
|
|
||||||
value: conditionInput.value === 'OR' ? 'AND' : 'OR'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{condition}
|
|
||||||
<MyIcon ml={1} boxSize={5} name="change" />
|
|
||||||
</Flex>
|
|
||||||
<Box
|
|
||||||
w={'auto'}
|
|
||||||
flex={1}
|
|
||||||
height={'1px'}
|
|
||||||
style={{
|
|
||||||
background:
|
|
||||||
'linear-gradient(90deg, #E8EBF0 0%, rgba(232, 235, 240, 0.00) 100%)'
|
|
||||||
}}
|
|
||||||
></Box>
|
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
{/* condition list */}
|
|
||||||
<Flex gap={2} alignItems={'center'}>
|
|
||||||
{/* variable reference */}
|
|
||||||
<Box minW={'250px'}>
|
|
||||||
<Reference
|
|
||||||
nodeId={nodeId}
|
|
||||||
variable={item.variable}
|
|
||||||
onSelect={(e) => {
|
|
||||||
onUpdateIfElseList(
|
|
||||||
ifElseList.map((ifElse, index) => {
|
|
||||||
if (index === i) {
|
|
||||||
return {
|
|
||||||
...ifElse,
|
|
||||||
variable: e
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return ifElse;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
{/* condition select */}
|
|
||||||
<Box w={'130px'} flex={1}>
|
|
||||||
<ConditionSelect
|
|
||||||
condition={item.condition}
|
|
||||||
variable={item.variable}
|
|
||||||
onSelect={(e) => {
|
|
||||||
onUpdateIfElseList(
|
|
||||||
ifElseList.map((ifElse, index) => {
|
|
||||||
if (index === i) {
|
|
||||||
return {
|
|
||||||
...ifElse,
|
|
||||||
condition: e
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return ifElse;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
{/* value */}
|
|
||||||
<Box w={'200px'}>
|
|
||||||
<ConditionValueInput
|
|
||||||
value={item.value}
|
|
||||||
condition={item.condition}
|
|
||||||
variable={item.variable}
|
|
||||||
onChange={(e) => {
|
|
||||||
onUpdateIfElseList(
|
|
||||||
ifElseList.map((ifElse, index) => {
|
|
||||||
if (index === i) {
|
|
||||||
return {
|
|
||||||
...ifElse,
|
|
||||||
value: e
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return ifElse;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
{/* delete */}
|
|
||||||
{ifElseList.length > 1 && (
|
|
||||||
<MyIcon
|
|
||||||
ml={2}
|
|
||||||
boxSize={5}
|
|
||||||
name="delete"
|
|
||||||
cursor={'pointer'}
|
|
||||||
_hover={{ color: 'red.600' }}
|
|
||||||
color={'myGray.400'}
|
|
||||||
onClick={() => {
|
|
||||||
onUpdateIfElseList(ifElseList.filter((_, index) => index !== i));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Box>
|
|
||||||
{RenderAddCondition}
|
|
||||||
</Box>
|
|
||||||
<Box px={6} mb={4}>
|
|
||||||
<RenderOutput nodeId={nodeId} flowOutputList={[outputs[1]]} />
|
|
||||||
</Box>
|
|
||||||
</NodeCard>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export default React.memo(NodeIfElse);
|
|
||||||
|
|
||||||
const Reference = ({
|
|
||||||
nodeId,
|
|
||||||
variable,
|
|
||||||
onSelect
|
|
||||||
}: {
|
|
||||||
nodeId: string;
|
|
||||||
variable?: ReferenceValueProps;
|
|
||||||
onSelect: (e: ReferenceValueProps) => void;
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const { referenceList, formatValue } = useReference({
|
|
||||||
nodeId,
|
|
||||||
valueType: WorkflowIOValueTypeEnum.any,
|
|
||||||
value: variable
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ReferSelector
|
|
||||||
placeholder={t('选择引用变量')}
|
|
||||||
list={referenceList}
|
|
||||||
value={formatValue}
|
|
||||||
onSelect={onSelect}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Different data types have different options */
|
|
||||||
const ConditionSelect = ({
|
|
||||||
condition,
|
|
||||||
variable,
|
|
||||||
onSelect
|
|
||||||
}: {
|
|
||||||
condition?: VariableConditionEnum;
|
|
||||||
variable?: ReferenceValueProps;
|
|
||||||
onSelect: (e: VariableConditionEnum) => void;
|
|
||||||
}) => {
|
|
||||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
|
||||||
|
|
||||||
// get condition type
|
|
||||||
const valueType = useMemo(() => {
|
|
||||||
if (!variable) return;
|
|
||||||
const node = nodeList.find((node) => node.nodeId === variable[0]);
|
|
||||||
|
|
||||||
if (!node) return WorkflowIOValueTypeEnum.any;
|
|
||||||
const output = node.outputs.find((item) => item.id === variable[1]);
|
|
||||||
|
|
||||||
if (!output) return WorkflowIOValueTypeEnum.any;
|
|
||||||
return output.valueType;
|
|
||||||
}, [nodeList, variable]);
|
|
||||||
|
|
||||||
const conditionList = useMemo(() => {
|
|
||||||
if (valueType === WorkflowIOValueTypeEnum.string) return stringConditionList;
|
|
||||||
if (valueType === WorkflowIOValueTypeEnum.number) return numberConditionList;
|
|
||||||
if (valueType === WorkflowIOValueTypeEnum.boolean) return booleanConditionList;
|
|
||||||
if (
|
|
||||||
valueType === WorkflowIOValueTypeEnum.chatHistory ||
|
|
||||||
valueType === WorkflowIOValueTypeEnum.datasetQuote ||
|
|
||||||
valueType === WorkflowIOValueTypeEnum.dynamic ||
|
|
||||||
valueType === WorkflowIOValueTypeEnum.selectApp ||
|
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayBoolean ||
|
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayNumber ||
|
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayObject ||
|
|
||||||
valueType === WorkflowIOValueTypeEnum.arrayString ||
|
|
||||||
valueType === WorkflowIOValueTypeEnum.object
|
|
||||||
)
|
|
||||||
return arrayConditionList;
|
|
||||||
|
|
||||||
if (valueType === WorkflowIOValueTypeEnum.any) return allConditionList;
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}, [valueType]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MySelect
|
|
||||||
w={'100%'}
|
|
||||||
list={conditionList}
|
|
||||||
value={condition}
|
|
||||||
onchange={onSelect}
|
|
||||||
placeholder="选择条件"
|
|
||||||
></MySelect>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Different condition can be entered differently
|
|
||||||
empty, notEmpty: forbid input
|
|
||||||
boolean type: select true/false
|
|
||||||
*/
|
|
||||||
const ConditionValueInput = ({
|
|
||||||
value = '',
|
|
||||||
variable,
|
|
||||||
condition,
|
|
||||||
onChange
|
|
||||||
}: {
|
|
||||||
value?: string;
|
|
||||||
variable?: ReferenceValueProps;
|
|
||||||
condition?: VariableConditionEnum;
|
|
||||||
onChange: (e: string) => void;
|
|
||||||
}) => {
|
|
||||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
|
||||||
|
|
||||||
// get value type
|
|
||||||
const valueType = useMemo(() => {
|
|
||||||
if (!variable) return;
|
|
||||||
const node = nodeList.find((node) => node.nodeId === variable[0]);
|
|
||||||
|
|
||||||
if (!node) return WorkflowIOValueTypeEnum.any;
|
|
||||||
const output = node.outputs.find((item) => item.id === variable[1]);
|
|
||||||
|
|
||||||
if (!output) return WorkflowIOValueTypeEnum.any;
|
|
||||||
return output.valueType;
|
|
||||||
}, [nodeList, variable]);
|
|
||||||
|
|
||||||
if (valueType === WorkflowIOValueTypeEnum.boolean) {
|
|
||||||
return (
|
|
||||||
<MySelect
|
|
||||||
list={[
|
|
||||||
{ label: 'True', value: 'true' },
|
|
||||||
{ label: 'False', value: 'false' }
|
|
||||||
]}
|
|
||||||
onchange={onChange}
|
|
||||||
value={value}
|
|
||||||
placeholder={'选择值'}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<MyInput
|
|
||||||
value={value}
|
|
||||||
placeholder={'输入值'}
|
|
||||||
w={'100%'}
|
|
||||||
isDisabled={
|
|
||||||
condition === VariableConditionEnum.isEmpty ||
|
|
||||||
condition === VariableConditionEnum.isNotEmpty
|
|
||||||
}
|
|
||||||
onChange={(e) => onChange(e.target.value)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,421 @@
|
|||||||
|
import { Box, Button, Flex } from '@chakra-ui/react';
|
||||||
|
import {
|
||||||
|
DraggableProvided,
|
||||||
|
DraggableStateSnapshot
|
||||||
|
} from '@fastgpt/web/components/common/DndDrag/index';
|
||||||
|
import Container from '../../components/Container';
|
||||||
|
import { DragHandleIcon, MinusIcon, SmallAddIcon } from '@chakra-ui/icons';
|
||||||
|
import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type';
|
||||||
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
|
import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ReferSelector, useReference } from '../render/RenderInput/templates/Reference';
|
||||||
|
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import {
|
||||||
|
VariableConditionEnum,
|
||||||
|
allConditionList,
|
||||||
|
arrayConditionList,
|
||||||
|
booleanConditionList,
|
||||||
|
numberConditionList,
|
||||||
|
objectConditionList,
|
||||||
|
stringConditionList
|
||||||
|
} from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { WorkflowContext } from '../../../context';
|
||||||
|
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||||
|
import MyInput from '@/components/MyInput';
|
||||||
|
import { getElseIFLabel, getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
import { SourceHandle } from '../render/Handle';
|
||||||
|
import { Position, useReactFlow } from 'reactflow';
|
||||||
|
import { getReferenceDataValueType } from '@/web/core/workflow/utils';
|
||||||
|
import DragIcon from '@fastgpt/web/components/common/DndDrag/DragIcon';
|
||||||
|
|
||||||
|
const ListItem = ({
|
||||||
|
provided,
|
||||||
|
snapshot,
|
||||||
|
conditionIndex,
|
||||||
|
conditionItem,
|
||||||
|
ifElseList,
|
||||||
|
onUpdateIfElseList,
|
||||||
|
nodeId
|
||||||
|
}: {
|
||||||
|
provided: DraggableProvided;
|
||||||
|
snapshot: DraggableStateSnapshot;
|
||||||
|
conditionIndex: number;
|
||||||
|
conditionItem: IfElseListItemType;
|
||||||
|
ifElseList: IfElseListItemType[];
|
||||||
|
onUpdateIfElseList: (value: IfElseListItemType[]) => void;
|
||||||
|
nodeId: string;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { getZoom } = useReactFlow();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
ref={provided.innerRef}
|
||||||
|
{...provided.draggableProps}
|
||||||
|
style={{
|
||||||
|
...provided.draggableProps.style,
|
||||||
|
opacity: snapshot.isDragging ? 0.8 : 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
alignItems={'center'}
|
||||||
|
position={'relative'}
|
||||||
|
transform={snapshot.isDragging ? `scale(${getZoom()})` : ''}
|
||||||
|
transformOrigin={'top left'}
|
||||||
|
>
|
||||||
|
<Container w={snapshot.isDragging ? '' : 'full'} className="nodrag">
|
||||||
|
<Flex mb={4} alignItems={'center'}>
|
||||||
|
{ifElseList.length > 1 && <DragIcon provided={provided} />}
|
||||||
|
<Box color={'black'} fontSize={'lg'} ml={2}>
|
||||||
|
{getElseIFLabel(conditionIndex)}
|
||||||
|
</Box>
|
||||||
|
{conditionItem.list?.length > 1 && (
|
||||||
|
<Flex
|
||||||
|
px={'2.5'}
|
||||||
|
color={'primary.600'}
|
||||||
|
fontWeight={'medium'}
|
||||||
|
alignItems={'center'}
|
||||||
|
cursor={'pointer'}
|
||||||
|
rounded={'md'}
|
||||||
|
onClick={() => {
|
||||||
|
onUpdateIfElseList(
|
||||||
|
ifElseList.map((ifElse, index) => {
|
||||||
|
if (index === conditionIndex) {
|
||||||
|
return {
|
||||||
|
...ifElse,
|
||||||
|
condition: ifElse.condition === 'AND' ? 'OR' : 'AND'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ifElse;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{conditionItem.condition}
|
||||||
|
<MyIcon ml={1} boxSize={5} name="change" />
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
<Box flex={1}></Box>
|
||||||
|
{ifElseList.length > 1 && (
|
||||||
|
<MyIcon
|
||||||
|
ml={2}
|
||||||
|
boxSize={5}
|
||||||
|
name="delete"
|
||||||
|
cursor={'pointer'}
|
||||||
|
_hover={{ color: 'red.600' }}
|
||||||
|
color={'myGray.400'}
|
||||||
|
onClick={() => {
|
||||||
|
onUpdateIfElseList(ifElseList.filter((_, index) => index !== conditionIndex));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
<Box>
|
||||||
|
{conditionItem.list?.map((item, i) => {
|
||||||
|
return (
|
||||||
|
<Box key={i}>
|
||||||
|
{/* condition list */}
|
||||||
|
<Flex gap={2} mb={2} alignItems={'center'}>
|
||||||
|
{/* variable reference */}
|
||||||
|
<Box minW={'250px'}>
|
||||||
|
<Reference
|
||||||
|
nodeId={nodeId}
|
||||||
|
variable={item.variable}
|
||||||
|
onSelect={(e) => {
|
||||||
|
onUpdateIfElseList(
|
||||||
|
ifElseList.map((ifElse, index) => {
|
||||||
|
if (index === conditionIndex) {
|
||||||
|
return {
|
||||||
|
...ifElse,
|
||||||
|
list: ifElse.list.map((item, index) => {
|
||||||
|
if (index === i) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
variable: e,
|
||||||
|
condition: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ifElse;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
{/* condition select */}
|
||||||
|
<Box w={'130px'} flex={1}>
|
||||||
|
<ConditionSelect
|
||||||
|
condition={item.condition}
|
||||||
|
variable={item.variable}
|
||||||
|
onSelect={(e) => {
|
||||||
|
onUpdateIfElseList(
|
||||||
|
ifElseList.map((ifElse, index) => {
|
||||||
|
if (index === conditionIndex) {
|
||||||
|
return {
|
||||||
|
...ifElse,
|
||||||
|
list: ifElse.list.map((item, index) => {
|
||||||
|
if (index === i) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
condition: e
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ifElse;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
{/* value */}
|
||||||
|
<Box w={'200px'}>
|
||||||
|
<ConditionValueInput
|
||||||
|
value={item.value}
|
||||||
|
condition={item.condition}
|
||||||
|
variable={item.variable}
|
||||||
|
onChange={(e) => {
|
||||||
|
onUpdateIfElseList(
|
||||||
|
ifElseList.map((ifElse, index) => {
|
||||||
|
if (index === conditionIndex) {
|
||||||
|
return {
|
||||||
|
...ifElse,
|
||||||
|
list: ifElse.list.map((item, index) => {
|
||||||
|
if (index === i) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
value: e
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ifElse;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
{/* delete */}
|
||||||
|
{conditionItem.list.length > 1 && (
|
||||||
|
<MinusIcon
|
||||||
|
ml={2}
|
||||||
|
boxSize={3}
|
||||||
|
name="delete"
|
||||||
|
cursor={'pointer'}
|
||||||
|
_hover={{ color: 'red.600' }}
|
||||||
|
color={'myGray.400'}
|
||||||
|
onClick={() => {
|
||||||
|
onUpdateIfElseList(
|
||||||
|
ifElseList.map((ifElse, index) => {
|
||||||
|
if (index === conditionIndex) {
|
||||||
|
return {
|
||||||
|
...ifElse,
|
||||||
|
list: ifElse.list.filter((_, index) => index !== i)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ifElse;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
onUpdateIfElseList(
|
||||||
|
ifElseList.map((ifElse, index) => {
|
||||||
|
if (index === conditionIndex) {
|
||||||
|
return {
|
||||||
|
...ifElse,
|
||||||
|
list: ifElse.list.concat({
|
||||||
|
variable: undefined,
|
||||||
|
condition: undefined,
|
||||||
|
value: undefined
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ifElse;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
variant={'link'}
|
||||||
|
leftIcon={<SmallAddIcon />}
|
||||||
|
my={3}
|
||||||
|
color={'primary.600'}
|
||||||
|
>
|
||||||
|
{t('core.module.input.add')}
|
||||||
|
</Button>
|
||||||
|
</Container>
|
||||||
|
{!snapshot.isDragging && (
|
||||||
|
<SourceHandle
|
||||||
|
nodeId={nodeId}
|
||||||
|
handleId={getHandleId(nodeId, 'source', getElseIFLabel(conditionIndex))}
|
||||||
|
position={Position.Right}
|
||||||
|
translate={[18, 0]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(ListItem);
|
||||||
|
|
||||||
|
const Reference = ({
|
||||||
|
nodeId,
|
||||||
|
variable,
|
||||||
|
onSelect
|
||||||
|
}: {
|
||||||
|
nodeId: string;
|
||||||
|
variable?: ReferenceValueProps;
|
||||||
|
onSelect: (e: ReferenceValueProps) => void;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { referenceList, formatValue } = useReference({
|
||||||
|
nodeId,
|
||||||
|
valueType: WorkflowIOValueTypeEnum.any,
|
||||||
|
value: variable
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReferSelector
|
||||||
|
placeholder={t('选择引用变量')}
|
||||||
|
list={referenceList}
|
||||||
|
value={formatValue}
|
||||||
|
onSelect={onSelect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Different data types have different options */
|
||||||
|
const ConditionSelect = ({
|
||||||
|
condition,
|
||||||
|
variable,
|
||||||
|
onSelect
|
||||||
|
}: {
|
||||||
|
condition?: VariableConditionEnum;
|
||||||
|
variable?: ReferenceValueProps;
|
||||||
|
onSelect: (e: VariableConditionEnum) => void;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
|
// get condition type
|
||||||
|
const valueType = useMemo(() => {
|
||||||
|
return getReferenceDataValueType({
|
||||||
|
variable,
|
||||||
|
nodeList,
|
||||||
|
t
|
||||||
|
});
|
||||||
|
}, [nodeList, t, variable]);
|
||||||
|
|
||||||
|
const conditionList = useMemo(() => {
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.string) return stringConditionList;
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.number) return numberConditionList;
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.boolean) return booleanConditionList;
|
||||||
|
if (
|
||||||
|
valueType === WorkflowIOValueTypeEnum.chatHistory ||
|
||||||
|
valueType === WorkflowIOValueTypeEnum.datasetQuote ||
|
||||||
|
valueType === WorkflowIOValueTypeEnum.dynamic ||
|
||||||
|
valueType === WorkflowIOValueTypeEnum.selectApp ||
|
||||||
|
valueType === WorkflowIOValueTypeEnum.arrayBoolean ||
|
||||||
|
valueType === WorkflowIOValueTypeEnum.arrayNumber ||
|
||||||
|
valueType === WorkflowIOValueTypeEnum.arrayObject ||
|
||||||
|
valueType === WorkflowIOValueTypeEnum.arrayString
|
||||||
|
)
|
||||||
|
return arrayConditionList;
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.object) return objectConditionList;
|
||||||
|
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.any) return allConditionList;
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}, [valueType]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MySelect
|
||||||
|
w={'100%'}
|
||||||
|
list={conditionList}
|
||||||
|
value={condition}
|
||||||
|
onchange={onSelect}
|
||||||
|
placeholder="选择条件"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Different condition can be entered differently
|
||||||
|
empty, notEmpty: forbid input
|
||||||
|
boolean type: select true/false
|
||||||
|
*/
|
||||||
|
const ConditionValueInput = ({
|
||||||
|
value = '',
|
||||||
|
variable,
|
||||||
|
condition,
|
||||||
|
onChange
|
||||||
|
}: {
|
||||||
|
value?: string;
|
||||||
|
variable?: ReferenceValueProps;
|
||||||
|
condition?: VariableConditionEnum;
|
||||||
|
onChange: (e: string) => void;
|
||||||
|
}) => {
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
|
// get value type
|
||||||
|
const valueType = useMemo(() => {
|
||||||
|
if (!variable) return;
|
||||||
|
const node = nodeList.find((node) => node.nodeId === variable[0]);
|
||||||
|
|
||||||
|
if (!node) return WorkflowIOValueTypeEnum.any;
|
||||||
|
const output = node.outputs.find((item) => item.id === variable[1]);
|
||||||
|
|
||||||
|
if (!output) return WorkflowIOValueTypeEnum.any;
|
||||||
|
return output.valueType;
|
||||||
|
}, [nodeList, variable]);
|
||||||
|
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.boolean) {
|
||||||
|
return (
|
||||||
|
<MySelect
|
||||||
|
list={[
|
||||||
|
{ label: 'True', value: 'true' },
|
||||||
|
{ label: 'False', value: 'false' }
|
||||||
|
]}
|
||||||
|
onchange={onChange}
|
||||||
|
value={value}
|
||||||
|
placeholder={'选择值'}
|
||||||
|
isDisabled={
|
||||||
|
condition === VariableConditionEnum.isEmpty ||
|
||||||
|
condition === VariableConditionEnum.isNotEmpty
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<MyInput
|
||||||
|
value={value}
|
||||||
|
placeholder={'输入值'}
|
||||||
|
w={'100%'}
|
||||||
|
bg={'white'}
|
||||||
|
isDisabled={
|
||||||
|
condition === VariableConditionEnum.isEmpty ||
|
||||||
|
condition === VariableConditionEnum.isNotEmpty
|
||||||
|
}
|
||||||
|
onChange={(e) => onChange(e.target.value)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
|
import NodeCard from '../render/NodeCard';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import { Box, Button, Flex } from '@chakra-ui/react';
|
||||||
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { NodeProps, Position } from 'reactflow';
|
||||||
|
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||||
|
import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '../../../context';
|
||||||
|
import Container from '../../components/Container';
|
||||||
|
import DndDrag, { Draggable, DropResult } from '@fastgpt/web/components/common/DndDrag/index';
|
||||||
|
import { SourceHandle } from '../render/Handle';
|
||||||
|
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
import ListItem from './ListItem';
|
||||||
|
import { IfElseResultEnum } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
||||||
|
|
||||||
|
const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { nodeId, inputs = [] } = data;
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
|
const ifElseList = useMemo(
|
||||||
|
() =>
|
||||||
|
(inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList)
|
||||||
|
?.value as IfElseListItemType[]) || [],
|
||||||
|
[inputs]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onUpdateIfElseList = useCallback(
|
||||||
|
(value: IfElseListItemType[]) => {
|
||||||
|
const ifElseListInput = inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList);
|
||||||
|
if (!ifElseListInput) return;
|
||||||
|
|
||||||
|
onChangeNode({
|
||||||
|
nodeId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: NodeInputKeyEnum.ifElseList,
|
||||||
|
value: {
|
||||||
|
...ifElseListInput,
|
||||||
|
value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[inputs, nodeId, onChangeNode]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NodeCard selected={selected} maxW={'1000px'} {...data}>
|
||||||
|
<Box px={4} cursor={'default'}>
|
||||||
|
<DndDrag<IfElseListItemType>
|
||||||
|
onDragEndCb={(list) => onUpdateIfElseList(list)}
|
||||||
|
dataList={ifElseList}
|
||||||
|
renderClone={(provided, snapshot, rubric) => (
|
||||||
|
<ListItem
|
||||||
|
provided={provided}
|
||||||
|
snapshot={snapshot}
|
||||||
|
conditionItem={ifElseList[rubric.source.index]}
|
||||||
|
conditionIndex={rubric.source.index}
|
||||||
|
ifElseList={ifElseList}
|
||||||
|
onUpdateIfElseList={onUpdateIfElseList}
|
||||||
|
nodeId={nodeId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{(provided) => (
|
||||||
|
<Box {...provided.droppableProps} ref={provided.innerRef}>
|
||||||
|
{ifElseList.map((conditionItem, conditionIndex) => (
|
||||||
|
<Draggable
|
||||||
|
key={conditionIndex}
|
||||||
|
draggableId={conditionIndex.toString()}
|
||||||
|
index={conditionIndex}
|
||||||
|
>
|
||||||
|
{(provided, snapshot) => (
|
||||||
|
<ListItem
|
||||||
|
provided={provided}
|
||||||
|
snapshot={snapshot}
|
||||||
|
conditionItem={conditionItem}
|
||||||
|
conditionIndex={conditionIndex}
|
||||||
|
ifElseList={ifElseList}
|
||||||
|
onUpdateIfElseList={onUpdateIfElseList}
|
||||||
|
nodeId={nodeId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Draggable>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</DndDrag>
|
||||||
|
|
||||||
|
<Container position={'relative'}>
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Box color={'black'} fontSize={'lg'} ml={2}>
|
||||||
|
{IfElseResultEnum.ELSE}
|
||||||
|
</Box>
|
||||||
|
<SourceHandle
|
||||||
|
nodeId={nodeId}
|
||||||
|
handleId={getHandleId(nodeId, 'source', IfElseResultEnum.ELSE)}
|
||||||
|
position={Position.Right}
|
||||||
|
translate={[26, 0]}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Container>
|
||||||
|
</Box>
|
||||||
|
<Box py={3} px={6}>
|
||||||
|
<Button
|
||||||
|
variant={'whiteBase'}
|
||||||
|
w={'full'}
|
||||||
|
onClick={() => {
|
||||||
|
const ifElseListInput = inputs.find(
|
||||||
|
(input) => input.key === NodeInputKeyEnum.ifElseList
|
||||||
|
);
|
||||||
|
if (!ifElseListInput) return;
|
||||||
|
|
||||||
|
onUpdateIfElseList([
|
||||||
|
...ifElseList,
|
||||||
|
{
|
||||||
|
condition: 'AND',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
variable: undefined,
|
||||||
|
condition: undefined,
|
||||||
|
value: undefined
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('core.module.input.Add Branch')}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</NodeCard>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default React.memo(NodeIfElse);
|
||||||
@@ -33,6 +33,7 @@ import { getNanoid } from '@fastgpt/global/common/string/tools';
|
|||||||
import IOTitle from '../components/IOTitle';
|
import IOTitle from '../components/IOTitle';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext } from '../../context';
|
import { WorkflowContext } from '../../context';
|
||||||
|
import { putUpdateTeam } from '@/web/support/user/team/api';
|
||||||
|
|
||||||
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
||||||
|
|
||||||
@@ -47,20 +48,11 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
|
|
||||||
const requestUrl = inputs.find((item) => item.key === NodeInputKeyEnum.httpReqUrl);
|
const requestUrl = inputs.find((item) => item.key === NodeInputKeyEnum.httpReqUrl);
|
||||||
|
|
||||||
const { userInfo } = useUserStore();
|
const { userInfo, initUserInfo } = useUserStore();
|
||||||
|
|
||||||
const token = userInfo?.team.lafAccount?.token;
|
const token = userInfo?.team.lafAccount?.token;
|
||||||
const appid = userInfo?.team.lafAccount?.appid;
|
const appid = userInfo?.team.lafAccount?.appid;
|
||||||
|
|
||||||
// not config laf
|
|
||||||
if (!token || !appid) {
|
|
||||||
return (
|
|
||||||
<NodeCard minW={'350px'} selected={selected} {...data}>
|
|
||||||
<ConfigLaf />
|
|
||||||
</NodeCard>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: lafData,
|
data: lafData,
|
||||||
isLoading: isLoadingFunctions,
|
isLoading: isLoadingFunctions,
|
||||||
@@ -69,24 +61,32 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
['getLafFunctionList'],
|
['getLafFunctionList'],
|
||||||
async () => {
|
async () => {
|
||||||
// load laf app detail
|
// load laf app detail
|
||||||
const appDetail = await getLafAppDetail(appid);
|
try {
|
||||||
|
const appDetail = await getLafAppDetail(appid || '');
|
||||||
|
// load laf app functions
|
||||||
|
const schemaUrl = `https://${appDetail?.domain.domain}/_/api-docs?token=${appDetail?.openapi_token}`;
|
||||||
|
|
||||||
// load laf app functions
|
const schema = await getApiSchemaByUrl(schemaUrl);
|
||||||
const schemaUrl = `https://${appDetail?.domain.domain}/_/api-docs?token=${appDetail?.openapi_token}`;
|
const openApiSchema = await str2OpenApiSchema(JSON.stringify(schema));
|
||||||
|
const filterPostSchema = openApiSchema.pathData.filter((item) => item.method === 'post');
|
||||||
|
|
||||||
const schema = await getApiSchemaByUrl(schemaUrl);
|
return {
|
||||||
const openApiSchema = await str2OpenApiSchema(JSON.stringify(schema));
|
lafApp: appDetail,
|
||||||
const filterPostSchema = openApiSchema.pathData.filter((item) => item.method === 'post');
|
lafFunctions: filterPostSchema.map((item) => ({
|
||||||
|
...item,
|
||||||
return {
|
requestUrl: `https://${appDetail?.domain.domain}${item.path}`
|
||||||
lafApp: appDetail,
|
}))
|
||||||
lafFunctions: filterPostSchema.map((item) => ({
|
};
|
||||||
...item,
|
} catch (err) {
|
||||||
requestUrl: `https://${appDetail?.domain.domain}${item.path}`
|
await putUpdateTeam({
|
||||||
}))
|
teamId: userInfo?.team.teamId || '',
|
||||||
};
|
lafAccount: { token: '', appid: '', pat: '' }
|
||||||
|
});
|
||||||
|
initUserInfo();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
enabled: !!token && !!appid,
|
||||||
onError(err) {
|
onError(err) {
|
||||||
toast({
|
toast({
|
||||||
status: 'error',
|
status: 'error',
|
||||||
@@ -155,14 +155,14 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
desc: bodyParams[key].description,
|
desc: bodyParams[key].description,
|
||||||
required: requiredParams?.includes(key) || false,
|
required: requiredParams?.includes(key) || false,
|
||||||
value: `{{${key}}}`,
|
value: `{{${key}}}`,
|
||||||
type: 'string'
|
type: bodyParams[key].type
|
||||||
}))
|
}))
|
||||||
].filter((item) => !inputs.find((input) => input.key === item.name));
|
].filter((item) => !inputs.find((input) => input.key === item.name));
|
||||||
|
|
||||||
allParams.forEach((param) => {
|
allParams.forEach((param) => {
|
||||||
const newInput: FlowNodeInputItemType = {
|
const newInput: FlowNodeInputItemType = {
|
||||||
key: param.name,
|
key: param.name,
|
||||||
valueType: WorkflowIOValueTypeEnum.string,
|
valueType: param.type,
|
||||||
label: param.name,
|
label: param.name,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||||
required: param.required,
|
required: param.required,
|
||||||
@@ -215,54 +215,63 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
|||||||
successToast: t('common.Sync success')
|
successToast: t('common.Sync success')
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
// not config laf
|
||||||
<NodeCard minW={'350px'} selected={selected} {...data}>
|
if (!token || !appid) {
|
||||||
<Container>
|
return (
|
||||||
{/* select function */}
|
<NodeCard minW={'350px'} selected={selected} {...data}>
|
||||||
<MySelect
|
<ConfigLaf />
|
||||||
isLoading={isLoadingFunctions}
|
</NodeCard>
|
||||||
list={lafFunctionSelectList}
|
);
|
||||||
placeholder={t('core.module.laf.Select laf function')}
|
} else {
|
||||||
onchange={(e) => {
|
return (
|
||||||
onChangeNode({
|
<NodeCard minW={'350px'} selected={selected} {...data}>
|
||||||
nodeId,
|
<Container>
|
||||||
type: 'updateInput',
|
{/* select function */}
|
||||||
key: NodeInputKeyEnum.httpReqUrl,
|
<MySelect
|
||||||
value: {
|
isLoading={isLoadingFunctions}
|
||||||
...requestUrl,
|
list={lafFunctionSelectList}
|
||||||
value: e
|
placeholder={t('core.module.laf.Select laf function')}
|
||||||
}
|
onchange={(e) => {
|
||||||
});
|
onChangeNode({
|
||||||
}}
|
nodeId,
|
||||||
value={selectedFunction}
|
type: 'updateInput',
|
||||||
/>
|
key: NodeInputKeyEnum.httpReqUrl,
|
||||||
{/* auto set params and go to edit */}
|
value: {
|
||||||
{!!selectedFunction && (
|
...requestUrl,
|
||||||
<Flex justifyContent={'flex-end'} mt={2} gap={2}>
|
value: e
|
||||||
<Button isLoading={isSyncing} variant={'grayBase'} size={'sm'} onClick={onSyncParams}>
|
}
|
||||||
{t('core.module.Laf sync params')}
|
});
|
||||||
</Button>
|
}}
|
||||||
<Button
|
value={selectedFunction}
|
||||||
variant={'grayBase'}
|
/>
|
||||||
size={'sm'}
|
{/* auto set params and go to edit */}
|
||||||
onClick={() => {
|
{!!selectedFunction && (
|
||||||
const lafFunction = lafData?.lafFunctions.find(
|
<Flex justifyContent={'flex-end'} mt={2} gap={2}>
|
||||||
(item) => item.requestUrl === selectedFunction
|
<Button isLoading={isSyncing} variant={'grayBase'} size={'sm'} onClick={onSyncParams}>
|
||||||
);
|
{t('core.module.Laf sync params')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={'grayBase'}
|
||||||
|
size={'sm'}
|
||||||
|
onClick={() => {
|
||||||
|
const lafFunction = lafData?.lafFunctions.find(
|
||||||
|
(item) => item.requestUrl === selectedFunction
|
||||||
|
);
|
||||||
|
|
||||||
if (!lafFunction) return;
|
if (!lafFunction) return;
|
||||||
const url = `${feConfigs.lafEnv}/app/${lafData?.lafApp?.appid}/function${lafFunction?.path}?templateid=FastGPT_Laf`;
|
const url = `${feConfigs.lafEnv}/app/${lafData?.lafApp?.appid}/function${lafFunction?.path}?templateid=FastGPT_Laf`;
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('plugin.go to laf')}
|
{t('plugin.go to laf')}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
{!!selectedFunction && <RenderIO {...props} />}
|
{!!selectedFunction && <RenderIO {...props} />}
|
||||||
</NodeCard>
|
</NodeCard>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
export default React.memo(NodeLaf);
|
export default React.memo(NodeLaf);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,309 @@
|
|||||||
|
import React, { useCallback, useMemo } from 'react';
|
||||||
|
import NodeCard from './render/NodeCard';
|
||||||
|
import { NodeProps } from 'reactflow';
|
||||||
|
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Flex,
|
||||||
|
NumberDecrementStepper,
|
||||||
|
NumberIncrementStepper,
|
||||||
|
NumberInput,
|
||||||
|
NumberInputField,
|
||||||
|
NumberInputStepper,
|
||||||
|
Switch,
|
||||||
|
Textarea
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import { TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
|
||||||
|
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
|
import { useContextSelector } from 'use-context-selector';
|
||||||
|
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||||
|
import {
|
||||||
|
FlowNodeInputMap,
|
||||||
|
FlowNodeInputTypeEnum
|
||||||
|
} from '@fastgpt/global/core/workflow/node/constant';
|
||||||
|
import Container from '../components/Container';
|
||||||
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
|
import JsonEditor from '@fastgpt/web/components/common/Textarea/JsonEditor';
|
||||||
|
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||||
|
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||||
|
import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
|
||||||
|
import { ReferSelector, useReference } from './render/RenderInput/templates/Reference';
|
||||||
|
import { getReferenceDataValueType } from '@/web/core/workflow/utils';
|
||||||
|
import { isReferenceValue } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
|
||||||
|
const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
|
const { inputs = [], nodeId } = data;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
|
|
||||||
|
const updateList = useMemo(
|
||||||
|
() =>
|
||||||
|
(inputs.find((input) => input.key === NodeInputKeyEnum.updateList)
|
||||||
|
?.value as TUpdateListItem[]) || [],
|
||||||
|
[inputs]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onUpdateList = useCallback(
|
||||||
|
(value: TUpdateListItem[]) => {
|
||||||
|
const updateListInput = inputs.find((input) => input.key === NodeInputKeyEnum.updateList);
|
||||||
|
if (!updateListInput) return;
|
||||||
|
|
||||||
|
onChangeNode({
|
||||||
|
nodeId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: NodeInputKeyEnum.updateList,
|
||||||
|
value: {
|
||||||
|
...updateListInput,
|
||||||
|
value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[inputs, nodeId, onChangeNode]
|
||||||
|
);
|
||||||
|
|
||||||
|
const Render = useMemo(() => {
|
||||||
|
const menuList = [
|
||||||
|
{
|
||||||
|
renderType: FlowNodeInputTypeEnum.input,
|
||||||
|
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
|
||||||
|
label: t('core.workflow.inputType.Manual input')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
renderType: FlowNodeInputTypeEnum.reference,
|
||||||
|
icon: FlowNodeInputMap[FlowNodeInputTypeEnum.reference].icon,
|
||||||
|
label: t('core.workflow.inputType.Reference')
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{updateList.map((updateItem, index) => {
|
||||||
|
const valueType = getReferenceDataValueType({
|
||||||
|
variable: updateItem.variable,
|
||||||
|
nodeList,
|
||||||
|
t
|
||||||
|
});
|
||||||
|
|
||||||
|
const renderTypeData = menuList.find((item) => item.renderType === updateItem.renderType);
|
||||||
|
const handleUpdate = (newValue: ReferenceValueProps | string) => {
|
||||||
|
if (isReferenceValue(newValue)) {
|
||||||
|
onUpdateList(
|
||||||
|
updateList.map((update, i) =>
|
||||||
|
i === index ? { ...update, value: newValue as ReferenceValueProps } : update
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
onUpdateList(
|
||||||
|
updateList.map((update, i) =>
|
||||||
|
i === index ? { ...update, value: ['', newValue as string] } : update
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container key={index} mt={4} w={'full'} mx={0}>
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Flex w={'60px'}>{t('core.workflow.variable')}</Flex>
|
||||||
|
<Reference
|
||||||
|
nodeId={nodeId}
|
||||||
|
variable={updateItem.variable}
|
||||||
|
onSelect={(value) => {
|
||||||
|
onUpdateList(
|
||||||
|
updateList.map((update, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
return {
|
||||||
|
...update,
|
||||||
|
value: ['', ''],
|
||||||
|
valueType,
|
||||||
|
variable: value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return update;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Box flex={1} />
|
||||||
|
{updateList.length > 1 && (
|
||||||
|
<MyIcon
|
||||||
|
className="delete"
|
||||||
|
name={'delete'}
|
||||||
|
w={'14px'}
|
||||||
|
color={'myGray.600'}
|
||||||
|
cursor={'pointer'}
|
||||||
|
_hover={{ color: 'red.500' }}
|
||||||
|
position={'absolute'}
|
||||||
|
top={3}
|
||||||
|
right={3}
|
||||||
|
onClick={() => {
|
||||||
|
onUpdateList(updateList.filter((_, i) => i !== index));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
<Flex mt={2} w={'full'} alignItems={'center'} className="nodrag">
|
||||||
|
<Flex w={'60px'}>
|
||||||
|
<Box>{t('core.workflow.value')}</Box>
|
||||||
|
<MyTooltip
|
||||||
|
label={
|
||||||
|
menuList.find((item) => item.renderType === updateItem.renderType)?.label
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
size={'xs'}
|
||||||
|
bg={'white'}
|
||||||
|
borderRadius={'xs'}
|
||||||
|
mx={2}
|
||||||
|
onClick={() => {
|
||||||
|
onUpdateList(
|
||||||
|
updateList.map((update, i) => {
|
||||||
|
if (i === index) {
|
||||||
|
return {
|
||||||
|
...update,
|
||||||
|
value: ['', ''],
|
||||||
|
renderType:
|
||||||
|
updateItem.renderType === FlowNodeInputTypeEnum.input
|
||||||
|
? FlowNodeInputTypeEnum.reference
|
||||||
|
: FlowNodeInputTypeEnum.input
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return update;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MyIcon name={renderTypeData?.icon as any} w={'14px'} />
|
||||||
|
</Button>
|
||||||
|
</MyTooltip>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{/* Render input components */}
|
||||||
|
{(() => {
|
||||||
|
if (updateItem.renderType === FlowNodeInputTypeEnum.reference) {
|
||||||
|
return (
|
||||||
|
<Reference
|
||||||
|
nodeId={nodeId}
|
||||||
|
variable={updateItem.value}
|
||||||
|
valueType={valueType}
|
||||||
|
onSelect={handleUpdate}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.string) {
|
||||||
|
return (
|
||||||
|
<Textarea
|
||||||
|
bg="white"
|
||||||
|
value={updateItem.value?.[1] || ''}
|
||||||
|
w="300px"
|
||||||
|
onChange={(e) => handleUpdate(e.target.value)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.number) {
|
||||||
|
return (
|
||||||
|
<NumberInput value={Number(updateItem.value?.[1]) || 0}>
|
||||||
|
<NumberInputField
|
||||||
|
bg="white"
|
||||||
|
onChange={(e) => handleUpdate(e.target.value)}
|
||||||
|
/>
|
||||||
|
<NumberInputStepper>
|
||||||
|
<NumberIncrementStepper />
|
||||||
|
<NumberDecrementStepper />
|
||||||
|
</NumberInputStepper>
|
||||||
|
</NumberInput>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (valueType === WorkflowIOValueTypeEnum.boolean) {
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
size="lg"
|
||||||
|
defaultChecked={updateItem.value?.[1] === 'true'}
|
||||||
|
onChange={(e) => handleUpdate(String(e.target.checked))}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<JsonEditor
|
||||||
|
bg="white"
|
||||||
|
resize
|
||||||
|
w="300px"
|
||||||
|
value={String(updateItem.value?.[1] || '')}
|
||||||
|
onChange={(e) => {
|
||||||
|
handleUpdate(e);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</Flex>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, [nodeId, nodeList, onUpdateList, t, updateList]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NodeCard selected={selected} maxW={'1000px'} {...data}>
|
||||||
|
<Box px={4} pb={4}>
|
||||||
|
{Render}
|
||||||
|
<Flex className="nodrag" cursor={'default'} alignItems={'center'} position={'relative'}>
|
||||||
|
<Button
|
||||||
|
variant={'whiteBase'}
|
||||||
|
leftIcon={<SmallAddIcon />}
|
||||||
|
iconSpacing={1}
|
||||||
|
w={'full'}
|
||||||
|
size={'sm'}
|
||||||
|
onClick={() => {
|
||||||
|
onUpdateList([
|
||||||
|
...updateList,
|
||||||
|
{
|
||||||
|
variable: ['', ''],
|
||||||
|
value: ['', ''],
|
||||||
|
renderType: FlowNodeInputTypeEnum.input
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('common.Add New')}
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
</NodeCard>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default React.memo(NodeVariableUpdate);
|
||||||
|
|
||||||
|
const Reference = ({
|
||||||
|
nodeId,
|
||||||
|
variable,
|
||||||
|
valueType,
|
||||||
|
onSelect
|
||||||
|
}: {
|
||||||
|
nodeId: string;
|
||||||
|
variable?: ReferenceValueProps;
|
||||||
|
valueType?: WorkflowIOValueTypeEnum;
|
||||||
|
onSelect: (e: ReferenceValueProps) => void;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { referenceList, formatValue } = useReference({
|
||||||
|
nodeId,
|
||||||
|
valueType,
|
||||||
|
value: variable
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReferSelector
|
||||||
|
placeholder={t('选择引用变量')}
|
||||||
|
list={referenceList}
|
||||||
|
value={formatValue}
|
||||||
|
onSelect={onSelect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -28,7 +28,7 @@ export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
|
|||||||
edges.some((edge) => edge.targetHandle === getHandleId(nodeId, 'target', 'top')));
|
edges.some((edge) => edge.targetHandle === getHandleId(nodeId, 'target', 'top')));
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
return (
|
return hidden ? null : (
|
||||||
<MyTooltip label={t('core.workflow.tool.Handle')} shouldWrapChildren={false}>
|
<MyTooltip label={t('core.workflow.tool.Handle')} shouldWrapChildren={false}>
|
||||||
<Handle
|
<Handle
|
||||||
style={{
|
style={{
|
||||||
@@ -49,7 +49,7 @@ export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
|
|||||||
border={'4px solid #8774EE'}
|
border={'4px solid #8774EE'}
|
||||||
transform={'translate(0,-30%) rotate(45deg)'}
|
transform={'translate(0,-30%) rotate(45deg)'}
|
||||||
pointerEvents={'none'}
|
pointerEvents={'none'}
|
||||||
visibility={hidden ? 'hidden' : 'visible'}
|
visibility={'visible'}
|
||||||
/>
|
/>
|
||||||
</Handle>
|
</Handle>
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
|
|||||||
@@ -200,14 +200,19 @@ const MyTargetHandle = React.memo(function MyTargetHandle({
|
|||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectingEdge?.handleId && !connectingEdge.handleId?.includes('source')) return false;
|
if (connectingEdge?.handleId && !connectingEdge.handleId?.includes('source')) return false;
|
||||||
|
|
||||||
// Same source node
|
// From same source node
|
||||||
if (connectedEdges.some((item) => item.target === nodeId && item.targetHandle !== handleId))
|
if (
|
||||||
|
connectedEdges.some(
|
||||||
|
(item) => item.source === connectingEdge?.nodeId && item.target === nodeId
|
||||||
|
)
|
||||||
|
)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, [connectedEdges, connectingEdge?.handleId, edges, handleId, node, nodeId]);
|
}, [connectedEdges, connectingEdge?.handleId, connectingEdge?.nodeId, edges, node, nodeId]);
|
||||||
|
|
||||||
const RenderHandle = useMemo(() => {
|
const RenderHandle = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ type Props = FlowNodeItemType & {
|
|||||||
|
|
||||||
const NodeCard = (props: Props) => {
|
const NodeCard = (props: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
children,
|
children,
|
||||||
avatar = LOGO_ICON,
|
avatar = LOGO_ICON,
|
||||||
@@ -59,6 +61,13 @@ const NodeCard = (props: Props) => {
|
|||||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
const setHoverNodeId = useContextSelector(WorkflowContext, (v) => v.setHoverNodeId);
|
const setHoverNodeId = useContextSelector(WorkflowContext, (v) => v.setHoverNodeId);
|
||||||
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
||||||
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
|
// custom title edit
|
||||||
|
const { onOpenModal: onOpenCustomTitleModal, EditModal: EditTitleModal } = useEditTitle({
|
||||||
|
title: t('common.Custom Title'),
|
||||||
|
placeholder: t('app.module.Custom Title Tip') || ''
|
||||||
|
});
|
||||||
|
|
||||||
const showToolHandle = useMemo(
|
const showToolHandle = useMemo(
|
||||||
() => isTool && !!nodeList.find((item) => item?.flowNodeType === FlowNodeTypeEnum.tools),
|
() => isTool && !!nodeList.find((item) => item?.flowNodeType === FlowNodeTypeEnum.tools),
|
||||||
@@ -70,7 +79,6 @@ const NodeCard = (props: Props) => {
|
|||||||
return (
|
return (
|
||||||
<Box position={'relative'}>
|
<Box position={'relative'}>
|
||||||
{/* debug */}
|
{/* debug */}
|
||||||
<NodeDebugResponse nodeId={nodeId} debugResult={debugResult} />
|
|
||||||
<Box className="custom-drag-handle" px={4} py={3}>
|
<Box className="custom-drag-handle" px={4} py={3}>
|
||||||
{/* tool target handle */}
|
{/* tool target handle */}
|
||||||
{showToolHandle && <ToolTargetHandle nodeId={nodeId} />}
|
{showToolHandle && <ToolTargetHandle nodeId={nodeId} />}
|
||||||
@@ -81,13 +89,42 @@ const NodeCard = (props: Props) => {
|
|||||||
<Box ml={3} fontSize={'lg'} fontWeight={'medium'}>
|
<Box ml={3} fontSize={'lg'} fontWeight={'medium'}>
|
||||||
{t(name)}
|
{t(name)}
|
||||||
</Box>
|
</Box>
|
||||||
|
{!menuForbid?.rename && (
|
||||||
|
<MyIcon
|
||||||
|
className="controller-rename"
|
||||||
|
display={'none'}
|
||||||
|
name={'edit'}
|
||||||
|
w={'14px'}
|
||||||
|
cursor={'pointer'}
|
||||||
|
ml={1}
|
||||||
|
color={'myGray.500'}
|
||||||
|
_hover={{ color: 'primary.600' }}
|
||||||
|
onClick={() => {
|
||||||
|
onOpenCustomTitleModal({
|
||||||
|
defaultVal: name,
|
||||||
|
onSuccess: (e) => {
|
||||||
|
if (!e) {
|
||||||
|
return toast({
|
||||||
|
title: t('app.modules.Title is required'),
|
||||||
|
status: 'warning'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onChangeNode({
|
||||||
|
nodeId,
|
||||||
|
type: 'attr',
|
||||||
|
key: 'name',
|
||||||
|
value: e
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
<MenuRender
|
<MenuRender
|
||||||
name={name}
|
|
||||||
nodeId={nodeId}
|
nodeId={nodeId}
|
||||||
pluginId={pluginId}
|
pluginId={pluginId}
|
||||||
flowNodeType={flowNodeType}
|
flowNodeType={flowNodeType}
|
||||||
inputs={inputs}
|
|
||||||
menuForbid={menuForbid}
|
menuForbid={menuForbid}
|
||||||
/>
|
/>
|
||||||
<NodeIntro nodeId={nodeId} intro={intro} />
|
<NodeIntro nodeId={nodeId} intro={intro} />
|
||||||
@@ -96,16 +133,17 @@ const NodeCard = (props: Props) => {
|
|||||||
);
|
);
|
||||||
}, [
|
}, [
|
||||||
nodeId,
|
nodeId,
|
||||||
debugResult,
|
|
||||||
showToolHandle,
|
showToolHandle,
|
||||||
avatar,
|
avatar,
|
||||||
t,
|
t,
|
||||||
name,
|
name,
|
||||||
|
menuForbid,
|
||||||
pluginId,
|
pluginId,
|
||||||
flowNodeType,
|
flowNodeType,
|
||||||
inputs,
|
intro,
|
||||||
menuForbid,
|
onOpenCustomTitleModal,
|
||||||
intro
|
onChangeNode,
|
||||||
|
toast
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -123,6 +161,9 @@ const NodeCard = (props: Props) => {
|
|||||||
},
|
},
|
||||||
'& .controller-debug': {
|
'& .controller-debug': {
|
||||||
display: 'block'
|
display: 'block'
|
||||||
|
},
|
||||||
|
'& .controller-rename': {
|
||||||
|
display: 'block'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onMouseEnter={() => setHoverNodeId(nodeId)}
|
onMouseEnter={() => setHoverNodeId(nodeId)}
|
||||||
@@ -136,10 +177,13 @@ const NodeCard = (props: Props) => {
|
|||||||
borderColor: selected ? 'primary.600' : 'borderColor.base'
|
borderColor: selected ? 'primary.600' : 'borderColor.base'
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
<NodeDebugResponse nodeId={nodeId} debugResult={debugResult} />
|
||||||
{Header}
|
{Header}
|
||||||
{children}
|
{children}
|
||||||
<ConnectionSourceHandle nodeId={nodeId} />
|
<ConnectionSourceHandle nodeId={nodeId} />
|
||||||
<ConnectionTargetHandle nodeId={nodeId} />
|
<ConnectionTargetHandle nodeId={nodeId} />
|
||||||
|
|
||||||
|
<EditTitleModal maxLength={20} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -147,18 +191,14 @@ const NodeCard = (props: Props) => {
|
|||||||
export default React.memo(NodeCard);
|
export default React.memo(NodeCard);
|
||||||
|
|
||||||
const MenuRender = React.memo(function MenuRender({
|
const MenuRender = React.memo(function MenuRender({
|
||||||
name,
|
|
||||||
nodeId,
|
nodeId,
|
||||||
pluginId,
|
pluginId,
|
||||||
flowNodeType,
|
flowNodeType,
|
||||||
inputs,
|
|
||||||
menuForbid
|
menuForbid
|
||||||
}: {
|
}: {
|
||||||
name: string;
|
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
pluginId?: string;
|
pluginId?: string;
|
||||||
flowNodeType: Props['flowNodeType'];
|
flowNodeType: Props['flowNodeType'];
|
||||||
inputs: Props['inputs'];
|
|
||||||
menuForbid?: Props['menuForbid'];
|
menuForbid?: Props['menuForbid'];
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -169,11 +209,7 @@ const MenuRender = React.memo(function MenuRender({
|
|||||||
const { openConfirm: onOpenConfirmSync, ConfirmModal: ConfirmSyncModal } = useConfirm({
|
const { openConfirm: onOpenConfirmSync, ConfirmModal: ConfirmSyncModal } = useConfirm({
|
||||||
content: t('module.Confirm Sync Plugin')
|
content: t('module.Confirm Sync Plugin')
|
||||||
});
|
});
|
||||||
// custom title edit
|
|
||||||
const { onOpenModal: onOpenCustomTitleModal, EditModal: EditTitleModal } = useEditTitle({
|
|
||||||
title: t('common.Custom Title'),
|
|
||||||
placeholder: t('app.module.Custom Title Tip') || ''
|
|
||||||
});
|
|
||||||
const { openConfirm: onOpenConfirmDeleteNode, ConfirmModal: ConfirmDeleteModal } = useConfirm({
|
const { openConfirm: onOpenConfirmDeleteNode, ConfirmModal: ConfirmDeleteModal } = useConfirm({
|
||||||
content: t('core.module.Confirm Delete Node'),
|
content: t('core.module.Confirm Delete Node'),
|
||||||
type: 'delete'
|
type: 'delete'
|
||||||
@@ -182,7 +218,6 @@ const MenuRender = React.memo(function MenuRender({
|
|||||||
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||||
const onResetNode = useContextSelector(WorkflowContext, (v) => v.onResetNode);
|
const onResetNode = useContextSelector(WorkflowContext, (v) => v.onResetNode);
|
||||||
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
|
||||||
|
|
||||||
const onCopyNode = useCallback(
|
const onCopyNode = useCallback(
|
||||||
(nodeId: string) => {
|
(nodeId: string) => {
|
||||||
@@ -223,6 +258,22 @@ const MenuRender = React.memo(function MenuRender({
|
|||||||
},
|
},
|
||||||
[setEdges, setNodes]
|
[setEdges, setNodes]
|
||||||
);
|
);
|
||||||
|
const onclickSyncVersion = useCallback(async () => {
|
||||||
|
if (!pluginId) return;
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
onResetNode({
|
||||||
|
id: nodeId,
|
||||||
|
node: await getPreviewPluginModule(pluginId)
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return toast({
|
||||||
|
status: 'error',
|
||||||
|
title: getErrText(e, t('plugin.Get Plugin Module Detail Failed'))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
}, [nodeId, onResetNode, pluginId, setLoading, t, toast]);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
const menuList = [
|
const menuList = [
|
||||||
@@ -236,61 +287,6 @@ const MenuRender = React.memo(function MenuRender({
|
|||||||
onClick: () => openDebugNode({ entryNodeId: nodeId })
|
onClick: () => openDebugNode({ entryNodeId: nodeId })
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
...(flowNodeType === FlowNodeTypeEnum.pluginModule
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
icon: 'common/refreshLight',
|
|
||||||
label: t('plugin.Synchronous version'),
|
|
||||||
variant: 'whiteBase',
|
|
||||||
onClick: () => {
|
|
||||||
if (!pluginId) return;
|
|
||||||
onOpenConfirmSync(async () => {
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
const pluginModule = await getPreviewPluginModule(pluginId);
|
|
||||||
onResetNode({
|
|
||||||
id: nodeId,
|
|
||||||
module: pluginModule
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
return toast({
|
|
||||||
status: 'error',
|
|
||||||
title: getErrText(e, t('plugin.Get Plugin Module Detail Failed'))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setLoading(false);
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
...(menuForbid?.rename
|
|
||||||
? []
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
icon: 'edit',
|
|
||||||
label: t('common.Rename'),
|
|
||||||
variant: 'whiteBase',
|
|
||||||
onClick: () =>
|
|
||||||
onOpenCustomTitleModal({
|
|
||||||
defaultVal: name,
|
|
||||||
onSuccess: (e) => {
|
|
||||||
if (!e) {
|
|
||||||
return toast({
|
|
||||||
title: t('app.modules.Title is required'),
|
|
||||||
status: 'warning'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
onChangeNode({
|
|
||||||
nodeId,
|
|
||||||
type: 'attr',
|
|
||||||
key: 'name',
|
|
||||||
value: e
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]),
|
|
||||||
...(menuForbid?.copy
|
...(menuForbid?.copy
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
@@ -301,6 +297,17 @@ const MenuRender = React.memo(function MenuRender({
|
|||||||
onClick: () => onCopyNode(nodeId)
|
onClick: () => onCopyNode(nodeId)
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
|
...(flowNodeType === FlowNodeTypeEnum.pluginModule
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
icon: 'common/refreshLight',
|
||||||
|
label: t('plugin.Synchronous version'),
|
||||||
|
variant: 'whiteBase',
|
||||||
|
onClick: onOpenConfirmSync(onclickSyncVersion)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
|
||||||
...(menuForbid?.delete
|
...(menuForbid?.delete
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
@@ -342,7 +349,6 @@ const MenuRender = React.memo(function MenuRender({
|
|||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
<EditTitleModal maxLength={20} />
|
|
||||||
<ConfirmSyncModal />
|
<ConfirmSyncModal />
|
||||||
<ConfirmDeleteModal />
|
<ConfirmDeleteModal />
|
||||||
<DebugInputModal />
|
<DebugInputModal />
|
||||||
@@ -352,26 +358,18 @@ const MenuRender = React.memo(function MenuRender({
|
|||||||
ConfirmDeleteModal,
|
ConfirmDeleteModal,
|
||||||
ConfirmSyncModal,
|
ConfirmSyncModal,
|
||||||
DebugInputModal,
|
DebugInputModal,
|
||||||
EditTitleModal,
|
|
||||||
flowNodeType,
|
flowNodeType,
|
||||||
menuForbid?.copy,
|
menuForbid?.copy,
|
||||||
menuForbid?.debug,
|
menuForbid?.debug,
|
||||||
menuForbid?.delete,
|
menuForbid?.delete,
|
||||||
menuForbid?.rename,
|
|
||||||
name,
|
|
||||||
nodeId,
|
nodeId,
|
||||||
onChangeNode,
|
|
||||||
onCopyNode,
|
onCopyNode,
|
||||||
onDelNode,
|
onDelNode,
|
||||||
onOpenConfirmDeleteNode,
|
onOpenConfirmDeleteNode,
|
||||||
onOpenConfirmSync,
|
onOpenConfirmSync,
|
||||||
onOpenCustomTitleModal,
|
onclickSyncVersion,
|
||||||
onResetNode,
|
|
||||||
openDebugNode,
|
openDebugNode,
|
||||||
pluginId,
|
t
|
||||||
setLoading,
|
|
||||||
t,
|
|
||||||
toast
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return Render;
|
return Render;
|
||||||
@@ -388,7 +386,7 @@ const NodeIntro = React.memo(function NodeIntro({
|
|||||||
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const moduleIsTool = useMemo(() => {
|
const NodeIsTool = useMemo(() => {
|
||||||
const { isTool } = splitToolInputs([], nodeId);
|
const { isTool } = splitToolInputs([], nodeId);
|
||||||
return isTool;
|
return isTool;
|
||||||
}, [nodeId, splitToolInputs]);
|
}, [nodeId, splitToolInputs]);
|
||||||
@@ -407,7 +405,7 @@ const NodeIntro = React.memo(function NodeIntro({
|
|||||||
<Box fontSize={'xs'} color={'myGray.600'} flex={'1 0 0'}>
|
<Box fontSize={'xs'} color={'myGray.600'} flex={'1 0 0'}>
|
||||||
{t(intro)}
|
{t(intro)}
|
||||||
</Box>
|
</Box>
|
||||||
{moduleIsTool && (
|
{NodeIsTool && (
|
||||||
<Button
|
<Button
|
||||||
size={'xs'}
|
size={'xs'}
|
||||||
variant={'whiteBase'}
|
variant={'whiteBase'}
|
||||||
@@ -432,7 +430,7 @@ const NodeIntro = React.memo(function NodeIntro({
|
|||||||
<EditIntroModal maxLength={500} />
|
<EditIntroModal maxLength={500} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}, [EditIntroModal, intro, moduleIsTool, nodeId, onChangeNode, onOpenIntroModal, t]);
|
}, [EditIntroModal, intro, NodeIsTool, nodeId, onChangeNode, onOpenIntroModal, t]);
|
||||||
|
|
||||||
return Render;
|
return Render;
|
||||||
});
|
});
|
||||||
@@ -526,7 +524,8 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
|||||||
top={0}
|
top={0}
|
||||||
zIndex={10}
|
zIndex={10}
|
||||||
w={'420px'}
|
w={'420px'}
|
||||||
maxH={'540px'}
|
maxH={'100%'}
|
||||||
|
minH={'300px'}
|
||||||
overflowY={'auto'}
|
overflowY={'auto'}
|
||||||
border={'base'}
|
border={'base'}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export default React.memo(Reference);
|
|||||||
|
|
||||||
export const useReference = ({
|
export const useReference = ({
|
||||||
nodeId,
|
nodeId,
|
||||||
valueType,
|
valueType = WorkflowIOValueTypeEnum.any,
|
||||||
value
|
value
|
||||||
}: {
|
}: {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import { createContext } from 'use-context-selector';
|
|||||||
import { defaultRunningStatus } from './constants';
|
import { defaultRunningStatus } from './constants';
|
||||||
import { checkNodeRunStatus } from '@fastgpt/global/core/workflow/runtime/utils';
|
import { checkNodeRunStatus } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
|
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
|
||||||
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
|
||||||
|
|
||||||
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
||||||
|
|
||||||
@@ -56,7 +55,7 @@ type WorkflowContextType = {
|
|||||||
hoverNodeId?: string;
|
hoverNodeId?: string;
|
||||||
setHoverNodeId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
setHoverNodeId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||||
onUpdateNodeError: (node: string, isError: Boolean) => void;
|
onUpdateNodeError: (node: string, isError: Boolean) => void;
|
||||||
onResetNode: (e: { id: string; module: FlowNodeTemplateType }) => void;
|
onResetNode: (e: { id: string; node: FlowNodeTemplateType }) => void;
|
||||||
onChangeNode: (e: FlowNodeChangeProps) => void;
|
onChangeNode: (e: FlowNodeChangeProps) => void;
|
||||||
|
|
||||||
// edges
|
// edges
|
||||||
@@ -160,7 +159,7 @@ export const WorkflowContext = createContext<WorkflowContextType>({
|
|||||||
onEdgesChange: function (changes: EdgeChange[]): void {
|
onEdgesChange: function (changes: EdgeChange[]): void {
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
onResetNode: function (e: { id: string; module: FlowNodeTemplateType }): void {
|
onResetNode: function (e: { id: string; node: FlowNodeTemplateType }): void {
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
onDelEdge: function (e: {
|
onDelEdge: function (e: {
|
||||||
@@ -256,7 +255,11 @@ const WorkflowContextProvider = ({
|
|||||||
const [nodes = [], setNodes, onNodesChange] = useNodesState<FlowNodeItemType>([]);
|
const [nodes = [], setNodes, onNodesChange] = useNodesState<FlowNodeItemType>([]);
|
||||||
const [hoverNodeId, setHoverNodeId] = useState<string>();
|
const [hoverNodeId, setHoverNodeId] = useState<string>();
|
||||||
|
|
||||||
const nodeList = useCreation(() => nodes.map((node) => node.data), [nodes]);
|
const nodeListString = JSON.stringify(nodes.map((node) => node.data));
|
||||||
|
const nodeList = useMemo(
|
||||||
|
() => JSON.parse(nodeListString) as FlowNodeItemType[],
|
||||||
|
[nodeListString]
|
||||||
|
);
|
||||||
|
|
||||||
const hasToolNode = useMemo(() => {
|
const hasToolNode = useMemo(() => {
|
||||||
return !!nodes.find((node) => node.data.flowNodeType === FlowNodeTypeEnum.tools);
|
return !!nodes.find((node) => node.data.flowNodeType === FlowNodeTypeEnum.tools);
|
||||||
@@ -276,31 +279,30 @@ const WorkflowContextProvider = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// reset a node data. delete edge and replace it
|
// reset a node data. delete edge and replace it
|
||||||
const onResetNode = useMemoizedFn(
|
const onResetNode = useMemoizedFn(({ id, node }: { id: string; node: FlowNodeTemplateType }) => {
|
||||||
({ id, module }: { id: string; module: FlowNodeTemplateType }) => {
|
setNodes((state) =>
|
||||||
setNodes((state) =>
|
state.map((item) => {
|
||||||
state.map((node) => {
|
if (item.id === id) {
|
||||||
if (node.id === id) {
|
return {
|
||||||
// delete edge
|
...item,
|
||||||
node.data.inputs.forEach((item) => {
|
data: {
|
||||||
onDelEdge({ nodeId: id, targetHandle: item.key });
|
...item.data,
|
||||||
});
|
|
||||||
node.data.outputs.forEach((item) => {
|
|
||||||
onDelEdge({ nodeId: id, sourceHandle: item.key });
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...node,
|
...node,
|
||||||
data: {
|
inputs: node.inputs.map((input) => {
|
||||||
...node.data,
|
const value =
|
||||||
...module
|
item.data.inputs.find((i) => i.key === input.key)?.value ?? input.value;
|
||||||
}
|
return {
|
||||||
};
|
...input,
|
||||||
}
|
value
|
||||||
return node;
|
};
|
||||||
})
|
})
|
||||||
);
|
}
|
||||||
}
|
};
|
||||||
);
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const onChangeNode = useMemoizedFn((props: FlowNodeChangeProps) => {
|
const onChangeNode = useMemoizedFn((props: FlowNodeChangeProps) => {
|
||||||
const { nodeId, type } = props;
|
const { nodeId, type } = props;
|
||||||
@@ -410,7 +412,7 @@ const WorkflowContextProvider = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* If the module is connected by a tool, the tool input and the normal input are separated */
|
/* If the module is connected by a tool, the tool input and the normal input are separated */
|
||||||
const splitToolInputs = useMemoizedFn((inputs: FlowNodeInputItemType[], nodeId: string) => {
|
const splitToolInputs = (inputs: FlowNodeInputItemType[], nodeId: string) => {
|
||||||
const isTool = !!edges.find(
|
const isTool = !!edges.find(
|
||||||
(edge) => edge.targetHandle === NodeOutputKeyEnum.selectedTools && edge.target === nodeId
|
(edge) => edge.targetHandle === NodeOutputKeyEnum.selectedTools && edge.target === nodeId
|
||||||
);
|
);
|
||||||
@@ -423,12 +425,11 @@ const WorkflowContextProvider = ({
|
|||||||
return !item.toolDescription;
|
return !item.toolDescription;
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
});
|
};
|
||||||
|
|
||||||
const initData = useMemoizedFn(
|
const initData = useMemoizedFn(
|
||||||
async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {
|
async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {
|
||||||
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })));
|
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })));
|
||||||
|
|
||||||
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })));
|
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -486,7 +487,6 @@ const WorkflowContextProvider = ({
|
|||||||
// 3. Set entry node status to running
|
// 3. Set entry node status to running
|
||||||
entryNodes.forEach((node) => {
|
entryNodes.forEach((node) => {
|
||||||
if (runtimeNodeStatus[node.nodeId] !== 'wait') {
|
if (runtimeNodeStatus[node.nodeId] !== 'wait') {
|
||||||
console.log(node.name);
|
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
nodeId: node.nodeId,
|
nodeId: node.nodeId,
|
||||||
type: 'attr',
|
type: 'attr',
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ const LafAccountModal = ({
|
|||||||
enabled: !!lafToken,
|
enabled: !!lafToken,
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (!getValues('appid') && data.length > 0) {
|
if (!getValues('appid') && data.length > 0) {
|
||||||
setValue('appid', data[0].appid);
|
setValue('appid', data.filter((app) => app.state === 'Running')[0]?.appid);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (err) => {
|
onError: (err) => {
|
||||||
@@ -175,7 +175,13 @@ const LafAccountModal = ({
|
|||||||
)}
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button variant={'whiteBase'} onClick={onClose}>
|
<Button
|
||||||
|
variant={'whiteBase'}
|
||||||
|
onClick={() => {
|
||||||
|
initUserInfo();
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
{t('common.Close')}
|
{t('common.Close')}
|
||||||
</Button>
|
</Button>
|
||||||
{appid && (
|
{appid && (
|
||||||
|
|||||||
@@ -63,7 +63,10 @@ export async function getInitConfig() {
|
|||||||
initSystemConfig(),
|
initSystemConfig(),
|
||||||
// getSimpleModeTemplates(),
|
// getSimpleModeTemplates(),
|
||||||
getSystemVersion(),
|
getSystemVersion(),
|
||||||
getSystemPlugin()
|
getSystemPlugin(),
|
||||||
|
|
||||||
|
// abandon
|
||||||
|
getSystemPluginV1()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log({
|
console.log({
|
||||||
@@ -164,3 +167,29 @@ function getSystemPlugin() {
|
|||||||
|
|
||||||
global.communityPlugins = fileTemplates;
|
global.communityPlugins = fileTemplates;
|
||||||
}
|
}
|
||||||
|
function getSystemPluginV1() {
|
||||||
|
if (global.communityPluginsV1 && global.communityPluginsV1.length > 0) return;
|
||||||
|
|
||||||
|
const basePath =
|
||||||
|
process.env.NODE_ENV === 'development'
|
||||||
|
? 'data/pluginTemplates/v1'
|
||||||
|
: '/app/data/pluginTemplates/v1';
|
||||||
|
// read data/pluginTemplates directory, get all json file
|
||||||
|
const files = readdirSync(basePath);
|
||||||
|
// filter json file
|
||||||
|
const filterFiles = files.filter((item) => item.endsWith('.json'));
|
||||||
|
|
||||||
|
// read json file
|
||||||
|
const fileTemplates: (PluginTemplateType & { weight: number })[] = filterFiles.map((filename) => {
|
||||||
|
const content = readFileSync(`${basePath}/${filename}`, 'utf-8');
|
||||||
|
return {
|
||||||
|
...JSON.parse(content),
|
||||||
|
id: `${PluginSourceEnum.community}-${filename.replace('.json', '')}`,
|
||||||
|
source: PluginSourceEnum.community
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
fileTemplates.sort((a, b) => b.weight - a.weight);
|
||||||
|
|
||||||
|
global.communityPluginsV1 = fileTemplates;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ import { SseResponseEventEnum } from '@fastgpt/global/core/workflow/runtime/cons
|
|||||||
import { responseWrite } from '@fastgpt/service/common/response';
|
import { responseWrite } from '@fastgpt/service/common/response';
|
||||||
import { pushChatUsage } from '@/service/support/wallet/usage/push';
|
import { pushChatUsage } from '@/service/support/wallet/usage/push';
|
||||||
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
||||||
import type { ChatItemType, ChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
import type {
|
||||||
|
ChatItemType,
|
||||||
|
ChatItemValueItemType,
|
||||||
|
UserChatItemValueItemType
|
||||||
|
} from '@fastgpt/global/core/chat/type';
|
||||||
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
||||||
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
|
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
|
||||||
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
||||||
@@ -13,10 +17,11 @@ import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/a
|
|||||||
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||||
import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||||
import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
|
import { removeEmptyUserInput } from '@fastgpt/global/core/chat/utils';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
history: ChatItemType[];
|
history: ChatItemType[];
|
||||||
prompt: ChatItemValueItemType[];
|
prompt: UserChatItemValueItemType[];
|
||||||
nodes: RuntimeNodeItemType[];
|
nodes: RuntimeNodeItemType[];
|
||||||
edges: RuntimeEdgeItemType[];
|
edges: RuntimeEdgeItemType[];
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
@@ -33,7 +38,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
res.end();
|
res.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
let {
|
||||||
nodes = [],
|
nodes = [],
|
||||||
edges = [],
|
edges = [],
|
||||||
history = [],
|
history = [],
|
||||||
@@ -66,10 +71,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
// auth balance
|
// auth balance
|
||||||
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
||||||
|
|
||||||
const { text, files } = chatValue2RuntimePrompt(prompt);
|
|
||||||
|
|
||||||
/* start process */
|
/* start process */
|
||||||
const { flowResponses, flowUsages } = await dispatchWorkFlow({
|
const { flowResponses, flowUsages, newVariables } = await dispatchWorkFlow({
|
||||||
res,
|
res,
|
||||||
mode: 'test',
|
mode: 'test',
|
||||||
teamId,
|
teamId,
|
||||||
@@ -78,11 +81,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
appId,
|
appId,
|
||||||
runtimeNodes: nodes,
|
runtimeNodes: nodes,
|
||||||
runtimeEdges: edges,
|
runtimeEdges: edges,
|
||||||
variables: {
|
variables,
|
||||||
...variables,
|
query: removeEmptyUserInput(prompt),
|
||||||
userChatInput: text
|
|
||||||
},
|
|
||||||
inputFiles: files,
|
|
||||||
histories: history,
|
histories: history,
|
||||||
stream: true,
|
stream: true,
|
||||||
detail: true,
|
detail: true,
|
||||||
@@ -99,6 +99,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
event: SseResponseEventEnum.flowResponses,
|
event: SseResponseEventEnum.flowResponses,
|
||||||
data: JSON.stringify(flowResponses)
|
data: JSON.stringify(flowResponses)
|
||||||
});
|
});
|
||||||
|
responseWrite({
|
||||||
|
res,
|
||||||
|
event: SseResponseEventEnum.updateVariables,
|
||||||
|
data: JSON.stringify(newVariables)
|
||||||
|
});
|
||||||
res.end();
|
res.end();
|
||||||
|
|
||||||
pushChatUsage({
|
pushChatUsage({
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
import { jsonRes } from '@fastgpt/service/common/response';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
|
||||||
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
||||||
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
||||||
import type { InitChatProps, InitChatResponse } from '@/global/core/chat/api.d';
|
import type { InitChatProps, InitChatResponse } from '@/global/core/chat/api.d';
|
||||||
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
|
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
|
||||||
@@ -10,74 +9,73 @@ import { getChatItems } from '@fastgpt/service/core/chat/controller';
|
|||||||
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { getAppLatestVersion } from '@fastgpt/service/core/app/controller';
|
import { getAppLatestVersion } from '@fastgpt/service/core/app/controller';
|
||||||
|
import { NextAPI } from '@/service/middle/entry';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
async function handler(
|
||||||
try {
|
req: NextApiRequest,
|
||||||
await connectToDatabase();
|
res: NextApiResponse
|
||||||
|
): Promise<InitChatResponse | void> {
|
||||||
|
let { appId, chatId, loadCustomFeedbacks } = req.query as InitChatProps;
|
||||||
|
|
||||||
let { appId, chatId, loadCustomFeedbacks } = req.query as InitChatProps;
|
if (!appId) {
|
||||||
|
return jsonRes(res, {
|
||||||
if (!appId) {
|
code: 501,
|
||||||
return jsonRes(res, {
|
message: "You don't have an app yet"
|
||||||
code: 501,
|
|
||||||
message: "You don't have an app yet"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// auth app permission
|
|
||||||
const [{ app, tmbId }, chat] = await Promise.all([
|
|
||||||
authApp({
|
|
||||||
req,
|
|
||||||
authToken: true,
|
|
||||||
appId,
|
|
||||||
per: 'r'
|
|
||||||
}),
|
|
||||||
chatId ? MongoChat.findOne({ appId, chatId }) : undefined
|
|
||||||
]);
|
|
||||||
|
|
||||||
// auth chat permission
|
|
||||||
if (chat && !app.canWrite && String(tmbId) !== String(chat?.tmbId)) {
|
|
||||||
throw new Error(ChatErrEnum.unAuthChat);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get app and history
|
|
||||||
const [{ history }, { nodes }] = await Promise.all([
|
|
||||||
getChatItems({
|
|
||||||
appId,
|
|
||||||
chatId,
|
|
||||||
limit: 30,
|
|
||||||
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback ${
|
|
||||||
DispatchNodeResponseKeyEnum.nodeResponse
|
|
||||||
} ${loadCustomFeedbacks ? 'customFeedbacks' : ''}`
|
|
||||||
}),
|
|
||||||
getAppLatestVersion(app._id, app)
|
|
||||||
]);
|
|
||||||
|
|
||||||
jsonRes<InitChatResponse>(res, {
|
|
||||||
data: {
|
|
||||||
chatId,
|
|
||||||
appId,
|
|
||||||
title: chat?.title || '新对话',
|
|
||||||
userAvatar: undefined,
|
|
||||||
variables: chat?.variables || {},
|
|
||||||
history,
|
|
||||||
app: {
|
|
||||||
userGuideModule: getGuideModule(nodes),
|
|
||||||
chatModels: getChatModelNameListByModules(nodes),
|
|
||||||
name: app.name,
|
|
||||||
avatar: app.avatar,
|
|
||||||
intro: app.intro
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// auth app permission
|
||||||
|
const [{ app, tmbId }, chat] = await Promise.all([
|
||||||
|
authApp({
|
||||||
|
req,
|
||||||
|
authToken: true,
|
||||||
|
appId,
|
||||||
|
per: 'r'
|
||||||
|
}),
|
||||||
|
chatId ? MongoChat.findOne({ appId, chatId }) : undefined
|
||||||
|
]);
|
||||||
|
|
||||||
|
// auth chat permission
|
||||||
|
if (chat && !app.canWrite && String(tmbId) !== String(chat?.tmbId)) {
|
||||||
|
throw new Error(ChatErrEnum.unAuthChat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get app and history
|
||||||
|
const [{ history }, { nodes }] = await Promise.all([
|
||||||
|
getChatItems({
|
||||||
|
appId,
|
||||||
|
chatId,
|
||||||
|
limit: 30,
|
||||||
|
field: `dataId obj value adminFeedback userBadFeedback userGoodFeedback ${
|
||||||
|
DispatchNodeResponseKeyEnum.nodeResponse
|
||||||
|
} ${loadCustomFeedbacks ? 'customFeedbacks' : ''}`
|
||||||
|
}),
|
||||||
|
getAppLatestVersion(app._id, app)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
chatId,
|
||||||
|
appId,
|
||||||
|
title: chat?.title || '新对话',
|
||||||
|
userAvatar: undefined,
|
||||||
|
variables: chat?.variables || {},
|
||||||
|
history,
|
||||||
|
app: {
|
||||||
|
userGuideModule: replaceAppChatConfig({
|
||||||
|
node: getGuideModule(nodes),
|
||||||
|
variableList: chat?.variableList,
|
||||||
|
welcomeText: chat?.welcomeText
|
||||||
|
}),
|
||||||
|
chatModels: getChatModelNameListByModules(nodes),
|
||||||
|
name: app.name,
|
||||||
|
avatar: app.avatar,
|
||||||
|
intro: app.intro
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default NextAPI(handler);
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
api: {
|
api: {
|
||||||
responseLimit: '10mb'
|
responseLimit: '10mb'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
|||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
import { jsonRes } from '@fastgpt/service/common/response';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
|
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
|
||||||
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { getChatItems } from '@fastgpt/service/core/chat/controller';
|
import { getChatItems } from '@fastgpt/service/core/chat/controller';
|
||||||
@@ -72,7 +72,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
variables: chat?.variables || {},
|
variables: chat?.variables || {},
|
||||||
history,
|
history,
|
||||||
app: {
|
app: {
|
||||||
userGuideModule: getGuideModule(nodes),
|
userGuideModule: replaceAppChatConfig({
|
||||||
|
node: getGuideModule(nodes),
|
||||||
|
variableList: chat?.variableList,
|
||||||
|
welcomeText: chat?.welcomeText
|
||||||
|
}),
|
||||||
chatModels: getChatModelNameListByModules(nodes),
|
chatModels: getChatModelNameListByModules(nodes),
|
||||||
name: app.name,
|
name: app.name,
|
||||||
avatar: app.avatar,
|
avatar: app.avatar,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
import { jsonRes } from '@fastgpt/service/common/response';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
|
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import type { InitChatResponse, InitTeamChatProps } from '@/global/core/chat/api.d';
|
import type { InitChatResponse, InitTeamChatProps } from '@/global/core/chat/api.d';
|
||||||
@@ -73,7 +73,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
variables: chat?.variables || {},
|
variables: chat?.variables || {},
|
||||||
history,
|
history,
|
||||||
app: {
|
app: {
|
||||||
userGuideModule: getGuideModule(nodes),
|
userGuideModule: replaceAppChatConfig({
|
||||||
|
node: getGuideModule(nodes),
|
||||||
|
variableList: chat?.variableList,
|
||||||
|
welcomeText: chat?.welcomeText
|
||||||
|
}),
|
||||||
chatModels: getChatModelNameListByModules(nodes),
|
chatModels: getChatModelNameListByModules(nodes),
|
||||||
name: app.name,
|
name: app.name,
|
||||||
avatar: app.avatar,
|
avatar: app.avatar,
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
|
||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
|
||||||
import { pushChatUsage } from '@/service/support/wallet/usage/push';
|
import { pushChatUsage } from '@/service/support/wallet/usage/push';
|
||||||
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
|
||||||
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
import { authApp } from '@fastgpt/service/support/permission/auth/app';
|
||||||
@@ -9,8 +7,12 @@ import { authCert } from '@fastgpt/service/support/permission/auth/common';
|
|||||||
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
|
import { getUserChatInfoAndAuthTeamPoints } from '@/service/support/permission/auth/team';
|
||||||
import { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core/workflow/api';
|
import { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core/workflow/api';
|
||||||
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
|
import { authPluginCrud } from '@fastgpt/service/support/permission/auth/plugin';
|
||||||
|
import { NextAPI } from '@/service/middle/entry';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse
|
||||||
|
): Promise<PostWorkflowDebugResponse> {
|
||||||
const {
|
const {
|
||||||
nodes = [],
|
nodes = [],
|
||||||
edges = [],
|
edges = [],
|
||||||
@@ -18,75 +20,65 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
appId,
|
appId,
|
||||||
pluginId
|
pluginId
|
||||||
} = req.body as PostWorkflowDebugProps;
|
} = req.body as PostWorkflowDebugProps;
|
||||||
try {
|
|
||||||
await connectToDatabase();
|
|
||||||
if (!nodes) {
|
|
||||||
throw new Error('Prams Error');
|
|
||||||
}
|
|
||||||
if (!Array.isArray(nodes)) {
|
|
||||||
throw new Error('Nodes is not array');
|
|
||||||
}
|
|
||||||
if (!Array.isArray(edges)) {
|
|
||||||
throw new Error('Edges is not array');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* user auth */
|
if (!nodes) {
|
||||||
const [{ teamId, tmbId }] = await Promise.all([
|
throw new Error('Prams Error');
|
||||||
authCert({
|
|
||||||
req,
|
|
||||||
authToken: true
|
|
||||||
}),
|
|
||||||
appId && authApp({ req, authToken: true, appId, per: 'r' }),
|
|
||||||
pluginId && authPluginCrud({ req, authToken: true, pluginId, per: 'r' })
|
|
||||||
]);
|
|
||||||
|
|
||||||
// auth balance
|
|
||||||
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
|
||||||
|
|
||||||
/* start process */
|
|
||||||
const { flowUsages, flowResponses, debugResponse } = await dispatchWorkFlow({
|
|
||||||
res,
|
|
||||||
mode: 'debug',
|
|
||||||
teamId,
|
|
||||||
tmbId,
|
|
||||||
user,
|
|
||||||
appId,
|
|
||||||
runtimeNodes: nodes,
|
|
||||||
runtimeEdges: edges,
|
|
||||||
variables: {
|
|
||||||
...variables,
|
|
||||||
userChatInput: ''
|
|
||||||
},
|
|
||||||
inputFiles: [],
|
|
||||||
histories: [],
|
|
||||||
stream: false,
|
|
||||||
detail: true,
|
|
||||||
maxRunTimes: 200
|
|
||||||
});
|
|
||||||
|
|
||||||
pushChatUsage({
|
|
||||||
appName: '工作流Debug',
|
|
||||||
appId,
|
|
||||||
teamId,
|
|
||||||
tmbId,
|
|
||||||
source: UsageSourceEnum.fastgpt,
|
|
||||||
flowUsages
|
|
||||||
});
|
|
||||||
|
|
||||||
jsonRes<PostWorkflowDebugResponse>(res, {
|
|
||||||
data: {
|
|
||||||
...debugResponse,
|
|
||||||
flowResponses
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (err: any) {
|
|
||||||
jsonRes(res, {
|
|
||||||
code: 500,
|
|
||||||
error: err
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (!Array.isArray(nodes)) {
|
||||||
|
throw new Error('Nodes is not array');
|
||||||
|
}
|
||||||
|
if (!Array.isArray(edges)) {
|
||||||
|
throw new Error('Edges is not array');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* user auth */
|
||||||
|
const [{ teamId, tmbId }] = await Promise.all([
|
||||||
|
authCert({
|
||||||
|
req,
|
||||||
|
authToken: true
|
||||||
|
}),
|
||||||
|
appId && authApp({ req, authToken: true, appId, per: 'r' }),
|
||||||
|
pluginId && authPluginCrud({ req, authToken: true, pluginId, per: 'r' })
|
||||||
|
]);
|
||||||
|
|
||||||
|
// auth balance
|
||||||
|
const { user } = await getUserChatInfoAndAuthTeamPoints(tmbId);
|
||||||
|
|
||||||
|
/* start process */
|
||||||
|
const { flowUsages, flowResponses, debugResponse } = await dispatchWorkFlow({
|
||||||
|
res,
|
||||||
|
mode: 'debug',
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
user,
|
||||||
|
appId,
|
||||||
|
runtimeNodes: nodes,
|
||||||
|
runtimeEdges: edges,
|
||||||
|
variables,
|
||||||
|
query: [],
|
||||||
|
histories: [],
|
||||||
|
stream: false,
|
||||||
|
detail: true,
|
||||||
|
maxRunTimes: 200
|
||||||
|
});
|
||||||
|
|
||||||
|
pushChatUsage({
|
||||||
|
appName: '工作流Debug',
|
||||||
|
appId,
|
||||||
|
teamId,
|
||||||
|
tmbId,
|
||||||
|
source: UsageSourceEnum.fastgpt,
|
||||||
|
flowUsages
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...debugResponse,
|
||||||
|
flowResponses
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default NextAPI(handler);
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
api: {
|
api: {
|
||||||
bodyParser: {
|
bodyParser: {
|
||||||
|
|||||||
72
projects/app/src/pages/api/plugins/TFSwitch/index.ts
Normal file
72
projects/app/src/pages/api/plugins/TFSwitch/index.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
// @ts-ignore
|
||||||
|
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||||
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
|
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||||
|
|
||||||
|
type Props = HttpBodyType<{
|
||||||
|
input: string;
|
||||||
|
rule?: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
|
try {
|
||||||
|
const { input, rule = '' } = req.body as Props;
|
||||||
|
|
||||||
|
await authRequestFromLocal({ req });
|
||||||
|
|
||||||
|
const result = (() => {
|
||||||
|
if (typeof input === 'string') {
|
||||||
|
const defaultReg: any[] = [
|
||||||
|
'',
|
||||||
|
undefined,
|
||||||
|
'undefined',
|
||||||
|
null,
|
||||||
|
'null',
|
||||||
|
false,
|
||||||
|
'false',
|
||||||
|
0,
|
||||||
|
'0',
|
||||||
|
'none'
|
||||||
|
];
|
||||||
|
const customReg = rule.split('\n');
|
||||||
|
defaultReg.push(...customReg);
|
||||||
|
|
||||||
|
return !defaultReg.find((item) => {
|
||||||
|
const reg = typeof item === 'string' ? stringToRegex(item) : null;
|
||||||
|
if (reg) {
|
||||||
|
return reg.test(input);
|
||||||
|
}
|
||||||
|
return input === item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!input;
|
||||||
|
})();
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
...(result
|
||||||
|
? {
|
||||||
|
true: true
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
false: false
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
res.status(500).send(getErrText(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringToRegex(str: string) {
|
||||||
|
const regexFormat = /^\/(.+)\/([gimuy]*)$/;
|
||||||
|
const match = str.match(regexFormat);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
const [, pattern, flags] = match;
|
||||||
|
return new RegExp(pattern, flags);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +1,36 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import type { HttpBodyType } from '@fastgpt/global/core/workflow/api.d';
|
//@ts-ignore
|
||||||
|
import type { HttpBodyType } from '@fastgpt/global/core/module/api.d';
|
||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
import { addCustomFeedbacks } from '@fastgpt/service/core/chat/controller';
|
import { addCustomFeedbacks } from '@fastgpt/service/core/chat/controller';
|
||||||
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
import { authRequestFromLocal } from '@fastgpt/service/support/permission/auth/common';
|
||||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|
||||||
|
|
||||||
type Props = HttpBodyType<{
|
type Props = HttpBodyType<{
|
||||||
|
appId: string;
|
||||||
|
chatId?: string;
|
||||||
|
responseChatItemId?: string;
|
||||||
|
defaultFeedback: string;
|
||||||
customFeedback: string;
|
customFeedback: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
customFeedback,
|
appId,
|
||||||
system_addInputParam: { appId, chatId, responseChatItemId: chatItemId }
|
chatId,
|
||||||
|
responseChatItemId: chatItemId,
|
||||||
|
defaultFeedback,
|
||||||
|
customFeedback
|
||||||
} = req.body as Props;
|
} = req.body as Props;
|
||||||
|
|
||||||
await authRequestFromLocal({ req });
|
await authRequestFromLocal({ req });
|
||||||
|
|
||||||
if (!customFeedback) {
|
const feedback = customFeedback || defaultFeedback;
|
||||||
return res.json({});
|
|
||||||
|
if (!feedback) {
|
||||||
|
return res.json({
|
||||||
|
response: ''
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait the chat finish
|
// wait the chat finish
|
||||||
@@ -28,17 +39,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
appId,
|
appId,
|
||||||
chatId,
|
chatId,
|
||||||
chatItemId,
|
chatItemId,
|
||||||
feedbacks: [customFeedback]
|
feedbacks: [feedback]
|
||||||
});
|
});
|
||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
if (!chatId || !chatItemId) {
|
if (!chatId || !chatItemId) {
|
||||||
return res.json({
|
return res.json({
|
||||||
[NodeOutputKeyEnum.answerText]: `\\n\\n**自动反馈调试**: "${customFeedback}"\\n\\n`
|
response: `\\n\\n**自动反馈调试**: ${feedback}\\n\\n`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json({});
|
return res.json({
|
||||||
|
response: ''
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
res.status(500).send(getErrText(err));
|
res.status(500).send(getErrText(err));
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user