Compare commits

...

71 Commits

Author SHA1 Message Date
Archer
08190c2f0d fix: toolNode max tokens and toolDescription i18n (#2655)
* fix: toolNode max tokens

* fix: toolNode max tokens

* fix: workflow  tool desc i18n
2024-09-09 22:26:20 +08:00
heheer
6a85c8c2b6 fix: cq template missing chatconfig (#2654) 2024-09-09 19:37:15 +08:00
Archer
bbdab1d40e fix: entry (#2652) 2024-09-09 16:21:22 +08:00
Finley Ge
78ad2791cd chore: openapi doc generator (#2644)
* chore: extract the type and comment from apis

* chore: template code

* feat: openapi

* pref: openapi generator. send into public/openapi folder
2024-09-09 15:43:09 +08:00
Archer
5f3c8e9046 Fix: workflow init status (#2649)
* i18n

* fix: entry
2024-09-09 15:37:20 +08:00
papapatrick
30057f01a6 fix: workflow i18n (#2645)
* fix: workflow i18n

* i18n completion
2024-09-09 14:36:35 +08:00
Archer
3ea185315d fix: workflow clear repeat check run (#2646) 2024-09-09 14:14:32 +08:00
Finley Ge
a1ae08f62b perf: logs, auth root as super admin, etc (#2615)
* chore: usePagination hook type

* feat: chat log show outlinkuid or tmb avatar and name

* fix: ts error for pagination

* feat: auth root
2024-09-09 10:05:18 +08:00
Archer
91ec895fd2 fix: oauth (#2640)
* fix: oauth

* remove log

* fix: oauth dispatch
2024-09-08 20:56:33 +08:00
xianlezheng
1a33642635 Fixs:当最后一条数据因大模型没返回数据时导致调试时前端报错。 (#2637)
在lastMessageValue取值时需要提前判断空值。

Co-authored-by: zhengxianle <nopanic@ilikejobs.com>
2024-09-08 15:26:05 +08:00
archer
e9681c8ed5 log 2024-09-08 15:03:29 +08:00
imgbot[bot]
69ff65973f [ImgBot] Optimize images (#2639)
*Total -- 6,985.44kb -> 4,501.25kb (35.56%)

/python/sensevoice/app/iic/SenseVoiceSmall/fig/inference.png -- 935.23kb -> 292.81kb (68.69%)
/python/sensevoice/app/iic/SenseVoiceSmall/fig/asr_results.png -- 238.19kb -> 76.62kb (67.83%)
/python/sensevoice/app/iic/SenseVoiceSmall/fig/sensevoice.png -- 879.78kb -> 332.45kb (62.21%)
/python/sensevoice/app/iic/SenseVoiceSmall/fig/ser_table.png -- 318.12kb -> 145.67kb (54.21%)
/docSite/assets/imgs/wechat6.png -- 208.98kb -> 119.19kb (42.97%)
/docSite/assets/imgs/collection-tags-2.png -- 83.02kb -> 52.57kb (36.67%)
/.github/imgs/intro3.png -- 258.74kb -> 167.94kb (35.09%)
/python/sensevoice/app/iic/speech_fsmn_vad_zh-cn-16k-common-pytorch/fig/struct.png -- 27.26kb -> 17.81kb (34.66%)
/.github/imgs/intro1.png -- 259.12kb -> 173.33kb (33.11%)
/docSite/assets/imgs/fileinpu-2.png -- 214.61kb -> 147.20kb (31.41%)
/.github/imgs/intro4.png -- 227.64kb -> 158.71kb (30.28%)
/docSite/assets/imgs/questionGuide.png -- 38.89kb -> 27.95kb (28.13%)
/python/sensevoice/app/iic/SenseVoiceSmall/fig/aed_figure.png -- 115.93kb -> 85.46kb (26.28%)
/.github/imgs/intro2.png -- 370.64kb -> 273.45kb (26.22%)
/docSite/assets/imgs/offiaccount-9.png -- 38.62kb -> 28.89kb (25.18%)
/docSite/assets/imgs/collection-tags-3.png -- 125.71kb -> 98.27kb (21.83%)
/docSite/assets/imgs/offiaccount-3.png -- 90.57kb -> 71.85kb (20.66%)
/docSite/assets/imgs/feishu-bot-4.png -- 85.73kb -> 68.44kb (20.17%)
/docSite/assets/imgs/feishu-bot-2.png -- 92.49kb -> 73.94kb (20.05%)
/docSite/assets/imgs/offiaccount-1.png -- 99.70kb -> 79.77kb (19.98%)
/docSite/assets/imgs/feishu-bot-1.png -- 154.50kb -> 126.89kb (17.87%)
/docSite/assets/imgs/feishu-bot-6.png -- 160.72kb -> 133.59kb (16.88%)
/docSite/assets/imgs/fileinpu-6.jpg -- 179.04kb -> 150.60kb (15.88%)
/docSite/assets/imgs/feishu-bot-8.png -- 43.64kb -> 36.83kb (15.61%)
/docSite/assets/imgs/offiaccount-7.png -- 73.88kb -> 62.58kb (15.29%)
/python/sensevoice/app/iic/SenseVoiceSmall/fig/ser_figure.png -- 194.25kb -> 167.12kb (13.97%)
/docSite/assets/imgs/feishu-bot-5.png -- 169.50kb -> 146.65kb (13.48%)
/docSite/assets/imgs/offiaccount-8.png -- 129.99kb -> 114.37kb (12.02%)
/docSite/assets/imgs/offiaccount-6.png -- 131.04kb -> 115.30kb (12.01%)
/docSite/assets/imgs/feishu-bot-3.png -- 165.20kb -> 145.86kb (11.71%)
/docSite/assets/imgs/offiaccount-4.png -- 158.75kb -> 140.69kb (11.38%)
/docSite/assets/imgs/feishu-bot-7.png -- 95.10kb -> 84.29kb (11.37%)
/docSite/assets/imgs/offiaccount-5.png -- 158.34kb -> 140.59kb (11.21%)
/docSite/assets/imgs/offiaccount-2.png -- 163.30kb -> 145.59kb (10.84%)
/docSite/assets/imgs/gpt-translate-example.png -- 299.24kb -> 297.98kb (0.42%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2024-09-08 10:23:27 +08:00
Archer
52ac445557 fix: mobild sso login (#2636)
* fix: mobild sso login

* feat: max call tool times
2024-09-07 18:24:38 +08:00
Archer
d45cb2f84a Update 4810.md (#2634) 2024-09-06 17:29:23 +08:00
Archer
1cb71c6bfb 4.8.10 perf (#2633)
* perf: i18n init

* i18n

* 4.8.10 doc

* doc
2024-09-06 17:22:24 +08:00
papapatrick
fb59b60761 addition i18n (#2631) 2024-09-06 16:57:47 +08:00
Archer
9334a0dcf6 4.8.10 perf (#2630)
* perf: i18n init

* i18n

* fix: user select end status

* fix: interactive workflow

* fix: restart chat

* fix: oauth login
2024-09-06 15:45:02 +08:00
Archer
c614f8b9ca Perf: i18n change and captcha code. (#2625)
* perf: send captcha check

* perf: back router

* perf: i18n init

* perf: ui

* i18n

* perf: ui duration
2024-09-05 23:01:12 +08:00
heheer
478386c612 chore: template author name & icon border radius (#2624) 2024-09-05 20:44:31 +08:00
papapatrick
dfcffc7fc1 I18n: Completed i18n&&proofread some translations (#2619)
* i18n-1

* i18n: Completed the remaining parts of i18n and proofread some translations

* i18n: add default lang&&add app template i18n
2024-09-05 17:29:36 +08:00
Finley Ge
b4238257b6 feat: dynamic website crawler (#2609)
* feat: cheerio returns cherrio.load for pro version website sync

* chore: rename
2024-09-05 14:49:57 +08:00
Archer
38f47956cd fix: ts (#2621) 2024-09-05 14:04:45 +08:00
Archer
7fed4d697f perf: captcha code (#2620)
* perf:  captcha code

* perf: dockerfile
2024-09-05 13:41:11 +08:00
EthanD4869
5ed89130ef add sensevoice & cosevoice (#2562)
Signed-off-by: EthanD <EthanD4869@gmail.com>
Co-authored-by: EthanD <EthanD4869@gmail.com>
2024-09-05 13:36:11 +08:00
Archer
3671e55001 4.8.10 test (#2618)
* perf: menu arrow ui

* perf: http node placeholder

* perf: http node form input

* perf: chatBox performance
2024-09-05 11:49:13 +08:00
papapatrick
3bcc3430fb feat: add captcha (#2613)
* feat: captcha

* add borderRadius

* code perf
2024-09-05 11:46:51 +08:00
heheer
d6233cd7b1 fix: add http params focus & ui (#2611) 2024-09-04 13:37:29 +08:00
Archer
64708ea424 Update userselect ux (#2610)
* perf: user select ux and api

* perf: http variables replace code

* perf: http variables replace code

* perf: chat box question guide adapt interactive

* remove comment
2024-09-04 11:11:08 +08:00
heheer
85a11d08b2 feat: http body type & http input support editor variable (#2603)
* feat: http body type & http input support editor variable

* fix type

* chore: code

* code
2024-09-03 23:43:21 +08:00
papapatrick
a7569037fe perf: modal add size props&menu add menuItemStyles (#2600)
* perf: modal add size props&menu add menuItemStyles

* delete minH

* mobile adaptation

* 优化部分代码
2024-09-03 14:56:09 +08:00
Archer
4726034344 Update official_account.md (#2604) 2024-09-03 14:41:46 +08:00
Archer
9a57e94b79 4.8.10 test (#2601)
* perf: workflow children run params

* feat: workflow userId

* fix: ui size

* perf: Markdown whitespace and ai images split

* fix: openai sdk ts
2024-09-03 13:43:56 +08:00
Archer
761e35c226 4.8.10 workflow perf (#2596)
* perf: run plugin variables init

* perf: init free plan

* perf: dataset data ui

* perf: workflow theme

* perf: plugin input modal ui

* perf: workflow dispatch

* fix: account ui

* feat: 4810 doc
2024-09-03 09:56:33 +08:00
papapatrick
5ebe0017a0 perf: user default avatar (#2594)
* perf: user default avatar

* refactor: 修改文件路径
2024-09-02 21:04:49 +08:00
papapatrick
036097243a perf: workflow&plugins json config import and export (#2592) 2024-09-02 15:05:58 +08:00
heheer
84de95d294 fix: plugin input type options & save button (#2590) 2024-09-02 13:06:48 +08:00
papapatrick
fdab383b26 Style-dataset-2.5 (#2580)
* style: dataset detail page 2.5

* fix merge error

* fix: flash bug

* fix: build error

* revert: 滚动变回分页
2024-09-02 10:00:55 +08:00
Archer
060492dbf7 feat: admin add custom plugin (#2582)
* feat: admin add custom plugin

* refresh plugins

* plugin input box ui

* fix: run plugin varialbes error

* perf: comment

* fix: ts
2024-08-30 22:45:35 +08:00
heheer
9d5fd24085 feat: plugin input type add select and custom var (#2571)
* feat: plugin input type add select and custom var

* fix

* fix ui

* fix

* fix
2024-08-30 18:03:04 +08:00
heheer
903f39fe17 feat: add plugin instruction config (#2579)
* feat: add plugin instruction config

* fix build
2024-08-30 17:12:57 +08:00
Archer
2ef98c24be 4.8.10 test (#2578)
* fix: auth error

* perf: refresh members

* fix: variable run

* fix: runtime check

* fix: dataset info show
2024-08-30 10:27:07 +08:00
Archer
6d00f73e91 4.8.10 test (#2573)
* feat: more debug response

* fix: debug edge status

* perf: doc

* fix: workflow edge check

* perf: i18n

* package.json

* perf: markdown mask
2024-08-29 23:19:39 +08:00
Archer
813eaacfd0 4.8.10 fix (#2572)
* fix: circle workflow response modal

* perf: workflow runtime check
2024-08-29 18:00:56 +08:00
Archer
322ca757af 4.8.10 test (#2568)
* perf: i18n perf

* fix: detail=fasle response

* fix: dataset tag load repeat

* feat :doc

* perf: rename fun

* code comment
2024-08-29 14:51:34 +08:00
heheer
a177a302d4 fix: plugin input (#2567) 2024-08-29 14:19:16 +08:00
heheer
034108c218 fix: global variable during debug & variable update textarea rerender (#2553)
* fix: global variable during debug & variable update textarea rerender

* update var node use prompt editor

* fix
2024-08-29 14:09:20 +08:00
heheer
0632dfed80 fix: tags manage (#2556)
* fix: tags manage

* fix infinite invoke
2024-08-29 12:04:45 +08:00
居里栈栈
6c16fa9166 Fix: Custom delimiter does not take effect when document type is link (#2565)
Co-authored-by: 勤劳上班的卑微小张 <jiazhan.zhang@ggimage.com>
2024-08-29 11:16:17 +08:00
papapatrick
ac4854a47b template add i18n (#2558)
* template add i18n

* add English translation
2024-08-28 21:33:03 +08:00
Archer
b9a6b71fe9 perf: Dataset new ui (#2555)
* perf: dataset detail ui

* fix: collection tag modal

* perf: data card support markdown

* fix :ts
2024-08-28 12:48:55 +08:00
papapatrick
aba50e958e style: 知识库二期 (#2554) 2024-08-28 12:17:45 +08:00
Archer
52cbfeace3 feat: custom read file service (#2548) 2024-08-28 11:35:06 +08:00
papapatrick
bebf565c06 style: dataset detail page style refactor (#2501)
* style: dataset detail page style refactor

* remove px

* remove py px px

* change shadow

* style: 2期联调结束

* 优化部分代码
2024-08-28 10:17:49 +08:00
Archer
c9bb39d802 4.8.10 test (#2539)
* fix: i18n

* fix: null value

* fix: workflow refresh variables

* perf: copy data

* doc

* perf: run app code

* perf: variable store

* update doc

* perf: pay ui

* fix: log header ui

* fix: log header ui
2024-08-27 19:48:42 +08:00
papapatrick
454a479fd8 style: pay page perf (#2535)
* style: pay page perf

* perf: package status logic && add pay text
2024-08-27 18:56:08 +08:00
heheer
d057ad3a45 fix: global variable persist during api calls (#2544) 2024-08-27 18:23:15 +08:00
heheer
a206d77287 fix: run app node display (#2546) 2024-08-27 18:16:35 +08:00
不吃辣不喝酒
14bd1b5404 fix: toolCall.function.arguments maybe undefined (#2545)
当arg===undefined时,会导致 currentTool.function.arguments += arg; 字符串拼接出问题。
2024-08-27 17:41:59 +08:00
Archer
450167c951 App run node update (#2542)
* feat(workflow): allow apps to be invoked like plugins (#2521)

* feat(workflow): allow apps to be invoked like plugins

* fix type

* Encapsulate SSE response methods (#2530)

* perf: sse response fn

* perf: sse response

* fix: ts

* perf: not ssl copy

* perf: myselect auto scroll

* perf: run app code

* fix: app plugin (#2538)

---------

Co-authored-by: heheer <heheer@sealos.io>
2024-08-27 16:43:19 +08:00
heheer
67445b40bc fix: global variable key repeat & value type (#2540) 2024-08-27 16:04:00 +08:00
heheer
d3731d221a fix: change workflow start node output when change file config (#2527) 2024-08-27 13:47:26 +08:00
Archer
f6e2d13e21 fix: load member list (#2536)
* fix: load member list

* fix: extract field type error

* fix: workflow runtime error

* fix: ts
2024-08-27 12:07:57 +08:00
Carson Yang
77e6cf4157 Docs: update baseURL (#2533)
Signed-off-by: Carson Yang <yangchuansheng33@gmail.com>
2024-08-27 09:47:20 +08:00
heheer
fd3f32d083 fix welcome text rerender & add copyright (#2525) 2024-08-26 16:03:15 +08:00
Archer
f7544ea47b 4.8.10 test fix (#2517)
* fix: chat config load error

* prompt perf
2024-08-26 14:26:45 +08:00
Finley Ge
a1a9a0b463 chore: add i18n query script (#2518) 2024-08-26 12:31:30 +08:00
Finley Ge
dbfe1fca31 fix: fix i18n (#2516) 2024-08-26 12:23:19 +08:00
Archer
94f3b7f2d6 conversion points (#2514) 2024-08-26 10:48:02 +08:00
Archer
22a0f6bcfa perf: plan tip (#2513) 2024-08-26 10:43:52 +08:00
Archer
c1d08c0ccc New pay (#2484) (#2510)
* New pay (#2484)

* remove sub status

* feat: new pay mode

* fix: ts

* limit
2024-08-26 09:52:09 +08:00
Archer
a4c19fbd0a 4810 doc (#2504)
* 4810 doc

* doc

* feishu doc

* 4811 文档
2024-08-26 01:00:11 +08:00
472 changed files with 14608 additions and 12158 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 KiB

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 159 KiB

View File

@@ -13,7 +13,7 @@
"js",
"ts"
],
"i18n-ally.keystyle": "nested",
"i18n-ally.keystyle": "flat",
"i18n-ally.sortKeys": true,
"i18n-ally.keepFulfilled": false,
"i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译其他语言文件的变量和内容

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 KiB

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

After

Width:  |  Height:  |  Size: 119 KiB

View File

@@ -86,3 +86,12 @@ Verification Token 默认生成的这个 Token 用于校验来源。但我们使
然后就可以在工作台里找到你的机器人啦。接下来就是把机器人拉进群组,或者单独与它对话。
![图片](/imgs/feishu-bot-9.png)
## FAQ
### 发送了消息,没响应
1. 检查飞书机器人回调地址、权限等是否正确。
2. 查看 FastGPT 对话日志,是否有对应的提问记录
3. 如果有记录,飞书没回应,则是没给机器人开权限。
4. 如果没记录,则可能是应用运行报错了,可以先试试最简单的机器人。(飞书机器人无法输入全局变量、文件、图片内容)

View File

@@ -62,6 +62,23 @@ weight: 113
34.142.157.52
```
国内版用户fastgpt.cn)可以填写下面的 IP 白名单:
```
47.97.59.172
121.43.108.48
121.41.75.88
121.41.178.7
121.40.65.187
121.196.235.183
120.55.195.90
120.55.193.112
120.26.229.115
112.124.41.79
101.37.205.32
47.98.190.173
```
## 4. 获取AES Key选择加密方式
![图片](/imgs/offiaccount-5.png)

View File

@@ -1,5 +1,5 @@
---
title: 'V4.8.10(进行中)'
title: 'V4.8.10'
description: 'FastGPT V4.8.10 更新说明'
icon: 'upgrade'
draft: false
@@ -11,37 +11,94 @@ weight: 814
### 1. 做好数据备份
### 2. 更新商业版环境变量
### 2. 商业版 —— 修改环境变量
1. 需要给`fastgpt-pro`镜像,增加沙盒的环境变量:`SANDBOX_URL=http://xxxxx:3000`
2.两个镜像增加环境变量,以便更好的存储系统日志:
2.`fastgpt-pro`镜像和`fastgpt`镜像增加环境变量,以便更好的存储系统日志:
```
LOG_LEVEL=debug
STORE_LOG_LEVEL=warn
```
### 3. 修改镜像tag
- 更新 FastGPT 镜像 tag: v4.8.10
- 更新 FastGPT 商业版镜像 tag: v4.8.10
- Sandbox 镜像,可以不更新
## 4. 执行初始化
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`{{host}} 替换成**FastGPT 域名**。
```bash
curl --location --request POST 'https://{{host}}/api/admin/initv4810' \
--header 'rootkey: {{rootkey}}' \
--header 'Content-Type: application/json'
```
1. 初始化发布记录版本标记
2. 初始化开票记录
-------
## V4.8.10 更新说明
1. 新增 - 模板市场
2. 新增 - 工作流节点拖动自动对齐吸附
3. 新增 - 用户选择节点Debug 模式暂未支持)
4. 新增 - 工作流撤销和重做
5. 新增 - 工作流本次编辑记录,取代自动保存
6. 新增 - 工作流版本支持重命名
7. 商业版新增 - 飞书机器人接入
8. 商业版新增 - 公众号接入接入
9. 商业版新增 - 自助开票申请
10. 商业版新增 - SSO 定制
11. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态
12. 优化 - 节点选择,避免切换 tab 时候path 加载报错
13. 优化 - 最新 React Markdown 组件,支持 Base64 图片
14. 优化 - 知识库列表 UI
15. 优化 - 支持无网络配置情况下运行
16. 修复 - Prompt 模式调用工具stream=false 模式下,会携带 0: 开头标记
17. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情
18. 修复 - 选择 Milvus 部署时,无法导出知识库。
19. 修复 - 创建 APP 副本,无法复制系统配置
20. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。
完整内容请见:[4.8.10 release](https://github.com/labring/FastGPT/releases/tag/v4.8.10)
1. 新增 - 模板市场。
2. 新增 - 工作流节点拖动自动对齐吸附。
3. 新增 - 用户选择节点Debug 模式暂未支持)。
4. 新增 - 工作流增加 uid 全局变量。
5. 新增 - 工作流撤销和重做。
6. 新增 - 工作流本次编辑记录,取代自动保存。
7. 新增 - 工作流版本支持重命名。
8. 新增 - 工作流的“应用调用”节点弃用,迁移成单独节点,与插件使用方式相同,同时可以传递全局变量和用户上传的文件。
9. 新增 - 插件增加使用说明配置
10. 新增 - 插件自定义输入支持单选框
11. 新增 - HTTP 节点支持 text/plain 模式
12. 新增 - HTTP模块支持超时配置、支持更多的 Body 类型params 和 headers 支持新的变量选择模式
13. 新增 - 工作流导出导入,支持直接导出和导入 JSON 文件,便于交流
14. 新增 - 发送验证码安全校验
15. 商业版新增 - 飞书机器人接入
16. 商业版新增 - 公众号接入接入。
17. 商业版新增 - 自助开票申请
18. 商业版新增 - SSO 定制。
19. 优化 - 工作流循环校验,避免 skip 循环空转。同时支持分支完全并发执行。
20. 优化 - 工作流嵌套执行,参数可能存在的污染问题。
21. 优化 - 部分全局变量,增加数据类型约束。
22. 优化 - 节点选择,避免切换 tab 时候path 加载报错。
23. 优化 - 最新 React Markdown 组件,支持 Base64 图片。
24. 优化 - 对话框性能问题。
25. 优化 - 单选框打开后自动滚动到选中的位置。
26. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。
27. 优化 - SSE 响应代码优化。
28. 优化 - 无 SSL 证书情况下,优化复制。
29. 优化 - 知识库列表 UI。
30. 优化 - 知识库详情页 UI。
31. 优化 - 支持无网络配置情况下运行。
32. 优化 - 调整.env.template关于mongodb的说明使得更易于理解。
33. 优化 - 新的支付模式。
34. 优化 - 用户默认头像。
35. 修复 - Prompt 模式调用工具stream=false 模式下,会携带 0: 开头标记。
36. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。
37. 修复 - 选择 Milvus 部署时,无法导出知识库。
38. 修复 - 创建 APP 副本,无法复制系统配置。
39. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。
40. 修复 - 内容提取的数据类型与输出数据类型未一致。
41. 修复 - 工作流运行时间统计错误。
42. 修复 - stream 模式下,工具调用有可能出现 undefined。
43. 修复 - reranker typo。
44. 修复 - home host typo。
45. 修复 - i18n display。
46. 修复 - 全局变量可重复定义 key。
47. 修复 - 全局变量在 Debug 模式下不可持久化。
48. 修复 - 全局变量在 API 中无法持久化。
49. 修复 - OpenAPIdetail=false模式下不应该返回 tool 调用结果,仅返回文字。(可解决 cow 不适配问题)。
50. 修复 - 知识库标签重复加载。
51. 修复 - 网络链接重新获取时,自定义分割符不生效。
52. 修复 - 插件运行时,会传递额外的全局变量,可能造成插件内变量污染。
53. 文档 - qa docs。
54. 文档 - Update feishu.md。
55. 文档 - update baseURL。

View File

@@ -0,0 +1,24 @@
---
title: 'V4.8.11(进行中)'
description: 'FastGPT V4.8.11 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 813
---
## 更新指南
### 1. 做好数据备份
-------
## V4.8.11 更新预告
1.
2. 新增 - 工作流循环执行节点。
3. 新增 - 工作流用户表单输入节点。
4. 新增 - 插件输出,支持指定某些字段为工具调用结果。
5. 新增 - 插件支持配置使用引导、全局变量和文件输入。
6. 新增 - 简易模式支持新的版本管理方式。
7. 新增 - 聊天记录滚动加载,不再只加载 30 条。

View File

@@ -1,4 +1,4 @@
baseURL = "https://doc.fastgpt.in"
baseURL = "https://doc.tryfastgpt.ai"
languageCode = "en-GB"
contentDir = "content"
enableEmoji = true

0
fastgpt@4.0 Normal file
View File

View File

@@ -10,7 +10,7 @@
"postinstall": "sh ./scripts/postinstall.sh",
"initIcon": "node ./scripts/icon/init.js",
"previewIcon": "node ./scripts/icon/index.js",
"checkI18n": "node ./scripts/i18n/delete-unused-keys.js"
"api:gen": "tsc ./scripts/openapi/index.ts && node ./scripts/openapi/index.js && npx @redocly/cli build-docs ./scripts/openapi/openapi.json -o ./projects/app/public/openapi/index.html"
},
"devDependencies": {
"@chakra-ui/cli": "^2.4.1",
@@ -30,4 +30,4 @@
"node": ">=18.16.0",
"pnpm": ">=9.0.0"
}
}
}

View File

@@ -1,15 +1,15 @@
import { PromptTemplateItem } from '../type.d';
import { i18nT } from '../../../../web/i18n/utils';
export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
{
title: '标准模板',
desc: '标准提示词,用于结构不固定的知识库。',
title: i18nT('app:template.standard_template'),
desc: i18nT('app:template.standard_template_des'),
value: `{{q}}
{{a}}`
},
{
title: '问答模板',
desc: '适合 QA 问答结构的知识库可以让AI较为严格的按预设内容回答',
title: i18nT('app:template.qa_template'),
desc: i18nT('app:template.qa_template_des'),
value: `<Question>
{{q}}
</Question>
@@ -18,14 +18,14 @@ export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
</Answer>`
},
{
title: '标准严格模板',
desc: '在标准模板基础上,对模型的回答做更严格的要求。',
title: i18nT('app:template.standard_strict'),
desc: i18nT('app:template.standard_strict_des'),
value: `{{q}}
{{a}}`
},
{
title: '严格问答模板',
desc: '在问答模板基础上,对模型的回答做更严格的要求。',
title: i18nT('app:template.hard_strict'),
desc: i18nT('app:template.hard_strict_des'),
value: `<Question>
{{q}}
</Question>
@@ -37,7 +37,7 @@ export const Prompt_QuoteTemplateList: PromptTemplateItem[] = [
export const Prompt_QuotePromptList: PromptTemplateItem[] = [
{
title: '标准模板',
title: i18nT('app:template.standard_template'),
desc: '',
value: `使用 <Data></Data> 标记中的内容作为你的知识:
@@ -55,7 +55,7 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
问题:"""{{question}}"""`
},
{
title: '问答模板',
title: i18nT('app:template.qa_template'),
desc: '',
value: `使用 <QA></QA> 标记中的问答对进行回答。
@@ -72,7 +72,7 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
问题:"""{{question}}"""`
},
{
title: '标准严格模板',
title: i18nT('app:template.standard_strict'),
desc: '',
value: `忘记你已有的知识,仅使用 <Data></Data> 标记中的内容作为你的知识:
@@ -94,7 +94,7 @@ export const Prompt_QuotePromptList: PromptTemplateItem[] = [
问题:"""{{question}}"""`
},
{
title: '严格问答模板',
title: i18nT('app:template.hard_strict'),
desc: '',
value: `忘记你已有的知识,仅使用 <QA></QA> 标记中的问答对进行回答。

View File

@@ -4,6 +4,7 @@ export const Prompt_AgentQA = {
- 答案需详细完整,尽可能保留原文描述,可以适当扩展答案描述。
- 答案可以包含普通文字、链接、代码、表格、公示、媒体链接等 Markdown 元素。
- 最多提出 50 个问题。
- 生成的问题和答案和源文本语言相同。
`,
fixedText: `请按以下格式整理学习成果:
<Context>

View File

@@ -1,7 +1,11 @@
import type { FlowNodeTemplateType, StoreNodeItemType } from '../workflow/type/node';
import { AppTypeEnum } from './constants';
import { PermissionTypeEnum } from '../../support/permission/constant';
import { NodeInputKeyEnum, VariableInputEnum } from '../workflow/constants';
import {
NodeInputKeyEnum,
VariableInputEnum,
WorkflowIOValueTypeEnum
} 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';
@@ -92,6 +96,9 @@ export type AppChatConfigType = {
scheduledTriggerConfig?: AppScheduledTriggerConfigType;
chatInputGuide?: ChatInputGuideConfigType;
fileSelectConfig?: AppFileSelectConfigType;
// plugin
instruction?: string;
};
export type SettingAIDataType = {
model: string;
@@ -111,6 +118,7 @@ export type VariableItemType = {
required: boolean;
maxLen: number;
enums: { value: string }[];
valueType: WorkflowIOValueTypeEnum;
};
// tts
export type AppTTSConfigType = {

View File

@@ -118,7 +118,7 @@ export const chats2GPTMessages = ({
tool_calls
})
.concat(toolResponse);
} else if (value.text) {
} else if (value.text?.content) {
results.push({
dataId,
role: ChatCompletionRequestMessageRoleEnum.Assistant,
@@ -142,7 +142,7 @@ export const GPTMessages2Chats = (
messages: ChatCompletionMessageParam[],
reserveTool = true
): ChatItemType[] => {
return messages
const chatMessages = messages
.map((item) => {
const value: ChatItemType['value'] = [];
const obj = GPT2Chat[item.role];
@@ -151,12 +151,23 @@ export const GPTMessages2Chats = (
obj === ChatRoleEnum.System &&
item.role === ChatCompletionRequestMessageRoleEnum.System
) {
value.push({
type: ChatItemValueTypeEnum.text,
text: {
content: item.content
}
});
if (Array.isArray(item.content)) {
item.content.forEach((item) => [
value.push({
type: ChatItemValueTypeEnum.text,
text: {
content: item.text
}
})
]);
} else {
value.push({
type: ChatItemValueTypeEnum.text,
text: {
content: item.content
}
});
}
} else if (
obj === ChatRoleEnum.Human &&
item.role === ChatCompletionRequestMessageRoleEnum.User
@@ -277,6 +288,22 @@ export const GPTMessages2Chats = (
} as ChatItemType;
})
.filter((item) => item.value.length > 0);
// Merge data with the same dataId
const result = chatMessages.reduce((result: ChatItemType[], currentItem) => {
const lastItem = result[result.length - 1];
if (lastItem && lastItem.dataId === currentItem.dataId && lastItem.obj === currentItem.obj) {
// @ts-ignore
lastItem.value = lastItem.value.concat(currentItem.value);
} else {
result.push(currentItem);
}
return result;
}, []);
return result;
};
export const chatValue2RuntimePrompt = (value: ChatItemValueItemType[]): RuntimeUserPromptType => {

View File

@@ -151,6 +151,7 @@ export type ChatHistoryItemType = HistoryItemType & {
/* ------- response data ------------ */
export type ChatHistoryItemResType = DispatchNodeResponseType & {
nodeId: string;
id: string;
moduleType: FlowNodeTypeEnum;
moduleName: string;
};

View File

@@ -12,17 +12,17 @@ export const DatasetTypeMap = {
collectionLabel: 'common.Folder'
},
[DatasetTypeEnum.dataset]: {
icon: 'core/dataset/commonDataset',
icon: 'core/dataset/commonDatasetOutline',
label: 'common_dataset',
collectionLabel: 'common.File'
},
[DatasetTypeEnum.websiteDataset]: {
icon: 'core/dataset/websiteDataset',
icon: 'core/dataset/websiteDatasetOutline',
label: 'website_dataset',
collectionLabel: 'common.Website'
},
[DatasetTypeEnum.externalFile]: {
icon: 'core/dataset/externalDataset',
icon: 'core/dataset/externalDatasetOutline',
label: 'external_file',
collectionLabel: 'common.File'
}

View File

@@ -51,6 +51,7 @@ export type DatasetCollectionSchemaType = {
chunkSize: number;
chunkSplitter?: string;
qaPrompt?: string;
ocrParse?: boolean;
tags?: string[];

View File

@@ -52,6 +52,9 @@ export enum NodeInputKeyEnum {
scheduleTrigger = 'scheduleTrigger',
chatInputGuide = 'chatInputGuide',
// plugin config
instruction = 'instruction',
// entry
userChatInput = 'userChatInput',
inputFiles = 'inputFiles',
@@ -105,6 +108,8 @@ export enum NodeInputKeyEnum {
httpMethod = 'system_httpMethod',
httpParams = 'system_httpParams',
httpJsonBody = 'system_httpJsonBody',
httpFormBody = 'system_httpFormBody',
httpContentType = 'system_httpContentType',
httpTimeout = 'system_httpTimeout',
abandon_httpUrl = 'url',
@@ -128,6 +133,7 @@ export enum NodeInputKeyEnum {
// read files
fileUrlList = 'fileUrlList',
// user select
userSelectOptions = 'userSelectOptions'
}
@@ -213,3 +219,13 @@ export enum RuntimeEdgeStatusEnum {
export const VARIABLE_NODE_ID = 'VARIABLE_NODE_ID';
export const DYNAMIC_INPUT_REFERENCE_KEY = 'DYNAMIC_INPUT_REFERENCE_KEY';
// http node body content type
export enum ContentTypes {
none = 'none',
formData = 'form-data',
xWwwFormUrlencoded = 'x-www-form-urlencoded',
json = 'json',
xml = 'xml',
raw = 'raw-text'
}

View File

@@ -1,5 +1,5 @@
import { WorkflowIOValueTypeEnum } from '../constants';
import { i18nT } from '../../../../web/i18n/utils';
export enum FlowNodeInputTypeEnum { // render ui
reference = 'reference', // reference to other node output
input = 'input', // one line input
@@ -15,6 +15,7 @@ export enum FlowNodeInputTypeEnum { // render ui
// special input
selectApp = 'selectApp',
customVariable = 'customVariable',
// ai model select
selectLLMModel = 'selectLLMModel',
@@ -44,7 +45,7 @@ export const FlowNodeInputMap: Record<
icon: 'core/workflow/inputType/numberInput'
},
[FlowNodeInputTypeEnum.select]: {
icon: 'core/workflow/inputType/input'
icon: 'core/workflow/inputType/option'
},
[FlowNodeInputTypeEnum.switch]: {
icon: 'core/workflow/inputType/switch'
@@ -79,8 +80,11 @@ export const FlowNodeInputMap: Record<
[FlowNodeInputTypeEnum.hidden]: {
icon: 'core/workflow/inputType/select'
},
[FlowNodeInputTypeEnum.customVariable]: {
icon: 'core/workflow/inputType/customVariable'
},
[FlowNodeInputTypeEnum.custom]: {
icon: 'core/workflow/inputType/select'
icon: 'core/workflow/inputType/custom'
}
};
@@ -94,6 +98,7 @@ export enum FlowNodeOutputTypeEnum {
export enum FlowNodeTypeEnum {
emptyNode = 'emptyNode',
systemConfig = 'userGuide',
pluginConfig = 'pluginConfig',
globalVariable = 'globalVariable',
workflowStart = 'workflowStart',
chatNode = 'chatNode',
@@ -106,6 +111,7 @@ export enum FlowNodeTypeEnum {
contentExtract = 'contentExtract',
httpRequest468 = 'httpRequest468',
runApp = 'app',
appModule = 'appModule',
pluginModule = 'pluginModule',
pluginInput = 'pluginInput',
pluginOutput = 'pluginOutput',
@@ -161,23 +167,23 @@ export const FlowValueTypeMap = {
value: WorkflowIOValueTypeEnum.any
},
[WorkflowIOValueTypeEnum.chatHistory]: {
label: '历史记录',
label: i18nT('common:core.chat.History'),
value: WorkflowIOValueTypeEnum.chatHistory
},
[WorkflowIOValueTypeEnum.datasetQuote]: {
label: '知识库引用',
label: i18nT('common:core.workflow.Dataset quote'),
value: WorkflowIOValueTypeEnum.datasetQuote
},
[WorkflowIOValueTypeEnum.selectApp]: {
label: '选择应用',
label: i18nT('common:plugin.App'),
value: WorkflowIOValueTypeEnum.selectApp
},
[WorkflowIOValueTypeEnum.selectDataset]: {
label: '选择知识库',
label: i18nT('common:core.chat.Select dataset'),
value: WorkflowIOValueTypeEnum.selectDataset
},
[WorkflowIOValueTypeEnum.dynamic]: {
label: '动态输入',
label: i18nT('common:core.workflow.dynamic_input'),
value: WorkflowIOValueTypeEnum.dynamic
}
};

View File

@@ -22,6 +22,7 @@ export enum DispatchNodeResponseKeyEnum {
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
rewriteHistories = 'rewriteHistories', // If have the response, workflow histories will be rewrite
interactive = 'INTERACTIVE' // is interactive
}

View File

@@ -2,9 +2,9 @@ import { ChatNodeUsageType } from '../../../support/wallet/bill/type';
import {
ChatItemType,
UserChatItemValueItemType,
ChatItemValueItemType,
ToolRunResponseItemType,
NodeOutputItemType
NodeOutputItemType,
AIChatItemValueItemType
} from '../../chat/type';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../type/io.d';
import { StoreNodeItemType } from '../type/node';
@@ -19,16 +19,22 @@ import { RuntimeNodeItemType } from '../runtime/type';
import { RuntimeEdgeItemType } from './edge';
import { ReadFileNodeResponse } from '../template/system/readFiles/type';
import { UserSelectOptionType } from '../template/system/userSelect/type';
import { WorkflowResponseType } from '../../../../service/core/workflow/dispatch/type';
/* workflow props */
export type ChatDispatchProps = {
res?: NextApiResponse;
requestOrigin?: string;
mode: 'test' | 'chat' | 'debug';
teamId: string;
tmbId: string;
user: UserModelSchema;
app: AppDetailType | AppSchema;
runningAppInfo: {
id: string; // May be the id of the system plug-in (cannot be used directly to look up the table)
teamId: string;
tmbId: string; // App tmbId
};
uid: string; // Who run this workflow
chatId?: string;
responseChatItemId?: string;
histories: ChatItemType[];
@@ -36,9 +42,9 @@ export type ChatDispatchProps = {
query: UserChatItemValueItemType[]; // trigger query
chatConfig: AppSchema['chatConfig'];
stream: boolean;
detail: boolean; // response detail
maxRunTimes: number;
isToolCall?: boolean;
workflowStreamResponse?: WorkflowResponseType;
};
export type ModuleDispatchProps<T> = ChatDispatchProps & {
@@ -49,10 +55,12 @@ export type ModuleDispatchProps<T> = ChatDispatchProps & {
};
export type SystemVariablesType = {
userId: string;
appId: string;
chatId?: string;
responseChatItemId?: string;
histories: ChatItemType[];
cTime: string;
};
/* node props */
@@ -68,7 +76,7 @@ export type RuntimeNodeItemType = {
inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[];
pluginId?: string;
pluginId?: string; // workflow id / plugin id
};
export type PluginRuntimeType = {
@@ -95,6 +103,8 @@ export type DispatchNodeResponseType = {
error?: Record<string, any>;
customInputs?: Record<string, any>;
customOutputs?: Record<string, any>;
nodeInputs?: Record<string, any>;
nodeOutputs?: Record<string, any>;
// bill
tokens?: number;
@@ -158,15 +168,19 @@ export type DispatchNodeResponseType = {
// user select
userSelectResult?: string;
// update var
updateVarResult?: any[];
};
export type DispatchNodeResultType<T> = {
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[];
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]?: ChatNodeUsageType[]; // Node total usage
[DispatchNodeResponseKeyEnum.childrenResponses]?: DispatchNodeResultType[]; // Children node response
[DispatchNodeResponseKeyEnum.toolResponses]?: ToolRunResponseItemType; // Tool response
[DispatchNodeResponseKeyEnum.assistantResponses]?: AIChatItemValueItemType[]; // Assistant response(Store to db)
[DispatchNodeResponseKeyEnum.rewriteHistories]?: ChatItemType[];
} & T;
/* Single node props */

View File

@@ -27,16 +27,32 @@ export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number
return limit * 2;
};
/*
Get interaction information (if any) from the last AI message.
What can be done:
1. Get the interactive data
2. Check that the workflow starts at the interaction node
*/
export const getLastInteractiveValue = (histories: ChatItemType[]) => {
const lastAIMessage = histories.findLast((item) => item.obj === ChatRoleEnum.AI);
if (lastAIMessage) {
const interactiveValue = lastAIMessage.value.find(
(v) => v.type === ChatItemValueTypeEnum.interactive
);
const lastValue = lastAIMessage.value[lastAIMessage.value.length - 1];
if (interactiveValue && 'interactive' in interactiveValue) {
return interactiveValue.interactive;
if (
!lastValue ||
lastValue.type !== ChatItemValueTypeEnum.interactive ||
!lastValue.interactive
) {
return null;
}
// Check is user select
if (
lastValue.interactive.type === 'userSelect' &&
!lastValue.interactive.params.userSelectedVal
) {
return lastValue.interactive;
}
}
@@ -117,39 +133,6 @@ export const filterWorkflowEdges = (edges: RuntimeEdgeItemType[]) => {
);
};
/*
区分普通连线和递归连线
递归连线:可以通过往上查询 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 执行
@@ -161,31 +144,72 @@ export const checkNodeRunStatus = ({
node: RuntimeNodeItemType;
runtimeEdges: RuntimeEdgeItemType[];
}) => {
const workflowEdges = filterWorkflowEdges(runtimeEdges).filter(
/*
区分普通连线和递归连线
递归连线:可以通过往上查询 nodes最终追溯到自身
*/
const splitEdges2WorkflowEdges = ({
sourceEdges,
allEdges,
currentNode
}: {
sourceEdges: RuntimeEdgeItemType[];
allEdges: RuntimeEdgeItemType[];
currentNode: RuntimeNodeItemType;
}) => {
const commonEdges: RuntimeEdgeItemType[] = [];
const recursiveEdges: RuntimeEdgeItemType[] = [];
const checkIsCircular = (edge: RuntimeEdgeItemType, visited: Set<string>): boolean => {
if (edge.source === currentNode.nodeId) {
return true; // 检测到环,并且环中包含当前节点
}
if (visited.has(edge.source)) {
return false; // 检测到环,但不包含当前节点(子节点成环)
}
visited.add(edge.source);
const nextEdges = allEdges.filter((item) => item.target === edge.source);
return nextEdges.some((nextEdge) => checkIsCircular(nextEdge, new Set(visited)));
};
sourceEdges.forEach((edge) => {
if (checkIsCircular(edge, new Set([currentNode.nodeId]))) {
recursiveEdges.push(edge);
} else {
commonEdges.push(edge);
}
});
return { commonEdges, recursiveEdges };
};
const runtimeNodeSourceEdge = filterWorkflowEdges(runtimeEdges).filter(
(item) => item.target === node.nodeId
);
// Entry
if (workflowEdges.length === 0) {
if (runtimeNodeSourceEdge.length === 0) {
return 'run';
}
// Classify edges
const { commonEdges, recursiveEdges } = splitEdges2WorkflowEdges({
edges: workflowEdges,
sourceEdges: runtimeNodeSourceEdge,
allEdges: runtimeEdges,
currentNode: node
});
// check skip
if (commonEdges.every((item) => item.status === 'skipped')) {
// check skip(其中一组边,全 skip
if (commonEdges.length > 0 && 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')) {
// check active(有一类边,不全是 wait 即可运行)
if (commonEdges.length > 0 && commonEdges.every((item) => item.status !== 'waiting')) {
return 'run';
}
if (recursiveEdges.length > 0 && recursiveEdges.every((item) => item.status !== 'waiting')) {
@@ -236,7 +260,7 @@ export const textAdaptGptResponse = ({
finish_reason?: null | 'stop';
extraData?: Object;
}) => {
return JSON.stringify({
return {
...extraData,
id: '',
object: '',
@@ -252,7 +276,7 @@ export const textAdaptGptResponse = ({
finish_reason
}
]
});
};
};
/* Update runtimeNode's outputs with interactive data from history */

View File

@@ -1,4 +1,5 @@
import { SystemConfigNode } from './system/systemConfig';
import { PluginConfigNode } from './system/pluginConfig';
import { EmptyNode } from './system/emptyNode';
import { WorkflowStart } from './system/workflowStart';
import { AiChatModule } from './system/aiChat';
@@ -12,10 +13,11 @@ import { HttpNode468 } from './system/http468';
import { ToolModule } from './system/tools';
import { StopToolNode } from './system/stopTool';
import { RunAppModule } from './system/runApp/index';
import { RunAppModule } from './system/abandoned/runApp/index';
import { PluginInputModule } from './system/pluginInput';
import { PluginOutputModule } from './system/pluginOutput';
import { RunPluginModule } from './system/runPlugin';
import { RunAppNode } from './system/runApp';
import { AiQueryExtension } from './system/queryExtension';
import type { FlowNodeTemplateType } from '../type/node';
@@ -44,8 +46,7 @@ const systemNodes: FlowNodeTemplateType[] = [
LafModule,
IfElseNode,
VariableUpdateNode,
CodeNode,
RunAppModule
CodeNode
];
/* app flow module templates */
export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
@@ -57,6 +58,7 @@ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
];
/* plugin flow module templates */
export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
PluginConfigNode,
PluginInputModule,
PluginOutputModule,
...systemNodes
@@ -70,5 +72,7 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [
)
),
EmptyNode,
RunPluginModule
RunPluginModule,
RunAppNode,
RunAppModule
];

View File

@@ -9,8 +9,9 @@ export const Input_Template_History: FlowNodeInputItemType = {
key: NodeInputKeyEnum.history,
renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.chatHistory,
label: 'core.module.input.label.chat history',
description: '最多携带多少轮对话记录',
label: i18nT('common:core.module.input.label.chat history'),
description: i18nT('workflow:max_dialog_rounds'),
required: true,
min: 0,
max: 50,
@@ -21,7 +22,7 @@ export const Input_Template_UserChatInput: FlowNodeInputItemType = {
key: NodeInputKeyEnum.userChatInput,
renderTypeList: [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.textarea],
valueType: WorkflowIOValueTypeEnum.string,
label: '用户问题',
label: i18nT('workflow:user_question'),
required: true
};
@@ -36,14 +37,14 @@ export const Input_Template_DynamicInput: FlowNodeInputItemType = {
export const Input_Template_SelectAIModel: FlowNodeInputItemType = {
key: NodeInputKeyEnum.aiModel,
renderTypeList: [FlowNodeInputTypeEnum.selectLLMModel, FlowNodeInputTypeEnum.reference],
label: 'core.module.input.label.aiModel',
label: i18nT('common: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',
label: i18nT('common:core.module.input.label.aiModel'),
valueType: WorkflowIOValueTypeEnum.string
};
@@ -52,7 +53,7 @@ export const Input_Template_System_Prompt: FlowNodeInputItemType = {
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
max: 3000,
valueType: WorkflowIOValueTypeEnum.string,
label: 'core.ai.Prompt',
label: i18nT('common:core.ai.Prompt'),
description: chatNodeSystemPromptTip,
placeholder: chatNodeSystemPromptTip
};
@@ -61,7 +62,7 @@ export const Input_Template_Dataset_Quote: FlowNodeInputItemType = {
key: NodeInputKeyEnum.aiChatDatasetQuote,
renderTypeList: [FlowNodeInputTypeEnum.settingDatasetQuotePrompt],
label: '',
debugLabel: '知识库引用',
debugLabel: i18nT('workflow:knowledge_base_reference'),
description: '',
valueType: WorkflowIOValueTypeEnum.datasetQuote
};
@@ -73,3 +74,12 @@ export const Input_Template_Text_Quote: FlowNodeInputItemType = {
description: i18nT('app:document_quote_tip'),
valueType: WorkflowIOValueTypeEnum.string
};
export const Input_Template_File_Link: FlowNodeInputItemType = {
key: NodeInputKeyEnum.fileUrlList,
renderTypeList: [FlowNodeInputTypeEnum.reference],
required: true,
label: i18nT('app:workflow.user_file_input'),
debugLabel: i18nT('app:workflow.user_file_input'),
description: i18nT('app:workflow.user_file_input_desc'),
valueType: WorkflowIOValueTypeEnum.arrayString
};

View File

@@ -3,16 +3,17 @@ import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../../node/constant';
import { FlowNodeTemplateType } from '../../../type/node.d';
} from '../../../../node/constant';
import { FlowNodeTemplateType } from '../../../../type/node';
import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum
} from '../../../constants';
import { Input_Template_History, Input_Template_UserChatInput } from '../../input';
import { getHandleConfig } from '../../utils';
} from '../../../../constants';
import { Input_Template_History, Input_Template_UserChatInput } from '../../../input';
import { getHandleConfig } from '../../../utils';
import { i18nT } from '../../../../../../../web/i18n/utils';
export const RunAppModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.runApp,
@@ -21,8 +22,8 @@ export const RunAppModule: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/runApp',
name: '应用调用',
intro: '可以选择一个其他应用进行调用',
name: i18nT('workflow:application_call'),
intro: i18nT('workflow:select_another_application_to_call'),
showStatus: true,
version: '481',
isTool: true,
@@ -31,22 +32,22 @@ export const RunAppModule: FlowNodeTemplateType = {
key: NodeInputKeyEnum.runAppSelectApp,
renderTypeList: [FlowNodeInputTypeEnum.selectApp, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.selectApp,
label: '选择一个应用',
description: '选择一个其他应用进行调用',
label: i18nT('workflow:select_an_application'),
description: i18nT('workflow:choose_another_application_to_call'),
required: true
},
Input_Template_History,
{
...Input_Template_UserChatInput,
toolDescription: '用户问题'
toolDescription: i18nT('workflow:user_question')
}
],
outputs: [
{
id: NodeOutputKeyEnum.history,
key: NodeOutputKeyEnum.history,
label: '新的上下文',
description: '将该应用回复内容拼接到历史记录中,作为新的上下文返回',
label: i18nT('workflow:new_context'),
description: i18nT('workflow:append_application_reply_to_history_as_new_context'),
valueType: WorkflowIOValueTypeEnum.chatHistory,
valueDesc: chatHistoryValueDesc,
required: true,
@@ -55,8 +56,8 @@ export const RunAppModule: FlowNodeTemplateType = {
{
id: NodeOutputKeyEnum.answerText,
key: NodeOutputKeyEnum.answerText,
label: '回复的文本',
description: '将在应用完全结束后触发',
label: i18nT('workflow:reply_text'),
description: i18nT('workflow:trigger_after_application_completion'),
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}

View File

@@ -81,22 +81,23 @@ export const AiChatModule: FlowNodeTemplateType = {
// settings modal ---
{
...Input_Template_System_Prompt,
label: 'core.ai.Prompt',
label: i18nT('common:core.ai.Prompt'),
description: chatNodeSystemPromptTip,
placeholder: chatNodeSystemPromptTip
},
Input_Template_History,
Input_Template_Dataset_Quote,
Input_Template_Text_Quote,
{ ...Input_Template_UserChatInput, toolDescription: '用户问题' }
{ ...Input_Template_UserChatInput, toolDescription: i18nT('workflow:user_question') }
],
outputs: [
{
id: NodeOutputKeyEnum.history,
key: NodeOutputKeyEnum.history,
required: true,
label: 'core.module.output.label.New context',
description: 'core.module.output.description.New context',
label: i18nT('common:core.module.output.label.New context'),
description: i18nT('common:core.module.output.description.New context'),
valueType: WorkflowIOValueTypeEnum.chatHistory,
valueDesc: chatHistoryValueDesc,
type: FlowNodeOutputTypeEnum.static
@@ -105,8 +106,8 @@ export const AiChatModule: FlowNodeTemplateType = {
id: NodeOutputKeyEnum.answerText,
key: NodeOutputKeyEnum.answerText,
required: true,
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
label: i18nT('common:core.module.output.label.Ai response content'),
description: i18nT('common:core.module.output.description.Ai response content'),
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}

View File

@@ -6,6 +6,7 @@ import {
FlowNodeTemplateTypeEnum
} from '../../constants';
import { getHandleConfig } from '../utils';
import { i18nT } from '../../../../../web/i18n/utils';
export const AssignedAnswerModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.answerNode,
@@ -14,9 +15,9 @@ export const AssignedAnswerModule: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/reply',
name: '指定回复',
intro:
'该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。',
name: i18nT('workflow:assigned_reply'),
intro: i18nT('workflow:intro_assigned_reply'),
version: '481',
isTool: true,
inputs: [
@@ -25,9 +26,9 @@ export const AssignedAnswerModule: FlowNodeTemplateType = {
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.any,
required: true,
label: 'core.module.input.label.Response content',
description: 'core.module.input.description.Response content',
placeholder: 'core.module.input.description.Response content'
label: i18nT('common:core.module.input.label.Response content'),
description: i18nT('common:core.module.input.description.Response content'),
placeholder: i18nT('common:core.module.input.description.Response content')
}
],
outputs: []

View File

@@ -18,6 +18,7 @@ import {
import { Input_Template_System_Prompt } from '../../input';
import { LLMModelTypeEnum } from '../../../../ai/constants';
import { getHandleConfig } from '../../utils';
import { i18nT } from '../../../../../../web/i18n/utils';
export const ClassifyQuestionModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.classifyQuestion,
@@ -26,8 +27,8 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(true, false, true, true),
avatar: 'core/workflow/template/questionClassify',
name: '问题分类',
intro: `根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题`,
name: i18nT('workflow:question_classification'),
intro: i18nT('workflow:intro_question_classification'),
showStatus: true,
version: '481',
inputs: [
@@ -50,15 +51,15 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
label: '',
value: [
{
value: '打招呼',
value: 'Greeting',
key: 'wqre'
},
{
value: '关于 xxx 的问题',
value: 'Question regarding xxx',
key: 'sdfa'
},
{
value: '其他问题',
value: 'Other Questions',
key: 'agex'
}
]
@@ -69,7 +70,7 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
id: NodeOutputKeyEnum.cqResult,
key: NodeOutputKeyEnum.cqResult,
required: true,
label: '分类结果',
label: i18nT('workflow:classification_result'),
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}

View File

@@ -13,6 +13,7 @@ import {
import { Input_Template_SelectAIModel, Input_Template_History } from '../../input';
import { LLMModelTypeEnum } from '../../../../ai/constants';
import { getHandleConfig } from '../../utils';
import { i18nT } from '../../../../../../web/i18n/utils';
export const ContextExtractModule: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.contentExtract,
@@ -21,8 +22,8 @@ export const ContextExtractModule: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/extractJson',
name: '文本内容提取',
intro: '可从文本中提取指定的数据例如sql语句、搜索关键词、代码等',
name: i18nT('workflow:text_content_extraction'),
intro: i18nT('workflow:intro_text_content_extraction'),
showStatus: true,
isTool: true,
version: '481',
@@ -35,27 +36,25 @@ export const ContextExtractModule: FlowNodeTemplateType = {
key: NodeInputKeyEnum.description,
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.string,
label: '提取要求描述',
description:
'给AI一些对应的背景知识或要求描述引导AI更好的完成任务。\n该输入框可使用全局变量。',
placeholder:
'例如: \n1. 当前时间为: {{cTime}}。你是一个实验室预约助手,你的任务是帮助用户预约实验室,从文本中获取对应的预约信息。\n2. 你是谷歌搜索助手,需要从文本中提取出合适的搜索词。'
label: i18nT('workflow:extraction_requirements_description'),
description: i18nT('workflow:extraction_requirements_description_detail'),
placeholder: i18nT('workflow:extraction_requirements_placeholder')
},
Input_Template_History,
{
key: NodeInputKeyEnum.contextExtractInput,
renderTypeList: [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.textarea],
label: '需要提取的文本',
label: i18nT('workflow:text_to_extract'),
required: true,
valueType: WorkflowIOValueTypeEnum.string,
toolDescription: '需要检索的内容'
toolDescription: i18nT('workflow:content_to_retrieve')
},
{
key: NodeInputKeyEnum.extractKeys,
renderTypeList: [FlowNodeInputTypeEnum.custom],
label: '',
valueType: WorkflowIOValueTypeEnum.any,
description: "由 '描述' 和 'key' 组成一个目标字段,可提取多个目标字段",
description: i18nT('workflow:target_fields_description'),
value: [] // {valueType: string; desc: string; key: string; required: boolean; enum: string[]}[]
}
],
@@ -63,18 +62,18 @@ export const ContextExtractModule: FlowNodeTemplateType = {
{
id: NodeOutputKeyEnum.success,
key: NodeOutputKeyEnum.success,
label: '字段完全提取',
label: i18nT('workflow:full_field_extraction'),
required: true,
description: '提取字段全部填充时返回 true (模型提取或使用默认值均属于成功)',
description: i18nT('workflow:full_field_extraction_description'),
valueType: WorkflowIOValueTypeEnum.boolean,
type: FlowNodeOutputTypeEnum.static
},
{
id: NodeOutputKeyEnum.contextExtractFields,
key: NodeOutputKeyEnum.contextExtractFields,
label: '完整提取结果',
label: i18nT('workflow:complete_extraction_result'),
required: true,
description: '一个 JSON 字符串,例如:{"name:":"YY","Time":"2023/7/2 18:00"}',
description: i18nT('workflow:complete_extraction_result_description'),
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}

View File

@@ -1,5 +1,10 @@
import { WorkflowIOValueTypeEnum } from '../../../constants';
export type ContextExtractAgentItemType = {
valueType: 'string' | 'number' | 'boolean';
valueType:
| WorkflowIOValueTypeEnum.string
| WorkflowIOValueTypeEnum.number
| WorkflowIOValueTypeEnum.boolean;
desc: string;
key: string;
required: boolean;

View File

@@ -6,6 +6,7 @@ import {
NodeInputKeyEnum
} from '../../constants';
import { getHandleConfig } from '../utils';
import { i18nT } from '../../../../../web/i18n/utils';
export const CustomFeedbackNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.customFeedback,
@@ -14,8 +15,8 @@ export const CustomFeedbackNode: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/customFeedback',
name: '自定义反馈',
intro: '该模块被触发时,会给当前的对话记录增加一条反馈。可用于自动记录对话效果等。',
name: i18nT('workflow:custom_feedback'),
intro: i18nT('workflow:intro_custom_feedback'),
version: '486',
inputs: [
{
@@ -23,7 +24,7 @@ export const CustomFeedbackNode: FlowNodeTemplateType = {
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.string,
required: true,
label: '反馈的文本'
label: i18nT('workflow:feedback_text')
}
],
outputs: []

View File

@@ -14,6 +14,7 @@ import {
import { getNanoid } from '../../../../common/string/tools';
import { getHandleConfig } from '../utils';
import { FlowNodeInputItemType } from '../../type/io.d';
import { i18nT } from '../../../../../web/i18n/utils';
export const getOneQuoteInputTemplate = ({
key = getNanoid(),
@@ -24,8 +25,8 @@ export const getOneQuoteInputTemplate = ({
}): FlowNodeInputItemType => ({
key,
renderTypeList: [FlowNodeInputTypeEnum.reference],
label: `引用${index}`,
debugLabel: '知识库引用',
label: `${i18nT('workflow:quote_num')},{ num: ${index} }`,
debugLabel: i18nT('workflow:knowledge_base_reference'),
canEdit: true,
valueType: WorkflowIOValueTypeEnum.datasetQuote
});
@@ -37,15 +38,17 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/datasetConcat',
name: '知识库搜索引用合并',
intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。',
name: i18nT('workflow:knowledge_base_search_merge'),
intro: i18nT('workflow:intro_knowledge_base_search_merge'),
showStatus: false,
version: '486',
inputs: [
{
key: NodeInputKeyEnum.datasetMaxTokens,
renderTypeList: [FlowNodeInputTypeEnum.custom],
label: '最大 Tokens',
label: i18nT('workflow:max_tokens'),
value: 3000,
valueType: WorkflowIOValueTypeEnum.number
},
@@ -60,7 +63,7 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
{
id: NodeOutputKeyEnum.datasetQuoteQA,
key: NodeOutputKeyEnum.datasetQuoteQA,
label: 'core.module.Dataset quote.label',
label: i18nT('common:core.module.Dataset quote.label'),
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.datasetQuote,
valueDesc: datasetQuoteValueDesc

View File

@@ -34,7 +34,7 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
{
key: NodeInputKeyEnum.datasetSelectList,
renderTypeList: [FlowNodeInputTypeEnum.selectDataset, FlowNodeInputTypeEnum.reference],
label: 'core.module.input.label.Select dataset',
label: i18nT('common:core.module.input.label.Select dataset'),
value: [],
valueType: WorkflowIOValueTypeEnum.selectDataset,
required: true
@@ -90,34 +90,24 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
},
{
...Input_Template_UserChatInput,
toolDescription: '需要检索的内容'
toolDescription: i18nT('workflow:content_to_search')
},
{
key: NodeInputKeyEnum.collectionFilterMatch,
renderTypeList: [FlowNodeInputTypeEnum.JSONEditor, FlowNodeInputTypeEnum.reference],
label: '集合元数据过滤',
label: i18nT('workflow:collection_metadata_filter'),
valueType: WorkflowIOValueTypeEnum.object,
isPro: true,
description: `目前支持标签和创建时间过滤,需按照以下格式填写:
{
"tags": {
"$and": ["标签 1","标签 2"],
"$or": ["有 $and 标签时and 生效or 不生效"]
},
"createTime": {
"$gte": "YYYY-MM-DD HH:mm 格式即可,集合的创建时间大于该时间",
"$lte": "YYYY-MM-DD HH:mm 格式即可,集合的创建时间小于该时间,可和 $gte 共同使用"
}
}
`
description: i18nT('workflow:filter_description')
}
],
outputs: [
{
id: NodeOutputKeyEnum.datasetQuoteQA,
key: NodeOutputKeyEnum.datasetQuoteQA,
label: 'core.module.Dataset quote.label',
description: '特殊数组格式,搜索结果为空时,返回空数组。',
label: i18nT('common:core.module.Dataset quote.label'),
description: i18nT('workflow:special_array_format'),
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.datasetQuote,
valueDesc: datasetQuoteValueDesc

View File

@@ -8,11 +8,13 @@ import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
FlowNodeTemplateTypeEnum
FlowNodeTemplateTypeEnum,
ContentTypes
} from '../../constants';
import { Input_Template_DynamicInput } from '../input';
import { Output_Template_AddOutput } from '../output';
import { getHandleConfig } from '../utils';
import { i18nT } from '../../../../../web/i18n/utils';
export const HttpNode468: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.httpRequest468,
@@ -21,15 +23,15 @@ export const HttpNode468: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/httpRequest',
name: 'HTTP 请求',
intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
name: i18nT('workflow:http_request'),
intro: i18nT('workflow:intro_http_request'),
showStatus: true,
isTool: true,
version: '481',
inputs: [
{
...Input_Template_DynamicInput,
description: 'core.module.input.description.HTTP Dynamic Input',
description: i18nT('common:core.module.input.description.HTTP Dynamic Input'),
customInputConfig: {
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
showDescription: false,
@@ -59,7 +61,7 @@ export const HttpNode468: FlowNodeTemplateType = {
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.string,
label: '',
description: 'core.module.input.description.Http Request Url',
description: i18nT('common:core.module.input.description.Http Request Url'),
placeholder: 'https://api.ai.com/getInventory',
required: false
},
@@ -69,8 +71,8 @@ export const HttpNode468: FlowNodeTemplateType = {
valueType: WorkflowIOValueTypeEnum.any,
value: [],
label: '',
description: 'core.module.input.description.Http Request Header',
placeholder: 'core.module.input.description.Http Request Header',
description: i18nT('common:core.module.input.description.Http Request Header'),
placeholder: i18nT('common:core.module.input.description.Http Request Header'),
required: false
},
{
@@ -81,6 +83,7 @@ export const HttpNode468: FlowNodeTemplateType = {
label: '',
required: false
},
// json body data
{
key: NodeInputKeyEnum.httpJsonBody,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
@@ -88,6 +91,24 @@ export const HttpNode468: FlowNodeTemplateType = {
value: '',
label: '',
required: false
},
// form body data
{
key: NodeInputKeyEnum.httpFormBody,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
value: [],
label: '',
required: false
},
// body data type
{
key: NodeInputKeyEnum.httpContentType,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.string,
value: ContentTypes.json,
label: '',
required: false
}
],
outputs: [
@@ -97,17 +118,17 @@ export const HttpNode468: FlowNodeTemplateType = {
{
id: NodeOutputKeyEnum.error,
key: NodeOutputKeyEnum.error,
label: '请求错误',
description: 'HTTP请求错误信息成功时返回空',
label: i18nT('workflow:request_error'),
description: i18nT('workflow:http_request_error_info'),
valueType: WorkflowIOValueTypeEnum.object,
type: FlowNodeOutputTypeEnum.static
},
{
id: NodeOutputKeyEnum.httpRawResponse,
key: NodeOutputKeyEnum.httpRawResponse,
label: '原始响应',
required: true,
description: 'HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。',
label: i18nT('workflow:raw_response'),
description: i18nT('workflow:http_raw_response_description'),
valueType: WorkflowIOValueTypeEnum.any,
type: FlowNodeOutputTypeEnum.static
}

View File

@@ -1,3 +1,5 @@
import { i18nT } from '../../../../../../web/i18n/utils';
export enum VariableConditionEnum {
equalTo = 'equalTo',
notEqual = 'notEqual',
@@ -29,64 +31,85 @@ export enum IfElseResultEnum {
}
export const stringConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '等于', value: VariableConditionEnum.equalTo },
{ label: '不等于', value: VariableConditionEnum.notEqual },
{ label: '正则', value: VariableConditionEnum.reg },
{ label: '包含', value: VariableConditionEnum.include },
{ label: '不包含', value: VariableConditionEnum.notInclude },
{ label: '开始为', value: VariableConditionEnum.startWith },
{ label: '结束为', value: VariableConditionEnum.endWith }
{ label: i18nT('workflow:is_empty'), value: VariableConditionEnum.isEmpty },
{ label: i18nT('workflow:is_not_empty'), value: VariableConditionEnum.isNotEmpty },
{ label: i18nT('workflow:is_equal_to'), value: VariableConditionEnum.equalTo },
{ label: i18nT('workflow:is_not_equal'), value: VariableConditionEnum.notEqual },
{ label: i18nT('workflow:regex'), value: VariableConditionEnum.reg },
{ label: i18nT('workflow:contains'), value: VariableConditionEnum.include },
{ label: i18nT('workflow:not_contains'), value: VariableConditionEnum.notInclude },
{ label: i18nT('workflow:start_with'), value: VariableConditionEnum.startWith },
{ label: i18nT('workflow:end_with'), value: VariableConditionEnum.endWith }
];
export const numberConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '等于', value: VariableConditionEnum.equalTo },
{ label: '不等于', value: VariableConditionEnum.notEqual },
{ label: '大于', value: VariableConditionEnum.greaterThan },
{ label: '大于等于', value: VariableConditionEnum.greaterThanOrEqualTo },
{ label: '小于', value: VariableConditionEnum.lessThan },
{ label: '小于等于', value: VariableConditionEnum.lessThanOrEqualTo }
{ label: i18nT('workflow:is_empty'), value: VariableConditionEnum.isEmpty },
{ label: i18nT('workflow:is_not_empty'), value: VariableConditionEnum.isNotEmpty },
{ label: i18nT('workflow:is_equal_to'), value: VariableConditionEnum.equalTo },
{ label: i18nT('workflow:is_not_equal'), value: VariableConditionEnum.notEqual },
{ label: i18nT('workflow:greater_than'), value: VariableConditionEnum.greaterThan },
{
label: i18nT('workflow:greater_than_or_equal_to'),
value: VariableConditionEnum.greaterThanOrEqualTo
},
{ label: i18nT('workflow:less_than'), value: VariableConditionEnum.lessThan },
{ label: i18nT('workflow:less_than_or_equal_to'), value: VariableConditionEnum.lessThanOrEqualTo }
];
export const booleanConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '等于', value: VariableConditionEnum.equalTo }
{ label: i18nT('workflow:is_empty'), value: VariableConditionEnum.isEmpty },
{ label: i18nT('workflow:is_not_empty'), value: VariableConditionEnum.isNotEmpty },
{ label: i18nT('workflow:is_equal_to'), value: VariableConditionEnum.equalTo }
];
export const arrayConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '包含', value: VariableConditionEnum.include },
{ label: '不包含', value: VariableConditionEnum.notInclude },
{ label: '长度等于', value: VariableConditionEnum.lengthEqualTo },
{ label: '长度不等于', value: VariableConditionEnum.lengthNotEqualTo },
{ label: '长度大于', value: VariableConditionEnum.lengthGreaterThan },
{ label: '长度大于等于', value: VariableConditionEnum.lengthGreaterThanOrEqualTo },
{ label: '长度小于', value: VariableConditionEnum.lengthLessThan },
{ label: '长度小于等于', value: VariableConditionEnum.lengthLessThanOrEqualTo }
{ label: i18nT('workflow:is_empty'), value: VariableConditionEnum.isEmpty },
{ label: i18nT('workflow:is_not_empty'), value: VariableConditionEnum.isNotEmpty },
{ label: i18nT('workflow:contains'), value: VariableConditionEnum.include },
{ label: i18nT('workflow:not_contains'), value: VariableConditionEnum.notInclude },
{ label: i18nT('workflow:length_equal_to'), value: VariableConditionEnum.lengthEqualTo },
{ label: i18nT('workflow:length_not_equal_to'), value: VariableConditionEnum.lengthNotEqualTo },
{ label: i18nT('workflow:length_greater_than'), value: VariableConditionEnum.lengthGreaterThan },
{
label: i18nT('workflow:length_greater_than_or_equal_to'),
value: VariableConditionEnum.lengthGreaterThanOrEqualTo
},
{ label: i18nT('workflow:length_less_than'), value: VariableConditionEnum.lengthLessThan },
{
label: i18nT('workflow:length_less_than_or_equal_to'),
value: VariableConditionEnum.lengthLessThanOrEqualTo
}
];
export const objectConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty }
{ label: i18nT('workflow:is_empty'), value: VariableConditionEnum.isEmpty },
{ label: i18nT('workflow:is_not_empty'), value: VariableConditionEnum.isNotEmpty }
];
export const allConditionList = [
{ label: '为空', value: VariableConditionEnum.isEmpty },
{ label: '不为空', value: VariableConditionEnum.isNotEmpty },
{ label: '等于', value: VariableConditionEnum.equalTo },
{ label: '不等于', value: VariableConditionEnum.notEqual },
{ label: '包含', value: VariableConditionEnum.include },
{ label: '不包含', value: VariableConditionEnum.notInclude },
{ label: '开始为', value: VariableConditionEnum.startWith },
{ label: '结束为', value: VariableConditionEnum.endWith },
{ label: '大于', value: VariableConditionEnum.greaterThan },
{ label: '大于等于', value: VariableConditionEnum.greaterThanOrEqualTo },
{ label: '小于', value: VariableConditionEnum.lessThan },
{ label: '小于等于', value: VariableConditionEnum.lessThanOrEqualTo },
{ label: '长度等于', value: VariableConditionEnum.lengthEqualTo },
{ label: '长度不等于', value: VariableConditionEnum.lengthNotEqualTo },
{ label: '长度大于', value: VariableConditionEnum.lengthGreaterThan },
{ label: '长度大于等于', value: VariableConditionEnum.lengthGreaterThanOrEqualTo },
{ label: '长度小于', value: VariableConditionEnum.lengthLessThan },
{ label: '长度小于等于', value: VariableConditionEnum.lengthLessThanOrEqualTo }
{ label: i18nT('workflow:is_empty'), value: VariableConditionEnum.isEmpty },
{ label: i18nT('workflow:is_not_empty'), value: VariableConditionEnum.isNotEmpty },
{ label: i18nT('workflow:is_equal_to'), value: VariableConditionEnum.equalTo },
{ label: i18nT('workflow:is_not_equal'), value: VariableConditionEnum.notEqual },
{ label: i18nT('workflow:contains'), value: VariableConditionEnum.include },
{ label: i18nT('workflow:not_contains'), value: VariableConditionEnum.notInclude },
{ label: i18nT('workflow:start_with'), value: VariableConditionEnum.startWith },
{ label: i18nT('workflow:end_with'), value: VariableConditionEnum.endWith },
{ label: i18nT('workflow:greater_than'), value: VariableConditionEnum.greaterThan },
{
label: i18nT('workflow:greater_than_or_equal_to'),
value: VariableConditionEnum.greaterThanOrEqualTo
},
{ label: i18nT('workflow:less_than'), value: VariableConditionEnum.lessThan },
{
label: i18nT('workflow:less_than_or_equal_to'),
value: VariableConditionEnum.lessThanOrEqualTo
},
{ label: i18nT('workflow:length_equal_to'), value: VariableConditionEnum.lengthEqualTo },
{ label: i18nT('workflow:length_not_equal_to'), value: VariableConditionEnum.lengthNotEqualTo },
{ label: i18nT('workflow:length_greater_than'), value: VariableConditionEnum.lengthGreaterThan },
{
label: i18nT('workflow:length_greater_than_or_equal_to'),
value: VariableConditionEnum.lengthGreaterThanOrEqualTo
},
{ label: i18nT('workflow:length_less_than'), value: VariableConditionEnum.lengthLessThan },
{
label: i18nT('workflow:length_less_than_or_equal_to'),
value: VariableConditionEnum.lengthLessThanOrEqualTo
}
];

View File

@@ -1,3 +1,4 @@
import { i18nT } from '../../../../../../web/i18n/utils';
import {
FlowNodeTemplateTypeEnum,
NodeInputKeyEnum,
@@ -19,8 +20,8 @@ export const IfElseNode: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(true, false, true, true),
avatar: 'core/workflow/template/ifelse',
name: '判断器',
intro: '根据一定的条件,执行不同的分支。',
name: i18nT('workflow:condition_checker'),
intro: i18nT('workflow:execute_different_branches_based_on_conditions'),
showStatus: true,
version: '481',
inputs: [
@@ -47,7 +48,7 @@ export const IfElseNode: FlowNodeTemplateType = {
{
id: NodeOutputKeyEnum.ifElseResult,
key: NodeOutputKeyEnum.ifElseResult,
label: '判断结果',
label: i18nT('workflow:judgment_result'),
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}

View File

@@ -13,6 +13,7 @@ import {
import { Input_Template_DynamicInput } from '../input';
import { Output_Template_AddOutput } from '../output';
import { getHandleConfig } from '../utils';
import { i18nT } from '../../../../../web/i18n/utils';
export const nodeLafCustomInputConfig = {
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
@@ -27,15 +28,15 @@ export const LafModule: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/lafDispatch',
name: 'Laf 函数调用(测试)',
intro: '可以调用Laf账号下的云函数。',
name: i18nT('workflow:laf_function_call_test'),
intro: i18nT('workflow:intro_laf_function_call'),
showStatus: true,
isTool: true,
version: '481',
inputs: [
{
...Input_Template_DynamicInput,
description: '接收前方节点的输出值作为变量,这些变量可以被 Laf 请求参数使用。',
description: i18nT('workflow:dynamic_input_description'),
customInputConfig: nodeLafCustomInputConfig
},
{
@@ -52,8 +53,8 @@ export const LafModule: FlowNodeTemplateType = {
{
id: NodeOutputKeyEnum.httpRawResponse,
key: NodeOutputKeyEnum.httpRawResponse,
label: '原始响应',
description: 'HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。',
label: i18nT('workflow:raw_response'),
description: i18nT('workflow:http_raw_response_description'),
valueType: WorkflowIOValueTypeEnum.any,
type: FlowNodeOutputTypeEnum.static
},

View File

@@ -0,0 +1,21 @@
import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/node.d';
import { FlowNodeTemplateTypeEnum } from '../../constants';
import { getHandleConfig } from '../utils';
import { i18nT } from '../../../../../web/i18n/utils';
export const PluginConfigNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.pluginConfig,
templateType: FlowNodeTemplateTypeEnum.systemInput,
flowNodeType: FlowNodeTypeEnum.pluginConfig,
sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(false, false, false, false),
avatar: 'core/workflow/template/systemConfig',
name: i18nT('workflow:template.system_config'),
intro: '',
unique: true,
forbidDelete: true,
version: '4811',
inputs: [],
outputs: []
};

View File

@@ -1,3 +1,4 @@
import { i18nT } from '../../../../../web/i18n/utils';
import { FlowNodeTemplateTypeEnum } from '../../constants';
import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/node';
@@ -12,8 +13,8 @@ export const PluginInputModule: FlowNodeTemplateType = {
unique: true,
forbidDelete: true,
avatar: 'core/workflow/template/workflowStart',
name: '插件输入',
intro: '可以配置插件需要哪些输入,利用这些输入来运行插件',
name: i18nT('workflow:plugin_input'),
intro: i18nT('workflow:intro_plugin_input'),
showStatus: false,
version: '481',
inputs: [],

View File

@@ -1,3 +1,4 @@
import { i18nT } from '../../../../../web/i18n/utils';
import { FlowNodeTemplateTypeEnum } from '../../constants';
import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/node';
@@ -12,8 +13,8 @@ export const PluginOutputModule: FlowNodeTemplateType = {
unique: true,
forbidDelete: true,
avatar: 'core/workflow/template/pluginOutput',
name: '自定义插件输出',
intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出',
name: i18nT('workflow:custom_plugin_output'),
intro: i18nT('workflow:intro_custom_plugin_output'),
showStatus: false,
version: '481',
inputs: [],

View File

@@ -17,6 +17,7 @@ import {
} from '../input';
import { LLMModelTypeEnum } from '../../../ai/constants';
import { getHandleConfig } from '../utils';
import { i18nT } from '../../../../../web/i18n/utils';
export const AiQueryExtension: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.queryExtension,
@@ -25,9 +26,8 @@ export const AiQueryExtension: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/queryExtension',
name: '问题优化',
intro:
'使用问题优化功能,可以提高知识库连续对话时搜索的精度。使用该功能后,会先利用 AI 根据上下文构建一个或多个新的检索词,这些检索词更利于进行知识库搜索。该模块已内置在知识库搜索模块中,如果您仅进行一次知识库搜索,可直接使用知识库内置的补全功能。',
name: i18nT('workflow:question_optimization'),
intro: i18nT('workflow:intro_question_optimization'),
showStatus: true,
version: '481',
inputs: [
@@ -38,11 +38,11 @@ export const AiQueryExtension: FlowNodeTemplateType = {
{
key: NodeInputKeyEnum.aiSystemPrompt,
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
label: 'core.app.edit.Query extension background prompt',
label: i18nT('common:core.app.edit.Query extension background prompt'),
max: 300,
valueType: WorkflowIOValueTypeEnum.string,
description: 'core.app.edit.Query extension background tip',
placeholder: 'core.module.QueryExtension.placeholder'
description: i18nT('common:core.app.edit.Query extension background tip'),
placeholder: i18nT('common:core.module.QueryExtension.placeholder')
},
Input_Template_History,
Input_Template_UserChatInput
@@ -51,8 +51,8 @@ export const AiQueryExtension: FlowNodeTemplateType = {
{
id: NodeOutputKeyEnum.text,
key: NodeOutputKeyEnum.text,
label: 'core.module.output.label.query extension result',
description: 'core.module.output.description.query extension result',
label: i18nT('common:core.module.output.label.query extension result'),
description: i18nT('common:core.module.output.description.query extension result'),
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}

View File

@@ -0,0 +1,19 @@
import { FlowNodeTemplateTypeEnum } from '../../constants';
import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/node';
import { getHandleConfig } from '../utils';
export const RunAppNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.appModule,
templateType: FlowNodeTemplateTypeEnum.other,
flowNodeType: FlowNodeTypeEnum.appModule,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
intro: '',
name: '',
showStatus: false,
isTool: false,
version: '481',
inputs: [], // [{key:'pluginId'},...]
outputs: []
};

View File

@@ -14,6 +14,7 @@ import { getHandleConfig } from '../../utils';
import { Input_Template_DynamicInput } from '../../input';
import { Output_Template_AddOutput } from '../../output';
import { JS_TEMPLATE } from './constants';
import { i18nT } from '../../../../../../web/i18n/utils';
export const CodeNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.code,
@@ -22,14 +23,14 @@ export const CodeNode: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/codeRun',
name: '代码运行',
intro: '执行一段简单的脚本代码,通常用于进行复杂的数据处理。',
name: i18nT('workflow:code_execution'),
intro: i18nT('workflow:execute_a_simple_script_code_usually_for_complex_data_processing'),
showStatus: true,
version: '482',
inputs: [
{
...Input_Template_DynamicInput,
description: '这些变量会作为代码的运行的输入参数',
description: i18nT('workflow:these_variables_will_be_input_parameters_for_code_execution'),
customInputConfig: {
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
showDescription: false,
@@ -78,20 +79,20 @@ export const CodeNode: FlowNodeTemplateType = {
outputs: [
{
...Output_Template_AddOutput,
description: '将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key'
description: i18nT('workflow:pass_returned_object_as_output_to_next_nodes')
},
{
id: NodeOutputKeyEnum.rawResponse,
key: NodeOutputKeyEnum.rawResponse,
label: '完整响应数据',
label: i18nT('workflow:full_response_data'),
valueType: WorkflowIOValueTypeEnum.object,
type: FlowNodeOutputTypeEnum.static
},
{
id: NodeOutputKeyEnum.error,
key: NodeOutputKeyEnum.error,
label: '运行错误',
description: '代码运行错误信息,成功时返回空',
label: i18nT('workflow:execution_error'),
description: i18nT('workflow:error_info_returns_empty_on_success'),
valueType: WorkflowIOValueTypeEnum.object,
type: FlowNodeOutputTypeEnum.static
},

View File

@@ -2,6 +2,7 @@ import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/node';
import { FlowNodeTemplateTypeEnum } from '../../constants';
import { getHandleConfig } from '../utils';
import { i18nT } from '../../../../../web/i18n/utils';
export const StopToolNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.stopTool,
@@ -10,9 +11,8 @@ export const StopToolNode: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/stopTool',
name: '工具调用终止',
intro:
'该模块需配置工具调用使用。当该模块被执行时本次工具调用将会强制结束并且不再调用AI针对工具调用结果回答问题。',
name: i18nT('workflow:tool_call_termination'),
intro: i18nT('workflow:intro_tool_call_termination'),
version: '481',
inputs: [],
outputs: []

View File

@@ -12,6 +12,7 @@ import {
} from '../../constants';
import { getHandleConfig } from '../utils';
import { Input_Template_DynamicInput } from '../input';
import { i18nT } from '../../../../../web/i18n/utils';
export const TextEditorNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.textEditor,
@@ -20,13 +21,13 @@ export const TextEditorNode: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/textConcat',
name: '文本拼接',
intro: '可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。',
name: i18nT('workflow:text_concatenation'),
intro: i18nT('workflow:intro_text_concatenation'),
version: '486',
inputs: [
{
...Input_Template_DynamicInput,
description: '可以引用其他节点的输出,作为文本拼接的变量,输入 / 唤起变量列表',
description: i18nT('workflow:dynamic_input_description_concat'),
customInputConfig: {
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
showDescription: false,
@@ -38,15 +39,15 @@ export const TextEditorNode: FlowNodeTemplateType = {
renderTypeList: [FlowNodeInputTypeEnum.textarea],
valueType: WorkflowIOValueTypeEnum.string,
required: true,
label: '拼接文本',
placeholder: '可输入 / 唤起变量列表'
label: i18nT('workflow:concatenation_text'),
placeholder: i18nT('workflow:input_variable_list')
}
],
outputs: [
{
id: NodeOutputKeyEnum.text,
key: NodeOutputKeyEnum.text,
label: '拼接结果',
label: i18nT('workflow:concatenation_result'),
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.string
}

View File

@@ -61,7 +61,7 @@ export const ToolModule: FlowNodeTemplateType = {
{
...Input_Template_System_Prompt,
label: 'core.ai.Prompt',
label: i18nT('common:core.ai.Prompt'),
description: chatNodeSystemPromptTip,
placeholder: chatNodeSystemPromptTip
},
@@ -72,8 +72,8 @@ export const ToolModule: FlowNodeTemplateType = {
{
id: NodeOutputKeyEnum.answerText,
key: NodeOutputKeyEnum.answerText,
label: 'core.module.output.label.Ai response content',
description: 'core.module.output.description.Ai response content',
label: i18nT('common:core.module.output.label.Ai response content'),
description: i18nT('common:core.module.output.description.Ai response content'),
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}

View File

@@ -15,12 +15,10 @@ type InteractiveBasicType = {
type UserSelectInteractive = {
type: 'userSelect';
params: {
// description: string;
description: string;
userSelectOptions: UserSelectOptionItemType[];
userSelectedVal?: string;
};
};
export type InteractiveNodeResponseItemType = InteractiveBasicType & UserSelectInteractive;
export type UserInteractiveType = UserSelectInteractive;

View File

@@ -6,6 +6,7 @@ import {
WorkflowIOValueTypeEnum
} from '../../../constants';
import { getHandleConfig } from '../../utils';
import { i18nT } from '../../../../../../web/i18n/utils';
export const VariableUpdateNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.variableUpdate,
@@ -14,8 +15,8 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/variableUpdate',
name: '变量更新',
intro: '可以更新指定节点的输出值或更新全局变量',
name: i18nT('workflow:variable_update'),
intro: i18nT('workflow:update_specified_node_output_or_global_variable'),
showStatus: false,
isTool: false,
version: '481',

View File

@@ -31,7 +31,7 @@ export const WorkflowStart: FlowNodeTemplateType = {
forbidDelete: true,
unique: true,
version: '481',
inputs: [{ ...Input_Template_UserChatInput, toolDescription: '用户问题' }],
inputs: [{ ...Input_Template_UserChatInput, toolDescription: i18nT('workflow:user_question') }],
outputs: [
{
id: NodeOutputKeyEnum.userChatInput,

View File

@@ -28,7 +28,7 @@ export type WorkflowTemplateBasicType = {
};
export type WorkflowTemplateType = {
id: string;
parentId?: string;
parentId?: ParentIdType;
isFolder?: boolean;
name: string;
@@ -62,6 +62,8 @@ export type TemplateMarketListItemType = {
// system plugin
export type SystemPluginTemplateItemType = WorkflowTemplateType & {
customWorkflow?: string;
templateType: FlowNodeTemplateTypeEnum;
isTool?: boolean;
@@ -77,8 +79,6 @@ export type SystemPluginTemplateItemType = WorkflowTemplateType & {
description: string;
value?: any;
}[];
workflow: WorkflowTemplateBasicType;
};
export type THelperLine = {

View File

@@ -1,10 +1,16 @@
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './node/constant';
import {
chatHistoryValueDesc,
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from './node/constant';
import {
WorkflowIOValueTypeEnum,
NodeInputKeyEnum,
VariableInputEnum,
variableMap,
VARIABLE_NODE_ID
VARIABLE_NODE_ID,
NodeOutputKeyEnum
} from './constants';
import { FlowNodeInputItemType, FlowNodeOutputItemType, ReferenceValueProps } from './type/io.d';
import { StoreNodeItemType } from './type/node';
@@ -25,6 +31,8 @@ import {
import { IfElseResultEnum } from './template/system/ifElse/constant';
import { RuntimeNodeItemType } from './runtime/type';
import { getReferenceVariableValue } from './runtime/utils';
import { Input_Template_History, Input_Template_UserChatInput } from './template/input';
import { i18nT } from '../../../web/i18n/utils';
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
return `${nodeId}-${type}-${key}`;
@@ -72,6 +80,10 @@ export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.chatInputGuide)?.value ||
defaultChatInputGuideConfig;
// plugin
const instruction: string =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.instruction)?.value || '';
return {
welcomeText,
variables,
@@ -79,7 +91,8 @@ export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
ttsConfig,
whisperConfig,
scheduledTriggerConfig,
chatInputGuide
chatInputGuide,
instruction
};
};
@@ -104,7 +117,8 @@ export const getAppChatConfig = ({
ttsConfig,
whisperConfig,
scheduledTriggerConfig,
chatInputGuide
chatInputGuide,
instruction
} = splitGuideModule(systemConfigNode);
const config: AppChatConfigType = {
@@ -113,6 +127,7 @@ export const getAppChatConfig = ({
whisperConfig,
scheduledTriggerConfig,
chatInputGuide,
instruction,
...chatConfig,
variables: storeVariables ?? chatConfig?.variables ?? variables,
welcomeText: storeWelcomeText ?? chatConfig?.welcomeText ?? welcomeText
@@ -147,9 +162,11 @@ export const getModuleInputUiField = (input: FlowNodeInputItemType) => {
return {};
};
export const pluginData2FlowNodeIO = (
nodes: StoreNodeItemType[]
): {
export const pluginData2FlowNodeIO = ({
nodes
}: {
nodes: StoreNodeItemType[];
}): {
inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[];
} => {
@@ -157,14 +174,17 @@ export const pluginData2FlowNodeIO = (
const pluginOutput = nodes.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginOutput);
return {
inputs: pluginInput
? pluginInput.inputs.map((item) => ({
...item,
...getModuleInputUiField(item),
value: getOrInitModuleInputValue(item),
canEdit: false
}))
: [],
inputs:
pluginInput?.inputs.map((item) => ({
...item,
...getModuleInputUiField(item),
value: getOrInitModuleInputValue(item),
canEdit: false,
renderTypeList:
item.renderTypeList[0] === FlowNodeInputTypeEnum.customVariable
? [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.input]
: item.renderTypeList
})) || [],
outputs: pluginOutput
? [
...pluginOutput.inputs.map((item) => ({
@@ -180,6 +200,80 @@ export const pluginData2FlowNodeIO = (
};
};
export const appData2FlowNodeIO = ({
chatConfig
}: {
chatConfig?: AppChatConfigType;
}): {
inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[];
} => {
const variableInput = !chatConfig?.variables
? []
: chatConfig.variables.map((item) => {
const renderTypeMap = {
[VariableInputEnum.input]: [FlowNodeInputTypeEnum.input, FlowNodeInputTypeEnum.reference],
[VariableInputEnum.textarea]: [
FlowNodeInputTypeEnum.textarea,
FlowNodeInputTypeEnum.reference
],
[VariableInputEnum.select]: [FlowNodeInputTypeEnum.select],
[VariableInputEnum.custom]: [
FlowNodeInputTypeEnum.input,
FlowNodeInputTypeEnum.reference
],
default: [FlowNodeInputTypeEnum.reference]
};
return {
key: item.key,
renderTypeList: renderTypeMap[item.type] || renderTypeMap.default,
label: item.label,
debugLabel: item.label,
description: '',
valueType: WorkflowIOValueTypeEnum.any,
required: item.required,
list: item.enums.map((enumItem) => ({
label: enumItem.value,
value: enumItem.value
}))
};
});
// const showFileLink =
// chatConfig?.fileSelectConfig?.canSelectFile || chatConfig?.fileSelectConfig?.canSelectImg;
return {
inputs: [
Input_Template_History,
Input_Template_UserChatInput,
// ...(showFileLink ? [Input_Template_File_Link] : []),
...variableInput
],
outputs: [
{
id: NodeOutputKeyEnum.history,
key: NodeOutputKeyEnum.history,
required: true,
label: i18nT('common:core.module.output.label.New context'),
description: i18nT('common:core.module.output.description.New context'),
valueType: WorkflowIOValueTypeEnum.chatHistory,
valueDesc: chatHistoryValueDesc,
type: FlowNodeOutputTypeEnum.static
},
{
id: NodeOutputKeyEnum.answerText,
key: NodeOutputKeyEnum.answerText,
required: false,
label: i18nT('common:core.module.output.label.Ai response content'),
description: i18nT('common:core.module.output.description.Ai response content'),
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static
}
]
};
};
export const formatEditorVariablePickerIcon = (
variables: { key: string; label: string; type?: `${VariableInputEnum}`; required?: boolean }[]
): EditorVariablePickerType[] => {
@@ -232,25 +326,8 @@ export const updatePluginInputByVariables = (
);
};
export const removePluginInputVariables = (
variables: Record<string, any>,
nodes: RuntimeNodeItemType[]
) => {
const pluginInputNode = nodes.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput);
if (!pluginInputNode) return variables;
return Object.keys(variables).reduce(
(acc, key) => {
if (!pluginInputNode.inputs.find((input) => input.key === key)) {
acc[key] = variables[key];
}
return acc;
},
{} as Record<string, any>
);
};
export function replaceVariableLabel({
// replace {{$xx.xx$}} variables for text
export function replaceEditorVariable({
text,
nodes,
variables,
@@ -258,7 +335,7 @@ export function replaceVariableLabel({
}: {
text: any;
nodes: RuntimeNodeItemType[];
variables: Record<string, string | number>;
variables: Record<string, any>; // global variables
runningNode: RuntimeNodeItemType;
}) {
if (typeof text !== 'string') return text;

View File

@@ -11,7 +11,7 @@
"jschardet": "3.1.1",
"nanoid": "^4.0.1",
"next": "14.2.5",
"openai": "4.53.0",
"openai": "4.57.0",
"openapi-types": "^12.1.3",
"timezones-list": "^3.0.2"
},

View File

@@ -1,19 +1,19 @@
import { NullPermission, PermissionKeyEnum, PermissionList } from '../constant';
import { PermissionListType } from '../type';
import { i18nT } from '../../../../web/i18n/utils';
export enum AppPermissionKeyEnum {}
export const AppPermissionList: PermissionListType = {
[PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read],
description: '可使用该应用进行对话'
description: i18nT('app:permission.des.read')
},
[PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write],
description: '可查看和编辑应用'
description: i18nT('app:permission.des.write')
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
description: '写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限'
description: i18nT('app:permission.des.manage')
}
};

View File

@@ -1,6 +1,6 @@
import { Permission } from './controller';
import { PermissionListType } from './type';
import { i18nT } from '../../../web/i18n/utils';
export enum AuthUserTypeEnum {
token = 'token',
root = 'root',
@@ -27,15 +27,15 @@ export const PermissionTypeMap = {
},
[PermissionTypeEnum.publicRead]: {
iconLight: 'support/permission/publicLight',
label: '团队可访问'
label: i18nT('user:permission.team_read')
},
[PermissionTypeEnum.publicWrite]: {
iconLight: 'support/permission/publicLight',
label: '团队可编辑'
label: i18nT('user:permission.team_write')
},
[PermissionTypeEnum.clbPrivate]: {
iconLight: 'support/permission/privateLight',
label: '仅协作者'
label: i18nT('user:permission.only_collaborators')
}
};
@@ -53,19 +53,19 @@ export enum PermissionKeyEnum {
}
export const PermissionList: PermissionListType = {
[PermissionKeyEnum.read]: {
name: '读权限',
name: i18nT('common:permission.read'),
description: '',
value: 0b100,
checkBoxType: 'single'
},
[PermissionKeyEnum.write]: {
name: '写权限',
name: i18nT('common:permission.write'),
description: '',
value: 0b110, // 如果某个资源有特殊要求,再重写这个值
checkBoxType: 'single'
},
[PermissionKeyEnum.manage]: {
name: '管理员',
name: i18nT('common:permission.manager'),
description: '',
value: 0b111,
checkBoxType: 'single'

View File

@@ -1,3 +1,4 @@
import { i18nT } from '../../../../web/i18n/utils';
import { NullPermission, PermissionKeyEnum, PermissionList } from '../constant';
export enum DatasetPermissionKeyEnum {}
@@ -5,15 +6,15 @@ export enum DatasetPermissionKeyEnum {}
export const DatasetPermissionList = {
[PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read],
description: '可查看知识库内容'
description: i18nT('dataset:permission.des.read')
},
[PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write],
description: '可增加和变更知识库内容'
description: i18nT('dataset:permission.des.write')
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
description: '可管理整个知识库数据和信息'
description: i18nT('dataset:permission.des.manage')
}
};

View File

@@ -1,18 +1,18 @@
import { PermissionKeyEnum, PermissionList, ReadPermissionVal } from '../constant';
import { PermissionListType } from '../type';
import { i18nT } from '../../../../web/i18n/utils';
export const TeamPermissionList: PermissionListType = {
[PermissionKeyEnum.read]: {
...PermissionList[PermissionKeyEnum.read],
description: '成员仅可阅读相关资源,无法新建资源'
description: i18nT('user:permission_des.read')
},
[PermissionKeyEnum.write]: {
...PermissionList[PermissionKeyEnum.write],
description: '除了可读资源外,还可以新建新的资源'
description: i18nT('user:permission_des.write')
},
[PermissionKeyEnum.manage]: {
...PermissionList[PermissionKeyEnum.manage],
description: '可创建资源、邀请、删除成员'
description: i18nT('user:permission_des.manage')
}
};

View File

@@ -2,12 +2,14 @@ export enum UserAuthTypeEnum {
register = 'register',
findPassword = 'findPassword',
wxLogin = 'wxLogin',
bindNotification = 'bindNotification'
bindNotification = 'bindNotification',
captcha = 'captcha'
}
export const userAuthTypeMap = {
[UserAuthTypeEnum.register]: 'register',
[UserAuthTypeEnum.findPassword]: 'findPassword',
[UserAuthTypeEnum.wxLogin]: 'wxLogin',
[UserAuthTypeEnum.bindNotification]: 'bindNotification'
[UserAuthTypeEnum.bindNotification]: 'bindNotification',
[UserAuthTypeEnum.captcha]: 'captcha'
};

View File

@@ -1,16 +1,25 @@
import { StandardSubLevelEnum, SubModeEnum } from '../sub/constants';
import { BillTypeEnum } from './constants';
export type CreateBillProps = {
type: BillTypeEnum;
// balance
balance?: number; // read
month?: number;
// extra dataset size
extraDatasetSize?: number; // 1k
extraPoints?: number; // 100w
export type CreateStandPlanBill = {
type: BillTypeEnum.standSubPlan;
level: `${StandardSubLevelEnum}`;
subMode: `${SubModeEnum}`;
};
type CreateExtractPointsBill = {
type: BillTypeEnum.extraPoints;
extraPoints: number;
};
type CreateExtractDatasetBill = {
type: BillTypeEnum.extraDatasetSub;
extraDatasetSize: number;
month: number;
};
export type CreateBillProps =
| CreateStandPlanBill
| CreateExtractPointsBill
| CreateExtractDatasetBill;
export type CreateBillResponse = {
billId: string;
codeUrl: string;

View File

@@ -19,7 +19,6 @@ export type BillSchemaType = {
month?: number;
datasetSize?: number;
extraPoints?: number;
invoice: boolean;
};
};

View File

@@ -1,3 +1,5 @@
import { i18nT } from '../../../../web/i18n/utils';
export enum SubTypeEnum {
standard = 'standard',
extraDatasetSize = 'extraDatasetSize',
@@ -19,19 +21,6 @@ export const subTypeMap = {
}
};
export enum SubStatusEnum {
active = 'active',
expired = 'expired'
}
export const subStatusMap = {
[SubStatusEnum.active]: {
label: 'support.wallet.subscription.status.active'
},
[SubStatusEnum.expired]: {
label: 'support.wallet.subscription.status.canceled'
}
};
export enum SubModeEnum {
month = 'month',
year = 'year'
@@ -39,11 +28,13 @@ export enum SubModeEnum {
export const subModeMap = {
[SubModeEnum.month]: {
label: 'support.wallet.subscription.mode.Month',
durationMonth: 1
durationMonth: 1,
payMonth: 1
},
[SubModeEnum.year]: {
label: 'support.wallet.subscription.mode.Year',
durationMonth: 12
durationMonth: 12,
payMonth: 10
}
};
@@ -56,23 +47,28 @@ export enum StandardSubLevelEnum {
}
export const standardSubLevelMap = {
[StandardSubLevelEnum.free]: {
label: 'support.wallet.subscription.standardSubLevel.free',
desc: 'support.wallet.subscription.standardSubLevel.free desc'
label: i18nT('common:support.wallet.subscription.standardSubLevel.free'),
desc: i18nT('common:support.wallet.subscription.standardSubLevel.free desc'),
weight: 1
},
[StandardSubLevelEnum.experience]: {
label: 'support.wallet.subscription.standardSubLevel.experience',
desc: ''
label: i18nT('common:support.wallet.subscription.standardSubLevel.experience'),
desc: i18nT('common:support.wallet.subscription.standardSubLevel.experience_desc'),
weight: 2
},
[StandardSubLevelEnum.team]: {
label: 'support.wallet.subscription.standardSubLevel.team',
desc: ''
label: i18nT('common:support.wallet.subscription.standardSubLevel.team'),
desc: i18nT('common:support.wallet.subscription.standardSubLevel.team_desc'),
weight: 3
},
[StandardSubLevelEnum.enterprise]: {
label: 'support.wallet.subscription.standardSubLevel.enterprise',
desc: ''
label: i18nT('common:support.wallet.subscription.standardSubLevel.enterprise'),
desc: i18nT('common:support.wallet.subscription.standardSubLevel.enterprise_desc'),
weight: 4
},
[StandardSubLevelEnum.custom]: {
label: 'support.wallet.subscription.standardSubLevel.custom',
desc: ''
label: i18nT('common:support.wallet.subscription.standardSubLevel.custom'),
desc: '',
weight: 5
}
};

View File

@@ -1,4 +1,4 @@
import { StandardSubLevelEnum, SubModeEnum, SubStatusEnum, SubTypeEnum } from './constants';
import { StandardSubLevelEnum, SubModeEnum, SubTypeEnum } from './constants';
// Content of plan
export type TeamStandardSubPlanItemType = {
@@ -36,17 +36,14 @@ export type TeamSubSchema = {
_id: string;
teamId: string;
type: `${SubTypeEnum}`;
status: `${SubStatusEnum}`;
startTime: Date;
expiredTime: Date;
price: number;
currentMode: `${SubModeEnum}`;
nextMode: `${SubModeEnum}`;
currentSubLevel: `${StandardSubLevelEnum}`;
nextSubLevel: `${StandardSubLevelEnum}`;
currentSubLevel: StandardSubLevelEnum;
nextSubLevel: StandardSubLevelEnum;
pointPrice: number;
totalPoints: number;
surplusPoints: number;

View File

@@ -14,13 +14,13 @@ export enum UsageSourceEnum {
export const UsageSourceMap = {
[UsageSourceEnum.fastgpt]: {
label: '在线使用'
label: i18nT('common:core.chat.logs.online')
},
[UsageSourceEnum.api]: {
label: 'Api'
},
[UsageSourceEnum.shareLink]: {
label: '免登录链接'
label: i18nT('common:core.chat.logs.free_login')
},
[UsageSourceEnum.training]: {
label: 'dataset.Training Name'

View File

@@ -2,11 +2,14 @@ import { markdownProcess } from '@fastgpt/global/common/string/markdown';
import { uploadMongoImg } from '../image/controller';
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
import { addHours } from 'date-fns';
import FormData from 'form-data';
import { WorkerNameEnum, runWorker } from '../../../worker/utils';
import fs from 'fs';
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
import type { ReadFileResponse } from '../../../worker/readFile/type';
import axios from 'axios';
import { addLog } from '../../system/log';
export type readRawTextByLocalFileParams = {
teamId: string;
@@ -51,15 +54,7 @@ export const readRawContentByFileBuffer = async ({
metadata?: Record<string, any>;
}) => {
// Upload image in markdown
const matchMdImgTextAndUpload = ({
teamId,
md,
metadata
}: {
md: string;
teamId: string;
metadata?: Record<string, any>;
}) =>
const matchMdImgTextAndUpload = ({ teamId, md }: { md: string; teamId: string }) =>
markdownProcess({
rawText: md,
uploadImgController: (base64Img) =>
@@ -72,18 +67,63 @@ export const readRawContentByFileBuffer = async ({
})
});
let { rawText, formatText } = await runWorker<ReadFileResponse>(WorkerNameEnum.readFile, {
extension,
encoding,
buffer
});
/* If */
const customReadfileUrl = process.env.CUSTOM_READ_FILE_URL;
const customReadFileExtension = process.env.CUSTOM_READ_FILE_EXTENSION || '';
const ocrParse = process.env.CUSTOM_READ_FILE_OCR || 'false';
const readFileFromCustomService = async (): Promise<ReadFileResponse | undefined> => {
if (
!customReadfileUrl ||
!customReadFileExtension ||
!customReadFileExtension.includes(extension)
)
return;
const start = Date.now();
const data = new FormData();
data.append('file', buffer, {
filename: `file.${extension}`
});
data.append('extension', extension);
data.append('ocr', ocrParse);
const { data: response } = await axios.post<{
success: boolean;
message: string;
data: {
page: number;
markdown: string;
};
}>(customReadfileUrl, data, {
timeout: 600000,
headers: {
...data.getHeaders()
}
});
addLog.info(`Use custom read file service, time: ${Date.now() - start}ms`);
const rawText = response.data.markdown;
return {
rawText,
formatText: rawText
};
};
let { rawText, formatText } =
(await readFileFromCustomService()) ||
(await runWorker<ReadFileResponse>(WorkerNameEnum.readFile, {
extension,
encoding,
buffer
}));
// markdown data format
if (['md', 'html', 'docx'].includes(extension)) {
if (['md', 'html', 'docx', ...customReadFileExtension.split(',')].includes(extension)) {
rawText = await matchMdImgTextAndUpload({
teamId: teamId,
md: rawText,
metadata: metadata
md: rawText
});
}

View File

@@ -101,3 +101,5 @@ export const urlsFetch = async ({
return response;
};
export const loadContentByCheerio = async (content: string) => cheerio.load(content);

View File

@@ -48,7 +48,7 @@ export class PgVectorCtrl {
const { teamId, datasetId, collectionId, vector, retry = 3 } = props;
try {
const { rows } = await PgClient.insert(DatasetVectorTableName, {
const { rowCount, rows } = await PgClient.insert(DatasetVectorTableName, {
values: [
[
{ key: 'vector', value: `[${vector}]` },
@@ -58,6 +58,11 @@ export class PgVectorCtrl {
]
]
});
if (rowCount === 0) {
return Promise.reject('insertDatasetData: no insert');
}
return {
insertId: rows[0].id
};

View File

@@ -3,7 +3,7 @@ import { getAIApi } from '../config';
import { countGptMessagesTokens } from '../../../common/string/tiktoken/index';
import { loadRequestMessages } from '../../chat/utils';
export const Prompt_QuestionGuide = `你是一个AI智能助手可以回答和解决我的问题。请结合前面的对话记录帮我生成 3 个问题引导我继续提问。问题的长度应小于20个字符按 JSON 格式返回: ["问题1", "问题2", "问题3"]`;
export const Prompt_QuestionGuide = `你是一个AI智能助手可以回答和解决我的问题。请结合前面的对话记录帮我生成 3 个问题,引导我继续提问,生成问题的语言要与原问题相同。问题的长度应小于20个字符按 JSON 格式返回: ["问题1", "问题2", "问题3"]`;
export async function createQuestionGuide({
messages,
@@ -19,6 +19,7 @@ export async function createQuestionGuide({
content: Prompt_QuestionGuide
}
];
const ai = getAIApi({
timeout: 480000
});

View File

@@ -50,9 +50,11 @@ export const getAppLatestVersion = async (appId: string, app?: AppSchema) => {
const version = await MongoAppVersion.findOne({
appId,
isPublish: true
}).sort({
time: -1
});
})
.sort({
time: -1
})
.lean();
if (version) {
return {

View File

@@ -1,6 +1,6 @@
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node.d';
import { FlowNodeTypeEnum, defaultNodeVersion } from '@fastgpt/global/core/workflow/node/constant';
import { pluginData2FlowNodeIO } from '@fastgpt/global/core/workflow/utils';
import { appData2FlowNodeIO, pluginData2FlowNodeIO } from '@fastgpt/global/core/workflow/utils';
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
import type { PluginRuntimeType } from '@fastgpt/global/core/workflow/runtime/type';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
@@ -52,10 +52,10 @@ const getPluginTemplateById = async (
showStatus: true,
workflow: {
nodes: item.modules,
edges: item.edges
edges: item.edges,
chatConfig: item.chatConfig
},
templateType: FlowNodeTemplateTypeEnum.teamApp,
isTool: true,
version: item?.pluginData?.nodeVersion || defaultNodeVersion,
originCost: 0,
currentCost: 0
@@ -71,22 +71,27 @@ const getPluginTemplateById = async (
/* format plugin modules to plugin preview module */
export async function getPluginPreviewNode({ id }: { id: string }): Promise<FlowNodeTemplateType> {
const plugin = await getPluginTemplateById(id);
const isPlugin = !!plugin.workflow.nodes.find(
(node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput
);
return {
id: getNanoid(),
pluginId: plugin.id,
templateType: plugin.templateType,
flowNodeType: FlowNodeTypeEnum.pluginModule,
flowNodeType: isPlugin ? FlowNodeTypeEnum.pluginModule : FlowNodeTypeEnum.appModule,
avatar: plugin.avatar,
name: plugin.name,
intro: plugin.intro,
inputExplanationUrl: plugin.inputExplanationUrl,
showStatus: plugin.showStatus,
isTool: plugin.isTool,
isTool: isPlugin,
version: plugin.version,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
...pluginData2FlowNodeIO(plugin.workflow.nodes)
...(isPlugin
? pluginData2FlowNodeIO({ nodes: plugin.workflow.nodes })
: appData2FlowNodeIO({ chatConfig: plugin.workflow.chatConfig }))
};
}

View File

@@ -24,7 +24,8 @@ const SystemPluginSchema = new Schema({
currentCost: {
type: Number,
default: 0
}
},
customConfig: Object
});
SystemPluginSchema.index({ pluginId: 1 });

View File

@@ -1,4 +1,8 @@
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
import {
SystemPluginTemplateItemType,
WorkflowTemplateBasicType
} from '@fastgpt/global/core/workflow/type';
export type SystemPluginConfigSchemaType = {
pluginId: string;
@@ -7,4 +11,14 @@ export type SystemPluginConfigSchemaType = {
currentCost: number;
isActive: boolean;
inputConfig: SystemPluginTemplateItemType['inputConfig'];
customConfig?: {
name: string;
avatar: string;
intro?: string;
version: string;
weight?: number;
workflow: WorkflowTemplateBasicType;
templateType: FlowNodeTemplateTypeEnum;
};
};

View File

@@ -18,7 +18,8 @@ export const chatConfigType = {
whisperConfig: Object,
scheduledTriggerConfig: Object,
chatInputGuide: Object,
fileSelectConfig: Object
fileSelectConfig: Object,
instruction: String
};
// schema

View File

@@ -1,7 +1,7 @@
import type { ChatItemType, ChatItemValueItemType } from '@fastgpt/global/core/chat/type';
import { MongoChatItem } from './chatItemSchema';
import { addLog } from '../../common/system/log';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
import { delFileByFileIdList, getGFSCollection } from '../../common/file/gridfs/controller';
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
import { MongoChat } from './chatSchema';
@@ -35,7 +35,8 @@ export async function getChatItems({
return { histories };
}
/* 临时适配旧的对话记录 */
/* Temporary adaptation for old conversation records */
export const adaptStringValue = (value: any): ChatItemValueItemType[] => {
if (typeof value === 'string') {
return [
@@ -79,52 +80,6 @@ export const addCustomFeedbacks = async ({
}
};
/*
Update the user selected index of the interactive module
*/
export const updateUserSelectedResult = async ({
appId,
chatId,
userSelectedVal
}: {
appId: string;
chatId?: string;
userSelectedVal: string;
}) => {
if (!chatId) return;
try {
const chatItem = await MongoChatItem.findOne(
{ appId, chatId, obj: ChatRoleEnum.AI },
'value'
).sort({ _id: -1 });
if (!chatItem) return;
const interactiveValue = chatItem.value.find(
(v) => v.type === ChatItemValueTypeEnum.interactive
);
if (
!interactiveValue ||
interactiveValue.type !== ChatItemValueTypeEnum.interactive ||
!interactiveValue.interactive?.params
)
return;
interactiveValue.interactive = {
...interactiveValue.interactive,
params: {
...interactiveValue.interactive.params,
userSelectedVal
}
};
await chatItem.save();
} catch (error) {
addLog.error('updateUserSelectedResult error', error);
}
};
/*
Delete chat files
1. ChatId: Delete one chat files

View File

@@ -1,6 +1,10 @@
import type { AIChatItemType, UserChatItemType } from '@fastgpt/global/core/chat/type.d';
import { MongoApp } from '../app/schema';
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
import {
ChatItemValueTypeEnum,
ChatRoleEnum,
ChatSourceEnum
} from '@fastgpt/global/core/chat/constants';
import { MongoChatItem } from './chatItemSchema';
import { MongoChat } from './chatSchema';
import { addLog } from '../../common/system/log';
@@ -111,3 +115,85 @@ export async function saveChat({
addLog.error(`update chat history error`, error);
}
}
export const updateInteractiveChat = async ({
chatId,
appId,
teamId,
tmbId,
userSelectedVal,
aiResponse,
newVariables,
newTitle
}: {
chatId: string;
appId: string;
teamId: string;
tmbId: string;
userSelectedVal: string;
aiResponse: AIChatItemType & { dataId?: string };
newVariables?: Record<string, any>;
newTitle: string;
}) => {
if (!chatId) return;
const chatItem = await MongoChatItem.findOne({ appId, chatId, obj: ChatRoleEnum.AI }).sort({
_id: -1
});
if (!chatItem || chatItem.obj !== ChatRoleEnum.AI) return;
const interactiveValue = chatItem.value[chatItem.value.length - 1];
if (
!interactiveValue ||
interactiveValue.type !== ChatItemValueTypeEnum.interactive ||
!interactiveValue.interactive?.params
) {
return;
}
interactiveValue.interactive = {
...interactiveValue.interactive,
params: {
...interactiveValue.interactive.params,
userSelectedVal
}
};
if (aiResponse.customFeedbacks) {
chatItem.customFeedbacks = chatItem.customFeedbacks
? [...chatItem.customFeedbacks, ...aiResponse.customFeedbacks]
: aiResponse.customFeedbacks;
}
if (aiResponse.responseData) {
chatItem.responseData = chatItem.responseData
? [...chatItem.responseData, ...aiResponse.responseData]
: aiResponse.responseData;
}
if (aiResponse.value) {
chatItem.value = chatItem.value ? [...chatItem.value, ...aiResponse.value] : aiResponse.value;
}
await mongoSessionRun(async (session) => {
await chatItem.save({ session });
await MongoChat.updateOne(
{
appId,
chatId
},
{
$set: {
variables: newVariables,
title: newTitle,
updateTime: new Date()
}
},
{
session
}
);
});
};

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