Compare commits

...

111 Commits

Author SHA1 Message Date
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
Archer
ace84f015e 4.8.10 test (#2499)
* 48190 init

* path
2024-08-25 01:06:18 +08:00
heheer
bb7adc96ed perf: disabled change version when change version name (#2497)
* perf: disabled change version when change version name

* fix

* fix

* toast condition
2024-08-25 00:49:33 +08:00
Archer
ad63210f45 perf: onpublish app (#2498) 2024-08-24 23:43:52 +08:00
Archer
fa106eb24c fix: dispatch workflow skip status (#2496) 2024-08-24 23:36:59 +08:00
heheer
3248e95d53 fix: undo & redo (#2493)
* fix: undo & redo

* fix

* fix
2024-08-24 23:15:28 +08:00
Archer
3e57c7f559 perf: workflow code (#2492)
* perf: workflow code

* perf: converpoints ui

* perf: account page ui
2024-08-23 17:56:38 +08:00
Finley Ge
eaaf6f5978 feat(fe): balance conversion button and modal (#2491)
* feat: add balance conversion api declaration

* feat(fe): add conversion modal

* fix: show button when standplan and the user has manage permission

* feat: hide balance when <= 0
2024-08-23 17:14:07 +08:00
heheer
6288dc9492 feat: undo-redo & edit snapshots (#2436)
* feat: undo-redo & edit snapshots

* fix merge

* add simple history back

* fix some undo

* change app latest version

* fix

* chatconfig

* fix snapshot

* fix

* fix

* fix

* fix compare

* fix initial

* fix merge:

* fix useEffect

* fix snapshot initial and saved state

* chore

* fix

* compare snapshot

* nodes edges useEffct

* fix chatconfig

* fix

* delete unused method

* fix

* fix

* fix

* default version name
2024-08-23 15:58:43 +08:00
Archer
de573e4303 4.8.10 test fix (#2488)
* perf: update vision default

* fix: update dataset default permission

* perf: no network request
2024-08-23 14:57:52 +08:00
Archer
b3acd570f7 4.8.10 test (#2470)
* i18n

* perf: invoice type

* fix: helper line change error

* perf: base64 image

* perf: app list ui

* perf: upload max size check

* perf: init system plugin

* perf: dataset list ui

* perf: http node ui

* perf: ui

* perf: invoice tip

* fix: ts

* perf: invoice table

* perf: null check
2024-08-22 13:43:19 +08:00
Archer
19904e648b Update official_account.md (#2472) 2024-08-22 13:38:52 +08:00
Archer
785ba03239 Update official_account.md (#2471) 2024-08-22 13:37:05 +08:00
papapatrick
366fe0eada perf: invoice page refresh after apply (#2469)
* perf: 发票申请弹窗成功后刷新

* refactor: 组件内拿invoiceTab
2024-08-22 12:24:33 +08:00
Archer
225554f22c Update README.md (#2468) 2024-08-22 10:12:40 +08:00
heheer
5627a4bfde feat: add http node timeout (#2465)
* fix $ in replacement string misinterpreted as regex special character

* add http timeout

* delete console log
2024-08-21 20:23:35 +08:00
papapatrick
113c57bcbe style: database refactor (#2460)
* fix: dataset folder modal

* style: dataset style refactor

* sideTag i18n pef
2024-08-21 18:15:05 +08:00
Finley Ge
649de7f028 pref: login/forgetpass texts (#2457)
* chore: fastgptfeconfig type

* pref: login, forget password, texts
2024-08-21 14:46:53 +08:00
Archer
26d800981c 4.8.10 test (#2433)
* perf: node template ui

* perf: select tool path load error

* pay i18n

* i18n

* perf: oneapi code

* perf: doc

* node templates

* perf: usage table role

* feat: count vector total by datasetId

* perf: user select tip and tempalte market ui

* i18n

* perf: sso config tip
2024-08-20 18:31:40 +08:00
papapatrick
40b1d22d9d style: 知识库新列表 (#2448)
* style: 知识库新列表

* i18n adjust

* fix:  i18n
2024-08-20 17:29:41 +08:00
Finley Ge
2d0e6bd085 feat: SSO (#2414)
* feat: sso button

* feat: sso

* feat: sso callback url should be a page

* feat: sso redirect page

* chore: sso fe adjusting
2024-08-20 17:09:29 +08:00
Finley Ge
226cae5ab9 perf: add docs entries in the publish page (#2449) 2024-08-20 17:08:45 +08:00
Finley Ge
238381256d feat: custom-censor-check (#2437)
* feat: custom-censor-check

* chore: adjust
2024-08-20 10:05:19 +08:00
Archer
5fab3734fa Invoice (#2435)
* feat: invoice (#2293)

* feat: default voice header

* add i18n

* refactor: 优化代码

* feat: 用户开票

* refactor: 代码优化&&样式联调 (#2384)

* Feat: invoice upload (#2424)

* refactor: 验收问题&&样式调整

* feat: 文件上传

* 小调整

* perf: invoice ui

---------

Co-authored-by: papapatrick <109422393+Patrickill@users.noreply.github.com>
2024-08-19 17:44:48 +08:00
papapatrick
884c2d9553 fix: i18n display (#2429) 2024-08-19 15:15:33 +08:00
Finley Ge
918d7fb257 docs(offiaccount): add offiaccount docs (#2427) 2024-08-19 12:17:15 +08:00
heheer
0719f7bd4a chore(ui): dataset-tags (#2415) 2024-08-16 18:32:20 +08:00
Finley Ge
9b74437417 fix(publish): generate correct chat history and usage (#2412) 2024-08-16 15:59:17 +08:00
heheer
bebbba399a perf: change value desc position & fix templates (#2413) 2024-08-16 15:58:21 +08:00
Archer
14e22687e3 4.8.10 test (#2411)
* update doc

* update doc

* update doc imgs
2024-08-16 13:27:44 +08:00
Archer
61347d9aaa 4.8.10 test (#2401)
* perf: i18n

* perf: i18n and img tip

* perf: readme

* perf: hide tool ai response

* fix: copy app

* fix: parse image url regx

* perf: folder collection forbid update
2024-08-16 13:09:17 +08:00
折戟沉沙、丿
5bf0dd0ef1 feat(http): text/plain is allowed (#2376)
* feat(http): plan/txt is allowed

* Update http468.ts

* Update http468.ts

* body 添加string类型
2024-08-16 10:03:43 +08:00
何翀彬
5545e84bb9 调整.env.template关于mongodb的说明,使得更易于理解 (#2398) 2024-08-16 09:58:50 +08:00
Archer
86c27e85ef 4.8.10 perf (#2378)
* perf: helpline code

* fix: prompt call stream=false response prefix

* fix: app chat log auth

* perf: new chat i18n

* fix: milvus dataset cannot export data

* perf: doc intro
2024-08-15 13:12:39 +08:00
Archer
fdeb1590d7 User select node (#2397)
* feat: add user select node (#2300)

* feat: add user select node

* fix

* type

* fix

* fix

* fix

* perf: user select code

* perf: user select histories

* perf: i18n

---------

Co-authored-by: heheer <heheer@sealos.io>
2024-08-15 12:27:04 +08:00
Finley Ge
f8b8fcc172 feat(publish): Wechat OffiAccount (#2386)
* feat: OffiAccount fe

* feat: offiaccount

* fix: wecom requires AES key

* fix: OffiAccountEditModal

* chore: change wechat svg icon

* chore: add offiaccount svg

* chore: hide unimplemented wecom entries
2024-08-15 12:06:13 +08:00
changan-77
5bbaa8264a Update feishu.md (#2382) 2024-08-14 11:45:03 +08:00
Archer
0f3418daf5 Publish app - feishu and wecom (#2375)
* feat(app publish): feishu bot (#2290)

* feat: feishu publish channel fe

* feat: enable feishu fe,
feat: feishu token api

* feat: feishu bot

* chore: extract saveChat from projects/app

* chore: remove debug log output

* feat: Basic Info

* chore: feishu bot fe adjusting

* feat: feishu bot docs

* feat: new tmpData collection for all tmpdata

* chore: compress the image

* perf: feishu config

* feat: source name

* perf: text desc

* perf: load system plugins

* perf: chat source

* feat(publish): Wecom bot (#2343)

* chore: Wecom Config

* feat(fe): wecom config fe

* feat: wecom fe

* chore: uses the newest editmodal

* feat: update png; adjust the fe

* chore: adjust fe

* perf: publish app ui

---------

Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
2024-08-13 21:52:18 +08:00
heheer
7417de74da feat: add workflow helperline (#2356)
* feat: add workflow helperline

* del console

* across zoom & adjust distance
2024-08-13 21:42:17 +08:00
Archer
fe9cb437e5 feat: file input doc (#2359) 2024-08-13 14:25:49 +08:00
Zong
2827c633cd docs(bge-rerank): qa docs (#2358) 2024-08-13 14:11:38 +08:00
Archer
dd1e2d5eb7 Update 489.md (#2353) 2024-08-13 10:06:29 +08:00
Zong
6293801bfa fix(docs): home host typo (#2352) 2024-08-13 10:04:34 +08:00
Zong
7f2aa97de7 fix(docs): reranker typo (#2341) 2024-08-12 18:25:06 +08:00
Archer
2196930005 App template market (#2337)
* feat: add app template market (#2012)

* feat: add app template market

* fix

* fix

* i18n

* fix

* perf: template market ux

* perf: simple mode app ui

* perf: tempalte modal ui

* perf: tempalte market ui

* perf: template position

* feat: create app modal

* regiter default app

* perf: icon

* change templates position (#2331)

* change templates position

* fix

* perf: template market ux

---------

Co-authored-by: heheer <heheer@sealos.io>
2024-08-12 16:21:21 +08:00
Archer
231afc4ac5 Update README.md (#2335) 2024-08-12 13:58:49 +08:00
Archer
2dc0b0fbec feat: 4.8.9 doc (#2334)
* feat: 4.8.9 doc

* doc

* README.md
2024-08-12 13:58:04 +08:00
Archer
72bb3f667b fix: doc (#2332) 2024-08-12 12:15:09 +08:00
Archer
02d6b7c788 4.8.9 test fix (#2330)
* perf: query extension prompt

* perf: get preview histories

* perf: i18n

* fix: share page cannot feedback

* fix: publish i18n
2024-08-12 12:09:14 +08:00
Archer
e098b2f1dc Update ExtraPlan.tsx 2024-08-10 00:43:25 +08:00
Finley Ge
832a4d6638 chore: change notification account bind hint text (#2310) 2024-08-09 17:56:03 +08:00
Menghuan1918
4d570ecd4f 修改插件:Doc2X插件适配文件上传功能 (#2284)
* Change to download first and check contentType

* Up to date

* Some bug fix, still some bug with img

* Update tool to read from file

* improve formatting in PDF

* Add tool of img file OCR , but meet some bug

* Bug fix for parameter passing error.

* Modification Introduction
2024-08-08 18:56:05 +08:00
Zong
067f3f4098 fix(query): extension prompt template (#2288) 2024-08-08 18:47:34 +08:00
Archer
d682a8252f 4.8.9 test (#2299)
* perf: read file prompt

* perf: read file prompt

* perf: free plan tip

* feat: cron job usage

* perf: app templates

* perf: get llm model by name

* feat: support outlink upload file

* fix: upload limit
2024-08-08 17:45:15 +08:00
papapatrick
c6dd3076c5 fix: quote display error (#2298) 2024-08-08 14:41:21 +08:00
Finley Ge
b4f3a77b01 fix: bind notification account (#2297) 2024-08-08 14:40:56 +08:00
679 changed files with 27546 additions and 16814 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 228 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", // 根据此语言文件翻译其他语言文件的变量和内容

View File

@@ -100,11 +100,9 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
- **⚡ 快速部署**
> [Sealos](https://sealos.io) 服务器在国外,不需要额外处理网络问题,无需服务器、无需魔法、无需域名,支持高并发 & 动态伸缩。点击以下按钮即可一键部署 👇
> 使用 [Sealos](https://sealos.io) 服务,无需采购服务器、无需域名,支持高并发 & 动态伸缩,并且数据库应用采用 kubeblocks 的数据库,在 IO 性能方面,远超于简单的 Docker 容器部署。
[![](https://cdn.jsdelivr.net/gh/labring-actions/templates@main/Deploy-on-Sealos.svg)](https://cloud.sealos.io/?openapp=system-fastdeploy%3FtemplateName%3Dfastgpt)
由于需要部署数据库,部署完后需要等待 2~4 分钟才能正常访问。默认用了最低配置,首次访问时会有些慢。相关使用教程可查看:[Sealos 部署 FastGPT](https://doc.fastgpt.in/docs/development/sealos/)
[点击查看 Sealos 一键部署 FastGPT 教程](https://doc.fastgpt.in/docs/development/sealos/)
* [快速开始本地开发](https://doc.fastgpt.in/docs/development/intro/)
* [部署 FastGPT](https://doc.fastgpt.in/docs/development/sealos)
@@ -214,4 +212,4 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
1. 允许作为后台服务直接商用,但不允许提供 SaaS 服务。
2. 未经商业授权,任何形式的商用服务均需保留相关版权信息。
3. 完整请查看 [FastGPT Open Source License](./LICENSE)
4. 联系方式:yujinlong@sealos.io[点击查看商业版定价策略](https://doc.fastgpt.in/docs/commercial)
4. 联系方式:Dennis@sealos.io[点击查看商业版定价策略](https://doc.fastgpt.in/docs/commercial)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 KiB

After

Width:  |  Height:  |  Size: 299 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@@ -29,8 +29,8 @@ FastGPT 商业版是基于 FastGPT 开源版的增强版本,增加了一些独
| web站点同步 | ❌ | ✅ | ✅ |
| 管理后台 | ❌ | ✅ | 不需要 |
| 增强训练模式 | ❌ | ✅ | ✅ |
| 第三方应用快速接入(飞书、公众号) | ❌ | ✅ | ✅ |
| 图片知识库 | ❌ | 设计中 | 设计中 |
| 自动规划召回 | ❌ | 设计中 | 设计中 |
| 对话日志运营分析 | ❌ | 设计中 | 设计中 |
| 完整商业授权 | ❌ | ✅ | ✅ |
{{< /table >}}

View File

@@ -60,6 +60,8 @@ Tips: 可以通过点击上下文按键查看完整的上下文组成,便于
### 引用模板和提示词设计
简易模式已移除该功能,仅在工作流中可配置,可点击工作流中`AI对话节点`内,知识库引用旁边的`setting icon`进行配置。随着模型的增强,这部分功能将逐步弱化。
引用模板和引用提示词通常是成对出现,引用提示词依赖引用模板。
FastGPT 知识库采用 QA 对(不一定都是问答格式,仅代表两个变量)的格式存储,在转义成字符串时候会根据**引用模板**来进行格式化。知识库包含多个可用变量: q, a, sourceId数据的ID, index(第n个数据), source(数据的集合名、文件名)score(距离得分0-1) 可以通过 {{q}} {{a}} {{sourceId}} {{index}} {{source}} {{score}} 按需引入。下面一个模板例子:

View File

@@ -4,7 +4,7 @@ description: "FastGPT 知识库集合标签使用说明"
icon: "developer_guide"
draft: false
toc: true
weight: 108
weight: 109
---
知识库集合标签是 FastGPT 商业版特有功能。它允许你对知识库中的数据集合添加标签进行分类,更高效地管理知识库数据。

View File

@@ -0,0 +1,97 @@
---
title: "接入飞书机器人教程"
description: "FastGPT 接入飞书机器人教程"
icon: "chat"
draft: false
toc: true
weight: 111
---
从 4.8.10 版本起FastGPT 商业版支持直接接入飞书机器人,无需额外的 API。
## 1. 申请飞书应用
开一个免费的测试企业更方便进行调试。
1. 在[飞书开放平台](https://open.feishu.cn/app)的开发者后台申请企业自建应用。
![图片](/imgs/feishu-bot-1.png)
添加一个**机器人**应用。
## 2. 在 FastGPT 新建发布渠道
在fastgpt中选择想要接入的应用在 发布渠道 页面,新建一个接入飞书机器人的发布渠道,填写好基础信息。
![图片](/imgs/feishu-bot-2.png)
## 3. 获取应用的 App ID, App Secret 两个凭证
在飞书开放平台开发者后台,刚刚创建的企业自建应用中,找到 App ID 和 App Secret填入 FastGPT 新建发布渠道的对话框里面。
![图片](/imgs/feishu-bot-3.png)
填入两个参数到 FastGPT 配置弹窗中。
![图片](/imgs/feishu-bot-4.png)
(可选)在飞书开放平台开发者后台,点击事件与回调 -> 加密策略 获取 Encrypt Key并填入飞书机器人接入的对话框里面
![图片](/imgs/feishu-bot-5.png)
Encrypt Key 用于加密飞书服务器与 FastGPT 之间通信。
建议如果使用 Https 协议,则不需要 Encrypt Key。如果使用 Http 协议通信,则建议使用 Encrypt Key
Verification Token 默认生成的这个 Token 用于校验来源。但我们使用飞书官方推荐的另一种更为安全的校验方式,因此可以忽略这个配置项。
## 4. 配置回调地址
新建好发布渠道后,点击**请求地址**,复制对应的请求地址。
在飞书控制台,点击左侧的 `事件与回调` ,点击`配置订阅方式`旁边的编辑 icon粘贴刚刚复制的请求地址到输入框中。
| | | |
| --- | --- | --- |
| ![图片](/imgs/feishu-bot-10.jpg) | ![图片](/imgs/feishu-bot-11.jpg) | ![图片](/imgs/feishu-bot-6.png) |
## 5. 配置机器人回调事件和权限
* 添加 `接收消息` 事件
`事件与回调`页面,点击`添加事件`
搜索`接收消息`,或者直接搜索 `im.message.receive_v1` ,找到`接收消息 v2.0`的时间,勾选上并点击`确认添加`
添加事件后,增加两个权限:点击对应权限,会有弹窗提示添加权限,添加上图两个权限。
| | |
| --- | --- |
| ![图片](/imgs/feishu-bot-7.png) | ![图片](/imgs/feishu-bot-8.png) |
不推荐启用上图中的两个“历史版本”,而是使用新版本的权限。
- 若开启 “读取用户发给机器人的单聊消息”, 则单聊发送给机器人的消息将被送到 FastGPT
- 若开启 “接收群聊中@机器人消息事件”, 则群聊中@机器人的消息将被送到 FastGPT
- 若开启(不推荐开启)“获取群组中所有消息”,则群聊中所有消息都将被送到 FastGPT
## 6. 配置回复消息权限
在飞书控制台,点击左侧的 `权限管理` ,搜索框中输入`发消息`,找到`以应用的身份发消息`的权限,点击开通权限。
![](/imgs/feishu-bot-13.jpg)
## 7. 发布机器人
点击飞书控制台左侧的`版本管理与发布`,即可发布机器人。
![](/imgs/feishu-bot-12.jpg)
然后就可以在工作台里找到你的机器人啦。接下来就是把机器人拉进群组,或者单独与它对话。
![图片](/imgs/feishu-bot-9.png)
## FAQ
### 发送了消息,没响应
1. 检查飞书机器人回调地址、权限等是否正确。
2. 查看 FastGPT 对话日志,是否有对应的提问记录
3. 如果有记录,飞书没回应,则是没给机器人开权限。
4. 如果没记录,则可能是应用运行报错了,可以先试试最简单的机器人。(飞书机器人无法输入全局变量、文件、图片内容)

View File

@@ -0,0 +1,132 @@
---
title: '文件输入功能介绍'
description: 'FastGPT 文件输入功能介绍'
icon: 'description'
draft: false
toc: true
weight: 110
---
从 4.8.9 版本起FastGPT 支持在`简易模式``工作流`中,配置用户上传文件、图片功能。下面先简单介绍下如何使用文件输入功能,最后是介绍下文件解析的工作原理。
## 简易模式中使用
简易模式打开文件上传后,会使用工具调用模式,也就是由模型自行决策,是否需要读取文件内容。
可以找到左侧文件上传的配置项,点击其右侧的`开启`/`关闭`按键,即可打开配置弹窗。
![打开文件上传](/imgs/fileinpu-1.png)
随后,你的调试对话框中,就会出现一个文件选择的 icon可以点击文件选择 icon选择你需要上传的文件。
由于采用的是工具调用模式,所以在提问时候,可能需要加上适当的引导,让模型知道,你需要读取`文档`
![打开文件上传](/imgs/fileinpu-2.png)
## 工作流中使用
工作流中,可以在系统配置中,找到`文件输入`配置项,点击其右侧的`开启`/`关闭`按键,即可打开配置弹窗。
![打开文件上传](/imgs/fileinpu-4.jpg)
在工作流中,使用文件的方式很多,最简单的就是类似下图中,直接通过工具调用接入文档解析,实现和简易模式一样的效果。
![打开文件上传](/imgs/fileinpu-3.jpg)
也可以更简单点,强制每轮对话都携带上文档内容进行回答,这样就不需要调用两次 AI 才能读取文档内容了。
![打开文件上传](/imgs/fileinpu-5.jpg)
当然,你也可以在工作流中,对文档进行内容提取、内容分析等,然后将分析的结果传递给 HTTP 或者其他模块,从而实现文件处理的 SOP。不过目前版本`插件`中并未支持文件处理,所以在构建 SOP 的话可能还是有一些麻烦。
## 文档解析工作原理
不同于图片识别LLM 模型目前没有支持直接解析文档的能力,所有的文档“理解”都是通过文档转文字后拼接 prompt 实现。这里通过几个 FAQ 来解释文档解析的工作原理,理解文档解析的原理,可以更好的在工作流中使用文档解析功能。
### 上传的文件如何存储在数据库中
FastGPT 的对话记录存储结构中role=user 的消息value 值会按以下结构存储:
```ts
type UserChatItemValueItemType = {
type: 'text' | 'file'
text?: {
content: string;
};
file?: {
type: 'img' | 'doc'
name?: string;
url: string;
};
};
```
也就是说,上传的图片和文档,都会以 URL 的形式存储在库中,并不会存储`解析后的文档内容`
### 图片如何处理
文档解析节点不会处理图片,图片链接会被过滤,图片识别请直接使用支持图片识别的 LLM 模型。
### 文档解析节点如何工作
文档解析依赖文档解析节点,这个节点会接收一个`array<string>`类型的输入,对应的是文件输入的 URL输出的是一个`string`,对应的是文档解析后的内容。
![打开文件上传](/imgs/fileinpu-6.jpg)
* 在文档解析节点中,只会解析`文档`类型的 URL它是通过文件 URL 解析出来的`文名件后缀`去判断的。如果你同时选择了文档和图片,图片会被忽略。
* 文档解析节点,除了解析本轮工作流接收的文件外,还会把历史记录中的文档 URL 进行解析。最终会解析至多 n 个文档n 取决于你配置文件上传时,允许的最大文件数量。
{{% alert icon="🤖" context="success" %}}
举例:
配置了最多允许 5 个文件上传
1. 第一轮对话,上传 3 个文档和 1 个图片:文档解析节点,返回 3 个文档内容。
2. 第二轮对话,不上传任何文件:文档解析节点,返回 3 个文档内容。
3. 第三轮对话,上传 2 个文档:文档解析节点,返回 5 个文档内容。
4. 第四轮对话,上传 1 个文档:文档解析节点,返回 5 个文档内容,第一轮对话中的第三个文档会被过滤掉。
{{% /alert %}}
* 多个文档内容如何拼接的
按下列的模板,对多个文件进行拼接,即文件名+文件内容的形式组成一个字符串,不同文档之间通过分隔符:`\n******\n` 进行分割。
```
File: ${filename}
<Content>
${content}
</Content>
```
### 工具调用如何使用文档解析
在工具调用中,文档解析节点的调用提示词为:`解析对话中所有上传的文档,并返回对应文档内容`
作为工具被执行后,文档解析节点会返回解析后的文档内容作为工具响应。
### AI对话中如何使用文档解析
在 AI 对话节点中,新增了一个文档引用的输入,可以直接引用文档解析节点的输出,从而实现文档内容的引用。
它接收一个`string`类型的输入,除了可以引用文档解析结果外,还可以实现自定义内容引用,最终会进行提示词拼接,放置在 role=system 的消息中。提示词模板如下:
```
将 <Quote></Quote> 中的内容作为你的知识:
<Quote>
{{quote}}
</Quote>
```
quote 为引用的内容。
![打开文件上传](/imgs/fileinpu-7.jpg)
## 文件输入后续更新
* 插件支持配置文件输入。
* 子应用和插件调用,支持传递文件输入。
* 文档解析,结构化解析结果。
* 更多的文件类型输入以及解析器。

View File

@@ -1,133 +0,0 @@
---
title: " 打造高质量 AI 知识库(过期)"
description: " 利用 FastGPT 打造高质量 AI 知识库"
icon: "school"
draft: false
toc: true
weight: 300
---
## 前言
自从去年 12 月 ChatGPT 发布后,带动了新的一轮应用交互革命。尤其是 GPT-3.5 接口全面放开后LLM 应用雨后春笋般快速涌现,但因为 GPT 的可控性、随机性和合规性等问题,很多应用场景都没法落地。
3 月时候,在 Twitter 上刷到一个老哥使用 GPT 训练自己的博客记录,并且成本非常低(比起 FT。他给出了一个完整的流程图
![向量搜索 GPT 流程图](/imgs/1.png)
看到这个推文后,我灵机一动,应用场景就十分清晰了。直接上手开干,在经过不到 1 个月时间FastGPT 在原来多助手管理基础上,加入了向量搜索。于是便有了最早的一期视频:
{{< bilibili BV1Wo4y1p7i1 >}}
3 个月过去了FastGPT 延续着早期的思路去完善和扩展,目前在向量搜索 + LLM 线性问答方面的功能基本上完成了。不过我们始终没有出一期关于如何构建知识库的教程,趁着 V4 在开发中,我们计划介绍一期《如何在 FastGPT 上构建高质量知识库》,以便大家更好的使用。
## FastGPT 知识库完整逻辑
在正式构建知识库前,我们先来了解下 FastGPT 是如何进行知识库检索的。首先了解几个基本概念:
1. 向量:将人类直观的语言(文字、图片、视频等)转成计算机可识别的语言(数组)。
2. 向量相似度:两个向量之间可以进行计算,得到一个相似度,即代表:两个语言相似的程度。
3. 语言大模型的一些特点:上下文理解、总结和推理。
结合上述 3 个概念,便有了 “向量搜索 + 大模型 = 知识库问答” 的公式。下图是 FastGPT V3 中知识库问答功能的完整逻辑:
![向量搜索 GPT 流程图](/imgs/2.png)
与大部分其他知识库问答产品不一样的是, FastGPT 采用了 QA 问答对进行存储,而不是仅进行 chunk文本分块处理。目的是为了减少向量化内容的长度让向量能更好的表达文本的含义从而提高搜索精准度。
此外 FastGPT 还提供了搜索测试和对话测试两种途径对数据进行调整,从而方便用户调整自己的数据。根据上述流程和方式,我们以构建一个 FastGPT 常见问题机器人为例,展示如何构建一个高质量的 AI 知识库。
## 构建知识库应用
首先,先创建一个 FastGPT 常见问题知识库
![创建知识库应用](/imgs/3.png)
### 通过 QA 拆分,获取基础知识
我们先直接把 FastGPT Git 上一些已有文档,进行 QA 拆分,从而获取一些 FastGPT 基础的知识。下面是 README 例子。
![QA 拆分示意图](/imgs/4.png)
![](/imgs/5.png)
### 修正 QA
通过 README 我们一共得到了 11 组数据,整体的质量还是不错的,图片和链接都提取出来了。不过最后一个知识点出现了一些截断,我们需要手动的修正一下。
此外,我们观察到第一列第三个知识点。这个知识点是介绍了 FastGPT 一些资源链接,但是 QA 拆分将答案放置在了 A 中,但通常来说用户的提问并不会直接问“有哪些链接”,通常会问:“部署教程”,“问题文档”之类的。因此,我们需要将这个知识点进行简单的一个处理,如下图:
![手动修改知识库数据](/imgs/6.png)
我们先来创建一个应用,看看效果如何。 首先需要去创建一个应用,并且在知识库中关联相关的知识库。另外还需要在配置页的提示词中,告诉 GPT“知识库的范围”。
![](/imgs/7.png)
![README QA 拆分后效果](/imgs/8.png)
整体的效果还是不错的,链接和对应的图片都可以顺利的展示。
### 录入社区常见问题
接着,我们再把 FastGPT 常见问题的文档导入,由于平时整理不当,我们只能手动的录入对应的问答。
![手动录入知识库结果](/imgs/9.png)
导入结果如上图。可以看到,我们均采用的是问答对的格式,而不是粗略的直接导入。目的就是为了模拟用户问题,进一步的提高向量搜索的匹配效果。可以为同一个问题设置多种问法,效果更佳。
FastGPT 还提供了 openapi 功能,你可以在本地对特殊格式的文件进行处理后,再上传到 FastGPT具体可以参考[FastGPT Api Docs](https://doc.fastgpt.in/docs/development/openapi)
## 知识库微调和参数调整
FastGPT 提供了搜索测试和对话测试两种途径对知识库进行微调,我们先来使用搜索测试对知识库进行调整。我们建议你提前收集一些用户问题进行测试,根据预期效果进行跳转。可以先进行搜索测试调整,判断知识点是否合理。
### 搜索测试
![搜索测试作用](/imgs/10.png)
你可能会遇到下面这种情况,由于“知识库”这个关键词导致一些无关内容的相似度也被搜索进去,此时就需要给第四条记录也增加一个“知识库”关键词,从而去提高它的相似度。
![搜索测试结果](/imgs/11.png)
![优化后的搜索测试结果](/imgs/12.png)
### 提示词设置
提示词的作用是引导模型对话的方向。在设置提示词时,遵守 2 个原则:
1. 告诉 Gpt 回答什么方面内容。
2. 给知识库一个基本描述,从而让 Gpt 更好的判断用户的问题是否属于知识库范围。
![提示词设置](/imgs/13.png)
### 更好的限定模型聊天范围
首先,你可以通过调整知识库搜索时的相似度和最大搜索数量,实现从知识库层面限制聊天范围。通常我们可以设置相似度为 0.82,并设置空搜索回复内容。这意味着,如果用户的问题无法在知识库中匹配时,会直接回复预设的内容。
![搜索参数设置](/imgs/14.png)
![空搜索控制效果](/imgs/15.png)
由于 openai 向量模型并不是针对中文,所以当问题中有一些知识库内容的关键词时,相似度
会较高,此时无法从知识库层面进行限定。需要通过限定词进行调整,例如:
> 我的问题如果不是关于 FastGPT 的,请直接回复:“我不确定”。你仅需要回答知识库中的内容,不在其中的内容,不需要回答。
效果如下:
![限定词效果](/imgs/16.png)
当然gpt35 在一定情况下依然是不可控的。
### 通过对话调整知识库
与搜索测试类似,你可以直接在对话页里,点击“引用”,来随时修改知识库内容。
![查看答案引用](/imgs/17.png)
## 总结
1. 向量搜索是一种可以比较文本相似度的技术。
2. 大模型具有总结和推理能力,可以从给定的文本中回答问题。
3. 最有效的知识库构建方式是 QA 和手动构建。
4. Q 的长度不宜过长。
5. 需要调整提示词,来引导模型回答知识库内容。
6. 可以通过调整搜索相似度、最大搜索数量和限定词来控制模型回复的范围。

View File

@@ -0,0 +1,106 @@
---
title: '接入微信公众号教程'
description: 'FastGPT 接入微信公众号教程'
icon: 'description'
draft: false
toc: true
weight: 113
---
从 4.8.10 版本起FastGPT 商业版支持直接接入微信公众号,无需额外的 API。
**注意⚠️: 目前只支持通过验证的公众号(服务号和订阅号都可以)**
## 1. 在 FastGPT 新建发布渠道
在 FastGPT 中选择想要接入的应用,在 *发布渠道* 页面,新建一个接入微信公众号的发布渠道,填写好基础信息。
![图片](/imgs/offiaccount-1.png)
## 2. 登录微信公众平台,获取 AppID 、 Secret和Token
### 1. https://mp.weixin.qq.com 登录微信公众平台,选择您的公众号。
**只支持通过验证的公众号,未通过验证的公众号暂不支持。**
开发者可以从这个链接申请微信公众号的测试号进行测试,测试号可以正常使用,但不能配置 AES Key
![图片](/imgs/offiaccount-2.png)
### 2. 把3个参数填入 FastGPT 配置弹窗中。
![图片](/imgs/offiaccount-3.png)
## 3. 在 IP 白名单中加入 FastGPT 的 IP
![图片](/imgs/offiaccount-4.png)
私有部署的用户可自行查阅自己的 IP 地址。
海外版用户fastgpt.in)可以填写下面的 IP 白名单:
```
34.87.20.17
35.247.161.35
34.87.51.146
34.87.110.152
35.247.163.68
34.126.163.205
34.87.20.189
34.87.102.86
35.240.227.100
35.198.192.104
34.143.149.171
34.87.152.33
34.124.237.188
35.197.149.75
34.87.44.74
34.124.189.116
34.87.79.202
34.87.173.252
34.143.240.160
34.87.180.104
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)
![图片](/imgs/offiaccount-6.png)
1. 随机生成AESKey填入 FastGPT 配置弹窗中。
2. 选择加密方式为安全模式。
## 5. 获取 URL
1. 在FastGPT确认创建获取URL。
![图片](/imgs/offiaccount-7.png)
2. 填入微信公众平台的 URL 处,然后提交保存
![图片](/imgs/offiaccount-8.png)
## 6. 启用服务器配置(如已自动启用,请忽略)
![图片](/imgs/offiaccount-9.png)
## 7. 开始使用
现在用户向公众号发消息,消息则会被转发到 FastGPT通过公众号返回对话结果。

View File

@@ -1,13 +1,15 @@
---
title: "对接第三方 GPT 应用"
description: "通过与 OpenAI 兼容的 API 对接第三方应用"
title: "通过 API 访问应用"
description: "通过 API 访问 FastGPT 应用"
icon: "model_training"
draft: false
toc: true
weight: 505
weight: 112
---
## 获取 API 秘钥
在 FastGPT 中,你可以为每一个应用创建多个 API 密钥,用于访问应用的 API 接口。每个密钥仅能访问一个应用。完整的接口可以[查看应用对话接口](/docs/development/openapi/chat)。
## 获取 API 密钥
依次选择应用 -> 「API访问」然后点击「API 密钥」来创建密钥。
@@ -15,7 +17,7 @@ weight: 505
密钥需要自己保管好,一旦关闭就无法再复制密钥,只能创建新密钥再复制。
{{% /alert %}}
![](/imgs/fastgpt-api.jpg)
![](/imgs/fastgpt-api1.jpg)
{{% alert icon="🍅" context="success" %}}
Tips: 安全起见,你可以设置一个额度或者过期时间,放置 key 被滥用。
@@ -26,7 +28,7 @@ Tips: 安全起见,你可以设置一个额度或者过期时间,放置 key
```bash
OPENAI_API_BASE_URL: https://api.fastgpt.in/api (改成自己部署的域名)
OPENAI_API_KEY = 上一步获取到的
OPENAI_API_KEY = 上一步获取到的
```
**[ChatGPT Next Web](https://github.com/Yidadaa/ChatGPT-Next-Web) 示例:**

View File

@@ -14,9 +14,9 @@ weight: 920
{{< table "table-hover table-striped-columns" >}}
| 模型名 | 内存 | 显存 | 硬盘空间 | 启动命令 |
|------|---------|---------|----------|--------------------------|
| bge-rerank-base | >=4GB | >=4GB | >=8GB | python app.py |
| bge-rerank-large | >=8GB | >=8GB | >=8GB | python app.py |
| bge-rerank-v2-m3 | >=8GB | >=8GB | >=8GB | python app.py |
| bge-reranker-base | >=4GB | >=4GB | >=8GB | python app.py |
| bge-reranker-large | >=8GB | >=8GB | >=8GB | python app.py |
| bge-reranker-v2-m3 | >=8GB | >=8GB | >=8GB | python app.py |
{{< /table >}}
## 源码部署
@@ -33,7 +33,7 @@ weight: 920
1. [https://github.com/labring/FastGPT/tree/main/python/bge-rerank/bge-reranker-base](https://github.com/labring/FastGPT/tree/main/python/bge-rerank/bge-reranker-base)
2. [https://github.com/labring/FastGPT/tree/main/python/bge-rerank/bge-reranker-large](https://github.com/labring/FastGPT/tree/main/python/bge-rerank/bge-reranker-large)
3. [https://github.com/labring/FastGPT/tree/main/python/bge-rerank/bge-rerank-v2-m3](https://github.com/labring/FastGPT/tree/main/python/bge-rerank/bge-rerank-v2-m3)
3. [https://github.com/labring/FastGPT/tree/main/python/bge-rerank/bge-reranker-v2-m3](https://github.com/labring/FastGPT/tree/main/python/bge-rerank/bge-reranker-v2-m3)
### 3. 安装依赖
@@ -47,7 +47,7 @@ pip install -r requirements.txt
1. [https://huggingface.co/BAAI/bge-reranker-base](https://huggingface.co/BAAI/bge-reranker-base)
2. [https://huggingface.co/BAAI/bge-reranker-large](https://huggingface.co/BAAI/bge-reranker-large)
3. [https://huggingface.co/BAAI/bge-rerank-v2-m3](https://huggingface.co/BAAI/bge-rerank-v2-m3)
3. [https://huggingface.co/BAAI/bge-reranker-v2-m3](https://huggingface.co/BAAI/bge-reranker-v2-m3)
在对应代码目录下 clone 模型。目录结构:
@@ -119,3 +119,19 @@ services:
## 接入 FastGPT
参考 [ReRank模型接入](/docs/development/configuration/#rerank-接入)host 变量为部署的域名。
## QA
### Docker 运行提示 `Bus error (core dumped)`
尝试增加 `docker-compose.yml` 配置项 `shm_size` ,以增加容器中的共享内存目录大小。
```
...
services:
reranker:
...
container_name: reranker
shm_size: '2gb'
...
```

View File

@@ -172,7 +172,7 @@ docker exec -it mongo mongorestore -u "username" -p "password" --authenticationD
5.重启容器 【C环境】
```
docker compose restart
docker logs -f mongo **强烈建议先检查mongo运行情况在去做登动作如果mongo报错访问web也会报错”
docker logs -f mongo **强烈建议先检查mongo运行情况在去做登动作如果mongo报错访问web也会报错”
```
如果mongo启动正常显示的是类似这样的而不是 “mongo is restarting”后者就是错误
@@ -182,5 +182,5 @@ docker logs -f mongo **强烈建议先检查mongo运行情况在去做登陆
<img width="508" alt="iShot_2024-05-09_19 23 13" src="https://github.com/labring/FastGPT/assets/103937568/2e2afc9f-484c-4b63-93ee-1c14aef03de0">
6. 启动fastgpt容器服务后新fastgpt web能看到原来的数据库内容完整显示说明已经导入系统了。
6. 启动fastgpt容器服务后新fastgpt web能看到原来的数据库内容完整显示说明已经导入系统了。
<img width="1728" alt="iShot_2024-05-09_19 23 51" src="https://github.com/labring/FastGPT/assets/103937568/846b6157-6b6a-4468-a1d9-c44d681ebf7c">

View File

@@ -8,9 +8,9 @@ weight: 852
---
{{% alert icon="🤖 " context="success" %}}
该接口的 API Key 需使用`应用特定的 key`,否则会报错。
* 该接口的 API Key 需使用`应用特定的 key`,否则会报错。
有些包调用时,`BaseUrl`需要添加`v1`路径有些不需要如果出现404情况可补充`v1`重试。
* 有些包调用时,`BaseUrl`需要添加`v1`路径有些不需要如果出现404情况可补充`v1`重试。
{{% /alert %}}
## 发起对话(简易应用和工作流)
@@ -18,7 +18,7 @@ weight: 852
对话接口兼容`GPT`的接口!如果你的项目使用的是标准的`GPT`官方接口,可以直接通过修改`BaseUrl``Authorization`来访问 FastGpt 应用,不过需要注意下面几个规则:
{{% alert icon="🤖 " context="success" %}}
* 传入的`model``temperature`等参数字段均无效,这些字段由编排决定。
* 传入的`model``temperature`等参数字段均无效,这些字段由编排决定,不会根据 API 参数改变
* 不会返回实际消耗`Token`值,如果需要,可以设置`detail=true`,并手动计算 `responseData` 里的`tokens`值。
{{% /alert %}}
@@ -457,6 +457,6 @@ event取值
## 使用案例
- [接入 NextWeb/ChatGPT web 等应用](/docs/use-cases/openapi)
- [接入 NextWeb/ChatGPT web 等应用](/docs/course/openapi)
- [接入 onwechat](/docs/use-cases/onwechat)
- [接入 飞书](/docs/use-cases/feishu)
- [接入 飞书](/docs/course/feishu)

View File

@@ -19,15 +19,36 @@ FastGPT 使用了 one-api 项目来管理模型池,其可以兼容 OpenAI 、A
## 一键部署
Sealos 的服务器在国外,不需要额外处理网络问题,无需服务器、无需魔法、无需域名,支持高并发 & 动态伸缩。点击以下按钮即可一键部署 👇
使用 Sealos 服务,无需采购服务器、无需域名,支持高并发 & 动态伸缩,并且数据库应用采用 kubeblocks 的数据库,在 IO 性能方面,远超于简单的 Docker 容器部署。可以根据需求,再下面两个区域选择部署。
### 新加坡区
新加披区的服务器在国外,可以直接访问 OpenAI但国内用户需要梯子才可以正常访问新加坡区。国际区价格稍贵点击下面按键即可部署👇
<a href="https://template.cloud.sealos.io/deploy?templateName=fastgpt" rel="external" target="_blank"><img src="https://cdn.jsdelivr.net/gh/labring-actions/templates@main/Deploy-on-Sealos.svg" alt="Deploy on Sealos"/></a>
### 北京区
北京区服务提供商为火山云,国内用户可以稳定访问,但无法访问 OpenAI 等境外服务,价格约为新加坡区的 1/4。点击下面按键即可部署👇
<a href="https://bja.sealos.run/?openapp=system-template%3FtemplateName%3Dfastgpt" rel="external" target="_blank"><img src="https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg" alt="Deploy on Sealos"/></a>
### 开始部署
由于需要部署数据库,部署完后需要等待 2~4 分钟才能正常访问。默认用了最低配置,首次访问时会有些慢。
根据提示,输入`root_password`,和 `openai`/`oneapi` 的地址和密钥。
![](/imgs/sealos1.png)
点击 Sealos 提供的外网地址即可打开 FastGPT 的可视化界面
点击部署后,会跳转到应用管理页面。可以点击`fastgpt`主应用右侧的详情按键(名字为 fastgpt-xxxx 如下图所示
![](/imgs/sealos-deploy1.jpg)
点击详情后,会跳转到 fastgpt 的部署管理页面,点击外网访问地址中的链接,即可打开 fastgpt 服务。
如需绑定自定义域名、修改部署参数,可以点击右上角变更,根据 sealos 的指引完成。
![](/imgs/sealos2.png)
@@ -53,6 +74,10 @@ Sealos 的服务器在国外,不需要额外处理网络问题,无需服务
点击变更或重启会自动拉取镜像更新,请确保镜像`tag`正确。建议不要使用`latest`,改成固定版本号。
## 收费
Sealos 采用按量计费的方式,也就是申请了多少 cpu、内存、磁盘就按该申请量进行计费。具体的计费标准可以打开`sealos`控制面板中的`费用中心`进行查看。
## Sealos 使用
### 简介

View File

@@ -0,0 +1,90 @@
---
title: 'V4.8.10(进行中)'
description: 'FastGPT V4.8.10 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 814
---
## 更新指南
### 1. 做好数据备份
### 2. 商业版 —— 修改环境变量
1. 需要给`fastgpt-pro`镜像,增加沙盒的环境变量:`SANDBOX_URL=http://xxxxx:3000`
2.`fastgpt-pro`镜像和`fastgpt`镜像增加环境变量,以便更好的存储系统日志:
```
LOG_LEVEL=debug
STORE_LOG_LEVEL=warn
```
### 3. 修改镜像tag
- 更新 FastGPT 镜像 tag: v4.8.10-alpha
- 更新 FastGPT 商业版镜像 tag: v4.8.10-alpha
- 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 更新说明
完整内容请见:[4.8.10 release](https://github.com/labring/FastGPT/releases/tag/v4.8.10-alpha)
1. 新增 - 模板市场
2. 新增 - 工作流节点拖动自动对齐吸附
3. 新增 - 用户选择节点Debug 模式暂未支持)
4. 新增 - 工作流撤销和重做
5. 新增 - 工作流本次编辑记录,取代自动保存
6. 新增 - 工作流版本支持重命名
7. 新增 - 应用调用迁移成单独节点,同时可以传递全局变量和用户的文件。
8. 新增 - 插件增加使用说明配置。
9. 新增 - 工作流导出导入,支持直接导出和导入 JSON 文件,便于交流。
10. 新增 - HTTP模块支持超时配置、支持更多的 Body 类型params 和 headers 支持新的变量选择模式。
11. 新增 - 发送验证码安全校验。
12. 商业版新增 - 飞书机器人接入
13. 商业版新增 - 公众号接入接入
14. 商业版新增 - 自助开票申请
15. 商业版新增 - SSO 定制
16. 优化 - 工作流循环校验,避免 skip 循环空转。同时支持分支完全并发执行。
17. 优化 - SSE 响应优化。
18. 优化 - 无 SSL 证书情况下,优化复制。
19. 优化 - 单选框打开后自动滚动到选中的位置。
20. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。
21. 优化 - 节点选择,避免切换 tab 时候path 加载报错。
22. 优化 - 最新 React Markdown 组件,支持 Base64 图片。
23. 优化 - 知识库列表 UI。
24. 优化 - 知识库详情页 UI。
25. 优化 - 支持无网络配置情况下运行。
26. 优化 - 部分全局变量,增加数据类型约束。
27. 优化 - 查看工作流详情,切换 tab 时,自动滚动到顶部。
28. 优化 - 对话框性能问题。
29. 修复 - 全局变量 key 可能重复。
30. 修复 - Prompt 模式调用工具stream=false 模式下,会携带 0: 开头标记。
31. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。
32. 修复 - 选择 Milvus 部署时,无法导出知识库。
33. 修复 - 创建 APP 副本,无法复制系统配置。
34. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。
35. 修复 - 内容提取的数据类型与输出数据类型未一致。
36. 修复 - 工作流运行时间统计错误。
37. 修复 - stream 模式下,工具调用有可能出现 undefined
38. 修复 - 全局变量在 API 中无法持久化。
39. 修复 - OpenAPIdetail=false模式下不应该返回 tool 调用结果,仅返回文字。(可解决 cow 不适配问题)
40. 修复 - 知识库标签重复加载。
41. 修复 - Debug 模式下,循环调用边问题。

View File

@@ -0,0 +1,23 @@
---
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. 优化 - SSE 响应代码。
6. 优化 - 非 HTTPS 环境下支持复制(除非 textarea 复制也不支持)

View File

@@ -1,10 +1,10 @@
---
title: 'V4.8.9进行中'
title: 'V4.8.9需要初始化'
description: 'FastGPT V4.8.9 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 816
weight: 815
---
## 升级指南
@@ -13,8 +13,11 @@ weight: 816
### 2. 修改镜像
- 更新 FastGPT 镜像 tag: v4.8.9
- 更新 FastGPT 商业版镜像 tag: v4.8.9
- Sandbox 镜像,可以不更新
### 3. 执行初始化
### 3. 商业版执行初始化
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`{{host}} 替换成**FastGPT 商业版域名**。
@@ -24,7 +27,7 @@ curl --location --request POST 'https://{{host}}/api/admin/init/489' \
--header 'Content-Type: application/json'
```
会初始化多租户的通知方式
会初始化多租户的通知方式,仅内部使用的,无需执行。
-------
@@ -49,3 +52,4 @@ curl --location --request POST 'https://{{host}}/api/admin/init/489' \
17. 修复 - 知识库文件上传进度更新可能异常。
18. 修复 - 知识库 rebuilding 时候,页面总是刷新到第一页。
19. 修复 - 知识库 list openapi 鉴权问题。
20. 修复 - 分享链接,新对话无法反馈。

View File

@@ -1,70 +0,0 @@
---
title: " 接入飞书(社区文章)"
description: "FastGPT 接入飞书机器人"
icon: "chat"
draft: false
toc: true
weight: 503
---
# FastGPT 一分钟接入飞书
[Feishu OpenAI GitHub 地址](https://github.com/ConnectAI-E/Feishu-OpenAI)
[查看视频教程](https://www.bilibili.com/video/BV1Su4y1r7R3/?spm_id_from=333.999.list.card_archive.click)
由于 FastGPT 的 API 接口和 OpenAI 的规范一致,可以无需变更第三方应用即可使用 FastGPT 上编排好的应用。API 使用可参考 [这篇文章](/docs/use-cases/openapi/)。编排示例,可参考 [高级编排介绍](/docs/workflow/intro)
## 1. 获取 FastGPT 的 OpenAPI 秘钥
依次选择应用 -> 「API 访问」然后点击「API 密钥」来创建密钥。 [参考这篇文章](/docs/use-cases/openapi/)
![](/imgs/fastgpt-api.png)
## 2. 部署飞书服务
推荐使用 Railway 一键部署
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/10D-TF?referralCode=oMcVS2)
参考环境变量配置:
![](/imgs/feishu-env.png)
FastGPT 集成**重点参数:**
```bash
#上一步FastGPT的OpenAPI 秘钥
OPENAI_KEY=fastgpt-z51pkjqm9nrk03a1rx2funoy
#调用OpenAI的BaseUrl要换成FastGPT的
API_URL=https://api.fastgpt.in/api/openapi
```
## 3. 创建飞书机器人
1. 前往 [开发者平台](https://open.feishu.cn/app?lang=zh-CN) 创建应用 , 并获取到 APPID 和 Secret
2. 前往`应用功能-机器人`, 创建机器人
3. 从 cpolar、serverless 或 Railway 获得公网地址,在飞书机器人后台的 `事件订阅` 板块填写。例如,
- `http://xxxx.r6.cpolar.top` 为 cpolar 暴露的公网地址
- `/webhook/event` 为统一的应用路由
- 最终的回调地址为 `http://xxxx.r6.cpolar.top/webhook/event`
4. 在飞书机器人后台的 `机器人` 板块,填写消息卡片请求网址。例如,
- `http://xxxx.r6.cpolar.top` 为 cpolar 暴露的公网地址
- `/webhook/card` 为统一的应用路由
- 最终的消息卡片请求网址为 `http://xxxx.r6.cpolar.top/webhook/card`
5. 在事件订阅板块,搜索三个词`机器人进群`、 `接收消息`、 `消息已读`, 把他们后面所有的权限全部勾选。 进入权限管理界面,搜索`图片`, 勾选`获取与上传图片或文件资源`。 最终会添加下列回调事件
- im:resource(获取与上传图片或文件资源)
- im:message
- im:message.group_at_msg(获取群组中所有消息)
- im:message.group_at_msg:readonly(接收群聊中 @ 机器人消息事件)
- im:message.p2p_msg(获取用户发给机器人的单聊消息)
- im:message.p2p_msg:readonly(读取用户发给机器人的单聊消息)
- im:message:send_as_bot(获取用户在群组中 @ 机器人的消息)
- im:chat:readonly(获取群组信息)
- im:chat(获取与更新群组信息)
## 4. 测试飞书机器人
私聊机器人,或者群里艾特它,就可以基于 FastGPT 的应用进行回答啦
![](/imgs/feishu-res.png)

View File

@@ -11,9 +11,9 @@ weight: 504
[chatgpt-on-wechat GitHub 地址](https://github.com/zhayujie/chatgpt-on-wechat)
由于 FastGPT 的 API 接口和 OpenAI 的规范一致,可以无需变更原来的应用即可使用 FastGPT 上编排好的应用。API 使用可参考 [这篇文章](/docs/use-cases/openapi/)。编排示例,可参考 [高级编排介绍](/docs/workflow/intro)
由于 FastGPT 的 API 接口和 OpenAI 的规范一致,可以无需变更原来的应用即可使用 FastGPT 上编排好的应用。API 使用可参考 [这篇文章](/docs/course/openapi/)。编排示例,可参考 [高级编排介绍](/docs/workflow/intro)
## 1. 获取 OpenAPI
## 1. 获取 OpenAPI
依次选择应用 -> 「API访问」然后点击「API 密钥」来创建密钥。
@@ -26,7 +26,7 @@ weight: 504
## 3. 创建 docker-compose.yml 文件
只需要修改 `OPEN_AI_API_KEY``OPEN_AI_API_BASE` 两个环境变量即可。其中 `OPEN_AI_API_KEY` 为第一步获取的钥,`OPEN_AI_API_BASE` 为 FastGPT 的 OpenAPI 地址,例如:`https://api.fastgpt.in/api/v1`
只需要修改 `OPEN_AI_API_KEY``OPEN_AI_API_BASE` 两个环境变量即可。其中 `OPEN_AI_API_KEY` 为第一步获取的钥,`OPEN_AI_API_BASE` 为 FastGPT 的 OpenAPI 地址,例如:`https://api.fastgpt.in/api/v1`
随便找一个目录,创建一个 docker-compose.yml 文件,将下面的代码复制进去。

View File

@@ -17,7 +17,7 @@ weight: 506
## 配置微秘书
打开[微秘书](https://wechat.aibotk.com?r=zWLnZK) 注册登后找到菜单栏「基础配置」->「智能配置」,按照下图配置。
打开[微秘书](https://wechat.aibotk.com?r=zWLnZK) 注册登后找到菜单栏「基础配置」->「智能配置」,按照下图配置。
![](/imgs/wechat2.png)
@@ -27,7 +27,7 @@ weight: 506
## sealos部署服务
[访问sealos](https://cloud.sealos.run/) 登进来之后打开「应用管理」-> 「新建应用」。
[访问sealos](https://cloud.sealos.run/) 登进来之后打开「应用管理」-> 「新建应用」。
- 应用名:称随便填写
- 镜像名:私人微信填写 aibotk/wechat-assistant 企业微信填写 aibotk/worker-assistant
- cpu和内存建议 1c1g
@@ -61,12 +61,12 @@ WORK_PRO_TOKEN=你申请的企微 token (企业微信需要填写,私人
![](/imgs/wechat8.png)
返回[微秘书](https://wechat.aibotk.com?r=zWLnZK) 找到「首页」,扫码登需要接入的微信号。
返回[微秘书](https://wechat.aibotk.com?r=zWLnZK) 找到「首页」,扫码登需要接入的微信号。
![](/imgs/wechat9.png)
## 测试
只需要发送信息,或者拉入群聊@登的微信就会回复信息啦
只需要发送信息,或者拉入群聊@登的微信就会回复信息啦
![](/imgs/wechat10.png)

View File

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

View File

@@ -121,8 +121,8 @@ services:
restart: always
fastgpt:
container_name: fastgpt
image: ghcr.io/labring/fastgpt:v4.8.8-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.8-fix2 # 阿里云
image: ghcr.io/labring/fastgpt:v4.8.9 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.9 # 阿里云
ports:
- 3000:3000
networks:

View File

@@ -79,8 +79,8 @@ services:
restart: always
fastgpt:
container_name: fastgpt
image: ghcr.io/labring/fastgpt:v4.8.8-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.8-fix2 # 阿里云
image: ghcr.io/labring/fastgpt:v4.8.9 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.9 # 阿里云
ports:
- 3000:3000
networks:

View File

@@ -60,8 +60,8 @@ services:
restart: always
fastgpt:
container_name: fastgpt
image: ghcr.io/labring/fastgpt:v4.8.8-fix2 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.8-fix2 # 阿里云
image: ghcr.io/labring/fastgpt:v4.8.9 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.9 # 阿里云
ports:
- 3000:3000
networks:

View File

@@ -10,7 +10,8 @@
"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"
"i18n:delete-unused-keys": "node ./scripts/i18n/delete-unused-keys.js",
"i18n:query": "node ./scripts/i18n/query.js"
},
"devDependencies": {
"@chakra-ui/cli": "^2.4.1",
@@ -30,4 +31,4 @@
"node": ">=18.16.0",
"pnpm": ">=9.0.0"
}
}
}

View File

@@ -0,0 +1,10 @@
export const retryRun = <T>(fn: () => T, retry = 2): T => {
try {
return fn();
} catch (error) {
if (retry > 0) {
return retryRun(fn, retry - 1);
}
throw error;
}
};

View File

@@ -7,6 +7,8 @@ dayjs.extend(utc);
dayjs.extend(timezone);
export const formatTime2YMDHMW = (time?: Date) => dayjs(time).format('YYYY-MM-DD HH:mm:ss dddd');
export const formatTime2YMDHMS = (time?: Date) =>
time ? dayjs(time).format('YYYY-MM-DD HH:mm:ss') : '';
export const formatTime2YMDHM = (time?: Date) =>
time ? dayjs(time).format('YYYY-MM-DD HH:mm') : '';
export const formatTime2YMD = (time?: Date) => (time ? dayjs(time).format('YYYY-MM-DD') : '');
@@ -26,7 +28,7 @@ export const formatTimeToChatTime = (time: Date) => {
// 如果时间是今天,展示几时:几分
if (now.isSame(target, 'day')) {
return target.format('HH:mm');
return target.format('HH : mm');
}
// 如果是昨天,展示昨天

View File

@@ -94,7 +94,11 @@ export const sliceJsonStr = (str: string) => {
export const sliceStrStartEnd = (str: string, start: number, end: number) => {
const overSize = str.length > start + end;
if (!overSize) return str;
const startContent = str.slice(0, start);
const endContent = overSize ? str.slice(-end) : '';
return startContent + (overSize ? ` ...... ` : '') + endContent;
return `${startContent}${overSize ? `\n\n...[hide ${str.length - start - end} chars]...\n\n` : ''}${endContent}`;
};

View File

@@ -24,7 +24,10 @@ export type FastGPTConfigFileType = {
export type FastGPTFeConfigsType = {
show_emptyChat?: boolean;
show_register?: boolean;
register_method?: ['email' | 'phone'];
login_method?: ['email' | 'phone']; // Attention: login method is diffrent with oauth
find_password_method?: ['email' | 'phone'];
bind_notification_method?: ['email' | 'phone'];
show_appStore?: boolean;
show_git?: boolean;
show_pay?: boolean;
@@ -37,13 +40,17 @@ export type FastGPTFeConfigsType = {
chatbotUrl?: string;
openAPIDocUrl?: string;
systemPluginCourseUrl?: string;
appTemplateCourse?: string;
systemTitle?: string;
systemDescription?: string;
googleClientVerKey?: string;
isPlus?: boolean;
show_phoneLogin?: boolean;
show_emailLogin?: boolean;
sso?: {
icon?: string;
title?: string;
url?: string;
};
oauth?: {
github?: string;
google?: string;

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

@@ -9,6 +9,7 @@ import type {
ChatCompletionUserMessageParam as SdkChatCompletionUserMessageParam
} from 'openai/resources';
import { ChatMessageTypeEnum } from './constants';
import { InteractiveNodeResponseItemType } from '../workflow/template/system/userSelect/type';
export * from 'openai/resources';
@@ -33,6 +34,7 @@ export type ChatCompletionMessageParam = (
| CustomChatCompletionUserMessageParam
) & {
dataId?: string;
interactive?: InteractiveNodeResponseItemType;
};
export type SdkChatCompletionMessageParam = SdkChatCompletionMessageParam;

View File

@@ -29,3 +29,12 @@ export const defaultAppSelectFileConfig: AppFileSelectConfigType = {
canSelectImg: false,
maxFiles: 10
};
export enum AppTemplateTypeEnum {
recommendation = 'recommendation',
writing = 'writing',
imageGeneration = 'image-generation',
webSearch = 'web-search',
roleplay = 'roleplay',
officeServices = 'office-services'
}

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

@@ -8,4 +8,7 @@ export type AppVersionSchemaType = {
nodes: AppSchema['modules'];
edges: AppSchema['edges'];
chatConfig: AppSchema['chatConfig'];
isPublish?: boolean;
versionName: string;
tmbId: string;
};

View File

@@ -118,12 +118,19 @@ export const chats2GPTMessages = ({
tool_calls
})
.concat(toolResponse);
} else if (value.text) {
} else if (value.text?.content) {
results.push({
dataId,
role: ChatCompletionRequestMessageRoleEnum.Assistant,
content: value.text.content
});
} else if (value.type === ChatItemValueTypeEnum.interactive) {
results = results.concat({
dataId,
role: ChatCompletionRequestMessageRoleEnum.Assistant,
interactive: value.interactive,
content: ''
});
}
});
}
@@ -135,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];
@@ -144,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
@@ -254,6 +272,12 @@ export const GPTMessages2Chats = (
]
});
}
} else if (item.interactive) {
value.push({
//@ts-ignore
type: ChatItemValueTypeEnum.interactive,
interactive: item.interactive
});
}
}
@@ -264,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

@@ -1,3 +1,5 @@
import { i18nT } from '../../../web/i18n/utils';
export enum ChatRoleEnum {
System = 'System',
Human = 'Human',
@@ -22,7 +24,8 @@ export enum ChatFileTypeEnum {
export enum ChatItemValueTypeEnum {
text = 'text',
file = 'file',
tool = 'tool'
tool = 'tool',
interactive = 'interactive'
}
export enum ChatSourceEnum {
@@ -30,23 +33,36 @@ export enum ChatSourceEnum {
online = 'online',
share = 'share',
api = 'api',
team = 'team'
team = 'team',
feishu = 'feishu',
official_account = 'official_account',
wecom = 'wecom'
}
export const ChatSourceMap = {
[ChatSourceEnum.test]: {
name: 'core.chat.logs.test'
name: i18nT('common:core.chat.logs.test')
},
[ChatSourceEnum.online]: {
name: 'core.chat.logs.online'
name: i18nT('common:core.chat.logs.online')
},
[ChatSourceEnum.share]: {
name: 'core.chat.logs.share'
name: i18nT('common:core.chat.logs.share')
},
[ChatSourceEnum.api]: {
name: 'core.chat.logs.api'
name: i18nT('common:core.chat.logs.api')
},
[ChatSourceEnum.team]: {
name: 'core.chat.logs.team'
name: i18nT('common:core.chat.logs.team')
},
[ChatSourceEnum.feishu]: {
name: i18nT('common:core.chat.logs.feishu')
},
[ChatSourceEnum.official_account]: {
name: i18nT('common:core.chat.logs.official_account')
},
[ChatSourceEnum.wecom]: {
name: i18nT('common:core.chat.logs.wecom')
}
};

View File

@@ -15,6 +15,7 @@ import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
import { DatasetSearchModeEnum } from '../dataset/constants';
import { DispatchNodeResponseType } from '../workflow/runtime/type.d';
import { ChatBoxInputType } from '../../../../projects/app/src/components/core/chat/ChatContainer/ChatBox/type';
import { InteractiveNodeResponseItemType } from '../workflow/template/system/userSelect/type';
export type ChatSchema = {
_id: string;
@@ -67,11 +68,12 @@ export type SystemChatItemType = {
value: SystemChatItemValueItemType[];
};
export type AIChatItemValueItemType = {
type: ChatItemValueTypeEnum.text | ChatItemValueTypeEnum.tool;
type: ChatItemValueTypeEnum.text | ChatItemValueTypeEnum.tool | ChatItemValueTypeEnum.interactive;
text?: {
content: string;
};
tools?: ToolModuleResponseItemType[];
interactive?: InteractiveNodeResponseItemType;
};
export type AIChatItemType = {
obj: ChatRoleEnum.AI;
@@ -149,10 +151,18 @@ export type ChatHistoryItemType = HistoryItemType & {
/* ------- response data ------------ */
export type ChatHistoryItemResType = DispatchNodeResponseType & {
nodeId: string;
id: string;
moduleType: FlowNodeTypeEnum;
moduleName: string;
};
/* ---------- node outputs ------------ */
export type NodeOutputItemType = {
nodeId: string;
key: NodeOutputKeyEnum;
value: any;
};
/* One tool run response */
export type ToolRunResponseItemType = any;
/* tool module response */

View File

@@ -1,8 +1,9 @@
import { DispatchNodeResponseType } from '../workflow/runtime/type';
import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { ChatItemValueTypeEnum, ChatRoleEnum } from './constants';
import { ChatItemValueTypeEnum, ChatRoleEnum, ChatSourceEnum } from './constants';
import { ChatHistoryItemResType, ChatItemType, UserChatItemValueItemType } from './type.d';
import { sliceStrStartEnd } from '../../common/string/tools';
import { PublishChannelEnum } from '../../support/outLink/constant';
// Concat 2 -> 1, and sort by role
export const concatHistories = (histories1: ChatItemType[], histories2: ChatItemType[]) => {
@@ -28,13 +29,15 @@ export const getChatTitleFromChatMessage = (message?: ChatItemType, defaultValue
// Keep the first n and last n characters
export const getHistoryPreview = (
completeMessages: ChatItemType[]
completeMessages: ChatItemType[],
size = 100
): {
obj: `${ChatRoleEnum}`;
value: string;
}[] => {
return completeMessages.map((item, i) => {
const n = item.obj === ChatRoleEnum.System || i >= completeMessages.length - 2 ? 80 : 40;
const n =
(item.obj === ChatRoleEnum.System && i === 0) || i >= completeMessages.length - 2 ? size : 50;
// Get message text content
const rawText = (() => {
@@ -65,13 +68,9 @@ export const getHistoryPreview = (
return '';
})();
const startContent = rawText.slice(0, n);
const endContent = rawText.length > 2 * n ? rawText.slice(-n) : '';
const content = startContent + (rawText.length > n ? ` ...... ` : '') + endContent;
return {
obj: item.obj,
value: sliceStrStartEnd(content, 80, 80)
value: sliceStrStartEnd(rawText, n, n)
};
});
};
@@ -125,3 +124,22 @@ export const getPluginOutputsFromChatResponses = (responses: ChatHistoryItemResT
responses.find((item) => item.moduleType === FlowNodeTypeEnum.pluginOutput)?.pluginOutput ?? {};
return outputs;
};
export const getChatSourceByPublishChannel = (publishChannel: PublishChannelEnum) => {
switch (publishChannel) {
case PublishChannelEnum.share:
return ChatSourceEnum.share;
case PublishChannelEnum.iframe:
return ChatSourceEnum.share;
case PublishChannelEnum.apikey:
return ChatSourceEnum.api;
case PublishChannelEnum.feishu:
return ChatSourceEnum.feishu;
case PublishChannelEnum.wecom:
return ChatSourceEnum.wecom;
case PublishChannelEnum.officialAccount:
return ChatSourceEnum.official_account;
default:
return ChatSourceEnum.online;
}
};

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[];
@@ -137,7 +138,9 @@ export type DatasetSimpleItemType = {
};
export type DatasetListItemType = {
_id: string;
tmbId: string;
avatar: string;
updateTime: Date;
name: string;
intro: string;
type: `${DatasetTypeEnum}`;

View File

@@ -1,8 +1,11 @@
import { i18nT } from '../../../web/i18n/utils';
export enum FlowNodeTemplateTypeEnum {
systemInput = 'systemInput',
ai = 'ai',
function = 'function',
tools = 'tools',
interactive = 'interactive',
search = 'search',
multimodal = 'multimodal',
@@ -49,6 +52,9 @@ export enum NodeInputKeyEnum {
scheduleTrigger = 'scheduleTrigger',
chatInputGuide = 'chatInputGuide',
// plugin config
instruction = 'instruction',
// entry
userChatInput = 'userChatInput',
inputFiles = 'inputFiles',
@@ -102,6 +108,9 @@ export enum NodeInputKeyEnum {
httpMethod = 'system_httpMethod',
httpParams = 'system_httpParams',
httpJsonBody = 'system_httpJsonBody',
httpFormBody = 'system_httpFormBody',
httpContentType = 'system_httpContentType',
httpTimeout = 'system_httpTimeout',
abandon_httpUrl = 'url',
// app
@@ -123,7 +132,10 @@ export enum NodeInputKeyEnum {
codeType = 'codeType', // js|py
// read files
fileUrlList = 'fileUrlList'
fileUrlList = 'fileUrlList',
// user select
userSelectOptions = 'userSelectOptions'
}
export enum NodeOutputKeyEnum {
@@ -162,7 +174,11 @@ export enum NodeOutputKeyEnum {
// plugin
pluginStart = 'pluginStart',
ifElseResult = 'ifElseResult'
// if else
ifElseResult = 'ifElseResult',
//user select
selectResult = 'selectResult'
}
export enum VariableInputEnum {
@@ -174,23 +190,23 @@ export enum VariableInputEnum {
export const variableMap = {
[VariableInputEnum.input]: {
icon: 'core/app/variable/input',
title: 'core.module.variable.input type',
title: i18nT('common:core.module.variable.input type'),
desc: ''
},
[VariableInputEnum.textarea]: {
icon: 'core/app/variable/textarea',
title: 'core.module.variable.textarea type',
desc: '允许用户最多输入4000字的对话框。'
title: i18nT('common:core.module.variable.textarea type'),
desc: i18nT('app:variable.textarea_type_desc')
},
[VariableInputEnum.select]: {
icon: 'core/app/variable/select',
title: 'core.module.variable.select type',
title: i18nT('common:core.module.variable.select type'),
desc: ''
},
[VariableInputEnum.custom]: {
icon: 'core/app/variable/external',
title: 'core.module.variable.Custom type',
desc: '可以定义一个无需用户填写的全局变量。\n该变量的值可以来自于 API 接口,分享链接的 Query 或通过【变量更新】模块进行赋值。'
title: i18nT('common:core.module.variable.Custom type'),
desc: i18nT('app:variable.select type_desc')
}
};
@@ -203,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',
@@ -118,68 +124,78 @@ export enum FlowNodeTypeEnum {
code = 'code',
textEditor = 'textEditor',
customFeedback = 'customFeedback',
readFiles = 'readFiles'
readFiles = 'readFiles',
userSelect = 'userSelect'
}
// node IO value type
export const FlowValueTypeMap = {
[WorkflowIOValueTypeEnum.string]: {
label: 'string',
value: WorkflowIOValueTypeEnum.string,
description: ''
value: WorkflowIOValueTypeEnum.string
},
[WorkflowIOValueTypeEnum.number]: {
label: 'number',
value: WorkflowIOValueTypeEnum.number,
description: ''
value: WorkflowIOValueTypeEnum.number
},
[WorkflowIOValueTypeEnum.boolean]: {
label: 'boolean',
value: WorkflowIOValueTypeEnum.boolean,
description: ''
value: WorkflowIOValueTypeEnum.boolean
},
[WorkflowIOValueTypeEnum.object]: {
label: 'object',
value: WorkflowIOValueTypeEnum.object,
description: ''
value: WorkflowIOValueTypeEnum.object
},
[WorkflowIOValueTypeEnum.arrayString]: {
label: 'array<string>',
value: WorkflowIOValueTypeEnum.arrayString,
description: ''
value: WorkflowIOValueTypeEnum.arrayString
},
[WorkflowIOValueTypeEnum.arrayNumber]: {
label: 'array<number>',
value: WorkflowIOValueTypeEnum.arrayNumber,
description: ''
value: WorkflowIOValueTypeEnum.arrayNumber
},
[WorkflowIOValueTypeEnum.arrayBoolean]: {
label: 'array<boolean>',
value: WorkflowIOValueTypeEnum.arrayBoolean,
description: ''
value: WorkflowIOValueTypeEnum.arrayBoolean
},
[WorkflowIOValueTypeEnum.arrayObject]: {
label: 'array<object>',
value: WorkflowIOValueTypeEnum.arrayObject,
description: ''
value: WorkflowIOValueTypeEnum.arrayObject
},
[WorkflowIOValueTypeEnum.any]: {
label: 'any',
value: WorkflowIOValueTypeEnum.any,
description: ''
value: WorkflowIOValueTypeEnum.any
},
[WorkflowIOValueTypeEnum.chatHistory]: {
label: '历史记录',
value: WorkflowIOValueTypeEnum.chatHistory,
description: `{
obj: System | Human | AI;
value: string;
}[]`
label: i18nT('common:core.chat.History'),
value: WorkflowIOValueTypeEnum.chatHistory
},
[WorkflowIOValueTypeEnum.datasetQuote]: {
label: '知识库引用',
value: WorkflowIOValueTypeEnum.datasetQuote,
description: `{
label: i18nT('common:core.workflow.Dataset quote'),
value: WorkflowIOValueTypeEnum.datasetQuote
},
[WorkflowIOValueTypeEnum.selectApp]: {
label: i18nT('common:plugin.App'),
value: WorkflowIOValueTypeEnum.selectApp
},
[WorkflowIOValueTypeEnum.selectDataset]: {
label: i18nT('common:core.chat.Select dataset'),
value: WorkflowIOValueTypeEnum.selectDataset
},
[WorkflowIOValueTypeEnum.dynamic]: {
label: i18nT('common:core.workflow.dynamic_input'),
value: WorkflowIOValueTypeEnum.dynamic
}
};
export const EDGE_TYPE = 'default';
export const defaultNodeVersion = '481';
export const chatHistoryValueDesc = `{
obj: System | Human | AI;
value: string;
}[]`;
export const datasetQuoteValueDesc = `{
id: string;
datasetId: string;
collectionId: string;
@@ -187,26 +203,4 @@ export const FlowValueTypeMap = {
sourceId?: string;
q: string;
a: string
}[]`
},
[WorkflowIOValueTypeEnum.selectApp]: {
label: '选择应用',
value: WorkflowIOValueTypeEnum.selectApp,
description: ''
},
[WorkflowIOValueTypeEnum.selectDataset]: {
label: '选择知识库',
value: WorkflowIOValueTypeEnum.selectDataset,
description: `{
datasetId: string;
}`
},
[WorkflowIOValueTypeEnum.dynamic]: {
label: '动态输入',
value: WorkflowIOValueTypeEnum.dynamic,
description: ''
}
};
export const EDGE_TYPE = 'default';
export const defaultNodeVersion = '481';
}[]`;

View File

@@ -10,7 +10,9 @@ export enum SseResponseEventEnum {
toolParams = 'toolParams', // tool params return
toolResponse = 'toolResponse', // tool response return
flowResponses = 'flowResponses', // sse response request
updateVariables = 'updateVariables'
updateVariables = 'updateVariables',
interactive = 'interactive' // user select
}
export enum DispatchNodeResponseKeyEnum {
@@ -19,7 +21,10 @@ export enum DispatchNodeResponseKeyEnum {
nodeDispatchUsages = 'nodeDispatchUsages', // the node bill.
childrenResponses = 'childrenResponses', // Some nodes make recursive calls that need to be returned
toolResponses = 'toolResponses', // The result is passed back to the tool node for use
assistantResponses = 'assistantResponses' // assistant response
assistantResponses = 'assistantResponses', // assistant response
rewriteHistories = 'rewriteHistories', // If have the response, workflow histories will be rewrite
interactive = 'INTERACTIVE' // is interactive
}
export const needReplaceReferenceInputTypeList = [

View File

@@ -2,8 +2,9 @@ import { ChatNodeUsageType } from '../../../support/wallet/bill/type';
import {
ChatItemType,
UserChatItemValueItemType,
ChatItemValueItemType,
ToolRunResponseItemType
ToolRunResponseItemType,
NodeOutputItemType,
AIChatItemValueItemType
} from '../../chat/type';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '../type/io.d';
import { StoreNodeItemType } from '../type/node';
@@ -17,16 +18,23 @@ import { AppDetailType, AppSchema } from '../../app/type';
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[];
@@ -34,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 & {
@@ -47,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 */
@@ -66,7 +76,7 @@ export type RuntimeNodeItemType = {
inputs: FlowNodeInputItemType[];
outputs: FlowNodeOutputItemType[];
pluginId?: string;
pluginId?: string; // workflow id / plugin id
};
export type PluginRuntimeType = {
@@ -93,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;
@@ -128,7 +140,7 @@ export type DispatchNodeResponseType = {
// http
params?: Record<string, any>;
body?: Record<string, any>;
body?: Record<string, any> | string;
headers?: Record<string, any>;
httpResult?: Record<string, any>;
@@ -153,15 +165,22 @@ export type DispatchNodeResponseType = {
// read files
readFilesResult?: string;
readFiles?: ReadFileNodeResponse;
// 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

@@ -6,7 +6,9 @@ import { StoreEdgeItemType } from '../type/edge';
import { RuntimeEdgeItemType, RuntimeNodeItemType } from './type';
import { VARIABLE_NODE_ID } from '../constants';
import { isReferenceValue } from '../utils';
import { ReferenceValueProps } from '../type/io';
import { FlowNodeOutputItemType, ReferenceValueProps } from '../type/io';
import { ChatItemType, NodeOutputItemType } from '../../../core/chat/type';
import { ChatItemValueTypeEnum, ChatRoleEnum } from '../../../core/chat/constants';
export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number => {
let limit = 10;
@@ -25,7 +27,51 @@ export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number
return limit * 2;
};
export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeItemType[] => {
/*
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 lastValue = lastAIMessage.value[lastAIMessage.value.length - 1];
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;
}
}
return null;
};
export const initWorkflowEdgeStatus = (
edges: StoreEdgeItemType[],
histories?: ChatItemType[]
): RuntimeEdgeItemType[] => {
// If there is a history, use the last interactive value
if (!!histories) {
const memoryEdges = getLastInteractiveValue(histories)?.memoryEdges;
if (memoryEdges && memoryEdges.length > 0) {
return memoryEdges;
}
}
return (
edges?.map((edge) => ({
...edge,
@@ -34,7 +80,19 @@ export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeI
);
};
export const getDefaultEntryNodeIds = (nodes: (StoreNodeItemType | RuntimeNodeItemType)[]) => {
export const getWorkflowEntryNodeIds = (
nodes: (StoreNodeItemType | RuntimeNodeItemType)[],
histories?: ChatItemType[]
) => {
// If there is a history, use the last interactive entry node
if (!!histories) {
const entryNodeIds = getLastInteractiveValue(histories)?.entryNodeIds;
if (Array.isArray(entryNodeIds) && entryNodeIds.length > 0) {
return entryNodeIds;
}
}
const entryList = [
FlowNodeTypeEnum.systemConfig,
FlowNodeTypeEnum.workflowStart,
@@ -75,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 执行
@@ -119,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')) {
@@ -194,7 +260,7 @@ export const textAdaptGptResponse = ({
finish_reason?: null | 'stop';
extraData?: Object;
}) => {
return JSON.stringify({
return {
...extraData,
id: '',
object: '',
@@ -210,5 +276,31 @@ export const textAdaptGptResponse = ({
finish_reason
}
]
});
};
};
/* Update runtimeNode's outputs with interactive data from history */
export function rewriteNodeOutputByHistories(
histories: ChatItemType[],
runtimeNodes: RuntimeNodeItemType[]
) {
const interactive = getLastInteractiveValue(histories);
if (!interactive?.nodeOutputs) {
return runtimeNodes;
}
return runtimeNodes.map((node) => {
return {
...node,
outputs: node.outputs.map((output: FlowNodeOutputItemType) => {
return {
...output,
value:
interactive?.nodeOutputs?.find(
(item: NodeOutputItemType) => item.nodeId === node.nodeId && item.key === output.key
)?.value || output?.value
};
})
};
});
}

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';
@@ -26,6 +28,7 @@ import { CodeNode } from './system/sandbox';
import { TextEditorNode } from './system/textEditor';
import { CustomFeedbackNode } from './system/customFeedback';
import { ReadFilesNodes } from './system/readFiles';
import { UserSelectNode } from './system/userSelect/index';
const systemNodes: FlowNodeTemplateType[] = [
AiChatModule,
@@ -43,18 +46,19 @@ const systemNodes: FlowNodeTemplateType[] = [
LafModule,
IfElseNode,
VariableUpdateNode,
CodeNode,
RunAppModule
CodeNode
];
/* app flow module templates */
export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
SystemConfigNode,
WorkflowStart,
...systemNodes,
CustomFeedbackNode
CustomFeedbackNode,
UserSelectNode
];
/* plugin flow module templates */
export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [
PluginConfigNode,
PluginInputModule,
PluginOutputModule,
...systemNodes
@@ -68,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

@@ -1,17 +1,19 @@
import {
chatHistoryValueDesc,
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,
@@ -20,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,
@@ -30,31 +32,32 @@ 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,
type: FlowNodeOutputTypeEnum.static
},
{
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

@@ -1,4 +1,5 @@
import {
chatHistoryValueDesc,
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
@@ -75,36 +76,38 @@ export const AiChatModule: FlowNodeTemplateType = {
renderTypeList: [FlowNodeInputTypeEnum.hidden],
label: '',
valueType: WorkflowIOValueTypeEnum.boolean,
value: true
value: false
},
// 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
},
{
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: i18nT('workflow:greeting'),
key: 'wqre'
},
{
value: '关于 xxx 的问题',
value: i18nT('workflow:about_xxx_question'),
key: 'sdfa'
},
{
value: '其他问题',
value: i18nT('workflow: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

@@ -1,4 +1,5 @@
import {
datasetQuoteValueDesc,
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
@@ -13,8 +14,7 @@ import {
import { getNanoid } from '../../../../common/string/tools';
import { getHandleConfig } from '../utils';
import { FlowNodeInputItemType } from '../../type/io.d';
const defaultQuoteKey = 'defaultQuoteKey';
import { i18nT } from '../../../../../web/i18n/utils';
export const getOneQuoteInputTemplate = ({
key = getNanoid(),
@@ -25,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
});
@@ -38,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
},
@@ -61,9 +63,10 @@ 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
valueType: WorkflowIOValueTypeEnum.datasetQuote,
valueDesc: datasetQuoteValueDesc
}
]
};

View File

@@ -1,4 +1,5 @@
import {
datasetQuoteValueDesc,
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
@@ -33,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
@@ -89,36 +90,27 @@ 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
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,
@@ -44,12 +46,22 @@ export const HttpNode468: FlowNodeTemplateType = {
value: 'POST',
required: true
},
{
key: NodeInputKeyEnum.httpTimeout,
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.number,
label: '',
value: 30,
min: 5,
max: 600,
required: true
},
{
key: NodeInputKeyEnum.httpReqUrl,
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
},
@@ -59,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
},
{
@@ -71,6 +83,7 @@ export const HttpNode468: FlowNodeTemplateType = {
label: '',
required: false
},
// json body data
{
key: NodeInputKeyEnum.httpJsonBody,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
@@ -78,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: [
@@ -87,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
},

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