Compare commits
30 Commits
v4.8.7
...
v4.8.8-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d25a1d3ec | ||
|
|
2d1e53c3b5 | ||
|
|
71d0093768 | ||
|
|
cd554f573e | ||
|
|
2d016b7462 | ||
|
|
65515e7952 | ||
|
|
5906daff9f | ||
|
|
55cefccad1 | ||
|
|
87dac54f1e | ||
|
|
45b8d7e8de | ||
|
|
a478621730 | ||
|
|
a233ab9584 | ||
|
|
8d2a192515 | ||
|
|
dcaf972767 | ||
|
|
f9d43ac009 | ||
|
|
abcf48d5ec | ||
|
|
bf5145e632 | ||
|
|
f37cdabb15 | ||
|
|
e99c91aaa6 | ||
|
|
a4787bce5c | ||
|
|
f24e41f5ec | ||
|
|
85de3c1d64 | ||
|
|
c6f682310c | ||
|
|
991398b8d2 | ||
|
|
f452554663 | ||
|
|
57ff38e16f | ||
|
|
f7b55b501f | ||
|
|
cf7145ab54 | ||
|
|
1eedb9caba | ||
|
|
6390d64417 |
3
.github/workflows/docs-deploy-kubeconfig.yml
vendored
3
.github/workflows/docs-deploy-kubeconfig.yml
vendored
@@ -16,6 +16,9 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Change baseURL
|
||||||
|
run: sed -i 's|^baseURL =.*|baseURL = "https://doc.fastgpt.cn"|g' ./docSite/hugo.toml
|
||||||
|
|
||||||
- name: Get current date and time
|
- name: Get current date and time
|
||||||
id: datetime
|
id: datetime
|
||||||
run: echo "datetime=$(date +'%Y%m%d%H%M%S')" >> "$GITHUB_OUTPUT"
|
run: echo "datetime=$(date +'%Y%m%d%H%M%S')" >> "$GITHUB_OUTPUT"
|
||||||
|
|||||||
2
.github/workflows/preview-image.yml
vendored
2
.github/workflows/preview-image.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-fastgpt-images:
|
preview-fastgpt-images:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|||||||
@@ -3,4 +3,6 @@ dist
|
|||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
docSite/
|
docSite/
|
||||||
*.md
|
*.md
|
||||||
|
|
||||||
|
cl100l_base.ts
|
||||||
46
.vscode/i18n-ally-custom-framework.yml
vendored
Normal file
46
.vscode/i18n-ally-custom-framework.yml
vendored
Normal 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})['\"`]"
|
||||||
|
- "[^\\w\\d]i18nT\\(['\"`]({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: "([^:]+):"
|
||||||
|
|
||||||
|
# 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: false
|
||||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -20,5 +20,8 @@
|
|||||||
"i18n-ally.displayLanguage": "zh", // 显示语言
|
"i18n-ally.displayLanguage": "zh", // 显示语言
|
||||||
"i18n-ally.namespace": true,
|
"i18n-ally.namespace": true,
|
||||||
"i18n-ally.pathMatcher": "{locale}/{namespaces}.json",
|
"i18n-ally.pathMatcher": "{locale}/{namespaces}.json",
|
||||||
"i18n-ally.extract.targetPickingStrategy": "most-similar-by-key"
|
"i18n-ally.extract.targetPickingStrategy": "most-similar-by-key",
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
72
dev.md
72
dev.md
@@ -23,6 +23,77 @@ pnpm dev
|
|||||||
make dev name=app
|
make dev name=app
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: If the Node version is >= 20, you need to pass the `--no-node-snapshot` parameter to Node when running `pnpm i`
|
||||||
|
|
||||||
|
```sh
|
||||||
|
NODE_OPTIONS=--no-node-snapshot pnpm i
|
||||||
|
```
|
||||||
|
|
||||||
|
## I18N
|
||||||
|
|
||||||
|
### Install i18n-ally Plugin
|
||||||
|
|
||||||
|
1. Open the Extensions Marketplace in VSCode, search for and install the `i18n Ally` plugin.
|
||||||
|
|
||||||
|
### Code Optimization Examples
|
||||||
|
|
||||||
|
#### Fetch Specific Namespace Translations in `getServerSideProps`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// pages/yourPage.tsx
|
||||||
|
export async function getServerSideProps(context: any) {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
currentTab: context?.query?.currentTab || TabEnum.info,
|
||||||
|
...(await serverSideTranslations(context.locale, ['publish', 'user']))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Use useTranslation Hook in Page
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// pages/yourPage.tsx
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
|
|
||||||
|
const YourComponent = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
mr={2}
|
||||||
|
onClick={() => setShowSelected(false)}
|
||||||
|
>
|
||||||
|
{t('common:close')}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default YourComponent;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Handle Static File Translations
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// utils/i18n.ts
|
||||||
|
import { i18nT } from '@fastgpt/web/i18n/utils';
|
||||||
|
|
||||||
|
const staticContent = {
|
||||||
|
id: 'simpleChat',
|
||||||
|
avatar: 'core/workflow/template/aiChat',
|
||||||
|
name: i18nT('app:template.simple_robot'),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default staticContent;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Standardize Translation Format
|
||||||
|
|
||||||
|
- Use the t(namespace:key) format to ensure consistent naming.
|
||||||
|
- Translation keys should use lowercase letters and underscores, e.g., common.close.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
@@ -37,4 +108,3 @@ docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/f
|
|||||||
# Make cmd: Build image with proxy
|
# Make cmd: Build image with proxy
|
||||||
make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 proxy=taobao
|
make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 proxy=taobao
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ docker-compose up -d
|
|||||||
|
|
||||||
商业版用户需要执行一个初始化,格式化团队信息。
|
商业版用户需要执行一个初始化,格式化团队信息。
|
||||||
|
|
||||||
发起 1 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 `rootkey`,{{host}} 替换成自己域名)
|
发起 1 个 HTTP 请求 ({{rootkey}} 替换成环境变量里的 `rootkey`,{{host}} 替换成商业版域名)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --location --request POST 'https://{{host}}/api/init/v468' \
|
curl --location --request POST 'https://{{host}}/api/init/v468' \
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 'V4.8.7(进行中)'
|
title: 'V4.8.7'
|
||||||
description: 'FastGPT V4.8.7 更新说明'
|
description: 'FastGPT V4.8.7 更新说明'
|
||||||
icon: 'upgrade'
|
icon: 'upgrade'
|
||||||
draft: false
|
draft: false
|
||||||
@@ -13,8 +13,8 @@ weight: 817
|
|||||||
|
|
||||||
### 2. 修改镜像
|
### 2. 修改镜像
|
||||||
|
|
||||||
- fastgpt 镜像 tag 修改成 v4.8.7-alpha
|
- fastgpt 镜像 tag 修改成 v4.8.7
|
||||||
- 商业版镜像 tag 修改成 v4.8.7-alpha
|
- 商业版镜像 tag 修改成 v4.8.7
|
||||||
|
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|||||||
49
docSite/content/zh-cn/docs/development/upgrading/488.md
Normal file
49
docSite/content/zh-cn/docs/development/upgrading/488.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
title: 'V4.8.8(进行中)'
|
||||||
|
description: 'FastGPT V4.8.8 更新说明'
|
||||||
|
icon: 'upgrade'
|
||||||
|
draft: false
|
||||||
|
toc: true
|
||||||
|
weight: 816
|
||||||
|
---
|
||||||
|
|
||||||
|
## 升级指南
|
||||||
|
|
||||||
|
### 1. 做好数据库备份
|
||||||
|
|
||||||
|
### 2. 修改镜像
|
||||||
|
|
||||||
|
- fastgpt 镜像 tag 修改成 v4.8.8-alpha
|
||||||
|
- 商业版镜像 tag 修改成 v4.8.8-alpha
|
||||||
|
|
||||||
|
### 3. 执行初始化
|
||||||
|
|
||||||
|
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`;{{host}} 替换成**FastGPT 域名**。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --location --request POST 'https://{{host}}/api/admin/initv488' \
|
||||||
|
--header 'rootkey: {{rootkey}}' \
|
||||||
|
--header 'Content-Type: application/json'
|
||||||
|
```
|
||||||
|
|
||||||
|
会初始化知识库的继承权限
|
||||||
|
|
||||||
|
-------
|
||||||
|
|
||||||
|
## V4.8.8 更新说明
|
||||||
|
|
||||||
|
1. 新增 - 重构系统插件的结构。允许向开源社区 PR 系统插件,具体可见: [如何向 FastGPT 社区提交系统插件](https://fael3z0zfze.feishu.cn/wiki/ERZnw9R26iRRG0kXZRec6WL9nwh)。
|
||||||
|
2. 新增 - DuckDuckGo 系统插件。
|
||||||
|
3. 新增 - 飞书 webhook 系统插件。
|
||||||
|
4. 新增 - 修改变量填写方式。提示词输入框以以及工作流中所有 Textarea 输入框,支持输入 / 唤起变量选择,可直接选择所有上游输出值,无需动态引入。
|
||||||
|
5. 商业版新增 - 知识库权限继承。
|
||||||
|
6. 优化 - 移动端快速切换应用交互。
|
||||||
|
7. 优化 - 节点图标。
|
||||||
|
8. 优化 - 对话框引用增加额外复制案件,便于复制。增加引用内容折叠。
|
||||||
|
9. 优化 - OpenAI sdk 升级,并自定义了 whisper 模型接口(未仔细查看 sdk 实现,但 sdk 中 whisper 接口,似乎无法适配一般 fastapi 接口)
|
||||||
|
10. 修复 - Permission 表声明问题。
|
||||||
|
11. 修复 - 并行执行节点,运行时间未正确记录。
|
||||||
|
12. 修复 - 运行详情未正确展示嵌套节点信息。
|
||||||
|
13. 修复 - 简易模式,首次进入,无法正确获取知识库配置。
|
||||||
|
14. 修复 - Log debug level 配置无效。
|
||||||
|
15. 修复 - 插件独立运行时,会将插件输入的值进行变量替换,可能导致后续节点变量异常。
|
||||||
@@ -5,6 +5,7 @@ enableEmoji = true
|
|||||||
enableGitInfo = false # N.B. .GitInfo does not currently function with git submodule content directories
|
enableGitInfo = false # N.B. .GitInfo does not currently function with git submodule content directories
|
||||||
|
|
||||||
defaultContentLanguage = 'zh-cn'
|
defaultContentLanguage = 'zh-cn'
|
||||||
|
defaultContentLanguageInSubdir = false
|
||||||
[languages]
|
[languages]
|
||||||
[languages.zh-cn]
|
[languages.zh-cn]
|
||||||
title = "FastGPT"
|
title = "FastGPT"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
<!-- change -->
|
<!-- change -->
|
||||||
{{ $repoURL = $repoURL | append "docSite/content" .Site.LanguagePrefix $filePath }}
|
{{ $repoURL = $repoURL | append "docSite/content" .Site.Language.Lang $filePath }}
|
||||||
{{ $repoURL = delimit $repoURL "/" }}
|
{{ $repoURL = delimit $repoURL "/" }}
|
||||||
{{ $editPageURL := replaceRE "(https?://)|(/)+" "$1$2" $repoURL }}
|
{{ $editPageURL := replaceRE "(https?://)|(/)+" "$1$2" $repoURL }}
|
||||||
|
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.8.6 # git
|
image: ghcr.io/labring/fastgpt:v4.8.7 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.6 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.7 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
@@ -179,7 +179,7 @@ services:
|
|||||||
- ./mysql:/var/lib/mysql
|
- ./mysql:/var/lib/mysql
|
||||||
oneapi:
|
oneapi:
|
||||||
container_name: oneapi
|
container_name: oneapi
|
||||||
image: ghcr.io/songquanpeng/one-api:latest
|
image: ghcr.io/songquanpeng/one-api:0.6.7
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/one-api:v0.6.6 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/one-api:v0.6.6 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3001:3000
|
- 3001:3000
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.8.6 # git
|
image: ghcr.io/labring/fastgpt:v4.8.7 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.6 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.7 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
@@ -136,7 +136,7 @@ services:
|
|||||||
- ./mysql:/var/lib/mysql
|
- ./mysql:/var/lib/mysql
|
||||||
oneapi:
|
oneapi:
|
||||||
container_name: oneapi
|
container_name: oneapi
|
||||||
image: ghcr.io/songquanpeng/one-api:latest
|
image: ghcr.io/songquanpeng/one-api:0.6.7
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/one-api:v0.6.6 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/one-api:v0.6.6 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3001:3000
|
- 3001:3000
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.8.6 # git
|
image: ghcr.io/labring/fastgpt:v4.8.7 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.6 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.7 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
@@ -117,7 +117,7 @@ services:
|
|||||||
- ./mysql:/var/lib/mysql
|
- ./mysql:/var/lib/mysql
|
||||||
oneapi:
|
oneapi:
|
||||||
container_name: oneapi
|
container_name: oneapi
|
||||||
image: ghcr.io/songquanpeng/one-api:latest
|
image: ghcr.io/songquanpeng/one-api:0.6.7
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/one-api:v0.6.6 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/one-api:v0.6.6 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3001:3000
|
- 3001:3000
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
"gen:theme-typings": "chakra-cli tokens packages/web/styles/theme.ts --out node_modules/.pnpm/node_modules/@chakra-ui/styled-system/dist/theming.types.d.ts",
|
"gen:theme-typings": "chakra-cli tokens packages/web/styles/theme.ts --out node_modules/.pnpm/node_modules/@chakra-ui/styled-system/dist/theming.types.d.ts",
|
||||||
"postinstall": "sh ./scripts/postinstall.sh",
|
"postinstall": "sh ./scripts/postinstall.sh",
|
||||||
"initIcon": "node ./scripts/icon/init.js",
|
"initIcon": "node ./scripts/icon/init.js",
|
||||||
"previewIcon": "node ./scripts/icon/index.js"
|
"previewIcon": "node ./scripts/icon/index.js",
|
||||||
|
"checkI18n": "node ./scripts/i18n/delete-unused-keys.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@chakra-ui/cli": "^2.4.1",
|
"@chakra-ui/cli": "^2.4.1",
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export enum DatasetErrEnum {
|
|||||||
unAuthDatasetCollection = 'unAuthDatasetCollection',
|
unAuthDatasetCollection = 'unAuthDatasetCollection',
|
||||||
unAuthDatasetData = 'unAuthDatasetData',
|
unAuthDatasetData = 'unAuthDatasetData',
|
||||||
unAuthDatasetFile = 'unAuthDatasetFile',
|
unAuthDatasetFile = 'unAuthDatasetFile',
|
||||||
|
unLinkCollection = 'unLinkCollection',
|
||||||
unLinkCollection = 'unLinkCollection'
|
invalidVectorModelOrQAModel = 'invalidVectorModelOrQAModel'
|
||||||
}
|
}
|
||||||
const datasetErr = [
|
const datasetErr = [
|
||||||
{
|
{
|
||||||
@@ -39,6 +39,10 @@ const datasetErr = [
|
|||||||
{
|
{
|
||||||
statusText: DatasetErrEnum.unLinkCollection,
|
statusText: DatasetErrEnum.unLinkCollection,
|
||||||
message: 'core.dataset.error.unLinkCollection'
|
message: 'core.dataset.error.unLinkCollection'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: DatasetErrEnum.invalidVectorModelOrQAModel,
|
||||||
|
message: 'core.dataset.error.invalidVectorModelOrQAModel'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
export default datasetErr.reduce((acc, cur, index) => {
|
export default datasetErr.reduce((acc, cur, index) => {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { ErrType } from '../errorCode';
|
|||||||
/* dataset: 506000 */
|
/* dataset: 506000 */
|
||||||
export enum OpenApiErrEnum {
|
export enum OpenApiErrEnum {
|
||||||
unExist = 'openapiUnExist',
|
unExist = 'openapiUnExist',
|
||||||
unAuth = 'openapiUnAuth'
|
unAuth = 'openapiUnAuth',
|
||||||
|
exceedLimit = 'openapiExceedLimit'
|
||||||
}
|
}
|
||||||
const errList = [
|
const errList = [
|
||||||
{
|
{
|
||||||
@@ -13,6 +14,10 @@ const errList = [
|
|||||||
{
|
{
|
||||||
statusText: OpenApiErrEnum.unAuth,
|
statusText: OpenApiErrEnum.unAuth,
|
||||||
message: '无权操作该 Api Key'
|
message: '无权操作该 Api Key'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statusText: OpenApiErrEnum.exceedLimit,
|
||||||
|
message: '最多 10 组 API 密钥'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
export default errList.reduce((acc, cur, index) => {
|
export default errList.reduce((acc, cur, index) => {
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ const commonSplit = (props: SplitProps): SplitResponse => {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCustomSteep = checkIsCustomStep(step);
|
const isCustomStep = checkIsCustomStep(step);
|
||||||
const isMarkdownSplit = checkIsMarkdownSplit(step);
|
const isMarkdownSplit = checkIsMarkdownSplit(step);
|
||||||
const independentChunk = checkIndependentChunk(step);
|
const independentChunk = checkIndependentChunk(step);
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ const commonSplit = (props: SplitProps): SplitResponse => {
|
|||||||
.replace(
|
.replace(
|
||||||
reg,
|
reg,
|
||||||
(() => {
|
(() => {
|
||||||
if (isCustomSteep) return splitMarker;
|
if (isCustomStep) return splitMarker;
|
||||||
if (independentChunk) return `${splitMarker}$1`;
|
if (independentChunk) return `${splitMarker}$1`;
|
||||||
return `$1${splitMarker}`;
|
return `$1${splitMarker}`;
|
||||||
})()
|
})()
|
||||||
|
|||||||
@@ -32,9 +32,12 @@ export type FastGPTFeConfigsType = {
|
|||||||
show_promotion?: boolean;
|
show_promotion?: boolean;
|
||||||
show_team_chat?: boolean;
|
show_team_chat?: boolean;
|
||||||
concatMd?: string;
|
concatMd?: string;
|
||||||
|
|
||||||
docUrl?: string;
|
docUrl?: string;
|
||||||
chatbotUrl?: string;
|
chatbotUrl?: string;
|
||||||
openAPIDocUrl?: string;
|
openAPIDocUrl?: string;
|
||||||
|
systemPluginCourseUrl?: string;
|
||||||
|
|
||||||
systemTitle?: string;
|
systemTitle?: string;
|
||||||
systemDescription?: string;
|
systemDescription?: string;
|
||||||
googleClientVerKey?: string;
|
googleClientVerKey?: string;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import type { LLMModelItemType, VectorModelItemType } from './model.d';
|
|||||||
|
|
||||||
export const defaultQAModels: LLMModelItemType[] = [
|
export const defaultQAModels: LLMModelItemType[] = [
|
||||||
{
|
{
|
||||||
model: 'gpt-3.5-turbo',
|
model: 'gpt-4o-mini',
|
||||||
name: 'gpt-3.5-turbo',
|
name: 'gpt-4o-mini',
|
||||||
maxContext: 16000,
|
maxContext: 16000,
|
||||||
maxResponse: 16000,
|
maxResponse: 16000,
|
||||||
quoteMaxToken: 13000,
|
quoteMaxToken: 13000,
|
||||||
|
|||||||
@@ -6,27 +6,29 @@ import { getAppChatConfig } from '../workflow/utils';
|
|||||||
import { StoreNodeItemType } from '../workflow/type/node';
|
import { StoreNodeItemType } from '../workflow/type/node';
|
||||||
import { DatasetSearchModeEnum } from '../dataset/constants';
|
import { DatasetSearchModeEnum } from '../dataset/constants';
|
||||||
|
|
||||||
export const getDefaultAppForm = (): AppSimpleEditFormType => ({
|
export const getDefaultAppForm = (): AppSimpleEditFormType => {
|
||||||
aiSettings: {
|
return {
|
||||||
model: 'gpt-3.5-turbo',
|
aiSettings: {
|
||||||
systemPrompt: '',
|
model: 'gpt-4o-mini',
|
||||||
temperature: 0,
|
systemPrompt: '',
|
||||||
isResponseAnswerText: true,
|
temperature: 0,
|
||||||
maxHistories: 6,
|
isResponseAnswerText: true,
|
||||||
maxToken: 4000
|
maxHistories: 6,
|
||||||
},
|
maxToken: 4000
|
||||||
dataset: {
|
},
|
||||||
datasets: [],
|
dataset: {
|
||||||
similarity: 0.4,
|
datasets: [],
|
||||||
limit: 1500,
|
similarity: 0.4,
|
||||||
searchMode: DatasetSearchModeEnum.embedding,
|
limit: 1500,
|
||||||
usingReRank: false,
|
searchMode: DatasetSearchModeEnum.embedding,
|
||||||
datasetSearchUsingExtensionQuery: false,
|
usingReRank: false,
|
||||||
datasetSearchExtensionBg: ''
|
datasetSearchUsingExtensionQuery: true,
|
||||||
},
|
datasetSearchExtensionBg: ''
|
||||||
selectedTools: [],
|
},
|
||||||
chatConfig: {}
|
selectedTools: [],
|
||||||
});
|
chatConfig: {}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/* format app nodes to edit form */
|
/* format app nodes to edit form */
|
||||||
export const appWorkflow2Form = ({
|
export const appWorkflow2Form = ({
|
||||||
|
|||||||
1
packages/global/core/dataset/api.d.ts
vendored
1
packages/global/core/dataset/api.d.ts
vendored
@@ -10,7 +10,6 @@ export type DatasetUpdateBody = {
|
|||||||
name?: string;
|
name?: string;
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
intro?: string;
|
intro?: string;
|
||||||
permission?: DatasetSchemaType['permission']; // TODO: Should be deleted.
|
|
||||||
agentModel?: LLMModelItemType;
|
agentModel?: LLMModelItemType;
|
||||||
status?: DatasetSchemaType['status'];
|
status?: DatasetSchemaType['status'];
|
||||||
|
|
||||||
|
|||||||
@@ -8,22 +8,22 @@ export enum DatasetTypeEnum {
|
|||||||
export const DatasetTypeMap = {
|
export const DatasetTypeMap = {
|
||||||
[DatasetTypeEnum.folder]: {
|
[DatasetTypeEnum.folder]: {
|
||||||
icon: 'common/folderFill',
|
icon: 'common/folderFill',
|
||||||
label: 'Folder Dataset',
|
label: 'folder_dataset',
|
||||||
collectionLabel: 'common.Folder'
|
collectionLabel: 'common.Folder'
|
||||||
},
|
},
|
||||||
[DatasetTypeEnum.dataset]: {
|
[DatasetTypeEnum.dataset]: {
|
||||||
icon: 'core/dataset/commonDataset',
|
icon: 'core/dataset/commonDataset',
|
||||||
label: 'Common Dataset',
|
label: 'common_dataset',
|
||||||
collectionLabel: 'common.File'
|
collectionLabel: 'common.File'
|
||||||
},
|
},
|
||||||
[DatasetTypeEnum.websiteDataset]: {
|
[DatasetTypeEnum.websiteDataset]: {
|
||||||
icon: 'core/dataset/websiteDataset',
|
icon: 'core/dataset/websiteDataset',
|
||||||
label: 'Website Dataset',
|
label: 'website_dataset',
|
||||||
collectionLabel: 'common.Website'
|
collectionLabel: 'common.Website'
|
||||||
},
|
},
|
||||||
[DatasetTypeEnum.externalFile]: {
|
[DatasetTypeEnum.externalFile]: {
|
||||||
icon: 'core/dataset/externalDataset',
|
icon: 'core/dataset/externalDataset',
|
||||||
label: 'External File',
|
label: 'external_file',
|
||||||
collectionLabel: 'common.File'
|
collectionLabel: 'common.File'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
21
packages/global/core/dataset/type.d.ts
vendored
21
packages/global/core/dataset/type.d.ts
vendored
@@ -1,4 +1,4 @@
|
|||||||
import { PermissionValueType } from 'support/permission/type';
|
import { PermissionSchemaType } from '../../support/permission/type';
|
||||||
import type { LLMModelItemType, VectorModelItemType } from '../../core/ai/model.d';
|
import type { LLMModelItemType, VectorModelItemType } from '../../core/ai/model.d';
|
||||||
import { PermissionTypeEnum } from '../../support/permission/constant';
|
import { PermissionTypeEnum } from '../../support/permission/constant';
|
||||||
import { PushDatasetDataChunkProps } from './api';
|
import { PushDatasetDataChunkProps } from './api';
|
||||||
@@ -12,31 +12,28 @@ import {
|
|||||||
import { DatasetPermission } from '../../support/permission/dataset/controller';
|
import { DatasetPermission } from '../../support/permission/dataset/controller';
|
||||||
import { Permission } from '../../support/permission/controller';
|
import { Permission } from '../../support/permission/controller';
|
||||||
|
|
||||||
/* schema */
|
|
||||||
export type DatasetSchemaType = {
|
export type DatasetSchemaType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
parentId: string;
|
parentId?: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
tmbId: string;
|
tmbId: string;
|
||||||
updateTime: Date;
|
updateTime: Date;
|
||||||
|
|
||||||
avatar: string;
|
avatar: string;
|
||||||
name: string;
|
name: string;
|
||||||
vectorModel: string;
|
vectorModel: string;
|
||||||
agentModel: string;
|
agentModel: string;
|
||||||
intro: string;
|
intro: string;
|
||||||
type: DatasetTypeEnum;
|
type: `${DatasetTypeEnum}`;
|
||||||
status: `${DatasetStatusEnum}`;
|
status: `${DatasetStatusEnum}`;
|
||||||
// permission: DatasetPermission;
|
|
||||||
|
|
||||||
// metadata
|
|
||||||
websiteConfig?: {
|
websiteConfig?: {
|
||||||
url: string;
|
url: string;
|
||||||
selector: string;
|
selector: string;
|
||||||
};
|
};
|
||||||
externalReadUrl?: string;
|
externalReadUrl?: string;
|
||||||
defaultPermission: PermissionValueType;
|
} & PermissionSchemaType;
|
||||||
};
|
// } & PermissionSchemaType;
|
||||||
|
|
||||||
export type DatasetCollectionSchemaType = {
|
export type DatasetCollectionSchemaType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
@@ -133,15 +130,13 @@ export type DatasetSimpleItemType = {
|
|||||||
};
|
};
|
||||||
export type DatasetListItemType = {
|
export type DatasetListItemType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
parentId: string;
|
|
||||||
avatar: string;
|
avatar: string;
|
||||||
name: string;
|
name: string;
|
||||||
intro: string;
|
intro: string;
|
||||||
type: DatasetTypeEnum;
|
type: `${DatasetTypeEnum}`;
|
||||||
permission: DatasetPermission;
|
permission: DatasetPermission;
|
||||||
vectorModel: VectorModelItemType;
|
vectorModel: VectorModelItemType;
|
||||||
defaultPermission: PermissionValueType;
|
} & PermissionSchemaType;
|
||||||
};
|
|
||||||
|
|
||||||
export type DatasetItemType = Omit<DatasetSchemaType, 'vectorModel' | 'agentModel'> & {
|
export type DatasetItemType = Omit<DatasetSchemaType, 'vectorModel' | 'agentModel'> & {
|
||||||
vectorModel: VectorModelItemType;
|
vectorModel: VectorModelItemType;
|
||||||
|
|||||||
2
packages/global/core/plugin/type.d.ts
vendored
2
packages/global/core/plugin/type.d.ts
vendored
@@ -32,7 +32,7 @@ export type PluginItemSchema = {
|
|||||||
export type PluginTemplateType = PluginRuntimeType & {
|
export type PluginTemplateType = PluginRuntimeType & {
|
||||||
author?: string;
|
author?: string;
|
||||||
id: string;
|
id: string;
|
||||||
source: `${PluginSourceEnum}`;
|
source: PluginSourceEnum;
|
||||||
templateType: FlowNodeTemplateType['templateType'];
|
templateType: FlowNodeTemplateType['templateType'];
|
||||||
intro: string;
|
intro: string;
|
||||||
version: string;
|
version: string;
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ export enum FlowNodeTemplateTypeEnum {
|
|||||||
function = 'function',
|
function = 'function',
|
||||||
tools = 'tools',
|
tools = 'tools',
|
||||||
|
|
||||||
|
search = 'search',
|
||||||
|
multimodal = 'multimodal',
|
||||||
|
communication = 'communication',
|
||||||
|
|
||||||
other = 'other',
|
other = 'other',
|
||||||
teamApp = 'teamApp'
|
teamApp = 'teamApp'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,11 +67,12 @@ export type RuntimeNodeItemType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type PluginRuntimeType = {
|
export type PluginRuntimeType = {
|
||||||
|
id: string;
|
||||||
teamId?: string;
|
teamId?: string;
|
||||||
name: string;
|
name: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
showStatus?: boolean;
|
showStatus?: boolean;
|
||||||
isTool?: boolean;
|
currentCost?: number;
|
||||||
nodes: StoreNodeItemType[];
|
nodes: StoreNodeItemType[];
|
||||||
edges: StoreEdgeItemType[];
|
edges: StoreEdgeItemType[];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const AiChatModule: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.chatNode,
|
flowNodeType: FlowNodeTypeEnum.chatNode,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/AI.png',
|
avatar: 'core/workflow/template/aiChat',
|
||||||
name: 'AI 对话',
|
name: 'AI 对话',
|
||||||
intro: 'AI 大模型对话',
|
intro: 'AI 大模型对话',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const AssignedAnswerModule: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.answerNode,
|
flowNodeType: FlowNodeTypeEnum.answerNode,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/reply.png',
|
avatar: 'core/workflow/template/reply',
|
||||||
name: '指定回复',
|
name: '指定回复',
|
||||||
intro:
|
intro:
|
||||||
'该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。',
|
'该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。',
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.classifyQuestion,
|
flowNodeType: FlowNodeTypeEnum.classifyQuestion,
|
||||||
sourceHandle: getHandleConfig(false, false, false, false),
|
sourceHandle: getHandleConfig(false, false, false, false),
|
||||||
targetHandle: getHandleConfig(true, false, true, true),
|
targetHandle: getHandleConfig(true, false, true, true),
|
||||||
avatar: '/imgs/workflow/cq.png',
|
avatar: 'core/workflow/template/questionClassify',
|
||||||
name: '问题分类',
|
name: '问题分类',
|
||||||
intro: `根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题`,
|
intro: `根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题`,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const ContextExtractModule: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.contentExtract,
|
flowNodeType: FlowNodeTypeEnum.contentExtract,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/extract.png',
|
avatar: 'core/workflow/template/extractJson',
|
||||||
name: '文本内容提取',
|
name: '文本内容提取',
|
||||||
intro: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等',
|
intro: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const CustomFeedbackNode: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.customFeedback,
|
flowNodeType: FlowNodeTypeEnum.customFeedback,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/customFeedback.svg',
|
avatar: 'core/workflow/template/customFeedback',
|
||||||
name: '自定义反馈',
|
name: '自定义反馈',
|
||||||
intro: '该模块被触发时,会给当前的对话记录增加一条反馈。可用于自动记录对话效果等。',
|
intro: '该模块被触发时,会给当前的对话记录增加一条反馈。可用于自动记录对话效果等。',
|
||||||
version: '486',
|
version: '486',
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
|
|||||||
templateType: FlowNodeTemplateTypeEnum.other,
|
templateType: FlowNodeTemplateTypeEnum.other,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/concat.svg',
|
avatar: 'core/workflow/template/datasetConcat',
|
||||||
name: '知识库搜索引用合并',
|
name: '知识库搜索引用合并',
|
||||||
intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。',
|
intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
|
flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/db.png',
|
avatar: 'core/workflow/template/datasetSearch',
|
||||||
name: '知识库搜索',
|
name: '知识库搜索',
|
||||||
intro: Dataset_SEARCH_DESC,
|
intro: Dataset_SEARCH_DESC,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const HttpNode468: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.httpRequest468,
|
flowNodeType: FlowNodeTypeEnum.httpRequest468,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/http.png',
|
avatar: 'core/workflow/template/httpRequest',
|
||||||
name: 'HTTP 请求',
|
name: 'HTTP 请求',
|
||||||
intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
|
intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const IfElseNode: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.ifElseNode,
|
flowNodeType: FlowNodeTypeEnum.ifElseNode,
|
||||||
sourceHandle: getHandleConfig(false, false, false, false),
|
sourceHandle: getHandleConfig(false, false, false, false),
|
||||||
targetHandle: getHandleConfig(true, false, true, true),
|
targetHandle: getHandleConfig(true, false, true, true),
|
||||||
avatar: '/imgs/workflow/ifElse.svg',
|
avatar: 'core/workflow/template/ifelse',
|
||||||
name: '判断器',
|
name: '判断器',
|
||||||
intro: '根据一定的条件,执行不同的分支。',
|
intro: '根据一定的条件,执行不同的分支。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const LafModule: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.lafModule,
|
flowNodeType: FlowNodeTypeEnum.lafModule,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/laf.png',
|
avatar: 'core/workflow/template/lafDispatch',
|
||||||
name: 'Laf 函数调用(测试)',
|
name: 'Laf 函数调用(测试)',
|
||||||
intro: '可以调用Laf账号下的云函数。',
|
intro: '可以调用Laf账号下的云函数。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const PluginInputModule: FlowNodeTemplateType = {
|
|||||||
targetHandle: getHandleConfig(false, false, false, false),
|
targetHandle: getHandleConfig(false, false, false, false),
|
||||||
unique: true,
|
unique: true,
|
||||||
forbidDelete: true,
|
forbidDelete: true,
|
||||||
avatar: '/imgs/workflow/input.png',
|
avatar: 'core/workflow/template/workflowStart',
|
||||||
name: '插件输入',
|
name: '插件输入',
|
||||||
intro: '可以配置插件需要哪些输入,利用这些输入来运行插件',
|
intro: '可以配置插件需要哪些输入,利用这些输入来运行插件',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const PluginOutputModule: FlowNodeTemplateType = {
|
|||||||
targetHandle: getHandleConfig(false, false, false, true),
|
targetHandle: getHandleConfig(false, false, false, true),
|
||||||
unique: true,
|
unique: true,
|
||||||
forbidDelete: true,
|
forbidDelete: true,
|
||||||
avatar: '/imgs/workflow/output.png',
|
avatar: 'core/workflow/template/pluginOutput',
|
||||||
name: '自定义插件输出',
|
name: '自定义插件输出',
|
||||||
intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出',
|
intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const AiQueryExtension: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.queryExtension,
|
flowNodeType: FlowNodeTypeEnum.queryExtension,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/cfr.svg',
|
avatar: 'core/workflow/template/queryExtension',
|
||||||
name: '问题优化',
|
name: '问题优化',
|
||||||
intro:
|
intro:
|
||||||
'使用问题优化功能,可以提高知识库连续对话时搜索的精度。使用该功能后,会先利用 AI 根据上下文构建一个或多个新的检索词,这些检索词更利于进行知识库搜索。该模块已内置在知识库搜索模块中,如果您仅进行一次知识库搜索,可直接使用知识库内置的补全功能。',
|
'使用问题优化功能,可以提高知识库连续对话时搜索的精度。使用该功能后,会先利用 AI 根据上下文构建一个或多个新的检索词,这些检索词更利于进行知识库搜索。该模块已内置在知识库搜索模块中,如果您仅进行一次知识库搜索,可直接使用知识库内置的补全功能。',
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const RunAppModule: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.runApp,
|
flowNodeType: FlowNodeTypeEnum.runApp,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/app.png',
|
avatar: 'core/workflow/template/runApp',
|
||||||
name: '应用调用',
|
name: '应用调用',
|
||||||
intro: '可以选择一个其他应用进行调用',
|
intro: '可以选择一个其他应用进行调用',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const CodeNode: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.code,
|
flowNodeType: FlowNodeTypeEnum.code,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/code.svg',
|
avatar: 'core/workflow/template/codeRun',
|
||||||
name: '代码运行',
|
name: '代码运行',
|
||||||
intro: '执行一段简单的脚本代码,通常用于进行复杂的数据处理。',
|
intro: '执行一段简单的脚本代码,通常用于进行复杂的数据处理。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const StopToolNode: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.stopTool,
|
flowNodeType: FlowNodeTypeEnum.stopTool,
|
||||||
sourceHandle: getHandleConfig(false, false, false, false),
|
sourceHandle: getHandleConfig(false, false, false, false),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/toolStop.svg',
|
avatar: 'core/workflow/template/stopTool',
|
||||||
name: '工具调用终止',
|
name: '工具调用终止',
|
||||||
intro:
|
intro:
|
||||||
'该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。',
|
'该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。',
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const SystemConfigNode: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.systemConfig,
|
flowNodeType: FlowNodeTypeEnum.systemConfig,
|
||||||
sourceHandle: getHandleConfig(false, false, false, false),
|
sourceHandle: getHandleConfig(false, false, false, false),
|
||||||
targetHandle: getHandleConfig(false, false, false, false),
|
targetHandle: getHandleConfig(false, false, false, false),
|
||||||
avatar: '/imgs/workflow/userGuide.png',
|
avatar: 'core/workflow/template/systemConfig',
|
||||||
name: '系统配置',
|
name: '系统配置',
|
||||||
intro: '可以配置应用的系统参数。',
|
intro: '可以配置应用的系统参数。',
|
||||||
unique: true,
|
unique: true,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const TextEditorNode: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.textEditor,
|
flowNodeType: FlowNodeTypeEnum.textEditor,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/textEditor.svg',
|
avatar: 'core/workflow/template/textConcat',
|
||||||
name: '文本拼接',
|
name: '文本拼接',
|
||||||
intro: '可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。',
|
intro: '可对固定或传入的文本进行加工后输出,非字符串类型数据最终会转成字符串类型。',
|
||||||
version: '486',
|
version: '486',
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const ToolModule: FlowNodeTemplateType = {
|
|||||||
templateType: FlowNodeTemplateTypeEnum.ai,
|
templateType: FlowNodeTemplateTypeEnum.ai,
|
||||||
sourceHandle: getHandleConfig(true, true, false, true),
|
sourceHandle: getHandleConfig(true, true, false, true),
|
||||||
targetHandle: getHandleConfig(true, true, false, true),
|
targetHandle: getHandleConfig(true, true, false, true),
|
||||||
avatar: '/imgs/workflow/tool.svg',
|
avatar: 'core/workflow/template/toolCall',
|
||||||
name: '工具调用',
|
name: '工具调用',
|
||||||
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.variableUpdate,
|
flowNodeType: FlowNodeTypeEnum.variableUpdate,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
avatar: '/imgs/workflow/variable.png',
|
avatar: 'core/workflow/template/variableUpdate',
|
||||||
name: '变量更新',
|
name: '变量更新',
|
||||||
intro: '可以更新指定节点的输出值或更新全局变量',
|
intro: '可以更新指定节点的输出值或更新全局变量',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const WorkflowStart: FlowNodeTemplateType = {
|
|||||||
flowNodeType: FlowNodeTypeEnum.workflowStart,
|
flowNodeType: FlowNodeTypeEnum.workflowStart,
|
||||||
sourceHandle: getHandleConfig(false, true, false, false),
|
sourceHandle: getHandleConfig(false, true, false, false),
|
||||||
targetHandle: getHandleConfig(false, false, false, false),
|
targetHandle: getHandleConfig(false, false, false, false),
|
||||||
avatar: '/imgs/workflow/userChatInput.svg',
|
avatar: 'core/workflow/template/workflowStart',
|
||||||
name: '流程开始',
|
name: '流程开始',
|
||||||
intro: '',
|
intro: '',
|
||||||
forbidDelete: true,
|
forbidDelete: true,
|
||||||
|
|||||||
13
packages/global/core/workflow/type/index.d.ts
vendored
13
packages/global/core/workflow/type/index.d.ts
vendored
@@ -35,6 +35,7 @@ export type WorkflowTemplateType = {
|
|||||||
avatar: string;
|
avatar: string;
|
||||||
intro?: string;
|
intro?: string;
|
||||||
author?: string;
|
author?: string;
|
||||||
|
inputExplanationUrl?: string;
|
||||||
version: string;
|
version: string;
|
||||||
|
|
||||||
showStatus?: boolean;
|
showStatus?: boolean;
|
||||||
@@ -42,17 +43,29 @@ export type WorkflowTemplateType = {
|
|||||||
|
|
||||||
workflow: WorkflowTemplateBasicType;
|
workflow: WorkflowTemplateBasicType;
|
||||||
};
|
};
|
||||||
|
|
||||||
// template market
|
// template market
|
||||||
export type TemplateMarketItemType = WorkflowTemplateType & {
|
export type TemplateMarketItemType = WorkflowTemplateType & {
|
||||||
tags?: { id: string; label: string }[];
|
tags?: { id: string; label: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// system plugin
|
// system plugin
|
||||||
export type SystemPluginTemplateItemType = WorkflowTemplateType & {
|
export type SystemPluginTemplateItemType = WorkflowTemplateType & {
|
||||||
templateType: FlowNodeTemplateTypeEnum;
|
templateType: FlowNodeTemplateTypeEnum;
|
||||||
isTool?: boolean;
|
isTool?: boolean;
|
||||||
|
|
||||||
|
// commercial plugin config
|
||||||
originCost: number; // n points/one time
|
originCost: number; // n points/one time
|
||||||
currentCost: number;
|
currentCost: number;
|
||||||
|
|
||||||
|
isActive?: boolean;
|
||||||
|
inputConfig?: {
|
||||||
|
// Render config input form. Find the corresponding node and replace the variable directly
|
||||||
|
key: string;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
value?: any;
|
||||||
|
}[];
|
||||||
|
|
||||||
workflow: WorkflowTemplateBasicType;
|
workflow: WorkflowTemplateBasicType;
|
||||||
};
|
};
|
||||||
|
|||||||
4
packages/global/core/workflow/type/node.d.ts
vendored
4
packages/global/core/workflow/type/node.d.ts
vendored
@@ -31,6 +31,7 @@ export type FlowNodeCommonType = {
|
|||||||
avatar?: string;
|
avatar?: string;
|
||||||
name: string;
|
name: string;
|
||||||
intro?: string; // template list intro
|
intro?: string; // template list intro
|
||||||
|
inputExplanationUrl?: string;
|
||||||
showStatus?: boolean; // chatting response step status
|
showStatus?: boolean; // chatting response step status
|
||||||
version: string;
|
version: string;
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ export type FlowNodeTemplateType = FlowNodeCommonType & {
|
|||||||
export type NodeTemplateListItemType = {
|
export type NodeTemplateListItemType = {
|
||||||
id: string; // 系统节点-系统节点的 id, 系统插件-插件的 id,团队应用的 id
|
id: string; // 系统节点-系统节点的 id, 系统插件-插件的 id,团队应用的 id
|
||||||
flowNodeType: FlowNodeTypeEnum; // render node card
|
flowNodeType: FlowNodeTypeEnum; // render node card
|
||||||
parentId?: string;
|
parentId?: ParentIdType;
|
||||||
isFolder?: boolean;
|
isFolder?: boolean;
|
||||||
templateType: FlowNodeTemplateTypeEnum;
|
templateType: FlowNodeTemplateTypeEnum;
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
@@ -79,6 +80,7 @@ export type NodeTemplateListItemType = {
|
|||||||
isTool?: boolean;
|
isTool?: boolean;
|
||||||
author?: string;
|
author?: string;
|
||||||
unique?: boolean; // 唯一的
|
unique?: boolean; // 唯一的
|
||||||
|
currentCost?: number; // 当前积分消耗
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NodeTemplateListType = {
|
export type NodeTemplateListType = {
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import {
|
|||||||
WorkflowIOValueTypeEnum,
|
WorkflowIOValueTypeEnum,
|
||||||
NodeInputKeyEnum,
|
NodeInputKeyEnum,
|
||||||
VariableInputEnum,
|
VariableInputEnum,
|
||||||
variableMap
|
variableMap,
|
||||||
|
VARIABLE_NODE_ID
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { FlowNodeInputItemType, FlowNodeOutputItemType } from './type/io.d';
|
import { FlowNodeInputItemType, FlowNodeOutputItemType, ReferenceValueProps } from './type/io.d';
|
||||||
import { StoreNodeItemType } from './type/node';
|
import { StoreNodeItemType } from './type/node';
|
||||||
import type {
|
import type {
|
||||||
VariableItemType,
|
VariableItemType,
|
||||||
@@ -23,6 +24,7 @@ import {
|
|||||||
} from '../app/constants';
|
} from '../app/constants';
|
||||||
import { IfElseResultEnum } from './template/system/ifElse/constant';
|
import { IfElseResultEnum } from './template/system/ifElse/constant';
|
||||||
import { RuntimeNodeItemType } from './runtime/type';
|
import { RuntimeNodeItemType } from './runtime/type';
|
||||||
|
import { getReferenceVariableValue } from './runtime/utils';
|
||||||
|
|
||||||
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
|
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
|
||||||
return `${nodeId}-${type}-${key}`;
|
return `${nodeId}-${type}-${key}`;
|
||||||
@@ -226,3 +228,90 @@ export const updatePluginInputByVariables = (
|
|||||||
: node
|
: node
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const removePluginInputVariables = (
|
||||||
|
variables: Record<string, any>,
|
||||||
|
nodes: RuntimeNodeItemType[]
|
||||||
|
) => {
|
||||||
|
const pluginInputNode = nodes.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput);
|
||||||
|
|
||||||
|
if (!pluginInputNode) return variables;
|
||||||
|
return Object.keys(variables).reduce(
|
||||||
|
(acc, key) => {
|
||||||
|
if (!pluginInputNode.inputs.find((input) => input.key === key)) {
|
||||||
|
acc[key] = variables[key];
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<string, any>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function replaceVariableLabel({
|
||||||
|
text,
|
||||||
|
nodes,
|
||||||
|
variables,
|
||||||
|
runningNode
|
||||||
|
}: {
|
||||||
|
text: any;
|
||||||
|
nodes: RuntimeNodeItemType[];
|
||||||
|
variables: Record<string, string | number>;
|
||||||
|
runningNode: RuntimeNodeItemType;
|
||||||
|
}) {
|
||||||
|
if (typeof text !== 'string') return text;
|
||||||
|
|
||||||
|
const globalVariables = Object.keys(variables).map((key) => {
|
||||||
|
return {
|
||||||
|
nodeId: VARIABLE_NODE_ID,
|
||||||
|
id: key,
|
||||||
|
value: variables[key]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Upstream node outputs
|
||||||
|
const nodeVariables = nodes
|
||||||
|
.map((node) => {
|
||||||
|
return node.outputs.map((output) => {
|
||||||
|
return {
|
||||||
|
nodeId: node.nodeId,
|
||||||
|
id: output.id,
|
||||||
|
value: output.value
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
// Get runningNode inputs(Will be replaced with reference)
|
||||||
|
const customInputs = runningNode.inputs.flatMap((item) => {
|
||||||
|
if (Array.isArray(item.value)) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: item.key,
|
||||||
|
value: getReferenceVariableValue({
|
||||||
|
value: item.value as ReferenceValueProps,
|
||||||
|
nodes,
|
||||||
|
variables
|
||||||
|
}),
|
||||||
|
nodeId: runningNode.nodeId
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
const allVariables = [...globalVariables, ...nodeVariables, ...customInputs];
|
||||||
|
|
||||||
|
// Replace {{$xxx.xxx$}} to value
|
||||||
|
for (const key in allVariables) {
|
||||||
|
const val = allVariables[key];
|
||||||
|
const regex = new RegExp(`\\{\\{\\$(${val.nodeId}\\.${val.id})\\$\\}\\}`, 'g');
|
||||||
|
if (['string', 'number'].includes(typeof val.value)) {
|
||||||
|
text = text.replace(regex, String(val.value));
|
||||||
|
} else if (['object'].includes(typeof val.value)) {
|
||||||
|
text = text.replace(regex, JSON.stringify(val.value));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text || '';
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"jschardet": "3.1.1",
|
"jschardet": "3.1.1",
|
||||||
"nanoid": "^4.0.1",
|
"nanoid": "^4.0.1",
|
||||||
"next": "14.2.5",
|
"next": "14.2.5",
|
||||||
"openai": "4.28.0",
|
"openai": "4.53.0",
|
||||||
"openapi-types": "^12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
"timezones-list": "^3.0.2"
|
"timezones-list": "^3.0.2"
|
||||||
},
|
},
|
||||||
|
|||||||
14
packages/global/support/permission/type.d.ts
vendored
14
packages/global/support/permission/type.d.ts
vendored
@@ -1,11 +1,13 @@
|
|||||||
import { TeamMemberWithUserSchema } from '../user/team/type';
|
import { TeamMemberWithUserSchema } from '../user/team/type';
|
||||||
import { AuthUserTypeEnum, PermissionKeyEnum } from './constant';
|
import { AuthUserTypeEnum, PermissionKeyEnum, PerResourceTypeEnum } from './constant';
|
||||||
|
|
||||||
// PermissionValueType, the type of permission's value is a number, which is a bit field actually.
|
// PermissionValueType, the type of permission's value is a number, which is a bit field actually.
|
||||||
// It is spired by the permission system in Linux.
|
// It is spired by the permission system in Linux.
|
||||||
// The lowest 3 bits present the permission of reading, writing and managing.
|
// The lowest 3 bits present the permission of reading, writing and managing.
|
||||||
// The higher bits are advanced permissions or extended permissions, which could be customized.
|
// The higher bits are advanced permissions or extended permissions, which could be customized.
|
||||||
export type PermissionValueType = number;
|
export type PermissionValueType = number;
|
||||||
|
export type ResourceType = `${PerResourceTypeEnum}`;
|
||||||
|
|
||||||
export type PermissionListType<T = {}> = Record<
|
export type PermissionListType<T = {}> = Record<
|
||||||
T | PermissionKeyEnum,
|
T | PermissionKeyEnum,
|
||||||
{
|
{
|
||||||
@@ -16,16 +18,6 @@ export type PermissionListType<T = {}> = Record<
|
|||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type AuthResponseType = {
|
|
||||||
teamId: string;
|
|
||||||
tmbId: string;
|
|
||||||
isOwner: boolean;
|
|
||||||
canWrite: boolean;
|
|
||||||
authType?: `${AuthUserTypeEnum}`;
|
|
||||||
appId?: string;
|
|
||||||
apikey?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ResourcePermissionType = {
|
export type ResourcePermissionType = {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
tmbId: string;
|
tmbId: string;
|
||||||
|
|||||||
@@ -3,22 +3,13 @@ export const TeamMemberCollectionName = 'team_members';
|
|||||||
export const TeamTagsCollectionName = 'team_tags';
|
export const TeamTagsCollectionName = 'team_tags';
|
||||||
|
|
||||||
export enum TeamMemberRoleEnum {
|
export enum TeamMemberRoleEnum {
|
||||||
owner = 'owner',
|
owner = 'owner'
|
||||||
admin = 'admin',
|
|
||||||
visitor = 'visitor'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TeamMemberRoleMap = {
|
export const TeamMemberRoleMap = {
|
||||||
[TeamMemberRoleEnum.owner]: {
|
[TeamMemberRoleEnum.owner]: {
|
||||||
value: TeamMemberRoleEnum.owner,
|
value: TeamMemberRoleEnum.owner,
|
||||||
label: 'user.team.role.Owner'
|
label: 'user.team.role.Owner'
|
||||||
},
|
|
||||||
[TeamMemberRoleEnum.admin]: {
|
|
||||||
value: TeamMemberRoleEnum.admin,
|
|
||||||
label: 'user.team.role.Admin'
|
|
||||||
},
|
|
||||||
[TeamMemberRoleEnum.visitor]: {
|
|
||||||
value: TeamMemberRoleEnum.visitor,
|
|
||||||
label: 'user.team.role.Visitor'
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,6 +19,7 @@ export enum TeamMemberStatusEnum {
|
|||||||
reject = 'reject',
|
reject = 'reject',
|
||||||
leave = 'leave'
|
leave = 'leave'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TeamMemberStatusMap = {
|
export const TeamMemberStatusMap = {
|
||||||
[TeamMemberStatusEnum.waiting]: {
|
[TeamMemberStatusEnum.waiting]: {
|
||||||
label: 'user.team.member.waiting',
|
label: 'user.team.member.waiting',
|
||||||
@@ -46,4 +38,5 @@ export const TeamMemberStatusMap = {
|
|||||||
color: 'red.600'
|
color: 'red.600'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const notLeaveStatus = { $ne: TeamMemberStatusEnum.leave };
|
export const notLeaveStatus = { $ne: TeamMemberStatusEnum.leave };
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
"name": "@fastgpt/plugins",
|
"name": "@fastgpt/plugins",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"duck-duck-scrape": "^2.2.5",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"axios": "^1.5.1",
|
||||||
"expr-eval": "^2.0.2"
|
"expr-eval": "^2.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fastgpt/global": "workspace:*",
|
"@fastgpt/global": "workspace:*",
|
||||||
"@fastgpt/service": "workspace:*",
|
"@fastgpt/service": "workspace:*",
|
||||||
|
"@types/lodash": "^4.14.191",
|
||||||
"@types/node": "20.14.0"
|
"@types/node": "20.14.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1,143 @@
|
|||||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
|
||||||
import { SystemPluginResponseType } from './type';
|
import { SystemPluginResponseType } from './type';
|
||||||
import { NodeTemplateListItemType } from '@fastgpt/global/core/workflow/type/node';
|
import { FastGPTProUrl, isProduction } from '../service/common/system/constants';
|
||||||
import { isProduction } from '../service/common/system/constants';
|
import { GET, POST } from '@fastgpt/service/common/api/plusRequest';
|
||||||
|
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
import { WorkerNameEnum, runWorker } from '@fastgpt/service/worker/utils';
|
||||||
|
|
||||||
let list = ['getTime', 'fetchUrl', 'mathExprVal'];
|
// Run in main thread
|
||||||
|
const staticPluginList = [
|
||||||
|
'getTime',
|
||||||
|
'fetchUrl',
|
||||||
|
'Doc2X',
|
||||||
|
'Doc2X/URLPDF2text',
|
||||||
|
'Doc2X/URLImg2text',
|
||||||
|
'feishu'
|
||||||
|
];
|
||||||
|
// Run in worker thread (Have npm packages)
|
||||||
|
const packagePluginList = [
|
||||||
|
'mathExprVal',
|
||||||
|
'duckduckgo',
|
||||||
|
'duckduckgo/search',
|
||||||
|
'duckduckgo/searchImg',
|
||||||
|
'duckduckgo/searchNews',
|
||||||
|
'duckduckgo/searchVideo'
|
||||||
|
];
|
||||||
|
|
||||||
|
const list = [...staticPluginList, ...packagePluginList];
|
||||||
|
|
||||||
|
/* Get plugins */
|
||||||
export const getCommunityPlugins = () => {
|
export const getCommunityPlugins = () => {
|
||||||
if (isProduction && global.communitySystemPlugins) return global.communitySystemPlugins;
|
return list.map<SystemPluginTemplateItemType>((name) => {
|
||||||
|
const config = require(`./src/${name}/template.json`);
|
||||||
|
|
||||||
global.communitySystemPlugins = list.map((name) => ({
|
const isFolder = list.find((item) => item.startsWith(`${name}/`));
|
||||||
...require(`./src/${name}/template.json`),
|
|
||||||
id: `${PluginSourceEnum.community}-${name}`
|
|
||||||
}));
|
|
||||||
|
|
||||||
return global.communitySystemPlugins;
|
const parentIdList = name.split('/').slice(0, -1);
|
||||||
|
const parentId =
|
||||||
|
parentIdList.length > 0 ? `${PluginSourceEnum.community}-${parentIdList.join('/')}` : null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...config,
|
||||||
|
id: `${PluginSourceEnum.community}-${name}`,
|
||||||
|
isFolder,
|
||||||
|
parentId,
|
||||||
|
isActive: true
|
||||||
|
};
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
const getCommercialPlugins = () => {
|
||||||
|
return GET<SystemPluginTemplateItemType[]>('/core/app/plugin/getSystemPlugins');
|
||||||
|
};
|
||||||
|
export const getSystemPluginTemplates = async (refresh = false) => {
|
||||||
|
if (isProduction && global.systemPlugins && !refresh) return cloneDeep(global.systemPlugins);
|
||||||
|
|
||||||
export const getCommunityPluginsTemplateList = () => {
|
try {
|
||||||
return getCommunityPlugins().map<NodeTemplateListItemType>((plugin) => ({
|
if (!global.systemPlugins) {
|
||||||
id: plugin.id,
|
global.systemPlugins = [];
|
||||||
templateType: plugin.templateType ?? FlowNodeTemplateTypeEnum.other,
|
}
|
||||||
flowNodeType: FlowNodeTypeEnum.pluginModule,
|
|
||||||
avatar: plugin.avatar,
|
global.systemPlugins = FastGPTProUrl ? await getCommercialPlugins() : getCommunityPlugins();
|
||||||
name: plugin.name,
|
|
||||||
intro: plugin.intro,
|
return cloneDeep(global.systemPlugins);
|
||||||
isTool: plugin.isTool
|
} catch (error) {
|
||||||
}));
|
//@ts-ignore
|
||||||
|
global.systemPlugins = undefined;
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCommunityCb = async () => {
|
export const getCommunityCb = async () => {
|
||||||
if (isProduction && global.communitySystemPluginCb) return global.communitySystemPluginCb;
|
const loadCommunityModule = async (name: string) => {
|
||||||
|
|
||||||
// Do not modify the following code
|
|
||||||
const loadModule = async (name: string) => {
|
|
||||||
const module = await import(`./src/${name}/index`);
|
const module = await import(`./src/${name}/index`);
|
||||||
return module.default;
|
return module.default;
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await Promise.all(
|
const result = (
|
||||||
list.map(async (name) => ({
|
await Promise.all(
|
||||||
name,
|
list.map(async (name) => {
|
||||||
cb: await loadModule(name)
|
try {
|
||||||
}))
|
return {
|
||||||
|
name,
|
||||||
|
cb: staticPluginList.includes(name)
|
||||||
|
? await loadCommunityModule(name)
|
||||||
|
: (e: any) => {
|
||||||
|
return runWorker(WorkerNameEnum.systemPluginRun, {
|
||||||
|
pluginName: name,
|
||||||
|
data: e
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (error) {}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).filter(Boolean) as {
|
||||||
|
name: string;
|
||||||
|
cb: any;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
return result.reduce<Record<string, (e: any) => SystemPluginResponseType>>(
|
||||||
|
(acc, { name, cb }) => {
|
||||||
|
acc[name] = cb;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{}
|
||||||
);
|
);
|
||||||
|
};
|
||||||
global.communitySystemPluginCb = result.reduce<
|
const getCommercialCb = async () => {
|
||||||
Record<string, (e: any) => SystemPluginResponseType>
|
const plugins = await getSystemPluginTemplates();
|
||||||
>((acc, { name, cb }) => {
|
const result = plugins.map((plugin) => {
|
||||||
acc[name] = cb;
|
const name = plugin.id.split('-')[1];
|
||||||
return acc;
|
|
||||||
}, {});
|
return {
|
||||||
|
name,
|
||||||
return global.communitySystemPluginCb;
|
cb: (e: any) =>
|
||||||
|
POST<Record<string, any>>('/core/app/plugin/run', {
|
||||||
|
pluginName: name,
|
||||||
|
data: e
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return result.reduce<Record<string, (e: any) => SystemPluginResponseType>>(
|
||||||
|
(acc, { name, cb }) => {
|
||||||
|
acc[name] = cb;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const getSystemPluginCb = async () => {
|
||||||
|
if (isProduction && global.systemPluginCb) return global.systemPluginCb;
|
||||||
|
|
||||||
|
try {
|
||||||
|
global.systemPluginCb = {};
|
||||||
|
global.systemPluginCb = FastGPTProUrl ? await getCommercialCb() : await getCommunityCb();
|
||||||
|
return global.systemPluginCb;
|
||||||
|
} catch (error) {
|
||||||
|
//@ts-ignore
|
||||||
|
global.systemPluginCb = undefined;
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
24
packages/plugins/runtime/worker.ts
Normal file
24
packages/plugins/runtime/worker.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { SystemPluginResponseType } from '../type';
|
||||||
|
import { parentPort } from 'worker_threads';
|
||||||
|
|
||||||
|
const loadModule = async (name: string): Promise<(e: any) => SystemPluginResponseType> => {
|
||||||
|
const module = await import(`../src/${name}/index`);
|
||||||
|
return module.default;
|
||||||
|
};
|
||||||
|
|
||||||
|
parentPort?.on('message', async ({ pluginName, data }: { pluginName: string; data: any }) => {
|
||||||
|
try {
|
||||||
|
const cb = await loadModule(pluginName);
|
||||||
|
parentPort?.postMessage({
|
||||||
|
type: 'success',
|
||||||
|
data: await cb(data)
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
parentPort?.postMessage({
|
||||||
|
type: 'error',
|
||||||
|
data: error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
158
packages/plugins/src/Doc2X/URLImg2text/index.ts
Normal file
158
packages/plugins/src/Doc2X/URLImg2text/index.ts
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import { delay } from '@fastgpt/global/common/system/utils';
|
||||||
|
import { addLog } from '@fastgpt/service/common/system/log';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
apikey: string;
|
||||||
|
url: string;
|
||||||
|
img_correction: boolean;
|
||||||
|
formula: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Response type same as HTTP outputs
|
||||||
|
type Response = Promise<{
|
||||||
|
result: string;
|
||||||
|
success: boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const main = async ({ apikey, url, img_correction, formula }: Props): Response => {
|
||||||
|
// Check the apikey
|
||||||
|
if (!apikey) {
|
||||||
|
return {
|
||||||
|
result: `API key is required`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let real_api_key = apikey;
|
||||||
|
if (!apikey.startsWith('sk-')) {
|
||||||
|
const response = await fetch('https://api.doc2x.noedgeai.com/api/token/refresh', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${apikey}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (response.status !== 200) {
|
||||||
|
return {
|
||||||
|
result: `Get token failed: ${await response.text()}`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
real_api_key = data.data.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the image binary from the URL
|
||||||
|
const extension = url.split('.').pop()?.toLowerCase();
|
||||||
|
const name = url.split('/').pop()?.split('.').shift();
|
||||||
|
let mini = '';
|
||||||
|
switch (extension) {
|
||||||
|
case 'jpg':
|
||||||
|
case 'jpeg':
|
||||||
|
mini = 'image/jpeg';
|
||||||
|
break;
|
||||||
|
case 'png':
|
||||||
|
mini = 'image/png';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
result: `Not supported image format, only support jpg/jpeg/png`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
return {
|
||||||
|
result: `Failed to fetch image from URL: ${url}`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = await response.blob();
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', new Blob([blob], { type: mini }), name + '.' + extension);
|
||||||
|
formData.append('img_correction', img_correction ? '1' : '0');
|
||||||
|
formData.append('equation', formula ? '1' : '0');
|
||||||
|
|
||||||
|
let upload_url = 'https://api.doc2x.noedgeai.com/api/platform/async/img';
|
||||||
|
if (real_api_key.startsWith('sk-')) {
|
||||||
|
upload_url = 'https://api.doc2x.noedgeai.com/api/v1/async/img';
|
||||||
|
}
|
||||||
|
|
||||||
|
let uuid;
|
||||||
|
const uploadAttempts = [1, 2, 3];
|
||||||
|
for await (const attempt of uploadAttempts) {
|
||||||
|
const upload_response = await fetch(upload_url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${real_api_key}`
|
||||||
|
},
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!upload_response.ok) {
|
||||||
|
// Rate limit, wait for 10s and retry at most 3 times
|
||||||
|
if (upload_response.status === 429 && attempt < 3) {
|
||||||
|
await delay(10000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
result: `Failed to upload image: ${await upload_response.text()}`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const upload_data = await upload_response.json();
|
||||||
|
uuid = upload_data.data.uuid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the result by uuid
|
||||||
|
let result_url = 'https://api.doc2x.noedgeai.com/api/platform/async/status?uuid=' + uuid;
|
||||||
|
if (real_api_key.startsWith('sk-')) {
|
||||||
|
result_url = 'https://api.doc2x.noedgeai.com/api/v1/async/status?uuid=' + uuid;
|
||||||
|
}
|
||||||
|
const maxAttempts = 100;
|
||||||
|
// Wait for the result, at most 100s
|
||||||
|
for await (const _ of Array(maxAttempts).keys()) {
|
||||||
|
const result_response = await fetch(result_url, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${real_api_key}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!result_response.ok) {
|
||||||
|
return {
|
||||||
|
result: `Failed to get result: ${await result_response.text()}`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const result_data = await result_response.json();
|
||||||
|
if (['ready', 'processing'].includes(result_data.data.status)) {
|
||||||
|
await delay(1000);
|
||||||
|
} else if (result_data.data.status === 'pages limit exceeded') {
|
||||||
|
return {
|
||||||
|
result: 'Doc2X Pages limit exceeded',
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
} else if (result_data.data.status === 'success') {
|
||||||
|
let result = result_data.data.result.pages[0].md;
|
||||||
|
result = result.replace(/\\[\(\)]/g, '$').replace(/\\[\[\]]/g, '$$');
|
||||||
|
return {
|
||||||
|
result: result,
|
||||||
|
success: true
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
result: `Failed to get result: ${await result_data.text()}`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: 'Timeout waiting for result',
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default main;
|
||||||
421
packages/plugins/src/Doc2X/URLImg2text/template.json
Normal file
421
packages/plugins/src/Doc2X/URLImg2text/template.json
Normal file
@@ -0,0 +1,421 @@
|
|||||||
|
{
|
||||||
|
"author": "Menghuan1918",
|
||||||
|
"version": "488",
|
||||||
|
"name": "Doc2X 图像(URL)识别",
|
||||||
|
"avatar": "plugins/doc2x",
|
||||||
|
"intro": "将传入的图片(URL)发送至Doc2X进行解析,返回带LaTeX公式的markdown格式的文本",
|
||||||
|
"inputExplanationUrl": "https://fael3z0zfze.feishu.cn/wiki/Rkc5witXWiJoi5kORd2cofh6nDg?fromScene=spaceOverview",
|
||||||
|
"showStatus": true,
|
||||||
|
"weight": 10,
|
||||||
|
|
||||||
|
"isTool": true,
|
||||||
|
"templateType": "tools",
|
||||||
|
|
||||||
|
"workflow": {
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"nodeId": "pluginInput",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"intro": "可以配置插件需要哪些输入,利用这些输入来运行插件",
|
||||||
|
"avatar": "core/workflow/template/workflowStart",
|
||||||
|
"flowNodeType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 388.243055058894,
|
||||||
|
"y": -75.09744210499466
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["input"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "apikey",
|
||||||
|
"label": "apikey",
|
||||||
|
"description": "Doc2X的验证密匙,对于个人用户可以从Doc2X官网 - 个人信息 - 身份令牌获得",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "url",
|
||||||
|
"label": "url",
|
||||||
|
"description": "待处理图片的URL",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "待处理图片的URL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["switch"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "boolean",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "img_correction",
|
||||||
|
"label": "img_correction",
|
||||||
|
"description": "是否启用图形矫正功能",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "",
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["switch"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "boolean",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "formula",
|
||||||
|
"label": "formula",
|
||||||
|
"description": "是否开启纯公式识别(仅适用于图片内容仅有公式时)",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "",
|
||||||
|
"defaultValue": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "apikey",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "apikey",
|
||||||
|
"label": "apikey",
|
||||||
|
"type": "hidden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "url",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "url",
|
||||||
|
"label": "url",
|
||||||
|
"type": "hidden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "img_correction",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"key": "img_correction",
|
||||||
|
"label": "img_correction",
|
||||||
|
"type": "hidden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "formula",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"key": "formula",
|
||||||
|
"label": "formula",
|
||||||
|
"type": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "pluginOutput",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
|
"avatar": "core/workflow/template/pluginOutput",
|
||||||
|
"flowNodeType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1654.8021754314786,
|
||||||
|
"y": -22.243376051504086
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "result",
|
||||||
|
"label": "result",
|
||||||
|
"description": "处理结果(或者是报错信息)",
|
||||||
|
"value": ["zHG5jJBkXmjB", "xWQuEf50F3mr"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "boolean",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "success",
|
||||||
|
"label": "success",
|
||||||
|
"description": "是否处理成功",
|
||||||
|
"value": ["zHG5jJBkXmjB", "m6CJJj7GFud5"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "zHG5jJBkXmjB",
|
||||||
|
"name": "HTTP 请求",
|
||||||
|
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||||
|
"avatar": "core/workflow/template/httpRequest",
|
||||||
|
"flowNodeType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1081.967607938733,
|
||||||
|
"y": -426.08028677656125
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"renderTypeList": ["addInputParam"],
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.HTTP Dynamic Input",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"value": "Doc2X/URLImg2text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\n \"apikey\": \"{{apikey}}\",\n \"url\": \"{{url}}\",\n \"img_correction\": \"{{img_correction}}\",\n \"formula\": \"{{img_correction}}\"\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "apikey",
|
||||||
|
"label": "apikey",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "apikey"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "url",
|
||||||
|
"label": "url",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "url"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "boolean",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "img_correction",
|
||||||
|
"label": "img_correction",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "img_correction"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "boolean",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "formula",
|
||||||
|
"label": "formula",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "formula"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "error",
|
||||||
|
"key": "error",
|
||||||
|
"label": "请求错误",
|
||||||
|
"description": "HTTP请求错误信息,成功时返回空",
|
||||||
|
"valueType": "object",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "httpRawResponse",
|
||||||
|
"key": "httpRawResponse",
|
||||||
|
"label": "原始响应",
|
||||||
|
"required": true,
|
||||||
|
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||||
|
"valueType": "any",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_addOutputParam",
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "dynamic",
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"customFieldConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "xWQuEf50F3mr",
|
||||||
|
"valueType": "string",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "result",
|
||||||
|
"label": "result"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "m6CJJj7GFud5",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "success",
|
||||||
|
"label": "success"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"source": "pluginInput",
|
||||||
|
"target": "zHG5jJBkXmjB",
|
||||||
|
"sourceHandle": "pluginInput-source-right",
|
||||||
|
"targetHandle": "zHG5jJBkXmjB-target-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "zHG5jJBkXmjB",
|
||||||
|
"target": "pluginOutput",
|
||||||
|
"sourceHandle": "zHG5jJBkXmjB-source-right",
|
||||||
|
"targetHandle": "pluginOutput-target-left"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
130
packages/plugins/src/Doc2X/URLPDF2text/index.ts
Normal file
130
packages/plugins/src/Doc2X/URLPDF2text/index.ts
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import { delay } from '@fastgpt/global/common/system/utils';
|
||||||
|
import { addLog } from '@fastgpt/service/common/system/log';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
apikey: string;
|
||||||
|
url: string;
|
||||||
|
ocr: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Response type same as HTTP outputs
|
||||||
|
type Response = Promise<{
|
||||||
|
result: string;
|
||||||
|
success: boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const main = async ({ apikey, url, ocr }: Props): Response => {
|
||||||
|
// Check the apikey
|
||||||
|
if (!apikey) {
|
||||||
|
return {
|
||||||
|
result: `API key is required`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let real_api_key = apikey;
|
||||||
|
if (!apikey.startsWith('sk-')) {
|
||||||
|
const response = await fetch('https://api.doc2x.noedgeai.com/api/token/refresh', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${apikey}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (response.status !== 200) {
|
||||||
|
return {
|
||||||
|
result: `Get token failed: ${await response.text()}`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
real_api_key = data.data.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the image binary from the URL
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('pdf_url', url);
|
||||||
|
formData.append('ocr', ocr ? '1' : '0');
|
||||||
|
|
||||||
|
let upload_url = 'https://api.doc2x.noedgeai.com/api/platform/async/pdf';
|
||||||
|
if (real_api_key.startsWith('sk-')) {
|
||||||
|
upload_url = 'https://api.doc2x.noedgeai.com/api/v1/async/pdf';
|
||||||
|
}
|
||||||
|
|
||||||
|
let uuid;
|
||||||
|
const uploadAttempts = [1, 2, 3];
|
||||||
|
for await (const attempt of uploadAttempts) {
|
||||||
|
const upload_response = await fetch(upload_url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${real_api_key}`
|
||||||
|
},
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
if (!upload_response.ok) {
|
||||||
|
if (upload_response.status === 429 && attempt < 3) {
|
||||||
|
await delay(10000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
result: `Failed to upload file: ${await upload_response.text()}`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const upload_data = await upload_response.json();
|
||||||
|
uuid = upload_data.data.uuid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the result by uuid
|
||||||
|
let result_url = 'https://api.doc2x.noedgeai.com/api/platform/async/status?uuid=' + uuid;
|
||||||
|
if (real_api_key.startsWith('sk-')) {
|
||||||
|
result_url = 'https://api.doc2x.noedgeai.com/api/v1/async/status?uuid=' + uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = '';
|
||||||
|
// Wait for the result, at most 100s
|
||||||
|
const maxAttempts = 100;
|
||||||
|
for await (const _ of Array(maxAttempts).keys()) {
|
||||||
|
const result_response = await fetch(result_url, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${real_api_key}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!result_response.ok) {
|
||||||
|
return {
|
||||||
|
result: `Failed to get result: ${await result_response.text()}`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const result_data = await result_response.json();
|
||||||
|
if (['ready', 'processing'].includes(result_data.data.status)) {
|
||||||
|
await delay(1000);
|
||||||
|
} else if (result_data.data.status === 'pages limit exceeded') {
|
||||||
|
return {
|
||||||
|
result: 'Doc2X Pages limit exceeded',
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
} else if (result_data.data.status === 'success') {
|
||||||
|
result = await Promise.all(
|
||||||
|
result_data.data.result.pages.map((page: { md: any }) => page.md)
|
||||||
|
).then((pages) => pages.join('\n'));
|
||||||
|
result = result.replace(/\\[\(\)]/g, '$').replace(/\\[\[\]]/g, '$$');
|
||||||
|
return {
|
||||||
|
result: result,
|
||||||
|
success: true
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
result: `Failed to get result: ${await result_data.text()}`,
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: 'Timeout waiting for result',
|
||||||
|
success: false
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default main;
|
||||||
373
packages/plugins/src/Doc2X/URLPDF2text/template.json
Normal file
373
packages/plugins/src/Doc2X/URLPDF2text/template.json
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
{
|
||||||
|
"author": "Menghuan1918",
|
||||||
|
"version": "488",
|
||||||
|
"name": "Doc2X PDF文件(URL)识别",
|
||||||
|
"avatar": "plugins/doc2x",
|
||||||
|
"intro": "将传入的PDF文件(URL)发送至Doc2X进行解析,返回带LaTeX公式的markdown格式的文本",
|
||||||
|
"inputExplanationUrl": "https://fael3z0zfze.feishu.cn/wiki/Rkc5witXWiJoi5kORd2cofh6nDg?fromScene=spaceOverview",
|
||||||
|
"showStatus": true,
|
||||||
|
"weight": 10,
|
||||||
|
|
||||||
|
"isTool": true,
|
||||||
|
"templateType": "tools",
|
||||||
|
|
||||||
|
"workflow": {
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"nodeId": "pluginInput",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"intro": "可以配置插件需要哪些输入,利用这些输入来运行插件",
|
||||||
|
"avatar": "core/workflow/template/workflowStart",
|
||||||
|
"flowNodeType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 388.243055058894,
|
||||||
|
"y": -75.09744210499466
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["input"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "apikey",
|
||||||
|
"label": "apikey",
|
||||||
|
"description": "Doc2X的验证密匙,对于个人用户可以从Doc2X官网 - 个人信息 - 身份令牌获得",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "url",
|
||||||
|
"label": "url",
|
||||||
|
"description": "待处理PDF文件的URL",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "待处理PDF文件的URL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["switch"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "boolean",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "ocr",
|
||||||
|
"label": "ocr",
|
||||||
|
"description": "是否开启对PDF文件内图片的OCR识别,建议开启",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "",
|
||||||
|
"defaultValue": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "apikey",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "apikey",
|
||||||
|
"label": "apikey",
|
||||||
|
"type": "hidden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "url",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "url",
|
||||||
|
"label": "url",
|
||||||
|
"type": "hidden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "formula",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"key": "ocr",
|
||||||
|
"label": "ocr",
|
||||||
|
"type": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "pluginOutput",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
|
"avatar": "core/workflow/template/pluginOutput",
|
||||||
|
"flowNodeType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1654.8021754314786,
|
||||||
|
"y": -22.243376051504086
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "result",
|
||||||
|
"label": "result",
|
||||||
|
"description": "处理结果(或者是报错信息)",
|
||||||
|
"value": ["zHG5jJBkXmjB", "xWQuEf50F3mr"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "boolean",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "success",
|
||||||
|
"label": "success",
|
||||||
|
"description": "是否处理成功",
|
||||||
|
"value": ["zHG5jJBkXmjB", "m6CJJj7GFud5"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "zHG5jJBkXmjB",
|
||||||
|
"name": "HTTP 请求",
|
||||||
|
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||||
|
"avatar": "core/workflow/template/httpRequest",
|
||||||
|
"flowNodeType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1081.967607938733,
|
||||||
|
"y": -426.08028677656125
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"renderTypeList": ["addInputParam"],
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.HTTP Dynamic Input",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"value": "Doc2X/URLPDF2text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\n \"apikey\": \"{{apikey}}\",\n \"url\": \"{{url}}\",\n \"ocr\": \"{{ocr}}\"\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "apikey",
|
||||||
|
"label": "apikey",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "apikey"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "url",
|
||||||
|
"label": "url",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "url"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "boolean",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "ocr",
|
||||||
|
"label": "ocr",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "formula"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "error",
|
||||||
|
"key": "error",
|
||||||
|
"label": "请求错误",
|
||||||
|
"description": "HTTP请求错误信息,成功时返回空",
|
||||||
|
"valueType": "object",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "httpRawResponse",
|
||||||
|
"key": "httpRawResponse",
|
||||||
|
"label": "原始响应",
|
||||||
|
"required": true,
|
||||||
|
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||||
|
"valueType": "any",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_addOutputParam",
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "dynamic",
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"customFieldConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "xWQuEf50F3mr",
|
||||||
|
"valueType": "string",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "result",
|
||||||
|
"label": "result"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "m6CJJj7GFud5",
|
||||||
|
"valueType": "boolean",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "success",
|
||||||
|
"label": "success"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"source": "pluginInput",
|
||||||
|
"target": "zHG5jJBkXmjB",
|
||||||
|
"sourceHandle": "pluginInput-source-right",
|
||||||
|
"targetHandle": "zHG5jJBkXmjB-target-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "zHG5jJBkXmjB",
|
||||||
|
"target": "pluginOutput",
|
||||||
|
"sourceHandle": "zHG5jJBkXmjB-source-right",
|
||||||
|
"targetHandle": "pluginOutput-target-left"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
17
packages/plugins/src/Doc2X/template.json
Normal file
17
packages/plugins/src/Doc2X/template.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"author": "Menghuan1918",
|
||||||
|
"version": "488",
|
||||||
|
"name": "Doc2X服务",
|
||||||
|
"avatar": "plugins/doc2x",
|
||||||
|
"intro": "传入的URL形式的图片或PDF文件发送至Doc2X进行解析,返回带LaTeX公式的markdown格式的文本。",
|
||||||
|
"showStatus": true,
|
||||||
|
"weight": 10,
|
||||||
|
|
||||||
|
"isTool": true,
|
||||||
|
"templateType": "tools",
|
||||||
|
|
||||||
|
"workflow": {
|
||||||
|
"nodes": [],
|
||||||
|
"edges": []
|
||||||
|
}
|
||||||
|
}
|
||||||
46
packages/plugins/src/duckduckgo/search/index.ts
Normal file
46
packages/plugins/src/duckduckgo/search/index.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { search, SafeSearchType } from 'duck-duck-scrape';
|
||||||
|
import { delay } from '@fastgpt/global/common/system/utils';
|
||||||
|
import { addLog } from '@fastgpt/service/common/system/log';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
query: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Response type same as HTTP outputs
|
||||||
|
type Response = Promise<{
|
||||||
|
result: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const main = async (props: Props, retry = 3): Response => {
|
||||||
|
const { query } = props;
|
||||||
|
try {
|
||||||
|
const searchResults = await search(query, {
|
||||||
|
safeSearch: SafeSearchType.STRICT,
|
||||||
|
time: 'y'
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = searchResults.results
|
||||||
|
.map((item) => ({
|
||||||
|
title: item.title,
|
||||||
|
link: item.url,
|
||||||
|
snippet: item.description
|
||||||
|
}))
|
||||||
|
.slice(0, 10);
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: JSON.stringify(result)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
if (retry <= 0) {
|
||||||
|
addLog.warn('DuckDuckGo error', { error });
|
||||||
|
return {
|
||||||
|
result: 'Failed to fetch data'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await delay(Math.random() * 5000);
|
||||||
|
return main(props, retry - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default main;
|
||||||
260
packages/plugins/src/duckduckgo/search/template.json
Normal file
260
packages/plugins/src/duckduckgo/search/template.json
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
{
|
||||||
|
"author": "",
|
||||||
|
"version": "486",
|
||||||
|
"name": "DuckDuckGo 网络搜索",
|
||||||
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
|
"intro": "使用 DuckDuckGo 进行网络搜索",
|
||||||
|
"showStatus": true,
|
||||||
|
"weight": 10,
|
||||||
|
|
||||||
|
"isTool": true,
|
||||||
|
"templateType": "search",
|
||||||
|
|
||||||
|
"workflow": {
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"nodeId": "pluginInput",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"intro": "可以配置插件需要哪些输入,利用这些输入来运行插件",
|
||||||
|
"avatar": "/imgs/workflow/input.png",
|
||||||
|
"flowNodeType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 393.68844551739926,
|
||||||
|
"y": -58.80666875994541
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"description": "检索词",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "检索词"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "query",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"type": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "pluginOutput",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
|
"avatar": "/imgs/workflow/output.png",
|
||||||
|
"flowNodeType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1795.6509902691012,
|
||||||
|
"y": -47.04550785550961
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "result",
|
||||||
|
"label": "result",
|
||||||
|
"description": " 检索结果",
|
||||||
|
"value": ["hjnVuJAOwyXV", "lEyy5QqyIBrK"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "hjnVuJAOwyXV",
|
||||||
|
"name": "HTTP 请求",
|
||||||
|
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||||
|
"avatar": "/imgs/workflow/http.png",
|
||||||
|
"flowNodeType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1054.6774638324207,
|
||||||
|
"y": -403.06127656499825
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"renderTypeList": ["addInputParam"],
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.HTTP Dynamic Input",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"value": "duckduckgo/search"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\n \"query\": \"{{query}}\"\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "query"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "system_addOutputParam",
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "dynamic",
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"customFieldConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "error",
|
||||||
|
"key": "error",
|
||||||
|
"label": "请求错误",
|
||||||
|
"description": "HTTP请求错误信息,成功时返回空",
|
||||||
|
"valueType": "object",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "httpRawResponse",
|
||||||
|
"key": "httpRawResponse",
|
||||||
|
"label": "原始响应",
|
||||||
|
"required": true,
|
||||||
|
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||||
|
"valueType": "any",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lEyy5QqyIBrK",
|
||||||
|
"valueType": "string",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "result",
|
||||||
|
"label": "result"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"source": "pluginInput",
|
||||||
|
"target": "hjnVuJAOwyXV",
|
||||||
|
"sourceHandle": "pluginInput-source-right",
|
||||||
|
"targetHandle": "hjnVuJAOwyXV-target-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "hjnVuJAOwyXV",
|
||||||
|
"target": "pluginOutput",
|
||||||
|
"sourceHandle": "hjnVuJAOwyXV-source-right",
|
||||||
|
"targetHandle": "pluginOutput-target-left"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
45
packages/plugins/src/duckduckgo/searchImg/index.ts
Normal file
45
packages/plugins/src/duckduckgo/searchImg/index.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { searchImages, SafeSearchType } from 'duck-duck-scrape';
|
||||||
|
import { delay } from '@fastgpt/global/common/system/utils';
|
||||||
|
import { addLog } from '@fastgpt/service/common/system/log';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
query: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Response type same as HTTP outputs
|
||||||
|
type Response = Promise<{
|
||||||
|
result: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const main = async (props: Props, retry = 3): Response => {
|
||||||
|
const { query } = props;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const searchResults = await searchImages(query, {
|
||||||
|
safeSearch: SafeSearchType.STRICT
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = searchResults.results
|
||||||
|
.map((item) => ({
|
||||||
|
title: item.title,
|
||||||
|
image: item.image
|
||||||
|
}))
|
||||||
|
.slice(0, 10);
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: JSON.stringify(result)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
if (retry <= 0) {
|
||||||
|
addLog.warn('DuckDuckGo error', { error });
|
||||||
|
return {
|
||||||
|
result: 'Failed to fetch data'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await delay(Math.random() * 5000);
|
||||||
|
return main(props, retry - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default main;
|
||||||
260
packages/plugins/src/duckduckgo/searchImg/template.json
Normal file
260
packages/plugins/src/duckduckgo/searchImg/template.json
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
{
|
||||||
|
"author": "",
|
||||||
|
"version": "486",
|
||||||
|
"name": "DuckDuckGo 图片搜索",
|
||||||
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
|
"intro": "使用 DuckDuckGo 进行图片搜索",
|
||||||
|
"showStatus": true,
|
||||||
|
"weight": 10,
|
||||||
|
|
||||||
|
"isTool": true,
|
||||||
|
"templateType": "search",
|
||||||
|
|
||||||
|
"workflow": {
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"nodeId": "pluginInput",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"intro": "可以配置插件需要哪些输入,利用这些输入来运行插件",
|
||||||
|
"avatar": "/imgs/workflow/input.png",
|
||||||
|
"flowNodeType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 393.68844551739926,
|
||||||
|
"y": -58.80666875994541
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"description": "检索词",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "检索词"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "query",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"type": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "pluginOutput",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
|
"avatar": "/imgs/workflow/output.png",
|
||||||
|
"flowNodeType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1795.6509902691012,
|
||||||
|
"y": -47.04550785550961
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "result",
|
||||||
|
"label": "result",
|
||||||
|
"description": " 检索结果",
|
||||||
|
"value": ["hjnVuJAOwyXV", "lEyy5QqyIBrK"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "hjnVuJAOwyXV",
|
||||||
|
"name": "HTTP 请求",
|
||||||
|
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||||
|
"avatar": "/imgs/workflow/http.png",
|
||||||
|
"flowNodeType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1054.6774638324207,
|
||||||
|
"y": -403.06127656499825
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"renderTypeList": ["addInputParam"],
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.HTTP Dynamic Input",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"value": "duckduckgo/searchImg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\n \"query\": \"{{query}}\"\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "query"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "system_addOutputParam",
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "dynamic",
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"customFieldConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "error",
|
||||||
|
"key": "error",
|
||||||
|
"label": "请求错误",
|
||||||
|
"description": "HTTP请求错误信息,成功时返回空",
|
||||||
|
"valueType": "object",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "httpRawResponse",
|
||||||
|
"key": "httpRawResponse",
|
||||||
|
"label": "原始响应",
|
||||||
|
"required": true,
|
||||||
|
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||||
|
"valueType": "any",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lEyy5QqyIBrK",
|
||||||
|
"valueType": "string",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "result",
|
||||||
|
"label": "result"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"source": "pluginInput",
|
||||||
|
"target": "hjnVuJAOwyXV",
|
||||||
|
"sourceHandle": "pluginInput-source-right",
|
||||||
|
"targetHandle": "hjnVuJAOwyXV-target-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "hjnVuJAOwyXV",
|
||||||
|
"target": "pluginOutput",
|
||||||
|
"sourceHandle": "hjnVuJAOwyXV-source-right",
|
||||||
|
"targetHandle": "pluginOutput-target-left"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
46
packages/plugins/src/duckduckgo/searchNews/index.ts
Normal file
46
packages/plugins/src/duckduckgo/searchNews/index.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { searchNews, SafeSearchType } from 'duck-duck-scrape';
|
||||||
|
import { delay } from '@fastgpt/global/common/system/utils';
|
||||||
|
import { addLog } from '@fastgpt/service/common/system/log';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
query: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Response type same as HTTP outputs
|
||||||
|
type Response = Promise<{
|
||||||
|
result: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const main = async (props: Props, retry = 3): Response => {
|
||||||
|
const { query } = props;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const searchResults = await searchNews(query, {
|
||||||
|
safeSearch: SafeSearchType.STRICT
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = searchResults.results
|
||||||
|
.map((item) => ({
|
||||||
|
title: item.title,
|
||||||
|
excerpt: item.excerpt,
|
||||||
|
url: item.url
|
||||||
|
}))
|
||||||
|
.slice(0, 10);
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: JSON.stringify(result)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
if (retry <= 0) {
|
||||||
|
addLog.warn('DuckDuckGo error', { error });
|
||||||
|
return {
|
||||||
|
result: 'Failed to fetch data'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await delay(Math.random() * 5000);
|
||||||
|
return main(props, retry - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default main;
|
||||||
260
packages/plugins/src/duckduckgo/searchNews/template.json
Normal file
260
packages/plugins/src/duckduckgo/searchNews/template.json
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
{
|
||||||
|
"author": "",
|
||||||
|
"version": "486",
|
||||||
|
"name": "DuckDuckGo 新闻检索",
|
||||||
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
|
"intro": "使用 DuckDuckGo 进行新闻检索",
|
||||||
|
"showStatus": true,
|
||||||
|
"weight": 10,
|
||||||
|
|
||||||
|
"isTool": true,
|
||||||
|
"templateType": "search",
|
||||||
|
|
||||||
|
"workflow": {
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"nodeId": "pluginInput",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"intro": "可以配置插件需要哪些输入,利用这些输入来运行插件",
|
||||||
|
"avatar": "/imgs/workflow/input.png",
|
||||||
|
"flowNodeType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 393.68844551739926,
|
||||||
|
"y": -58.80666875994541
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"description": "检索词",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "检索词"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "query",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"type": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "pluginOutput",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
|
"avatar": "/imgs/workflow/output.png",
|
||||||
|
"flowNodeType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1795.6509902691012,
|
||||||
|
"y": -47.04550785550961
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "result",
|
||||||
|
"label": "result",
|
||||||
|
"description": " 检索结果",
|
||||||
|
"value": ["hjnVuJAOwyXV", "lEyy5QqyIBrK"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "hjnVuJAOwyXV",
|
||||||
|
"name": "HTTP 请求",
|
||||||
|
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||||
|
"avatar": "/imgs/workflow/http.png",
|
||||||
|
"flowNodeType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1054.6774638324207,
|
||||||
|
"y": -403.06127656499825
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"renderTypeList": ["addInputParam"],
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.HTTP Dynamic Input",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"value": "duckduckgo/searchNews"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\n \"query\": \"{{query}}\"\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "query"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "system_addOutputParam",
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "dynamic",
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"customFieldConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "error",
|
||||||
|
"key": "error",
|
||||||
|
"label": "请求错误",
|
||||||
|
"description": "HTTP请求错误信息,成功时返回空",
|
||||||
|
"valueType": "object",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "httpRawResponse",
|
||||||
|
"key": "httpRawResponse",
|
||||||
|
"label": "原始响应",
|
||||||
|
"required": true,
|
||||||
|
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||||
|
"valueType": "any",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lEyy5QqyIBrK",
|
||||||
|
"valueType": "string",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "result",
|
||||||
|
"label": "result"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"source": "pluginInput",
|
||||||
|
"target": "hjnVuJAOwyXV",
|
||||||
|
"sourceHandle": "pluginInput-source-right",
|
||||||
|
"targetHandle": "hjnVuJAOwyXV-target-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "hjnVuJAOwyXV",
|
||||||
|
"target": "pluginOutput",
|
||||||
|
"sourceHandle": "hjnVuJAOwyXV-source-right",
|
||||||
|
"targetHandle": "pluginOutput-target-left"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
46
packages/plugins/src/duckduckgo/searchVideo/index.ts
Normal file
46
packages/plugins/src/duckduckgo/searchVideo/index.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { searchVideos, SafeSearchType } from 'duck-duck-scrape';
|
||||||
|
import { delay } from '@fastgpt/global/common/system/utils';
|
||||||
|
import { addLog } from '@fastgpt/service/common/system/log';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
query: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Response type same as HTTP outputs
|
||||||
|
type Response = Promise<{
|
||||||
|
result: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const main = async (props: Props, retry = 3): Response => {
|
||||||
|
const { query } = props;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const searchResults = await searchVideos(query, {
|
||||||
|
safeSearch: SafeSearchType.STRICT
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = searchResults.results
|
||||||
|
.map((item) => ({
|
||||||
|
title: item.title,
|
||||||
|
description: item.description,
|
||||||
|
url: item.url
|
||||||
|
}))
|
||||||
|
.slice(0, 10);
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: JSON.stringify(result)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
if (retry <= 0) {
|
||||||
|
addLog.warn('DuckDuckGo error', { error });
|
||||||
|
return {
|
||||||
|
result: 'Failed to fetch data'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await delay(Math.random() * 5000);
|
||||||
|
return main(props, retry - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default main;
|
||||||
260
packages/plugins/src/duckduckgo/searchVideo/template.json
Normal file
260
packages/plugins/src/duckduckgo/searchVideo/template.json
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
{
|
||||||
|
"author": "",
|
||||||
|
"version": "486",
|
||||||
|
"name": "DuckDuckGo 视频搜索",
|
||||||
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
|
"intro": "使用 DuckDuckGo 进行视频搜索",
|
||||||
|
"showStatus": true,
|
||||||
|
"weight": 10,
|
||||||
|
|
||||||
|
"isTool": true,
|
||||||
|
"templateType": "search",
|
||||||
|
|
||||||
|
"workflow": {
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"nodeId": "pluginInput",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"intro": "可以配置插件需要哪些输入,利用这些输入来运行插件",
|
||||||
|
"avatar": "/imgs/workflow/input.png",
|
||||||
|
"flowNodeType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 393.68844551739926,
|
||||||
|
"y": -58.80666875994541
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"description": "检索词",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "检索词"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "query",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"type": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "pluginOutput",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
|
"avatar": "/imgs/workflow/output.png",
|
||||||
|
"flowNodeType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1795.6509902691012,
|
||||||
|
"y": -47.04550785550961
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "result",
|
||||||
|
"label": "result",
|
||||||
|
"description": " 检索结果",
|
||||||
|
"value": ["hjnVuJAOwyXV", "lEyy5QqyIBrK"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "hjnVuJAOwyXV",
|
||||||
|
"name": "HTTP 请求",
|
||||||
|
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||||
|
"avatar": "/imgs/workflow/http.png",
|
||||||
|
"flowNodeType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1054.6774638324207,
|
||||||
|
"y": -403.06127656499825
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"renderTypeList": ["addInputParam"],
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.HTTP Dynamic Input",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"value": "duckduckgo/searchVideo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{\n \"query\": \"{{query}}\"\n}",
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "query",
|
||||||
|
"label": "query",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "query"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "system_addOutputParam",
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "dynamic",
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"customFieldConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "error",
|
||||||
|
"key": "error",
|
||||||
|
"label": "请求错误",
|
||||||
|
"description": "HTTP请求错误信息,成功时返回空",
|
||||||
|
"valueType": "object",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "httpRawResponse",
|
||||||
|
"key": "httpRawResponse",
|
||||||
|
"label": "原始响应",
|
||||||
|
"required": true,
|
||||||
|
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||||
|
"valueType": "any",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lEyy5QqyIBrK",
|
||||||
|
"valueType": "string",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "result",
|
||||||
|
"label": "result"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"source": "pluginInput",
|
||||||
|
"target": "hjnVuJAOwyXV",
|
||||||
|
"sourceHandle": "pluginInput-source-right",
|
||||||
|
"targetHandle": "hjnVuJAOwyXV-target-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "hjnVuJAOwyXV",
|
||||||
|
"target": "pluginOutput",
|
||||||
|
"sourceHandle": "hjnVuJAOwyXV-source-right",
|
||||||
|
"targetHandle": "pluginOutput-target-left"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
17
packages/plugins/src/duckduckgo/template.json
Normal file
17
packages/plugins/src/duckduckgo/template.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"author": "",
|
||||||
|
"version": "486",
|
||||||
|
"name": "DuckDuckGo服务",
|
||||||
|
"avatar": "core/workflow/template/duckduckgo",
|
||||||
|
"intro": "DuckDuckGo 服务,包含网络搜索、图片搜索、新闻搜索等。",
|
||||||
|
"showStatus": false,
|
||||||
|
"weight": 100,
|
||||||
|
|
||||||
|
"isTool": true,
|
||||||
|
"templateType": "tools",
|
||||||
|
|
||||||
|
"workflow": {
|
||||||
|
"nodes": [],
|
||||||
|
"edges": []
|
||||||
|
}
|
||||||
|
}
|
||||||
443
packages/plugins/src/feishu/template.json
Normal file
443
packages/plugins/src/feishu/template.json
Normal file
@@ -0,0 +1,443 @@
|
|||||||
|
{
|
||||||
|
"author": "",
|
||||||
|
"version": "488",
|
||||||
|
"name": "飞书机器人 webhook",
|
||||||
|
"avatar": "/imgs/app/templates/feishu.svg",
|
||||||
|
"intro": "向飞书机器人发起 webhook 请求。",
|
||||||
|
"inputExplanationUrl": "https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot#f62e72d5",
|
||||||
|
"showStatus": false,
|
||||||
|
"weight": 10,
|
||||||
|
|
||||||
|
"isTool": true,
|
||||||
|
"templateType": "communication",
|
||||||
|
|
||||||
|
"workflow": {
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"nodeId": "pluginInput",
|
||||||
|
"name": "自定义插件输入",
|
||||||
|
"intro": "可以配置插件需要哪些输入,利用这些输入来运行插件",
|
||||||
|
"avatar": "core/workflow/template/workflowStart",
|
||||||
|
"flowNodeType": "pluginInput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 156.37657136084977,
|
||||||
|
"y": 90.73380846709256
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "content",
|
||||||
|
"label": "content",
|
||||||
|
"description": "需要发送的消息",
|
||||||
|
"required": true,
|
||||||
|
"toolDescription": "需要发送的消息"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["input"],
|
||||||
|
"selectedTypeIndex": 0,
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "hook_url",
|
||||||
|
"label": "hook_url",
|
||||||
|
"description": "飞书机器人地址",
|
||||||
|
"required": true,
|
||||||
|
"defaultValue": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "query",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "content",
|
||||||
|
"label": "content",
|
||||||
|
"type": "hidden"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hook_url",
|
||||||
|
"valueType": "string",
|
||||||
|
"key": "hook_url",
|
||||||
|
"label": "hook_url",
|
||||||
|
"type": "hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "pluginOutput",
|
||||||
|
"name": "自定义插件输出",
|
||||||
|
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
|
||||||
|
"avatar": "core/workflow/template/pluginOutput",
|
||||||
|
"flowNodeType": "pluginOutput",
|
||||||
|
"showStatus": false,
|
||||||
|
"position": {
|
||||||
|
"x": 2110.7223589692912,
|
||||||
|
"y": 120.17602722162474
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "object",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "result",
|
||||||
|
"label": "result",
|
||||||
|
"description": "",
|
||||||
|
"value": ["vzreK6vHrPvZ", "httpRawResponse"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "vzreK6vHrPvZ",
|
||||||
|
"name": "HTTP 请求",
|
||||||
|
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
|
||||||
|
"avatar": "core/workflow/template/httpRequest",
|
||||||
|
"flowNodeType": "httpRequest468",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 1363.4233257919495,
|
||||||
|
"y": -182.3490463845037
|
||||||
|
},
|
||||||
|
"version": "481",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"renderTypeList": ["addInputParam"],
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"description": "core.module.input.description.HTTP Dynamic Input",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpMethod",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"value": "POST",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpReqUrl",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "string",
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Url",
|
||||||
|
"placeholder": "https://api.ai.com/getInventory",
|
||||||
|
"required": false,
|
||||||
|
"value": "{{url}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpHeader",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"description": "core.module.input.description.Http Request Header",
|
||||||
|
"placeholder": "core.module.input.description.Http Request Header",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpParams",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": [],
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "system_httpJsonBody",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"valueType": "any",
|
||||||
|
"value": "{{content}}",
|
||||||
|
"label": "",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "url",
|
||||||
|
"label": "url",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "hook_url"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "object",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "content",
|
||||||
|
"label": "content",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["qcJpBBVtXsGd", "system_rawResponse"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "error",
|
||||||
|
"key": "error",
|
||||||
|
"label": "请求错误",
|
||||||
|
"description": "HTTP请求错误信息,成功时返回空",
|
||||||
|
"valueType": "object",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "httpRawResponse",
|
||||||
|
"key": "httpRawResponse",
|
||||||
|
"label": "原始响应",
|
||||||
|
"required": true,
|
||||||
|
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
|
||||||
|
"valueType": "any",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_addOutputParam",
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "dynamic",
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"customFieldConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "qcJpBBVtXsGd",
|
||||||
|
"name": "代码运行",
|
||||||
|
"intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
|
||||||
|
"avatar": "core/workflow/template/codeRun",
|
||||||
|
"flowNodeType": "code",
|
||||||
|
"showStatus": true,
|
||||||
|
"position": {
|
||||||
|
"x": 805.8169457909617,
|
||||||
|
"y": -159.52218926716316
|
||||||
|
},
|
||||||
|
"version": "482",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"key": "system_addInputParam",
|
||||||
|
"renderTypeList": ["addInputParam"],
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"required": false,
|
||||||
|
"description": "这些变量会作为代码的运行的输入参数",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "codeType",
|
||||||
|
"renderTypeList": ["hidden"],
|
||||||
|
"label": "",
|
||||||
|
"value": "js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "code",
|
||||||
|
"renderTypeList": ["custom"],
|
||||||
|
"label": "",
|
||||||
|
"value": "function main({data1}){\n try{\n const parseData = JSON.parse(data1)\n if(typeof parseData === 'object') {\n return parseData\n }\n return {\n \"msg_type\": \"text\",\n content: {\n \"text\": data1\n }\n }\n } catch(err) {\n return {\n \"msg_type\": \"text\",\n content: {\n \"text\": data1\n }\n }\n }\n}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"renderTypeList": ["reference"],
|
||||||
|
"valueType": "string",
|
||||||
|
"canEdit": true,
|
||||||
|
"key": "data1",
|
||||||
|
"label": "data1",
|
||||||
|
"customInputConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": true
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"value": ["pluginInput", "query"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": "system_rawResponse",
|
||||||
|
"key": "system_rawResponse",
|
||||||
|
"label": "完整响应数据",
|
||||||
|
"valueType": "object",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "error",
|
||||||
|
"key": "error",
|
||||||
|
"label": "运行错误",
|
||||||
|
"description": "代码运行错误信息,成功时返回空",
|
||||||
|
"valueType": "object",
|
||||||
|
"type": "static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_addOutputParam",
|
||||||
|
"key": "system_addOutputParam",
|
||||||
|
"type": "dynamic",
|
||||||
|
"valueType": "dynamic",
|
||||||
|
"label": "",
|
||||||
|
"customFieldConfig": {
|
||||||
|
"selectValueTypeList": [
|
||||||
|
"string",
|
||||||
|
"number",
|
||||||
|
"boolean",
|
||||||
|
"object",
|
||||||
|
"arrayString",
|
||||||
|
"arrayNumber",
|
||||||
|
"arrayBoolean",
|
||||||
|
"arrayObject",
|
||||||
|
"any",
|
||||||
|
"chatHistory",
|
||||||
|
"datasetQuote",
|
||||||
|
"dynamic",
|
||||||
|
"selectApp",
|
||||||
|
"selectDataset"
|
||||||
|
],
|
||||||
|
"showDescription": false,
|
||||||
|
"showDefaultValue": false
|
||||||
|
},
|
||||||
|
"description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "qLUQfhG0ILRX",
|
||||||
|
"type": "dynamic",
|
||||||
|
"key": "content",
|
||||||
|
"valueType": "object",
|
||||||
|
"label": "content"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"source": "vzreK6vHrPvZ",
|
||||||
|
"target": "pluginOutput",
|
||||||
|
"sourceHandle": "vzreK6vHrPvZ-source-right",
|
||||||
|
"targetHandle": "pluginOutput-target-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "pluginInput",
|
||||||
|
"target": "qcJpBBVtXsGd",
|
||||||
|
"sourceHandle": "pluginInput-source-right",
|
||||||
|
"targetHandle": "qcJpBBVtXsGd-target-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "qcJpBBVtXsGd",
|
||||||
|
"target": "vzreK6vHrPvZ",
|
||||||
|
"sourceHandle": "qcJpBBVtXsGd-source-right",
|
||||||
|
"targetHandle": "vzreK6vHrPvZ-target-left"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"author": "FastGPT",
|
"author": "",
|
||||||
"version": "486",
|
"version": "486",
|
||||||
"name": "网页内容抓取",
|
"name": "网页内容抓取",
|
||||||
"avatar": "/imgs/workflow/fetchUrl.svg",
|
"avatar": "core/workflow/template/fetchUrl",
|
||||||
"intro": "可获取一个网页链接内容,并以 Markdown 格式输出,仅支持获取静态网站。",
|
"intro": "可获取一个网页链接内容,并以 Markdown 格式输出,仅支持获取静态网站。",
|
||||||
"showStatus": true,
|
"showStatus": true,
|
||||||
"weight": 10,
|
"weight": 10,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"author": "FastGPT Team",
|
"author": "",
|
||||||
"version": "481",
|
"version": "481",
|
||||||
"templateType": "tools",
|
"templateType": "tools",
|
||||||
"name": "获取当前时间",
|
"name": "获取当前时间",
|
||||||
"avatar": "/imgs/workflow/getCurrentTime.svg",
|
"avatar": "core/workflow/template/getTime",
|
||||||
"intro": "获取用户当前时区的时间。",
|
"intro": "获取用户当前时区的时间。",
|
||||||
"showStatus": false,
|
"showStatus": false,
|
||||||
"isTool": true,
|
"isTool": true,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|
||||||
import { Parser } from 'expr-eval';
|
import { Parser } from 'expr-eval';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"author": "FastGPT",
|
"author": "",
|
||||||
"version": "486",
|
"version": "486",
|
||||||
"name": "数学公式执行",
|
"name": "数学公式执行",
|
||||||
"avatar": "/imgs/workflow/mathExprEval.svg",
|
"avatar": "core/workflow/template/mathCall",
|
||||||
"intro": "用于执行数学表达式的工具,通过 js 的 expr-eval 库运行表达式并返回结果。",
|
"intro": "用于执行数学表达式的工具,通过 js 的 expr-eval 库运行表达式并返回结果。",
|
||||||
"showStatus": false,
|
"showStatus": false,
|
||||||
"weight": 10,
|
"weight": 10,
|
||||||
|
|||||||
6
packages/plugins/type.d.ts
vendored
6
packages/plugins/type.d.ts
vendored
@@ -1,7 +1,9 @@
|
|||||||
|
import { PluginTemplateType } from '@fastgpt/global/core/plugin/type.d';
|
||||||
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||||
|
|
||||||
export type SystemPluginResponseType = Promise<Record<string, any>>;
|
export type SystemPluginResponseType = Promise<Record<string, any>>;
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
var communitySystemPlugins: SystemPluginTemplateItemType[];
|
var systemPlugins: SystemPluginTemplateItemType[];
|
||||||
var communitySystemPluginCb: Record<string, (e: any) => SystemPluginResponseType>;
|
var systemPluginCb: Record<string, (e: any) => SystemPluginResponseType>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ export const readFileContentFromMongo = async ({
|
|||||||
|
|
||||||
const encoding = file?.metadata?.encoding || detectFileEncoding(fileBuffers);
|
const encoding = file?.metadata?.encoding || detectFileEncoding(fileBuffers);
|
||||||
|
|
||||||
|
// Get raw text
|
||||||
const { rawText } = await readRawContentByFileBuffer({
|
const { rawText } = await readRawContentByFileBuffer({
|
||||||
extension,
|
extension,
|
||||||
isQAImport,
|
isQAImport,
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ import { UploadImgProps } from '@fastgpt/global/common/file/api';
|
|||||||
import { imageBaseUrl } from '@fastgpt/global/common/file/image/constants';
|
import { imageBaseUrl } from '@fastgpt/global/common/file/image/constants';
|
||||||
import { MongoImage } from './schema';
|
import { MongoImage } from './schema';
|
||||||
import { ClientSession } from '../../../common/mongo';
|
import { ClientSession } from '../../../common/mongo';
|
||||||
|
import { guessBase64ImageType } from '../utils';
|
||||||
|
|
||||||
export function getMongoImgUrl(id: string) {
|
export function getMongoImgUrl(id: string, extension: string) {
|
||||||
return `${imageBaseUrl}${id}`;
|
return `${imageBaseUrl}${id}.${extension}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const maxImgSize = 1024 * 1024 * 12;
|
export const maxImgSize = 1024 * 1024 * 12;
|
||||||
@@ -23,9 +24,10 @@ export async function uploadMongoImg({
|
|||||||
return Promise.reject('Image too large');
|
return Promise.reject('Image too large');
|
||||||
}
|
}
|
||||||
|
|
||||||
const [base64Mime, base64Data] = base64Img.split(',')
|
const [base64Mime, base64Data] = base64Img.split(',');
|
||||||
const mime = `image/${base64Mime.match(base64MimeRegex)?.[1] ?? 'jpeg'}`
|
const mime = `image/${base64Mime.match(base64MimeRegex)?.[1] ?? 'image/jpeg'}`;
|
||||||
const binary = Buffer.from(base64Data, 'base64');
|
const binary = Buffer.from(base64Data, 'base64');
|
||||||
|
const extension = mime.split('/')[1];
|
||||||
|
|
||||||
const { _id } = await MongoImage.create({
|
const { _id } = await MongoImage.create({
|
||||||
type,
|
type,
|
||||||
@@ -36,15 +38,20 @@ export async function uploadMongoImg({
|
|||||||
shareId
|
shareId
|
||||||
});
|
});
|
||||||
|
|
||||||
return getMongoImgUrl(String(_id));
|
return getMongoImgUrl(String(_id), extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function readMongoImg({ id }: { id: string }) {
|
export async function readMongoImg({ id }: { id: string }) {
|
||||||
const data = await MongoImage.findById(id);
|
const formatId = id.replace(/\.[^/.]+$/, '');
|
||||||
|
|
||||||
|
const data = await MongoImage.findById(formatId);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return Promise.reject('Image not found');
|
return Promise.reject('Image not found');
|
||||||
}
|
}
|
||||||
return data;
|
return {
|
||||||
|
binary: data.binary,
|
||||||
|
mime: data.metadata?.mime ?? guessBase64ImageType(data.binary.toString('base64'))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function delImgByRelatedId({
|
export async function delImgByRelatedId({
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import { addHours } from 'date-fns';
|
|||||||
import { WorkerNameEnum, runWorker } from '../../../worker/utils';
|
import { WorkerNameEnum, runWorker } from '../../../worker/utils';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
||||||
import { ReadFileResponse } from '../../../worker/file/type';
|
import type { ReadFileResponse } from '../../../worker/readFile/type';
|
||||||
|
|
||||||
export const initMarkdownText = ({
|
// match md img text and upload to db
|
||||||
|
export const matchMdImgTextAndUpload = ({
|
||||||
teamId,
|
teamId,
|
||||||
md,
|
md,
|
||||||
metadata
|
metadata
|
||||||
@@ -79,7 +80,7 @@ export const readRawContentByFileBuffer = async ({
|
|||||||
|
|
||||||
// markdown data format
|
// markdown data format
|
||||||
if (['md', 'html', 'docx'].includes(extension)) {
|
if (['md', 'html', 'docx'].includes(extension)) {
|
||||||
rawText = await initMarkdownText({
|
rawText = await matchMdImgTextAndUpload({
|
||||||
teamId: teamId,
|
teamId: teamId,
|
||||||
md: rawText,
|
md: rawText,
|
||||||
metadata: metadata
|
metadata: metadata
|
||||||
|
|||||||
@@ -47,8 +47,6 @@ const addCommonMiddleware = (schema: mongoose.Schema) => {
|
|||||||
|
|
||||||
if (duration > 1000) {
|
if (duration > 1000) {
|
||||||
addLog.warn(`Slow operation ${duration}ms`, warnLogData);
|
addLog.warn(`Slow operation ${duration}ms`, warnLogData);
|
||||||
} else if (duration > 3000) {
|
|
||||||
addLog.error(`Slow operation ${duration}ms`, warnLogData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { delay } from '@fastgpt/global/common/system/utils';
|
||||||
import { addLog } from '../system/log';
|
import { addLog } from '../system/log';
|
||||||
import { connectionMongo } from './index';
|
import { connectionMongo } from './index';
|
||||||
import type { Mongoose } from 'mongoose';
|
import type { Mongoose } from 'mongoose';
|
||||||
@@ -17,9 +18,11 @@ export async function connectMongo(): Promise<Mongoose> {
|
|||||||
try {
|
try {
|
||||||
connectionMongo.set('strictQuery', true);
|
connectionMongo.set('strictQuery', true);
|
||||||
|
|
||||||
connectionMongo.connection.on('error', (error) => {
|
connectionMongo.connection.on('error', async (error) => {
|
||||||
console.log('mongo error', error);
|
console.log('mongo error', error);
|
||||||
connectionMongo.disconnect();
|
await connectionMongo.disconnect();
|
||||||
|
await delay(1000);
|
||||||
|
connectMongo();
|
||||||
});
|
});
|
||||||
connectionMongo.connection.on('disconnected', () => {
|
connectionMongo.connection.on('disconnected', () => {
|
||||||
console.log('mongo disconnected');
|
console.log('mongo disconnected');
|
||||||
@@ -43,10 +46,11 @@ export async function connectMongo(): Promise<Mongoose> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log('mongo connected');
|
console.log('mongo connected');
|
||||||
|
return connectionMongo;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
connectionMongo.disconnect();
|
|
||||||
addLog.error('mongo connect error', error);
|
addLog.error('mongo connect error', error);
|
||||||
|
await connectionMongo.disconnect();
|
||||||
|
await delay(1000);
|
||||||
|
return connectMongo();
|
||||||
}
|
}
|
||||||
|
|
||||||
return connectionMongo;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,95 +6,41 @@ import {
|
|||||||
} from '@fastgpt/global/core/ai/type';
|
} from '@fastgpt/global/core/ai/type';
|
||||||
import { chats2GPTMessages } from '@fastgpt/global/core/chat/adapt';
|
import { chats2GPTMessages } from '@fastgpt/global/core/chat/adapt';
|
||||||
import { ChatItemType } from '@fastgpt/global/core/chat/type';
|
import { ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||||
import { WorkerNameEnum, getWorker } from '../../../worker/utils';
|
import { WorkerNameEnum, getWorkerController } from '../../../worker/utils';
|
||||||
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
|
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
|
||||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
|
||||||
import { addLog } from '../../system/log';
|
import { addLog } from '../../system/log';
|
||||||
|
|
||||||
export const getTiktokenWorker = () => {
|
export const countGptMessagesTokens = async (
|
||||||
const maxWorkers = global.systemEnv?.tokenWorkers || 20;
|
|
||||||
|
|
||||||
if (!global.tiktokenWorkers) {
|
|
||||||
global.tiktokenWorkers = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (global.tiktokenWorkers.length >= maxWorkers) {
|
|
||||||
return global.tiktokenWorkers[Math.floor(Math.random() * global.tiktokenWorkers.length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
const worker = getWorker(WorkerNameEnum.countGptMessagesTokens);
|
|
||||||
|
|
||||||
const i = global.tiktokenWorkers.push({
|
|
||||||
index: global.tiktokenWorkers.length,
|
|
||||||
worker,
|
|
||||||
callbackMap: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
worker.on('message', ({ id, data }: { id: string; data: number }) => {
|
|
||||||
const callback = global.tiktokenWorkers[i - 1]?.callbackMap?.[id];
|
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
callback?.(data);
|
|
||||||
delete global.tiktokenWorkers[i - 1].callbackMap[id];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return global.tiktokenWorkers[i - 1];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const countGptMessagesTokens = (
|
|
||||||
messages: ChatCompletionMessageParam[],
|
messages: ChatCompletionMessageParam[],
|
||||||
tools?: ChatCompletionTool[],
|
tools?: ChatCompletionTool[],
|
||||||
functionCall?: ChatCompletionCreateParams.Function[]
|
functionCall?: ChatCompletionCreateParams.Function[]
|
||||||
) => {
|
) => {
|
||||||
return new Promise<number>(async (resolve) => {
|
try {
|
||||||
try {
|
const workerController = getWorkerController<
|
||||||
const start = Date.now();
|
{
|
||||||
|
messages: ChatCompletionMessageParam[];
|
||||||
|
tools?: ChatCompletionTool[];
|
||||||
|
functionCall?: ChatCompletionCreateParams.Function[];
|
||||||
|
},
|
||||||
|
number
|
||||||
|
>({
|
||||||
|
name: WorkerNameEnum.countGptMessagesTokens,
|
||||||
|
maxReservedThreads: global.systemEnv?.tokenWorkers || 20
|
||||||
|
});
|
||||||
|
|
||||||
const { worker, callbackMap } = getTiktokenWorker();
|
const total = await workerController.run({ messages, tools, functionCall });
|
||||||
|
|
||||||
const id = getNanoid();
|
return total;
|
||||||
|
} catch (error) {
|
||||||
const timer = setTimeout(() => {
|
addLog.error('Count token error', error);
|
||||||
console.log('Count token Time out');
|
const total = messages.reduce((sum, item) => {
|
||||||
resolve(
|
if (item.content) {
|
||||||
messages.reduce((sum, item) => {
|
return sum + item.content.length * 0.5;
|
||||||
if (item.content) {
|
}
|
||||||
return sum + item.content.length * 0.5;
|
return sum;
|
||||||
}
|
}, 0);
|
||||||
return sum;
|
return total;
|
||||||
}, 0)
|
}
|
||||||
);
|
|
||||||
delete callbackMap[id];
|
|
||||||
}, 60000);
|
|
||||||
|
|
||||||
callbackMap[id] = (data) => {
|
|
||||||
// 检测是否有内存泄漏
|
|
||||||
addLog.debug(`Count token time: ${Date.now() - start}, token: ${data}`);
|
|
||||||
// console.log(process.memoryUsage());
|
|
||||||
|
|
||||||
resolve(data);
|
|
||||||
clearTimeout(timer);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 可以进一步优化(传递100w token数据,实际需要300ms,较慢)
|
|
||||||
worker.postMessage({
|
|
||||||
id,
|
|
||||||
messages,
|
|
||||||
tools,
|
|
||||||
functionCall
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
addLog.error('Count token error', error);
|
|
||||||
const total = messages.reduce((sum, item) => {
|
|
||||||
if (item.content) {
|
|
||||||
return sum + item.content.length;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}, 0);
|
|
||||||
resolve(total);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const countMessagesTokens = (messages: ChatItemType[]) => {
|
export const countMessagesTokens = (messages: ChatItemType[]) => {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const { LOG_LEVEL, STORE_LOG_LEVEL } = (() => {
|
|||||||
const STORE_LOG_LEVEL = (process.env.STORE_LOG_LEVEL || '').toLocaleLowerCase();
|
const STORE_LOG_LEVEL = (process.env.STORE_LOG_LEVEL || '').toLocaleLowerCase();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
LOG_LEVEL: envLogLevelMap[LOG_LEVEL] || LogLevelEnum.info,
|
LOG_LEVEL: envLogLevelMap[LOG_LEVEL] ?? LogLevelEnum.info,
|
||||||
STORE_LOG_LEVEL: envLogLevelMap[STORE_LOG_LEVEL] ?? 99
|
STORE_LOG_LEVEL: envLogLevelMap[STORE_LOG_LEVEL] ?? 99
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
InsertVectorControllerProps
|
InsertVectorControllerProps
|
||||||
} from '../controller.d';
|
} from '../controller.d';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import { addLog } from '../../system/log';
|
||||||
|
|
||||||
export class PgVectorCtrl {
|
export class PgVectorCtrl {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
@@ -38,9 +39,9 @@ export class PgVectorCtrl {
|
|||||||
`CREATE INDEX CONCURRENTLY IF NOT EXISTS create_time_index ON ${DatasetVectorTableName} USING btree(createtime);`
|
`CREATE INDEX CONCURRENTLY IF NOT EXISTS create_time_index ON ${DatasetVectorTableName} USING btree(createtime);`
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('init pg successful');
|
addLog.info('init pg successful');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('init pg error', error);
|
addLog.error('init pg error', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
insert = async (props: InsertVectorControllerProps): Promise<{ insertId: string }> => {
|
insert = async (props: InsertVectorControllerProps): Promise<{ insertId: string }> => {
|
||||||
|
|||||||
30
packages/service/core/ai/audio/transcriptions.ts
Normal file
30
packages/service/core/ai/audio/transcriptions.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import { getAxiosConfig } from '../config';
|
||||||
|
import axios from 'axios';
|
||||||
|
import FormData from 'form-data';
|
||||||
|
|
||||||
|
export const aiTranscriptions = async ({
|
||||||
|
model,
|
||||||
|
fileStream
|
||||||
|
}: {
|
||||||
|
model: string;
|
||||||
|
fileStream: fs.ReadStream;
|
||||||
|
}) => {
|
||||||
|
const data = new FormData();
|
||||||
|
data.append('model', model);
|
||||||
|
data.append('file', fileStream);
|
||||||
|
|
||||||
|
const aiAxiosConfig = getAxiosConfig();
|
||||||
|
const { data: result } = await axios<{ text: string }>({
|
||||||
|
method: 'post',
|
||||||
|
baseURL: aiAxiosConfig.baseUrl,
|
||||||
|
url: '/audio/transcriptions',
|
||||||
|
headers: {
|
||||||
|
Authorization: aiAxiosConfig.authorization,
|
||||||
|
...data.getHeaders()
|
||||||
|
},
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
@@ -21,3 +21,16 @@ export const getAIApi = (props?: {
|
|||||||
maxRetries: 2
|
maxRetries: 2
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAxiosConfig = (props?: { userKey?: UserModelSchema['openaiAccount'] }) => {
|
||||||
|
const { userKey } = props || {};
|
||||||
|
|
||||||
|
const baseUrl =
|
||||||
|
userKey?.baseUrl || global?.systemEnv?.oneapiUrl || process.env.ONEAPI_URL || openaiBaseUrl;
|
||||||
|
const apiKey = userKey?.key || global?.systemEnv?.chatApiKey || process.env.CHAT_API_KEY || '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl,
|
||||||
|
authorization: `Bearer ${apiKey}`
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { getNanoid } from '@fastgpt/global/common/string/tools';
|
|||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { MongoApp } from '../schema';
|
import { MongoApp } from '../schema';
|
||||||
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||||
import { getCommunityPlugins } from '@fastgpt/plugins/register';
|
import { getSystemPluginTemplates } from '../../../../plugins/register';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
plugin id rule:
|
plugin id rule:
|
||||||
@@ -28,7 +28,7 @@ export async function splitCombinePluginId(id: string) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const [source, pluginId] = id.split('-') as [`${PluginSourceEnum}`, string];
|
const [source, pluginId] = id.split('-') as [PluginSourceEnum, string];
|
||||||
if (!source || !pluginId) return Promise.reject('pluginId not found');
|
if (!source || !pluginId) return Promise.reject('pluginId not found');
|
||||||
|
|
||||||
return { source, pluginId: id };
|
return { source, pluginId: id };
|
||||||
@@ -39,14 +39,6 @@ const getPluginTemplateById = async (
|
|||||||
): Promise<SystemPluginTemplateItemType & { teamId?: string }> => {
|
): Promise<SystemPluginTemplateItemType & { teamId?: string }> => {
|
||||||
const { source, pluginId } = await splitCombinePluginId(id);
|
const { source, pluginId } = await splitCombinePluginId(id);
|
||||||
|
|
||||||
if (source === PluginSourceEnum.community) {
|
|
||||||
const item = [...global.communityPlugins, ...getCommunityPlugins()].find(
|
|
||||||
(plugin) => plugin.id === pluginId
|
|
||||||
);
|
|
||||||
if (!item) return Promise.reject('plugin not found');
|
|
||||||
|
|
||||||
return cloneDeep(item);
|
|
||||||
}
|
|
||||||
if (source === PluginSourceEnum.personal) {
|
if (source === PluginSourceEnum.personal) {
|
||||||
const item = await MongoApp.findById(id).lean();
|
const item = await MongoApp.findById(id).lean();
|
||||||
if (!item) return Promise.reject('plugin not found');
|
if (!item) return Promise.reject('plugin not found');
|
||||||
@@ -68,8 +60,14 @@ const getPluginTemplateById = async (
|
|||||||
originCost: 0,
|
originCost: 0,
|
||||||
currentCost: 0
|
currentCost: 0
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
const item = [...global.communityPlugins, ...(await getSystemPluginTemplates())].find(
|
||||||
|
(plugin) => plugin.id === pluginId
|
||||||
|
);
|
||||||
|
if (!item) return Promise.reject('plugin not found');
|
||||||
|
|
||||||
|
return cloneDeep(item);
|
||||||
}
|
}
|
||||||
return Promise.reject('plugin not found');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* format plugin modules to plugin preview module */
|
/* format plugin modules to plugin preview module */
|
||||||
@@ -84,6 +82,7 @@ export async function getPluginPreviewNode({ id }: { id: string }): Promise<Flow
|
|||||||
avatar: plugin.avatar,
|
avatar: plugin.avatar,
|
||||||
name: plugin.name,
|
name: plugin.name,
|
||||||
intro: plugin.intro,
|
intro: plugin.intro,
|
||||||
|
inputExplanationUrl: plugin.inputExplanationUrl,
|
||||||
showStatus: plugin.showStatus,
|
showStatus: plugin.showStatus,
|
||||||
isTool: plugin.isTool,
|
isTool: plugin.isTool,
|
||||||
version: plugin.version,
|
version: plugin.version,
|
||||||
@@ -98,10 +97,12 @@ export async function getPluginRuntimeById(id: string): Promise<PluginRuntimeTyp
|
|||||||
const plugin = await getPluginTemplateById(id);
|
const plugin = await getPluginTemplateById(id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
id: plugin.id,
|
||||||
teamId: plugin.teamId,
|
teamId: plugin.teamId,
|
||||||
name: plugin.name,
|
name: plugin.name,
|
||||||
avatar: plugin.avatar,
|
avatar: plugin.avatar,
|
||||||
showStatus: plugin.showStatus,
|
showStatus: plugin.showStatus,
|
||||||
|
currentCost: plugin.currentCost,
|
||||||
nodes: plugin.workflow.nodes,
|
nodes: plugin.workflow.nodes,
|
||||||
edges: plugin.workflow.edges
|
edges: plugin.workflow.edges
|
||||||
};
|
};
|
||||||
|
|||||||
35
packages/service/core/app/plugin/systemPluginSchema.ts
Normal file
35
packages/service/core/app/plugin/systemPluginSchema.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { connectionMongo, getMongoModel } from '../../../common/mongo/index';
|
||||||
|
const { Schema } = connectionMongo;
|
||||||
|
import type { SystemPluginConfigSchemaType } from './type';
|
||||||
|
|
||||||
|
export const collectionName = 'app_system_plugins';
|
||||||
|
|
||||||
|
const SystemPluginSchema = new Schema({
|
||||||
|
pluginId: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isActive: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
inputConfig: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
originCost: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
currentCost: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SystemPluginSchema.index({ pluginId: 1 });
|
||||||
|
|
||||||
|
export const MongoSystemPluginSchema = getMongoModel<SystemPluginConfigSchemaType>(
|
||||||
|
collectionName,
|
||||||
|
SystemPluginSchema
|
||||||
|
);
|
||||||
10
packages/service/core/app/plugin/type.d.ts
vendored
Normal file
10
packages/service/core/app/plugin/type.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { SystemPluginTemplateItemType } from '@fastgpt/global/core/workflow/type';
|
||||||
|
|
||||||
|
export type SystemPluginConfigSchemaType = {
|
||||||
|
pluginId: string;
|
||||||
|
|
||||||
|
originCost: number; // n points/one time
|
||||||
|
currentCost: number;
|
||||||
|
isActive: boolean;
|
||||||
|
inputConfig: SystemPluginTemplateItemType['inputConfig'];
|
||||||
|
};
|
||||||
21
packages/service/core/app/plugin/utils.ts
Normal file
21
packages/service/core/app/plugin/utils.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { PluginRuntimeType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
|
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||||
|
import { splitCombinePluginId } from './controller';
|
||||||
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Commercial plugin: n points per times
|
||||||
|
2. Other plugin: sum of children points
|
||||||
|
*/
|
||||||
|
export const computedPluginUsage = async (
|
||||||
|
plugin: PluginRuntimeType,
|
||||||
|
childrenUsage: ChatNodeUsageType[]
|
||||||
|
) => {
|
||||||
|
const { source } = await splitCombinePluginId(plugin.id);
|
||||||
|
|
||||||
|
if (source === PluginSourceEnum.commercial) {
|
||||||
|
return plugin.currentCost ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return childrenUsage.reduce((sum, item) => sum + (item.totalPoints || 0), 0);
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { connectionMongo, getMongoModel, type Model } from '../../common/mongo';
|
import { connectionMongo, getMongoModel } from '../../common/mongo';
|
||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema } = connectionMongo;
|
||||||
import { ChatSchema as ChatType } from '@fastgpt/global/core/chat/type.d';
|
import { ChatSchema as ChatType } from '@fastgpt/global/core/chat/type.d';
|
||||||
import { ChatSourceMap } from '@fastgpt/global/core/chat/constants';
|
import { ChatSourceMap } from '@fastgpt/global/core/chat/constants';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { connectionMongo, getMongoModel, type Model } from '../../common/mongo';
|
import { getMongoModel, Schema } from '../../common/mongo';
|
||||||
const { Schema, model, models } = connectionMongo;
|
|
||||||
import { DatasetSchemaType } from '@fastgpt/global/core/dataset/type.d';
|
|
||||||
import {
|
import {
|
||||||
DatasetStatusEnum,
|
DatasetStatusEnum,
|
||||||
DatasetStatusMap,
|
DatasetStatusMap,
|
||||||
@@ -12,6 +10,8 @@ import {
|
|||||||
TeamMemberCollectionName
|
TeamMemberCollectionName
|
||||||
} from '@fastgpt/global/support/user/team/constant';
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
import { DatasetDefaultPermissionVal } from '@fastgpt/global/support/permission/dataset/constant';
|
import { DatasetDefaultPermissionVal } from '@fastgpt/global/support/permission/dataset/constant';
|
||||||
|
import { getPermissionSchema } from '@fastgpt/global/support/permission/utils';
|
||||||
|
import type { DatasetSchemaType } from '@fastgpt/global/core/dataset/type.d';
|
||||||
|
|
||||||
export const DatasetCollectionName = 'datasets';
|
export const DatasetCollectionName = 'datasets';
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ const DatasetSchema = new Schema({
|
|||||||
agentModel: {
|
agentModel: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
default: 'gpt-3.5-turbo'
|
default: 'gpt-4o-mini'
|
||||||
},
|
},
|
||||||
intro: {
|
intro: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -85,11 +85,10 @@ const DatasetSchema = new Schema({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
externalReadUrl: String,
|
externalReadUrl: {
|
||||||
defaultPermission: {
|
type: String
|
||||||
type: Number,
|
},
|
||||||
default: DatasetDefaultPermissionVal
|
...getPermissionSchema(DatasetDefaultPermissionVal)
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -441,11 +441,18 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
|
|
||||||
// token filter
|
// token filter
|
||||||
const filterMaxTokensResult = await (async () => {
|
const filterMaxTokensResult = await (async () => {
|
||||||
|
const tokensScoreFilter = await Promise.all(
|
||||||
|
scoreFilter.map(async (item) => ({
|
||||||
|
...item,
|
||||||
|
tokens: await countPromptTokens(item.q + item.a)
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
const results: SearchDataResponseItemType[] = [];
|
const results: SearchDataResponseItemType[] = [];
|
||||||
let totalTokens = 0;
|
let totalTokens = 0;
|
||||||
|
|
||||||
for await (const item of scoreFilter) {
|
for await (const item of tokensScoreFilter) {
|
||||||
totalTokens += await countPromptTokens(item.q + item.a);
|
totalTokens += item.tokens;
|
||||||
|
|
||||||
if (totalTokens > maxTokens + 500) {
|
if (totalTokens > maxTokens + 500) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -161,70 +161,86 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
stream,
|
stream,
|
||||||
messages: requestMessages
|
messages: requestMessages
|
||||||
};
|
};
|
||||||
const response = await ai.chat.completions.create(requestBody, {
|
try {
|
||||||
headers: {
|
const response = await ai.chat.completions.create(requestBody, {
|
||||||
Accept: 'application/json, text/plain, */*'
|
headers: {
|
||||||
}
|
Accept: 'application/json, text/plain, */*'
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const { answerText } = await (async () => {
|
const { answerText } = await (async () => {
|
||||||
if (res && stream) {
|
if (res && stream) {
|
||||||
// sse response
|
// sse response
|
||||||
const { answer } = await streamResponse({
|
const { answer } = await streamResponse({
|
||||||
res,
|
res,
|
||||||
detail,
|
detail,
|
||||||
stream: response,
|
stream: response
|
||||||
requestBody
|
});
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
if (!answer) {
|
||||||
answerText: answer
|
throw new Error('LLM model response empty');
|
||||||
};
|
}
|
||||||
} else {
|
|
||||||
const unStreamResponse = response as ChatCompletion;
|
|
||||||
const answer = unStreamResponse.choices?.[0]?.message?.content || '';
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
answerText: answer
|
answerText: answer
|
||||||
};
|
};
|
||||||
}
|
} else {
|
||||||
})();
|
const unStreamResponse = response as ChatCompletion;
|
||||||
|
const answer = unStreamResponse.choices?.[0]?.message?.content || '';
|
||||||
|
|
||||||
const completeMessages = filterMessages.concat({
|
return {
|
||||||
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
answerText: answer
|
||||||
content: answerText
|
};
|
||||||
});
|
}
|
||||||
const chatCompleteMessages = GPTMessages2Chats(completeMessages);
|
})();
|
||||||
|
|
||||||
const tokens = await countMessagesTokens(chatCompleteMessages);
|
const completeMessages = filterMessages.concat({
|
||||||
const { totalPoints, modelName } = formatModelChars2Points({
|
role: ChatCompletionRequestMessageRoleEnum.Assistant,
|
||||||
model,
|
content: answerText
|
||||||
tokens,
|
});
|
||||||
modelType: ModelTypeEnum.llm
|
const chatCompleteMessages = GPTMessages2Chats(completeMessages);
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
const tokens = await countMessagesTokens(chatCompleteMessages);
|
||||||
answerText,
|
const { totalPoints, modelName } = formatModelChars2Points({
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
model,
|
||||||
totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
|
|
||||||
model: modelName,
|
|
||||||
tokens,
|
tokens,
|
||||||
query: `${userChatInput}`,
|
modelType: ModelTypeEnum.llm
|
||||||
maxToken: max_tokens,
|
});
|
||||||
historyPreview: getHistoryPreview(chatCompleteMessages),
|
|
||||||
contextTotalLen: completeMessages.length
|
return {
|
||||||
},
|
answerText,
|
||||||
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
{
|
|
||||||
moduleName: name,
|
|
||||||
totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
|
totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
|
||||||
model: modelName,
|
model: modelName,
|
||||||
tokens
|
tokens,
|
||||||
}
|
query: `${userChatInput}`,
|
||||||
],
|
maxToken: max_tokens,
|
||||||
[DispatchNodeResponseKeyEnum.toolResponses]: answerText,
|
historyPreview: getHistoryPreview(chatCompleteMessages),
|
||||||
history: chatCompleteMessages
|
contextTotalLen: completeMessages.length
|
||||||
};
|
},
|
||||||
|
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
|
||||||
|
{
|
||||||
|
moduleName: name,
|
||||||
|
totalPoints: user.openaiAccount?.key ? 0 : totalPoints,
|
||||||
|
model: modelName,
|
||||||
|
tokens
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[DispatchNodeResponseKeyEnum.toolResponses]: answerText,
|
||||||
|
history: chatCompleteMessages
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
addLog.warn(`LLM response error`, {
|
||||||
|
baseUrl: user.openaiAccount?.baseUrl,
|
||||||
|
requestBody
|
||||||
|
});
|
||||||
|
|
||||||
|
if (user.openaiAccount?.baseUrl) {
|
||||||
|
return Promise.reject(`您的 OpenAI key 出错了: ${JSON.stringify(requestBody)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function filterQuote({
|
async function filterQuote({
|
||||||
@@ -334,13 +350,11 @@ async function getMaxTokens({
|
|||||||
async function streamResponse({
|
async function streamResponse({
|
||||||
res,
|
res,
|
||||||
detail,
|
detail,
|
||||||
stream,
|
stream
|
||||||
requestBody
|
|
||||||
}: {
|
}: {
|
||||||
res: NextApiResponse;
|
res: NextApiResponse;
|
||||||
detail: boolean;
|
detail: boolean;
|
||||||
stream: StreamChatType;
|
stream: StreamChatType;
|
||||||
requestBody: Record<string, any>;
|
|
||||||
}) {
|
}) {
|
||||||
const write = responseWriteController({
|
const write = responseWriteController({
|
||||||
res,
|
res,
|
||||||
@@ -364,10 +378,5 @@ async function streamResponse({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!answer) {
|
|
||||||
addLog.info(`LLM model response empty`, requestBody);
|
|
||||||
return Promise.reject('core.chat.Chat API is error or undefined');
|
|
||||||
}
|
|
||||||
|
|
||||||
return { answer };
|
return { answer };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
import { replaceVariable } from '@fastgpt/global/common/string/tools';
|
||||||
import { responseWriteNodeStatus } from '../../../common/response';
|
import { responseWriteNodeStatus } from '../../../common/response';
|
||||||
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
import { getSystemTime } from '@fastgpt/global/common/time/timezone';
|
||||||
|
import { replaceVariableLabel } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
|
||||||
import { dispatchWorkflowStart } from './init/workflowStart';
|
import { dispatchWorkflowStart } from './init/workflowStart';
|
||||||
import { dispatchChatCompletion } from './chat/oneapi';
|
import { dispatchChatCompletion } from './chat/oneapi';
|
||||||
@@ -120,7 +121,6 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
let chatAssistantResponse: AIChatItemValueItemType[] = []; // The value will be returned to the user
|
let chatAssistantResponse: AIChatItemValueItemType[] = []; // The value will be returned to the user
|
||||||
let chatNodeUsages: ChatNodeUsageType[] = [];
|
let chatNodeUsages: ChatNodeUsageType[] = [];
|
||||||
let toolRunResponse: ToolRunResponseItemType;
|
let toolRunResponse: ToolRunResponseItemType;
|
||||||
let runningTime = Date.now();
|
|
||||||
let debugNextStepRunNodes: RuntimeNodeItemType[] = [];
|
let debugNextStepRunNodes: RuntimeNodeItemType[] = [];
|
||||||
|
|
||||||
/* Store special response field */
|
/* Store special response field */
|
||||||
@@ -140,13 +140,8 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
[DispatchNodeResponseKeyEnum.assistantResponses]?: AIChatItemValueItemType[]; // tool module, save the response value
|
[DispatchNodeResponseKeyEnum.assistantResponses]?: AIChatItemValueItemType[]; // tool module, save the response value
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const time = Date.now();
|
|
||||||
|
|
||||||
if (responseData) {
|
if (responseData) {
|
||||||
chatResponses.push({
|
chatResponses.push(responseData);
|
||||||
...responseData,
|
|
||||||
runningTime: +((time - runningTime) / 1000).toFixed(2)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (nodeDispatchUsages) {
|
if (nodeDispatchUsages) {
|
||||||
chatNodeUsages = chatNodeUsages.concat(nodeDispatchUsages);
|
chatNodeUsages = chatNodeUsages.concat(nodeDispatchUsages);
|
||||||
@@ -173,8 +168,6 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runningTime = time;
|
|
||||||
}
|
}
|
||||||
/* Pass the output of the module to the next stage */
|
/* Pass the output of the module to the next stage */
|
||||||
function nodeOutput(
|
function nodeOutput(
|
||||||
@@ -269,13 +262,14 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
/* Inject data into module input */
|
/* Inject data into module input */
|
||||||
function getNodeRunParams(node: RuntimeNodeItemType) {
|
function getNodeRunParams(node: RuntimeNodeItemType) {
|
||||||
if (node.flowNodeType === FlowNodeTypeEnum.pluginInput) {
|
if (node.flowNodeType === FlowNodeTypeEnum.pluginInput) {
|
||||||
|
// Format plugin input to object
|
||||||
return node.inputs.reduce<Record<string, any>>((acc, item) => {
|
return node.inputs.reduce<Record<string, any>>((acc, item) => {
|
||||||
acc[item.key] = valueTypeFormat(item.value, item.valueType);
|
acc[item.key] = valueTypeFormat(item.value, item.valueType);
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// common nodes
|
// Dynamic input need to store a key.
|
||||||
const dynamicInput = node.inputs.find(
|
const dynamicInput = node.inputs.find(
|
||||||
(item) => item.renderTypeList[0] === FlowNodeInputTypeEnum.addInputParam
|
(item) => item.renderTypeList[0] === FlowNodeInputTypeEnum.addInputParam
|
||||||
);
|
);
|
||||||
@@ -288,9 +282,17 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
node.inputs.forEach((input) => {
|
node.inputs.forEach((input) => {
|
||||||
if (input.key === dynamicInput?.key) return;
|
if (input.key === dynamicInput?.key) return;
|
||||||
|
|
||||||
// replace {{}} variables
|
// replace {{xx}} variables
|
||||||
let value = replaceVariable(input.value, variables);
|
let value = replaceVariable(input.value, variables);
|
||||||
|
|
||||||
|
// replace {{$xx.xx$}} variables
|
||||||
|
value = replaceVariableLabel({
|
||||||
|
text: value,
|
||||||
|
nodes: runtimeNodes,
|
||||||
|
variables,
|
||||||
|
runningNode: node
|
||||||
|
});
|
||||||
|
|
||||||
// replace reference variables
|
// replace reference variables
|
||||||
value = getReferenceVariableValue({
|
value = getReferenceVariableValue({
|
||||||
value,
|
value,
|
||||||
@@ -298,12 +300,11 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
variables
|
variables
|
||||||
});
|
});
|
||||||
|
|
||||||
// concat dynamic inputs
|
// Dynamic input is stored in the dynamic key
|
||||||
if (input.canEdit && dynamicInput && params[dynamicInput.key]) {
|
if (input.canEdit && dynamicInput && params[dynamicInput.key]) {
|
||||||
params[dynamicInput.key][input.key] = valueTypeFormat(value, input.valueType);
|
params[dynamicInput.key][input.key] = valueTypeFormat(value, input.valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not dynamic input
|
|
||||||
params[input.key] = valueTypeFormat(value, input.valueType);
|
params[input.key] = valueTypeFormat(value, input.valueType);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -318,6 +319,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
status: 'running'
|
status: 'running'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
// get node running params
|
// get node running params
|
||||||
const params = getNodeRunParams(node);
|
const params = getNodeRunParams(node);
|
||||||
@@ -352,6 +354,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
nodeId: node.nodeId,
|
nodeId: node.nodeId,
|
||||||
moduleName: node.name,
|
moduleName: node.name,
|
||||||
moduleType: node.flowNodeType,
|
moduleType: node.flowNodeType,
|
||||||
|
runningTime: +((Date.now() - startTime) / 1000).toFixed(2),
|
||||||
...dispatchRes[DispatchNodeResponseKeyEnum.nodeResponse]
|
...dispatchRes[DispatchNodeResponseKeyEnum.nodeResponse]
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/
|
|||||||
import { dispatchWorkFlow } from '../index';
|
import { dispatchWorkFlow } from '../index';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
import { getPluginRuntimeById, splitCombinePluginId } from '../../../app/plugin/controller';
|
import { getPluginRuntimeById } from '../../../app/plugin/controller';
|
||||||
import {
|
import {
|
||||||
getDefaultEntryNodeIds,
|
getDefaultEntryNodeIds,
|
||||||
initWorkflowEdgeStatus,
|
initWorkflowEdgeStatus,
|
||||||
@@ -10,9 +10,9 @@ import {
|
|||||||
} from '@fastgpt/global/core/workflow/runtime/utils';
|
} from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { updateToolInputValue } from '../agent/runTool/utils';
|
import { updateToolInputValue } from '../agent/runTool/utils';
|
||||||
import { authAppByTmbId } from '../../../../support/permission/app/auth';
|
import { authPluginByTmbId } from '../../../../support/permission/app/auth';
|
||||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
import { computedPluginUsage } from '../../../app/plugin/utils';
|
||||||
|
|
||||||
type RunPluginProps = ModuleDispatchProps<{
|
type RunPluginProps = ModuleDispatchProps<{
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@@ -33,14 +33,12 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// auth plugin
|
// auth plugin
|
||||||
const { source } = await splitCombinePluginId(pluginId);
|
await authPluginByTmbId({
|
||||||
if (source === PluginSourceEnum.personal) {
|
appId: pluginId,
|
||||||
await authAppByTmbId({
|
tmbId: workflowApp.tmbId,
|
||||||
appId: pluginId,
|
per: ReadPermissionVal
|
||||||
tmbId: workflowApp.tmbId,
|
});
|
||||||
per: ReadPermissionVal
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const plugin = await getPluginRuntimeById(pluginId);
|
const plugin = await getPluginRuntimeById(pluginId);
|
||||||
|
|
||||||
// concat dynamic inputs
|
// concat dynamic inputs
|
||||||
@@ -78,12 +76,15 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
|||||||
output.moduleLogo = plugin.avatar;
|
output.moduleLogo = plugin.avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isError = !!output?.pluginOutput?.error;
|
||||||
|
const usagePoints = isError ? 0 : await computedPluginUsage(plugin, flowUsages);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
assistantResponses,
|
assistantResponses,
|
||||||
// responseData, // debug
|
// responseData, // debug
|
||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
moduleLogo: plugin.avatar,
|
moduleLogo: plugin.avatar,
|
||||||
totalPoints: flowResponses.reduce((sum, item) => sum + (item.totalPoints || 0), 0),
|
totalPoints: usagePoints,
|
||||||
pluginOutput: output?.pluginOutput,
|
pluginOutput: output?.pluginOutput,
|
||||||
pluginDetail:
|
pluginDetail:
|
||||||
mode === 'test' && plugin.teamId === teamId
|
mode === 'test' && plugin.teamId === teamId
|
||||||
@@ -96,8 +97,7 @@ export const dispatchRunPlugin = async (props: RunPluginProps): Promise<RunPlugi
|
|||||||
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
|
[DispatchNodeResponseKeyEnum.nodeDispatchUsages]: [
|
||||||
{
|
{
|
||||||
moduleName: plugin.name,
|
moduleName: plugin.name,
|
||||||
totalPoints: flowUsages.reduce((sum, item) => sum + (item.totalPoints || 0), 0),
|
totalPoints: usagePoints,
|
||||||
model: plugin.name,
|
|
||||||
tokens: 0
|
tokens: 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/ty
|
|||||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||||
import { responseWrite } from '../../../../common/response';
|
import { responseWrite } from '../../../../common/response';
|
||||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { getCommunityCb } from '@fastgpt/plugins/register';
|
import { getSystemPluginCb } from '../../../../../plugins/register';
|
||||||
|
|
||||||
type PropsArrType = {
|
type PropsArrType = {
|
||||||
key: string;
|
key: string;
|
||||||
@@ -106,6 +106,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
|||||||
acc[key] = valueTypeFormat(value, WorkflowIOValueTypeEnum.string);
|
acc[key] = valueTypeFormat(value, WorkflowIOValueTypeEnum.string);
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const requestBody = await (() => {
|
const requestBody = await (() => {
|
||||||
if (!httpJsonBody) return {};
|
if (!httpJsonBody) return {};
|
||||||
try {
|
try {
|
||||||
@@ -121,9 +122,9 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { formatResponse, rawResponse } = await (async () => {
|
const { formatResponse, rawResponse } = await (async () => {
|
||||||
const communityPluginCb = await getCommunityCb();
|
const systemPluginCb = await getSystemPluginCb();
|
||||||
if (communityPluginCb[httpReqUrl]) {
|
if (systemPluginCb[httpReqUrl]) {
|
||||||
const pluginResult = await communityPluginCb[httpReqUrl](requestBody);
|
const pluginResult = await systemPluginCb[httpReqUrl](requestBody);
|
||||||
return {
|
return {
|
||||||
formatResponse: pluginResult,
|
formatResponse: pluginResult,
|
||||||
rawResponse: pluginResult
|
rawResponse: pluginResult
|
||||||
@@ -292,14 +293,14 @@ async function fetchData({
|
|||||||
function replaceVariable(text: string, obj: Record<string, any>) {
|
function replaceVariable(text: string, obj: Record<string, any>) {
|
||||||
for (const [key, value] of Object.entries(obj)) {
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
text = text.replace(new RegExp(`{{${key}}}`, 'g'), UNDEFINED_SIGN);
|
text = text.replace(new RegExp(`{{(${key})}}`, 'g'), UNDEFINED_SIGN);
|
||||||
} else {
|
} else {
|
||||||
const replacement = JSON.stringify(value);
|
const replacement = JSON.stringify(value);
|
||||||
const unquotedReplacement =
|
const unquotedReplacement =
|
||||||
replacement.startsWith('"') && replacement.endsWith('"')
|
replacement.startsWith('"') && replacement.endsWith('"')
|
||||||
? replacement.slice(1, -1)
|
? replacement.slice(1, -1)
|
||||||
: replacement;
|
: replacement;
|
||||||
text = text.replace(new RegExp(`{{${key}}}`, 'g'), unquotedReplacement);
|
text = text.replace(new RegExp(`{{(${key})}}`, 'g'), unquotedReplacement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return text || '';
|
return text || '';
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||||
DispatchNodeResponseKeyEnum,
|
|
||||||
SseResponseEventEnum
|
|
||||||
} from '@fastgpt/global/core/workflow/runtime/constants';
|
|
||||||
import { responseWrite } from '../../../../common/response';
|
|
||||||
import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils';
|
|
||||||
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
import type { ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
import { DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastgpt/global": "workspace:*",
|
"@fastgpt/global": "workspace:*",
|
||||||
"@fastgpt/plugins": "workspace:*",
|
|
||||||
"@node-rs/jieba": "1.10.0",
|
"@node-rs/jieba": "1.10.0",
|
||||||
"@xmldom/xmldom": "^0.8.10",
|
"@xmldom/xmldom": "^0.8.10",
|
||||||
"@zilliz/milvus2-sdk-node": "2.4.2",
|
"@zilliz/milvus2-sdk-node": "2.4.2",
|
||||||
@@ -17,6 +16,7 @@
|
|||||||
"domino-ext": "^2.1.4",
|
"domino-ext": "^2.1.4",
|
||||||
"encoding": "^0.1.13",
|
"encoding": "^0.1.13",
|
||||||
"file-type": "^19.0.0",
|
"file-type": "^19.0.0",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
"joplin-turndown-plugin-gfm": "^1.0.12",
|
"joplin-turndown-plugin-gfm": "^1.0.12",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
@@ -28,9 +28,9 @@
|
|||||||
"next": "14.2.5",
|
"next": "14.2.5",
|
||||||
"nextjs-cors": "^2.2.0",
|
"nextjs-cors": "^2.2.0",
|
||||||
"node-cron": "^3.0.3",
|
"node-cron": "^3.0.3",
|
||||||
"node-xlsx": "^0.23.0",
|
"node-xlsx": "^0.24.0",
|
||||||
"papaparse": "5.4.1",
|
"papaparse": "5.4.1",
|
||||||
"pdfjs-dist": "4.0.269",
|
"pdfjs-dist": "4.4.168",
|
||||||
"pg": "^8.10.0",
|
"pg": "^8.10.0",
|
||||||
"tiktoken": "^1.0.15",
|
"tiktoken": "^1.0.15",
|
||||||
"tunnel": "^0.0.6",
|
"tunnel": "^0.0.6",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user