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>
This commit is contained in:
Archer 2024-04-25 17:51:20 +08:00 committed by GitHub
parent b08d81f887
commit 439c819ff1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
505 changed files with 23570 additions and 18215 deletions

View File

@ -19,20 +19,6 @@ RUN [ -f pnpm-lock.yaml ] || (echo "Lockfile not found." && exit 1)
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 -----------
FROM node:18.17-alpine AS builder
WORKDIR /app
@ -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 --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 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 --from=builder /app/projects/$name/package.json ./package.json
# copy woker
COPY --from=workerDeps /app/worker /app/worker
# copy config
COPY ./projects/$name/data /app/data
RUN chown -R nextjs:nodejs /app/data
ENV NODE_ENV production

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -28,8 +28,8 @@ images: []
### 其他模型没法进行问题分类/内容提取
需要给其他模型配置`toolChoice=false`就会默认走提示词模式。目前内置提示词仅针对了商业模型API进行测试。
问题分类基本可用,内容提取不太行
1. 看日志。如果提示 JSON invalidnot support tool 之类的,说明该模型不支持工具调用或函数调用,需要设置`toolChoice=false``functionCall=false`就会默认走提示词模式。目前内置提示词仅针对了商业模型API进行测试。问题分类基本可用,内容提取不太行。
2. 如果已经配置正常,并且没有错误日志,则说明可能提示词不太适合该模型,可以通过修改`customCQPrompt`来自定义提示词
### 页面崩溃

View File

