Commit 439c819f by Archer Committed by GitHub

4.8 preview (#1288)

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* perf: workflow ux

* system config

* Newflow (#89)

* docs: Add doc for Xinference (#1266)

Signed-off-by: Carson Yang <yangchuansheng33@gmail.com>

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* perf: workflow ux

* system config

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* Revert "lafAccount add pat & re request when token invalid (#76)" (#77)

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* rename code

* move code

* update flow

* input type selector

* perf: workflow runtime

* feat: node adapt newflow

* feat: adapt plugin

* feat: 360 connection

* check workflow

* perf: flow 性能

* change plugin input type (#81)

* change plugin input type

* plugin label mode

* perf: nodecard

* debug

* perf: debug ui

* connection ui

* change workflow ui (#82)

* feat: workflow debug

* adapt openAPI for new workflow (#83)

* adapt openAPI for new workflow

* i18n

* perf: plugin debug

* plugin input ui

* delete

* perf: global variable select

* fix rebase

* perf: workflow performance

* feat: input render type icon

* input icon

* adapt flow (#84)

* adapt newflow

* temp

* temp

* fix

* feat: app schedule trigger

* feat: app schedule trigger

* perf: schedule ui

* feat: ioslatevm run js code

* perf: workflow varialbe table ui

* feat: adapt simple mode

* feat: adapt input params

* output

* feat: adapt tamplate

* fix: ts

* add if-else module (#86)

* perf: worker

* if else node

* perf: tiktoken worker

* fix: ts

* perf: tiktoken

* fix if-else node (#87)

* fix if-else node

* type

* fix

* perf: audio render

* perf: Parallel worker

* log

* perf: if else node

* adapt plugin

* prompt

* perf: reference ui

* reference ui

* handle ux

* template ui and plugin tool

* adapt v1 workflow

* adapt v1 workflow completions

* perf: time variables

* feat: workflow keyboard shortcuts

* adapt v1 workflow

* update workflow example doc (#88)

* fix: simple mode select tool

---------

Signed-off-by: Carson Yang <yangchuansheng33@gmail.com>
Co-authored-by: Carson Yang <yangchuansheng33@gmail.com>
Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>

* doc

* perf: extract node

* extra node field

* update plugin version

* doc

* variable

* change doc & fix prompt editor (#90)

* fold workflow code

* value type label

---------

Signed-off-by: Carson Yang <yangchuansheng33@gmail.com>
Co-authored-by: Carson Yang <yangchuansheng33@gmail.com>
Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
parent b08d81f8
...@@ -19,20 +19,6 @@ RUN [ -f pnpm-lock.yaml ] || (echo "Lockfile not found." && exit 1) ...@@ -19,20 +19,6 @@ RUN [ -f pnpm-lock.yaml ] || (echo "Lockfile not found." && exit 1)
RUN pnpm i RUN pnpm i
# --------- install dependence -----------
FROM node:18.17-alpine AS workerDeps
WORKDIR /app
ARG proxy
RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN apk add --no-cache libc6-compat && npm install -g pnpm@8.6.0
# if proxy exists, set proxy
RUN [ -z "$proxy" ] || pnpm config set registry https://registry.npmmirror.com
COPY ./worker /app/worker
RUN cd /app/worker && pnpm i --production --ignore-workspace
# --------- builder ----------- # --------- builder -----------
FROM node:18.17-alpine AS builder FROM node:18.17-alpine AS builder
WORKDIR /app WORKDIR /app
...@@ -72,12 +58,15 @@ COPY --from=builder /app/projects/$name/public /app/projects/$name/public ...@@ -72,12 +58,15 @@ COPY --from=builder /app/projects/$name/public /app/projects/$name/public
COPY --from=builder /app/projects/$name/next.config.js /app/projects/$name/next.config.js COPY --from=builder /app/projects/$name/next.config.js /app/projects/$name/next.config.js
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/standalone /app/ COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/standalone /app/
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/static /app/projects/$name/.next/static COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/static /app/projects/$name/.next/static
# copy server chunks
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/server/chunks /app/projects/$name/.next/server/chunks
# copy worker
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/server/worker /app/projects/$name/.next/server/worker
# copy package.json to version file # copy package.json to version file
COPY --from=builder /app/projects/$name/package.json ./package.json COPY --from=builder /app/projects/$name/package.json ./package.json
# copy woker
COPY --from=workerDeps /app/worker /app/worker
# copy config # copy config
COPY ./projects/$name/data /app/data COPY ./projects/$name/data /app/data
RUN chown -R nextjs:nodejs /app/data RUN chown -R nextjs:nodejs /app/data
ENV NODE_ENV production ENV NODE_ENV production
......

40.8 KB | W: | H:

186 KB | W: | H:

docSite/assets/imgs/demo-appointment6.jpg
docSite/assets/imgs/demo-appointment6.jpg
docSite/assets/imgs/demo-appointment6.jpg
docSite/assets/imgs/demo-appointment6.jpg
  • 2-up
  • Swipe
  • Onion skin
...@@ -28,8 +28,8 @@ images: [] ...@@ -28,8 +28,8 @@ images: []
### 其他模型没法进行问题分类/内容提取 ### 其他模型没法进行问题分类/内容提取
需要给其他模型配置`toolChoice=false`,就会默认走提示词模式。目前内置提示词仅针对了商业模型API进行测试 1. 看日志。如果提示 JSON invalid,not support tool 之类的,说明该模型不支持工具调用或函数调用,需要设置`toolChoice=false``functionCall=false`,就会默认走提示词模式。目前内置提示词仅针对了商业模型API进行测试。问题分类基本可用,内容提取不太行
问题分类基本可用,内容提取不太行 2. 如果已经配置正常,并且没有错误日志,则说明可能提示词不太适合该模型,可以通过修改`customCQPrompt`来自定义提示词
### 页面崩溃 ### 页面崩溃
......
...@@ -286,7 +286,7 @@ type ResponseType = { ...@@ -286,7 +286,7 @@ type ResponseType = {
pluginOutput?: Record<string, any>; // 插件输出 pluginOutput?: Record<string, any>; // 插件输出
pluginDetail?: ChatHistoryItemResType[]; // 插件详情 pluginDetail?: ChatHistoryItemResType[]; // 插件详情
tfSwitchResult?: boolean; // 判断器结果 isElseResult?: boolean; // 判断器结果
} }
``` ```
......
---
title: 'V4.8(进行中)'
description: 'FastGPT V4.8 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 824
---
## 新工作流
FastGPT workflow V2上线,支持更加简洁的工作流模式。
**由于工作流差异较大,需要手动重新构建。**
给应用和插件增加了 version 的字段,用于标识是旧工作流还是新工作流。当你更新 4.8 后,保存和新建的工作流均为新版,旧版工作流会有一个重置的弹窗提示。并且,如果是通过 API 和 分享链接 调用的工作流,仍可以正常使用,直到你下次保存它们。
## V4.8 更新说明
1. 重构 - 工作流
2. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流。
3. 新增 - 定时执行应用。可轻松实现定时任务。
4. 新增 - 插件自定义输入优化,可以渲染输入组件。
5. 优化 - 工作流连线,可以四向连接,方便构建循环工作流。
6. 优化 - worker进程管理,并将计算 Token 任务分配给 worker 进程。
\ No newline at end of file
...@@ -11,7 +11,7 @@ weight: 404 ...@@ -11,7 +11,7 @@ weight: 404
| | | | | |
| --------------------- | --------------------- | | --------------------- | --------------------- |
| ![](/imgs/feishuwebhook1.png) | ![](/imgs/feishuwebhook2.webp) | | ![](/imgs/feishuwebhook1.webp) | ![](/imgs/feishuwebhook2.webp) |
## 1. 准备飞书机器人 ## 1. 准备飞书机器人
...@@ -23,14 +23,16 @@ weight: 404 ...@@ -23,14 +23,16 @@ weight: 404
复制下面配置,点击「高级编排」右上角的导入按键,导入该配置,导入后将飞书提供的接口地址复制到「HTTP 模块」。 复制下面配置,点击「高级编排」右上角的导入按键,导入该配置,导入后将飞书提供的接口地址复制到「HTTP 模块」。
{{% details title="编排配置" closed="true" %}}
```json ```json
[ [
{ {
"moduleId": "userGuide", "nodeId": "userGuide",
"name": "core.module.template.App system setting", "name": "core.module.template.App system setting",
"intro": "core.app.tip.userGuideTip", "intro": "core.app.tip.userGuideTip",
"avatar": "/imgs/module/userGuide.png", "avatar": "/imgs/workflow/userGuide.png",
"flowType": "userGuide", "flowNodeType": "userGuide",
"position": { "position": {
"x": -92.26884681344463, "x": -92.26884681344463,
"y": 710.9354029649536 "y": 710.9354029649536
...@@ -82,11 +84,11 @@ weight: 404 ...@@ -82,11 +84,11 @@ weight: 404
"outputs": [] "outputs": []
}, },
{ {
"moduleId": "userChatInput", "nodeId": "userChatInput",
"name": "core.module.template.Chat entrance", "name": "core.module.template.Chat entrance",
"intro": "当用户发送一个内容后,流程将会从这个模块开始执行。", "intro": "当用户发送一个内容后,流程将会从这个模块开始执行。",
"avatar": "/imgs/module/userChatInput.svg", "avatar": "/imgs/workflow/userChatInput.svg",
"flowType": "questionInput", "flowNodeType": "questionInput",
"position": { "position": {
"x": 241.60980819261408, "x": 241.60980819261408,
"y": 1330.9528898009685 "y": 1330.9528898009685
...@@ -110,7 +112,7 @@ weight: 404 ...@@ -110,7 +112,7 @@ weight: 404
"valueType": "string", "valueType": "string",
"targets": [ "targets": [
{ {
"moduleId": "n84rvg", "nodeId": "n84rvg",
"key": "userChatInput" "key": "userChatInput"
} }
] ]
...@@ -118,11 +120,11 @@ weight: 404 ...@@ -118,11 +120,11 @@ weight: 404
] ]
}, },
{ {
"moduleId": "n84rvg", "nodeId": "n84rvg",
"name": "工具调用(实验)", "name": "工具调用(实验)",
"intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。", "intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。",
"avatar": "/imgs/module/tool.svg", "avatar": "/imgs/workflow/tool.svg",
"flowType": "tools", "flowNodeType": "tools",
"showStatus": true, "showStatus": true,
"position": { "position": {
"x": 809.4264785615641, "x": 809.4264785615641,
...@@ -130,16 +132,6 @@ weight: 404 ...@@ -130,16 +132,6 @@ weight: 404
}, },
"inputs": [ "inputs": [
{ {
"key": "switch",
"type": "triggerAndFinish",
"label": "",
"description": "core.module.input.description.Trigger",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{
"key": "model", "key": "model",
"type": "settingLLMModel", "type": "settingLLMModel",
"label": "core.module.input.label.aiModel", "label": "core.module.input.label.aiModel",
...@@ -227,7 +219,7 @@ weight: 404 ...@@ -227,7 +219,7 @@ weight: 404
"type": "hidden", "type": "hidden",
"targets": [ "targets": [
{ {
"moduleId": "3mbu91", "nodeId": "3mbu91",
"key": "selectedTools" "key": "selectedTools"
} }
] ]
...@@ -243,27 +235,18 @@ weight: 404 ...@@ -243,27 +235,18 @@ weight: 404
] ]
}, },
{ {
"moduleId": "3mbu91", "nodeId": "3mbu91",
"name": "HTTP 请求", "name": "HTTP 请求",
"intro": "调用飞书webhook,发送一个通知", "intro": "调用飞书webhook,发送一个通知",
"avatar": "/imgs/module/http.png", "avatar": "/imgs/workflow/http.png",
"flowType": "httpRequest468", "flowNodeType": "httpRequest468",
"showStatus": true, "showStatus": true,
"position": { "position": {
"x": 1483.6437630977423, "x": 1483.6437630977423,
"y": 798.9716928475544 "y": 798.9716928475544
}, },
"inputs": [ "inputs": [
{
"key": "switch",
"type": "triggerAndFinish",
"label": "",
"description": "core.module.input.description.Trigger",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{ {
"key": "system_httpMethod", "key": "system_httpMethod",
"type": "custom", "type": "custom",
...@@ -327,7 +310,7 @@ weight: 404 ...@@ -327,7 +310,7 @@ weight: 404
"key": "DYNAMIC_INPUT_KEY", "key": "DYNAMIC_INPUT_KEY",
"type": "target", "type": "target",
"valueType": "any", "valueType": "any",
"label": "core.module.inputType.dynamicTargetInput", "label": "core.workflow.inputType.dynamicTargetInput",
"description": "core.module.input.description.dynamic input", "description": "core.module.input.description.dynamic input",
"required": false, "required": false,
"showTargetInApp": false, "showTargetInApp": false,
...@@ -376,11 +359,11 @@ weight: 404 ...@@ -376,11 +359,11 @@ weight: 404
"type": "source", "type": "source",
"targets": [ "targets": [
{ {
"moduleId": "rzx4mj", "nodeId": "rzx4mj",
"key": "switch" "key": "switch"
}, },
{ {
"moduleId": "psdhs1", "nodeId": "psdhs1",
"key": "switch" "key": "switch"
} }
] ]
...@@ -424,11 +407,11 @@ weight: 404 ...@@ -424,11 +407,11 @@ weight: 404
] ]
}, },
{ {
"moduleId": "rzx4mj", "nodeId": "rzx4mj",
"name": "工具调用终止", "name": "工具调用终止",
"intro": "该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。", "intro": "该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。",
"avatar": "/imgs/module/toolStop.svg", "avatar": "/imgs/workflow/toolStop.svg",
"flowType": "stopTool", "flowNodeType": "stopTool",
"position": { "position": {
"x": 2145.5070710160267, "x": 2145.5070710160267,
"y": 1306.3581817783079 "y": 1306.3581817783079
...@@ -448,11 +431,11 @@ weight: 404 ...@@ -448,11 +431,11 @@ weight: 404
"outputs": [] "outputs": []
}, },
{ {
"moduleId": "psdhs1", "nodeId": "psdhs1",
"name": "指定回复", "name": "指定回复",
"intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。", "intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
"avatar": "/imgs/module/reply.png", "avatar": "/imgs/workflow/reply.png",
"flowType": "answerNode", "flowNodeType": "answerNode",
"position": { "position": {
"x": 2117.0429459850598, "x": 2117.0429459850598,
"y": 1658.4125434513746 "y": 1658.4125434513746
...@@ -495,6 +478,9 @@ weight: 404 ...@@ -495,6 +478,9 @@ weight: 404
] ]
``` ```
{{% /details %}}
## 3. 流程说明 ## 3. 流程说明
1. 为工具调用挂载一个HTTP模块,功能描述写上:调用飞书webhook,发送一个通知。 1. 为工具调用挂载一个HTTP模块,功能描述写上:调用飞书webhook,发送一个通知。
......
...@@ -53,4 +53,4 @@ export const uniqueImageTypeList = Object.entries(mongoImageTypeMap) ...@@ -53,4 +53,4 @@ export const uniqueImageTypeList = Object.entries(mongoImageTypeMap)
export const FolderIcon = 'file/fill/folder'; export const FolderIcon = 'file/fill/folder';
export const FolderImgUrl = '/imgs/files/folder.svg'; export const FolderImgUrl = '/imgs/files/folder.svg';
export const HttpImgUrl = '/imgs/module/http.png'; export const HttpImgUrl = '/imgs/workflow/http.png';
import type { Tiktoken } from 'js-tiktoken';
declare global {
var TikToken: Tiktoken;
}
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import cronParser from 'cron-parser';
export const formatTime2YMDHM = (time?: Date) => export const formatTime2YMDHM = (time?: Date) =>
time ? dayjs(time).format('YYYY-MM-DD HH:mm') : ''; time ? dayjs(time).format('YYYY-MM-DD HH:mm') : '';
export const formatTime2YMD = (time?: Date) => (time ? dayjs(time).format('YYYY-MM-DD') : ''); export const formatTime2YMD = (time?: Date) => (time ? dayjs(time).format('YYYY-MM-DD') : '');
/* cron time parse */
export const cronParser2Fields = (cronString: string) => {
try {
const cronField = cronParser.parseExpression(cronString).fields;
return cronField;
} catch (error) {
return null;
}
};
// 根据cron表达式和时区获取下一个时间
export const getNextTimeByCronStringAndTimezone = ({
cronString,
timezone
}: {
cronString: string;
timezone: string;
}) => {
try {
const options = {
currentDate: dayjs().tz(timezone).format(),
tz: timezone
};
const interval = cronParser.parseExpression(cronString, options);
const date = interval.next().toString();
return new Date(date);
} catch (error) {
return new Date('2099');
}
};
...@@ -28,7 +28,9 @@ export const simpleText = (text = '') => { ...@@ -28,7 +28,9 @@ export const simpleText = (text = '') => {
/* /*
replace {{variable}} to value replace {{variable}} to value
*/ */
export function replaceVariable(text: string, obj: Record<string, string | number>) { export function replaceVariable(text: any, obj: Record<string, string | number>) {
if (!(typeof text === 'string')) return text;
for (const key in obj) { for (const key in obj) {
const val = obj[key]; const val = obj[key];
if (!['string', 'number'].includes(typeof val)) continue; if (!['string', 'number'].includes(typeof val)) continue;
......
...@@ -76,5 +76,5 @@ export const getSystemTime = (timeZone: string) => { ...@@ -76,5 +76,5 @@ export const getSystemTime = (timeZone: string) => {
const timezoneDiff = getTimezoneOffset(timeZone); const timezoneDiff = getTimezoneOffset(timeZone);
const now = Date.now(); const now = Date.now();
const targetTime = now + timezoneDiff * 60 * 60 * 1000; const targetTime = now + timezoneDiff * 60 * 60 * 1000;
return dayjs(targetTime).format('YYYY-MM-DD HH:mm:ss'); return dayjs(targetTime).format('YYYY-MM-DD HH:mm:ss dddd');
}; };
...@@ -41,20 +41,22 @@ export const Prompt_ExtractJson = `你可以从 <对话记录></对话记录> ...@@ -41,20 +41,22 @@ export const Prompt_ExtractJson = `你可以从 <对话记录></对话记录>
</对话记录> </对话记录>
`; `;
export const Prompt_CQJson = `我会给你几个问题类型,请参考背景知识(可能为空)和对话记录,判断我“本次问题”的类型,并返回一个问题“类型ID”: export const Prompt_CQJson = `请帮我执行一个“问题分类”任务,将问题分类为以下几种类型之一:
<问题类型>
"""
{{typeList}} {{typeList}}
</问题类型> """
<背景知识> ## 背景知识
{{systemPrompt}} {{systemPrompt}}
</背景知识>
<对话记录> ## 对话记录
{{history}} {{history}}
</对话记录>
Human:"{{question}}" ## 开始任务
现在,我们开始分类,我会给你一个"问题",请结合背景知识和对话记录,将问题分类到对应的类型中,并返回类型ID。
问题:"{{question}}"
类型ID= 类型ID=
`; `;
...@@ -7,6 +7,7 @@ export type CreateAppParams = { ...@@ -7,6 +7,7 @@ export type CreateAppParams = {
avatar?: string; avatar?: string;
type?: `${AppTypeEnum}`; type?: `${AppTypeEnum}`;
modules: AppSchema['modules']; modules: AppSchema['modules'];
edges?: AppSchema['edges'];
}; };
export interface AppUpdateParams { export interface AppUpdateParams {
...@@ -15,6 +16,7 @@ export interface AppUpdateParams { ...@@ -15,6 +16,7 @@ export interface AppUpdateParams {
avatar?: string; avatar?: string;
intro?: string; intro?: string;
modules?: AppSchema['modules']; modules?: AppSchema['modules'];
edges?: AppSchema['edges'];
permission?: AppSchema['permission']; permission?: AppSchema['permission'];
teamTags?: AppSchema['teamTags']; teamTags?: AppSchema['teamTags'];
} }
import type { FlowNodeTemplateType, ModuleItemType } from '../module/type.d'; import type { FlowNodeTemplateType, StoreNodeItemType } from '../workflow/type';
import { AppTypeEnum } from './constants'; import { AppTypeEnum } from './constants';
import { PermissionTypeEnum } from '../../support/permission/constant'; import { PermissionTypeEnum } from '../../support/permission/constant';
import type { DatasetModuleProps } from '../module/node/type.d'; import { VariableInputEnum } from '../workflow/constants';
import { VariableInputEnum } from '../module/constants'; import { SelectedDatasetType } from '../workflow/api';
import { SelectedDatasetType } from '../module/api';
import { DatasetSearchModeEnum } from '../dataset/constants'; import { DatasetSearchModeEnum } from '../dataset/constants';
import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d'; import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
import { StoreEdgeItemType } from 'core/workflow/type/edge';
export interface AppSchema { export interface AppSchema {
_id: string; _id: string;
userId: string;
teamId: string; teamId: string;
tmbId: string; tmbId: string;
name: string; name: string;
type: `${AppTypeEnum}`; type: `${AppTypeEnum}`;
version?: 'v1' | 'v2';
avatar: string; avatar: string;
intro: string; intro: string;
updateTime: number; updateTime: number;
modules: ModuleItemType[]; modules: StoreNodeItemType[];
edges: StoreEdgeItemType[];
// App system config
scheduledTriggerConfig?: AppScheduledTriggerConfigType | null;
scheduledTriggerNextTime?: Date;
permission: `${PermissionTypeEnum}`; permission: `${PermissionTypeEnum}`;
inited?: boolean; inited?: boolean;
teamTags: string[]; teamTags: string[];
...@@ -79,10 +86,19 @@ export type AppSimpleEditFormType = { ...@@ -79,10 +86,19 @@ export type AppSimpleEditFormType = {
speed?: number | undefined; speed?: number | undefined;
}; };
whisper: AppWhisperConfigType; whisper: AppWhisperConfigType;
scheduleTrigger: AppScheduledTriggerConfigType | null;
}; };
}; };
/* app function config */ /* app function config */
export type SettingAIDataType = {
model: string;
temperature: number;
maxToken: number;
isResponseAnswerText?: boolean;
maxHistories?: number;
};
// variable // variable
export type VariableItemType = { export type VariableItemType = {
id: string; id: string;
...@@ -106,3 +122,9 @@ export type AppWhisperConfigType = { ...@@ -106,3 +122,9 @@ export type AppWhisperConfigType = {
autoSend: boolean; autoSend: boolean;
autoTTSResponse: boolean; autoTTSResponse: boolean;
}; };
// interval timer
export type AppScheduledTriggerConfigType = {
cronString: string;
timezone: string;
defaultPrompt: string;
};
import type { AppSimpleEditFormType } from '../app/type'; import type { AppSimpleEditFormType } from '../app/type';
import { FlowNodeTypeEnum } from '../module/node/constant'; import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { import { NodeInputKeyEnum, FlowNodeTemplateTypeEnum } from '../workflow/constants';
ModuleOutputKeyEnum, import type { FlowNodeInputItemType } from '../workflow/type/io.d';
ModuleInputKeyEnum, import { getGuideModule, splitGuideModule } from '../workflow/utils';
FlowNodeTemplateTypeEnum import { StoreNodeItemType } from '../workflow/type';
} from '../module/constants';
import type { FlowNodeInputItemType } from '../module/node/type.d';
import { getGuideModule, splitGuideModule } from '../module/utils';
import { ModuleItemType } from '../module/type.d';
import { DatasetSearchModeEnum } from '../dataset/constants'; import { DatasetSearchModeEnum } from '../dataset/constants';
import { defaultWhisperConfig } from './constants'; import { defaultWhisperConfig } from './constants';
...@@ -38,97 +34,104 @@ export const getDefaultAppForm = (): AppSimpleEditFormType => { ...@@ -38,97 +34,104 @@ export const getDefaultAppForm = (): AppSimpleEditFormType => {
tts: { tts: {
type: 'web' type: 'web'
}, },
whisper: defaultWhisperConfig whisper: defaultWhisperConfig,
scheduleTrigger: null
} }
}; };
}; };
/* format app modules to edit form */ /* format app nodes to edit form */
export const appModules2Form = ({ modules }: { modules: ModuleItemType[] }) => { export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
const defaultAppForm = getDefaultAppForm(); const defaultAppForm = getDefaultAppForm();
const findInputValueByKey = (inputs: FlowNodeInputItemType[], key: string) => { const findInputValueByKey = (inputs: FlowNodeInputItemType[], key: string) => {
return inputs.find((item) => item.key === key)?.value; return inputs.find((item) => item.key === key)?.value;
}; };
modules.forEach((module) => { nodes.forEach((node) => {
if ( if (
module.flowType === FlowNodeTypeEnum.chatNode || node.flowNodeType === FlowNodeTypeEnum.chatNode ||
module.flowType === FlowNodeTypeEnum.tools node.flowNodeType === FlowNodeTypeEnum.tools
) { ) {
defaultAppForm.aiSettings.model = findInputValueByKey( defaultAppForm.aiSettings.model = findInputValueByKey(node.inputs, NodeInputKeyEnum.aiModel);
module.inputs,
ModuleInputKeyEnum.aiModel
);
defaultAppForm.aiSettings.systemPrompt = findInputValueByKey( defaultAppForm.aiSettings.systemPrompt = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.aiSystemPrompt NodeInputKeyEnum.aiSystemPrompt
); );
defaultAppForm.aiSettings.temperature = findInputValueByKey( defaultAppForm.aiSettings.temperature = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.aiChatTemperature NodeInputKeyEnum.aiChatTemperature
); );
defaultAppForm.aiSettings.maxToken = findInputValueByKey( defaultAppForm.aiSettings.maxToken = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.aiChatMaxToken NodeInputKeyEnum.aiChatMaxToken
); );
defaultAppForm.aiSettings.maxHistories = findInputValueByKey( defaultAppForm.aiSettings.maxHistories = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.history NodeInputKeyEnum.history
); );
} else if (module.flowType === FlowNodeTypeEnum.datasetSearchNode) { } else if (node.flowNodeType === FlowNodeTypeEnum.datasetSearchNode) {
defaultAppForm.dataset.datasets = findInputValueByKey( defaultAppForm.dataset.datasets = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.datasetSelectList NodeInputKeyEnum.datasetSelectList
); );
defaultAppForm.dataset.similarity = findInputValueByKey( defaultAppForm.dataset.similarity = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.datasetSimilarity NodeInputKeyEnum.datasetSimilarity
); );
defaultAppForm.dataset.limit = findInputValueByKey( defaultAppForm.dataset.limit = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.datasetMaxTokens NodeInputKeyEnum.datasetMaxTokens
); );
defaultAppForm.dataset.searchMode = defaultAppForm.dataset.searchMode =
findInputValueByKey(module.inputs, ModuleInputKeyEnum.datasetSearchMode) || findInputValueByKey(node.inputs, NodeInputKeyEnum.datasetSearchMode) ||
DatasetSearchModeEnum.embedding; DatasetSearchModeEnum.embedding;
defaultAppForm.dataset.usingReRank = !!findInputValueByKey( defaultAppForm.dataset.usingReRank = !!findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.datasetSearchUsingReRank NodeInputKeyEnum.datasetSearchUsingReRank
); );
defaultAppForm.dataset.datasetSearchUsingExtensionQuery = findInputValueByKey( defaultAppForm.dataset.datasetSearchUsingExtensionQuery = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.datasetSearchUsingExtensionQuery NodeInputKeyEnum.datasetSearchUsingExtensionQuery
); );
defaultAppForm.dataset.datasetSearchExtensionModel = findInputValueByKey( defaultAppForm.dataset.datasetSearchExtensionModel = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.datasetSearchExtensionModel NodeInputKeyEnum.datasetSearchExtensionModel
); );
defaultAppForm.dataset.datasetSearchExtensionBg = findInputValueByKey( defaultAppForm.dataset.datasetSearchExtensionBg = findInputValueByKey(
module.inputs, node.inputs,
ModuleInputKeyEnum.datasetSearchExtensionBg NodeInputKeyEnum.datasetSearchExtensionBg
); );
} else if (module.flowType === FlowNodeTypeEnum.userGuide) { } else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
const { welcomeText, variableModules, questionGuide, ttsConfig, whisperConfig } = const {
splitGuideModule(getGuideModule(modules)); welcomeText,
variableModules,
questionGuide,
ttsConfig,
whisperConfig,
scheduledTriggerConfig
} = splitGuideModule(getGuideModule(nodes));
defaultAppForm.userGuide = { defaultAppForm.userGuide = {
welcomeText: welcomeText, welcomeText: welcomeText,
variables: variableModules, variables: variableModules,
questionGuide: questionGuide, questionGuide: questionGuide,
tts: ttsConfig, tts: ttsConfig,
whisper: whisperConfig whisper: whisperConfig,
scheduleTrigger: scheduledTriggerConfig
}; };
} else if (module.flowType === FlowNodeTypeEnum.pluginModule) { } else if (node.flowNodeType === FlowNodeTypeEnum.pluginModule) {
if (!node.pluginId) return;
defaultAppForm.selectedTools.push({ defaultAppForm.selectedTools.push({
id: module.inputs.find((input) => input.key === ModuleInputKeyEnum.pluginId)?.value || '', id: node.pluginId,
name: module.name, name: node.name,
avatar: module.avatar, avatar: node.avatar,
intro: module.intro || '', intro: node.intro || '',
flowType: module.flowType, flowNodeType: node.flowNodeType,
showStatus: module.showStatus, showStatus: node.showStatus,
inputs: module.inputs, inputs: node.inputs,
outputs: module.outputs, outputs: node.outputs,
templateType: FlowNodeTemplateTypeEnum.other templateType: FlowNodeTemplateTypeEnum.other
}); });
} }
......
import { ClassifyQuestionAgentItemType } from '../module/type'; import { ClassifyQuestionAgentItemType } from '../workflow/type';
import { SearchDataResponseItemType } from '../dataset/type'; import { SearchDataResponseItemType } from '../dataset/type';
import { import {
ChatFileTypeEnum, ChatFileTypeEnum,
...@@ -7,14 +7,14 @@ import { ...@@ -7,14 +7,14 @@ import {
ChatSourceEnum, ChatSourceEnum,
ChatStatusEnum ChatStatusEnum
} from './constants'; } from './constants';
import { FlowNodeTypeEnum } from '../module/node/constant'; import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { ModuleOutputKeyEnum } from '../module/constants'; import { NodeOutputKeyEnum } from '../workflow/constants';
import { DispatchNodeResponseKeyEnum } from '../module/runtime/constants'; import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
import { AppSchema } from '../app/type'; import { AppSchema } 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';
import { DispatchNodeResponseType } from '../module/runtime/type.d'; import { DispatchNodeResponseType } from '../workflow/runtime/type.d';
export type ChatSchema = { export type ChatSchema = {
_id: string; _id: string;
...@@ -136,6 +136,7 @@ export type ChatHistoryItemType = HistoryItemType & { ...@@ -136,6 +136,7 @@ export type ChatHistoryItemType = HistoryItemType & {
/* ------- response data ------------ */ /* ------- response data ------------ */
export type ChatHistoryItemResType = DispatchNodeResponseType & { export type ChatHistoryItemResType = DispatchNodeResponseType & {
nodeId: string;
moduleType: `${FlowNodeTypeEnum}`; moduleType: `${FlowNodeTypeEnum}`;
moduleName: string; moduleName: string;
}; };
......
import { DispatchNodeResponseType } from '../module/runtime/type'; import { DispatchNodeResponseType } from '../workflow/runtime/type';
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../module/node/constant'; import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../workflow/node/constant';
import { ChatItemValueTypeEnum, ChatRoleEnum } from './constants'; import { ChatItemValueTypeEnum, ChatRoleEnum } from './constants';
import { ChatHistoryItemResType, ChatItemType } from './type.d'; import { ChatHistoryItemResType, ChatItemType } from './type.d';
......
import { countPromptTokens } from '../../../common/string/tiktoken';
import { SearchScoreTypeEnum } from '../constants'; import { SearchScoreTypeEnum } from '../constants';
import { SearchDataResponseItemType } from '../type'; import { SearchDataResponseItemType } from '../type';
...@@ -71,25 +70,3 @@ export const datasetSearchResultConcat = ( ...@@ -71,25 +70,3 @@ export const datasetSearchResultConcat = (
return item; return item;
}); });
}; };
export const filterSearchResultsByMaxChars = (
list: SearchDataResponseItemType[],
maxTokens: number
) => {
const results: SearchDataResponseItemType[] = [];
let totalTokens = 0;
for (let i = 0; i < list.length; i++) {
const item = list[i];
totalTokens += countPromptTokens(item.q + item.a);
if (totalTokens > maxTokens + 500) {
break;
}
results.push(item);
if (totalTokens > maxTokens) {
break;
}
}
return results.length === 0 ? list.slice(0, 1) : results;
};
export enum FlowNodeInputTypeEnum {
triggerAndFinish = 'triggerAndFinish',
systemInput = 'systemInput', // history, userChatInput, variableInput
input = 'input', // one line input
numberInput = 'numberInput',
select = 'select',
slider = 'slider',
target = 'target', // data input
switch = 'switch',
// editor
textarea = 'textarea',
JSONEditor = 'JSONEditor',
addInputParam = 'addInputParam', // params input
selectApp = 'selectApp',
// chat special input
aiSettings = 'aiSettings',
// ai model select
selectLLMModel = 'selectLLMModel',
settingLLMModel = 'settingLLMModel',
// dataset special input
selectDataset = 'selectDataset',
selectDatasetParamsModal = 'selectDatasetParamsModal',
settingDatasetQuotePrompt = 'settingDatasetQuotePrompt',
hidden = 'hidden',
custom = 'custom'
}
export enum FlowNodeOutputTypeEnum {
answer = 'answer',
source = 'source',
hidden = 'hidden',
addOutputParam = 'addOutputParam'
}
export enum FlowNodeTypeEnum {
userGuide = 'userGuide',
questionInput = 'questionInput',
historyNode = 'historyNode',
chatNode = 'chatNode',
datasetSearchNode = 'datasetSearchNode',
datasetConcatNode = 'datasetConcatNode',
answerNode = 'answerNode',
classifyQuestion = 'classifyQuestion',
contentExtract = 'contentExtract',
httpRequest = 'httpRequest',
httpRequest468 = 'httpRequest468',
runApp = 'app',
pluginModule = 'pluginModule',
pluginInput = 'pluginInput',
pluginOutput = 'pluginOutput',
queryExtension = 'cfr',
tools = 'tools',
stopTool = 'stopTool',
lafModule = 'lafModule'
// abandon
}
export const EDGE_TYPE = 'default';
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './constant';
import { ModuleIOValueTypeEnum, ModuleInputKeyEnum, ModuleOutputKeyEnum } from '../constants';
import { SelectedDatasetType } from '../api';
import { EditInputFieldMap, EditOutputFieldMap } from './type';
import { LLMModelTypeEnum } from '../../ai/constants';
export type FlowNodeChangeProps = {
moduleId: string;
type:
| 'attr' // key: attr, value: new value
| 'updateInput' // key: update input key, value: new input value
| 'replaceInput' // key: old input key, value: new input value
| 'addInput' // key: null, value: new input value
| 'delInput' // key: delete input key, value: null
| 'updateOutput' // key: update output key, value: new output value
| 'replaceOutput' // key: old output key, value: new output value
| 'addOutput' // key: null, value: new output value
| 'delOutput'; // key: delete output key, value: null
key?: string;
value?: any;
index?: number;
};
export type FlowNodeInputItemType = {
valueType?: `${ModuleIOValueTypeEnum}`; // data type
type: `${FlowNodeInputTypeEnum}`; // Node Type. Decide on a render style
key: `${ModuleInputKeyEnum}` | string;
value?: any;
label: string;
description?: string;
required?: boolean;
toolDescription?: string; // If this field is not empty, it is entered as a tool
edit?: boolean; // Whether to allow editing
editField?: EditInputFieldMap;
defaultEditField?: EditNodeFieldType;
connected?: boolean; // There are incoming data
showTargetInApp?: boolean;
showTargetInPlugin?: boolean;
hideInApp?: boolean;
hideInPlugin?: boolean;
placeholder?: string; // input,textarea
list?: { label: string; value: any }[]; // select
markList?: { label: string; value: any }[]; // slider
step?: number; // slider
max?: number; // slider, number input
min?: number; // slider, number input
llmModelType?: `${LLMModelTypeEnum}`;
};
export type FlowNodeOutputTargetItemType = {
moduleId: string;
key: string;
};
export type FlowNodeOutputItemType = {
type?: `${FlowNodeOutputTypeEnum}`;
key: `${ModuleOutputKeyEnum}` | string;
valueType?: `${ModuleIOValueTypeEnum}`;
label?: string;
description?: string;
required?: boolean;
defaultValue?: any;
edit?: boolean;
editField?: EditOutputFieldMap;
defaultEditField?: EditNodeFieldType;
targets: FlowNodeOutputTargetItemType[];
};
/* --------------- edit field ------------------- */
export type EditInputFieldMap = EditOutputFieldMap & {
inputType?: boolean;
required?: boolean;
isToolInput?: boolean;
};
export type EditOutputFieldMap = {
name?: boolean;
key?: boolean;
description?: boolean;
dataType?: boolean;
defaultValue?: boolean;
};
export type EditNodeFieldType = {
inputType?: `${FlowNodeInputTypeEnum}`; // input type
outputType?: `${FlowNodeOutputTypeEnum}`;
required?: boolean;
key?: string;
label?: string;
description?: string;
valueType?: `${ModuleIOValueTypeEnum}`;
isToolInput?: boolean;
defaultValue?: string;
};
/* ------------- item type --------------- */
export type SettingAIDataType = {
model: string;
temperature: number;
maxToken: number;
isResponseAnswerText?: boolean;
maxHistories?: number;
};
/* ai chat modules props */
export type AIChatModuleProps = {
[ModuleInputKeyEnum.aiModel]: string;
[ModuleInputKeyEnum.aiSystemPrompt]?: string;
[ModuleInputKeyEnum.aiChatTemperature]: number;
[ModuleInputKeyEnum.aiChatMaxToken]: number;
[ModuleInputKeyEnum.aiChatIsResponseText]: boolean;
[ModuleInputKeyEnum.aiChatQuoteTemplate]?: string;
[ModuleInputKeyEnum.aiChatQuotePrompt]?: string;
};
export type DatasetModuleProps = {
[ModuleInputKeyEnum.datasetSelectList]: SelectedDatasetType;
[ModuleInputKeyEnum.datasetSimilarity]: number;
[ModuleInputKeyEnum.datasetMaxTokens]: number;
[ModuleInputKeyEnum.datasetStartReRank]: boolean;
};
import { ChatCompletionRequestMessageRoleEnum } from '../../ai/constants';
export const textAdaptGptResponse = ({
text,
model = '',
finish_reason = null,
extraData = {}
}: {
model?: string;
text: string | null;
finish_reason?: null | 'stop';
extraData?: Object;
}) => {
return JSON.stringify({
...extraData,
id: '',
object: '',
created: 0,
model,
choices: [
{
delta:
text === null
? {}
: { role: ChatCompletionRequestMessageRoleEnum.Assistant, content: text },
index: 0,
finish_reason
}
]
});
};
import type { FlowNodeInputItemType } from '../node/type.d';
import { DYNAMIC_INPUT_KEY, ModuleInputKeyEnum } from '../constants';
import { FlowNodeInputTypeEnum } from '../node/constant';
import { ModuleIOValueTypeEnum } from '../constants';
import { chatNodeSystemPromptTip } from './tip';
export const Input_Template_Switch: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.switch,
type: FlowNodeInputTypeEnum.hidden,
label: '',
description: 'core.module.input.description.Trigger',
valueType: ModuleIOValueTypeEnum.any,
showTargetInApp: true,
showTargetInPlugin: true
};
export const Input_Template_History: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.history,
type: FlowNodeInputTypeEnum.numberInput,
label: 'core.module.input.label.chat history',
required: true,
min: 0,
max: 30,
valueType: ModuleIOValueTypeEnum.chatHistory,
value: 6,
showTargetInApp: true,
showTargetInPlugin: true
};
export const Input_Template_UserChatInput: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.userChatInput,
type: FlowNodeInputTypeEnum.custom,
label: '',
required: true,
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: true,
showTargetInPlugin: true
};
export const Input_Template_AddInputParam: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.addInputParam,
type: FlowNodeInputTypeEnum.addInputParam,
valueType: ModuleIOValueTypeEnum.any,
label: '',
required: false,
showTargetInApp: false,
showTargetInPlugin: false
};
export const Input_Template_DynamicInput: FlowNodeInputItemType = {
key: DYNAMIC_INPUT_KEY,
type: FlowNodeInputTypeEnum.target,
valueType: ModuleIOValueTypeEnum.any,
label: 'core.module.inputType.dynamicTargetInput',
description: 'core.module.input.description.dynamic input',
required: false,
showTargetInApp: false,
showTargetInPlugin: true,
hideInApp: true
};
export const Input_Template_SelectAIModel: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.aiModel,
type: FlowNodeInputTypeEnum.selectLLMModel,
label: 'core.module.input.label.aiModel',
required: true,
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false
};
export const Input_Template_SettingAiModel: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.aiModel,
type: FlowNodeInputTypeEnum.settingLLMModel,
label: 'core.module.input.label.aiModel',
required: true,
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false
};
export const Input_Template_System_Prompt: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.aiSystemPrompt,
type: FlowNodeInputTypeEnum.textarea,
max: 3000,
valueType: ModuleIOValueTypeEnum.string,
label: 'core.ai.Prompt',
description: chatNodeSystemPromptTip,
placeholder: chatNodeSystemPromptTip,
showTargetInApp: true,
showTargetInPlugin: true
};
export const Input_Template_Dataset_Quote: FlowNodeInputItemType = {
key: ModuleInputKeyEnum.aiChatDatasetQuote,
type: FlowNodeInputTypeEnum.settingDatasetQuotePrompt,
label: '知识库引用',
description: 'core.module.Dataset quote.Input description',
valueType: ModuleIOValueTypeEnum.datasetQuote,
showTargetInApp: true,
showTargetInPlugin: true
};
import type { FlowNodeOutputItemType } from '../node/type';
import { ModuleOutputKeyEnum } from '../constants';
import { FlowNodeOutputTypeEnum } from '../node/constant';
import { ModuleIOValueTypeEnum } from '../constants';
export const Output_Template_UserChatInput: FlowNodeOutputItemType = {
key: ModuleOutputKeyEnum.userChatInput,
label: 'core.module.input.label.user question',
type: FlowNodeOutputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.string,
targets: []
};
export const Output_Template_Finish: FlowNodeOutputItemType = {
key: ModuleOutputKeyEnum.finish,
label: '',
description: '',
valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeOutputTypeEnum.hidden,
targets: []
};
export const Output_Template_AddOutput: FlowNodeOutputItemType = {
key: ModuleOutputKeyEnum.addOutputParam,
type: FlowNodeOutputTypeEnum.addOutputParam,
valueType: ModuleIOValueTypeEnum.any,
label: '',
targets: []
};
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../../node/constant';
import { FlowNodeTemplateType } from '../../../type';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../../constants';
import {
Input_Template_AddInputParam,
Input_Template_DynamicInput,
Input_Template_Switch
} from '../../input';
import { Output_Template_AddOutput, Output_Template_Finish } from '../../output';
export const HttpModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.httpRequest,
templateType: FlowNodeTemplateTypeEnum.externalCall,
flowType: FlowNodeTypeEnum.httpRequest,
avatar: '/imgs/module/http.png',
name: 'core.module.template.Http request',
intro:
'该Http模块已被弃用,将于2024/3/31 不再提供服务。请尽快删除该模块并重新添加新的 Http 模块。',
showStatus: true,
inputs: [
Input_Template_Switch,
{
key: ModuleInputKeyEnum.httpMethod,
type: FlowNodeInputTypeEnum.select,
valueType: ModuleIOValueTypeEnum.string,
label: 'core.module.input.label.Http Request Method',
value: 'POST',
list: [
{
label: 'GET',
value: 'GET'
},
{
label: 'POST',
value: 'POST'
}
],
required: true,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.httpReqUrl,
type: FlowNodeInputTypeEnum.input,
valueType: ModuleIOValueTypeEnum.string,
label: 'core.module.input.label.Http Request Url',
description: 'core.module.input.description.Http Request Url',
placeholder: 'https://api.ai.com/getInventory',
required: false,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.httpHeaders,
type: FlowNodeInputTypeEnum.JSONEditor,
valueType: ModuleIOValueTypeEnum.string,
value: '',
label: 'core.module.input.label.Http Request Header',
description: 'core.module.input.description.Http Request Header',
placeholder: 'core.module.input.description.Http Request Header',
required: false,
showTargetInApp: false,
showTargetInPlugin: false
},
Input_Template_DynamicInput,
{
...Input_Template_AddInputParam,
editField: {
key: true,
name: true,
description: true,
required: true,
dataType: true
},
defaultEditField: {
label: '',
key: '',
description: '',
inputType: FlowNodeInputTypeEnum.target,
valueType: ModuleIOValueTypeEnum.string,
required: true
}
}
],
outputs: [
Output_Template_Finish,
{
...Output_Template_AddOutput,
editField: {
key: true,
name: true,
description: true,
dataType: true
},
defaultEditField: {
label: '',
key: '',
description: '',
outputType: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.string
}
}
]
};
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import { Input_Template_Switch } from '../input';
import { Output_Template_Finish } from '../output';
export const AssignedAnswerModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.answerNode,
templateType: FlowNodeTemplateTypeEnum.textAnswer,
flowType: FlowNodeTypeEnum.answerNode,
avatar: '/imgs/module/reply.png',
name: '指定回复',
intro:
'该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。',
inputs: [
Input_Template_Switch,
{
key: ModuleInputKeyEnum.answerText,
type: FlowNodeInputTypeEnum.textarea,
valueType: ModuleIOValueTypeEnum.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
}
],
outputs: [Output_Template_Finish]
};
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import {
Input_Template_AddInputParam,
Input_Template_DynamicInput,
Input_Template_Switch
} from '../input';
import { Output_Template_AddOutput, Output_Template_Finish } from '../output';
export const HttpModule468: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.httpRequest468,
templateType: FlowNodeTemplateTypeEnum.externalCall,
flowType: FlowNodeTypeEnum.httpRequest468,
avatar: '/imgs/module/http.png',
name: 'HTTP 请求',
intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
showStatus: true,
isTool: true,
inputs: [
Input_Template_Switch,
{
key: ModuleInputKeyEnum.httpMethod,
type: FlowNodeInputTypeEnum.custom,
valueType: ModuleIOValueTypeEnum.string,
label: '',
value: 'POST',
required: true,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.httpReqUrl,
type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.string,
label: '',
description: 'core.module.input.description.Http Request Url',
placeholder: 'https://api.ai.com/getInventory',
required: false,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.httpHeaders,
type: FlowNodeInputTypeEnum.custom,
valueType: ModuleIOValueTypeEnum.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
},
{
key: ModuleInputKeyEnum.httpParams,
type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.any,
value: [],
label: '',
required: false,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.httpJsonBody,
type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.any,
value: '',
label: '',
required: false,
showTargetInApp: false,
showTargetInPlugin: false
},
Input_Template_DynamicInput,
{
...Input_Template_AddInputParam,
editField: {
key: true,
description: true,
dataType: true
},
defaultEditField: {
label: '',
key: '',
description: '',
inputType: FlowNodeInputTypeEnum.target,
valueType: ModuleIOValueTypeEnum.string
}
}
],
outputs: [
{
key: ModuleOutputKeyEnum.httpRawResponse,
label: '原始响应',
description: 'HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。',
valueType: ModuleIOValueTypeEnum.any,
type: FlowNodeOutputTypeEnum.source,
targets: []
},
{
...Output_Template_AddOutput,
editField: {
key: true,
description: true,
dataType: true,
defaultValue: true
},
defaultEditField: {
label: '',
key: '',
description: '',
outputType: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.string
}
},
Output_Template_Finish
]
};
import {
FlowNodeTemplateTypeEnum,
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum
} from '../../constants';
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
export const PluginInputModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.pluginInput,
templateType: FlowNodeTemplateTypeEnum.systemInput,
flowType: FlowNodeTypeEnum.pluginInput,
avatar: '/imgs/module/input.png',
name: '定义插件输入',
intro: '自定义配置外部输入,使用插件时,仅暴露自定义配置的输入',
showStatus: false,
inputs: [
{
key: ModuleInputKeyEnum.pluginStart,
type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.boolean,
label: '插件开始运行',
description:
'插件开始运行时,会输出一个 True 的标识。有时候,插件不会有额外的的输入,为了顺利的进入下一个阶段,你可以将该值连接到下一个节点的触发器中。',
showTargetInApp: true,
showTargetInPlugin: true
}
],
outputs: [
{
key: ModuleOutputKeyEnum.pluginStart,
label: '插件开始运行',
type: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.boolean,
targets: []
}
]
};
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
export const UserGuideModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.userGuide,
templateType: FlowNodeTemplateTypeEnum.userGuide,
flowType: FlowNodeTypeEnum.userGuide,
avatar: '/imgs/module/userGuide.png',
name: '系统配置',
intro: '可以配置应用的系统参数。',
inputs: [
{
key: ModuleInputKeyEnum.welcomeText,
type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.string,
label: 'core.app.Welcome Text',
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.variables,
type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.any,
label: 'core.module.Variable',
value: [],
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.questionGuide,
valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeInputTypeEnum.switch,
label: '',
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.tts,
type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.any,
label: '',
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.whisper,
type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.any,
label: '',
showTargetInApp: false,
showTargetInPlugin: false
}
],
outputs: []
};
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
export const UserInputModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.questionInput,
templateType: FlowNodeTemplateTypeEnum.systemInput,
flowType: FlowNodeTypeEnum.questionInput,
avatar: '/imgs/module/userChatInput.svg',
name: '对话入口',
intro: '当用户发送一个内容后,流程将会从这个模块开始执行。',
inputs: [
{
key: ModuleInputKeyEnum.userChatInput,
type: FlowNodeInputTypeEnum.systemInput,
valueType: ModuleIOValueTypeEnum.string,
label: 'core.module.input.label.user question',
showTargetInApp: false,
showTargetInPlugin: false
}
],
outputs: [
{
key: ModuleOutputKeyEnum.userChatInput,
label: 'core.module.input.label.user question',
type: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.string,
targets: []
}
]
};
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from './node/constant';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
VariableInputEnum,
variableMap
} from './constants';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './node/type';
import { ModuleItemType } from './type';
import type { VariableItemType, AppTTSConfigType, AppWhisperConfigType } from '../app/type';
import { Input_Template_Switch } from './template/input';
import { EditorVariablePickerType } from '../../../web/components/common/Textarea/PromptEditor/type';
import { Output_Template_Finish } from './template/output';
import { defaultWhisperConfig } from '../app/constants';
/* module */
export const getGuideModule = (modules: ModuleItemType[]) =>
modules.find((item) => item.flowType === FlowNodeTypeEnum.userGuide);
export const splitGuideModule = (guideModules?: ModuleItemType) => {
const welcomeText: string =
guideModules?.inputs?.find((item) => item.key === ModuleInputKeyEnum.welcomeText)?.value || '';
const variableModules: VariableItemType[] =
guideModules?.inputs.find((item) => item.key === ModuleInputKeyEnum.variables)?.value || [];
const questionGuide: boolean =
!!guideModules?.inputs?.find((item) => item.key === ModuleInputKeyEnum.questionGuide)?.value ||
false;
const ttsConfig: AppTTSConfigType = guideModules?.inputs?.find(
(item) => item.key === ModuleInputKeyEnum.tts
)?.value || { type: 'web' };
const whisperConfig: AppWhisperConfigType =
guideModules?.inputs?.find((item) => item.key === ModuleInputKeyEnum.whisper)?.value ||
defaultWhisperConfig;
return {
welcomeText,
variableModules,
questionGuide,
ttsConfig,
whisperConfig
};
};
export const getOrInitModuleInputValue = (input: FlowNodeInputItemType) => {
if (input.value !== undefined || !input.valueType) return input.value;
const map: Record<string, any> = {
[ModuleIOValueTypeEnum.boolean]: false,
[ModuleIOValueTypeEnum.number]: 0,
[ModuleIOValueTypeEnum.string]: ''
};
return map[input.valueType];
};
export const getModuleInputUiField = (input: FlowNodeInputItemType) => {
if (input.type === FlowNodeInputTypeEnum.input || input.type === FlowNodeInputTypeEnum.textarea) {
return {
placeholder: input.placeholder || input.description
};
}
return {};
};
export const plugin2ModuleIO = (
pluginId: string,
modules: ModuleItemType[]
): {
inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[];
} => {
const pluginInput = modules.find((module) => module.flowType === FlowNodeTypeEnum.pluginInput);
const pluginOutput = modules.find((module) => module.flowType === FlowNodeTypeEnum.pluginOutput);
return {
inputs: pluginInput
? [
{
// plugin id
key: ModuleInputKeyEnum.pluginId,
type: FlowNodeInputTypeEnum.hidden,
label: '',
value: pluginId,
valueType: ModuleIOValueTypeEnum.string,
connected: true,
showTargetInApp: false,
showTargetInPlugin: false
},
// switch
Input_Template_Switch,
...pluginInput.inputs.map((item) => ({
...item,
...getModuleInputUiField(item),
value: getOrInitModuleInputValue(item),
edit: false,
connected: false
}))
]
: [Input_Template_Switch],
outputs: pluginOutput
? [
...pluginOutput.outputs.map((item) => ({
...item,
edit: false
})),
Output_Template_Finish
]
: [Output_Template_Finish]
};
};
export const formatEditorVariablePickerIcon = (
variables: { key: string; label: string; type?: `${VariableInputEnum}` }[]
): EditorVariablePickerType[] => {
return variables.map((item) => ({
...item,
icon: item.type ? variableMap[item.type]?.icon : variableMap['input'].icon
}));
};
import { ModuleItemType } from '../module/type'; import { StoreNodeItemType } from '../workflow/type';
export const defaultModules: ModuleItemType[] = [
{
moduleId: 'custom-output',
name: '自定义输出',
flowType: 'pluginOutput',
showStatus: false,
position: {
x: 994.1266684738011,
y: -45.87689365278443
},
inputs: [],
outputs: []
},
{
moduleId: 'custom-input',
name: '自定义输入',
flowType: 'pluginInput',
showStatus: false,
position: {
x: 457.57860319995154,
y: -44.25099042468186
},
inputs: [],
outputs: []
}
];
export enum PluginTypeEnum { export enum PluginTypeEnum {
folder = 'folder', folder = 'folder',
......
import type { ModuleItemType } from '../module/type.d'; import { StoreEdgeItemType } from 'core/workflow/type/edge';
import type { StoreNodeItemType } from '../workflow/type';
import { PluginTypeEnum } from './constants'; import { PluginTypeEnum } from './constants';
import { HttpAuthMethodType } from './httpPlugin/type'; import { HttpAuthMethodType } from './httpPlugin/type';
...@@ -6,7 +7,7 @@ export type CreateOnePluginParams = { ...@@ -6,7 +7,7 @@ export type CreateOnePluginParams = {
name: string; name: string;
avatar: string; avatar: string;
intro: string; intro: string;
modules: ModuleItemType[]; modules: StoreNodeItemType[];
parentId: string | null; parentId: string | null;
type: `${PluginTypeEnum}`; type: `${PluginTypeEnum}`;
metadata?: { metadata?: {
...@@ -20,7 +21,8 @@ export type UpdatePluginParams = { ...@@ -20,7 +21,8 @@ export type UpdatePluginParams = {
name?: string; name?: string;
avatar?: string; avatar?: string;
intro?: string; intro?: string;
modules?: ModuleItemType[]; modules?: StoreNodeItemType[];
edges?: StoreEdgeItemType[];
metadata?: { metadata?: {
apiSchemaStr?: string; apiSchemaStr?: string;
customHeaders?: string; customHeaders?: string;
......
import { ModuleTemplateTypeEnum } from 'core/module/constants'; import { StoreEdgeItemType } from 'core/workflow/type/edge';
import type { FlowModuleTemplateType, ModuleItemType } from '../module/type.d'; import { ModuleTemplateTypeEnum } from '../workflow/constants';
import type { FlowModuleTemplateType, StoreNodeItemType } from '../workflow/type';
import { PluginSourceEnum, PluginTypeEnum } from './constants'; import { PluginSourceEnum, PluginTypeEnum } from './constants';
import { MethodType } from './controller'; import { MethodType } from './controller';
...@@ -12,7 +13,8 @@ export type PluginItemSchema = { ...@@ -12,7 +13,8 @@ export type PluginItemSchema = {
avatar: string; avatar: string;
intro: string; intro: string;
updateTime: Date; updateTime: Date;
modules: ModuleItemType[]; modules: StoreNodeItemType[];
edges: StoreEdgeItemType[];
parentId: string; parentId: string;
type: `${PluginTypeEnum}`; type: `${PluginTypeEnum}`;
metadata?: { metadata?: {
...@@ -20,6 +22,7 @@ export type PluginItemSchema = { ...@@ -20,6 +22,7 @@ export type PluginItemSchema = {
apiSchemaStr?: string; apiSchemaStr?: string;
customHeaders?: string; customHeaders?: string;
}; };
version?: 'v1' | 'v2';
}; };
/* plugin template */ /* plugin template */
...@@ -29,7 +32,6 @@ export type PluginTemplateType = PluginRuntimeType & { ...@@ -29,7 +32,6 @@ export type PluginTemplateType = PluginRuntimeType & {
source: `${PluginSourceEnum}`; source: `${PluginSourceEnum}`;
templateType: FlowNodeTemplateType['templateType']; templateType: FlowNodeTemplateType['templateType'];
intro: string; intro: string;
modules: ModuleItemType[];
}; };
export type PluginRuntimeType = { export type PluginRuntimeType = {
...@@ -38,5 +40,6 @@ export type PluginRuntimeType = { ...@@ -38,5 +40,6 @@ export type PluginRuntimeType = {
avatar: string; avatar: string;
showStatus?: boolean; showStatus?: boolean;
isTool?: boolean; isTool?: boolean;
modules: ModuleItemType[]; nodes: StoreNodeItemType[];
edges: StoreEdgeItemType[];
}; };
import { VectorModelItemType } from '../ai/model.d'; import { VectorModelItemType } from '../ai/model.d';
import { DYNAMIC_INPUT_KEY } from './constants'; import { NodeInputKeyEnum } from './constants';
export type SelectedDatasetType = { datasetId: string; vectorModel: VectorModelItemType }[]; export type SelectedDatasetType = { datasetId: string; vectorModel: VectorModelItemType }[];
export type HttpBodyType<T = any> = { export type HttpBodyType<T = Record<string, any>> = {
[DYNAMIC_INPUT_KEY]: Record<string, any>; [NodeInputKeyEnum.addInputParam]: Record<string, any>;
} & T; } & T;
export type HttpQueryType = { export type HttpQueryType = {
appId: string; appId: string;
......
export enum FlowNodeTemplateTypeEnum { export enum FlowNodeTemplateTypeEnum {
userGuide = 'userGuide',
systemInput = 'systemInput', systemInput = 'systemInput',
tools = 'tools', tools = 'tools',
textAnswer = 'textAnswer', textAnswer = 'textAnswer',
...@@ -11,13 +10,15 @@ export enum FlowNodeTemplateTypeEnum { ...@@ -11,13 +10,15 @@ export enum FlowNodeTemplateTypeEnum {
other = 'other' other = 'other'
} }
export enum ModuleIOValueTypeEnum { export enum WorkflowIOValueTypeEnum {
string = 'string', string = 'string',
number = 'number', number = 'number',
boolean = 'boolean', boolean = 'boolean',
any = 'any',
chatHistory = 'chatHistory', chatHistory = 'chatHistory',
datasetQuote = 'datasetQuote', datasetQuote = 'datasetQuote',
any = 'any', dynamic = 'dynamic',
// plugin special type // plugin special type
selectApp = 'selectApp', selectApp = 'selectApp',
...@@ -28,17 +29,21 @@ export enum ModuleIOValueTypeEnum { ...@@ -28,17 +29,21 @@ export enum ModuleIOValueTypeEnum {
} }
/* reg: modulename key */ /* reg: modulename key */
export enum ModuleInputKeyEnum { export enum NodeInputKeyEnum {
// old // old
welcomeText = 'welcomeText', welcomeText = 'welcomeText',
variables = 'variables',
switch = 'switch', // a trigger switch switch = 'switch', // a trigger switch
history = 'history', history = 'history',
userChatInput = 'userChatInput', userChatInput = 'userChatInput',
answerText = 'text',
// system config
questionGuide = 'questionGuide', questionGuide = 'questionGuide',
tts = 'tts', tts = 'tts',
whisper = 'whisper', whisper = 'whisper',
answerText = 'text', variables = 'variables',
scheduleTrigger = 'scheduleTrigger',
agents = 'agents', // cq agent key agents = 'agents', // cq agent key
// latest // latest
...@@ -89,13 +94,16 @@ export enum ModuleInputKeyEnum { ...@@ -89,13 +94,16 @@ export enum ModuleInputKeyEnum {
// plugin // plugin
pluginId = 'pluginId', pluginId = 'pluginId',
pluginStart = 'pluginStart' pluginStart = 'pluginStart',
// if else
condition = 'condition',
ifElseList = 'ifElseList'
} }
export enum ModuleOutputKeyEnum { export enum NodeOutputKeyEnum {
// common // common
userChatInput = 'userChatInput', userChatInput = 'userChatInput',
finish = 'finish',
history = 'history', history = 'history',
answerText = 'answerText', // module answer. the value will be show and save to history answerText = 'answerText', // module answer. the value will be show and save to history
success = 'success', success = 'success',
...@@ -104,10 +112,10 @@ export enum ModuleOutputKeyEnum { ...@@ -104,10 +112,10 @@ export enum ModuleOutputKeyEnum {
addOutputParam = 'system_addOutputParam', addOutputParam = 'system_addOutputParam',
// dataset // dataset
datasetIsEmpty = 'isEmpty',
datasetUnEmpty = 'unEmpty',
datasetQuoteQA = 'quoteQA', datasetQuoteQA = 'quoteQA',
// classify
cqResult = 'cqResult',
// context extract // context extract
contextExtractFields = 'fields', contextExtractFields = 'fields',
...@@ -122,7 +130,10 @@ export enum ModuleOutputKeyEnum { ...@@ -122,7 +130,10 @@ export enum ModuleOutputKeyEnum {
httpRawResponse = 'httpRawResponse', httpRawResponse = 'httpRawResponse',
// plugin // plugin
pluginStart = 'pluginStart' pluginStart = 'pluginStart',
if = 'IF',
else = 'ELSE'
} }
export enum VariableInputEnum { export enum VariableInputEnum {
...@@ -154,4 +165,11 @@ export const variableMap = { ...@@ -154,4 +165,11 @@ export const variableMap = {
} }
}; };
export const DYNAMIC_INPUT_KEY = 'DYNAMIC_INPUT_KEY'; export const DYNAMIC_INPUT_REFERENCE_KEY = 'DYNAMIC_INPUT_REFERENCE_KEY';
/* run time */
export enum RuntimeEdgeStatusEnum {
'waiting' = 'waiting',
'active' = 'active',
'skipped' = 'skipped'
}
export enum FlowNodeInputTypeEnum { // render ui
reference = 'reference', // reference to other node output
input = 'input', // one line input
numberInput = 'numberInput',
switch = 'switch', // true/false
// editor
textarea = 'textarea',
JSONEditor = 'JSONEditor',
addInputParam = 'addInputParam', // params input
// special input
selectApp = 'selectApp',
// ai model select
selectLLMModel = 'selectLLMModel',
settingLLMModel = 'settingLLMModel',
// dataset special input
selectDataset = 'selectDataset',
selectDatasetParamsModal = 'selectDatasetParamsModal',
settingDatasetQuotePrompt = 'settingDatasetQuotePrompt',
select = 'select',
hidden = 'hidden',
custom = 'custom'
}
export const FlowNodeInputMap: Record<
FlowNodeInputTypeEnum,
{
icon: string;
}
> = {
[FlowNodeInputTypeEnum.reference]: {
icon: 'core/workflow/inputType/reference'
},
[FlowNodeInputTypeEnum.input]: {
icon: 'core/workflow/inputType/input'
},
[FlowNodeInputTypeEnum.numberInput]: {
icon: 'core/workflow/inputType/numberInput'
},
[FlowNodeInputTypeEnum.select]: {
icon: 'core/workflow/inputType/input'
},
[FlowNodeInputTypeEnum.switch]: {
icon: 'core/workflow/inputType/switch'
},
[FlowNodeInputTypeEnum.textarea]: {
icon: 'core/workflow/inputType/textarea'
},
[FlowNodeInputTypeEnum.JSONEditor]: {
icon: 'core/workflow/inputType/jsonEditor'
},
[FlowNodeInputTypeEnum.addInputParam]: {
icon: 'core/workflow/inputType/dynamic'
},
[FlowNodeInputTypeEnum.selectApp]: {
icon: 'core/workflow/inputType/selectApp'
},
[FlowNodeInputTypeEnum.selectLLMModel]: {
icon: 'core/workflow/inputType/selectLLM'
},
[FlowNodeInputTypeEnum.settingLLMModel]: {
icon: 'core/workflow/inputType/selectLLM'
},
[FlowNodeInputTypeEnum.selectDataset]: {
icon: 'core/workflow/inputType/selectDataset'
},
[FlowNodeInputTypeEnum.selectDatasetParamsModal]: {
icon: 'core/workflow/inputType/selectDataset'
},
[FlowNodeInputTypeEnum.settingDatasetQuotePrompt]: {
icon: 'core/workflow/inputType/selectDataset'
},
[FlowNodeInputTypeEnum.hidden]: {
icon: 'core/workflow/inputType/select'
},
[FlowNodeInputTypeEnum.custom]: {
icon: 'core/workflow/inputType/select'
}
};
export enum FlowNodeOutputTypeEnum {
hidden = 'hidden',
source = 'source',
static = 'static',
dynamic = 'dynamic'
}
export enum FlowNodeTypeEnum {
emptyNode = 'emptyNode',
systemConfig = 'userGuide',
globalVariable = 'globalVariable',
workflowStart = 'workflowStart',
chatNode = 'chatNode',
datasetSearchNode = 'datasetSearchNode',
datasetConcatNode = 'datasetConcatNode',
answerNode = 'answerNode',
classifyQuestion = 'classifyQuestion',
contentExtract = 'contentExtract',
httpRequest468 = 'httpRequest468',
runApp = 'app',
pluginModule = 'pluginModule',
pluginInput = 'pluginInput',
pluginOutput = 'pluginOutput',
queryExtension = 'cfr',
tools = 'tools',
stopTool = 'stopTool',
lafModule = 'lafModule',
ifElseNode = 'ifElseNode'
}
export const EDGE_TYPE = 'default';
/*
react flow type
*/
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './constant';
import { WorkflowIOValueTypeEnum, NodeInputKeyEnum, NodeOutputKeyEnum } from '../constants';
import { SelectedDatasetType } from '../api';
import { LLMModelTypeEnum } from '../../ai/constants';
/* --------------- edit field ------------------- */
export type EditInputFieldMapType = EditOutputFieldMapType & {
inputType?: boolean;
};
export type EditOutputFieldMapType = {
key?: boolean;
description?: boolean;
valueType?: boolean; // output
required?: boolean;
defaultValue?: boolean;
};
export type EditNodeFieldType = {
inputType?: FlowNodeInputTypeEnum; // input type
valueType?: WorkflowIOValueTypeEnum;
required?: boolean;
key?: string;
label?: string;
description?: string;
isToolInput?: boolean;
defaultValue?: string;
maxLength?: number;
max?: number;
min?: number;
editField?: EditInputFieldMapType;
dynamicParamDefaultValue?: {
inputType?: FlowNodeInputTypeEnum; // input type
valueType?: WorkflowIOValueTypeEnum;
required?: boolean;
};
};
import { FlowNodeInputTypeEnum } from '../node/constant';
export enum SseResponseEventEnum { export enum SseResponseEventEnum {
error = 'error', error = 'error',
answer = 'answer', // animation stream answer = 'answer', // animation stream
...@@ -11,9 +13,17 @@ export enum SseResponseEventEnum { ...@@ -11,9 +13,17 @@ export enum SseResponseEventEnum {
} }
export enum DispatchNodeResponseKeyEnum { export enum DispatchNodeResponseKeyEnum {
skipHandleId = 'skipHandleId', // skip handle id
nodeResponse = 'responseData', // run node response nodeResponse = 'responseData', // run node response
nodeDispatchUsages = 'nodeDispatchUsages', // the node bill. nodeDispatchUsages = 'nodeDispatchUsages', // the node bill.
childrenResponses = 'childrenResponses', // Some nodes make recursive calls that need to be returned childrenResponses = 'childrenResponses', // Some nodes make recursive calls that need to be returned
toolResponses = 'toolResponses', // The result is passed back to the tool node for use toolResponses = 'toolResponses', // The result is passed back to the tool node for use
assistantResponses = 'assistantResponses' // assistant response assistantResponses = 'assistantResponses' // assistant response
} }
export const needReplaceReferenceInputTypeList = [
FlowNodeInputTypeEnum.reference,
FlowNodeInputTypeEnum.settingDatasetQuotePrompt,
FlowNodeInputTypeEnum.addInputParam,
FlowNodeInputTypeEnum.custom
] as string[];
import { ChatNodeUsageType } from '../../../support/wallet/bill/type'; import { ChatNodeUsageType } from '../../../support/wallet/bill/type';
import { ChatItemValueItemType, ToolRunResponseItemType } from '../../chat/type'; import { ChatItemValueItemType, ToolRunResponseItemType } from '../../chat/type';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../node/type'; import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../type/io.d';
import { ModuleItemType } from '../type'; import { StoreNodeItemType } from '../type';
import { DispatchNodeResponseKeyEnum } from './constants'; import { DispatchNodeResponseKeyEnum } from './constants';
import { StoreEdgeItemType } from '../type/edge';
import { NodeInputKeyEnum } from '../constants';
export type RunningModuleItemType = { export type RuntimeNodeItemType = {
name: ModuleItemType['name']; nodeId: StoreNodeItemType['nodeId'];
avatar: ModuleItemType['avatar']; name: StoreNodeItemType['name'];
intro?: ModuleItemType['intro']; avatar: StoreNodeItemType['avatar'];
moduleId: ModuleItemType['moduleId']; intro?: StoreNodeItemType['intro'];
flowType: ModuleItemType['flowType']; flowNodeType: StoreNodeItemType['flowNodeType'];
showStatus?: ModuleItemType['showStatus']; showStatus?: StoreNodeItemType['showStatus'];
isEntry?: ModuleItemType['isEntry']; isEntry?: StoreNodeItemType['isEntry'];
inputs: { inputs: FlowNodeInputItemType[];
key: string; outputs: FlowNodeOutputItemType[];
value?: any;
valueType?: FlowNodeInputItemType['valueType']; pluginId?: string;
required?: boolean; };
toolDescription?: string;
}[]; export type RuntimeEdgeItemType = StoreEdgeItemType & {
outputs: { status: 'waiting' | 'active' | 'skipped';
key: string;
required?: boolean;
defaultValue?: any;
answer?: boolean;
response?: boolean;
value?: any;
valueType?: FlowNodeOutputItemType['valueType'];
targets: {
moduleId: string;
key: string;
}[];
}[];
}; };
export type DispatchNodeResponseType = { export type DispatchNodeResponseType = {
...@@ -84,8 +74,8 @@ export type DispatchNodeResponseType = { ...@@ -84,8 +74,8 @@ export type DispatchNodeResponseType = {
pluginOutput?: Record<string, any>; pluginOutput?: Record<string, any>;
pluginDetail?: ChatHistoryItemResType[]; pluginDetail?: ChatHistoryItemResType[];
// tf switch // if-else
tfSwitchResult?: boolean; ifElseResult?: 'IF' | 'ELSE';
// tool // tool
toolCallTokens?: number; toolCallTokens?: number;
...@@ -94,9 +84,21 @@ export type DispatchNodeResponseType = { ...@@ -94,9 +84,21 @@ export type DispatchNodeResponseType = {
}; };
export type DispatchNodeResultType<T> = { export type DispatchNodeResultType<T> = {
[DispatchNodeResponseKeyEnum.skipHandleId]?: string[]; // skip some edge handle id
[DispatchNodeResponseKeyEnum.nodeResponse]?: DispatchNodeResponseType; // The node response detail [DispatchNodeResponseKeyEnum.nodeResponse]?: DispatchNodeResponseType; // The node response detail
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]?: ChatNodeUsageType[]; // [DispatchNodeResponseKeyEnum.nodeDispatchUsages]?: ChatNodeUsageType[]; //
[DispatchNodeResponseKeyEnum.childrenResponses]?: DispatchNodeResultType[]; [DispatchNodeResponseKeyEnum.childrenResponses]?: DispatchNodeResultType[];
[DispatchNodeResponseKeyEnum.toolResponses]?: ToolRunResponseItemType; [DispatchNodeResponseKeyEnum.toolResponses]?: ToolRunResponseItemType;
[DispatchNodeResponseKeyEnum.assistantResponses]?: ChatItemValueItemType[]; [DispatchNodeResponseKeyEnum.assistantResponses]?: ChatItemValueItemType[];
} & T; } & T;
/* Single node props */
export type AIChatNodeProps = {
[NodeInputKeyEnum.aiModel]: string;
[NodeInputKeyEnum.aiSystemPrompt]?: string;
[NodeInputKeyEnum.aiChatTemperature]: number;
[NodeInputKeyEnum.aiChatMaxToken]: number;
[NodeInputKeyEnum.aiChatIsResponseText]: boolean;
[NodeInputKeyEnum.aiChatQuoteTemplate]?: string;
[NodeInputKeyEnum.aiChatQuotePrompt]?: string;
};
import { ChatCompletionRequestMessageRoleEnum } from '../../ai/constants';
import { NodeOutputKeyEnum } from '../constants';
import { FlowNodeTypeEnum } from '../node/constant';
import { StoreNodeItemType } from '../type';
import { StoreEdgeItemType } from '../type/edge';
import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
import { VARIABLE_NODE_ID } from '../../../../../projects/app/src/web/core/workflow/constants/index';
export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeItemType[] => {
return (
edges?.map((edge) => ({
...edge,
status: 'waiting'
})) || []
);
};
export const getDefaultEntryNodeIds = (nodes: (StoreNodeItemType | RuntimeNodeItemType)[]) => {
const entryList = [
FlowNodeTypeEnum.systemConfig,
FlowNodeTypeEnum.workflowStart,
FlowNodeTypeEnum.pluginInput
];
return nodes
.filter((node) => entryList.includes(node.flowNodeType as any))
.map((item) => item.nodeId);
};
export const storeNodes2RuntimeNodes = (
nodes: StoreNodeItemType[],
entryNodeIds: string[]
): RuntimeNodeItemType[] => {
return (
nodes.map<RuntimeNodeItemType>((node) => {
return {
nodeId: node.nodeId,
name: node.name,
avatar: node.avatar,
intro: node.intro,
flowNodeType: node.flowNodeType,
showStatus: node.showStatus,
isEntry: entryNodeIds.includes(node.nodeId),
inputs: node.inputs,
outputs: node.outputs,
pluginId: node.pluginId
};
}) || []
);
};
export const filterWorkflowEdges = (edges: RuntimeEdgeItemType[]) => {
return edges.filter(
(edge) =>
edge.sourceHandle !== NodeOutputKeyEnum.selectedTools &&
edge.targetHandle !== NodeOutputKeyEnum.selectedTools
);
};
/*
区分普通连线和递归连线
递归连线:可以通过往上查询 nodes,最终追溯到自身
*/
export const splitEdges2WorkflowEdges = ({
edges,
allEdges,
currentNode
}: {
edges: RuntimeEdgeItemType[];
allEdges: RuntimeEdgeItemType[];
currentNode: RuntimeNodeItemType;
}) => {
const commonEdges: RuntimeEdgeItemType[] = [];
const recursiveEdges: RuntimeEdgeItemType[] = [];
edges.forEach((edge) => {
const checkIsCurrentNode = (edge: RuntimeEdgeItemType): boolean => {
const sourceEdge = allEdges.find((item) => item.target === edge.source);
if (!sourceEdge) return false;
if (sourceEdge.source === currentNode.nodeId) return true;
return checkIsCurrentNode(sourceEdge);
};
if (checkIsCurrentNode(edge)) {
recursiveEdges.push(edge);
} else {
commonEdges.push(edge);
}
});
return { commonEdges, recursiveEdges };
};
/*
1. 输入线分类:普通线和递归线(可以追溯到自身)
2. 起始线全部非 waiting 执行,或递归线全部非 waiting 执行
*/
export const checkNodeRunStatus = ({
node,
runtimeEdges
}: {
node: RuntimeNodeItemType;
runtimeEdges: RuntimeEdgeItemType[];
}) => {
const workflowEdges = filterWorkflowEdges(runtimeEdges).filter(
(item) => item.target === node.nodeId
);
if (workflowEdges.length === 0) {
return 'run';
}
const { commonEdges, recursiveEdges } = splitEdges2WorkflowEdges({
edges: workflowEdges,
allEdges: runtimeEdges,
currentNode: node
});
// check skip
if (commonEdges.every((item) => item.status === 'skipped')) {
return 'skip';
}
if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status === 'skipped')) {
return 'skip';
}
// check active
if (commonEdges.every((item) => item.status !== 'waiting')) {
return 'run';
}
if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status !== 'waiting')) {
return 'run';
}
return 'wait';
};
export const getReferenceVariableValue = ({
value,
nodes,
variables
}: {
value: [string, string];
nodes: RuntimeNodeItemType[];
variables: Record<string, any>;
}) => {
if (
!Array.isArray(value) ||
value.length !== 2 ||
typeof value[0] !== 'string' ||
typeof value[1] !== 'string'
) {
return value;
}
const sourceNodeId = value[0];
const outputId = value[1];
if (sourceNodeId === VARIABLE_NODE_ID && outputId) {
return variables[outputId];
}
const node = nodes.find((node) => node.nodeId === sourceNodeId);
if (!node) {
return undefined;
}
const outputValue = node.outputs.find((output) => output.id === outputId)?.value;
return outputValue;
};
export const textAdaptGptResponse = ({
text,
model = '',
finish_reason = null,
extraData = {}
}: {
model?: string;
text: string | null;
finish_reason?: null | 'stop';
extraData?: Object;
}) => {
return JSON.stringify({
...extraData,
id: '',
object: '',
created: 0,
model,
choices: [
{
delta:
text === null
? {}
: { role: ChatCompletionRequestMessageRoleEnum.Assistant, content: text },
index: 0,
finish_reason
}
]
});
};
import { UserGuideModule } from './system/userGuide'; import { SystemConfigNode } from './system/systemConfig';
import { UserInputModule } from './system/userInput'; import { EmptyNode } from './system/emptyNode';
import { WorkflowStart } from './system/workflowStart';
import { AiChatModule } from './system/aiChat'; import { AiChatModule } from './system/aiChat';
import { DatasetSearchModule } from './system/datasetSearch'; import { DatasetSearchModule } from './system/datasetSearch';
import { DatasetConcatModule } from './system/datasetConcat'; import { DatasetConcatModule } from './system/datasetConcat';
...@@ -7,7 +8,6 @@ import { AssignedAnswerModule } from './system/assignedAnswer'; ...@@ -7,7 +8,6 @@ import { AssignedAnswerModule } from './system/assignedAnswer';
import { ClassifyQuestionModule } from './system/classifyQuestion'; import { ClassifyQuestionModule } from './system/classifyQuestion';
import { ContextExtractModule } from './system/contextExtract'; import { ContextExtractModule } from './system/contextExtract';
import { HttpModule468 } from './system/http468'; import { HttpModule468 } from './system/http468';
import { HttpModule } from './system/abandon/http';
import { ToolModule } from './system/tools'; import { ToolModule } from './system/tools';
import { StopToolNode } from './system/stopTool'; import { StopToolNode } from './system/stopTool';
...@@ -18,14 +18,15 @@ import { PluginOutputModule } from './system/pluginOutput'; ...@@ -18,14 +18,15 @@ 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, moduleTemplateListType } from '../../module/type.d'; import type { FlowNodeTemplateType, nodeTemplateListType } from '../type';
import { FlowNodeTemplateTypeEnum } from '../../module/constants'; import { FlowNodeTemplateTypeEnum } from '../../workflow/constants';
import { lafModule } from './system/laf'; import { lafModule } from './system/laf';
import { ifElseNode } from './system/ifElse/index';
/* app flow module templates */ /* app flow module templates */
export const appSystemModuleTemplates: FlowNodeTemplateType[] = [ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
UserGuideModule, SystemConfigNode,
UserInputModule, WorkflowStart,
AiChatModule, AiChatModule,
AssignedAnswerModule, AssignedAnswerModule,
DatasetSearchModule, DatasetSearchModule,
...@@ -37,7 +38,8 @@ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [ ...@@ -37,7 +38,8 @@ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
ContextExtractModule, ContextExtractModule,
HttpModule468, HttpModule468,
AiQueryExtension, AiQueryExtension,
lafModule lafModule,
ifElseNode
]; ];
/* plugin flow module templates */ /* plugin flow module templates */
export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [ export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
...@@ -54,13 +56,15 @@ export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [ ...@@ -54,13 +56,15 @@ export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
ContextExtractModule, ContextExtractModule,
HttpModule468, HttpModule468,
AiQueryExtension, AiQueryExtension,
lafModule lafModule,
ifElseNode
]; ];
/* all module */ /* all module */
export const moduleTemplatesFlat: FlowNodeTemplateType[] = [ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
UserGuideModule, EmptyNode,
UserInputModule, SystemConfigNode,
WorkflowStart,
AiChatModule, AiChatModule,
DatasetSearchModule, DatasetSearchModule,
DatasetConcatModule, DatasetConcatModule,
...@@ -68,7 +72,6 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [ ...@@ -68,7 +72,6 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
ClassifyQuestionModule, ClassifyQuestionModule,
ContextExtractModule, ContextExtractModule,
HttpModule468, HttpModule468,
HttpModule,
ToolModule, ToolModule,
StopToolNode, StopToolNode,
AiChatModule, AiChatModule,
...@@ -77,13 +80,14 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [ ...@@ -77,13 +80,14 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
PluginOutputModule, PluginOutputModule,
RunPluginModule, RunPluginModule,
AiQueryExtension, AiQueryExtension,
lafModule lafModule,
ifElseNode
]; ];
export const moduleTemplatesList: moduleTemplateListType = [ export const moduleTemplatesList: nodeTemplateListType = [
{ {
type: FlowNodeTemplateTypeEnum.userGuide, type: FlowNodeTemplateTypeEnum.systemInput,
label: '', label: 'core.module.template.System input module',
list: [] list: []
}, },
{ {
...@@ -115,10 +119,5 @@ export const moduleTemplatesList: moduleTemplateListType = [ ...@@ -115,10 +119,5 @@ export const moduleTemplatesList: moduleTemplateListType = [
type: FlowNodeTemplateTypeEnum.other, type: FlowNodeTemplateTypeEnum.other,
label: '其他', label: '其他',
list: [] list: []
},
{
type: FlowNodeTemplateTypeEnum.systemInput,
label: 'core.module.template.System input module',
list: []
} }
]; ];
import { NodeInputKeyEnum } from '../constants';
import { FlowNodeInputTypeEnum } from '../node/constant';
import { WorkflowIOValueTypeEnum } from '../constants';
import { chatNodeSystemPromptTip } from './tip';
import { FlowNodeInputItemType } from '../type/io';
export const Input_Template_History: FlowNodeInputItemType = {
key: NodeInputKeyEnum.history,
renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.chatHistory,
label: 'core.module.input.label.chat history',
required: true,
min: 0,
max: 30,
value: 6
};
export const Input_Template_UserChatInput: FlowNodeInputItemType = {
key: NodeInputKeyEnum.userChatInput,
renderTypeList: [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.textarea],
valueType: WorkflowIOValueTypeEnum.string,
label: '用户问题',
required: true
};
export const Input_Template_DynamicInput: FlowNodeInputItemType = {
key: NodeInputKeyEnum.addInputParam,
renderTypeList: [FlowNodeInputTypeEnum.addInputParam],
valueType: WorkflowIOValueTypeEnum.dynamic,
label: '',
required: false
};
export const Input_Template_SelectAIModel: FlowNodeInputItemType = {
key: NodeInputKeyEnum.aiModel,
renderTypeList: [FlowNodeInputTypeEnum.selectLLMModel, FlowNodeInputTypeEnum.reference],
label: 'core.module.input.label.aiModel',
required: true,
valueType: WorkflowIOValueTypeEnum.string
};
export const Input_Template_SettingAiModel: FlowNodeInputItemType = {
key: NodeInputKeyEnum.aiModel,
renderTypeList: [FlowNodeInputTypeEnum.settingLLMModel, FlowNodeInputTypeEnum.reference],
label: 'core.module.input.label.aiModel',
valueType: WorkflowIOValueTypeEnum.string
};
export const Input_Template_System_Prompt: FlowNodeInputItemType = {
key: NodeInputKeyEnum.aiSystemPrompt,
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
max: 3000,
valueType: WorkflowIOValueTypeEnum.string,
label: 'core.ai.Prompt',
description: chatNodeSystemPromptTip,
placeholder: chatNodeSystemPromptTip
};
export const Input_Template_Dataset_Quote: FlowNodeInputItemType = {
key: NodeInputKeyEnum.aiChatDatasetQuote,
renderTypeList: [FlowNodeInputTypeEnum.settingDatasetQuotePrompt],
label: '',
debugLabel: '知识库引用',
description: '',
valueType: WorkflowIOValueTypeEnum.datasetQuote
};
import type { FlowNodeOutputItemType } from '../type/io.d';
import { NodeOutputKeyEnum } from '../constants';
import { FlowNodeOutputTypeEnum } from '../node/constant';
import { WorkflowIOValueTypeEnum } from '../constants';
export const Output_Template_AddOutput: FlowNodeOutputItemType = {
id: NodeOutputKeyEnum.addOutputParam,
key: NodeOutputKeyEnum.addOutputParam,
type: FlowNodeOutputTypeEnum.dynamic,
valueType: WorkflowIOValueTypeEnum.dynamic,
label: '',
editField: {
key: true,
valueType: true
}
};
...@@ -3,85 +3,75 @@ import { ...@@ -3,85 +3,75 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d'; import { FlowNodeTemplateType } from '../../type';
import { import {
ModuleIOValueTypeEnum, WorkflowIOValueTypeEnum,
ModuleInputKeyEnum, NodeInputKeyEnum,
ModuleOutputKeyEnum, NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum FlowNodeTemplateTypeEnum
} from '../../constants'; } from '../../constants';
import { import {
Input_Template_SettingAiModel, Input_Template_SettingAiModel,
Input_Template_Dataset_Quote, Input_Template_Dataset_Quote,
Input_Template_History, Input_Template_History,
Input_Template_Switch,
Input_Template_System_Prompt, Input_Template_System_Prompt,
Input_Template_UserChatInput Input_Template_UserChatInput
} from '../input'; } from '../input';
import { chatNodeSystemPromptTip } from '../tip'; import { chatNodeSystemPromptTip } from '../tip';
import { Output_Template_Finish, Output_Template_UserChatInput } from '../output'; import { getHandleConfig } from '../utils';
export const AiChatModule: FlowNodeTemplateType = { export const AiChatModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.chatNode, id: FlowNodeTypeEnum.chatNode,
templateType: FlowNodeTemplateTypeEnum.textAnswer, templateType: FlowNodeTemplateTypeEnum.textAnswer,
flowType: FlowNodeTypeEnum.chatNode, flowNodeType: FlowNodeTypeEnum.chatNode,
avatar: '/imgs/module/AI.png', sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/AI.png',
name: 'AI 对话', name: 'AI 对话',
intro: 'AI 大模型对话', intro: 'AI 大模型对话',
showStatus: true, showStatus: true,
isTool: true, isTool: true,
inputs: [ inputs: [
Input_Template_Switch,
Input_Template_SettingAiModel, Input_Template_SettingAiModel,
// --- settings modal // --- settings modal
{ {
key: ModuleInputKeyEnum.aiChatTemperature, key: NodeInputKeyEnum.aiChatTemperature,
type: FlowNodeInputTypeEnum.hidden, // Set in the pop-up window renderTypeList: [FlowNodeInputTypeEnum.hidden], // Set in the pop-up window
label: '', label: '',
value: 0, value: 0,
valueType: ModuleIOValueTypeEnum.number, valueType: WorkflowIOValueTypeEnum.number,
min: 0, min: 0,
max: 10, max: 10,
step: 1, step: 1
showTargetInApp: false,
showTargetInPlugin: false
}, },
{ {
key: ModuleInputKeyEnum.aiChatMaxToken, key: NodeInputKeyEnum.aiChatMaxToken,
type: FlowNodeInputTypeEnum.hidden, // Set in the pop-up window renderTypeList: [FlowNodeInputTypeEnum.hidden], // Set in the pop-up window
label: '', label: '',
value: 2000, value: 2000,
valueType: ModuleIOValueTypeEnum.number, valueType: WorkflowIOValueTypeEnum.number,
min: 100, min: 100,
max: 4000, max: 4000,
step: 50, step: 50
showTargetInApp: false,
showTargetInPlugin: false
}, },
{ {
key: ModuleInputKeyEnum.aiChatIsResponseText, key: NodeInputKeyEnum.aiChatIsResponseText,
type: FlowNodeInputTypeEnum.hidden, renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
value: true, value: true,
valueType: ModuleIOValueTypeEnum.boolean, valueType: WorkflowIOValueTypeEnum.boolean
showTargetInApp: false,
showTargetInPlugin: false
}, },
{ {
key: ModuleInputKeyEnum.aiChatQuoteTemplate, key: NodeInputKeyEnum.aiChatQuoteTemplate,
type: FlowNodeInputTypeEnum.hidden, renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
valueType: ModuleIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string
showTargetInApp: false,
showTargetInPlugin: false
}, },
{ {
key: ModuleInputKeyEnum.aiChatQuotePrompt, key: NodeInputKeyEnum.aiChatQuotePrompt,
type: FlowNodeInputTypeEnum.hidden, renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
valueType: ModuleIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string
showTargetInApp: false,
showTargetInPlugin: false
}, },
// settings modal --- // settings modal ---
{ {
...@@ -95,23 +85,21 @@ export const AiChatModule: FlowNodeTemplateType = { ...@@ -95,23 +85,21 @@ export const AiChatModule: FlowNodeTemplateType = {
Input_Template_Dataset_Quote Input_Template_Dataset_Quote
], ],
outputs: [ outputs: [
Output_Template_UserChatInput,
{ {
key: ModuleOutputKeyEnum.history, id: NodeOutputKeyEnum.history,
key: NodeOutputKeyEnum.history,
label: 'core.module.output.label.New context', label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context', description: 'core.module.output.description.New context',
valueType: ModuleIOValueTypeEnum.chatHistory, valueType: WorkflowIOValueTypeEnum.chatHistory,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.static
targets: []
}, },
{ {
key: ModuleOutputKeyEnum.answerText, id: NodeOutputKeyEnum.answerText,
key: NodeOutputKeyEnum.answerText,
label: 'core.module.output.label.Ai response content', label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content', description: 'core.module.output.description.Ai response content',
valueType: ModuleIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.static
targets: [] }
},
Output_Template_Finish
] ]
}; };
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d';
import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
FlowNodeTemplateTypeEnum,
NodeOutputKeyEnum
} from '../../constants';
import { getHandleConfig } from '../utils';
export const AssignedAnswerModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.answerNode,
templateType: FlowNodeTemplateTypeEnum.textAnswer,
flowNodeType: FlowNodeTypeEnum.answerNode,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/reply.png',
name: '指定回复',
intro:
'该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。',
inputs: [
{
key: NodeInputKeyEnum.answerText,
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.string,
label: 'core.module.input.label.Response content',
description: 'core.module.input.description.Response content',
placeholder: 'core.module.input.description.Response content'
}
],
outputs: []
};
...@@ -3,32 +3,33 @@ import { ...@@ -3,32 +3,33 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d'; import { FlowNodeTemplateType } from '../../type';
import { import {
ModuleIOValueTypeEnum, WorkflowIOValueTypeEnum,
ModuleInputKeyEnum, NodeInputKeyEnum,
FlowNodeTemplateTypeEnum FlowNodeTemplateTypeEnum,
NodeOutputKeyEnum
} from '../../constants'; } from '../../constants';
import { import {
Input_Template_SelectAIModel, Input_Template_SelectAIModel,
Input_Template_History, Input_Template_History,
Input_Template_Switch,
Input_Template_UserChatInput Input_Template_UserChatInput
} from '../input'; } from '../input';
import { Output_Template_UserChatInput } from '../output';
import { Input_Template_System_Prompt } from '../input'; import { Input_Template_System_Prompt } from '../input';
import { LLMModelTypeEnum } from '../../../ai/constants'; import { LLMModelTypeEnum } from '../../../ai/constants';
import { getHandleConfig } from '../utils';
export const ClassifyQuestionModule: FlowNodeTemplateType = { export const ClassifyQuestionModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.classifyQuestion, id: FlowNodeTypeEnum.classifyQuestion,
templateType: FlowNodeTemplateTypeEnum.functionCall, templateType: FlowNodeTemplateTypeEnum.functionCall,
flowType: FlowNodeTypeEnum.classifyQuestion, flowNodeType: FlowNodeTypeEnum.classifyQuestion,
avatar: '/imgs/module/cq.png', sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(true, false, true, true),
avatar: '/imgs/workflow/cq.png',
name: '问题分类', name: '问题分类',
intro: `根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题`, intro: `根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题`,
showStatus: true, showStatus: true,
inputs: [ inputs: [
Input_Template_Switch,
{ {
...Input_Template_SelectAIModel, ...Input_Template_SelectAIModel,
llmModelType: LLMModelTypeEnum.classify llmModelType: LLMModelTypeEnum.classify
...@@ -42,9 +43,9 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = { ...@@ -42,9 +43,9 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
Input_Template_History, Input_Template_History,
Input_Template_UserChatInput, Input_Template_UserChatInput,
{ {
key: ModuleInputKeyEnum.agents, key: NodeInputKeyEnum.agents,
type: FlowNodeInputTypeEnum.custom, renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: ModuleIOValueTypeEnum.any, valueType: WorkflowIOValueTypeEnum.any,
label: '', label: '',
value: [ value: [
{ {
...@@ -59,31 +60,16 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = { ...@@ -59,31 +60,16 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
value: '其他问题', value: '其他问题',
key: 'agex' key: 'agex'
} }
], ]
showTargetInApp: false,
showTargetInPlugin: false
} }
], ],
outputs: [ outputs: [
Output_Template_UserChatInput,
// custom output
{
key: 'wqre',
label: '',
type: FlowNodeOutputTypeEnum.hidden,
targets: []
},
{ {
key: 'sdfa', id: NodeOutputKeyEnum.cqResult,
label: '', key: NodeOutputKeyEnum.cqResult,
type: FlowNodeOutputTypeEnum.hidden, label: '分类结果',
targets: [] valueType: WorkflowIOValueTypeEnum.string,
}, type: FlowNodeOutputTypeEnum.static
{
key: 'agex',
label: '',
type: FlowNodeOutputTypeEnum.hidden,
targets: []
} }
] ]
}; };
...@@ -3,92 +3,84 @@ import { ...@@ -3,92 +3,84 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d'; import { FlowNodeTemplateType } from '../../type';
import { import {
ModuleIOValueTypeEnum, WorkflowIOValueTypeEnum,
ModuleInputKeyEnum, NodeInputKeyEnum,
ModuleOutputKeyEnum, NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum FlowNodeTemplateTypeEnum
} from '../../constants'; } from '../../constants';
import { import { Input_Template_SelectAIModel, Input_Template_History } from '../input';
Input_Template_SelectAIModel,
Input_Template_History,
Input_Template_Switch
} from '../input';
import { LLMModelTypeEnum } from '../../../ai/constants'; import { LLMModelTypeEnum } from '../../../ai/constants';
import { getHandleConfig } from '../utils';
export const ContextExtractModule: FlowNodeTemplateType = { export const ContextExtractModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.contentExtract, id: FlowNodeTypeEnum.contentExtract,
templateType: FlowNodeTemplateTypeEnum.functionCall, templateType: FlowNodeTemplateTypeEnum.functionCall,
flowType: FlowNodeTypeEnum.contentExtract, flowNodeType: FlowNodeTypeEnum.contentExtract,
avatar: '/imgs/module/extract.png', sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/extract.png',
name: '文本内容提取', name: '文本内容提取',
intro: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等', intro: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等',
showStatus: true, showStatus: true,
isTool: true, isTool: true,
inputs: [ inputs: [
Input_Template_Switch,
{ {
...Input_Template_SelectAIModel, ...Input_Template_SelectAIModel,
llmModelType: LLMModelTypeEnum.extractFields llmModelType: LLMModelTypeEnum.extractFields
}, },
{ {
key: ModuleInputKeyEnum.description, key: NodeInputKeyEnum.description,
type: FlowNodeInputTypeEnum.textarea, renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
valueType: ModuleIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string,
label: '提取要求描述', label: '提取要求描述',
description: description:
'给AI一些对应的背景知识或要求描述,引导AI更好的完成任务。\n该输入框可使用全局变量。', '给AI一些对应的背景知识或要求描述,引导AI更好的完成任务。\n该输入框可使用全局变量。',
placeholder: placeholder:
'例如: \n1. 当前时间为: {{cTime}}。你是一个实验室预约助手,你的任务是帮助用户预约实验室,从文本中获取对应的预约信息。\n2. 你是谷歌搜索助手,需要从文本中提取出合适的搜索词。', '例如: \n1. 当前时间为: {{cTime}}。你是一个实验室预约助手,你的任务是帮助用户预约实验室,从文本中获取对应的预约信息。\n2. 你是谷歌搜索助手,需要从文本中提取出合适的搜索词。'
showTargetInApp: true,
showTargetInPlugin: true
}, },
Input_Template_History, Input_Template_History,
{ {
key: ModuleInputKeyEnum.contextExtractInput, key: NodeInputKeyEnum.contextExtractInput,
type: FlowNodeInputTypeEnum.target, renderTypeList: [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.textarea],
label: '需要提取的文本', label: '需要提取的文本',
required: true, required: true,
valueType: ModuleIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string,
showTargetInApp: true,
showTargetInPlugin: true,
toolDescription: '需要检索的内容' toolDescription: '需要检索的内容'
}, },
{ {
key: ModuleInputKeyEnum.extractKeys, key: NodeInputKeyEnum.extractKeys,
type: FlowNodeInputTypeEnum.custom, renderTypeList: [FlowNodeInputTypeEnum.custom],
label: '', label: '',
valueType: ModuleIOValueTypeEnum.any, valueType: WorkflowIOValueTypeEnum.any,
description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段", description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段",
value: [], // {desc: string; key: string; required: boolean; enum: string[]}[] value: [] // {desc: string; key: string; required: boolean; enum: string[]}[]
showTargetInApp: false,
showTargetInPlugin: false
} }
], ],
outputs: [ outputs: [
// {
// id: NodeOutputKeyEnum.success,
// key: NodeOutputKeyEnum.success,
// label: '字段完全提取',
// valueType: WorkflowIOValueTypeEnum.boolean,
// type: FlowNodeOutputTypeEnum.source
// },
// {
// id: NodeOutputKeyEnum.failed,
// key: NodeOutputKeyEnum.failed,
// label: '提取字段缺失',
// description: '存在一个或多个字段未提取成功。尽管使用了默认值也算缺失。',
// valueType: WorkflowIOValueTypeEnum.boolean,
// type: FlowNodeOutputTypeEnum.source
// },
{ {
key: ModuleOutputKeyEnum.success, id: NodeOutputKeyEnum.contextExtractFields,
label: '字段完全提取', key: NodeOutputKeyEnum.contextExtractFields,
valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeOutputTypeEnum.source,
targets: []
},
{
key: ModuleOutputKeyEnum.failed,
label: '提取字段缺失',
description: '存在一个或多个字段未提取成功。尽管使用了默认值也算缺失。',
valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeOutputTypeEnum.source,
targets: []
},
{
key: ModuleOutputKeyEnum.contextExtractFields,
label: '完整提取结果', label: '完整提取结果',
description: '一个 JSON 字符串,例如:{"name:":"YY","Time":"2023/7/2 18:00"}', description: '一个 JSON 字符串,例如:{"name:":"YY","Time":"2023/7/2 18:00"}',
valueType: ModuleIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.static
targets: []
} }
] ]
}; };
...@@ -3,51 +3,57 @@ import { ...@@ -3,51 +3,57 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d'; import { FlowNodeTemplateType } from '../../type';
import { import {
ModuleIOValueTypeEnum, WorkflowIOValueTypeEnum,
ModuleInputKeyEnum, NodeInputKeyEnum,
ModuleOutputKeyEnum, NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum FlowNodeTemplateTypeEnum
} from '../../constants'; } from '../../constants';
import { Input_Template_Dataset_Quote, Input_Template_Switch } from '../input'; import { Input_Template_Dataset_Quote } from '../input';
import { Output_Template_Finish } from '../output';
import { getNanoid } from '../../../../common/string/tools'; import { getNanoid } from '../../../../common/string/tools';
import { getHandleConfig } from '../utils';
import { FlowNodeInputItemType } from '../../type/io.d';
export const getOneQuoteInputTemplate = (key = getNanoid()) => ({ export const getOneQuoteInputTemplate = (key = getNanoid()): FlowNodeInputItemType => ({
...Input_Template_Dataset_Quote, ...Input_Template_Dataset_Quote,
key, key,
type: FlowNodeInputTypeEnum.hidden renderTypeList: [FlowNodeInputTypeEnum.custom],
description: ''
}); });
export const DatasetConcatModule: FlowNodeTemplateType = { export const DatasetConcatModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.datasetConcatNode, id: FlowNodeTypeEnum.datasetConcatNode,
flowType: FlowNodeTypeEnum.datasetConcatNode, flowNodeType: FlowNodeTypeEnum.datasetConcatNode,
templateType: FlowNodeTemplateTypeEnum.other, templateType: FlowNodeTemplateTypeEnum.other,
avatar: '/imgs/module/concat.svg', sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/concat.svg',
name: '知识库搜索引用合并', name: '知识库搜索引用合并',
intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。', intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。',
showStatus: false, showStatus: false,
inputs: [ inputs: [
Input_Template_Switch,
{ {
key: ModuleInputKeyEnum.datasetMaxTokens, key: NodeInputKeyEnum.datasetMaxTokens,
type: FlowNodeInputTypeEnum.custom, renderTypeList: [FlowNodeInputTypeEnum.custom],
label: '最大 Tokens', label: '最大 Tokens',
value: 1500, value: 1500,
valueType: ModuleIOValueTypeEnum.number, valueType: WorkflowIOValueTypeEnum.number
showTargetInApp: false,
showTargetInPlugin: false
}, },
getOneQuoteInputTemplate('defaultQuote') {
key: 'customComponent',
renderTypeList: [FlowNodeInputTypeEnum.custom],
label: ''
},
getOneQuoteInputTemplate()
], ],
outputs: [ outputs: [
{ {
key: ModuleOutputKeyEnum.datasetQuoteQA, id: NodeOutputKeyEnum.datasetQuoteQA,
key: NodeOutputKeyEnum.datasetQuoteQA,
label: 'core.module.Dataset quote.label', label: 'core.module.Dataset quote.label',
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.static,
valueType: ModuleIOValueTypeEnum.datasetQuote, valueType: WorkflowIOValueTypeEnum.datasetQuote
targets: []
} }
] ]
}; };
...@@ -3,16 +3,16 @@ import { ...@@ -3,16 +3,16 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d'; import { FlowNodeTemplateType } from '../../type';
import { import {
ModuleIOValueTypeEnum, WorkflowIOValueTypeEnum,
ModuleInputKeyEnum, NodeInputKeyEnum,
ModuleOutputKeyEnum, NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum FlowNodeTemplateTypeEnum
} from '../../constants'; } from '../../constants';
import { Input_Template_Switch, Input_Template_UserChatInput } from '../input'; import { Input_Template_UserChatInput } from '../input';
import { Output_Template_Finish, Output_Template_UserChatInput } from '../output';
import { DatasetSearchModeEnum } from '../../../dataset/constants'; import { DatasetSearchModeEnum } from '../../../dataset/constants';
import { getHandleConfig } from '../utils';
export const Dataset_SEARCH_DESC = export const Dataset_SEARCH_DESC =
'调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容'; '调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容';
...@@ -20,85 +20,71 @@ export const Dataset_SEARCH_DESC = ...@@ -20,85 +20,71 @@ export const Dataset_SEARCH_DESC =
export const DatasetSearchModule: FlowNodeTemplateType = { export const DatasetSearchModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.datasetSearchNode, id: FlowNodeTypeEnum.datasetSearchNode,
templateType: FlowNodeTemplateTypeEnum.functionCall, templateType: FlowNodeTemplateTypeEnum.functionCall,
flowType: FlowNodeTypeEnum.datasetSearchNode, flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
avatar: '/imgs/module/db.png', sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/db.png',
name: '知识库搜索', name: '知识库搜索',
intro: Dataset_SEARCH_DESC, intro: Dataset_SEARCH_DESC,
showStatus: true, showStatus: true,
isTool: true, isTool: true,
inputs: [ inputs: [
Input_Template_Switch,
{ {
key: ModuleInputKeyEnum.datasetSelectList, key: NodeInputKeyEnum.datasetSelectList,
type: FlowNodeInputTypeEnum.selectDataset, renderTypeList: [FlowNodeInputTypeEnum.selectDataset, FlowNodeInputTypeEnum.reference],
label: 'core.module.input.label.Select dataset', label: 'core.module.input.label.Select dataset',
value: [], value: [],
valueType: ModuleIOValueTypeEnum.selectDataset, valueType: WorkflowIOValueTypeEnum.selectDataset,
list: [], list: [],
required: true, required: true
showTargetInApp: false,
showTargetInPlugin: true
}, },
{ {
key: ModuleInputKeyEnum.datasetSimilarity, key: NodeInputKeyEnum.datasetSimilarity,
type: FlowNodeInputTypeEnum.selectDatasetParamsModal, renderTypeList: [FlowNodeInputTypeEnum.selectDatasetParamsModal],
label: '', label: '',
value: 0.4, value: 0.4,
valueType: ModuleIOValueTypeEnum.number, valueType: WorkflowIOValueTypeEnum.number
showTargetInApp: false,
showTargetInPlugin: false
}, },
// setting from modal
{ {
key: ModuleInputKeyEnum.datasetMaxTokens, key: NodeInputKeyEnum.datasetMaxTokens,
type: FlowNodeInputTypeEnum.hidden, renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
value: 1500, value: 1500,
valueType: ModuleIOValueTypeEnum.number, valueType: WorkflowIOValueTypeEnum.number
showTargetInApp: false,
showTargetInPlugin: false
}, },
{ {
key: ModuleInputKeyEnum.datasetSearchMode, key: NodeInputKeyEnum.datasetSearchMode,
type: FlowNodeInputTypeEnum.hidden, renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
valueType: ModuleIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false,
value: DatasetSearchModeEnum.embedding value: DatasetSearchModeEnum.embedding
}, },
{ {
key: ModuleInputKeyEnum.datasetSearchUsingReRank, key: NodeInputKeyEnum.datasetSearchUsingReRank,
type: FlowNodeInputTypeEnum.hidden, renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
valueType: ModuleIOValueTypeEnum.boolean, valueType: WorkflowIOValueTypeEnum.boolean,
showTargetInApp: false,
showTargetInPlugin: false,
value: false value: false
}, },
{ {
key: ModuleInputKeyEnum.datasetSearchUsingExtensionQuery, key: NodeInputKeyEnum.datasetSearchUsingExtensionQuery,
type: FlowNodeInputTypeEnum.hidden, renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
valueType: ModuleIOValueTypeEnum.boolean, valueType: WorkflowIOValueTypeEnum.boolean,
showTargetInApp: false,
showTargetInPlugin: false,
value: true value: true
}, },
{ {
key: ModuleInputKeyEnum.datasetSearchExtensionModel, key: NodeInputKeyEnum.datasetSearchExtensionModel,
type: FlowNodeInputTypeEnum.hidden, renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
valueType: ModuleIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string
showTargetInApp: false,
showTargetInPlugin: false
}, },
{ {
key: ModuleInputKeyEnum.datasetSearchExtensionBg, key: NodeInputKeyEnum.datasetSearchExtensionBg,
type: FlowNodeInputTypeEnum.hidden, renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '', label: '',
valueType: ModuleIOValueTypeEnum.string, valueType: WorkflowIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false,
value: '' value: ''
}, },
{ {
...@@ -107,27 +93,13 @@ export const DatasetSearchModule: FlowNodeTemplateType = { ...@@ -107,27 +93,13 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
} }
], ],
outputs: [ outputs: [
Output_Template_UserChatInput,
{ {
key: ModuleOutputKeyEnum.datasetIsEmpty, id: NodeOutputKeyEnum.datasetQuoteQA,
label: 'core.module.output.label.Search result empty', key: NodeOutputKeyEnum.datasetQuoteQA,
type: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.boolean,
targets: []
},
{
key: ModuleOutputKeyEnum.datasetUnEmpty,
label: 'core.module.output.label.Search result not empty',
type: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.boolean,
targets: []
},
{
key: ModuleOutputKeyEnum.datasetQuoteQA,
label: 'core.module.Dataset quote.label', label: 'core.module.Dataset quote.label',
type: FlowNodeOutputTypeEnum.source, description: '特殊数组格式,搜索结果为空时,返回空数组。',
valueType: ModuleIOValueTypeEnum.datasetQuote, type: FlowNodeOutputTypeEnum.static,
targets: [] valueType: WorkflowIOValueTypeEnum.datasetQuote
} }
] ]
}; };
import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type';
import { FlowNodeTemplateTypeEnum } from '../../constants';
import { getHandleConfig } from '../utils';
export const EmptyNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.emptyNode,
templateType: FlowNodeTemplateTypeEnum.systemInput,
flowNodeType: FlowNodeTypeEnum.emptyNode,
sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(false, false, false, false),
avatar: '',
name: '',
intro: '',
inputs: [],
outputs: []
};
import { FlowNodeTemplateTypeEnum, WorkflowIOValueTypeEnum } from '../../constants';
import { getHandleConfig } from '../utils';
import { FlowNodeTypeEnum } from '../../node/constant';
import { VariableItemType } from '../../../app/type';
import { FlowNodeTemplateType } from '../../type';
export const getGlobalVariableNode = ({
id,
variables
}: {
id: string;
variables: VariableItemType[];
}): FlowNodeTemplateType => {
return {
id,
templateType: FlowNodeTemplateTypeEnum.other,
flowNodeType: FlowNodeTypeEnum.systemConfig,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/variable.png',
name: '全局变量',
intro: '',
inputs: [],
outputs: variables.map((item) => ({
id: item.key,
key: item.key,
valueType: WorkflowIOValueTypeEnum.string,
label: item.label
}))
};
};
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/index.d';
import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import { Input_Template_DynamicInput } from '../input';
import { Output_Template_AddOutput } from '../output';
import { getHandleConfig } from '../utils';
export const HttpModule468: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.httpRequest468,
templateType: FlowNodeTemplateTypeEnum.externalCall,
flowNodeType: FlowNodeTypeEnum.httpRequest468,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/http.png',
name: 'HTTP 请求',
intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
showStatus: true,
isTool: true,
inputs: [
{
...Input_Template_DynamicInput,
description: 'core.module.input.description.HTTP Dynamic Input',
editField: {
key: true,
valueType: true
}
},
{
key: NodeInputKeyEnum.httpMethod,
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.string,
label: '',
value: 'POST',
required: true
},
{
key: NodeInputKeyEnum.httpReqUrl,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.string,
label: '',
description: 'core.module.input.description.Http Request Url',
placeholder: 'https://api.ai.com/getInventory',
required: false
},
{
key: NodeInputKeyEnum.httpHeaders,
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.any,
value: [],
label: '',
description: 'core.module.input.description.Http Request Header',
placeholder: 'core.module.input.description.Http Request Header',
required: false
},
{
key: NodeInputKeyEnum.httpParams,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
value: [],
label: '',
required: false
},
{
key: NodeInputKeyEnum.httpJsonBody,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
value: '',
label: '',
required: false
}
],
outputs: [
Output_Template_AddOutput,
{
id: NodeOutputKeyEnum.httpRawResponse,
key: NodeOutputKeyEnum.httpRawResponse,
label: '原始响应',
description: 'HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。',
valueType: WorkflowIOValueTypeEnum.any,
type: FlowNodeOutputTypeEnum.static
}
]
};
export enum VariableConditionEnum {
equalTo = 'equalTo',
notEqual = 'notEqual',
isEmpty = 'isEmpty',
isNotEmpty = 'isNotEmpty',
include = 'include',
notInclude = 'notInclude',
startWith = 'startWith',
endWith = 'endWith',
greaterThan = 'greaterThan',
greaterThanOrEqualTo = 'greaterThanOrEqualTo',
lessThan = 'lessThan',
lessThanOrEqualTo = 'lessThanOrEqualTo',
lengthEqualTo = 'lengthEqualTo',
lengthNotEqualTo = 'lengthNotEqualTo',
lengthGreaterThan = 'lengthGreaterThan',
lengthGreaterThanOrEqualTo = 'lengthGreaterThanOrEqualTo',
lengthLessThan = 'lengthLessThan',
lengthLessThanOrEqualTo = 'lengthLessThanOrEqualTo'
}
export const stringConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '等于', value: VariableConditionEnum.equalTo },
{ label: '不等于', value: VariableConditionEnum.notEqual },
{ label: '包含', value: VariableConditionEnum.include },
{ label: '不包含', value: VariableConditionEnum.notInclude },
{ label: '开始为', value: VariableConditionEnum.startWith },
{ label: '结束为', value: VariableConditionEnum.endWith }
];
export const numberConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '等于', value: VariableConditionEnum.equalTo },
{ label: '不等于', value: VariableConditionEnum.notEqual },
{ label: '大于', value: VariableConditionEnum.greaterThan },
{ label: '大于等于', value: VariableConditionEnum.greaterThanOrEqualTo },
{ label: '小于', value: VariableConditionEnum.lessThan },
{ label: '小于等于', value: VariableConditionEnum.lessThanOrEqualTo }
];
export const booleanConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '等于', value: VariableConditionEnum.equalTo }
];
export const arrayConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '包含', value: VariableConditionEnum.include },
{ label: '不包含', value: VariableConditionEnum.notInclude },
{ label: '长度等于', value: VariableConditionEnum.lengthEqualTo },
{ label: '长度不等于', value: VariableConditionEnum.lengthNotEqualTo },
{ label: '长度大于', value: VariableConditionEnum.lengthGreaterThan },
{ label: '长度大于等于', value: VariableConditionEnum.lengthGreaterThanOrEqualTo },
{ label: '长度小于', value: VariableConditionEnum.lengthLessThan },
{ label: '长度小于等于', value: VariableConditionEnum.lengthLessThanOrEqualTo }
];
export const objectConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty }
];
export const allConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '等于', value: VariableConditionEnum.equalTo },
{ label: '不等于', value: VariableConditionEnum.notEqual },
{ label: '包含', value: VariableConditionEnum.include },
{ label: '不包含', value: VariableConditionEnum.notInclude },
{ label: '开始为', value: VariableConditionEnum.startWith },
{ label: '结束为', value: VariableConditionEnum.endWith },
{ label: '大于', value: VariableConditionEnum.greaterThan },
{ label: '大于等于', value: VariableConditionEnum.greaterThanOrEqualTo },
{ label: '小于', value: VariableConditionEnum.lessThan },
{ label: '小于等于', value: VariableConditionEnum.lessThanOrEqualTo },
{ label: '长度等于', value: VariableConditionEnum.lengthEqualTo },
{ label: '长度不等于', value: VariableConditionEnum.lengthNotEqualTo },
{ label: '长度大于', value: VariableConditionEnum.lengthGreaterThan },
{ label: '长度大于等于', value: VariableConditionEnum.lengthGreaterThanOrEqualTo },
{ label: '长度小于', value: VariableConditionEnum.lengthLessThan },
{ label: '长度小于等于', value: VariableConditionEnum.lengthLessThanOrEqualTo }
];
import {
FlowNodeTemplateTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
WorkflowIOValueTypeEnum
} from '../../../constants';
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../../node/constant';
import { FlowNodeTemplateType } from '../../../type';
import { getHandleConfig } from '../../utils';
export const ifElseNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.ifElseNode,
templateType: FlowNodeTemplateTypeEnum.tools,
flowNodeType: FlowNodeTypeEnum.ifElseNode,
sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(true, false, true, true),
avatar: '/imgs/workflow/ifElse.svg',
name: '判断器',
intro: '根据一定的条件,执行不同的分支。',
showStatus: true,
inputs: [
{
key: NodeInputKeyEnum.condition,
valueType: WorkflowIOValueTypeEnum.string,
label: '',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
required: false,
value: 'AND' // AND, OR
},
{
key: NodeInputKeyEnum.ifElseList,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
label: '',
value: [
{
variable: undefined,
condition: undefined,
value: undefined
}
]
}
],
outputs: [
{
id: NodeOutputKeyEnum.if,
key: NodeOutputKeyEnum.if,
label: 'IF',
valueType: WorkflowIOValueTypeEnum.any,
type: FlowNodeOutputTypeEnum.source
},
{
id: NodeOutputKeyEnum.else,
key: NodeOutputKeyEnum.else,
label: 'ELSE',
valueType: WorkflowIOValueTypeEnum.any,
type: FlowNodeOutputTypeEnum.source
}
]
};
import { ReferenceValueProps } from 'core/workflow/type/io';
import { VariableConditionEnum } from './constant';
export type IfElseConditionType = 'AND' | 'OR';
export type IfElseListItemType = {
variable?: ReferenceValueProps;
condition?: VariableConditionEnum;
value?: string;
};
...@@ -3,84 +3,58 @@ import { ...@@ -3,84 +3,58 @@ import {
FlowNodeOutputTypeEnum, FlowNodeOutputTypeEnum,
FlowNodeTypeEnum FlowNodeTypeEnum
} from '../../node/constant'; } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type'; import { FlowNodeTemplateType } from '../../type/index.d';
import { import {
ModuleIOValueTypeEnum, WorkflowIOValueTypeEnum,
ModuleInputKeyEnum, NodeInputKeyEnum,
ModuleOutputKeyEnum, NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum FlowNodeTemplateTypeEnum
} from '../../constants'; } from '../../constants';
import { import { Input_Template_DynamicInput } from '../input';
Input_Template_DynamicInput, import { Output_Template_AddOutput } from '../output';
Input_Template_Switch, import { getHandleConfig } from '../utils';
Input_Template_AddInputParam
} from '../input';
import { Output_Template_Finish, Output_Template_AddOutput } from '../output';
export const lafModule: FlowNodeTemplateType = { export const lafModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.lafModule, id: FlowNodeTypeEnum.lafModule,
templateType: FlowNodeTemplateTypeEnum.externalCall, templateType: FlowNodeTemplateTypeEnum.externalCall,
flowType: FlowNodeTypeEnum.lafModule, flowNodeType: FlowNodeTypeEnum.lafModule,
avatar: '/imgs/module/laf.png', sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/laf.png',
name: 'Laf 函数调用(测试)', name: 'Laf 函数调用(测试)',
intro: '可以调用Laf账号下的云函数。', intro: '可以调用Laf账号下的云函数。',
showStatus: true, showStatus: true,
isTool: true, isTool: true,
inputs: [ inputs: [
Input_Template_Switch,
{
key: ModuleInputKeyEnum.httpReqUrl,
type: FlowNodeInputTypeEnum.hidden,
valueType: ModuleIOValueTypeEnum.string,
label: '',
description: 'core.module.input.description.Http Request Url',
placeholder: 'https://api.ai.com/getInventory',
required: false,
showTargetInApp: false,
showTargetInPlugin: false
},
Input_Template_DynamicInput,
{ {
...Input_Template_AddInputParam, ...Input_Template_DynamicInput,
description: '接收前方节点的输出值作为变量,这些变量可以被 Laf 请求参数使用。',
editField: { editField: {
key: true, key: true,
description: true, valueType: true
dataType: true }
}, },
defaultEditField: { {
key: NodeInputKeyEnum.httpReqUrl,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.string,
label: '', label: '',
key: '', description: 'core.module.input.description.Http Request Url',
description: '', placeholder: 'https://api.ai.com/getInventory',
inputType: FlowNodeInputTypeEnum.target, required: false
valueType: ModuleIOValueTypeEnum.string
}
} }
], ],
outputs: [ outputs: [
{ {
key: ModuleOutputKeyEnum.httpRawResponse, id: NodeOutputKeyEnum.httpRawResponse,
key: NodeOutputKeyEnum.httpRawResponse,
label: '原始响应', label: '原始响应',
description: 'HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。', description: 'HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。',
valueType: ModuleIOValueTypeEnum.any, valueType: WorkflowIOValueTypeEnum.any,
type: FlowNodeOutputTypeEnum.source, type: FlowNodeOutputTypeEnum.static
targets: []
}, },
{ {
...Output_Template_AddOutput, ...Output_Template_AddOutput
editField: {
key: true,
description: true,
dataType: true,
defaultValue: true
},
defaultEditField: {
label: '',
key: '',
description: '',
outputType: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.string
} }
},
Output_Template_Finish
] ]
}; };
import { FlowNodeTemplateTypeEnum } from '../../constants';
import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type';
import { getHandleConfig } from '../utils';
export const PluginInputModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.pluginInput,
templateType: FlowNodeTemplateTypeEnum.systemInput,
flowNodeType: FlowNodeTypeEnum.pluginInput,
sourceHandle: getHandleConfig(false, true, false, false),
targetHandle: getHandleConfig(false, false, false, false),
unique: true,
forbidDelete: true,
avatar: '/imgs/workflow/input.png',
name: '定义插件输入',
intro: '自定义配置外部输入,使用插件时,仅暴露自定义配置的输入',
showStatus: false,
inputs: [],
outputs: []
};
import { FlowNodeTemplateTypeEnum } from '../../constants'; import { FlowNodeTemplateTypeEnum } from '../../constants';
import { FlowNodeTypeEnum } from '../../node/constant'; import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d'; import { FlowNodeTemplateType } from '../../type';
import { getHandleConfig } from '../utils';
export const PluginOutputModule: FlowNodeTemplateType = { export const PluginOutputModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.pluginOutput, id: FlowNodeTypeEnum.pluginOutput,
templateType: FlowNodeTemplateTypeEnum.systemInput, templateType: FlowNodeTemplateTypeEnum.systemInput,
flowType: FlowNodeTypeEnum.pluginOutput, flowNodeType: FlowNodeTypeEnum.pluginOutput,
avatar: '/imgs/module/output.png', sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(false, false, false, true),
unique: true,
forbidDelete: true,
avatar: '/imgs/workflow/output.png',
name: '定义插件输出', name: '定义插件输出',
intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出', intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出',
showStatus: false, showStatus: false,
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment