Compare commits

..

57 Commits

Author SHA1 Message Date
Archer
a14a8ae627 perf: input guide (#1558) 2024-05-21 18:18:32 +08:00
Archer
fb368a581c Perf input guide (#1557)
* perf: input guide code

* perf: input guide ui

* Chat input guide api

* Update app chat config store

* perf: app chat config field

* perf: app context

* perf: params

* fix: ts

* perf: filter private config

* perf: filter private config

* perf: import workflow

* perf: limit max tip amount
2024-05-21 17:52:04 +08:00
Archer
8e8ceb7439 Add request log and uncatch error tip. (#1531) 2024-05-20 10:31:44 +08:00
heheer
e35ce2caa0 feat: question guide (#1508)
* feat: question guide

* fix

* fix

* fix

* change interface

* fix
2024-05-19 17:34:16 +08:00
Archer
fd31a0b763 feat: fix admin role (#1527) 2024-05-18 13:32:50 +08:00
Archer
ba517b6a73 fix: api key delete bug (#1524) 2024-05-17 18:03:14 +08:00
Archer
2f93dedfb6 Update permission (#1522)
* Permission (#1442)

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

This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be.

* feat: add permission display in the team manager modal

* feat: add permission i18n

* feat: let team module acquire permission ablity

* feat: add ownerPermission property into metaData

* feat: team premission system

* feat: extract the resourcePermission from resource schemas

* fix: move enum definition to constant

* feat: auth member permission handler, invite user

* feat: permission manage

* feat: adjust the style

* feat: team card style
- add a new icon

* feat: team permission in guest mode

* chore: change the type

* chore: delete useless file

* chore: delete useless code

* feat: do not show owner in PermissionManage view

* chore: fix style

* fix: icon remove fill

* feat: adjust the codes

---------

Co-authored-by: Archer <545436317@qq.com>

* perf: permission modal

* lock

---------

Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
2024-05-17 17:42:33 +08:00
Archer
67c52992d7 External dataset (#1519)
* perf: local file create collection

* rename middleware

* perf: remove code

* feat: next14

* feat: external file dataset

* collection tags field

* external file dataset doc

* fix: ts
2024-05-17 16:44:15 +08:00
Archer
2d1ec9b3ad perf: token count (#1509) 2024-05-16 17:05:56 +08:00
Archer
6067f5aff3 perf: tiktoken count (#1507)
* perf: tiktoken count

* fix: rerank histories

* fix: rerank histories

* update npmrc
2024-05-16 15:42:15 +08:00
Archer
c6d9b15897 External dataset (#1497)
* perf: read rawText and chunk code

* perf: read raw text

* perf: read rawtext

* perf: token count

* log
2024-05-16 11:47:53 +08:00
heheer
d5073f98ab perf:change plugin version update position (#1493)
* perf:change plugin version update position

* use nodeversion
2024-05-15 17:06:49 +08:00
Archer
8386f707cd Perf workflow (#1492)
* perf: handle edge check

* search model

* feat: plugin input can render all input; fix: plugin default value

* fix ts

* feat: plugin input support required
2024-05-15 16:17:43 +08:00
Archer
cd876251b7 External dataset (#1485)
* fix: revert version

* feat: external collection

* import context

* external ui

* doc

* fix: ts

* clear invalid data

* feat: rename sub name

* fix: node if else edge remove

* fix: init

* api size

* fix: if else node refresh
2024-05-15 10:19:51 +08:00
heheer
fb04889a31 feat: node version (#1484)
* feat: node version tip

* fix

* i18n

* init version

* fix ts

* fix ts

* fix ts
2024-05-14 23:26:03 +08:00
Archer
b779e2806d fix doc (#1475) 2024-05-14 12:58:04 +08:00
Fengrui Liu
240f60c0ca Fixes: fix edge handler with onDelEdge (#1471)
* fixes: Fix edge handler

* fixes: fix edge handler with onDelEdge

* fixes: fix edge handler with onDelEdge
2024-05-14 00:17:44 +08:00
Archer
8d2230f24f Update intro.md 2024-05-13 17:08:37 +08:00
Archer
610ebded3b Dir tree doc and move some code (#1466)
* tree doc and move some code

* fix: ts
2024-05-13 17:07:29 +08:00
Archer
80a84a5733 Change embedding (#1463)
* rebuild embedding queue

* dataset menu

* feat: rebuild data api

* feat: ui change embedding model

* dataset ui

* feat: rebuild index ui

* rename collection
2024-05-13 14:51:42 +08:00
Archer
59fd94384d fix: session (#1455)
* fix: session

* doc

* fix: i188n
2024-05-13 11:04:50 +08:00
Archer
ee8cb0915e i18n (#1444)
* adapt not input type

* adapt not input type

* file i18n

* publish i18n

* translate

* i18n
2024-05-11 00:21:01 +08:00
Archer
8cf643d972 adapt not input type (#1443)
* adapt not input type

* adapt not input type
2024-05-10 22:27:32 +08:00
Archer
26f4c92124 Perf: i18n ns (#1441)
* i18n

* fix: handle
2024-05-10 18:41:41 +08:00
heheer
f351d4ea68 fix: openapi integer & array type (#1439) 2024-05-10 18:40:01 +08:00
Archer
d70efe1d6f Fix export dataset (#1436)
* fix: export dataset

* remove file buffer
2024-05-10 16:15:23 +08:00
Cheer
435b2fba25 feat: i18n modify; (#1336) 2024-05-10 11:20:31 +08:00
Carson Yang
d61de17df2 README: update wechat qr code (#1431)
Signed-off-by: Carson Yang <yangchuansheng33@gmail.com>
2024-05-10 11:20:12 +08:00
Archer
08a310c41f Update doc (#1430) 2024-05-10 10:13:48 +08:00
samqin123
50716ff782 Create mongodump跨环境迁移数据库.md (#1426)
* Create mongodump跨环境迁移数据库.md

* Update mongodump跨环境迁移数据库.md
2024-05-10 10:00:59 +08:00
Archer
5e250b2f65 Change embedding (#1428)
* fix: text spliter

* perf: embedding model
2024-05-09 23:23:49 +08:00
Archer
434af56abd 4.8-alpha fix (#1424) 2024-05-09 22:48:44 +08:00
Archer
6463427d93 perf: detail=false, not response variable update (#1419) 2024-05-09 16:44:52 +08:00
heheer
af4c732d93 fix: change photo max size (#1416) 2024-05-09 16:31:56 +08:00
Archer
d4169bf066 fix: embedding recall drop-dead halt (#1415) 2024-05-09 16:13:06 +08:00
Archer
afe5039cd3 update docker-compose (#1414) 2024-05-09 15:52:15 +08:00
Archer
2155489be3 update doc and fix copy node (#1399)
* update doc

* fix: copy node

* perf: adapt tip

* update doc and package

* remove code
2024-05-09 14:09:24 +08:00
imgbot[bot]
eb36b71ac3 [ImgBot] Optimize images (#1398)
*Total -- 2,413.51kb -> 1,556.03kb (35.53%)

/docSite/assets/imgs/flow-tool2.png -- 171.30kb -> 34.32kb (79.96%)
/docSite/assets/imgs/judgement1.png -- 70.87kb -> 43.74kb (38.29%)
/docSite/assets/imgs/aichat2.png -- 64.94kb -> 40.39kb (37.8%)
/docSite/assets/imgs/demo-appointment5.png -- 70.95kb -> 45.23kb (36.25%)
/docSite/assets/imgs/cq1.png -- 104.80kb -> 67.09kb (35.98%)
/docSite/assets/imgs/string.png -- 67.67kb -> 43.75kb (35.35%)
/docSite/assets/imgs/chatinput.png -- 53.12kb -> 34.58kb (34.89%)
/docSite/assets/imgs/flow-intro2.png -- 263.99kb -> 173.15kb (34.41%)
/docSite/assets/imgs/flow-tool3.png -- 216.30kb -> 143.88kb (33.48%)
/docSite/assets/imgs/specialreply.png -- 152.58kb -> 101.64kb (33.39%)
/docSite/assets/imgs/aichat02.png -- 110.38kb -> 73.73kb (33.21%)
/docSite/assets/imgs/aichat.png -- 108.55kb -> 72.68kb (33.04%)
/docSite/assets/imgs/flow-intro1.png -- 306.26kb -> 205.67kb (32.85%)
/docSite/assets/imgs/flow-intro3.png -- 105.33kb -> 71.29kb (32.32%)
/docSite/assets/imgs/flow-dataset1.png -- 91.96kb -> 62.57kb (31.96%)
/docSite/assets/imgs/flow-tool1.png -- 94.70kb -> 64.60kb (31.78%)
/docSite/assets/imgs/extract1.png -- 74.00kb -> 50.68kb (31.51%)
/docSite/assets/imgs/flow-tool4.png -- 196.36kb -> 138.21kb (29.62%)
/docSite/assets/imgs/laf4.png -- 89.45kb -> 88.83kb (0.69%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2024-05-08 23:02:27 +08:00
左风
2230bc40c5 Doc: update doc (#1391)
* Doc: update doc

* Doc: update video link
2024-05-08 22:38:11 +08:00
Archer
917e4e9262 4.8 test fix (#1397)
* adapt v1 chat init

* adapt v1 chat init

* adapt v1 chat init

* perf: message input line; fix: http request un stream

* perf: message input line; fix: http request un stream

* perf: message input line; fix: http request un stream

* perf: error tip
2024-05-08 22:18:22 +08:00
Archer
3c6e5a6e00 4.8 test (#1394)
* fix: chat variable sync

* feat: chat save variable config

* fix: target handle hidden

* adapt v1 chat init

* adapt v1 chat init

* adapt v1 chat init

* adapt v1 chat init
2024-05-08 19:49:17 +08:00
heheer
7b75a99ba2 fix: add pptx encoding try catch (#1393) 2024-05-08 18:10:37 +08:00
heheer
2e468fc8ca 4.8 test fix (#1386)
* fix: boolean of if else input

* fix laf node

* fix laf bind

* fix laf input type

* fix if else check

* fix

* fix
2024-05-08 14:39:02 +08:00
Archer
caa0755d9a perf: global variable any type (#1387) 2024-05-07 18:54:32 +08:00
Archer
fef1a1702b 4.8 test fix (#1385)
* fix: tool name cannot startwith number

* fix: chatbox update

* fix: chatbox

* perf: drag ui

* perf: drag component

* drag component
2024-05-07 18:41:34 +08:00
heheer
2a99e46353 fix: if else node (#1383)
* fix: if else node

* fix

* fix
2024-05-07 17:16:33 +08:00
Archer
8f9203c053 4.8 test (#1382)
* perf: some log, chatTest histories slice; http request failed tip

* fix: ssr render

* perf: if else node ui and fix value type select
2024-05-07 15:27:05 +08:00
heheer
2053bbdb1b feat: add elseif to ifelse node (#1378) 2024-05-07 14:50:58 +08:00
Archer
9e192c6d11 Ai histories (#1376)
* perf: workflow node ui

* i18n

* rename controller

* fix: zindex

* fix: leave page callback

* revert button
2024-05-07 13:32:01 +08:00
Archer
eef609a063 Fix 4.8 node (#1370)
* perf: runtime props

* fix: Plugin run faied in debug mode

* perf: variable update

* fix: ts

* perf: variable ui
2024-05-06 17:13:50 +08:00
heheer
5bb9c550f6 fix: add judge to update variable node input (#1369) 2024-05-06 15:54:15 +08:00
Archer
db1c27cdc7 feat: adapt v1 system plugin (#1366) 2024-05-06 15:21:29 +08:00
heheer
8863337606 fix: reference input of updateVariable node (#1367)
* fix: reference input of updateVariable node

* fix
2024-05-06 13:51:15 +08:00
heheer
59bd2a47b6 feat: add update variable node (#1362)
* feat: add variable update node

* fix

* fix

* change component quote
2024-05-06 12:20:29 +08:00
Archer
d057ba29f0 feat: custom feedback plugin (#1365) 2024-05-06 11:01:50 +08:00
Archer
b500631a4d fix: leave user will can not login (#1345) 2024-05-06 10:41:01 +08:00
Carson Yang
bf6084da69 Enhance English language support in i18n (#1348)
Signed-off-by: Carson Yang <yangchuansheng33@gmail.com>
2024-05-02 08:35:59 +08:00
506 changed files with 15369 additions and 7924 deletions

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
public-hoist-pattern[]=*tiktoken*

46
.vscode/i18n-ally-custom-framework.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
# .vscode/i18n-ally-custom-framework.yml
# An array of strings which contain Language Ids defined by VS Code
# You can check available language ids here: https://code.visualstudio.com/docs/languages/identifiers
languageIds:
- javascript
- typescript
- javascriptreact
- typescriptreact
# An array of RegExes to find the key usage. **The key should be captured in the first match group**.
# You should unescape RegEx strings in order to fit in the YAML file
# To help with this, you can use https://www.freeformatter.com/json-escape.html
usageMatchRegex:
# The following example shows how to detect `t("your.i18n.keys")`
# the `{key}` will be placed by a proper keypath matching regex,
# you can ignore it and use your own matching rules as well
- "[^\\w\\d]t\\(['\"`]({key})['\"`]"
- "[^\\w\\d]commonT\\(['\"`]({key})['\"`]"
# 支持 appT("your.i18n.keys")
- "[^\\w\\d]appT\\(['\"`]({key})['\"`]"
# 支持 datasetT("your.i18n.keys")
- "[^\\w\\d]datasetT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]fileT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]publishT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]workflowT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]userT\\(['\"`]({key})['\"`]"
- "[^\\w\\d]chatT\\(['\"`]({key})['\"`]"
# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
# and works like how the i18next framework identifies the namespace scope from the
# useTranslation() hook.
# You should unescape RegEx strings in order to fit in the YAML file
# To help with this, you can use https://www.freeformatter.com/json-escape.html
scopeRangeRegex: "useTranslation\\(\\s*\\[?\\s*['\"`](.*?)['\"`]"
# An array of strings containing refactor templates.
# The "$1" will be replaced by the keypath specified.
# Optional: uncomment the following two lines to use
# refactorTemplates:
# - i18n.get("$1")
# If set to true, only enables this custom framework (will disable all built-in frameworks)
monopoly: true

View File

@@ -10,14 +10,19 @@
"scope": "javascript,typescript",
"prefix": "nextapi",
"body": [
"import type { NextApiRequest, NextApiResponse } from 'next';",
"import { NextAPI } from '@/service/middle/entry';",
"import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';",
"import { NextAPI } from '@/service/middleware/entry';",
"",
"type Props = {};",
"export type ${TM_FILENAME_BASE}Query = {};",
"",
"type Response = {};",
"export type ${TM_FILENAME_BASE}Body = {};",
"",
"async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<Response> {",
"export type ${TM_FILENAME_BASE}Response = {};",
"",
"async function handler(",
" req: ApiRequestProps<${TM_FILENAME_BASE}Body, ${TM_FILENAME_BASE}Query>,",
" res: ApiResponseType<any>",
"): Promise<${TM_FILENAME_BASE}Response> {",
" $1",
" return {}",
"}",
@@ -25,5 +30,23 @@
"export default NextAPI(handler);"
],
"description": "FastGPT Next API template"
},
"use context template": {
"scope": "typescriptreact",
"prefix": "context",
"body": [
"import { ReactNode } from 'react';",
"import { createContext } from 'use-context-selector';",
"",
"type ContextType = {$1};",
"",
"export const Context = createContext<ContextType>({});",
"",
"export const ContextProvider = ({ children }: { children: ReactNode }) => {",
" const contextValue: ContextType = {};",
" return <Context.Provider value={contextValue}>{children}</Context.Provider>;",
"};",
],
"description": "FastGPT usecontext template"
}
}

View File

@@ -6,10 +6,11 @@
"i18n-ally.localesPaths": [
"projects/app/i18n",
],
"i18n-ally.enabledParsers": ["json"],
"i18n-ally.enabledParsers": ["json", "yaml", "js", "ts"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.keepFulfilled": true,
"i18n-ally.keepFulfilled": false,
"i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译其他语言文件的变量和内容
"i18n-ally.displayLanguage": "zh", // 显示语言
"i18n-ally.extract.targetPickingStrategy": "most-similar-by-key"
}

View File

@@ -11,7 +11,7 @@ RUN apk add --no-cache libc6-compat && npm install -g pnpm@8.6.0
RUN [ -z "$proxy" ] || pnpm config set registry https://registry.npmmirror.com
# copy packages and one project
COPY pnpm-lock.yaml pnpm-workspace.yaml ./
COPY pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY ./packages ./packages
COPY ./projects/$name/package.json ./projects/$name/package.json
@@ -27,7 +27,7 @@ ARG name
ARG proxy
# copy common node_modules and one project node_modules
COPY package.json pnpm-workspace.yaml ./
COPY package.json pnpm-workspace.yaml .npmrc ./
COPY --from=mainDeps /app/node_modules ./node_modules
COPY --from=mainDeps /app/packages ./packages
COPY ./projects/$name ./projects/$name
@@ -36,6 +36,8 @@ COPY --from=mainDeps /app/projects/$name/node_modules ./projects/$name/node_modu
RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN apk add --no-cache libc6-compat && npm install -g pnpm@8.6.0
ENV NODE_OPTIONS="--max-old-space-size=4096"
RUN pnpm --filter=$name build
# --------- runner -----------
@@ -62,6 +64,11 @@ COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/static /app/
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/server/chunks /app/projects/$name/.next/server/chunks
# copy worker
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/server/worker /app/projects/$name/.next/server/worker
# copy tiktoken but not copy ./node_modules/tiktoken/encoders
COPY --from=mainDeps /app/node_modules/tiktoken ./node_modules/tiktoken
RUN rm -rf ./node_modules/tiktoken/encoders
# copy package.json to version file
COPY --from=builder /app/projects/$name/package.json ./package.json
# copy config
@@ -79,4 +86,4 @@ USER nextjs
ENV serverPath=./projects/$name/server.js
ENTRYPOINT ["sh","-c","node ${serverPath}"]
ENTRYPOINT ["sh","-c","node --max-old-space-size=4096 ${serverPath}"]

View File

@@ -122,7 +122,7 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
wx 扫一下加入:
![](https://oss.laf.run/htr4n1-images/fastgpt-qr-code.jpg)
![](https://oss.laf.run/htr4n1-images/wechat-qr-code.jpg)
<a href="#readme">
<img src="https://img.shields.io/badge/-返回顶部-7d09f1.svg" alt="#" align="right">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 293 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1,50 @@
---
title: "对话问题引导"
description: "FastGPT 对话问题引导"
icon: "code"
draft: false
toc: true
weight: 350
---
![](/imgs/questionGuide.png)
## 什么是自定义问题引导
你可以为你的应用提前预设一些问题,用户在输入时,会根据输入的内容,动态搜索这些问题作为提示,从而引导用户更快的进行提问。
你可以直接在 FastGPT 中配置词库,或者提供自定义词库接口。
## 自定义词库接口
需要保证这个接口可以被用户浏览器访问。
**请求:**
```bash
curl --location --request GET 'http://localhost:3000/api/core/chat/inputGuide/query?appId=663c75302caf8315b1c00194&searchKey=你'
```
**响应**
```json
{
"code": 200,
"statusText": "",
"message": "",
"data": [
"是你",
"你是谁呀",
"你好好呀",
"你好呀",
"你是谁!",
"你好"
]
}
```
**参数说明:**
- appId - 应用ID
- searchKey - 搜索关键字

View File

@@ -0,0 +1,26 @@
---
title: '外部文件知识库'
description: 'FastGPT 外部文件知识库功能介绍和使用方式'
icon: 'language'
draft: false
toc: true
weight: 107
---
外部文件库是 FastGPT 商业版特有功能。它允许接入你现在的文件系统,无需将文件再导入一份到 FastGPT 中。
并且,阅读权限可以通过你的文件系统进行控制。
| | | |
| --------------------- | --------------------- | --------------------- |
| ![](/imgs/external_file0.png) | ![](/imgs/external_file1.png) | ![](/imgs/external_file2.png) |
## 导入参数说明
- 外部预览地址用于跳转你的文件阅读地址会携带“文件阅读ID”进行访问。
- 文件访问URL文件可访问的地址。
- 文件阅读ID通常情况下文件访问URL是临时的。如果希望永久可以访问你需要使用该文件阅读ID并配合上“外部预览地址”跳转至新的阅读地址进行原文件访问。
- 文件名默认会自动解析文件访问URL上的文件名。如果你手动填写将会以手动填写的值为准。
[点击查看API导入文档](/docs/development/openapi/dataset/#创建一个外部文件库集合商业版)

View File

@@ -7,7 +7,7 @@ toc: true
weight: 101
---
更多使用技巧,[查看视屏教程](https://www.bilibili.com/video/BV1n34y1A7Bo/?spm_id_from=333.337.search-card.all.click&vd_source=903c2b09b7412037c2eddc6a8fb9828b)
更多使用技巧,[查看视屏教程](https://www.bilibili.com/video/BV1sH4y1T7s9)
## 知识库

View File

@@ -257,6 +257,13 @@ PG 数据库没有连接上/初始化失败可以查看日志。FastGPT 会
2. 非 docker 部署的,需要手动安装 pg vector 插件
3. 查看 fastgpt 日志,有没有相关报错
### Illegal instruction
可能原因:
1. arm架构。需要使用 Mongo 官方镜像: mongo:5.0.18
2. cpu 不支持 AVX无法用 mongo5需要换成 mongo4.x。把 mongo 的 image 换成: mongo:4.4.29
### Operation `auth_codes.findOne()` buffering timed out after 10000ms
mongo连接失败查看mongo的运行状态对应日志。

View File

@@ -17,18 +17,12 @@ images: []
4. 无法解决时,可以找找[Issue](https://github.com/labring/FastGPT/issues),或新提 Issue私有部署错误务必提供详细的日志否则很难排查。
## 二、通用问题
### 能否纯本地运行
可以。需要准备好向量模型和LLM模型。
### 页面中可以正常回复API 报错
页面中是用 stream=true 模式所以API也需要设置 stream=true 来进行测试。部分模型接口(国产居多)非 Stream 的兼容有点垃圾。
### 其他模型没法进行问题分类/内容提取
1. 看日志。如果提示 JSON invalidnot support tool 之类的,说明该模型不支持工具调用或函数调用,需要设置`toolChoice=false``functionCall=false`就会默认走提示词模式。目前内置提示词仅针对了商业模型API进行测试。问题分类基本可用内容提取不太行。
@@ -45,12 +39,36 @@ images: []
1. 问题补全需要经过一轮AI生成。
2. 会进行3~5轮的查询如果数据库性能不足会有明显影响。
### 模型响应为空(core.chat.Chat API is error or undefined)
### 对话接口报错或返回为空(core.chat.Chat API is error or undefined)
1. 检查 key 问题。
1. 检查 AI 的 key 问题:通过 curl 请求看是否正常。务必用 stream=true 模式。并且 maxToken 等相关参数尽量一致
2. 如果是国内模型,可能是命中风控了。
3. 查看模型请求日志,检查出入参数是否异常。
```sh
# curl 例子。
curl --location --request POST 'https://xxx.cn/v1/chat/completions' \
--header 'Authorization: Bearer sk-xxxx' \
--header 'Content-Type: application/json' \
--data-raw '{
"model": "gpt-3.5-turbo",
"stream": true,
"temperature": 1,
"max_tokens": 3000,
"messages": [
{
"role": "user",
"content": "你是谁"
}
]
}'
```
### 页面中可以正常回复API 报错
页面中是用 stream=true 模式所以API也需要设置 stream=true 来进行测试。部分模型接口(国产居多)非 Stream 的兼容有点垃圾。
和上一个问题一样curl 测试。
### 知识库索引没有进度/索引很慢
先看日志报错信息。有以下几种情况:
@@ -79,12 +97,14 @@ images: []
OneAPI 账号的余额不足,默认 root 用户只有 200 刀,可以手动修改。
路径打开OneAPI -> 用户 -> root用户右边的编辑 -> 剩余余额调大
### xxx渠道找不到
FastGPT 模型配置文件中的 model 必须与 OneAPI 渠道中的模型对应上,否则就会提示这个错误。可检查下面内容:
1. OneAPI 中没有配置该模型渠道,或者被禁用了。
2. 修改了 FastGPT 配置文件中一部分的模型,但没有全部修改,仍有模型是 OneAPI 没配置
2. FastGPT 配置文件有 OneAPI 没有配置的模型。如果 OneAPI 没配置对应模型的,配置文件中也不要写
3. 使用旧的向量模型创建了知识库,后又更新了向量模型。这时候需要删除以前的知识库,重建。
如果OneAPI中没有配置对应的模型`config.json`中也不要配置,否则容易报错。
@@ -98,4 +118,5 @@ OneAPI 的 API Key 配置错误,需要修改`OPENAI_API_KEY`环境变量,并
### bad_response_status_code bad response status code 503
1. 模型服务不可用
2. ....
2. 模型接口参数异常温度、max token等可能不适配
3. ....

View File

@@ -133,3 +133,57 @@ FastGPT 在`pnpm i`后会执行`postinstall`脚本,用于自动生成`ChakraUI
遇到困难了吗?有任何问题吗? 加入微信群与开发者和用户保持沟通。
<img width="400px" src="https://oss.laf.run/htr4n1-images/fastgpt-qr-code.jpg" class="medium-zoom-image" />
## 代码结构说明
### nextjs
FastGPT 使用了 nextjs 的 page route 作为框架。为了区分好前后端代码,在目录分配上会分成 global, service, web 3个自目录分别对应着 `前后端共用``后端专用``前端专用`的代码。
### monorepo
FastGPT 采用 pnpm workspace 方式构建 monorepo 项目,主要分为两个部分:
- projects/app - FastGPT 主项目
- packages/ - 子模块
- global - 共用代码,通常是放一些前后端都能执行的函数、类型声明、常量。
- service - 服务端代码
- web - 前端代码
- plugin - 工作流自定义插件的代码
### 领域驱动模式DDD
FastGPT 在代码模块划分时按DDD的思想进行划分主要分为以下几个领域
core - 核心功能(知识库,工作流,应用,对话)
support - 支撑功能(用户体系,计费,鉴权等)
common - 基础功能(日志管理,文件读写等)
{{% details title="代码结构说明" closed="true" %}}
```
.
├── .github // github 相关配置
├── .husky // 格式化配置
├── docSite // 文档
├── files // 一些外部文件,例如 docker-compose, helm
├── packages // 子包
│ ├── global // 前后端通用子包
│ ├── plugins // 工作流插件(需要自定义包时候使用到)
│ ├── service // 后端子包
│ └── web // 前端子包
├── projects
│ └── app // FastGPT 主项目
├── python // 存放一些模型代码,和 FastGPT 本身无关
└── scripts // 一些自动化脚本
├── icon // icon预览脚本可以在顶层 pnpm initIcon(把svg写入到代码中), pnpm previewIcon预览icon
└── postinstall.sh // chakraUI自定义theme初始化 ts 类型
├── package.json // 顶层monorepo
├── pnpm-lock.yaml
├── pnpm-workspace.yaml // monorepo 声明
├── Dockerfile
├── LICENSE
├── README.md
├── README_en.md
├── README_ja.md
├── dev.md
```
{{% /details %}}

View File

@@ -0,0 +1,186 @@
---
title: "Docker Mongo迁移(dump模式)"
description: "FastGPT Docker Mongo迁移"
icon: database
draft: false
weight: 762
---
## 作者
[https://github.com/samqin123](https://github.com/samqin123)
[相关PR。有问题可打开这里与作者交流](https://github.com/labring/FastGPT/pull/1426)
## 介绍
如何使用Mongodump来完成从A环境到B环境的Fastgpt的mongodb迁移
前提说明:
A环境我在阿里云上部署的fastgpt现在需要迁移到B环境。
B环境是新环境比如腾讯云新部署的fastgpt更特殊一点的是NAS群晖或者QNAP部署了fastgptmongo必须改成4.2或者4.4版本其实云端更方便支持fastgpt mongo默认版本
C环境妥善考虑用本地电脑作为C环境过渡保存相关文件并分离操作
## 1. 环境准备:进入 docker mongo 【A环境】
```
docker exec -it mongo sh
mongo -u 'username' -p 'password'
>> show dbs
```
看到fastgpt数据库以及其它几个确定下导出数据库名称
准备:
检查数据库,容器和宿主机都创建一下 backup 目录 【A环境 + C环境】
##### 准备:
检查数据库,容器和宿主机都创建一下“数据导出导入”临时目录 比如data/backup 【A环境建目录 + C环境建目录用于同步到容器中】
#### 先在【A环境】创建文件目录用于dump导出操作
容器先进入fastgpt docker容器
```
docker exec -it fastgpt sh
mkdir -p /data/backup
```
建好后未来导出mongo的数据会在A环境本地fastgpt的安装目录/Data/下看到自动同步好的目录数据会在data\backup中然后可以衔接后续的压缩和下载转移动作。如果没有同步到本地也可以手动建一下配合docker cp 把文件拷到本地用(基本不会发生)
#### 然后【C环境】宿主机目录类似操作用于把上传的文件自动同步到C环境部署的fastgpt容器里。
到fastgpt目录进入mongo目录有data目录下面建backup
```
mkdir -p /fastgpt/data/backup
```
准备好后,后续上传
```
### 新fastgpt环境【B】中也需要建一个比如/fastgpt/mongobackup目录注意不要在fastgpt/data目录下建立目录
```
mkdir -p /fastgpt/mongobackup
```
###2. 正题开始从fastgpt老环境【A】中导出数据
进入A环境使用mongodump 导出mongo数据库。
#### 2.1 导出
可以使用mongodump在源头容器中导出数据文件, 导出路径为上面指定临时目录,即"data\backup"
[导出的文件在代码中指定为/data/backup因为fastgpt配置文件已经建立了data的持久化所以会同步到容器所在环境本地fast/mongo/data应该就能看到这个导出的目录backup里面有文件]
一行指令导出代码,在服务器本地环境运行,不需要进入容器。
```
docker exec -it mongo bash -c "mongodump --db fastgpt -u 'username' -p 'password' --authenticationDatabase admin --out /data/backup"
```
也可以进入环境熟手可以结合建目录一次性完成建导出目录以及使用mongodump导出数据到该目录
```
1.docker exec -it fastgpt sh
2.mkdir -p /data/backup
3. mongodump --host 127.0.0.1:27017 --db fastgpt -u "username" -p "password" --authenticationDatabase admin --out /data/backup
##### 补充万一没自动同步也可以将mongodump导出的文件手工导出到宿主机【A环境】备用指令如下
```
docker cp mongo:/data/backup <A环境本地fastgpt目录>:/fastgpt/data/backup>
```
2.2 对新手建议稳妥起见压缩这个文件目录并将压缩文件下载到本地过渡环境【A环境 -> C环境】原因是因为留存一份并且检查文件数量是否一致。
熟手可以直接复制到新部署服务器腾讯云或者NAS【A环境-> B环境】
2.2.1 先进入 【A环境】源头系统的本地环境 fastgpt/mongo/data 目录
```
cd /usr/fastgpt/mongo/data
```
#执行,压缩文件命令
```
tar -czvf ../fastgpt-mongo-backup-$(date +%Y-%m-%d).tar.gz ./ 【A环境】
```
#接下来,把压缩包下载到本地 【A环境-> C环境】以便于检查和留存版本。熟手直接将该压缩包同步到B环境中新fastgpt目录data目录下备用。
```
scp -i /Users/path/<user.pem换成你自己的pem文件链接> root@<fastgpt所在云服务器地址>:/usr/fastgpt/mongo/fastgptbackup-2024-05-03.tar.gz /<本地电脑路径>/Downloads/fastgpt
```
熟手直接换成新环境地址
```
scp -i /Users/path/<user.pem换成你自己的pem文件链接> root@<老环境fastgpt服务器地址>:/usr/fastgpt/mongo/fastgptbackup-2024-05-03.tar.gz root@<新环境fastgpt服务器地址>:/Downloads/fastgpt2
```
2.2 【C环境】检查压缩文件是否完整如果不完整重新导出。事实上我也出现过问题因为跨环境scp会出现丢数据的情况。
压缩数据包导入到C环境本地后可以考虑在宿主机目录解压缩放在一个自定义目录比如. < user/fastgpt/mongobackup/data>
```
tar -xvzf fastgptbackup-2024-05-03.tar.gz -C user/fastgpt/mongobackup/data
```
解压缩后里面是bson文件这里可以检查下压缩文件数量是否一致。如果不一致后续启动新环境的fastgpt容器也不会有任何数据。
<img width="1561" alt="image" src="https://github.com/labring/FastGPT/assets/103937568/cbb8a93c-5834-4a0d-be6c-c45c701f593e">
如果没问题准备进入下一步将压缩包文件上传到B环境也就是新fastgpt环境里的指定目录比如/fastgpt/mongobackup, 注意不要放到fastgpt/data目录下因为下面会先清空一次这个目录否则导入会报错。
```
scp -rfv <本地电脑路径>/Downloads/fastgpt/fastgptbackup-2024-05-03.tar.gz root@<新环境fastgpt服务器地址>:/Downloads/fastgpt/backup
```
## 3 导入恢复: 实际恢复和导入步骤
### 3.1. 进入新fastgpt本地环境的安装目录后找到迁移的压缩文件包fastgptbackup-2024-05-03.tar.gz解压缩到指定目录
```
tar -xvzf fastgptbackup-2024-05-03.tar.gz -C user/fastgpt/mongobackup/data
```
再次核对文件数量,和上面对比一下。
熟手可以用tar指令检查文件完整性上面是给新手准备的便于比对核查。
### 3.2 手动上传新fastgpt docker容器里备用 【C环境】
说明因为没有放在data里所以不会自动同步到容器里。而且要确保容器的data目录被清理干净否则导入时会报错。
```
docker cp user/fastgpt/mongobackup/data mongo:/tmp/backup
```
### 3.3 建议初始化一次docker compose ,运行后建立新的 mongo/data 持久化目录
如果不是初始化的 mongo/db 目录, mongorestore 导入可能会报错。如果报错建议尝试初始化mongo。
操作指令
```
cd /fastgpt安装目录/mongo/data
rm -rf *
```
4.恢复: mongorestore 恢复 [C环境】
简单一点,退回到本地环境,用 docker 命令一键导入,当然你也可以在容器里操作
```
docker exec -it mongo mongorestore -u "username" -p "password" --authenticationDatabase admin /tmp/backup/ --db fastgpt
```
<img width="1668" alt="image" src="https://github.com/labring/FastGPT/assets/103937568/32c2cdb8-bf80-4d31-9269-4bf3909cf04e">
注意导入文件数量量级太少大概率是没导入成功的表现。如果导入不成功新环境fastgpt可以登入但是一片空白。
5.重启容器 【C环境】
```
docker compose restart
docker logs -f mongo **强烈建议先检查mongo运行情况在去做登陆动作如果mongo报错访问web也会报错”
```
如果mongo启动正常显示的是类似这样的而不是 “mongo is restarting”后者就是错误
<img width="1736" alt="iShot_2024-05-09_19 21 26" src="https://github.com/labring/FastGPT/assets/103937568/94ee00db-43de-48bd-a1fc-22dfe86aaa90">
报错情况
<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能看到原来的数据库内容完整显示说明已经导入系统了。
<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

@@ -0,0 +1,9 @@
---
weight: 960
title: "迁移&备份"
description: "FastGPT 迁移&备份"
icon: settings_backup_restore
draft: false
images: []
---
<!-- 960~970 -->

View File

@@ -0,0 +1,15 @@
---
weight: 762
title: "Docker 数据库迁移(无脑操作)"
description: "FastGPT Docker 数据库备份和迁移"
icon: database
draft: false
images: []
---
## Copy文件
Docker 部署数据库都会通过 volume 挂载本地的目录进入容器,如果要迁移,直接复制这些目录即可。
`PG 数据`: pg/data
`Mongo 数据`: mongo/data

View File

@@ -295,6 +295,24 @@ curl --location --request DELETE 'http://localhost:3000/api/core/dataset/delete?
## 集合
### 通用创建参数说明
**入参**
| 参数 | 说明 | 必填 |
| --- | --- | --- |
| datasetId | 知识库ID | ✅ |
| parentId | 父级ID不填则默认为根目录 | |
| trainingType | 训练模式。chunk: 按文本长度进行分割;qa: QA拆分;auto: 增强训练 | ✅ |
| chunkSize | 预估块大小 | |
| chunkSplitter | 自定义最高优先分割符号 | |
| qaPrompt | qa拆分提示词 | |
**出参**
- collectionId - 新建的集合ID
- insertLen插入的块数量
### 创建一个空的集合
{{< tabs tabTotal="3" >}}
@@ -500,7 +518,7 @@ data 为集合的 ID。
{{< /tab >}}
{{< /tabs >}}
### 创建一个文件集合(商业版)
### 创建一个文件集合
传入一个文件创建一个集合会读取文件内容进行分割。目前支持pdf, docx, md, txt, html, csv。
@@ -509,7 +527,7 @@ data 为集合的 ID。
{{< markdownify >}}
```bash
curl --location --request POST 'http://localhost:3000/api/proApi/core/dataset/collection/create/file' \
curl --location --request POST 'http://localhost:3000/api/core/dataset/collection/create/localFile' \
--header 'Authorization: Bearer {{authorization}}' \
--form 'file=@"C:\\Users\\user\\Desktop\\fastgpt测试文件\\index.html"' \
--form 'data="{\"datasetId\":\"6593e137231a2be9c5603ba7\",\"parentId\":null,\"trainingType\":\"chunk\",\"chunkSize\":512,\"chunkSplitter\":\"\",\"qaPrompt\":\"\",\"metadata\":{}}"'
@@ -565,6 +583,68 @@ data 为集合的 ID。
{{< /tab >}}
{{< /tabs >}}
### 创建一个外部文件库集合(商业版)
{{< tabs tabTotal="3" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}
```bash
curl --location --request POST 'http://localhost:3000/api/proApi/core/dataset/collection/create/externalFileUrl' \
--header 'Authorization: Bearer {{authorization}}' \
--header 'User-Agent: Apifox/1.0.0 (https://apifox.com)' \
--header 'Content-Type: application/json' \
--data-raw '{
"externalFileUrl":"https://image.xxxxx.com/fastgpt-dev/%E6%91%82.pdf",
"externalFileId":"1111",
"filename":"自定义文件名",
"datasetId":"6642d105a5e9d2b00255b27b",
"parentId": null,
"trainingType": "chunk",
"chunkSize":512,
"chunkSplitter":"",
"qaPrompt":""
}'
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="参数说明" >}}
{{< markdownify >}}
| 参数 | 说明 | 必填 |
| --- | --- | --- |
| externalFileUrl | 文件访问链接(可以是临时链接) | ✅ |
| externalFileId | 外部文件ID | |
| filename | 自定义文件名 | |
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="响应示例" >}}
{{< markdownify >}}
data 为集合的 ID。
```json
{
"code": 200,
"statusText": "",
"message": "",
"data": {
"collectionId": "6646fcedfabd823cdc6de746",
"insertLen": 3
}
}
```
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}
### 获取集合列表
{{< tabs tabTotal="3" >}}

View File

@@ -247,7 +247,7 @@ curl --location --request POST '{{host}}/shareAuth/finish' \
```ts
type ResponseType = {
moduleType: `${FlowNodeTypeEnum}`; // 模块类型
moduleType: FlowNodeTypeEnum; // 模块类型
moduleName: string; // 模块名
moduleLogo?: string; // logo
runningTime?: number; // 运行时间

View File

@@ -1,5 +1,5 @@
---
title: 'V4.8(进行中)'
title: 'V4.8'
description: 'FastGPT V4.8 更新说明'
icon: 'upgrade'
draft: false
@@ -11,17 +11,45 @@ weight: 824
FastGPT workflow V2上线支持更加简洁的工作流模式。
**由于工作流差异较大,需要手动重新构建。**
{{% alert icon="🤖 " context="success" %}}
**由于工作流差异较大,不少地方需要手动重新构建。请依次重建插件和应用**
简易尽快更新工作流,避免未来持续迭代后导致无法兼容。
{{% /alert %}}
给应用和插件增加了 version 的字段,用于标识是旧工作流还是新工作流。当你更新 4.8 后,保存和新建的工作流均为新版,旧版工作流会有一个重置的弹窗提示。并且,如果是通过 API 和 分享链接 调用的工作流,仍可以正常使用,直到你下次保存它们。
## 商业版配置更新
商业版用户如果配置了邮件验证码,需要在管理端 -> 项目配置 -> 登录配置 -> 邮箱登录配置 -> 修改 **邮箱服务SMTP地址**,之前只能配置别名,现在可以配置自定义的地址。下面是一组别名和实际地址关系:
qq: smtp.qq.com
gmail: smtp.gmail.com
## V4.8 更新说明
1. 重构 - 工作流
2. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流。
3. 新增 - 定时执行应用。可轻松实现定时任务。
4. 新增 - 插件自定义输入优化,可以渲染输入组件
6. 优化 - 工作流连线,可以四向连接,方便构建循环工作流。
7. 优化 - 工作流上下文传递,性能🚀
8. 优化 - 简易模式,更新配置后自动更新调试框内容,无需保存
9. 优化 - worker进程管理并将计算 Token 任务分配给 worker 进程。
2. 新增 - 判断器。支持 if elseIf else 判断。 @newfish-cmyk preview版本的if else节点需要删除重建
3. 新增 - 变量更新节点。支持更新运行中工作流输出变量,或更新全局变量。@newfish-cmyk
4. 新增 - 工作流自动保存和版本管理
5. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流。
6. 新增 - 定时执行应用。可轻松实现定时任务
7. 新增 - 插件自定义输入优化,可以渲染输入组件
8. 新增 - 分享链接发送对话前 hook https://github.com/labring/FastGPT/pull/1252 @gaord
9. 优化 - 工作流连线,可以四向连接,方便构建循环工作流。
10. 优化 - 工作流上下文传递,性能🚀。
11. 优化 - ctrl和alt+enter换行换行符位置不正确。
12. 优化 - chat中存储变量配置。避免修改变量后影响旧的对话。
13. 优化 - 简易模式,更新配置后自动更新调试框内容,无需保存。
14. 优化 - worker进程管理并将计算 Token 任务分配给 worker 进程。
15. 优化 - 工具调用支持指定字段数据类型string, boolean, number https://github.com/labring/FastGPT/issues/1236
16. 优化 - completions接口size限制 https://github.com/labring/FastGPT/issues/1241
17. 优化 - Node api 中间件。优化 api 端代码。@c121914yu
18. 优化 - 对话记录保持为偶数进行截取避免部分模型不支持奇数的历史记录最大长度增加到50轮。 https://github.com/labring/FastGPT/issues/1384
19. 优化 - HTTP节点错误后终止进程 https://github.com/labring/FastGPT/issues/1290
20. 修复 - 工具调用时候name不能是数字开头随机数有概率数字开头@c121914yu
21. 修复 - 分享链接, query 全局变量会被缓存。 @c121914yu
22. 修复 - 工具调用字段兼容。 https://github.com/labring/FastGPT/issues/1253
23. 修复 - HTTP 模块url光标问题 https://github.com/labring/FastGPT/issues/1334 @maquannene

View File

@@ -0,0 +1,45 @@
---
title: 'V4.8.1(进行中)'
description: 'FastGPT V4.8.1 更新说明'
icon: 'upgrade'
draft: false
toc: true
weight: 823
---
## 初始化脚本
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`{{host}} 替换成FastGPT的域名。
```bash
curl --location --request POST 'https://{{host}}/api/admin/initv481' \
--header 'rootkey: {{rootkey}}' \
--header 'Content-Type: application/json'
```
由于之前集合名不规范,该初始化会重置表名。请在初始化前,确保 dataset.trainings 表没有数据。
最好更新该版本时,暂停所有进行中业务,再进行初始化,避免数据冲突。
## 执行脏数据清理
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`{{host}} 替换成FastGPT的域名。
```bash
curl --location --request POST 'https://{{host}}/api/admin/clearInvalidData' \
--header 'rootkey: {{rootkey}}' \
--header 'Content-Type: application/json'
```
初始化完后,可以执行这个命令。之前定时清理的定时器有些问题,部分数据没被清理,可以手动执行清理。
## V4.8.1 更新说明
1. 新增 - 知识库重新选择向量模型重建
2. 新增 - 对话框支持问题模糊检索提示,可自定义预设问题词库。
3. 新增 - 工作流节点版本变更提示,并可以同步最新版本配置,避免存在隐藏脏数据。
4. 新增 - 开放文件导入知识库接口到开源版, [点击插件文档](/docs/development/openapi/dataset/#创建一个文件集合)
5. 新增 - 外部文件源知识库, [点击查看文档](/docs/course/externalfile/)
6. 优化 - 插件输入的 debug 模式,支持全量参数输入渲染。
7. 修复 - 插件输入默认值被清空问题。
8. 修复 - 工作流删除节点的动态输入和输出时候,没有正确的删除连接线,导致可能出现逻辑异常。
9. 修复 - 定时器清理脏数据任务

View File

@@ -17,16 +17,14 @@ FastGPT 从 V4 版本开始采用新的交互方式来构建 AI 应用。使用
在程序中,节点可以理解为一个个 Function 或者接口。可以理解为它就是一个**步骤**。将多个节点一个个拼接起来,即可一步步的去实现最终的 AI 输出。
如下图,这是一个最简单的 AI 对话。它由用户输入的问题、聊天记录以及 AI 对话节点组成。
如下图,这是一个最简单的 AI 对话。它由用流程开始和 AI 对话节点组成。
![](/imgs/flow-intro2.png)
执行流程如下:
1. 用户输入问题后,会向服务器发送一个请求,并携带问题。从而得到【用户问题】节点的输出
2. 根据设置的【最长记录数】来获取数据库中的记录数,从而得到【聊天记录】节点的输出
经过上面两个流程就得到了左侧两个蓝色点的结果。结果会被注入到右侧的【AI】对话节点。
3. 【AI 对话】节点根据传入的聊天记录和用户问题,调用对话接口,从而实现回答。(这里的对话结果输出隐藏了起来,默认只要触发了对话节点,就会往客户端输出内容)
1. 用户输入问题后,【流程开始】节点执行,用户问题被保存。
2. 【AI 对话】节点执行,此节点有两个必填参数“聊天记录” “用户问题”聊天记录的值是默认输入的6条表示此模块上下文长度。用户问题选择的是【流程开始】模块中保存的用户问题
3. 【AI 对话】节点根据传入的聊天记录和用户问题,调用对话接口,从而实现回答
### 节点分类
@@ -37,52 +35,46 @@ FastGPT 从 V4 版本开始采用新的交互方式来构建 AI 应用。使用
### 节点的组成
每个节点会包含 3 个核心部分:固定参数、外部输入(左边有个圆圈)和输出(右边有个圆圈)
每个节点会包含 3 个核心部分:输入、输出和触发器
![](/imgs/flow-intro3.png)
- 对话模型、温度、回复上限、系统提示词和限定词为固定参数,同时系统提示词和限定词也可以作为外部输入,意味着如果你有输入流向了系统提示词,那么原本填写的内容就会被**覆盖**
- 触发器、引用内容、聊天记录和用户问题则为外部输入,需要从其他节点的输出流入
- 回复结束则为该节点的输出
- AI模型、提示词、聊天记录、用户问题,知识库引用为输入,节点的输入可以是手动输入也可以是变量引用,变量引用的范围包括“全局变量”和之前任意一个节点的输出
- 新的上下文和AI回复内容为输出输出可以被之后任意节点变量引用
- 节点的上下左右有四个“触发器”可以被用来连接,被连接的节点按顺序决定是否执行
## 重点 - 工作流是如何运行的
与单出入口的工作流不同FastGPT的工作流可以指定**不同的入口**,并且没有**固定的出口**是以节点运行结束作为出口,如果在一个轮调用中,所有节点都不再允许,则工作流结束。
FastGPT的工作流从【流程开始】节点开始执行可以理解为从用户输入问题开始没有**固定的出口**,是以节点运行结束作为出口,如果在一个轮调用中,所有节点都不再允许,则工作流结束。
不过为了方便阅读,大部分时候,我们仍是设置一个模块作为入口,在工作流中,它被叫做`对话入口`下面我们来看下,工作流是如何运行的,以及每个节点何时被触发执行。
下面我们来看下,工作流是如何运行的,以及每个节点何时被触发执行。
记住3个**节点可执行**的原则:
![](/imgs/flow-intro1.png)
1. 仅关心**已连接的**外部输入,即左边的圆圈被连接了参数
2. 当**已连接的**内容都被赋值的时候触发。(这个地方经常会遇到,连接了很多根输入线,但是只要有一个输入没有值,这个节点也不会执行)
3. 可以多个输出连接到一个输入,后续的值会覆盖前面的值。
如上图所示节点会“被连接”也会“连接其他节点”我们称“被连接”的那根线为前置线“连接其他节点的线”为后置线。上图例子中【知识库搜索】模块左侧有一根前置线右侧有一根后置线。而【AI对话】节点只有左侧一根前置线
![](/imgs/workflow_process.png)
FastGPT工作流中的线有以下几种状态
- `waiting`:被连接的节点等待执行。
- `active`:被连接的节点可以执行。
- `skip`:被连接的节点不需要执行跳过。
### 示例 1
节点执行的原则:
聊天记录节点会自动执行因此聊天记录输入会自动赋值。当用户发送问题时【用户问题】节点会输出值此时【AI 对话】节点的用户问题输入也会被赋值。两个连接的输入都被赋值后,会执行 【AI 对话】节点。
1. 判断前置线中有没有状态为 `waiting` 的,如果有则等待。
2. 判断前置线中状态有没有状态为 `active` 如果有则执行。
3. 如果前置线中状态即没有 `waiting` 也没有 `active` 则认为此节点需要跳过。
4. 节点执行完毕后,需要根据实际情况更改后置线的状态为`active``skip`并且更改前置线状态为`waiting`等待下一轮执行。
![](/imgs/flow-intro1.png)
### 例子 2
下图是一个知识库搜索例子。
1. 历史记录会流入【AI 对话】节点。
2. 用户的问题会流入【知识库搜索】和【AI 对话】节点由于【AI 对话】节点的触发器和引用内容还是空,此时不会执行。
3. 【知识库搜索】节点仅一个外部输入,并且被赋值,开始执行。
4. 【知识库搜索】结果为空时“搜索结果不为空”的值为空不会输出因此【AI 对话】节点会因为触发器没有赋值而无法执行。而“搜索结果为空”会有输出,流向指定回复的触发器,因此【指定回复】节点进行输出。
5. 【知识库搜索】结果不为空时“搜索结果不为空”和“引用内容”都有输出会流向【AI 对话】此时【AI 对话】的 4 个外部输入都被赋值,开始执行。
![](/imgs/flow-intro4.png)
让我们看一下上面例子的执行过程:
1. 【流程开始】节点执行完毕,更改后置线为`active`
2. 【知识库搜索】节点判断前置线状态为`active`开始执行,执行完毕后更改后置线状态为`active` 前置线状态为`waiting`
3. 【AI对话】节点判断前置线状态为`active`开始执行,流程执行结束。
## 如何连接节点
1. 为了方便识别不同输入输出的类型FastGPT 每个节点的输入输出连接点赋予不同的颜色,你可以把相同颜色的连接点连接起来。其中,灰色代表任意类型,可以随意连接。
2. 位于左侧的连接点为输入,右侧的为输出,连接只能将一个输入和输出连接起来,不能连接“输入和输入”或者“输出和输出”
3. 可以点击连接线中间的 x 来删除连接线
4. 可以左键点击选中连接线
1. 为了方便连接FastGPT 每个节点的上下左右都有连接点,左和上是前置线连接点,右和下是后置线连接
2. 可以点击连接线中间的 x 来删除连接线
3. 可以左键点击选中连接线
## 如何阅读?
@@ -98,7 +90,4 @@ FastGPT 从 V4 版本开始采用新的交互方式来构建 AI 应用。使用
2. 知识库搜索合并,可以合并多个知识库搜索结果
3. 其他结果,无法直接合并,可以考虑传入到`HTTP`节点中进行合并,使用`[Laf](https://laf.run/)`可以快速实现一个无服务器HTTP接口。
### 节点为什么有2个用户问题
左侧的`用户问题`是指该节点所需的输入。右侧的`用户问题`是为了方便后续的连线,输出的值和传入的用户问题一样。

View File

@@ -10,8 +10,6 @@ weight: 351
## 特点
- 可重复添加
- 有外部输入
- 有静态配置
- 触发执行
- 核心模块

View File

@@ -10,7 +10,6 @@ weight: 352
## 特点
- 可重复添加
- 有外部输入
- 需要手动配置
- 触发执行
- function_call 模块
@@ -54,7 +53,5 @@ weight: 352
## 输出介绍
- **字段完全提取**:说明用户的问题中包含需要提取的所有内容。
- **提取字段缺失**:与 “字段完全提取” 对立,有缺失提取的字段时触发。
- **完整提取结果**: 一个 JSON 字符串,包含所有字段的提取结果。
- **目标字段提取结果**:类型均为字符串。

View File

@@ -29,16 +29,6 @@ weight: 357
[点击查看参数介绍](/docs/course/data_search/#搜索参数)
### 输出 - 搜索结果
输出部分给了两个 boolean 类型的搜索结果,以便根据搜索结果进行不同的处理,通常会有下方两个处理方式:
| 直接回复特定内容 | 对接普通的 gpt |
| ----------------------------- | ----------------------------- |
| ![](/imgs/flow-kbsearch2.png) | ![](/imgs/flow-kbsearch3.png) |
当然,你也可以连接到 HTTP 模块,从而实现无法从知识搜索到内容时,去进行联网搜索或者维基百科搜索。
### 输出 - 引用内容
以数组格式输出引用,长度可以为 0。意味着即使没有搜索到内容这个输出链路也会走通。

View File

@@ -10,7 +10,6 @@ weight: 355
## 特点
- 可重复添加
- 有外部输入
- 手动配置
- 触发执行
- 核中核模块
@@ -23,10 +22,11 @@ HTTP 模块会向对应的地址发送一个 `HTTP` 请求,实际操作与 Pos
- Params 为路径请求参数GET请求中用的居多。
- Body 为请求体POST/PUT请求中用的居多。
- Headers 为请求头,用于传递一些特殊的信息。
- Headers 为请求头,用于传递一些特殊的信息。
- 自定义变量中可以接收前方节点的输出作为变量
- 3 种数据中均可以通过 `{{}}` 来引用变量。
- url 也可以通过 `{{}}` 来引用变量。
- 变量来自于`全局变量``系统变量``局部传入`
- 变量来自于`全局变量``系统变量``前方节点输出`
## 参数结构

View File

@@ -9,9 +9,8 @@ weight: 356
## 特点
- 可重复添加(防止复杂编排时线太乱,重复添加可以更美观)
- 无外部输入
- 流程入口
- 无输入
- 自动执行
![](/imgs/chatinput.png)

View File

@@ -14,19 +14,13 @@ weight: 359
- 可外部输入
- 会输出结果给客户端
定回复模块通常用户特殊状态回复,当然你也可以像图 2 一样,实现一些比较骚的操作~ 触发逻辑非常简单
定回复模块通常用户特殊状态回复,回复内容有两种
1. 一种是写好回复内容,通过触发器触发
2. 一种是不写回复内容,直接由外部输入触发,并回复输入的内容
1. 一种是手动输入固定内容
2. 一种是通过变量引用
{{< figure
src="/imgs/specialreply.png"
alt=""
caption="图 1"
>}}
{{< figure
src="/imgs/specialreply2.png"
alt=""
caption="图 2"
>}}

View File

@@ -20,7 +20,7 @@ weight: 363
## 功能
对输入文本进行固定加工处理,入参仅支持字符串和数字格式,入参以变量形式使用在文本编辑区域。
根据上方示例图的处理方式,对任何输入都会在前面拼接“的问题是”。
根据上方示例图的处理方式,对任何输入都会在前面拼接“用户的问题是:”。
## 作用

View File

@@ -17,44 +17,13 @@ weight: 362
## 功能
对任意输入内容进行 True False 输出,默认情况下,当传入的内容为 false, undefined, null,0,none 时,会输出 false。
对任意变量进行`IF`判断,若满足条件则执行`IF`分支,不满足条件执行`ELSE`分支。
也可以增加自定义规则来补充输出 false 的内容,每行代表一个匹配规则,支持正则表达式。
**例子1**
上述例子中若「知识库引用」变量的长度等于0则执行`IF`分支,否则执行`ELSE`分支。
不填写任何自定义 False 规则。
| 输入 | 输出 |
| --- | --- |
| 123 | true |
| 这是一段文本 | true |
| false | false |
| 0 | false |
| null | false |
**例子2**
自定义 False 规则:
```
123
你好
aa
/dd/
```
| 输入 | 输出 | 说明 |
| --- | --- | --- |
| 123 | false | 命中自定义 false 规则 |
| 这是一段文本 | true | 未命中 |
| false | false | 命中自定义 内置 规则 |
| 0 | false | 命中自定义 内置 规则 |
| null | false | 命中自定义 内置 规则 |
| aa | false | 命中自定义 false 规则 |
| aaa | true | 未命中 |
| bb | false | 命中自定义 false 规则 |
| bbb | false | 命中自定义 false 规则(正则匹配通过) |
支持增加更多的判断条件和分支,同编程语言中的`IF`语句逻辑相同。
## 作用

View File

@@ -47,7 +47,7 @@ weight: 356
| --- | --- |
| ![](/imgs/flow-tool3.png) | ![](/imgs/flow-tool4.png) |
高级编排中,一旦有了工具调用模块,可用的工具头部会出现一个菱形,可以将它与工具调用模块底部的菱形相连接。
高级编排中,托动工具调用的连接点,可用的工具头部会出现一个菱形,可以将它与工具调用模块底部的菱形相连接。
被连接的工具,会自动分离工具输入与普通的输入,并且可以编辑`介绍`,可以通过调整介绍,使得该工具调用时机更加精确。

View File

@@ -1,24 +0,0 @@
---
title: "触发器"
description: "FastGPT 触发器模块介绍"
icon: "work_history"
draft: false
toc: true
weight: 360
---
细心的同学可以发现,在每个功能模块里都会有一个叫【触发器】的外部输入,并且是 any 类型。
它的**核心作用**就是控制模块的执行时机以下图两个知识库搜索中的【AI 对话】模块为例子:
| 图 1 | 图 2 |
| ---------------------------- | ---------------------------- |
| ![](/imgs/trigger1.png) | ![](/imgs/trigger2.png) |
【知识库搜索】模块中,由于**引用内容**始终会有输出会导致【AI 对话】模块的**引用内容**输入无论有没有搜到内容都会被赋值。如果此时不连接触发器(图 2在搜索结束后必定会执行【AI 对话】模块。
有时候,你可能希望空搜索时候进行额外处理,例如:回复固定内容、调用其他提示词的 GPT、发送一个 HTTP 请求…… 此时就需要用到触发器,需要将 **搜索结果不为空****触发器** 连接起来。
当搜索结果为空时,【知识库搜索】模块不会输出 **搜索结果不为空** 的结果,因此 【AI 对话】 模块的触发器始终为空,便不会执行。
总之,记住模块执行的逻辑就可以灵活的使用触发器:**外部输入字段(有连接的才有效)全部被赋值时才会被执行**。

View File

@@ -1,12 +1,13 @@
# 数据库的默认账号和密码仅首次运行时设置有效
# 如果修改了账号密码,记得改数据库和项目连接参数,别只改一处~
# 该配置文件只是给快速启动,测试使用。正式使用,记得务必修改账号密码,以及调整合适的知识库参数,共享内存等。
# 如何无法访问 dockerhub 和 git可以用阿里云阿里云没有arm包
version: '3.3'
services:
pg:
image: ankane/pgvector:v0.5.0 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.5.0 # 阿里云
image: pgvector/pgvector:0.7.0-pg15 # docker hub
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.7.0 # 阿里云
container_name: pg
restart: always
ports: # 生产环境建议不要暴露
@@ -21,7 +22,9 @@ services:
volumes:
- ./pg/data:/var/lib/postgresql/data
mongo:
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18
image: mongo:5.0.18 # dockerhub
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
# image: mongo:4.4.29 # cpu不支持AVX时候使用
container_name: mongo
restart: always
ports:
@@ -66,8 +69,8 @@ services:
wait $$!
fastgpt:
container_name: fastgpt
image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.7 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.7 # 阿里云
image: ghcr.io/labring/fastgpt:v4.8 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8 # 阿里云
ports:
- 3000:3000
networks:

View File

@@ -99,13 +99,41 @@ data:
}
],
"vectorModels": [
{
"model": "text-embedding-3-large",
"name": "Embedding-2",
"avatar": "/imgs/model/openai.svg",
"charsPointsPrice": 0,
"defaultToken": 512,
"maxToken": 3000,
"weight": 100,
"dbConfig": {},
"queryConfig": {},
"defaultConfig": {
"dimensions": 1024
}
},
{
"model": "text-embedding-3-small",
"name": "Embedding-2",
"avatar": "/imgs/model/openai.svg",
"charsPointsPrice": 0,
"defaultToken": 512,
"maxToken": 3000,
"weight": 100,
"dbConfig": {},
"queryConfig": {}
},
{
"model": "text-embedding-ada-002",
"name": "Embedding-2",
"avatar": "/imgs/model/openai.svg",
"charsPointsPrice": 0,
"defaultToken": 700,
"defaultToken": 512,
"maxToken": 3000,
"weight": 100
"weight": 100,
"dbConfig": {},
"queryConfig": {}
}
],
"reRankModels": [],

View File

@@ -2,7 +2,7 @@ import { ErrType } from '../errorCode';
/* dataset: 502000 */
export enum AppErrEnum {
unExist = 'unExist',
unExist = 'appUnExist',
unAuthApp = 'unAuthApp'
}
const appErrList = [

View File

@@ -2,8 +2,8 @@ import { ErrType } from '../errorCode';
/* dataset: 506000 */
export enum OpenApiErrEnum {
unExist = 'unExist',
unAuth = 'unAuth'
unExist = 'openapiUnExist',
unAuth = 'openapiUnAuth'
}
const errList = [
{

View File

@@ -2,7 +2,7 @@ import { ErrType } from '../errorCode';
/* dataset: 505000 */
export enum OutLinkErrEnum {
unExist = 'unExist',
unExist = 'outlinkUnExist',
unAuthLink = 'unAuthLink',
linkUnInvalid = 'linkUnInvalid',

View File

@@ -2,8 +2,8 @@ import { ErrType } from '../errorCode';
/* dataset: 507000 */
export enum PluginErrEnum {
unExist = 'unExist',
unAuth = 'unAuth'
unExist = 'pluginUnExist',
unAuth = 'pluginUnAuth'
}
const errList = [
{

View File

@@ -4,7 +4,7 @@ export enum BucketNameEnum {
}
export const bucketNameMap = {
[BucketNameEnum.dataset]: {
label: 'common.file.bucket.dataset'
label: 'file.bucket.dataset'
}
};

View File

@@ -13,36 +13,36 @@ export enum MongoImageTypeEnum {
}
export const mongoImageTypeMap = {
[MongoImageTypeEnum.systemAvatar]: {
label: 'common.file.type.appAvatar',
label: 'appAvatar',
unique: true
},
[MongoImageTypeEnum.appAvatar]: {
label: 'common.file.type.appAvatar',
label: 'appAvatar',
unique: true
},
[MongoImageTypeEnum.pluginAvatar]: {
label: 'common.file.type.pluginAvatar',
label: 'pluginAvatar',
unique: true
},
[MongoImageTypeEnum.datasetAvatar]: {
label: 'common.file.type.datasetAvatar',
label: 'datasetAvatar',
unique: true
},
[MongoImageTypeEnum.userAvatar]: {
label: 'common.file.type.userAvatar',
label: 'userAvatar',
unique: true
},
[MongoImageTypeEnum.teamAvatar]: {
label: 'common.file.type.teamAvatar',
label: 'teamAvatar',
unique: true
},
[MongoImageTypeEnum.chatImage]: {
label: 'common.file.type.chatImage',
label: 'chatImage',
unique: false
},
[MongoImageTypeEnum.collectionImage]: {
label: 'common.file.type.collectionImage',
label: 'collectionImage',
unique: false
}
};

View File

@@ -1,24 +1,99 @@
import { getErrText } from '../error/utils';
import { replaceRegChars } from './tools';
/**
* text split into chunks
* chunkLen - one chunk len. max: 3500
* overlapLen - The size of the before and after Text
* chunkLen > overlapLen
* markdown
*/
export const splitText2Chunks = (props: {
export const CUSTOM_SPLIT_SIGN = '-----CUSTOM_SPLIT_SIGN-----';
type SplitProps = {
text: string;
chunkLen: number;
overlapRatio?: number;
customReg?: string[];
}): {
};
export type TextSplitProps = Omit<SplitProps, 'text' | 'chunkLen'> & {
chunkLen?: number;
};
type SplitResponse = {
chunks: string[];
chars: number;
overlapRatio?: number;
} => {
};
// 判断字符串是否为markdown的表格形式
const strIsMdTable = (str: string) => {
// 检查是否包含表格分隔符 |
if (!str.includes('|')) {
return false;
}
const lines = str.split('\n');
// 检查表格是否至少有两行
if (lines.length < 2) {
return false;
}
// 检查表头行是否包含 |
const headerLine = lines[0].trim();
if (!headerLine.startsWith('|') || !headerLine.endsWith('|')) {
return false;
}
// 检查分隔行是否由 | 和 - 组成
const separatorLine = lines[1].trim();
const separatorRegex = /^(\|[\s:]*-+[\s:]*)+\|$/;
if (!separatorRegex.test(separatorLine)) {
return false;
}
// 检查数据行是否包含 |
for (let i = 2; i < lines.length; i++) {
const dataLine = lines[i].trim();
if (dataLine && (!dataLine.startsWith('|') || !dataLine.endsWith('|'))) {
return false;
}
}
return true;
};
const markdownTableSplit = (props: SplitProps): SplitResponse => {
let { text = '', chunkLen } = props;
const splitText2Lines = text.split('\n');
const header = splitText2Lines[0];
const headerSize = header.split('|').length - 2;
const mdSplitString = `| ${new Array(headerSize > 0 ? headerSize : 1)
.fill(0)
.map(() => '---')
.join(' | ')} |`;
const chunks: string[] = [];
let chunk = `${header}
${mdSplitString}
`;
for (let i = 2; i < splitText2Lines.length; i++) {
if (chunk.length + splitText2Lines[i].length > chunkLen * 1.2) {
chunks.push(chunk);
chunk = `${header}
${mdSplitString}
`;
}
chunk += `${splitText2Lines[i]}\n`;
}
if (chunk) {
chunks.push(chunk);
}
return {
chunks,
chars: chunks.reduce((sum, chunk) => sum + chunk.length, 0)
};
};
const commonSplit = (props: SplitProps): SplitResponse => {
let { text = '', chunkLen, overlapRatio = 0.2, customReg = [] } = props;
const splitMarker = 'SPLIT_HERE_SPLIT_HERE';
const codeBlockMarker = 'CODE_BLOCK_LINE_MARKER';
const overlapLen = Math.round(chunkLen * overlapRatio);
@@ -253,3 +328,29 @@ export const splitText2Chunks = (props: {
throw new Error(getErrText(err));
}
};
/**
* text split into chunks
* chunkLen - one chunk len. max: 3500
* overlapLen - The size of the before and after Text
* chunkLen > overlapLen
* markdown
*/
export const splitText2Chunks = (props: SplitProps): SplitResponse => {
let { text = '' } = props;
const splitWithCustomSign = text.split(CUSTOM_SPLIT_SIGN);
const splitResult = splitWithCustomSign.map((item) => {
if (strIsMdTable(item)) {
return markdownTableSplit(props);
}
return commonSplit(props);
});
return {
chunks: splitResult.map((item) => item.chunks).flat(),
chars: splitResult.reduce((sum, item) => sum + item.chars, 0)
};
};

View File

@@ -6,6 +6,42 @@ export const formatTime2YMDHM = (time?: Date) =>
export const formatTime2YMD = (time?: Date) => (time ? dayjs(time).format('YYYY-MM-DD') : '');
export const formatTime2HM = (time: Date = new Date()) => dayjs(time).format('HH:mm');
/**
* 格式化时间成聊天格式
*/
export const formatTimeToChatTime = (time: Date) => {
const now = dayjs();
const target = dayjs(time);
// 如果传入时间小于60秒返回刚刚
if (now.diff(target, 'second') < 60) {
return '刚刚';
}
// 如果时间是今天,展示几时:几分
if (now.isSame(target, 'day')) {
return target.format('HH:mm');
}
// 如果是昨天,展示昨天
if (now.subtract(1, 'day').isSame(target, 'day')) {
return '昨天';
}
// 如果是前天,展示前天
if (now.subtract(2, 'day').isSame(target, 'day')) {
return '前天';
}
// 如果是今年,展示某月某日
if (now.isSame(target, 'year')) {
return target.format('MM/DD');
}
// 如果是更久之前,展示某年某月某日
return target.format('YYYY/M/D');
};
/* cron time parse */
export const cronParser2Fields = (cronString: string) => {
try {

View File

@@ -50,8 +50,18 @@ export const replaceSensitiveText = (text: string) => {
return text;
};
/* Make sure the first letter is definitely lowercase */
export const getNanoid = (size = 12) => {
return customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', size)();
const firstChar = customAlphabet('abcdefghijklmnopqrstuvwxyz', 1)();
if (size === 1) return firstChar;
const randomsStr = customAlphabet(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
size - 1
)();
return `${firstChar}${randomsStr}`;
};
export const replaceRegChars = (text: string) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

View File

@@ -66,6 +66,8 @@ export type SystemEnvType = {
vectorMaxProcess: number;
qaMaxProcess: number;
pgHNSWEfSearch: number;
tokenWorkers: number; // token count max worker
oneapiUrl?: string;
chatApiKey?: string;
};

View File

@@ -23,7 +23,7 @@ export const defaultQAModels: LLMModelItemType[] = [
export const defaultVectorModels: VectorModelItemType[] = [
{
model: 'text-embedding-ada-002',
model: 'text-embedding-3-small',
name: 'Embedding-2',
charsPointsPrice: 0,
defaultToken: 500,

View File

@@ -1,4 +1,4 @@
import { AppWhisperConfigType } from './type';
import { AppTTSConfigType, AppWhisperConfigType } from './type';
export enum AppTypeEnum {
simple = 'simple',
@@ -13,8 +13,16 @@ export const AppTypeMap = {
}
};
export const defaultTTSConfig: AppTTSConfigType = { type: 'web' };
export const defaultWhisperConfig: AppWhisperConfigType = {
open: false,
autoSend: false,
autoTTSResponse: false
};
export const defaultChatInputGuideConfig = {
open: false,
textList: [],
customUrl: ''
};

View File

@@ -8,7 +8,7 @@ import { DatasetSearchModeEnum } from '../dataset/constants';
import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
import { StoreEdgeItemType } from '../workflow/type/edge';
export interface AppSchema {
export type AppSchema = {
_id: string;
teamId: string;
tmbId: string;
@@ -23,13 +23,14 @@ export interface AppSchema {
edges: StoreEdgeItemType[];
// App system config
chatConfig: AppChatConfigType;
scheduledTriggerConfig?: AppScheduledTriggerConfigType | null;
scheduledTriggerNextTime?: Date;
permission: `${PermissionTypeEnum}`;
inited?: boolean;
teamTags: string[];
}
};
export type AppListItemType = {
_id: string;
@@ -66,32 +67,19 @@ export type AppSimpleEditFormType = {
datasetSearchExtensionBg?: string;
};
selectedTools: FlowNodeTemplateType[];
userGuide: {
welcomeText: string;
variables: {
id: string;
key: string;
label: string;
type: `${VariableInputEnum}`;
required: boolean;
maxLen: number;
enums: {
value: string;
}[];
}[];
questionGuide: boolean;
tts: {
type: 'none' | 'web' | 'model';
model?: string | undefined;
voice?: string | undefined;
speed?: number | undefined;
};
whisper: AppWhisperConfigType;
scheduleTrigger: AppScheduledTriggerConfigType | null;
};
chatConfig: AppChatConfigType;
};
/* app function config */
/* app chat config type */
export type AppChatConfigType = {
welcomeText?: string;
variables?: VariableItemType[];
questionGuide?: boolean;
ttsConfig?: AppTTSConfigType;
whisperConfig?: AppWhisperConfigType;
scheduledTriggerConfig?: AppScheduledTriggerConfigType;
chatInputGuide?: ChatInputGuideConfigType;
};
export type SettingAIDataType = {
model: string;
temperature: number;
@@ -123,6 +111,11 @@ export type AppWhisperConfigType = {
autoSend: boolean;
autoTTSResponse: boolean;
};
// question guide text
export type ChatInputGuideConfigType = {
open: boolean;
customUrl: string;
};
// interval timer
export type AppScheduledTriggerConfigType = {
cronString: string;

View File

@@ -1,49 +1,42 @@
import type { AppSimpleEditFormType } from '../app/type';
import type { AppChatConfigType, AppSimpleEditFormType } from '../app/type';
import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { NodeInputKeyEnum, FlowNodeTemplateTypeEnum } from '../workflow/constants';
import type { FlowNodeInputItemType } from '../workflow/type/io.d';
import { getGuideModule, splitGuideModule } from '../workflow/utils';
import { getAppChatConfig } from '../workflow/utils';
import { StoreNodeItemType } from '../workflow/type';
import { DatasetSearchModeEnum } from '../dataset/constants';
import { defaultWhisperConfig } from './constants';
export const getDefaultAppForm = (): AppSimpleEditFormType => {
return {
aiSettings: {
model: 'gpt-3.5-turbo',
systemPrompt: '',
temperature: 0,
isResponseAnswerText: true,
maxHistories: 6,
maxToken: 4000
},
dataset: {
datasets: [],
similarity: 0.4,
limit: 1500,
searchMode: DatasetSearchModeEnum.embedding,
usingReRank: false,
datasetSearchUsingExtensionQuery: true,
datasetSearchExtensionBg: ''
},
selectedTools: [],
userGuide: {
welcomeText: '',
variables: [],
questionGuide: false,
tts: {
type: 'web'
},
whisper: defaultWhisperConfig,
scheduleTrigger: null
}
};
};
export const getDefaultAppForm = (): AppSimpleEditFormType => ({
aiSettings: {
model: 'gpt-3.5-turbo',
systemPrompt: '',
temperature: 0,
isResponseAnswerText: true,
maxHistories: 6,
maxToken: 4000
},
dataset: {
datasets: [],
similarity: 0.4,
limit: 1500,
searchMode: DatasetSearchModeEnum.embedding,
usingReRank: false,
datasetSearchUsingExtensionQuery: true,
datasetSearchExtensionBg: ''
},
selectedTools: [],
chatConfig: {}
});
/* format app nodes to edit form */
export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
export const appWorkflow2Form = ({
nodes,
chatConfig
}: {
nodes: StoreNodeItemType[];
chatConfig: AppChatConfigType;
}) => {
const defaultAppForm = getDefaultAppForm();
const findInputValueByKey = (inputs: FlowNodeInputItemType[], key: string) => {
return inputs.find((item) => item.key === key)?.value;
};
@@ -102,24 +95,6 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
node.inputs,
NodeInputKeyEnum.datasetSearchExtensionBg
);
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
const {
welcomeText,
variableModules,
questionGuide,
ttsConfig,
whisperConfig,
scheduledTriggerConfig
} = splitGuideModule(getGuideModule(nodes));
defaultAppForm.userGuide = {
welcomeText: welcomeText,
variables: variableModules,
questionGuide: questionGuide,
tts: ttsConfig,
whisper: whisperConfig,
scheduleTrigger: scheduledTriggerConfig
};
} else if (node.flowNodeType === FlowNodeTypeEnum.pluginModule) {
if (!node.pluginId) return;
@@ -131,10 +106,17 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
intro: node.intro || '',
flowNodeType: node.flowNodeType,
showStatus: node.showStatus,
version: '481',
inputs: node.inputs,
outputs: node.outputs,
templateType: FlowNodeTemplateTypeEnum.other
});
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
defaultAppForm.chatConfig = getAppChatConfig({
chatConfig,
systemConfigNode: node,
isPublicFetch: true
});
}
});

View File

@@ -1,5 +1,6 @@
import { StoreNodeItemType } from '../workflow/type';
import { StoreEdgeItemType } from '../workflow/type/edge';
import { AppChatConfigType } from './type';
export type AppVersionSchemaType = {
_id: string;
@@ -7,4 +8,5 @@ export type AppVersionSchemaType = {
time: Date;
nodes: StoreNodeItemType[];
edges: StoreEdgeItemType[];
chatConfig: AppChatConfigType;
};

View File

@@ -0,0 +1,5 @@
export type ChatInputGuideSchemaType = {
_id: string;
appId: string;
text: string;
};

View File

@@ -10,7 +10,7 @@ import {
import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { NodeOutputKeyEnum } from '../workflow/constants';
import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
import { AppSchema } from '../app/type';
import { AppChatConfigType, AppSchema, VariableItemType } from '../app/type';
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
import { DatasetSearchModeEnum } from '../dataset/constants';
import { ChatBoxInputType } from '../../../../projects/app/src/components/ChatBox/type';
@@ -27,11 +27,13 @@ export type ChatSchema = {
title: string;
customTitle: string;
top: boolean;
variables: Record<string, any>;
source: `${ChatSourceEnum}`;
shareId?: string;
outLinkUid?: string;
content: ChatItemType[];
variableList?: VariableItemType[];
welcomeText?: string;
variables: Record<string, any>;
metadata?: Record<string, any>;
};
@@ -137,7 +139,7 @@ export type ChatHistoryItemType = HistoryItemType & {
/* ------- response data ------------ */
export type ChatHistoryItemResType = DispatchNodeResponseType & {
nodeId: string;
moduleType: `${FlowNodeTypeEnum}`;
moduleType: FlowNodeTypeEnum;
moduleName: string;
};
@@ -155,6 +157,6 @@ export type ToolModuleResponseItemType = {
/* dispatch run time */
export type RuntimeUserPromptType = {
files?: UserChatItemValueItemType['file'][];
files: UserChatItemValueItemType['file'][];
text: string;
};

View File

@@ -1,7 +1,7 @@
import { DispatchNodeResponseType } from '../workflow/runtime/type';
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../workflow/node/constant';
import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { ChatItemValueTypeEnum, ChatRoleEnum } from './constants';
import { ChatHistoryItemResType, ChatItemType } from './type.d';
import { ChatHistoryItemResType, ChatItemType, UserChatItemValueItemType } from './type.d';
export const getChatTitleFromChatMessage = (message?: ChatItemType, defaultValue = '新对话') => {
// @ts-ignore
@@ -77,3 +77,15 @@ export const filterPublicNodeResponseData = ({
return obj as ChatHistoryItemResType;
});
};
export const removeEmptyUserInput = (input: UserChatItemValueItemType[]) => {
return input.filter((item) => {
if (item.type === ChatItemValueTypeEnum.text && !item.text?.content?.trim()) {
return false;
}
if (item.type === ChatItemValueTypeEnum.file && !item.file?.url) {
return false;
}
return true;
});
};

View File

@@ -11,31 +11,42 @@ export type DatasetUpdateBody = {
intro?: string;
permission?: DatasetSchemaType['permission'];
agentModel?: LLMModelItemType;
websiteConfig?: DatasetSchemaType['websiteConfig'];
status?: DatasetSchemaType['status'];
websiteConfig?: DatasetSchemaType['websiteConfig'];
externalReadUrl?: DatasetSchemaType['externalReadUrl'];
};
/* ================= collection ===================== */
export type DatasetCollectionChunkMetadataType = {
parentId?: string;
trainingType?: `${TrainingModeEnum}`;
trainingType?: TrainingModeEnum;
chunkSize?: number;
chunkSplitter?: string;
qaPrompt?: string;
metadata?: Record<string, any>;
};
// create collection params
export type CreateDatasetCollectionParams = DatasetCollectionChunkMetadataType & {
datasetId: string;
name: string;
type: `${DatasetCollectionTypeEnum}`;
type: DatasetCollectionTypeEnum;
tags?: string[];
fileId?: string;
rawLink?: string;
externalFileId?: string;
externalFileUrl?: string;
rawTextLength?: number;
hashRawText?: string;
};
export type ApiCreateDatasetCollectionParams = DatasetCollectionChunkMetadataType & {
datasetId: string;
tags?: string[];
};
export type TextCreateDatasetCollectionParams = ApiCreateDatasetCollectionParams & {
name: string;
@@ -56,6 +67,11 @@ export type CsvTableCreateDatasetCollectionParams = {
parentId?: string;
fileId: string;
};
export type ExternalFileCreateDatasetCollectionParams = ApiCreateDatasetCollectionParams & {
externalFileId?: string;
externalFileUrl: string;
filename?: string;
};
/* ================= data ===================== */
export type PgSearchRawType = {
@@ -78,7 +94,7 @@ export type PostWebsiteSyncParams = {
export type PushDatasetDataProps = {
collectionId: string;
data: PushDatasetDataChunkProps[];
trainingMode: `${TrainingModeEnum}`;
trainingMode: TrainingModeEnum;
prompt?: string;
billId?: string;
};

View File

@@ -0,0 +1,6 @@
/* sourceId = prefix-id; id=fileId;link url;externalFileId */
export enum CollectionSourcePrefixEnum {
local = 'local',
link = 'link',
external = 'external'
}

View File

@@ -0,0 +1,14 @@
import { CollectionWithDatasetType, DatasetCollectionSchemaType } from '../type';
export const getCollectionSourceData = (
collection?: CollectionWithDatasetType | DatasetCollectionSchemaType
) => {
return {
sourceId:
collection?.fileId ||
collection?.rawLink ||
collection?.externalFileId ||
collection?.externalFileUrl,
sourceName: collection?.name || ''
};
};

View File

@@ -2,23 +2,29 @@
export enum DatasetTypeEnum {
folder = 'folder',
dataset = 'dataset',
websiteDataset = 'websiteDataset' // depp link
websiteDataset = 'websiteDataset', // depp link
externalFile = 'externalFile'
}
export const DatasetTypeMap = {
[DatasetTypeEnum.folder]: {
icon: 'common/folderFill',
label: 'core.dataset.Folder Dataset',
label: 'Folder Dataset',
collectionLabel: 'common.Folder'
},
[DatasetTypeEnum.dataset]: {
icon: 'core/dataset/commonDataset',
label: 'core.dataset.Common Dataset',
label: 'Common Dataset',
collectionLabel: 'common.File'
},
[DatasetTypeEnum.websiteDataset]: {
icon: 'core/dataset/websiteDataset',
label: 'core.dataset.Website Dataset',
label: 'Website Dataset',
collectionLabel: 'common.Website'
},
[DatasetTypeEnum.externalFile]: {
icon: 'core/dataset/externalDataset',
label: 'External File',
collectionLabel: 'common.File'
}
};
@@ -38,9 +44,11 @@ export const DatasetStatusMap = {
/* ------------ collection -------------- */
export enum DatasetCollectionTypeEnum {
folder = 'folder',
virtual = 'virtual',
file = 'file',
link = 'link', // one link
virtual = 'virtual'
externalFile = 'externalFile'
}
export const DatasetCollectionTypeMap = {
[DatasetCollectionTypeEnum.folder]: {
@@ -49,6 +57,9 @@ export const DatasetCollectionTypeMap = {
[DatasetCollectionTypeEnum.file]: {
name: 'core.dataset.file'
},
[DatasetCollectionTypeEnum.externalFile]: {
name: 'core.dataset.externalFile'
},
[DatasetCollectionTypeEnum.link]: {
name: 'core.dataset.link'
},
@@ -77,7 +88,8 @@ export enum ImportDataSourceEnum {
fileLocal = 'fileLocal',
fileLink = 'fileLink',
fileCustom = 'fileCustom',
csvTable = 'csvTable'
csvTable = 'csvTable',
externalFile = 'externalFile'
}
export enum TrainingModeEnum {
@@ -163,3 +175,10 @@ export const SearchScoreTypeMap = {
export const CustomCollectionIcon = 'common/linkBlue';
export const LinkCollectionIcon = 'common/linkBlue';
/* source prefix */
export enum DatasetSourceReadTypeEnum {
fileLocal = 'fileLocal',
link = 'link',
externalFile = 'externalFile'
}

View File

@@ -0,0 +1,14 @@
import { DatasetSourceReadTypeEnum, ImportDataSourceEnum } from './constants';
export const importType2ReadType = (type: ImportDataSourceEnum) => {
if (type === ImportDataSourceEnum.csvTable || type === ImportDataSourceEnum.fileLocal) {
return DatasetSourceReadTypeEnum.fileLocal;
}
if (type === ImportDataSourceEnum.fileLink) {
return DatasetSourceReadTypeEnum.link;
}
if (type === ImportDataSourceEnum.externalFile) {
return DatasetSourceReadTypeEnum.externalFile;
}
return DatasetSourceReadTypeEnum.link;
};

View File

@@ -22,13 +22,16 @@ export type DatasetSchemaType = {
vectorModel: string;
agentModel: string;
intro: string;
type: `${DatasetTypeEnum}`;
type: DatasetTypeEnum;
status: `${DatasetStatusEnum}`;
permission: `${PermissionTypeEnum}`;
// metadata
websiteConfig?: {
url: string;
selector: string;
};
externalReadUrl?: string;
};
export type DatasetCollectionSchemaType = {
@@ -38,20 +41,24 @@ export type DatasetCollectionSchemaType = {
datasetId: string;
parentId?: string;
name: string;
type: `${DatasetCollectionTypeEnum}`;
type: DatasetCollectionTypeEnum;
createTime: Date;
updateTime: Date;
trainingType: `${TrainingModeEnum}`;
trainingType: TrainingModeEnum;
chunkSize: number;
chunkSplitter?: string;
qaPrompt?: string;
fileId?: string;
rawLink?: string;
tags?: string[];
fileId?: string; // local file id
rawLink?: string; // link url
externalFileId?: string; //external file id
rawTextLength?: number;
hashRawText?: string;
externalFileUrl?: string; // external import url
metadata?: {
webPageSelector?: string;
relatedImgId?: string; // The id of the associated image collections
@@ -80,6 +87,7 @@ export type DatasetDataSchemaType = {
a: string; // answer or custom content
fullTextToken: string;
indexes: DatasetDataIndexItemType[];
rebuilding?: boolean;
};
export type DatasetTrainingSchemaType = {
@@ -92,9 +100,10 @@ export type DatasetTrainingSchemaType = {
billId: string;
expireAt: Date;
lockTime: Date;
mode: `${TrainingModeEnum}`;
mode: TrainingModeEnum;
model: string;
prompt: string;
dataId?: string;
q: string;
a: string;
chunkIndex: number;
@@ -110,13 +119,19 @@ export type DatasetDataWithCollectionType = Omit<DatasetDataSchemaType, 'collect
};
/* ================= dataset ===================== */
export type DatasetSimpleItemType = {
_id: string;
avatar: string;
name: string;
vectorModel: VectorModelItemType;
};
export type DatasetListItemType = {
_id: string;
parentId: string;
avatar: string;
name: string;
intro: string;
type: `${DatasetTypeEnum}`;
type: DatasetTypeEnum;
isOwner: boolean;
canWrite: boolean;
permission: `${PermissionTypeEnum}`;

View File

@@ -3,7 +3,7 @@ import { getFileIcon } from '../../common/file/icon';
import { strIsLink } from '../../common/string/tools';
export function getCollectionIcon(
type: `${DatasetCollectionTypeEnum}` = DatasetCollectionTypeEnum.file,
type: DatasetCollectionTypeEnum = DatasetCollectionTypeEnum.file,
name = ''
) {
if (type === DatasetCollectionTypeEnum.folder) {
@@ -24,13 +24,13 @@ export function getSourceNameIcon({
sourceName: string;
sourceId?: string;
}) {
if (strIsLink(sourceId)) {
return 'common/linkBlue';
}
const fileIcon = getFileIcon(sourceName, '');
const fileIcon = getFileIcon(decodeURIComponent(sourceName), '');
if (fileIcon) {
return fileIcon;
}
if (strIsLink(sourceId)) {
return 'common/linkBlue';
}
return 'file/fill/manual';
}
@@ -46,7 +46,7 @@ export function getDefaultIndex(props?: { q?: string; a?: string; dataId?: strin
};
}
export const predictDataLimitLength = (mode: `${TrainingModeEnum}`, data: any[]) => {
export const predictDataLimitLength = (mode: TrainingModeEnum, data: any[]) => {
if (mode === TrainingModeEnum.qa) return data.length * 20;
if (mode === TrainingModeEnum.auto) return data.length * 5;
return data.length;

View File

@@ -52,13 +52,35 @@ export const str2OpenApiSchema = async (yamlStr = ''): Promise<OpenApiJsonSchema
})
.flat()
.filter(Boolean) as OpenApiJsonSchema['pathData'];
return { pathData, serverPath };
} catch (err) {
throw new Error('Invalid Schema');
}
};
export const getType = (schema: { type: string; items?: { type: string } }) => {
const typeMap: { [key: string]: WorkflowIOValueTypeEnum } = {
string: WorkflowIOValueTypeEnum.arrayString,
number: WorkflowIOValueTypeEnum.arrayNumber,
integer: WorkflowIOValueTypeEnum.arrayNumber,
boolean: WorkflowIOValueTypeEnum.arrayBoolean,
object: WorkflowIOValueTypeEnum.arrayObject
};
if (schema?.type === 'integer') {
return WorkflowIOValueTypeEnum.number;
}
if (schema?.type === 'array' && schema?.items) {
const itemType = typeMap[schema.items.type];
if (itemType) {
return itemType;
}
}
return schema?.type as WorkflowIOValueTypeEnum;
};
export const httpApiSchema2Plugins = async ({
parentId,
apiSchemaStr = '',
@@ -87,7 +109,7 @@ export const httpApiSchema2Plugins = async ({
...(item.params?.map((param: any) => {
return {
key: param.name,
valueType: param.schema.type,
valueType: getType(param.schema),
label: param.name,
renderTypeList: [FlowNodeInputTypeEnum.reference],
required: param.required,
@@ -109,7 +131,7 @@ export const httpApiSchema2Plugins = async ({
const prop = properties[key];
return {
key,
valueType: prop.type,
valueType: getType(prop),
label: key,
renderTypeList: [FlowNodeInputTypeEnum.reference],
required: false,
@@ -136,7 +158,7 @@ export const httpApiSchema2Plugins = async ({
return {
id,
key: param.name,
valueType: param.schema.type,
valueType: getType(param.schema),
label: param.name,
type: FlowNodeOutputTypeEnum.source
};
@@ -147,7 +169,7 @@ export const httpApiSchema2Plugins = async ({
return {
id,
key,
valueType: properties[key].type,
valueType: getType(properties[key]),
label: key,
type: FlowNodeOutputTypeEnum.source,
edit: true
@@ -159,7 +181,7 @@ export const httpApiSchema2Plugins = async ({
...(item.params?.map((param: any) => {
return {
key: param.name,
valueType: param.schema.type,
valueType: getType(param.schema),
label: param.name,
renderTypeList: [FlowNodeInputTypeEnum.reference],
canEdit: true,
@@ -173,7 +195,7 @@ export const httpApiSchema2Plugins = async ({
...(propsKeys?.map((key) => {
return {
key,
valueType: properties[key].type,
valueType: getType(properties[key]),
label: key,
renderTypeList: [FlowNodeInputTypeEnum.reference],
canEdit: true,
@@ -197,7 +219,7 @@ export const httpApiSchema2Plugins = async ({
if (param.in === 'header') {
httpNodeHeaders.push({
key: param.name,
type: param.schema?.type || WorkflowIOValueTypeEnum.string,
type: getType(param.schema) || WorkflowIOValueTypeEnum.string,
value: `{{${param.name}}}`
});
} else if (param.in === 'body') {
@@ -209,7 +231,7 @@ export const httpApiSchema2Plugins = async ({
} else if (param.in === 'query') {
httpNodeParams.push({
key: param.name,
type: param.schema?.type || WorkflowIOValueTypeEnum.string,
type: getType(param.schema) || WorkflowIOValueTypeEnum.string,
value: `{{${param.name}}}`
});
}
@@ -260,6 +282,7 @@ export const httpApiSchema2Plugins = async ({
x: 616.4226348688949,
y: -165.05298493910115
},
version: PluginInputModule.version,
inputs: pluginInputs,
outputs: pluginOutputs
},
@@ -274,6 +297,7 @@ export const httpApiSchema2Plugins = async ({
x: 1607.7142331269126,
y: -151.8669210746189
},
version: PluginOutputModule.version,
inputs: [
{
key: pluginOutputKey,
@@ -312,6 +336,7 @@ export const httpApiSchema2Plugins = async ({
x: 1042.549746602742,
y: -447.77496332641647
},
version: HttpModule468.version,
inputs: [
{
key: NodeInputKeyEnum.addInputParam,

View File

@@ -23,6 +23,7 @@ export type PluginItemSchema = {
customHeaders?: string;
};
version?: 'v1' | 'v2';
nodeVersion?: string;
};
/* plugin template */
@@ -32,6 +33,7 @@ export type PluginTemplateType = PluginRuntimeType & {
source: `${PluginSourceEnum}`;
templateType: FlowNodeTemplateType['templateType'];
intro: string;
nodeVersion: string;
};
export type PluginRuntimeType = {

View File

@@ -1,7 +1,7 @@
import { VectorModelItemType } from '../ai/model.d';
import { NodeInputKeyEnum } from './constants';
export type SelectedDatasetType = { datasetId: string; vectorModel: VectorModelItemType }[];
export type SelectedDatasetType = { datasetId: string }[];
export type HttpBodyType<T = Record<string, any>> = {
[NodeInputKeyEnum.addInputParam]: Record<string, any>;

View File

@@ -37,7 +37,6 @@ export enum NodeInputKeyEnum {
welcomeText = 'welcomeText',
switch = 'switch', // a trigger switch
history = 'history',
userChatInput = 'userChatInput',
answerText = 'text',
// system config
@@ -46,6 +45,11 @@ export enum NodeInputKeyEnum {
whisper = 'whisper',
variables = 'variables',
scheduleTrigger = 'scheduleTrigger',
chatInputGuide = 'chatInputGuide',
// entry
userChatInput = 'userChatInput',
inputFiles = 'inputFiles',
agents = 'agents', // cq agent key
@@ -101,7 +105,10 @@ export enum NodeInputKeyEnum {
// if else
condition = 'condition',
ifElseList = 'ifElseList'
ifElseList = 'ifElseList',
// variable update
updateList = 'updateList'
}
export enum NodeOutputKeyEnum {
@@ -135,15 +142,14 @@ export enum NodeOutputKeyEnum {
// plugin
pluginStart = 'pluginStart',
if = 'IF',
else = 'ELSE'
ifElseResult = 'ifElseResult'
}
export enum VariableInputEnum {
input = 'input',
textarea = 'textarea',
select = 'select',
external = 'external'
custom = 'custom'
}
export const variableMap = {
[VariableInputEnum.input]: {
@@ -161,10 +167,10 @@ export const variableMap = {
title: 'core.module.variable.select type',
desc: ''
},
[VariableInputEnum.external]: {
[VariableInputEnum.custom]: {
icon: 'core/app/variable/external',
title: 'core.module.variable.External type',
desc: '可以通过API接口或分享链接的Query传递变量。增加该类型变量的主要目的是用于变量提示。使用例子: 你可以通过分享链接Query中拼接Token来实现内部系统身份鉴权。'
title: 'core.module.variable.Custom type',
desc: '可以定义一个无需用户填写的全局变量。\n该变量的值可以来自于 API 接口,分享链接Query 或通过【变量更新】模块进行赋值。'
}
};

View File

@@ -112,7 +112,8 @@ export enum FlowNodeTypeEnum {
tools = 'tools',
stopTool = 'stopTool',
lafModule = 'lafModule',
ifElseNode = 'ifElseNode'
ifElseNode = 'ifElseNode',
variableUpdate = 'variableUpdate'
}
export const EDGE_TYPE = 'default';

View File

@@ -9,7 +9,8 @@ export enum SseResponseEventEnum {
toolCall = 'toolCall', // tool start
toolParams = 'toolParams', // tool params return
toolResponse = 'toolResponse', // tool response return
flowResponses = 'flowResponses' // sse response request
flowResponses = 'flowResponses', // sse response request
updateVariables = 'updateVariables'
}
export enum DispatchNodeResponseKeyEnum {

View File

@@ -75,7 +75,7 @@ export type DispatchNodeResponseType = {
pluginDetail?: ChatHistoryItemResType[];
// if-else
ifElseResult?: 'IF' | 'ELSE';
ifElseResult?: string;
// tool
toolCallTokens?: number;

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