@ -286,7 +286,7 @@ type ResponseType = {
pluginOutput?: Record<string, any>; // 插件输出
pluginDetail?: ChatHistoryItemResType[]; // 插件详情
tfSwitchResult?: boolean; // 判断器结果
isElseResult?: boolean; // 判断器结果
}
```

View File

@ -0,0 +1,25 @@
---
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 进程。

View File

@ -9,7 +9,7 @@ weight: 404
| | |
| --------------------- | --------------------- |
| ![](/imgs/demo-dalle1.png) | ![](/imgs/demo-dalle2.webp) |
| ![](/imgs/demo-dalle1.webp) | ![](/imgs/demo-dalle2.webp) |
## OpenAI Dalle3 接口
@ -44,14 +44,14 @@ Response
## 编排思路
1. 通过 AI 来优化图片绘制的提示词(这省略了,自己找提示词即可)
2. 通过`HTTP 模块`调用 Dalle3 接口,获取图片的 URL。
3. 通过`文本加工`来构建`Markdown`的图片格式。
4. 通过`指定回复`来直接输出图片链接。
1. 通过 AI 来优化图片绘制的提示词(这省略了,自己找提示词即可)
2. 通过 `HTTP 请求】模块` 调用 Dalle3 接口,获取图片的 URL。
3. 通过 `文本加工】模块` 来构建 `Markdown` 的图片格式。
4. 通过 `指定回复】模块` 来直接输出图片链接。
### 1. 构建 HTTP 模块
请求参数直接复制 Dalle3 接口的即可,并求改 prompt 为变量。需要增加一个`Headers.Authorization`
请求参数直接复制 Dalle3 接口的即可,并求改 prompt 为变量。需要增加一个 `Headers.Authorization`
Body:
@ -70,448 +70,402 @@ Headers:
Response:
响应值需要根据Dalle3接口的返回值进行获取我们只绘制了1张图片所以只需要取第一张图片的URL即可。给 HTTP 模块增加一个`key``data[0].url`的输出值
响应值需要根据 Dalle3 接口的返回值进行获取我们只绘制了1张图片所以只需要取第一张图片的 URL 即可。给 HTTP 模块增加一个自定义输出 `data[0].url`
### 2. 文本加工 - 构建图片链接
`Markdown`语法中`![图片描述](图片链接)`表示插入图片,图片链接由`HTTP模块`输出。
`Markdown` 语法中 `![图片描述](图片链接)` 表示插入图片图片链接由【HTTP 请求】模块输出。
因此可以增加一个输入来接收`HTTP模块`的图片链接输出,并在`文本内容`中通过变量来引用图片链接,从而得到一个完整的`Markdown`图片格式。
因此可以增加一个输入来接收 `【HTTP 请求】模块` 的图片链接输出,并在 `【文本加工】模块 - 文本` 中通过变量来引用图片链接,从而得到一个完整的 `Markdown` 图片格式。
### 3. 指定回复
指定回复可以直接输出传入的内容到客户端,因此可以直接输出加工好的`Markdown`图片格式即可。
指定回复可以直接输出传入的内容到客户端,因此可以直接输出加工好的 `Markdown` 图片格式即可。
## 编排代码
{{% details title="编排配置" closed="true" %}}
```json
[
{
"moduleId": "userGuide",
"name": "core.module.template.App system setting",
"flowType": "userGuide",
"position": {
"x": 454.98510354678695,
"y": 721.4016845336229
},
"inputs": [
{
"key": "welcomeText",
"type": "hidden",
"valueType": "string",
"label": "core.app.Welcome Text",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
{
"nodes": [
{
"nodeId": "userGuide",
"name": "系统配置",
"intro": "可以配置应用的系统参数",
"avatar": "/imgs/workflow/userGuide.png",
"flowNodeType": "userGuide",
"position": {
"x": 531.2422736065552,
"y": -486.7611729549753
},
{
"key": "variables",
"type": "hidden",
"valueType": "any",
"label": "core.module.Variable",
"value": [],
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
},
{
"key": "questionGuide",
"valueType": "boolean",
"type": "switch",
"label": "",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
},
{
"key": "tts",
"type": "hidden",
"valueType": "any",
"label": "",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
}
],
"outputs": []
},
{
"moduleId": "userChatInput",
"name": "core.module.template.Chat entrance",
"flowType": "questionInput",
"position": {
"x": 597.8136543694757,
"y": 1709.9244174501202
},
"inputs": [
{
"key": "userChatInput",
"type": "systemInput",
"valueType": "string",
"label": "core.module.input.label.user question",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
}
],
"outputs": [
{
"key": "userChatInput",
"label": "core.module.input.label.user question",
"type": "source",
"valueType": "string",
"targets": [
{
"moduleId": "mqgfub",
"key": "prompt"
}
]
}
]
},
{
"moduleId": "mqgfub",
"name": "Dalle3绘图",
"flowType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1071.8956245626034,
"y": 1236.690825267034
},
"inputs": [
{
"key": "switch",
"type": "target",
"label": "core.module.input.label.switch",
"description": "core.module.input.description.Trigger",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{
"key": "system_httpMethod",
"type": "custom",
"valueType": "string",
"label": "",
"value": "POST",
"required": true,
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
},
{
"key": "system_httpReqUrl",
"type": "hidden",
"valueType": "string",
"label": "",
"description": "core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": "https://api.openai.com/v1/images/generations",
"connected": false
},
{
"key": "system_httpHeader",
"type": "custom",
"valueType": "any",
"value": [
{
"key": "Authorization",
"type": "string",
"value": "sk-xxx"
}
],
"label": "",
"description": "core.module.input.description.Http Request Header",
"placeholder": "core.module.input.description.Http Request Header",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
},
{
"key": "system_httpParams",
"type": "hidden",
"valueType": "any",
"value": [],
"label": "",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
},
{
"key": "system_httpJsonBody",
"type": "hidden",
"valueType": "any",
"value": "{\r\n \"model\": \"dall-e-3\",\r\n \"prompt\": \"{{prompt}}\",\r\n \"n\": 1,\r\n \"size\": \"1024x1024\"\r\n }",
"label": "",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false
},
{
"key": "DYNAMIC_INPUT_KEY",
"type": "target",
"valueType": "any",
"label": "core.module.inputType.dynamicTargetInput",
"description": "core.module.input.description.dynamic input",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": true,
"hideInApp": true,
"connected": false
},
{
"key": "prompt",
"valueType": "string",
"label": "prompt",
"type": "target",
"required": true,
"description": "",
"edit": true,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true
},
"connected": true
},
{
"key": "system_addInputParam",
"type": "addInputParam",
"valueType": "any",
"label": "",
"required": false,
"showTargetInApp": false,
"showTargetInPlugin": false,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true
},
"defaultEditField": {
"label": "",
"key": "",
"description": "",
"inputType": "target",
"inputs": [
{
"key": "welcomeText",
"renderTypeList": [
"hidden"
],
"valueType": "string",
"required": true
"label": "core.app.Welcome Text",
"value": ""
},
"connected": false
}
],
"outputs": [
{
"key": "finish",
"label": "core.module.output.label.running done",
"description": "core.module.output.description.running done",
"valueType": "boolean",
"type": "source",
"targets": []
},
{
"key": "system_addOutputParam",
"type": "addOutputParam",
"valueType": "any",
"label": "",
"targets": [],
"editField": {
"key": true,
"name": true,
"description": true,
"dataType": true
{
"key": "variables",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "core.app.Chat Variable",
"value": []
},
"defaultEditField": {
{
"key": "questionGuide",
"valueType": "boolean",
"renderTypeList": [
"hidden"
],
"label": "core.app.Question Guide",
"value": false
},
{
"key": "tts",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "",
"key": "",
"description": "",
"outputType": "source",
"valueType": "string"
"value": {
"type": "web"
}
},
{
"key": "whisper",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "",
"value": {
"open": false,
"autoSend": false,
"autoTTSResponse": false
}
},
{
"key": "scheduleTrigger",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "",
"value": null
}
},
{
"type": "source",
"valueType": "string",
"key": "data[0].url",
"label": "url",
"description": "",
"edit": true,
"editField": {
"key": true,
"name": true,
"description": true,
"dataType": true
},
"targets": [
{
"moduleId": "nl6mr9",
"key": "url"
}
]
}
]
},
{
"moduleId": "xy76o2",
"name": "core.module.template.Assigned reply",
"flowType": "answerNode",
"position": {
"x": 2204.027057268489,
"y": 1256.786345213533
],
"outputs": []
},
"inputs": [
{
"key": "switch",
"type": "target",
"label": "core.module.input.label.switch",
"description": "core.module.input.description.Trigger",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
{
"nodeId": "448745",
"name": "流程开始",
"intro": "",
"avatar": "/imgs/workflow/userChatInput.svg",
"flowNodeType": "workflowStart",
"position": {
"x": 532.1275542407774,
"y": 46.03775600322817
},
{
"key": "text",
"type": "textarea",
"valueType": "any",
"label": "core.module.input.label.Response content",
"description": "core.module.input.description.Response content",
"placeholder": "core.module.input.description.Response content",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": true
}
],
"outputs": [
{
"key": "finish",
"label": "core.module.output.label.running done",
"description": "core.module.output.description.running done",
"valueType": "boolean",
"type": "source",
"targets": []
}
]
},
{
"moduleId": "nl6mr9",
"name": "core.module.template.textEditor",
"flowType": "pluginModule",
"showStatus": false,
"position": {
"x": 1690.1826860670342,
"y": 1262.3858719789062
},
"inputs": [
{
"key": "pluginId",
"type": "hidden",
"label": "",
"value": "community-textEditor",
"valueType": "string",
"connected": false,
"showTargetInApp": false,
"showTargetInPlugin": false
},
{
"key": "switch",
"type": "target",
"label": "core.module.input.label.switch",
"description": "core.module.input.description.Trigger",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{
"key": "textarea",
"valueType": "string",
"label": "文本内容",
"type": "textarea",
"required": true,
"description": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。",
"edit": false,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true,
"inputType": true
},
"connected": false,
"placeholder": "可以通过 {{key}} 的方式引用传入的变量。变量仅支持字符串或数字。",
"value": "![]({{url}})"
},
{
"key": "url",
"valueType": "string",
"label": "url",
"type": "target",
"required": true,
"description": "",
"edit": true,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true,
"inputType": false
},
"connected": true
},
{
"key": "DYNAMIC_INPUT_KEY",
"valueType": "any",
"label": "需要加工的输入",
"type": "addInputParam",
"required": false,
"description": "可动态的添加字符串类型变量,在文本编辑中通过 {{key}} 使用变量。非字符串类型,会自动转成字符串类型。",
"edit": false,
"editField": {
"key": true,
"name": true,
"description": true,
"required": true,
"dataType": true,
"inputType": false
},
"defaultEditField": {
"label": "",
"key": "",
"description": "",
"inputType": "target",
"inputs": [
{
"key": "userChatInput",
"renderTypeList": [
"reference",
"textarea"
],
"valueType": "string",
"label": "用户问题",
"required": true,
"toolDescription": "用户问题"
}
],
"outputs": [
{
"id": "userChatInput",
"key": "userChatInput",
"label": "core.module.input.label.user question",
"valueType": "string",
"type": "static"
}
]
},
{
"nodeId": "tMyUnRL5jIrC",
"name": "HTTP 请求",
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
"avatar": "/imgs/workflow/http.png",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 921.2377506442713,
"y": -483.94114977914256
},
"inputs": [
{
"key": "system_addInputParam",
"renderTypeList": [
"addInputParam"
],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "core.module.input.description.HTTP Dynamic Input",
"editField": {
"key": true,
"valueType": true
}
},
{
"key": "prompt",
"valueType": "string",
"label": "prompt",
"renderTypeList": [
"reference"
],
"description": "",
"canEdit": true,
"editField": {
"key": true,
"valueType": true
},
"value": [
"448745",
"userChatInput"
]
},
{
"key": "system_httpMethod",
"renderTypeList": [
"custom"
],
"valueType": "string",
"label": "",
"value": "POST",
"required": true
},
"connected": false
}
],
"outputs": [
{
"key": "text",
"valueType": "string",
"label": "core.module.output.label.text",
"type": "source",
"edit": false,
"targets": [
{
"moduleId": "xy76o2",
"key": "text"
{
"key": "system_httpReqUrl",
"renderTypeList": [
"hidden"
],
"valueType": "string",
"label": "",
"description": "core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"value": "https://api.openai.com/v1/images/generations"
},
{
"key": "system_httpHeader",
"renderTypeList": [
"custom"
],
"valueType": "any",
"value": [
{
"key": "Authorization",
"type": "string",
"value": "Bearer sk-zsfBsxEU3ApSFGYxF4CdB97e9556412588421823371b9f7b"
}
],
"label": "",
"description": "core.module.input.description.Http Request Header",
"placeholder": "core.module.input.description.Http Request Header",
"required": false
},
{
"key": "system_httpParams",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"value": [],
"label": "",
"required": false
},
{
"key": "system_httpJsonBody",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"value": "{\n \"model\": \"dall-e-3\",\n \"prompt\": \"{{prompt}}\",\n \"n\": 1,\n \"size\": \"1024x1024\"\n}",
"label": "",
"required": false
}
],
"outputs": [
{
"id": "system_addOutputParam",
"key": "system_addOutputParam",
"type": "dynamic",
"valueType": "dynamic",
"label": "",
"editField": {
"key": true,
"valueType": true
}
]
}
]
}
]
```
},
{
"id": "httpRawResponse",
"key": "httpRawResponse",
"label": "原始响应",
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
"valueType": "any",
"type": "static"
},
{
"id": "DeKGGioBwaMf",
"type": "dynamic",
"key": "data[0].url",
"valueType": "string",
"label": "data[0].url"
}
]
},
{
"nodeId": "CO3POL8svbbi",
"name": "文本加工",
"intro": "可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。",
"avatar": "/imgs/workflow/textEditor.svg",
"flowNodeType": "pluginModule",
"showStatus": false,
"position": {
"x": 1417.5940290051137,
"y": -478.81889618104356
},
"inputs": [
{
"key": "system_addInputParam",
"valueType": "dynamic",
"label": "动态外部数据",
"renderTypeList": [
"addInputParam"
],
"required": false,
"description": "",
"canEdit": false,
"value": "",
"editField": {
"key": true
},
"dynamicParamDefaultValue": {
"inputType": "reference",
"valueType": "string",
"required": true
}
},
{
"key": "url",
"valueType": "string",
"label": "url",
"renderTypeList": [
"reference"
],
"required": true,
"description": "",
"canEdit": true,
"editField": {
"key": true
},
"value": [
"tMyUnRL5jIrC",
"DeKGGioBwaMf"
]
},
{
"key": "文本",
"valueType": "string",
"label": "文本",
"renderTypeList": [
"textarea"
],
"required": true,
"description": "",
"canEdit": false,
"value": "![]({{url}})",
"editField": {
"key": true
},
"maxLength": "",
"dynamicParamDefaultValue": {
"inputType": "reference",
"valueType": "string",
"required": true
}
}
],
"outputs": [
{
"id": "text",
"type": "static",
"key": "text",
"valueType": "string",
"label": "text",
"description": ""
}
],
"pluginId": "community-textEditor"
},
{
"nodeId": "7mapnCgHfKW6",
"name": "指定回复",
"intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
"avatar": "/imgs/workflow/reply.png",
"flowNodeType": "answerNode",
"position": {
"x": 1922.5628399315042,
"y": -471.67391598231796
},
"inputs": [
{
"key": "text",
"renderTypeList": [
"textarea",
"reference"
],
"valueType": "string",
"label": "core.module.input.label.Response content",
"description": "core.module.input.description.Response content",
"placeholder": "core.module.input.description.Response content",
"selectedTypeIndex": 1,
"value": [
"CO3POL8svbbi",
"text"
]
}
],
"outputs": []
}
],
"edges": [
{
"source": "448745",
"target": "tMyUnRL5jIrC",
"sourceHandle": "448745-source-right",
"targetHandle": "tMyUnRL5jIrC-target-left"
},
{
"source": "tMyUnRL5jIrC",
"target": "CO3POL8svbbi",
"sourceHandle": "tMyUnRL5jIrC-source-right",
"targetHandle": "CO3POL8svbbi-target-left"
},
{
"source": "CO3POL8svbbi",
"target": "7mapnCgHfKW6",
"sourceHandle": "CO3POL8svbbi-source-right",
"targetHandle": "7mapnCgHfKW6-target-left"
}
]
}
```
{{% /details %}}

View File

@ -11,7 +11,7 @@ weight: 404
| | |
| --------------------- | --------------------- |
| ![](/imgs/feishuwebhook1.png) | ![](/imgs/feishuwebhook2.webp) |
| ![](/imgs/feishuwebhook1.webp) | ![](/imgs/feishuwebhook2.webp) |
## 1. 准备飞书机器人
@ -23,14 +23,16 @@ weight: 404
复制下面配置点击「高级编排」右上角的导入按键导入该配置导入后将飞书提供的接口地址复制到「HTTP 模块」。
{{% details title="编排配置" closed="true" %}}
```json
[
{
"moduleId": "userGuide",
"nodeId": "userGuide",
"name": "core.module.template.App system setting",
"intro": "core.app.tip.userGuideTip",
"avatar": "/imgs/module/userGuide.png",
"flowType": "userGuide",
"avatar": "/imgs/workflow/userGuide.png",
"flowNodeType": "userGuide",
"position": {
"x": -92.26884681344463,
"y": 710.9354029649536
@ -82,11 +84,11 @@ weight: 404
"outputs": []
},
{
"moduleId": "userChatInput",
"nodeId": "userChatInput",
"name": "core.module.template.Chat entrance",
"intro": "当用户发送一个内容后,流程将会从这个模块开始执行。",
"avatar": "/imgs/module/userChatInput.svg",
"flowType": "questionInput",
"avatar": "/imgs/workflow/userChatInput.svg",
"flowNodeType": "questionInput",
"position": {
"x": 241.60980819261408,
"y": 1330.9528898009685
@ -110,7 +112,7 @@ weight: 404
"valueType": "string",
"targets": [
{
"moduleId": "n84rvg",
"nodeId": "n84rvg",
"key": "userChatInput"
}
]
@ -118,27 +120,17 @@ weight: 404
]
},
{
"moduleId": "n84rvg",
"nodeId": "n84rvg",
"name": "工具调用(实验)",
"intro": "通过AI模型自动选择一个或多个功能块进行调用也可以对插件进行调用。",
"avatar": "/imgs/module/tool.svg",
"flowType": "tools",
"avatar": "/imgs/workflow/tool.svg",
"flowNodeType": "tools",
"showStatus": true,
"position": {
"x": 809.4264785615641,
"y": 873.3971746859133
},
"inputs": [
{
"key": "switch",
"type": "triggerAndFinish",
"label": "",
"description": "core.module.input.description.Trigger",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{
"key": "model",
"type": "settingLLMModel",
@ -227,7 +219,7 @@ weight: 404
"type": "hidden",
"targets": [
{
"moduleId": "3mbu91",
"nodeId": "3mbu91",
"key": "selectedTools"
}
]
@ -243,27 +235,18 @@ weight: 404
]
},
{
"moduleId": "3mbu91",
"nodeId": "3mbu91",
"name": "HTTP 请求",
"intro": "调用飞书webhook发送一个通知",
"avatar": "/imgs/module/http.png",
"flowType": "httpRequest468",
"avatar": "/imgs/workflow/http.png",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1483.6437630977423,
"y": 798.9716928475544
},
"inputs": [
{
"key": "switch",
"type": "triggerAndFinish",
"label": "",
"description": "core.module.input.description.Trigger",
"valueType": "any",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false
},
{
"key": "system_httpMethod",
"type": "custom",
@ -327,7 +310,7 @@ weight: 404
"key": "DYNAMIC_INPUT_KEY",
"type": "target",
"valueType": "any",
"label": "core.module.inputType.dynamicTargetInput",
"label": "core.workflow.inputType.dynamicTargetInput",
"description": "core.module.input.description.dynamic input",
"required": false,
"showTargetInApp": false,
@ -376,11 +359,11 @@ weight: 404
"type": "source",
"targets": [
{
"moduleId": "rzx4mj",
"nodeId": "rzx4mj",
"key": "switch"
},
{
"moduleId": "psdhs1",
"nodeId": "psdhs1",
"key": "switch"
}
]
@ -424,11 +407,11 @@ weight: 404
]
},
{
"moduleId": "rzx4mj",
"nodeId": "rzx4mj",
"name": "工具调用终止",
"intro": "该模块需配置工具调用使用。当该模块被执行时本次工具调用将会强制结束并且不再调用AI针对工具调用结果回答问题。",
"avatar": "/imgs/module/toolStop.svg",
"flowType": "stopTool",
"avatar": "/imgs/workflow/toolStop.svg",
"flowNodeType": "stopTool",
"position": {
"x": 2145.5070710160267,
"y": 1306.3581817783079
@ -448,11 +431,11 @@ weight: 404
"outputs": []
},
{
"moduleId": "psdhs1",
"nodeId": "psdhs1",
"name": "指定回复",
"intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
"avatar": "/imgs/module/reply.png",
"flowType": "answerNode",
"avatar": "/imgs/workflow/reply.png",
"flowNodeType": "answerNode",
"position": {
"x": 2117.0429459850598,
"y": 1658.4125434513746
@ -495,6 +478,9 @@ weight: 404
]
```
{{% /details %}}
## 3. 流程说明
1. 为工具调用挂载一个HTTP模块功能描述写上调用飞书webhook发送一个通知。

View File

@ -7,9 +7,9 @@ toc: true
weight: 401
---
![](/imgs/demo-fix-evidence1.png)
![](/imgs/demo-fix-evidence1.jpg)
![](/imgs/demo-fix-evidence2.png)
![](/imgs/demo-fix-evidence2.jpg)
如上图,可以通过指定回复编排一个固定的开头和结尾内容。
@ -21,318 +21,411 @@ weight: 401
{{% details title="编排配置" closed="true" %}}
```json
[
{
"moduleId": "userChatInput",
"name": "用户问题(对话入口)",
"flowType": "questionInput",
"position": {
"x": 59.03170043915989,
"y": 1604.8595605938747
{
"nodes": [
{
"nodeId": "7z5g5h",
"name": "流程开始",
"intro": "",
"avatar": "/imgs/workflow/userChatInput.svg",
"flowNodeType": "workflowStart",
"position": {
"x": -269.50851681351924,
"y": 1657.6123698022448
},
"inputs": [
{
"key": "userChatInput",
"renderTypeList": [
"reference",
"textarea"
],
"valueType": "string",
"label": "问题输入",
"required": true,
"toolDescription": "用户问题",
"type": "systemInput",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0,
"value": [
"7z5g5h",
"userChatInput"
]
}
],
"outputs": [
{
"id": "userChatInput",
"type": "static",
"key": "userChatInput",
"valueType": "string",
"label": "core.module.input.label.user question"
}
]
},
"inputs": [
{
"key": "userChatInput",
"type": "systemInput",
"label": "用户问题",
"connected": true
}
],
"outputs": [
{
"key": "userChatInput",
"label": "用户问题",
"type": "source",
"valueType": "string",
"targets": [
{
"moduleId": "chatModule",
"key": "userChatInput"
},
{
"moduleId": "ymqh0t",
"key": "switch"
}
]
}
]
},
{
"moduleId": "history",
"name": "聊天记录",
"flowType": "historyNode",
"position": {
"x": 38.19233923987295,
"y": 1184.4581738905642
{
"nodeId": "nlfwkc",
"name": "AI 对话",
"intro": "AI 大模型对话",
"avatar": "/imgs/workflow/AI.png",
"flowNodeType": "chatNode",
"showStatus": true,
"position": {
"x": 907.2058332478431,
"y": 1348.9992737142143
},
"inputs": [
{
"key": "model",
"renderTypeList": [
"settingLLMModel",
"reference"
],
"label": "core.module.input.label.aiModel",
"valueType": "string",
"type": "selectLLMModel",
"required": true,
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": "gpt-3.5-turbo",
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "temperature",
"renderTypeList": [
"hidden"
],
"label": "",
"value": 0,
"valueType": "number",
"min": 0,
"max": 10,
"step": 1,
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "maxToken",
"renderTypeList": [
"hidden"
],
"label": "",
"value": 2000,
"valueType": "number",
"min": 100,
"max": 4000,
"step": 50,
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "isResponseAnswerText",
"renderTypeList": [
"hidden"
],
"label": "",
"value": true,
"valueType": "boolean",
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "quoteTemplate",
"renderTypeList": [
"hidden"
],
"label": "",
"valueType": "string",
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "quotePrompt",
"renderTypeList": [
"hidden"
],
"label": "",
"valueType": "string",
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "systemPrompt",
"renderTypeList": [
"textarea",
"reference"
],
"max": 300,
"valueType": "string",
"label": "core.ai.Prompt",
"description": "core.app.tip.chatNodeSystemPromptTip",
"placeholder": "core.app.tip.chatNodeSystemPromptTip",
"type": "textarea",
"showTargetInApp": true,
"showTargetInPlugin": true,
"value": "",
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "history",
"renderTypeList": [
"numberInput",
"reference"
],
"valueType": "chatHistory",
"label": "core.module.input.label.chat history",
"required": true,
"min": 0,
"max": 30,
"value": 6,
"type": "numberInput",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "userChatInput",
"renderTypeList": [
"reference",
"textarea"
],
"valueType": "string",
"label": "问题输入",
"required": true,
"toolDescription": "用户问题",
"type": "custom",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": true,
"selectedTypeIndex": 0,
"value": [
"7z5g5h",
"userChatInput"
]
},
{
"key": "quoteQA",
"renderTypeList": [
"settingDatasetQuotePrompt"
],
"label": "",
"debugLabel": "知识库引用",
"description": "core.module.Dataset quote.Input description",
"valueType": "datasetQuote",
"type": "target",
"showTargetInApp": true,
"showTargetInPlugin": true,
"connected": true,
"selectedTypeIndex": 0,
"value": [
"fljhzy",
"quoteQA"
]
}
],
"outputs": [
{
"id": "answerText",
"type": "static",
"key": "answerText",
"valueType": "string",
"label": "core.module.output.label.Ai response content",
"description": "core.module.output.description.Ai response content"
},
{
"id": "history",
"type": "static",
"key": "history",
"valueType": "chatHistory",
"label": "core.module.output.label.New context",
"description": "core.module.output.description.New context"
}
]
},
"inputs": [
{
"key": "maxContext",
"type": "numberInput",
"label": "最长记录数",
"value": 6,
"min": 0,
"max": 50,
"connected": true
{
"nodeId": "q9equb",
"name": "core.module.template.App system setting",
"intro": "可以配置应用的系统参数。",
"avatar": "/imgs/workflow/userGuide.png",
"flowNodeType": "userGuide",
"position": {
"x": -275.92529567956024,
"y": 1094.1001488133452
},
{
"key": "history",
"type": "hidden",
"label": "聊天记录",
"connected": true
}
],
"outputs": [
{
"key": "history",
"label": "聊天记录",
"valueType": "chatHistory",
"type": "source",
"targets": [
{
"moduleId": "chatModule",
"key": "history"
}
]
}
]
},
{
"moduleId": "chatModule",
"name": "AI 对话",
"flowType": "chatNode",
"showStatus": true,
"position": {
"x": 943.1225685246793,
"y": 891.3094521573212
"inputs": [
{
"key": "welcomeText",
"renderTypeList": [
"hidden"
],
"valueType": "string",
"label": "core.app.Welcome Text",
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"value": "你好,我是电影《星际穿越》 AI 助手,有什么可以帮助你的?\n[导演是谁]\n[剧情介绍]\n[票房分析]",
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "variables",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "core.module.Variable",
"value": [],
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "questionGuide",
"valueType": "boolean",
"renderTypeList": [
"hidden"
],
"label": "",
"type": "switch",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "tts",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "",
"type": "hidden",
"showTargetInApp": false,
"showTargetInPlugin": false,
"connected": false,
"selectedTypeIndex": 0
},
{
"key": "whisper",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": ""
},
{
"key": "scheduleTrigger",
"renderTypeList": [
"hidden"
],
"valueType": "any",
"label": "",
"value": null
}
],
"outputs": []
},
"inputs": [
{
"key": "model",
"type": "custom",
"label": "对话模型",
"value": "gpt-3.5-turbo",
"list": [
{
"label": "FastGPT-4k",
"value": "gpt-3.5-turbo"
},
{
"label": "FastGPT-16k",
"value": "gpt-3.5-turbo-16k"
},
{
"label": "文心一言",
"value": "ERNIE-Bot"
},
{
"label": "FastGPT-Plus",
"value": "gpt-4"
},
{
"label": "glm2(演示娱乐)",
"value": "glm2-6b"
}
],
"connected": true
{
"nodeId": "tc90wz",
"name": "指定回复",
"intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
"avatar": "/imgs/workflow/reply.png",
"flowNodeType": "answerNode",
"position": {
"x": 159.49274056478237,
"y": 1621.4635230667668
},
{
"key": "temperature",
"type": "slider",
"label": "温度",
"value": 0,
"min": 0,
"max": 10,
"step": 1,
"markList": [
{
"label": "严谨",
"value": 0
},
{
"label": "发散",
"value": 10
}
],
"connected": true
},
{
"key": "maxToken",
"type": "custom",
"label": "回复上限",
"value": 2000,
"min": 100,
"max": 4000,
"step": 50,
"markList": [
{
"label": "100",
"value": 100
},
{
"label": "4000",
"value": 4000
}
],
"connected": true
},
{
"key": "systemPrompt",
"type": "textarea",
"label": "系统提示词",
"max": 300,
"valueType": "string",
"description": "模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}",
"placeholder": "模型固定的引导词,通过调整该内容,可以引导模型聊天方向。该内容会被固定在上下文的开头。可使用变量,例如 {{language}}",
"value": "",
"connected": true
},
{
"key": "limitPrompt",
"type": "textarea",
"valueType": "string",
"label": "限定词",
"max": 500,
"description": "限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。不建议内容太长,会影响上下文,可使用变量,例如 {{language}}。可在文档中找到对应的限定例子",
"placeholder": "限定模型对话范围,会被放置在本次提问前,拥有强引导和限定性。不建议内容太长,会影响上下文,可使用变量,例如 {{language}}。可在文档中找到对应的限定例子",
"value": "",
"connected": true
},
{
"key": "switch",
"type": "target",
"label": "触发器",
"valueType": "any",
"connected": true
},
{
"key": "quoteQA",
"type": "target",
"label": "引用内容",
"description": "对象数组格式,结构:\n [{q:'问题',a:'回答'}]",
"valueType": "datasetQuote",
"connected": false
},
{
"key": "history",
"type": "target",
"label": "聊天记录",
"valueType": "chatHistory",
"connected": true
},
{
"key": "userChatInput",
"type": "target",
"label": "用户问题",
"required": true,
"valueType": "string",
"connected": true
}
],
"outputs": [
{
"key": "answerText",
"label": "AI回复",
"description": "将在 stream 回复完毕后触发",
"valueType": "string",
"type": "source",
"targets": []
},
{
"key": "finish",
"label": "回复结束",
"description": "AI 回复完成后触发",
"valueType": "boolean",
"type": "source",
"targets": [
{
"moduleId": "ojeopv",
"key": "switch"
}
]
}
]
},
{
"moduleId": "ymqh0t",
"name": "指定回复",
"flowType": "answerNode",
"position": {
"x": 435.27459673941917,
"y": 1081.9477378716076
"inputs": [
{
"key": "text",
"renderTypeList": [
"textarea",
"reference"
],
"valueType": "any",
"label": "core.module.input.label.Response content",
"description": "core.module.input.description.Response content",
"placeholder": "core.module.input.description.Response content",
"type": "textarea",
"showTargetInApp": true,
"showTargetInPlugin": true,
"value": "这是开头\\n",
"connected": false,
"selectedTypeIndex": 0
}
],
"outputs": []
},
"inputs": [
{
"key": "switch",
"type": "target",
"label": "触发器",
"valueType": "any",
"connected": true
{
"nodeId": "U5T3dMVY4wj7",
"name": "指定回复",
"intro": "该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。",
"avatar": "/imgs/workflow/reply.png",
"flowNodeType": "answerNode",
"position": {
"x": 1467.0625486167608,
"y": 1597.346243737531
},
{
"key": "text",
"type": "textarea",
"valueType": "string",
"value": "这是AI作答\n\n---\n\n",
"label": "回复的内容",
"description": "可以使用 \\n 来实现换行。也可以通过外部模块输入实现回复,外部模块输入时会覆盖当前填写的内容",
"connected": true
}
],
"outputs": [
{
"key": "finish",
"label": "回复结束",
"description": "回复完成后触发",
"valueType": "boolean",
"type": "source",
"targets": [
{
"moduleId": "chatModule",
"key": "switch"
}
]
}
]
},
{
"moduleId": "ojeopv",
"name": "指定回复",
"flowType": "answerNode",
"position": {
"x": 1573.4540253108476,
"y": 1551.9808807287498
"inputs": [
{
"key": "text",
"renderTypeList": [
"textarea",
"reference"
],
"valueType": "string",
"label": "core.module.input.label.Response content",
"description": "core.module.input.description.Response content",
"placeholder": "core.module.input.description.Response content",
"value": "这是结尾"
}
],
"outputs": []
}
],
"edges": [
{
"source": "7z5g5h",
"target": "tc90wz",
"sourceHandle": "7z5g5h-source-right",
"targetHandle": "tc90wz-target-left"
},
"inputs": [
{
"key": "switch",
"type": "target",
"label": "触发器",
"valueType": "any",
"connected": true
},
{
"key": "text",
"type": "textarea",
"valueType": "string",
"value": "\\n\n---\n\n这是固定的结尾",
"label": "回复的内容",
"description": "可以使用 \\n 来实现换行。也可以通过外部模块输入实现回复,外部模块输入时会覆盖当前填写的内容",
"connected": true
}
],
"outputs": [
{
"key": "finish",
"label": "回复结束",
"description": "回复完成后触发",
"valueType": "boolean",
"type": "source",
"targets": []
}
]
}
]
{
"source": "tc90wz",
"target": "nlfwkc",
"sourceHandle": "tc90wz-source-right",
"targetHandle": "nlfwkc-target-left"
},
{
"source": "nlfwkc",
"target": "U5T3dMVY4wj7",
"sourceHandle": "nlfwkc-source-right",
"targetHandle": "U5T3dMVY4wj7-target-left"
}
]
}
```
{{% /details %}}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -53,4 +53,4 @@ export const uniqueImageTypeList = Object.entries(mongoImageTypeMap)
export const FolderIcon = 'file/fill/folder';
export const FolderImgUrl = '/imgs/files/folder.svg';
export const HttpImgUrl = '/imgs/module/http.png';
export const HttpImgUrl = '/imgs/workflow/http.png';

View File

@ -1,152 +0,0 @@
/* Only the token of gpt-3.5-turbo is used */
import type { ChatItemType } from '../../../core/chat/type';
import { Tiktoken } from 'js-tiktoken/lite';
import { chats2GPTMessages } from '../../../core/chat/adapt';
import encodingJson from './cl100k_base.json';
import {
ChatCompletionMessageParam,
ChatCompletionContentPart,
ChatCompletionCreateParams,
ChatCompletionTool
} from '../../../core/ai/type';
import { ChatCompletionRequestMessageRoleEnum } from '../../../core/ai/constants';
/* init tikToken obj */
export function getTikTokenEnc() {
if (typeof window !== 'undefined' && window.TikToken) {
return window.TikToken;
}
if (typeof global !== 'undefined' && global.TikToken) {
return global.TikToken;
}
const enc = new Tiktoken(encodingJson);
if (typeof window !== 'undefined') {
window.TikToken = enc;
}
if (typeof global !== 'undefined') {
global.TikToken = enc;
}
return enc;
}
/* count one prompt tokens */
export function countPromptTokens(
prompt: string | ChatCompletionContentPart[] | null | undefined = '',
role: '' | `${ChatCompletionRequestMessageRoleEnum}` = ''
) {
const enc = getTikTokenEnc();
const promptText = (() => {
if (!prompt) return '';
if (typeof prompt === 'string') return prompt;
let promptText = '';
prompt.forEach((item) => {
if (item.type === 'text') {
promptText += item.text;
} else if (item.type === 'image_url') {
promptText += item.image_url.url;
}
});
return promptText;
})();
const text = `${role}\n${promptText}`.trim();
try {
const encodeText = enc.encode(text);
const supplementaryToken = role ? 4 : 0;
return encodeText.length + supplementaryToken;
} catch (error) {
return text.length;
}
}
export const countToolsTokens = (
tools?: ChatCompletionTool[] | ChatCompletionCreateParams.Function[]
) => {
if (!tools || tools.length === 0) return 0;
const enc = getTikTokenEnc();
const toolText = tools
? JSON.stringify(tools)
.replace('"', '')
.replace('\n', '')
.replace(/( ){2,}/g, ' ')
: '';
return enc.encode(toolText).length;
};
/* count messages tokens */
export const countMessagesTokens = (messages: ChatItemType[]) => {
const adaptMessages = chats2GPTMessages({ messages, reserveId: true });
return countGptMessagesTokens(adaptMessages);
};
export const countGptMessagesTokens = (
messages: ChatCompletionMessageParam[],
tools?: ChatCompletionTool[],
functionCall?: ChatCompletionCreateParams.Function[]
) =>
messages.reduce((sum, item) => {
// Evaluates the text of toolcall and functioncall
const functionCallPrompt = (() => {
let prompt = '';
if (item.role === ChatCompletionRequestMessageRoleEnum.Assistant) {
const toolCalls = item.tool_calls;
prompt +=
toolCalls
?.map((item) => `${item?.function?.name} ${item?.function?.arguments}`.trim())
?.join('') || '';
const functionCall = item.function_call;
prompt += `${functionCall?.name} ${functionCall?.arguments}`.trim();
}
return prompt;
})();
const contentPrompt = (() => {
if (!item.content) return '';
if (typeof item.content === 'string') return item.content;
return item.content
.map((item) => {
if (item.type === 'text') return item.text;
return '';
})
.join('');
})();
return sum + countPromptTokens(`${contentPrompt}${functionCallPrompt}`, item.role);
}, 0) +
countToolsTokens(tools) +
countToolsTokens(functionCall);
/* slice messages from top to bottom by maxTokens */
export function sliceMessagesTB({
messages,
maxTokens
}: {
messages: ChatItemType[];
maxTokens: number;
}) {
const adaptMessages = chats2GPTMessages({ messages, reserveId: true });
let reduceTokens = maxTokens;
let result: ChatItemType[] = [];
for (let i = 0; i < adaptMessages.length; i++) {
const item = adaptMessages[i];
const tokens = countPromptTokens(item.content, item.role);
reduceTokens -= tokens;
if (reduceTokens > 0) {
result.push(messages[i]);
} else {
break;
}
}
return result.length === 0 && messages[0] ? [messages[0]] : result;
}

View File

@ -1,5 +0,0 @@
import type { Tiktoken } from 'js-tiktoken';
declare global {
var TikToken: Tiktoken;
}

View File

@ -1,5 +1,36 @@
import dayjs from 'dayjs';
import cronParser from 'cron-parser';
export const formatTime2YMDHM = (time?: Date) =>
time ? dayjs(time).format('YYYY-MM-DD HH:mm') : '';
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');
}
};

View File

@ -28,7 +28,9 @@ export const simpleText = (text = '') => {
/*
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) {
const val = obj[key];
if (!['string', 'number'].includes(typeof val)) continue;

View File

@ -76,5 +76,5 @@ export const getSystemTime = (timeZone: string) => {
const timezoneDiff = getTimezoneOffset(timeZone);
const now = Date.now();
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');
};

View File

@ -41,20 +41,22 @@ export const Prompt_ExtractJson = `你可以从 <对话记录></对话记录>
</对话记录>
`;
export const Prompt_CQJson = `我会给你几个问题类型请参考背景知识可能为空和对话记录判断我“本次问题”的类型并返回一个问题“类型ID”:
<问题类型>
export const Prompt_CQJson = `请帮我执行一个“问题分类”任务,将问题分类为以下几种类型之一:
"""
{{typeList}}
</问题类型>
"""
<背景知识>
##
{{systemPrompt}}
</背景知识>
<对话记录>
##
{{history}}
</对话记录>
Human"{{question}}"
##
"问题"ID
"{{question}}"
ID=
`;

View File

@ -7,6 +7,7 @@ export type CreateAppParams = {
avatar?: string;
type?: `${AppTypeEnum}`;
modules: AppSchema['modules'];
edges?: AppSchema['edges'];
};
export interface AppUpdateParams {
@ -15,6 +16,7 @@ export interface AppUpdateParams {
avatar?: string;
intro?: string;
modules?: AppSchema['modules'];
edges?: AppSchema['edges'];
permission?: AppSchema['permission'];
teamTags?: AppSchema['teamTags'];
}

View File

@ -1,23 +1,30 @@
import type { FlowNodeTemplateType, ModuleItemType } from '../module/type.d';
import type { FlowNodeTemplateType, StoreNodeItemType } from '../workflow/type';
import { AppTypeEnum } from './constants';
import { PermissionTypeEnum } from '../../support/permission/constant';
import type { DatasetModuleProps } from '../module/node/type.d';
import { VariableInputEnum } from '../module/constants';
import { SelectedDatasetType } from '../module/api';
import { VariableInputEnum } from '../workflow/constants';
import { SelectedDatasetType } from '../workflow/api';
import { DatasetSearchModeEnum } from '../dataset/constants';
import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
import { StoreEdgeItemType } from 'core/workflow/type/edge';
export interface AppSchema {
_id: string;
userId: string;
teamId: string;
tmbId: string;
name: string;
type: `${AppTypeEnum}`;
version?: 'v1' | 'v2';
avatar: string;
intro: string;
updateTime: number;
modules: ModuleItemType[];
modules: StoreNodeItemType[];
edges: StoreEdgeItemType[];
// App system config
scheduledTriggerConfig?: AppScheduledTriggerConfigType | null;
scheduledTriggerNextTime?: Date;
permission: `${PermissionTypeEnum}`;
inited?: boolean;
teamTags: string[];
@ -79,10 +86,19 @@ export type AppSimpleEditFormType = {
speed?: number | undefined;
};
whisper: AppWhisperConfigType;
scheduleTrigger: AppScheduledTriggerConfigType | null;
};
};
/* app function config */
export type SettingAIDataType = {
model: string;
temperature: number;
maxToken: number;
isResponseAnswerText?: boolean;
maxHistories?: number;
};
// variable
export type VariableItemType = {
id: string;
@ -106,3 +122,9 @@ export type AppWhisperConfigType = {
autoSend: boolean;
autoTTSResponse: boolean;
};
// interval timer
export type AppScheduledTriggerConfigType = {
cronString: string;
timezone: string;
defaultPrompt: string;
};

View File

@ -1,13 +1,9 @@
import type { AppSimpleEditFormType } from '../app/type';
import { FlowNodeTypeEnum } from '../module/node/constant';
import {
ModuleOutputKeyEnum,
ModuleInputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../module/constants';
import type { FlowNodeInputItemType } from '../module/node/type.d';
import { getGuideModule, splitGuideModule } from '../module/utils';
import { ModuleItemType } from '../module/type.d';
import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { NodeInputKeyEnum, FlowNodeTemplateTypeEnum } from '../workflow/constants';
import type { FlowNodeInputItemType } from '../workflow/type/io.d';
import { getGuideModule, splitGuideModule } from '../workflow/utils';
import { StoreNodeItemType } from '../workflow/type';
import { DatasetSearchModeEnum } from '../dataset/constants';
import { defaultWhisperConfig } from './constants';
@ -38,97 +34,104 @@ export const getDefaultAppForm = (): AppSimpleEditFormType => {
tts: {
type: 'web'
},
whisper: defaultWhisperConfig
whisper: defaultWhisperConfig,
scheduleTrigger: null
}
};
};
/* format app modules to edit form */
export const appModules2Form = ({ modules }: { modules: ModuleItemType[] }) => {
/* format app nodes to edit form */
export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
const defaultAppForm = getDefaultAppForm();
const findInputValueByKey = (inputs: FlowNodeInputItemType[], key: string) => {
return inputs.find((item) => item.key === key)?.value;
};
modules.forEach((module) => {
nodes.forEach((node) => {
if (
module.flowType === FlowNodeTypeEnum.chatNode ||
module.flowType === FlowNodeTypeEnum.tools
node.flowNodeType === FlowNodeTypeEnum.chatNode ||
node.flowNodeType === FlowNodeTypeEnum.tools
) {
defaultAppForm.aiSettings.model = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.aiModel
);
defaultAppForm.aiSettings.model = findInputValueByKey(node.inputs, NodeInputKeyEnum.aiModel);
defaultAppForm.aiSettings.systemPrompt = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.aiSystemPrompt
node.inputs,
NodeInputKeyEnum.aiSystemPrompt
);
defaultAppForm.aiSettings.temperature = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.aiChatTemperature
node.inputs,
NodeInputKeyEnum.aiChatTemperature
);
defaultAppForm.aiSettings.maxToken = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.aiChatMaxToken
node.inputs,
NodeInputKeyEnum.aiChatMaxToken
);
defaultAppForm.aiSettings.maxHistories = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.history
node.inputs,
NodeInputKeyEnum.history
);
} else if (module.flowType === FlowNodeTypeEnum.datasetSearchNode) {
} else if (node.flowNodeType === FlowNodeTypeEnum.datasetSearchNode) {
defaultAppForm.dataset.datasets = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.datasetSelectList
node.inputs,
NodeInputKeyEnum.datasetSelectList
);
defaultAppForm.dataset.similarity = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.datasetSimilarity
node.inputs,
NodeInputKeyEnum.datasetSimilarity
);
defaultAppForm.dataset.limit = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.datasetMaxTokens
node.inputs,
NodeInputKeyEnum.datasetMaxTokens
);
defaultAppForm.dataset.searchMode =
findInputValueByKey(module.inputs, ModuleInputKeyEnum.datasetSearchMode) ||
findInputValueByKey(node.inputs, NodeInputKeyEnum.datasetSearchMode) ||
DatasetSearchModeEnum.embedding;
defaultAppForm.dataset.usingReRank = !!findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.datasetSearchUsingReRank
node.inputs,
NodeInputKeyEnum.datasetSearchUsingReRank
);
defaultAppForm.dataset.datasetSearchUsingExtensionQuery = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.datasetSearchUsingExtensionQuery
node.inputs,
NodeInputKeyEnum.datasetSearchUsingExtensionQuery
);
defaultAppForm.dataset.datasetSearchExtensionModel = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.datasetSearchExtensionModel
node.inputs,
NodeInputKeyEnum.datasetSearchExtensionModel
);
defaultAppForm.dataset.datasetSearchExtensionBg = findInputValueByKey(
module.inputs,
ModuleInputKeyEnum.datasetSearchExtensionBg
node.inputs,
NodeInputKeyEnum.datasetSearchExtensionBg
);
} else if (module.flowType === FlowNodeTypeEnum.userGuide) {
const { welcomeText, variableModules, questionGuide, ttsConfig, whisperConfig } =
splitGuideModule(getGuideModule(modules));
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
const {
welcomeText,
variableModules,
questionGuide,
ttsConfig,
whisperConfig,
scheduledTriggerConfig
} = splitGuideModule(getGuideModule(nodes));
defaultAppForm.userGuide = {
welcomeText: welcomeText,
variables: variableModules,
questionGuide: questionGuide,
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({
id: module.inputs.find((input) => input.key === ModuleInputKeyEnum.pluginId)?.value || '',
name: module.name,
avatar: module.avatar,
intro: module.intro || '',
flowType: module.flowType,
showStatus: module.showStatus,
inputs: module.inputs,
outputs: module.outputs,
id: node.pluginId,
name: node.name,
avatar: node.avatar,
intro: node.intro || '',
flowNodeType: node.flowNodeType,
showStatus: node.showStatus,
inputs: node.inputs,
outputs: node.outputs,
templateType: FlowNodeTemplateTypeEnum.other
});
}

View File

@ -1,4 +1,4 @@
import { ClassifyQuestionAgentItemType } from '../module/type';
import { ClassifyQuestionAgentItemType } from '../workflow/type';
import { SearchDataResponseItemType } from '../dataset/type';
import {
ChatFileTypeEnum,
@ -7,14 +7,14 @@ import {
ChatSourceEnum,
ChatStatusEnum
} from './constants';
import { FlowNodeTypeEnum } from '../module/node/constant';
import { ModuleOutputKeyEnum } from '../module/constants';
import { DispatchNodeResponseKeyEnum } from '../module/runtime/constants';
import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { NodeOutputKeyEnum } from '../workflow/constants';
import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
import { AppSchema } from '../app/type';
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
import { DatasetSearchModeEnum } from '../dataset/constants';
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 = {
_id: string;
@ -136,6 +136,7 @@ export type ChatHistoryItemType = HistoryItemType & {
/* ------- response data ------------ */
export type ChatHistoryItemResType = DispatchNodeResponseType & {
nodeId: string;
moduleType: `${FlowNodeTypeEnum}`;
moduleName: string;
};

View File

@ -1,5 +1,5 @@
import { DispatchNodeResponseType } from '../module/runtime/type';
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../module/node/constant';
import { DispatchNodeResponseType } from '../workflow/runtime/type';
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../workflow/node/constant';
import { ChatItemValueTypeEnum, ChatRoleEnum } from './constants';
import { ChatHistoryItemResType, ChatItemType } from './type.d';

View File

@ -1,4 +1,3 @@
import { countPromptTokens } from '../../../common/string/tiktoken';
import { SearchScoreTypeEnum } from '../constants';
import { SearchDataResponseItemType } from '../type';
@ -71,25 +70,3 @@ export const datasetSearchResultConcat = (
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;
};

View File

@ -1,70 +0,0 @@
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';

View File

@ -1,128 +0,0 @@
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;
};

View File

@ -1,31 +0,0 @@
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
}
]
});
};

View File

@ -1,101 +0,0 @@
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
};

View File

@ -1,29 +0,0 @@
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: []
};

View File

@ -1,112 +0,0 @@
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
}
}
]
};

View File

@ -1,117 +0,0 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import {
Input_Template_SettingAiModel,
Input_Template_Dataset_Quote,
Input_Template_History,
Input_Template_Switch,
Input_Template_System_Prompt,
Input_Template_UserChatInput
} from '../input';
import { chatNodeSystemPromptTip } from '../tip';
import { Output_Template_Finish, Output_Template_UserChatInput } from '../output';
export const AiChatModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.chatNode,
templateType: FlowNodeTemplateTypeEnum.textAnswer,
flowType: FlowNodeTypeEnum.chatNode,
avatar: '/imgs/module/AI.png',
name: 'AI 对话',
intro: 'AI 大模型对话',
showStatus: true,
isTool: true,
inputs: [
Input_Template_Switch,
Input_Template_SettingAiModel,
// --- settings modal
{
key: ModuleInputKeyEnum.aiChatTemperature,
type: FlowNodeInputTypeEnum.hidden, // Set in the pop-up window
label: '',
value: 0,
valueType: ModuleIOValueTypeEnum.number,
min: 0,
max: 10,
step: 1,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.aiChatMaxToken,
type: FlowNodeInputTypeEnum.hidden, // Set in the pop-up window
label: '',
value: 2000,
valueType: ModuleIOValueTypeEnum.number,
min: 100,
max: 4000,
step: 50,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.aiChatIsResponseText,
type: FlowNodeInputTypeEnum.hidden,
label: '',
value: true,
valueType: ModuleIOValueTypeEnum.boolean,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.aiChatQuoteTemplate,
type: FlowNodeInputTypeEnum.hidden,
label: '',
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.aiChatQuotePrompt,
type: FlowNodeInputTypeEnum.hidden,
label: '',
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false
},
// settings modal ---
{
...Input_Template_System_Prompt,
label: 'core.ai.Prompt',
description: chatNodeSystemPromptTip,
placeholder: chatNodeSystemPromptTip
},
Input_Template_History,
{ ...Input_Template_UserChatInput, toolDescription: '用户问题' },
Input_Template_Dataset_Quote
],
outputs: [
Output_Template_UserChatInput,
{
key: ModuleOutputKeyEnum.history,
label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context',
valueType: ModuleIOValueTypeEnum.chatHistory,
type: FlowNodeOutputTypeEnum.source,
targets: []
},
{
key: ModuleOutputKeyEnum.answerText,
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
valueType: ModuleIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.source,
targets: []
},
Output_Template_Finish
]
};

View File

@ -1,33 +0,0 @@
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]
};

View File

@ -1,94 +0,0 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import {
Input_Template_SelectAIModel,
Input_Template_History,
Input_Template_Switch
} from '../input';
import { LLMModelTypeEnum } from '../../../ai/constants';
export const ContextExtractModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.contentExtract,
templateType: FlowNodeTemplateTypeEnum.functionCall,
flowType: FlowNodeTypeEnum.contentExtract,
avatar: '/imgs/module/extract.png',
name: '文本内容提取',
intro: '可从文本中提取指定的数据例如sql语句、搜索关键词、代码等',
showStatus: true,
isTool: true,
inputs: [
Input_Template_Switch,
{
...Input_Template_SelectAIModel,
llmModelType: LLMModelTypeEnum.extractFields
},
{
key: ModuleInputKeyEnum.description,
type: FlowNodeInputTypeEnum.textarea,
valueType: ModuleIOValueTypeEnum.string,
label: '提取要求描述',
description:
'给AI一些对应的背景知识或要求描述引导AI更好的完成任务。\n该输入框可使用全局变量。',
placeholder:
'例如: \n1. 当前时间为: {{cTime}}。你是一个实验室预约助手,你的任务是帮助用户预约实验室,从文本中获取对应的预约信息。\n2. 你是谷歌搜索助手,需要从文本中提取出合适的搜索词。',
showTargetInApp: true,
showTargetInPlugin: true
},
Input_Template_History,
{
key: ModuleInputKeyEnum.contextExtractInput,
type: FlowNodeInputTypeEnum.target,
label: '需要提取的文本',
required: true,
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: true,
showTargetInPlugin: true,
toolDescription: '需要检索的内容'
},
{
key: ModuleInputKeyEnum.extractKeys,
type: FlowNodeInputTypeEnum.custom,
label: '',
valueType: ModuleIOValueTypeEnum.any,
description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段",
value: [], // {desc: string; key: string; required: boolean; enum: string[]}[]
showTargetInApp: false,
showTargetInPlugin: false
}
],
outputs: [
{
key: ModuleOutputKeyEnum.success,
label: '字段完全提取',
valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeOutputTypeEnum.source,
targets: []
},
{
key: ModuleOutputKeyEnum.failed,
label: '提取字段缺失',
description: '存在一个或多个字段未提取成功。尽管使用了默认值也算缺失。',
valueType: ModuleIOValueTypeEnum.boolean,
type: FlowNodeOutputTypeEnum.source,
targets: []
},
{
key: ModuleOutputKeyEnum.contextExtractFields,
label: '完整提取结果',
description: '一个 JSON 字符串,例如:{"name:":"YY","Time":"2023/7/2 18:00"}',
valueType: ModuleIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.source,
targets: []
}
]
};

View File

@ -1,53 +0,0 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import { Input_Template_Dataset_Quote, Input_Template_Switch } from '../input';
import { Output_Template_Finish } from '../output';
import { getNanoid } from '../../../../common/string/tools';
export const getOneQuoteInputTemplate = (key = getNanoid()) => ({
...Input_Template_Dataset_Quote,
key,
type: FlowNodeInputTypeEnum.hidden
});
export const DatasetConcatModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.datasetConcatNode,
flowType: FlowNodeTypeEnum.datasetConcatNode,
templateType: FlowNodeTemplateTypeEnum.other,
avatar: '/imgs/module/concat.svg',
name: '知识库搜索引用合并',
intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。',
showStatus: false,
inputs: [
Input_Template_Switch,
{
key: ModuleInputKeyEnum.datasetMaxTokens,
type: FlowNodeInputTypeEnum.custom,
label: '最大 Tokens',
value: 1500,
valueType: ModuleIOValueTypeEnum.number,
showTargetInApp: false,
showTargetInPlugin: false
},
getOneQuoteInputTemplate('defaultQuote')
],
outputs: [
{
key: ModuleOutputKeyEnum.datasetQuoteQA,
label: 'core.module.Dataset quote.label',
type: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.datasetQuote,
targets: []
}
]
};

View File

@ -1,133 +0,0 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import { Input_Template_Switch, Input_Template_UserChatInput } from '../input';
import { Output_Template_Finish, Output_Template_UserChatInput } from '../output';
import { DatasetSearchModeEnum } from '../../../dataset/constants';
export const Dataset_SEARCH_DESC =
'调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容';
export const DatasetSearchModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.datasetSearchNode,
templateType: FlowNodeTemplateTypeEnum.functionCall,
flowType: FlowNodeTypeEnum.datasetSearchNode,
avatar: '/imgs/module/db.png',
name: '知识库搜索',
intro: Dataset_SEARCH_DESC,
showStatus: true,
isTool: true,
inputs: [
Input_Template_Switch,
{
key: ModuleInputKeyEnum.datasetSelectList,
type: FlowNodeInputTypeEnum.selectDataset,
label: 'core.module.input.label.Select dataset',
value: [],
valueType: ModuleIOValueTypeEnum.selectDataset,
list: [],
required: true,
showTargetInApp: false,
showTargetInPlugin: true
},
{
key: ModuleInputKeyEnum.datasetSimilarity,
type: FlowNodeInputTypeEnum.selectDatasetParamsModal,
label: '',
value: 0.4,
valueType: ModuleIOValueTypeEnum.number,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.datasetMaxTokens,
type: FlowNodeInputTypeEnum.hidden,
label: '',
value: 1500,
valueType: ModuleIOValueTypeEnum.number,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.datasetSearchMode,
type: FlowNodeInputTypeEnum.hidden,
label: '',
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false,
value: DatasetSearchModeEnum.embedding
},
{
key: ModuleInputKeyEnum.datasetSearchUsingReRank,
type: FlowNodeInputTypeEnum.hidden,
label: '',
valueType: ModuleIOValueTypeEnum.boolean,
showTargetInApp: false,
showTargetInPlugin: false,
value: false
},
{
key: ModuleInputKeyEnum.datasetSearchUsingExtensionQuery,
type: FlowNodeInputTypeEnum.hidden,
label: '',
valueType: ModuleIOValueTypeEnum.boolean,
showTargetInApp: false,
showTargetInPlugin: false,
value: true
},
{
key: ModuleInputKeyEnum.datasetSearchExtensionModel,
type: FlowNodeInputTypeEnum.hidden,
label: '',
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false
},
{
key: ModuleInputKeyEnum.datasetSearchExtensionBg,
type: FlowNodeInputTypeEnum.hidden,
label: '',
valueType: ModuleIOValueTypeEnum.string,
showTargetInApp: false,
showTargetInPlugin: false,
value: ''
},
{
...Input_Template_UserChatInput,
toolDescription: '需要检索的内容'
}
],
outputs: [
Output_Template_UserChatInput,
{
key: ModuleOutputKeyEnum.datasetIsEmpty,
label: 'core.module.output.label.Search result empty',
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',
type: FlowNodeOutputTypeEnum.source,
valueType: ModuleIOValueTypeEnum.datasetQuote,
targets: []
}
]
};

View File

@ -1,128 +0,0 @@
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
]
};

View File

@ -1,86 +0,0 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import {
Input_Template_DynamicInput,
Input_Template_Switch,
Input_Template_AddInputParam
} from '../input';
import { Output_Template_Finish, Output_Template_AddOutput } from '../output';
export const lafModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.lafModule,
templateType: FlowNodeTemplateTypeEnum.externalCall,
flowType: FlowNodeTypeEnum.lafModule,
avatar: '/imgs/module/laf.png',
name: 'Laf 函数调用(测试)',
intro: '可以调用Laf账号下的云函数。',
showStatus: true,
isTool: true,
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,
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
]
};

View File

@ -1,43 +0,0 @@
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: []
}
]
};

View File

@ -1,63 +0,0 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
ModuleOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import {
Input_Template_History,
Input_Template_Switch,
Input_Template_UserChatInput
} from '../input';
import { Output_Template_Finish, Output_Template_UserChatInput } from '../output';
export const RunAppModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.runApp,
templateType: FlowNodeTemplateTypeEnum.externalCall,
flowType: FlowNodeTypeEnum.runApp,
avatar: '/imgs/module/app.png',
name: '应用调用',
intro: '可以选择一个其他应用进行调用',
showStatus: true,
inputs: [
Input_Template_Switch,
{
key: ModuleInputKeyEnum.runAppSelectApp,
type: FlowNodeInputTypeEnum.selectApp,
valueType: ModuleIOValueTypeEnum.selectApp,
label: '选择一个应用',
description: '选择一个其他应用进行调用',
required: true,
showTargetInApp: false,
showTargetInPlugin: false
},
Input_Template_History,
Input_Template_UserChatInput
],
outputs: [
Output_Template_UserChatInput,
{
key: ModuleOutputKeyEnum.history,
label: '新的上下文',
description: '将该应用回复内容拼接到历史记录中,作为新的上下文返回',
valueType: ModuleIOValueTypeEnum.chatHistory,
type: FlowNodeOutputTypeEnum.source,
targets: []
},
{
key: ModuleOutputKeyEnum.answerText,
label: '回复的文本',
description: '将在应用完全结束后触发',
valueType: ModuleIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.source,
targets: []
},
Output_Template_Finish
]
};

View File

@ -1,60 +0,0 @@
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: []
};

View File

@ -1,40 +0,0 @@
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: []
}
]
};

View File

@ -1,107 +0,0 @@
import { FlowNodeTypeEnum } from './node/constant';
import {
ModuleIOValueTypeEnum,
ModuleOutputKeyEnum,
FlowNodeTemplateTypeEnum,
VariableInputEnum
} from './constants';
import { DispatchNodeResponseKeyEnum } from './runtime/constants';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './node/type';
import { UserModelSchema } from 'support/user/type';
import {
ChatItemType,
ChatItemValueItemType,
ToolRunResponseItemType,
UserChatItemValueItemType
} from '../chat/type';
import { ChatNodeUsageType } from '../../support/wallet/bill/type';
import { RunningModuleItemType } from './runtime/type';
import { PluginTypeEnum } from 'core/plugin/constants';
export type FlowNodeTemplateType = {
id: string; // module id, unique
templateType: `${FlowNodeTemplateTypeEnum}`;
flowType: `${FlowNodeTypeEnum}`; // render node card
avatar?: string;
name: string;
intro: string; // template list intro
isTool?: boolean; // can be connected by tool
showStatus?: boolean; // chatting response step status
inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[];
// plugin data
pluginType?: `${PluginTypeEnum}`;
parentId?: string;
};
export type FlowModuleItemType = FlowNodeTemplateType & {
moduleId: string;
};
export type moduleTemplateListType = {
type: `${FlowNodeTemplateTypeEnum}`;
label: string;
list: FlowNodeTemplateType[];
}[];
// store module type
export type ModuleItemType = {
name: string;
avatar?: string;
intro?: string;
moduleId: string;
position?: {
x: number;
y: number;
};
flowType: `${FlowNodeTypeEnum}`;
showStatus?: boolean;
inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[];
// runTime field
isEntry?: boolean;
};
/* --------------- function type -------------------- */
export type SelectAppItemType = {
id: string;
name: string;
logo: string;
};
/* agent */
export type ClassifyQuestionAgentItemType = {
value: string;
key: string;
};
export type ContextExtractAgentItemType = {
desc: string;
key: string;
required: boolean;
defaultValue?: string;
enum?: string;
};
/* -------------- running module -------------- */
export type ChatDispatchProps = {
res: NextApiResponse;
mode: 'test' | 'chat';
teamId: string;
tmbId: string;
user: UserModelSchema;
appId: string;
chatId?: string;
responseChatItemId?: string;
histories: ChatItemType[];
variables: Record<string, any>;
inputFiles?: UserChatItemValueItemType['file'][];
stream: boolean;
detail: boolean; // response detail
maxRunTimes: number;
};
export type ModuleDispatchProps<T> = ChatDispatchProps & {
module: RunningModuleItemType;
runtimeModules: RunningModuleItemType[];
params: T;
};

View File

@ -1,123 +0,0 @@
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
}));
};

View File

@ -1,31 +1,4 @@
import { ModuleItemType } from '../module/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: []
}
];
import { StoreNodeItemType } from '../workflow/type';
export enum PluginTypeEnum {
folder = 'folder',

View File

@ -1,4 +1,5 @@
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 { HttpAuthMethodType } from './httpPlugin/type';
@ -6,7 +7,7 @@ export type CreateOnePluginParams = {
name: string;
avatar: string;
intro: string;
modules: ModuleItemType[];
modules: StoreNodeItemType[];
parentId: string | null;
type: `${PluginTypeEnum}`;
metadata?: {
@ -20,7 +21,8 @@ export type UpdatePluginParams = {
name?: string;
avatar?: string;
intro?: string;
modules?: ModuleItemType[];
modules?: StoreNodeItemType[];
edges?: StoreEdgeItemType[];
metadata?: {
apiSchemaStr?: string;
customHeaders?: string;

View File

@ -3,15 +3,15 @@ import { OpenApiJsonSchema } from './type';
import yaml from 'js-yaml';
import { OpenAPIV3 } from 'openapi-types';
import { PluginTypeEnum } from '../constants';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../../module/node/type';
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum } from '../../module/node/constant';
import { ModuleIOValueTypeEnum } from '../../module/constants';
import { PluginInputModule } from '../../module/template/system/pluginInput';
import { PluginOutputModule } from '../../module/template/system/pluginOutput';
import { HttpModule468 } from '../../module/template/system/http468';
import { HttpParamAndHeaderItemType } from '../../module/api';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../../workflow/type/io.d';
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum } from '../../workflow/node/constant';
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '../../workflow/constants';
import { PluginInputModule } from '../../workflow/template/system/pluginInput';
import { PluginOutputModule } from '../../workflow/template/system/pluginOutput';
import { HttpModule468 } from '../../workflow/template/system/http468';
import { HttpParamAndHeaderItemType } from '../../workflow/api';
import { CreateOnePluginParams } from '../controller';
import { ModuleItemType } from '../../module/type';
import { StoreNodeItemType } from '../../workflow/type';
import { HttpImgUrl } from '../../../common/file/image/constants';
import SwaggerParser from '@apidevtools/swagger-parser';
@ -74,6 +74,9 @@ export const httpApiSchema2Plugins = async ({
return jsonSchema.pathData.map((item) => {
const pluginOutputId = getNanoid();
const httpId = getNanoid();
const pluginInputId = getNanoid();
const inputIdMap = new Map();
const pluginOutputKey = 'result';
const properties = item.request?.content?.['application/json']?.schema?.properties;
@ -83,12 +86,13 @@ export const httpApiSchema2Plugins = async ({
...(item.params?.map((param: any) => {
return {
key: param.name,
valueType: ModuleIOValueTypeEnum.string,
valueType: param.schema.type,
label: param.name,
type: FlowNodeInputTypeEnum.target,
renderTypeList: [FlowNodeInputTypeEnum.reference],
required: param.required,
description: param.description,
edit: true,
toolDescription: param.description,
canEdit: true,
editField: {
key: true,
name: true,
@ -97,21 +101,20 @@ export const httpApiSchema2Plugins = async ({
dataType: true,
inputType: true,
isToolInput: true
},
connected: true,
toolDescription: param.description
}
};
}) || []),
...(propsKeys?.map((key) => {
const prop = properties[key];
return {
key,
valueType: ModuleIOValueTypeEnum.string,
valueType: prop.type,
label: key,
type: FlowNodeInputTypeEnum.target,
renderTypeList: [FlowNodeInputTypeEnum.reference],
required: false,
description: prop.description,
edit: true,
toolDescription: prop.description,
canEdit: true,
editField: {
key: true,
name: true,
@ -120,42 +123,33 @@ export const httpApiSchema2Plugins = async ({
dataType: true,
inputType: true,
isToolInput: true
},
connected: true,
toolDescription: prop.description
}
};
}) || [])
];
const pluginOutputs: FlowNodeOutputItemType[] = [
...(item.params?.map((param: any) => {
const id = getNanoid();
inputIdMap.set(param.name, id);
return {
id,
key: param.name,
valueType: ModuleIOValueTypeEnum.string,
valueType: param.schema.type,
label: param.name,
type: FlowNodeOutputTypeEnum.source,
edit: true,
targets: [
{
moduleId: httpId,
key: param.name
}
]
type: FlowNodeOutputTypeEnum.source
};
}) || []),
...(propsKeys?.map((key) => {
const id = getNanoid();
inputIdMap.set(key, id);
return {
id,
key,
valueType: ModuleIOValueTypeEnum.string,
valueType: properties[key].type,
label: key,
type: FlowNodeOutputTypeEnum.source,
edit: true,
targets: [
{
moduleId: httpId,
key
}
]
edit: true
};
}) || [])
];
@ -164,34 +158,29 @@ export const httpApiSchema2Plugins = async ({
...(item.params?.map((param: any) => {
return {
key: param.name,
valueType: ModuleIOValueTypeEnum.string,
valueType: param.schema.type,
label: param.name,
type: FlowNodeInputTypeEnum.target,
description: param.description,
edit: true,
renderTypeList: [FlowNodeInputTypeEnum.reference],
canEdit: true,
editField: {
key: true,
description: true,
dataType: true
valueType: true
},
connected: true
value: [pluginInputId, inputIdMap.get(param.name)]
};
}) || []),
...(propsKeys?.map((key) => {
const prop = properties[key];
return {
key,
valueType: ModuleIOValueTypeEnum.string,
valueType: properties[key].type,
label: key,
type: FlowNodeInputTypeEnum.target,
description: prop.description,
edit: true,
renderTypeList: [FlowNodeInputTypeEnum.reference],
canEdit: true,
editField: {
key: true,
description: true,
dataType: true
valueType: true
},
connected: true
value: [pluginInputId, inputIdMap.get(key)]
};
}) || [])
];
@ -207,7 +196,7 @@ export const httpApiSchema2Plugins = async ({
if (param.in === 'header') {
httpNodeHeaders.push({
key: param.name,
type: param.schema?.type || ModuleIOValueTypeEnum.string,
type: param.schema?.type || WorkflowIOValueTypeEnum.string,
value: `{{${param.name}}}`
});
} else if (param.in === 'body') {
@ -219,7 +208,7 @@ export const httpApiSchema2Plugins = async ({
} else if (param.in === 'query') {
httpNodeParams.push({
key: param.name,
type: param.schema?.type || ModuleIOValueTypeEnum.string,
type: param.schema?.type || WorkflowIOValueTypeEnum.string,
value: `{{${param.name}}}`
});
}
@ -250,7 +239,7 @@ export const httpApiSchema2Plugins = async ({
for (const key in headersObj) {
httpNodeHeaders.push({
key,
type: 'string',
type: WorkflowIOValueTypeEnum.string,
// @ts-ignore
value: headersObj[key]
});
@ -258,57 +247,27 @@ export const httpApiSchema2Plugins = async ({
}
/* Combine complete modules */
const modules: ModuleItemType[] = [
const modules: StoreNodeItemType[] = [
{
moduleId: getNanoid(),
nodeId: pluginInputId,
name: PluginInputModule.name,
intro: PluginInputModule.intro,
avatar: PluginInputModule.avatar,
flowType: PluginInputModule.flowType,
flowNodeType: PluginInputModule.flowNodeType,
showStatus: PluginInputModule.showStatus,
position: {
x: 616.4226348688949,
y: -165.05298493910115
},
inputs: [
{
key: 'pluginStart',
type: 'hidden',
valueType: 'boolean',
label: '插件开始运行',
description:
'插件开始运行时,会输出一个 True 的标识。有时候,插件不会有额外的的输入,为了顺利的进入下一个阶段,你可以将该值连接到下一个节点的触发器中。',
showTargetInApp: true,
showTargetInPlugin: true,
connected: true
},
...pluginInputs
],
outputs: [
{
key: 'pluginStart',
label: '插件开始运行',
type: 'source',
valueType: 'boolean',
targets:
pluginOutputs.length === 0
? [
{
moduleId: httpId,
key: 'switch'
}
]
: []
},
...pluginOutputs
]
inputs: pluginInputs,
outputs: pluginOutputs
},
{
moduleId: pluginOutputId,
nodeId: pluginOutputId,
name: PluginOutputModule.name,
intro: PluginOutputModule.intro,
avatar: PluginOutputModule.avatar,
flowType: PluginOutputModule.flowType,
flowNodeType: PluginOutputModule.flowNodeType,
showStatus: PluginOutputModule.showStatus,
position: {
x: 1607.7142331269126,
@ -317,40 +276,36 @@ export const httpApiSchema2Plugins = async ({
inputs: [
{
key: pluginOutputKey,
valueType: 'string',
valueType: WorkflowIOValueTypeEnum.string,
label: pluginOutputKey,
type: 'target',
required: true,
renderTypeList: [FlowNodeInputTypeEnum.reference],
required: false,
description: '',
edit: true,
canEdit: true,
editField: {
key: true,
name: true,
description: true,
required: false,
dataType: true,
inputType: false
valueType: true
},
connected: true
value: [httpId, 'httpRawResponse']
}
],
outputs: [
{
id: pluginOutputId,
key: pluginOutputKey,
valueType: 'string',
valueType: WorkflowIOValueTypeEnum.string,
label: pluginOutputKey,
type: 'source',
edit: true,
targets: []
type: FlowNodeOutputTypeEnum.static
}
]
},
{
moduleId: httpId,
nodeId: httpId,
name: HttpModule468.name,
intro: HttpModule468.intro,
avatar: HttpModule468.avatar,
flowType: HttpModule468.flowType,
flowNodeType: HttpModule468.flowNodeType,
showStatus: true,
position: {
x: 1042.549746602742,
@ -358,153 +313,79 @@ export const httpApiSchema2Plugins = async ({
},
inputs: [
{
key: 'switch',
type: 'target',
label: 'core.module.input.label.switch',
description: 'core.module.input.description.Trigger',
valueType: 'any',
showTargetInApp: true,
showTargetInPlugin: true,
connected: false
key: NodeInputKeyEnum.addInputParam,
renderTypeList: [FlowNodeInputTypeEnum.addInputParam],
valueType: WorkflowIOValueTypeEnum.dynamic,
label: '',
required: false,
description: 'core.module.input.description.HTTP Dynamic Input',
editField: {
key: true,
valueType: true
}
},
...httpInputs,
{
key: 'system_httpMethod',
type: 'custom',
valueType: 'string',
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.string,
label: '',
value: item.method.toUpperCase(),
required: true,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
required: true
},
{
key: 'system_httpReqUrl',
type: 'hidden',
valueType: 'string',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.string,
label: '',
description: 'core.module.input.description.Http Request Url',
placeholder: 'https://api.ai.com/getInventory',
required: false,
showTargetInApp: false,
showTargetInPlugin: false,
value: requestUrl,
connected: false
value: requestUrl
},
{
key: 'system_httpHeader',
type: 'custom',
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.any,
value: httpNodeHeaders,
label: '',
description: 'core.module.input.description.Http Request Header',
placeholder: 'core.module.input.description.Http Request Header',
required: false,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
required: false
},
{
key: 'system_httpParams',
type: 'hidden',
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
value: httpNodeParams,
label: '',
required: false,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
required: false
},
{
key: 'system_httpJsonBody',
type: 'hidden',
valueType: 'any',
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
value: httpNodeBody,
label: '',
required: false,
showTargetInApp: false,
showTargetInPlugin: false,
connected: false
},
{
key: 'DYNAMIC_INPUT_KEY',
type: 'target',
valueType: 'any',
label: 'core.module.inputType.dynamicTargetInput',
description: 'core.module.input.description.dynamic input',
required: false,
showTargetInApp: false,
showTargetInPlugin: true,
hideInApp: true,
connected: false
},
{
key: 'system_addInputParam',
type: 'addInputParam',
valueType: 'any',
label: '',
required: false,
showTargetInApp: false,
showTargetInPlugin: false,
editField: {
key: true,
description: true,
dataType: true
},
defaultEditField: {
label: '',
key: '',
description: '',
inputType: 'target',
valueType: 'string'
},
connected: false
},
...httpInputs
],
outputs: [
{
key: 'finish',
label: 'core.module.output.label.running done',
description: 'core.module.output.description.running done',
valueType: 'boolean',
type: 'source',
targets: []
},
{
key: 'httpRawResponse',
label: '原始响应',
description: 'HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。',
valueType: 'any',
type: 'source',
targets: [
{
moduleId: pluginOutputId,
key: pluginOutputKey
}
]
},
{
key: 'system_addOutputParam',
type: 'addOutputParam',
valueType: 'any',
label: '',
targets: [],
editField: {
key: true,
description: true,
dataType: true,
defaultValue: true
},
defaultEditField: {
label: '',
key: '',
description: '',
outputType: 'source',
valueType: 'string'
}
required: false
}
]
],
outputs: HttpModule468.outputs
}
];
const edges = [
{
source: pluginInputId,
target: httpId,
sourcePort: `${pluginInputId}-source-right`,
targetPort: `${httpId}-target-left`
},
{
source: httpId,
target: pluginOutputId,
sourcePort: `${httpId}-source-right`,
targetPort: `${pluginOutputId}-target-left`
}
];
@ -514,7 +395,8 @@ export const httpApiSchema2Plugins = async ({
intro: item.description,
parentId,
type: PluginTypeEnum.http,
modules
modules,
edges
};
});
};

View File

@ -1,5 +1,6 @@
import { ModuleTemplateTypeEnum } from 'core/module/constants';
import type { FlowModuleTemplateType, ModuleItemType } from '../module/type.d';
import { StoreEdgeItemType } from 'core/workflow/type/edge';
import { ModuleTemplateTypeEnum } from '../workflow/constants';
import type { FlowModuleTemplateType, StoreNodeItemType } from '../workflow/type';
import { PluginSourceEnum, PluginTypeEnum } from './constants';
import { MethodType } from './controller';
@ -12,7 +13,8 @@ export type PluginItemSchema = {
avatar: string;
intro: string;
updateTime: Date;
modules: ModuleItemType[];
modules: StoreNodeItemType[];
edges: StoreEdgeItemType[];
parentId: string;
type: `${PluginTypeEnum}`;
metadata?: {
@ -20,6 +22,7 @@ export type PluginItemSchema = {
apiSchemaStr?: string;
customHeaders?: string;
};
version?: 'v1' | 'v2';
};
/* plugin template */
@ -29,7 +32,6 @@ export type PluginTemplateType = PluginRuntimeType & {
source: `${PluginSourceEnum}`;
templateType: FlowNodeTemplateType['templateType'];
intro: string;
modules: ModuleItemType[];
};
export type PluginRuntimeType = {
@ -38,5 +40,6 @@ export type PluginRuntimeType = {
avatar: string;
showStatus?: boolean;
isTool?: boolean;
modules: ModuleItemType[];
nodes: StoreNodeItemType[];
edges: StoreEdgeItemType[];
};

View File

@ -1,10 +1,10 @@
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 HttpBodyType<T = any> = {
[DYNAMIC_INPUT_KEY]: Record<string, any>;
export type HttpBodyType<T = Record<string, any>> = {
[NodeInputKeyEnum.addInputParam]: Record<string, any>;
} & T;
export type HttpQueryType = {
appId: string;

View File

@ -1,5 +1,4 @@
export enum FlowNodeTemplateTypeEnum {
userGuide = 'userGuide',
systemInput = 'systemInput',
tools = 'tools',
textAnswer = 'textAnswer',
@ -11,13 +10,15 @@ export enum FlowNodeTemplateTypeEnum {
other = 'other'
}
export enum ModuleIOValueTypeEnum {
export enum WorkflowIOValueTypeEnum {
string = 'string',
number = 'number',
boolean = 'boolean',
any = 'any',
chatHistory = 'chatHistory',
datasetQuote = 'datasetQuote',
any = 'any',
dynamic = 'dynamic',
// plugin special type
selectApp = 'selectApp',
@ -28,17 +29,21 @@ export enum ModuleIOValueTypeEnum {
}
/* reg: modulename key */
export enum ModuleInputKeyEnum {
export enum NodeInputKeyEnum {
// old
welcomeText = 'welcomeText',
variables = 'variables',
switch = 'switch', // a trigger switch
history = 'history',
userChatInput = 'userChatInput',
answerText = 'text',
// system config
questionGuide = 'questionGuide',
tts = 'tts',
whisper = 'whisper',
answerText = 'text',
variables = 'variables',
scheduleTrigger = 'scheduleTrigger',
agents = 'agents', // cq agent key
// latest
@ -89,13 +94,16 @@ export enum ModuleInputKeyEnum {
// plugin
pluginId = 'pluginId',
pluginStart = 'pluginStart'
pluginStart = 'pluginStart',
// if else
condition = 'condition',
ifElseList = 'ifElseList'
}
export enum ModuleOutputKeyEnum {
export enum NodeOutputKeyEnum {
// common
userChatInput = 'userChatInput',
finish = 'finish',
history = 'history',
answerText = 'answerText', // module answer. the value will be show and save to history
success = 'success',
@ -104,10 +112,10 @@ export enum ModuleOutputKeyEnum {
addOutputParam = 'system_addOutputParam',
// dataset
datasetIsEmpty = 'isEmpty',
datasetUnEmpty = 'unEmpty',
datasetQuoteQA = 'quoteQA',
// classify
cqResult = 'cqResult',
// context extract
contextExtractFields = 'fields',
@ -122,7 +130,10 @@ export enum ModuleOutputKeyEnum {
httpRawResponse = 'httpRawResponse',
// plugin
pluginStart = 'pluginStart'
pluginStart = 'pluginStart',
if = 'IF',
else = 'ELSE'
}
export enum VariableInputEnum {
@ -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'
}

View File

@ -0,0 +1,118 @@
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';

View File

@ -0,0 +1,39 @@
/*
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;
};
};

View File

@ -1,3 +1,5 @@
import { FlowNodeInputTypeEnum } from '../node/constant';
export enum SseResponseEventEnum {
error = 'error',
answer = 'answer', // animation stream
@ -11,9 +13,17 @@ export enum SseResponseEventEnum {
}
export enum DispatchNodeResponseKeyEnum {
skipHandleId = 'skipHandleId', // skip handle id
nodeResponse = 'responseData', // run node response
nodeDispatchUsages = 'nodeDispatchUsages', // the node bill.
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
assistantResponses = 'assistantResponses' // assistant response
}
export const needReplaceReferenceInputTypeList = [
FlowNodeInputTypeEnum.reference,
FlowNodeInputTypeEnum.settingDatasetQuotePrompt,
FlowNodeInputTypeEnum.addInputParam,
FlowNodeInputTypeEnum.custom
] as string[];

View File

@ -1,38 +1,28 @@
import { ChatNodeUsageType } from '../../../support/wallet/bill/type';
import { ChatItemValueItemType, ToolRunResponseItemType } from '../../chat/type';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../node/type';
import { ModuleItemType } from '../type';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../type/io.d';
import { StoreNodeItemType } from '../type';
import { DispatchNodeResponseKeyEnum } from './constants';
import { StoreEdgeItemType } from '../type/edge';
import { NodeInputKeyEnum } from '../constants';
export type RunningModuleItemType = {
name: ModuleItemType['name'];
avatar: ModuleItemType['avatar'];
intro?: ModuleItemType['intro'];
moduleId: ModuleItemType['moduleId'];
flowType: ModuleItemType['flowType'];
showStatus?: ModuleItemType['showStatus'];
isEntry?: ModuleItemType['isEntry'];
export type RuntimeNodeItemType = {
nodeId: StoreNodeItemType['nodeId'];
name: StoreNodeItemType['name'];
avatar: StoreNodeItemType['avatar'];
intro?: StoreNodeItemType['intro'];
flowNodeType: StoreNodeItemType['flowNodeType'];
showStatus?: StoreNodeItemType['showStatus'];
isEntry?: StoreNodeItemType['isEntry'];
inputs: {
key: string;
value?: any;
valueType?: FlowNodeInputItemType['valueType'];
required?: boolean;
toolDescription?: string;
}[];
outputs: {
key: string;
required?: boolean;
defaultValue?: any;
answer?: boolean;
response?: boolean;
value?: any;
valueType?: FlowNodeOutputItemType['valueType'];
targets: {
moduleId: string;
key: string;
}[];
}[];
inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[];
pluginId?: string;
};
export type RuntimeEdgeItemType = StoreEdgeItemType & {
status: 'waiting' | 'active' | 'skipped';
};
export type DispatchNodeResponseType = {
@ -84,8 +74,8 @@ export type DispatchNodeResponseType = {
pluginOutput?: Record<string, any>;
pluginDetail?: ChatHistoryItemResType[];
// tf switch
tfSwitchResult?: boolean;
// if-else
ifElseResult?: 'IF' | 'ELSE';
// tool
toolCallTokens?: number;
@ -94,9 +84,21 @@ export type DispatchNodeResponseType = {
};
export type DispatchNodeResultType<T> = {
[DispatchNodeResponseKeyEnum.skipHandleId]?: string[]; // skip some edge handle id
[DispatchNodeResponseKeyEnum.nodeResponse]?: DispatchNodeResponseType; // The node response detail
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]?: ChatNodeUsageType[]; //
[DispatchNodeResponseKeyEnum.childrenResponses]?: DispatchNodeResultType[];
[DispatchNodeResponseKeyEnum.toolResponses]?: ToolRunResponseItemType;
[DispatchNodeResponseKeyEnum.assistantResponses]?: ChatItemValueItemType[];
} & 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;
};

View File

@ -0,0 +1,199 @@
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
}
]
});
};

View File

@ -1,5 +1,6 @@
import { UserGuideModule } from './system/userGuide';
import { UserInputModule } from './system/userInput';
import { SystemConfigNode } from './system/systemConfig';
import { EmptyNode } from './system/emptyNode';
import { WorkflowStart } from './system/workflowStart';
import { AiChatModule } from './system/aiChat';
import { DatasetSearchModule } from './system/datasetSearch';
import { DatasetConcatModule } from './system/datasetConcat';
@ -7,7 +8,6 @@ import { AssignedAnswerModule } from './system/assignedAnswer';
import { ClassifyQuestionModule } from './system/classifyQuestion';
import { ContextExtractModule } from './system/contextExtract';
import { HttpModule468 } from './system/http468';
import { HttpModule } from './system/abandon/http';
import { ToolModule } from './system/tools';
import { StopToolNode } from './system/stopTool';
@ -18,14 +18,15 @@ import { PluginOutputModule } from './system/pluginOutput';
import { RunPluginModule } from './system/runPlugin';
import { AiQueryExtension } from './system/queryExtension';
import type { FlowNodeTemplateType, moduleTemplateListType } from '../../module/type.d';
import { FlowNodeTemplateTypeEnum } from '../../module/constants';
import type { FlowNodeTemplateType, nodeTemplateListType } from '../type';
import { FlowNodeTemplateTypeEnum } from '../../workflow/constants';
import { lafModule } from './system/laf';
import { ifElseNode } from './system/ifElse/index';
/* app flow module templates */
export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
UserGuideModule,
UserInputModule,
SystemConfigNode,
WorkflowStart,
AiChatModule,
AssignedAnswerModule,
DatasetSearchModule,
@ -37,7 +38,8 @@ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
ContextExtractModule,
HttpModule468,
AiQueryExtension,
lafModule
lafModule,
ifElseNode
];
/* plugin flow module templates */
export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
@ -54,13 +56,15 @@ export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
ContextExtractModule,
HttpModule468,
AiQueryExtension,
lafModule
lafModule,
ifElseNode
];
/* all module */
export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
UserGuideModule,
UserInputModule,
EmptyNode,
SystemConfigNode,
WorkflowStart,
AiChatModule,
DatasetSearchModule,
DatasetConcatModule,
@ -68,7 +72,6 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
ClassifyQuestionModule,
ContextExtractModule,
HttpModule468,
HttpModule,
ToolModule,
StopToolNode,
AiChatModule,
@ -77,13 +80,14 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
PluginOutputModule,
RunPluginModule,
AiQueryExtension,
lafModule
lafModule,
ifElseNode
];
export const moduleTemplatesList: moduleTemplateListType = [
export const moduleTemplatesList: nodeTemplateListType = [
{
type: FlowNodeTemplateTypeEnum.userGuide,
label: '',
type: FlowNodeTemplateTypeEnum.systemInput,
label: 'core.module.template.System input module',
list: []
},
{
@ -115,10 +119,5 @@ export const moduleTemplatesList: moduleTemplateListType = [
type: FlowNodeTemplateTypeEnum.other,
label: '其他',
list: []
},
{
type: FlowNodeTemplateTypeEnum.systemInput,
label: 'core.module.template.System input module',
list: []
}
];

View File

@ -0,0 +1,65 @@
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
};

View File

@ -0,0 +1,17 @@
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
}
};

View File

@ -0,0 +1,105 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type';
import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import {
Input_Template_SettingAiModel,
Input_Template_Dataset_Quote,
Input_Template_History,
Input_Template_System_Prompt,
Input_Template_UserChatInput
} from '../input';
import { chatNodeSystemPromptTip } from '../tip';
import { getHandleConfig } from '../utils';
export const AiChatModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.chatNode,
templateType: FlowNodeTemplateTypeEnum.textAnswer,
flowNodeType: FlowNodeTypeEnum.chatNode,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/AI.png',
name: 'AI 对话',
intro: 'AI 大模型对话',
showStatus: true,
isTool: true,
inputs: [
Input_Template_SettingAiModel,
// --- settings modal
{
key: NodeInputKeyEnum.aiChatTemperature,
renderTypeList: [FlowNodeInputTypeEnum.hidden], // Set in the pop-up window
label: '',
value: 0,
valueType: WorkflowIOValueTypeEnum.number,
min: 0,
max: 10,
step: 1
},
{
key: NodeInputKeyEnum.aiChatMaxToken,
renderTypeList: [FlowNodeInputTypeEnum.hidden], // Set in the pop-up window
label: '',
value: 2000,
valueType: WorkflowIOValueTypeEnum.number,
min: 100,
max: 4000,
step: 50
},
{
key: NodeInputKeyEnum.aiChatIsResponseText,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
value: true,
valueType: WorkflowIOValueTypeEnum.boolean
},
{
key: NodeInputKeyEnum.aiChatQuoteTemplate,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
valueType: WorkflowIOValueTypeEnum.string
},
{
key: NodeInputKeyEnum.aiChatQuotePrompt,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
valueType: WorkflowIOValueTypeEnum.string
},
// settings modal ---
{
...Input_Template_System_Prompt,
label: 'core.ai.Prompt',
description: chatNodeSystemPromptTip,
placeholder: chatNodeSystemPromptTip
},
Input_Template_History,
{ ...Input_Template_UserChatInput, toolDescription: '用户问题' },
Input_Template_Dataset_Quote
],
outputs: [
{
id: NodeOutputKeyEnum.history,
key: NodeOutputKeyEnum.history,
label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context',
valueType: WorkflowIOValueTypeEnum.chatHistory,
type: FlowNodeOutputTypeEnum.static
},
{
id: NodeOutputKeyEnum.answerText,
key: NodeOutputKeyEnum.answerText,
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}
]
};

View File

@ -0,0 +1,36 @@
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: []
};

View File

@ -3,32 +3,33 @@ import {
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type.d';
import { FlowNodeTemplateType } from '../../type';
import {
ModuleIOValueTypeEnum,
ModuleInputKeyEnum,
FlowNodeTemplateTypeEnum
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
FlowNodeTemplateTypeEnum,
NodeOutputKeyEnum
} from '../../constants';
import {
Input_Template_SelectAIModel,
Input_Template_History,
Input_Template_Switch,
Input_Template_UserChatInput
} from '../input';
import { Output_Template_UserChatInput } from '../output';
import { Input_Template_System_Prompt } from '../input';
import { LLMModelTypeEnum } from '../../../ai/constants';
import { getHandleConfig } from '../utils';
export const ClassifyQuestionModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.classifyQuestion,
templateType: FlowNodeTemplateTypeEnum.functionCall,
flowType: FlowNodeTypeEnum.classifyQuestion,
avatar: '/imgs/module/cq.png',
flowNodeType: FlowNodeTypeEnum.classifyQuestion,
sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(true, false, true, true),
avatar: '/imgs/workflow/cq.png',
name: '问题分类',
intro: `根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题`,
showStatus: true,
inputs: [
Input_Template_Switch,
{
...Input_Template_SelectAIModel,
llmModelType: LLMModelTypeEnum.classify
@ -42,9 +43,9 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
Input_Template_History,
Input_Template_UserChatInput,
{
key: ModuleInputKeyEnum.agents,
type: FlowNodeInputTypeEnum.custom,
valueType: ModuleIOValueTypeEnum.any,
key: NodeInputKeyEnum.agents,
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.any,
label: '',
value: [
{
@ -59,31 +60,16 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
value: '其他问题',
key: 'agex'
}
],
showTargetInApp: false,
showTargetInPlugin: false
]
}
],
outputs: [
Output_Template_UserChatInput,
// custom output
{
key: 'wqre',
label: '',
type: FlowNodeOutputTypeEnum.hidden,
targets: []
},
{
key: 'sdfa',
label: '',
type: FlowNodeOutputTypeEnum.hidden,
targets: []
},
{
key: 'agex',
label: '',
type: FlowNodeOutputTypeEnum.hidden,
targets: []
id: NodeOutputKeyEnum.cqResult,
key: NodeOutputKeyEnum.cqResult,
label: '分类结果',
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}
]
};

View File

@ -0,0 +1,86 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type';
import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import { Input_Template_SelectAIModel, Input_Template_History } from '../input';
import { LLMModelTypeEnum } from '../../../ai/constants';
import { getHandleConfig } from '../utils';
export const ContextExtractModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.contentExtract,
templateType: FlowNodeTemplateTypeEnum.functionCall,
flowNodeType: FlowNodeTypeEnum.contentExtract,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/extract.png',
name: '文本内容提取',
intro: '可从文本中提取指定的数据例如sql语句、搜索关键词、代码等',
showStatus: true,
isTool: true,
inputs: [
{
...Input_Template_SelectAIModel,
llmModelType: LLMModelTypeEnum.extractFields
},
{
key: NodeInputKeyEnum.description,
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.string,
label: '提取要求描述',
description:
'给AI一些对应的背景知识或要求描述引导AI更好的完成任务。\n该输入框可使用全局变量。',
placeholder:
'例如: \n1. 当前时间为: {{cTime}}。你是一个实验室预约助手,你的任务是帮助用户预约实验室,从文本中获取对应的预约信息。\n2. 你是谷歌搜索助手,需要从文本中提取出合适的搜索词。'
},
Input_Template_History,
{
key: NodeInputKeyEnum.contextExtractInput,
renderTypeList: [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.textarea],
label: '需要提取的文本',
required: true,
valueType: WorkflowIOValueTypeEnum.string,
toolDescription: '需要检索的内容'
},
{
key: NodeInputKeyEnum.extractKeys,
renderTypeList: [FlowNodeInputTypeEnum.custom],
label: '',
valueType: WorkflowIOValueTypeEnum.any,
description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段",
value: [] // {desc: string; key: string; required: boolean; enum: string[]}[]
}
],
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
// },
{
id: NodeOutputKeyEnum.contextExtractFields,
key: NodeOutputKeyEnum.contextExtractFields,
label: '完整提取结果',
description: '一个 JSON 字符串,例如:{"name:":"YY","Time":"2023/7/2 18:00"}',
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}
]
};

View File

@ -0,0 +1,59 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type';
import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import { Input_Template_Dataset_Quote } from '../input';
import { getNanoid } from '../../../../common/string/tools';
import { getHandleConfig } from '../utils';
import { FlowNodeInputItemType } from '../../type/io.d';
export const getOneQuoteInputTemplate = (key = getNanoid()): FlowNodeInputItemType => ({
...Input_Template_Dataset_Quote,
key,
renderTypeList: [FlowNodeInputTypeEnum.custom],
description: ''
});
export const DatasetConcatModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.datasetConcatNode,
flowNodeType: FlowNodeTypeEnum.datasetConcatNode,
templateType: FlowNodeTemplateTypeEnum.other,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/concat.svg',
name: '知识库搜索引用合并',
intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。',
showStatus: false,
inputs: [
{
key: NodeInputKeyEnum.datasetMaxTokens,
renderTypeList: [FlowNodeInputTypeEnum.custom],
label: '最大 Tokens',
value: 1500,
valueType: WorkflowIOValueTypeEnum.number
},
{
key: 'customComponent',
renderTypeList: [FlowNodeInputTypeEnum.custom],
label: ''
},
getOneQuoteInputTemplate()
],
outputs: [
{
id: NodeOutputKeyEnum.datasetQuoteQA,
key: NodeOutputKeyEnum.datasetQuoteQA,
label: 'core.module.Dataset quote.label',
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.datasetQuote
}
]
};

View File

@ -0,0 +1,105 @@
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../node/constant';
import { FlowNodeTemplateType } from '../../type';
import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../constants';
import { Input_Template_UserChatInput } from '../input';
import { DatasetSearchModeEnum } from '../../../dataset/constants';
import { getHandleConfig } from '../utils';
export const Dataset_SEARCH_DESC =
'调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容';
export const DatasetSearchModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.datasetSearchNode,
templateType: FlowNodeTemplateTypeEnum.functionCall,
flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: '/imgs/workflow/db.png',
name: '知识库搜索',
intro: Dataset_SEARCH_DESC,
showStatus: true,
isTool: true,
inputs: [
{
key: NodeInputKeyEnum.datasetSelectList,
renderTypeList: [FlowNodeInputTypeEnum.selectDataset, FlowNodeInputTypeEnum.reference],
label: 'core.module.input.label.Select dataset',
value: [],
valueType: WorkflowIOValueTypeEnum.selectDataset,
list: [],
required: true
},
{
key: NodeInputKeyEnum.datasetSimilarity,
renderTypeList: [FlowNodeInputTypeEnum.selectDatasetParamsModal],
label: '',
value: 0.4,
valueType: WorkflowIOValueTypeEnum.number
},
// setting from modal
{
key: NodeInputKeyEnum.datasetMaxTokens,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
value: 1500,
valueType: WorkflowIOValueTypeEnum.number
},
{
key: NodeInputKeyEnum.datasetSearchMode,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
valueType: WorkflowIOValueTypeEnum.string,
value: DatasetSearchModeEnum.embedding
},
{
key: NodeInputKeyEnum.datasetSearchUsingReRank,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
valueType: WorkflowIOValueTypeEnum.boolean,
value: false
},
{
key: NodeInputKeyEnum.datasetSearchUsingExtensionQuery,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
valueType: WorkflowIOValueTypeEnum.boolean,
value: true
},
{
key: NodeInputKeyEnum.datasetSearchExtensionModel,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
valueType: WorkflowIOValueTypeEnum.string
},
{
key: NodeInputKeyEnum.datasetSearchExtensionBg,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
valueType: WorkflowIOValueTypeEnum.string,
value: ''
},
{
...Input_Template_UserChatInput,
toolDescription: '需要检索的内容'
}
],
outputs: [
{
id: NodeOutputKeyEnum.datasetQuoteQA,
key: NodeOutputKeyEnum.datasetQuoteQA,
label: 'core.module.Dataset quote.label',
description: '特殊数组格式,搜索结果为空时,返回空数组。',
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.datasetQuote
}
]
};

View File

@ -0,0 +1,17 @@
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: []
};

Some files were not shown because too many files have changed in this diff Show More