Compare commits

...

17 Commits

Author SHA1 Message Date
Archer
a997f277ad 4.8.16 test (#3437)
* perf: auto login code

* perf: invoice phone
2024-12-19 14:52:19 +08:00
papapatrick
1f4e5f6d71 perf: add contact phone number in invoice header (#3427) 2024-12-19 14:01:07 +08:00
heheer
ce2e926d76 fix: add sso auto login config (#3436) 2024-12-19 13:33:56 +08:00
Archer
bd79e7701f V4.8.16 dev (#3431)
* feat: add feishu & yuque dataset (#3379)

* feat: add feishu & yuque dataset

* fix ts

* fix ts

* move type position

* fix

* fix: merge interface

* fix

* feat: dingtalk sso support (#3408)

* fix: optional sso state

* feat: dingtalk bot

* feat: dingtalk sso login

* chore: move i18n to user namespace

* feat: dingtalk bot integration (#3415)

* feat: dingtalk bot integration

* docs: config dingtalk bot

* feat:sear XNG服务 (#3413)

* feat:sear XNG服务

* 补充了courseUrl

* 添加了官方文档

* 错误时返回情况修正了一下

* Tracks (#3420)

* feat: node intro

* feat: add domain track

* dingding sso login

* perf: api dataset code and add doc

* feat: tracks

* feat: searXNG plugins

* fix: ts

* feat: delete node tracks (#3423)

* fix: dingtalk bot GET verification (#3424)

* 4.8.16 test: fix: plugin inputs render;fix: ui offset (#3426)

* fix: ui offset

* perf: dingding talk

* fix: plugin inputs render

* feat: menu all folder (#3429)

* fix: recall code

---------

Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: a.e. <49438478+I-Info@users.noreply.github.com>
Co-authored-by: Jiangween <145003935+Jiangween@users.noreply.github.com>
2024-12-18 19:30:19 +08:00
Archer
82871be054 Update 4815.md (#3409) 2024-12-16 19:02:43 +08:00
Archer
8ba339e78f Perf webhook (#3406)
* perf: plugin webhook

* perf: plugin webhook
2024-12-16 16:44:39 +08:00
Jiangween
8e9c030600 feat:钉钉和企微的webhook (#3393) 2024-12-16 15:05:02 +08:00
Hexiao Zhang
9b8779ba08 Update controller.ts (#3404) 2024-12-16 15:04:24 +08:00
Archer
bfac393ab1 Add question guide config (#3403)
* feat:Prompt task (#3337)

* feat:猜你想问自定义功能

* 修改用户输入框部分,去除冗余代码

* 删除不必要的属性

* 删除多余内容

* 修正了格式问题,并实现获取调试和app最新参数

* 修正了几行代码

* feat:Prompt task (#3337)

* feat:猜你想问自定义功能

* 修改用户输入框部分,去除冗余代码

* 删除不必要的属性

* 删除多余内容

* 修正了格式问题,并实现获取调试和app最新参数

* 修正了几行代码

* perf: question gudide code

* fix: i18n

* hunyuan logo

* fix: cq templates

* perf: create question guide code

* udpate svg

---------

Co-authored-by: Jiangween <145003935+Jiangween@users.noreply.github.com>
2024-12-16 13:49:31 +08:00
a.e.
76d20b2b76 fix: handle sso state (#3402) 2024-12-16 12:17:13 +08:00
papapatrick
b4933471cd refactor: 知识块都改为markdown渲染 (#3389) 2024-12-16 12:16:44 +08:00
Archer
c995bccef8 fix: input form value type error (#3399) 2024-12-15 19:58:50 +08:00
a.e.
3deac290bf fix: sso redirect (#3395) 2024-12-13 17:58:57 +08:00
Archer
b7eb4c15de fix: add multiple selector null check (#3392) 2024-12-13 14:15:30 +08:00
heheer
41a8536c16 fix template (#3390) 2024-12-13 12:08:36 +08:00
Archer
1e618502c7 Update 4815.md (#3388) 2024-12-13 11:27:50 +08:00
Archer
e9297c2c6a Update 4815.md (#3387) 2024-12-13 11:26:25 +08:00
223 changed files with 4573 additions and 967 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

View File

@@ -201,7 +201,7 @@ weight: 708
- /imgs/model/qwen.svg - 通义千问
- /imgs/model/sparkDesk.svg - 讯飞星火
- /imgs/model/yi.svg - 零一万物
-
- /imgs/model/hunyuan.svg - 腾讯混元
## 特殊模型

View File

@@ -866,6 +866,8 @@ curl --location --request DELETE 'http://localhost:3000/api/core/chat/delHistory
### 清空所有历史记录
仅会情况通过 API Key 创建的对话历史记录,不会清空在线使用、分享链接等其他来源的对话历史记录。
{{< tabs tabTotal="3" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}
@@ -1313,6 +1315,83 @@ curl --location --request POST 'http://localhost:3000/api/core/chat/feedback/upd
## 猜你想问
**4.8.16 后新版接口**
新版猜你想问,必须包含 appId 和 chatId 的参数才可以进行使用。会自动根据 chatId 去拉取最近 6 轮对话记录作为上下文来引导回答。
{{< tabs tabTotal="3" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}
```bash
curl --location --request POST 'http://localhost:3000/api/core/ai/agent/v2/createQuestionGuide' \
--header 'Authorization: Bearer {{apikey}}' \
--header 'Content-Type: application/json' \
--data-raw '{
"appId": "appId",
"chatId": "chatId",
"questionGuide": {
"open": true,
"model": "GPT-4o-mini",
"customPrompt": "你是一个智能助手,请根据用户的问题生成猜你想问。"
}
}'
```
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="参数说明" >}}
{{< markdownify >}}
{{% alert icon=" " context="success" %}}
| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| appId | string | ✅ | 应用 Id |
| chatId | string | ✅ | 对话 Id |
| questionGuide | object | | 自定义配置,不传的话,则会根据 appId取最新发布版本的配置 |
```ts
type CreateQuestionGuideParams = OutLinkChatAuthProps & {
appId: string;
chatId: string;
questionGuide?: {
open: boolean;
model?: string;
customPrompt?: string;
};
};
```
{{% /alert %}}
{{< /markdownify >}}
{{< /tab >}}
{{< tab tabName="响应示例" >}}
{{< markdownify >}}
```json
{
"code": 200,
"statusText": "",
"message": "",
"data": [
"你对AI有什么看法",
"想了解AI的应用吗",
"你希望AI能做什么"
]
}
```
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}
---
**4.8.16 前旧版接口:**
{{< tabs tabTotal="3" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}
@@ -1369,3 +1448,5 @@ curl --location --request POST 'http://localhost:3000/api/core/ai/agent/createQu

View File

@@ -23,7 +23,7 @@ weight: 809
## 升级指南
- 更新 fastgpt 镜像 tag: v4.8.15-fix2
- 更新 fastgpt 镜像 tag: v4.8.15-fix3
- 更新 fastgpt-pro 商业版镜像 tag: v4.8.15
- Sandbox 镜像,可以不更新
@@ -42,10 +42,10 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4815' \
----
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`{{host}} 替换成**FastGPT 域名**。
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`{{host}} 替换成**fastgpt-pro域名**。
```bash
curl --location --request POST 'https://{{host}}/api/admin/refreshFreeUser' \
curl --location --request POST 'https://{{host}}/api/admin/init/refreshFreeUser' \
--header 'rootkey: {{rootkey}}' \
--header 'Content-Type: application/json'
```

View File

@@ -10,11 +10,20 @@ weight: 808
## 完整更新内容
1.
1. 新增 - SearXNG 搜索插件[点击查看教程](/docs/guide/plugins/searxng_plugin_guide/)
2. 新增 - 商业版支持 API 知识库和链接集合定时同步。
3. 优化 - 工作流/简易模式变量初始化代码,去除监听初始化,避免因渲染顺序不一致导致的失败
4. 修复 - 无法自动切换默认语言。增加分享链接,强制执行一次切换默认语言
5. 修复 - 数组选择器自动兼容 4.8.13 以前的数据。
6. 修复 - 站点同步知识库,链接同步时未使用选择器。
7. 修复 - 简易模式转工作流,没有把系统配置项转化
8. 修复 - 插件独立运行,变量初始值未赋上。
3. 新增 - 猜你想问支持选择模型和自定义提示词
4. 新增 - 钉钉和企微机器人 webhook 插件
5. 新增 - 商业版支持钉钉 SSO 登录配置。[点击查看教程](/docs/guide/admin/sso_dingtalk/)
6. 新增 - 商业版支持飞书和语雀知识库导入。[点击查看教程](/docs/guide/knowledge_base/lark_dataset/)
7. 新增 - sandbox 新增 createHmac 加密全局方法
8. 新增 - 工作流右键支持
9. 优化 - 工作流/简易模式变量初始化代码,去除监听初始化,避免因渲染顺序不一致导致的失败。
10. 优化 - 工作流获取数据类型不一致数据时,增加类型转化,避免 undefined。
11. 修复 - 无法自动切换默认语言。增加分享链接,强制执行一次切换默认语言。
12. 修复 - 数组选择器自动兼容 4.8.13 以前的数据。
13. 修复 - 站点同步知识库,链接同步时未使用选择器。
14. 修复 - 简易模式转工作流,没有把系统配置项转化。
15. 修复 - 插件独立运行,变量初始值未赋上。
16. 修复 - 工作流使用弹窗组件时,关闭弹窗后,有时候会出现页面偏移。
17. 修复 - 插件调试时,日志未保存插件输入参数。

View File

@@ -0,0 +1,9 @@
---
weight: 490
title: '商业版后台'
description: '商业版后台使用教程'
icon: 'chat_bubble'
draft: false
images: []
---
<!-- 470 ~ 500 -->

View File

@@ -0,0 +1,44 @@
---
weight: 490
title: '钉钉 SSO 配置'
description: '钉钉 SSO 登录'
icon: 'chat_bubble'
draft: false
images: []
---
## 1. 注册钉钉应用
登录 [钉钉开放平台](https://open-dev.dingtalk.com/fe/app?hash=%23%2Fcorp%2Fapp#/corp/app),创建一个应用。
![alt text](/imgs/image-25.png)
## 2. 配置钉钉应用安全设置
点击进入创建好的应用后,点开`安全设置`,配置出口 IP服务器 IP和重定向 URL。重定向 URL 填写逻辑:
`{{fastgpt 域名}}/login/provider`
![alt text](/imgs/image-26.png)
## 3. 设置钉钉应用权限
点击进入创建好的应用后,点开`权限设置`,开放两个权限: `个人手机号信息``通讯录个人信息读权限`
![alt text](/imgs/image-27.png)
## 4. 发布应用
点击进入创建好的应用后,点开`版本管理与发布`,随便创建一个新版本即可。
## 5. 在 FastGPT Admin 配置钉钉应用 id
名字都是对应上,直接填写即可。
| | |
| --- | --- |
| ![alt text](/imgs/image-28.png)| ![alt text](/imgs/image-29.png) |
## 6. 测试
![alt text](/imgs/image-30.png)

View File

@@ -0,0 +1,59 @@
---
title: '飞书知识库'
description: 'FastGPT 飞书知识库功能介绍和使用方式'
icon: 'language'
draft: false
toc: true
weight: 405
---
| | |
| --- | --- |
| ![alt text](/imgs/image-39.png) | ![alt text](/imgs/image-40.png) |
FastGPT v4.8.16 版本开始,商业版用户支持飞书知识库导入,用户可以通过配置飞书应用的 appId 和 appSecret并选中一个**文档空间的顶层文件夹**来导入飞书知识库。目前处于测试阶段,部分交互有待优化。
由于飞书限制,无法直接获取所有文档内容,目前仅可以获取共享空间下文件目录的内容,无法获取个人空间和知识库里的内容。
## 1. 创建飞书应用
打开 [飞书开放平台](https://open.feishu.cn/?lang=zh-CN),点击**创建应用**,选择**自建应用**,然后填写应用名称。
## 2. 配置应用权限
创建应用后,进入应用可以配置相关权限,这里需要增加两个权限:
1. 获取云空间文件夹下的云文档清单
2. 查看新版文档
![alt text](/imgs/image-41.png)
## 3. 获取 appId 和 appSecret
![alt text](/imgs/image-42.png)
## 4. 给 Folder 增加权限
可参考飞书教程: https://open.feishu.cn/document/server-docs/docs/drive-v1/faq#b02e5bfb
大致总结为:
1. 把刚刚创建的应用拉入一个群里
2. 给这个群增加目录权限
如果你的目录已经给全员组增加权限了,则可以跳过上面步骤,直接获取 Folder Token。
![alt text](/imgs/image-43.png)
## 5. 获取 Folder Token
可以页面路径上获取 Folder Token注意不要把问号复制进来。
![alt text](/imgs/image-44.png)
## 6. 创建知识库
根据 3 和 5 获取到的 3 个参数,创建知识库,选择飞书文件库类型,然后填入对应的参数,点击创建。
![alt text](/imgs/image-39.png)

View File

@@ -0,0 +1,42 @@
---
title: '语雀文件库'
description: 'FastGPT 语雀文件库功能介绍和使用方式'
icon: 'language'
draft: false
toc: true
weight: 405
---
| | |
| --- | --- |
| ![alt text](/imgs/image-31.png) | ![alt text](/imgs/image-32.png) |
FastGPT v4.8.16 版本开始,商业版用户支持语雀文件库导入,用户可以通过配置语雀的 token 和 uid 来导入语雀文档库。目前处于测试阶段,部分交互有待优化。
## 1. 获取语雀的 token 和 uid
在语雀首页 - 个人头像 - 设置,可找到对应参数。
![alt text](/imgs/image-36.png)
参考下图获取 Token 和 User ID注意给 Token 赋值权限:
| 获取 Token | 增加权限 | 获取 User ID |
| --- | --- | --- |
| ![alt text](/imgs/image-33.png) | ![alt text](/imgs/image-34.png) | ![alt text](/imgs/image-35.png) |
## 2. 创建知识库
使用上一步获取的 token 和 uid创建知识库选择语雀文件库类型然后填入对应的参数点击创建。
![alt text](/imgs/image-37.png)
![alt text](/imgs/image-31.png)
## 3. 导入文档
创建完知识库后,点击`添加文件`即可导入语雀的文档库,跟随引导即可。
语雀知识库支持定时同步功能,每天会不定时的扫描一次,如果文档有更新,则会进行同步,也可以进行手动同步。
![alt text](/imgs/image-38.png)

View File

@@ -0,0 +1,178 @@
---
title: "SearXNG 搜索插件配置与使用说明"
description: "FastGPT SearXNG 搜索插件配置指南"
icon: "search"
draft: false
toc: true
weight: 303
---
[SearXNG](https://github.com/searxng/searxng)是一款免费的互联网元搜索引擎,它汇总了来自各种搜索服务和数据库的结果。它不会跟踪或分析用户。用户可以自行部署它进行使用。本文介绍 Searxng 的部署以及接入 FastGPT 插件。
## 1. 部署应用
这里介绍在 Sealos 中部署 SearXNG 的方法。Docker 部署,可以直接参考 [SearXNG 官方教程](https://github.com/searxng/searxng)。
点击打开 [Sealos 北京区](https://bja.sealos.run/),点击应用部署,并新建一个应用:
| 打开应用部署 | 点击新建应用 |
| --- | --- |
| ![](/imgs/searxng_plugin_guide1.png) | ![alt text](/imgs/image-45.png) |
## 2. 部署配置
把下面参数,填入配置中:
* 镜像名: searxng/searxng:latest
* CPU: 0.2
* 内存: 512M
* 容器暴露端口: 8080
* 开启公网访问
* 点击高级配置,填写环境变量和配置文件
![alt text](/imgs/image-50.png)
**环境变量**
填下面两个内容,主要是为了减小并发,不然内存占用非常大。
```
UWSGI_WORKERS=4
UWSGI_THREADS=4
```
**配置文件**
新增一个配置文件,文件名:`/etc/searx/settings.yml`
文件内容:
```txt
general:
debug: false
instance_name: "searxng"
privacypolicy_url: false
donation_url: false
contact_url: false
enable_metrics: true
open_metrics: ''
brand:
new_issue_url: https://github.com/searxng/searxng/issues/new
docs_url: https://docs.searxng.org/
public_instances: https://searx.space
wiki_url: https://github.com/searxng/searxng/wiki
issue_url: https://github.com/searxng/searxng/issues
search:
safe_search: 0
autocomplete: ""
autocomplete_min: 4
default_lang: "auto"
ban_time_on_fail: 5
max_ban_time_on_fail: 120
formats:
- html
server:
port: 8080
bind_address: "0.0.0.0"
base_url: false
limiter: false
public_instance: false
secret_key: "example"
image_proxy: false
http_protocol_version: "1.0"
method: "POST"
default_http_headers:
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Robots-Tag: noindex, nofollow
Referrer-Policy: no-referrer
redis:
url: false
ui:
static_path: ""
static_use_hash: false
templates_path: ""
default_theme: simple
default_locale: ""
query_in_title: false
infinite_scroll: false
center_alignment: false
theme_args:
simple_style: auto
outgoing:
request_timeout: 30.0
max_request_timeout: 40.0
pool_connections: 200
pool_maxsize: 50
enable_http2: false
retries: 5
engines:
- name: bing
engine: bing
shortcut: bi
doi_resolvers:
oadoi.org: 'https://oadoi.org/'
doi.org: 'https://doi.org/'
doai.io: 'https://dissem.in/'
sci-hub.se: 'https://sci-hub.se/'
sci-hub.st: 'https://sci-hub.st/'
sci-hub.ru: 'https://sci-hub.ru/'
default_doi_resolver: 'oadoi.org'
```
国内目前只有 Bing 引擎可以正常用,所以上面的配置只配置了 bing 引擎。如果在海外部署,可以使用[Sealos 新加坡可用区](https://cloud.sealos.io/),并配置其他搜索引擎,可以参考[SearXNG 默认配置文件](https://github.com/searxng/searxng/blob/master/searx/settings.yml), 从里面复制一些 engine 配置。例如:
```
- name: duckduckgo
engine: duckduckgo
shortcut: ddg
- name: google
engine: google
shortcut: go
```
## 3. FastGPT 使用
复制 Sealos 部署后提供的公网地址,填入 FastGPT 的 SearXNG 插件的 URL 中。
| 复制公网地址| 填入 URL |
| --- | --- |
| ![alt text](/imgs/image-48.png) | ![alt text](/imgs/image-49.png) |
## 返回格式
* 成功时返回搜索结果数组:
```Bash
{
"result": "[{\"title\":\"标题1\",\"link\":\"链接1\",\"snippet\":\"摘要1\"}, ...]"
}
```
* 失败时通过 Promise.reject 可能返回错误信息:
```Bash
- "缺少查询参数"
- "缺少url"
- "Failed to fetch data from Search XNG"
```
一般问题来源于参数缺失与服务部署,如有更多问题可在用户群提问。
## FAQ
### 无搜索结果
1. 先直接打开外网地址,测试是否可以正常搜索。
2. 检查是否有超时的搜索引擎,通过 API 调用时不会返回结果。

View File

@@ -84,4 +84,18 @@ function main({input}){
}
```
![alt text](/imgs/image-2.png)
![alt text](/imgs/image-2.png)
### createHmac 加密
与 node 中 crypto 的 createHmac 方法一致。
```js
function main({secret}){
const {sign,timestamp} = createHmac('sha256',secret)
return {
sign,timestamp
}
}
```

View File

@@ -0,0 +1,57 @@
---
title: "接入钉钉机器人教程"
description: "FastGPT 接入钉钉机器人教程"
icon: "chat"
draft: false
toc: true
weight: 505
---
从 4.8.16 版本起FastGPT 商业版支持直接接入钉钉机器人,无需额外的 API。
## 1. 创建钉钉企业内部应用
1. 在[钉钉开发者后台](https://open-dev.dingtalk.com/fe/app)创建企业内部应用。
![图片1](/imgs/dingtalk-bot-1.png)
2. 获取**Client ID**和**Client Secret**。
![图片2](/imgs/dingtalk-bot-2.png)
## 2. 为 FastGPT 添加发布渠道
在 FastGPT 中选择要接入的应用,在**发布渠道**页面,新建一个接入钉钉机器人的发布渠道。
将前面拿到的 **Client ID****Client Secret** 填入配置弹窗中。
![图片3](/imgs/dingtalk-bot-3.png)
创建完成后,点击**请求地址**按钮,然后复制回调地址。
## 3. 为应用添加**机器人**应用能力。
在钉钉开发者后台,点击左侧**添加应用能力**,为刚刚创建的企业内部应用添加 **机器人** 应用能力。
![图片4](/imgs/dingtalk-bot-4.png)
## 4. 配置机器人回调地址
点击左侧**机器人** 应用能力,然后将底部**消息接受模式**设置为**HTTP模式**,消息接收地址填入前面复制的 FastGPT 的回调地址。
![图片5](/imgs/dingtalk-bot-5.png)
调试完成后,点击**发布**。
## 5. 发布应用
机器人发布后,还需要在**版本管理与发布**页面发布应用版本。
![图片6](/imgs/dingtalk-bot-6.png)
点击**创建新版本**后,设置版本号和版本描述后点击保存发布即可。
![图片7](/imgs/dingtalk-bot-7.png)
应用发布后,即可在钉钉企业中使用机器人功能,可对机器人私聊。或者在群组添加机器人后`@机器人`,触发对话。
![图片8](/imgs/dingtalk-bot-8.png)

View File

@@ -12,7 +12,8 @@ export enum DatasetErrEnum {
unLinkCollection = 'unLinkCollection',
invalidVectorModelOrQAModel = 'invalidVectorModelOrQAModel',
notSupportSync = 'notSupportSync',
sameApiCollection = 'sameApiCollection'
sameApiCollection = 'sameApiCollection',
noApiServer = 'noApiServer'
}
const datasetErr = [
{

View File

@@ -0,0 +1,7 @@
export enum TrackEnum {
login = 'login',
createApp = 'createApp',
useAppTemplate = 'useAppTemplate',
createDataset = 'createDataset',
appNodes = 'appNodes'
}

View File

@@ -0,0 +1,18 @@
import { TrackEnum } from './constants';
import { OAuthEnum } from '../../../support/user/constant';
import { AppTypeEnum } from '../../../core/app/constants';
export type PushTrackCommonType = {
uid: string;
teamId: string;
tmbId: string;
};
export type TrackSchemaType = {
event: TrackEnum;
createTime: Date;
uid?: string;
teamId?: string;
tmbId?: string;
data: Record<string, any>;
};

View File

@@ -58,11 +58,13 @@ export type FastGPTFeConfigsType = {
icon?: string;
title?: string;
url?: string;
autoLogin?: boolean;
};
oauth?: {
github?: string;
google?: string;
wechat?: string;
dingtalk?: string;
microsoft?: {
clientId?: string;
tenantId?: string;

View File

@@ -65,3 +65,13 @@ export const Prompt_CQJson = `请帮我执行一个“问题分类”任务,
问题:"{{question}}"
类型ID=
`;
export const PROMPT_QUESTION_GUIDE = `You are an AI assistant tasked with predicting the user's next question based on the conversation history. Your goal is to generate 3 potential questions that will guide the user to continue the conversation. When generating these questions, adhere to the following rules:
1. Use the same language as the user's last question in the conversation history.
2. Keep each question under 20 characters in length.
Analyze the conversation history provided to you and use it as context to generate relevant and engaging follow-up questions. Your predictions should be logical extensions of the current topic or related areas that the user might be interested in exploring further.
Remember to maintain consistency in tone and style with the existing conversation while providing diverse options for the user to choose from. Your goal is to keep the conversation flowing naturally and help the user delve deeper into the subject matter or explore related topics.`;
export const PROMPT_QUESTION_GUIDE_FOOTER = `Please strictly follow the format rules: \nReturn questions in JSON format: ['Question 1', 'Question 2', 'Question 3']. Your output: `;

View File

@@ -1,8 +1,10 @@
import { PROMPT_QUESTION_GUIDE } from '../ai/prompt/agent';
import {
AppTTSConfigType,
AppFileSelectConfigType,
AppWhisperConfigType,
AppAutoExecuteConfigType
AppAutoExecuteConfigType,
AppQGConfigType
} from './type';
export enum AppTypeEnum {
@@ -28,6 +30,12 @@ export const defaultWhisperConfig: AppWhisperConfigType = {
autoTTSResponse: false
};
export const defaultQGConfig: AppQGConfigType = {
open: false,
model: 'gpt-4o-mini',
customPrompt: PROMPT_QUESTION_GUIDE
};
export const defaultChatInputGuideConfig = {
open: false,
textList: [],

View File

@@ -97,7 +97,7 @@ export type AppChatConfigType = {
welcomeText?: string;
variables?: VariableItemType[];
autoExecute?: AppAutoExecuteConfigType;
questionGuide?: boolean;
questionGuide?: AppQGConfigType;
ttsConfig?: AppTTSConfigType;
whisperConfig?: AppWhisperConfigType;
scheduledTriggerConfig?: AppScheduledTriggerConfigType;
@@ -148,6 +148,14 @@ export type AppWhisperConfigType = {
autoSend: boolean;
autoTTSResponse: boolean;
};
// question guide
export type AppQGConfigType = {
open: boolean;
model?: string;
customPrompt?: string;
};
// question guide text
export type ChatInputGuideConfigType = {
open: boolean;

View File

@@ -16,6 +16,7 @@ import { DatasetSearchModeEnum } from '../dataset/constants';
import { DispatchNodeResponseType } from '../workflow/runtime/type.d';
import { ChatBoxInputType } from '../../../../projects/app/src/components/core/chat/ChatContainer/ChatBox/type';
import { WorkflowInteractiveResponseType } from '../workflow/template/system/interactive/type';
import { FlowNodeInputItemType } from '../workflow/type/io';
export type ChatSchema = {
_id: string;
@@ -35,6 +36,7 @@ export type ChatSchema = {
variableList?: VariableItemType[];
welcomeText?: string;
variables: Record<string, any>;
pluginInputs?: FlowNodeInputItemType[];
metadata?: Record<string, any>;
};

View File

@@ -17,6 +17,8 @@ export type DatasetUpdateBody = {
externalReadUrl?: DatasetSchemaType['externalReadUrl'];
defaultPermission?: DatasetSchemaType['defaultPermission'];
apiServer?: DatasetSchemaType['apiServer'];
yuqueServer?: DatasetSchemaType['yuqueServer'];
feishuServer?: DatasetSchemaType['feishuServer'];
// sync schedule
autoSync?: boolean;

View File

@@ -22,3 +22,14 @@ export type APIFileContentResponse = {
export type APIFileReadResponse = {
url: string;
};
export type FeishuServer = {
appId: string;
appSecret: string;
folderToken: string;
};
export type YuqueServer = {
userId: string;
token: string;
};

View File

@@ -6,7 +6,9 @@ export enum DatasetTypeEnum {
dataset = 'dataset',
websiteDataset = 'websiteDataset', // depp link
externalFile = 'externalFile',
apiDataset = 'apiDataset'
apiDataset = 'apiDataset',
feishu = 'feishu',
yuque = 'yuque'
}
export const DatasetTypeMap = {
[DatasetTypeEnum.folder]: {
@@ -33,6 +35,16 @@ export const DatasetTypeMap = {
icon: 'core/dataset/externalDatasetOutline',
label: 'api_file',
collectionLabel: 'common.File'
},
[DatasetTypeEnum.feishu]: {
icon: 'core/dataset/feishuDatasetOutline',
label: 'feishu_dataset',
collectionLabel: 'common.File'
},
[DatasetTypeEnum.yuque]: {
icon: 'core/dataset/yuqueDatasetOutline',
label: 'yuque_dataset',
collectionLabel: 'common.File'
}
};

View File

@@ -10,7 +10,7 @@ import {
} from './constants';
import { DatasetPermission } from '../../support/permission/dataset/controller';
import { Permission } from '../../support/permission/controller';
import { APIFileServer } from './apiDataset';
import { APIFileServer, FeishuServer, YuqueServer } from './apiDataset';
export type DatasetSchemaType = {
_id: string;
@@ -33,6 +33,8 @@ export type DatasetSchemaType = {
};
inheritPermission: boolean;
apiServer?: APIFileServer;
feishuServer?: FeishuServer;
yuqueServer?: YuqueServer;
autoSync?: boolean;

View File

@@ -284,9 +284,13 @@ export const formatVariableValByType = (val: any, valueType?: WorkflowIOValueTyp
if (!valueType) return val;
// Value type check, If valueType invalid, return undefined
if (valueType.startsWith('array') && !Array.isArray(val)) return undefined;
if (valueType === WorkflowIOValueTypeEnum.boolean && typeof val !== 'boolean') return undefined;
if (valueType === WorkflowIOValueTypeEnum.number && typeof val !== 'number') return undefined;
if (valueType === WorkflowIOValueTypeEnum.string && typeof val !== 'string') return undefined;
if (valueType === WorkflowIOValueTypeEnum.boolean) return Boolean(val);
if (valueType === WorkflowIOValueTypeEnum.number) return Number(val);
if (valueType === WorkflowIOValueTypeEnum.string) {
if (val === undefined) return 'undefined';
if (val === null) return 'null';
return typeof val === 'object' ? JSON.stringify(val) : String(val);
}
if (
[
WorkflowIOValueTypeEnum.object,

View File

@@ -26,12 +26,14 @@ import type {
AppScheduledTriggerConfigType,
ChatInputGuideConfigType,
AppChatConfigType,
AppAutoExecuteConfigType
AppAutoExecuteConfigType,
AppQGConfigType
} from '../app/type';
import { EditorVariablePickerType } from '../../../web/components/common/Textarea/PromptEditor/type';
import {
defaultAutoExecuteConfig,
defaultChatInputGuideConfig,
defaultQGConfig,
defaultTTSConfig,
defaultWhisperConfig
} from '../app/constants';
@@ -76,9 +78,14 @@ export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
const variables: VariableItemType[] =
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value ?? [];
const questionGuide: boolean =
!!guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.questionGuide)?.value ??
false;
// Adapt old version
const questionGuideVal = guideModules?.inputs?.find(
(item) => item.key === NodeInputKeyEnum.questionGuide
)?.value;
const questionGuide: AppQGConfigType =
typeof questionGuideVal === 'boolean'
? { ...defaultQGConfig, open: questionGuideVal }
: questionGuideVal ?? defaultQGConfig;
const ttsConfig: AppTTSConfigType =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.tts)?.value ??

View File

@@ -3,6 +3,7 @@ export enum PublishChannelEnum {
iframe = 'iframe',
apikey = 'apikey',
feishu = 'feishu',
dingtalk = 'dingtalk',
wecom = 'wecom',
officialAccount = 'official_account'
}

View File

@@ -14,6 +14,11 @@ export interface FeishuAppType {
verificationToken?: string;
}
export interface DingtalkAppType {
clientId: string;
clientSecret: string;
}
export interface WecomAppType {
AgentId: string;
CorpId: string;
@@ -36,7 +41,12 @@ export interface OffiAccountAppType {
// because we can not reply anything in 15s. Thus, the wechat server will treat this request as a failed request.
}
export type OutlinkAppType = FeishuAppType | WecomAppType | OffiAccountAppType | undefined;
export type OutlinkAppType =
| FeishuAppType
| WecomAppType
| OffiAccountAppType
| DingtalkAppType
| undefined;
export type OutLinkSchema<T extends OutlinkAppType = undefined> = {
_id: string;

View File

@@ -1,4 +1,5 @@
import { OAuthEnum } from './constant';
import { TrackRegisterParams } from './login/api';
export type PostLoginProps = {
username: string;
@@ -9,8 +10,7 @@ export type OauthLoginProps = {
type: `${OAuthEnum}`;
code: string;
callbackUrl: string;
inviterId?: string;
};
} & TrackRegisterParams;
export type WxLoginProps = {
inviterId?: string;

View File

@@ -16,5 +16,6 @@ export enum OAuthEnum {
google = 'google',
wechat = 'wechat',
microsoft = 'microsoft',
dingtalk = 'dingtalk',
sso = 'sso'
}

View File

@@ -2,3 +2,17 @@ export type GetWXLoginQRResponse = {
code: string;
codeUrl: string;
};
export type TrackRegisterParams = {
inviterId?: string;
bd_vid?: string;
fastgpt_sem?: {
keyword: string;
};
sourceDomain?: string;
};
export type AccountRegisterBody = {
username: string;
code: string;
password: string;
} & TrackRegisterParams;

View File

@@ -12,6 +12,7 @@ export type CreateTeamProps = {
avatar?: string;
defaultTeam?: boolean;
lafAccount?: LafAccountType;
memberName?: string;
};
export type UpdateTeamProps = {
name?: string;

View File

@@ -101,6 +101,7 @@ export type TeamInvoiceHeaderType = {
bankName?: string;
bankAccount?: string;
needSpecialInvoice: boolean;
contactPhone: string;
emailAddress: string;
};

View File

@@ -9,6 +9,7 @@ export enum UsageSourceEnum {
share = 'share',
wecom = 'wecom',
feishu = 'feishu',
dingtalk = 'dingtalk',
official_account = 'official_account'
}
@@ -39,5 +40,8 @@ export const UsageSourceMap = {
},
[UsageSourceEnum.wecom]: {
label: i18nT('user:usage.wecom')
},
[UsageSourceEnum.dingtalk]: {
label: i18nT('user:usage.dingtalk')
}
};

View File

@@ -37,6 +37,8 @@ export const getUsageSourceByPublishChannel = (publishchannel: PublishChannelEnu
return UsageSourceEnum.wecom;
case PublishChannelEnum.officialAccount:
return UsageSourceEnum.official_account;
case PublishChannelEnum.dingtalk:
return UsageSourceEnum.dingtalk;
default:
return UsageSourceEnum.fastgpt;
}

View File

@@ -3,6 +3,7 @@
"version": "1.0.0",
"type": "module",
"dependencies": {
"cheerio": "1.0.0-rc.12",
"@types/pg": "^8.6.6",
"axios": "^1.5.1",
"duck-duck-scrape": "^2.2.5",

View File

@@ -5,7 +5,15 @@ import { cloneDeep } from 'lodash';
import { WorkerNameEnum, runWorker } from '@fastgpt/service/worker/utils';
// Run in main thread
const staticPluginList = ['getTime', 'fetchUrl', 'feishu', 'google', 'bing'];
const staticPluginList = [
'getTime',
'fetchUrl',
'feishu',
'DingTalkWebhook',
'WeWorkWebhook',
'google',
'bing'
];
// Run in worker thread (Have npm packages)
const packagePluginList = [
'mathExprVal',
@@ -19,7 +27,8 @@ const packagePluginList = [
'wiki',
'databaseConnection',
'Doc2X',
'Doc2X/PDF2text'
'Doc2X/PDF2text',
'searchXNG'
];
export const list = [...staticPluginList, ...packagePluginList];

View File

@@ -0,0 +1,536 @@
{
"author": "",
"version": "4816",
"name": "钉钉 webhook",
"avatar": "plugins/dingding",
"intro": "向钉钉机器人发起 webhook 请求。",
"courseUrl": "https://open.dingtalk.com/document/robots/custom-robot-access",
"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": 557.4542421888484,
"y": -131.2827008898969
},
"version": "481",
"inputs": [
{
"inputType": "input",
"valueType": "string",
"key": "钉钉机器人地址",
"label": "钉钉机器人地址",
"description": "",
"isToolInput": false,
"defaultValue": "",
"editField": {
"key": true
},
"dynamicParamDefaultValue": {
"inputType": "reference",
"valueType": "string",
"required": true
},
"renderTypeList": ["input"],
"required": true,
"canEdit": true,
"value": "",
"list": []
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "加签值",
"label": "加签值",
"description": "钉钉机器人加签值",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "发送的消息",
"label": "发送的消息",
"description": "发送的消息",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true,
"toolDescription": "发送的消息"
}
],
"outputs": [
{
"id": "mv52BrPVE6bm",
"key": "钉钉机器人地址",
"valueType": "string",
"label": "钉钉机器人地址",
"type": "static"
},
{
"id": "srcret",
"valueType": "string",
"key": "加签值",
"label": "加签值",
"type": "hidden"
},
{
"id": "发送的消息",
"valueType": "string",
"key": "发送的消息",
"label": "发送的消息",
"type": "hidden"
}
]
},
{
"nodeId": "pluginOutput",
"name": "插件输出",
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
"avatar": "core/workflow/template/pluginOutput",
"flowNodeType": "pluginOutput",
"showStatus": false,
"position": {
"x": 2420.0305926489386,
"y": -106.28270088989689
},
"version": "481",
"inputs": [],
"outputs": []
},
{
"nodeId": "rKBYGQuYefae",
"name": "HTTP 请求",
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
"avatar": "core/workflow/template/httpRequest",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1645.779103978597,
"y": -431.7827008898969
},
"version": "481",
"inputs": [
{
"key": "system_addInputParam",
"renderTypeList": ["addInputParam"],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "common:core.module.input.description.HTTP Dynamic Input",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpMethod",
"renderTypeList": ["custom"],
"valueType": "string",
"label": "",
"value": "POST",
"required": true,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpTimeout",
"renderTypeList": ["custom"],
"valueType": "number",
"label": "",
"value": 30,
"min": 5,
"max": 600,
"required": true,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpReqUrl",
"renderTypeList": ["hidden"],
"valueType": "string",
"label": "",
"description": "common:core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"value": "{{$a5qdMS7ECNYE.qLUQfhG0ILRX$}}",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpHeader",
"renderTypeList": ["custom"],
"valueType": "any",
"value": [],
"label": "",
"description": "common:core.module.input.description.Http Request Header",
"placeholder": "common:core.module.input.description.Http Request Header",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpParams",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpJsonBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": "{\r\n \"msgtype\": \"text\",\r\n \"text\": {\r\n \"content\": \"{{$pluginInput.发送的消息$}}\"\r\n }\r\n}",
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpFormBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpContentType",
"renderTypeList": ["hidden"],
"valueType": "string",
"value": "json",
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
}
],
"outputs": [
{
"id": "error",
"key": "error",
"label": "workflow:request_error",
"description": "HTTP请求错误信息成功时返回空",
"valueType": "object",
"type": "static"
},
{
"id": "httpRawResponse",
"key": "httpRawResponse",
"required": true,
"label": "workflow:raw_response",
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
"valueType": "any",
"type": "static"
},
{
"id": "system_addOutputParam",
"key": "system_addOutputParam",
"type": "dynamic",
"valueType": "dynamic",
"label": "",
"editField": {
"key": true,
"valueType": true
}
}
]
},
{
"nodeId": "q3ccNXiZIHoS",
"name": "系统配置",
"intro": "",
"avatar": "core/workflow/template/systemConfig",
"flowNodeType": "pluginConfig",
"position": {
"x": 99.73879703925843,
"y": -201.26482361861054
},
"version": "4811",
"inputs": [],
"outputs": []
},
{
"nodeId": "a5qdMS7ECNYE",
"name": "代码运行",
"intro": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
"avatar": "core/workflow/template/codeRun",
"flowNodeType": "code",
"showStatus": true,
"position": {
"x": 1106.1011901190363,
"y": -407.7827008898969
},
"version": "482",
"inputs": [
{
"key": "system_addInputParam",
"renderTypeList": ["addInputParam"],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "workflow:these_variables_will_be_input_parameters_for_code_execution",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"valueDesc": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "codeType",
"renderTypeList": ["hidden"],
"label": "",
"value": "js",
"valueDesc": "",
"description": "",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "code",
"renderTypeList": ["custom"],
"label": "",
"value": "function main({url, secret}){\n const {sign,timestamp} = createHmac('sha256',secret)\n\n return {\n result: `${url}&timestamp=${timestamp}&sign=${sign}`\n }\n}",
"valueDesc": "",
"description": "",
"debugLabel": "",
"toolDescription": ""
},
{
"renderTypeList": ["reference"],
"valueType": "string",
"canEdit": true,
"key": "url",
"label": "url",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"required": true,
"value": ["pluginInput", "mv52BrPVE6bm"]
},
{
"renderTypeList": ["reference"],
"valueType": "string",
"canEdit": true,
"key": "secret",
"label": "secret",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"required": true,
"value": ["pluginInput", "srcret"]
}
],
"outputs": [
{
"id": "system_rawResponse",
"key": "system_rawResponse",
"label": "workflow:full_response_data",
"valueType": "object",
"type": "static",
"description": ""
},
{
"id": "error",
"key": "error",
"label": "workflow:execution_error",
"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",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": false
},
"description": "将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key",
"valueDesc": ""
},
{
"id": "qLUQfhG0ILRX",
"type": "dynamic",
"key": "result",
"valueType": "string",
"label": "result",
"valueDesc": "",
"description": ""
}
]
}
],
"edges": [
{
"source": "rKBYGQuYefae",
"target": "pluginOutput",
"sourceHandle": "rKBYGQuYefae-source-right",
"targetHandle": "pluginOutput-target-left"
},
{
"source": "pluginInput",
"target": "a5qdMS7ECNYE",
"sourceHandle": "pluginInput-source-right",
"targetHandle": "a5qdMS7ECNYE-target-left"
},
{
"source": "a5qdMS7ECNYE",
"target": "rKBYGQuYefae",
"sourceHandle": "a5qdMS7ECNYE-source-right",
"targetHandle": "rKBYGQuYefae-target-left"
}
],
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": false,
"ttsConfig": {
"type": "web"
},
"whisperConfig": {
"open": false,
"autoSend": false,
"autoTTSResponse": false
},
"chatInputGuide": {
"open": false,
"textList": [],
"customUrl": ""
},
"instruction": "",
"autoExecute": {
"open": false,
"defaultPrompt": ""
},
"_id": "6710a5619c45325525326719"
}
}
}

View File

@@ -439,7 +439,9 @@
}
],
"chatConfig": {
"questionGuide": false,
"questionGuide": {
"open": false
},
"ttsConfig": {
"type": "web"
},

View File

@@ -0,0 +1,386 @@
{
"author": "",
"version": "4816",
"name": "企业微信 webhook",
"avatar": "plugins/qiwei",
"intro": "向企业微信机器人发起 webhook 请求。只能内部群使用。",
"courseUrl": "https://developer.work.weixin.qq.com/document/path/91770",
"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": 537.6357458754286,
"y": -201.26482361861054
},
"version": "481",
"inputs": [
{
"inputType": "input",
"valueType": "string",
"key": "企微机器人地址",
"label": "企微机器人地址",
"description": "",
"isToolInput": false,
"defaultValue": "",
"editField": {
"key": true
},
"dynamicParamDefaultValue": {
"inputType": "reference",
"valueType": "string",
"required": true
},
"renderTypeList": ["input"],
"required": true,
"canEdit": true,
"value": ""
},
{
"key": "发送的消息",
"valueType": "string",
"label": "发送的消息",
"renderTypeList": ["input", "reference"],
"required": true,
"description": "发送的消息",
"canEdit": true,
"value": "",
"editField": {
"key": true
},
"dynamicParamDefaultValue": {
"inputType": "reference",
"valueType": "string",
"required": true
},
"list": [],
"defaultValue": "",
"toolDescription": "发送的消息"
}
],
"outputs": [
{
"id": "mv52BrPVE6bm",
"key": "企微机器人地址",
"valueType": "string",
"label": "企微机器人地址",
"type": "static"
},
{
"id": "p0m68Dv5KaIp",
"key": "发送的消息",
"valueType": "string",
"label": "发送的消息",
"type": "static"
}
]
},
{
"nodeId": "pluginOutput",
"name": "插件输出",
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
"avatar": "core/workflow/template/pluginOutput",
"flowNodeType": "pluginOutput",
"showStatus": false,
"position": {
"x": 1776.027569211593,
"y": -58.264823618610535
},
"version": "481",
"inputs": [],
"outputs": []
},
{
"nodeId": "rKBYGQuYefae",
"name": "HTTP 请求",
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
"avatar": "core/workflow/template/httpRequest",
"flowNodeType": "httpRequest468",
"showStatus": true,
"position": {
"x": 1069.7228495148624,
"y": -392.26482361861054
},
"version": "481",
"inputs": [
{
"key": "system_addInputParam",
"renderTypeList": ["addInputParam"],
"valueType": "dynamic",
"label": "",
"required": false,
"description": "common:core.module.input.description.HTTP Dynamic Input",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpMethod",
"renderTypeList": ["custom"],
"valueType": "string",
"label": "",
"value": "POST",
"required": true,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpTimeout",
"renderTypeList": ["custom"],
"valueType": "number",
"label": "",
"value": 30,
"min": 5,
"max": 600,
"required": true,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpReqUrl",
"renderTypeList": ["hidden"],
"valueType": "string",
"label": "",
"description": "common:core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"value": "{{url}}",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpHeader",
"renderTypeList": ["custom"],
"valueType": "any",
"value": [],
"label": "",
"description": "common:core.module.input.description.Http Request Header",
"placeholder": "common:core.module.input.description.Http Request Header",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpParams",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpJsonBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": "{\r\n \"msgtype\": \"text\",\r\n \"text\": {\r\n \"content\": \"{{text}}\"\r\n }\r\n}",
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpFormBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpContentType",
"renderTypeList": ["hidden"],
"valueType": "string",
"value": "json",
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "text",
"valueType": "string",
"label": "text",
"renderTypeList": ["reference"],
"description": "",
"canEdit": true,
"editField": {
"key": true,
"valueType": true
},
"value": ["pluginInput", "p0m68Dv5KaIp"],
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
}
},
{
"key": "url",
"valueType": "string",
"label": "url",
"renderTypeList": ["reference"],
"description": "",
"canEdit": true,
"editField": {
"key": true,
"valueType": true
},
"value": ["pluginInput", "mv52BrPVE6bm"],
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
}
}
],
"outputs": [
{
"id": "error",
"key": "error",
"label": "workflow:request_error",
"description": "HTTP请求错误信息成功时返回空",
"valueType": "object",
"type": "static"
},
{
"id": "httpRawResponse",
"key": "httpRawResponse",
"required": true,
"label": "workflow:raw_response",
"description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
"valueType": "any",
"type": "static"
},
{
"id": "system_addOutputParam",
"key": "system_addOutputParam",
"type": "dynamic",
"valueType": "dynamic",
"label": "",
"editField": {
"key": true,
"valueType": true
}
}
]
},
{
"nodeId": "q3ccNXiZIHoS",
"name": "系统配置",
"intro": "",
"avatar": "core/workflow/template/systemConfig",
"flowNodeType": "pluginConfig",
"position": {
"x": 99.73879703925843,
"y": -201.26482361861054
},
"version": "4811",
"inputs": [],
"outputs": []
}
],
"edges": [
{
"source": "pluginInput",
"target": "rKBYGQuYefae",
"sourceHandle": "pluginInput-source-right",
"targetHandle": "rKBYGQuYefae-target-left"
},
{
"source": "rKBYGQuYefae",
"target": "pluginOutput",
"sourceHandle": "rKBYGQuYefae-source-right",
"targetHandle": "pluginOutput-target-left"
}
],
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": false,
"ttsConfig": {
"type": "web"
},
"whisperConfig": {
"open": false,
"autoSend": false,
"autoTTSResponse": false
},
"chatInputGuide": {
"open": false,
"textList": [],
"customUrl": ""
},
"instruction": "",
"autoExecute": {
"open": false,
"defaultPrompt": ""
},
"_id": "6710a5619c45325525326719"
}
}
}

View File

@@ -489,7 +489,9 @@
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": false,
"questionGuide": {
"open": false
},
"ttsConfig": {
"type": "web"
},

View File

@@ -666,7 +666,9 @@
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": false,
"questionGuide": {
"open": false
},
"ttsConfig": {
"type": "web"
},

View File

@@ -502,7 +502,9 @@
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": false,
"questionGuide": {
"open": false
},
"ttsConfig": {
"type": "web"
},

View File

@@ -1,7 +1,7 @@
{
"author": "",
"version": "488",
"name": "飞书机器人 webhook",
"name": "飞书 webhook",
"avatar": "/appMarketTemplates/plugin-feishu/avatar.svg",
"intro": "向飞书机器人发起 webhook 请求。",
"courseUrl": "https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot#f62e72d5",
@@ -27,7 +27,7 @@
"version": "481",
"inputs": [
{
"renderTypeList": ["reference"],
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
@@ -35,7 +35,9 @@
"label": "content",
"description": "需要发送的消息",
"required": true,
"toolDescription": "需要发送的消息"
"toolDescription": "需要发送的消息",
"list": [],
"defaultValue": ""
},
{
"renderTypeList": ["input"],
@@ -46,7 +48,8 @@
"label": "hook_url",
"description": "飞书机器人地址",
"required": true,
"defaultValue": ""
"defaultValue": "",
"list": []
}
],
"outputs": [
@@ -508,6 +511,30 @@
"sourceHandle": "qcJpBBVtXsGd-source-right",
"targetHandle": "vzreK6vHrPvZ-target-left"
}
]
],
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": false,
"ttsConfig": {
"type": "web"
},
"whisperConfig": {
"open": false,
"autoSend": false,
"autoTTSResponse": false
},
"chatInputGuide": {
"open": false,
"textList": [],
"customUrl": ""
},
"instruction": "",
"autoExecute": {
"open": false,
"defaultPrompt": ""
},
"_id": "6710a5619c45325525326719"
}
}
}

View File

@@ -538,7 +538,9 @@
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": false,
"questionGuide": {
"open": false
},
"ttsConfig": {
"type": "web"
},

View File

@@ -0,0 +1,66 @@
import { delay } from '@fastgpt/global/common/system/utils';
import * as cheerio from 'cheerio';
import { i18nT } from '../../../web/i18n/utils';
type Props = {
query: string;
url: string;
};
interface SearchResult {
title: string;
link: string;
snippet: string;
}
type Response = Promise<{
result: string;
error?: Record<string, any>;
}>;
const main = async (props: Props, retry = 3): Response => {
const { query, url } = props;
if (!query) {
return Promise.reject(i18nT('chat:not_query'));
}
if (!url) {
return Promise.reject('Can not find url');
}
try {
const response = await fetch(`${url}?q=${encodeURIComponent(query)}&language=auto`);
const html = await response.text();
const $ = cheerio.load(html, {
xml: false,
decodeEntities: true
});
const results: SearchResult[] = [];
$('.result').each((_: number, element: cheerio.Element) => {
const $element = $(element);
results.push({
title: $element.find('h3').text().trim(),
link: $element.find('a').first().attr('href') || '',
snippet: $element.find('.content').text().trim()
});
});
return {
result: JSON.stringify(results.slice(0, 10))
};
} catch (error) {
console.log(error);
if (retry <= 0) {
console.log('Search XNG error', { error });
return Promise.reject('Failed to fetch data from Search XNG');
}
await delay(Math.random() * 2000);
return main(props, retry - 1);
}
};
export default main;

View File

@@ -0,0 +1,414 @@
{
"author": "",
"version": "4816",
"name": "Search XNG 搜索",
"avatar": "core/workflow/template/searxng",
"intro": "使用 Search XNG 服务进行搜索。",
"courseUrl": "/docs/guide/plugins/searxng_plugin_guide/",
"showStatus": true,
"weight": 10,
"isTool": true,
"templateType": "search",
"workflow": {
"nodes": [
{
"nodeId": "pluginInput",
"name": "插件开始",
"intro": "可以配置插件需要哪些输入,利用这些输入来运行插件",
"avatar": "core/workflow/template/workflowStart",
"flowNodeType": "pluginInput",
"showStatus": false,
"position": {
"x": 482.8986144681427,
"y": -77.56127656499825
},
"version": "481",
"inputs": [
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "query",
"label": "query",
"description": "检索词",
"required": true,
"toolDescription": "检索词"
},
{
"renderTypeList": ["input", "reference"],
"selectedTypeIndex": 0,
"valueType": "string",
"canEdit": true,
"key": "url",
"label": "url",
"description": "部署的searXNG服务的链接",
"defaultValue": "",
"list": [
{
"label": "",
"value": ""
}
],
"maxFiles": 5,
"canSelectFile": true,
"canSelectImg": true,
"required": true,
"toolDescription": "部署的searXNG服务的链接"
}
],
"outputs": [
{
"id": "query",
"valueType": "string",
"key": "query",
"label": "query",
"type": "hidden"
},
{
"id": "url",
"valueType": "string",
"key": "url",
"label": "url",
"type": "hidden"
}
]
},
{
"nodeId": "pluginOutput",
"name": "插件输出",
"intro": "自定义配置外部输出,使用插件时,仅暴露自定义配置的输出",
"avatar": "core/workflow/template/pluginOutput",
"flowNodeType": "pluginOutput",
"showStatus": false,
"position": {
"x": 1763.7518709731714,
"y": -55.56127656499825
},
"version": "481",
"inputs": [
{
"renderTypeList": ["reference"],
"valueType": "string",
"canEdit": true,
"key": "result",
"label": "result",
"description": " 检索结果",
"value": ["hjnVuJAOwyXV", "lEyy5QqyIBrK"]
},
{
"renderTypeList": ["reference"],
"valueType": "object",
"canEdit": true,
"key": "error",
"label": "error",
"isToolOutput": true,
"description": "请求错误",
"required": true,
"value": ["hjnVuJAOwyXV", "error"]
}
],
"outputs": []
},
{
"nodeId": "hjnVuJAOwyXV",
"name": "HTTP 请求",
"intro": "可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)",
"avatar": "core/workflow/template/httpRequest",
"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": "common:core.module.input.description.HTTP Dynamic Input",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpMethod",
"renderTypeList": ["custom"],
"valueType": "string",
"label": "",
"value": "POST",
"required": true,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpTimeout",
"renderTypeList": ["custom"],
"valueType": "number",
"label": "",
"value": 30,
"min": 5,
"max": 600,
"required": true,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpReqUrl",
"renderTypeList": ["hidden"],
"valueType": "string",
"label": "",
"description": "common:core.module.input.description.Http Request Url",
"placeholder": "https://api.ai.com/getInventory",
"required": false,
"value": "searchXNG",
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpHeader",
"renderTypeList": ["custom"],
"valueType": "any",
"value": [],
"label": "",
"description": "common:core.module.input.description.Http Request Header",
"placeholder": "common:core.module.input.description.Http Request Header",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpParams",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpJsonBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": "{\n \"query\": \"{{query}}\",\n \"url\": \"{{url}}\"\n}",
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpFormBody",
"renderTypeList": ["hidden"],
"valueType": "any",
"value": [],
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"key": "system_httpContentType",
"renderTypeList": ["hidden"],
"valueType": "string",
"value": "json",
"label": "",
"required": false,
"debugLabel": "",
"toolDescription": ""
},
{
"renderTypeList": ["reference"],
"valueType": "string",
"canEdit": true,
"key": "query",
"label": "query",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"required": true,
"value": ["pluginInput", "query"]
},
{
"renderTypeList": ["reference"],
"valueType": "string",
"canEdit": true,
"key": "url",
"label": "url",
"customInputConfig": {
"selectValueTypeList": [
"string",
"number",
"boolean",
"object",
"arrayString",
"arrayNumber",
"arrayBoolean",
"arrayObject",
"arrayAny",
"any",
"chatHistory",
"datasetQuote",
"dynamic",
"selectApp",
"selectDataset"
],
"showDescription": false,
"showDefaultValue": true
},
"required": true,
"value": ["pluginInput", "url"]
}
],
"outputs": [
{
"id": "error",
"key": "error",
"label": "workflow:request_error",
"description": "HTTP请求错误信息成功时返回空",
"valueType": "object",
"type": "static"
},
{
"id": "httpRawResponse",
"key": "httpRawResponse",
"required": true,
"label": "workflow:raw_response",
"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": "lEyy5QqyIBrK",
"valueType": "string",
"type": "dynamic",
"key": "result",
"label": "result"
}
]
},
{
"nodeId": "f1mRh1D85H2D",
"name": "系统配置",
"intro": "",
"avatar": "core/workflow/template/systemConfig",
"flowNodeType": "pluginConfig",
"position": {
"x": -28.511358745511643,
"y": -103.56127656499825
},
"version": "4811",
"inputs": [],
"outputs": []
}
],
"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"
}
],
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": false,
"ttsConfig": {
"type": "web"
},
"whisperConfig": {
"open": false,
"autoSend": false,
"autoTTSResponse": false
},
"chatInputGuide": {
"open": false,
"textList": [],
"customUrl": ""
},
"instruction": "",
"autoExecute": {
"open": false,
"defaultPrompt": ""
},
"_id": "67611a5eed7efa452a6e50c5"
}
}
}

View File

@@ -320,7 +320,9 @@
"chatConfig": {
"welcomeText": "",
"variables": [],
"questionGuide": false,
"questionGuide": {
"open": false
},
"ttsConfig": {
"type": "web"
},

View File

@@ -35,7 +35,7 @@ export async function uploadMongoImg({
shareId
});
return `${process.env.FE_DOMAIN || ''}${imageBaseUrl}${String(_id)}.${extension}`;
return `${process.env.FE_DOMAIN || ''}${process.env.NEXT_PUBLIC_BASE_URL || ''}${imageBaseUrl}${String(_id)}.${extension}`;
}
export async function readMongoImg({ id }: { id: string }) {

View File

@@ -0,0 +1,20 @@
import { TrackSchemaType } from '@fastgpt/global/common/middle/tracks/type';
import { getMongoModel, Schema } from '../../mongo';
import { TrackEnum } from '@fastgpt/global/common/middle/tracks/constants';
const TrackSchema = new Schema({
event: { type: String, required: true, enum: Object.values(TrackEnum) },
uid: String,
teamId: String,
tmbId: String,
createTime: { type: Date, default: () => new Date() },
data: Object
});
try {
TrackSchema.index({ event: 1 });
} catch (error) {
console.log(error);
}
export const TrackModel = getMongoModel<TrackSchemaType>('track', TrackSchema);

View File

@@ -0,0 +1,62 @@
import { PushTrackCommonType } from '@fastgpt/global/common/middle/tracks/type';
import { TrackModel } from './schema';
import { TrackEnum } from '@fastgpt/global/common/middle/tracks/constants';
import { addLog } from '../../system/log';
import { OAuthEnum } from '@fastgpt/global/support/user/constant';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { getAppLatestVersion } from '../../../core/app/version/controller';
const createTrack = ({ event, data }: { event: TrackEnum; data: Record<string, any> }) => {
if (!global.feConfigs?.isPlus) return;
addLog.info('Push tracks', {
event,
...data
});
const { uid, teamId, tmbId, ...props } = data;
return TrackModel.create({
event,
uid,
teamId,
tmbId,
data: props
});
};
export const pushTrack = {
login: (data: PushTrackCommonType & { type: `${OAuthEnum}` | 'password' }) => {
return createTrack({
event: TrackEnum.login,
data
});
},
createApp: (data: PushTrackCommonType & { type: AppTypeEnum }) => {
return createTrack({
event: TrackEnum.createApp,
data
});
},
createDataset: (data: PushTrackCommonType & { type: DatasetTypeEnum }) => {
return createTrack({
event: TrackEnum.createDataset,
data
});
},
countAppNodes: async (data: PushTrackCommonType & { appId: string }) => {
try {
const { nodes } = await getAppLatestVersion(data.appId);
const nodeTypeList = nodes.map((node) => ({
type: node.flowNodeType,
pluginId: node.pluginId
}));
return createTrack({
event: TrackEnum.appNodes,
data: {
...data,
nodeTypeList
}
});
} catch (error) {}
}
};

View File

@@ -3,29 +3,30 @@ import { createChatCompletion } from '../config';
import { countGptMessagesTokens } from '../../../common/string/tiktoken/index';
import { loadRequestMessages } from '../../chat/utils';
import { llmCompletionsBodyFormat } from '../utils';
export const Prompt_QuestionGuide = `You are an AI assistant tasked with predicting the user's next question based on the conversation history. Your goal is to generate 3 potential questions that will guide the user to continue the conversation. When generating these questions, adhere to the following rules:
1. Use the same language as the user's last question in the conversation history.
2. Keep each question under 20 characters in length.
3. Return the questions in JSON format: ["question1", "question2", "question3"].
Analyze the conversation history provided to you and use it as context to generate relevant and engaging follow-up questions. Your predictions should be logical extensions of the current topic or related areas that the user might be interested in exploring further.
Remember to maintain consistency in tone and style with the existing conversation while providing diverse options for the user to choose from. Your goal is to keep the conversation flowing naturally and help the user delve deeper into the subject matter or explore related topics.`;
import {
PROMPT_QUESTION_GUIDE,
PROMPT_QUESTION_GUIDE_FOOTER
} from '@fastgpt/global/core/ai/prompt/agent';
import { addLog } from '../../../common/system/log';
import json5 from 'json5';
export async function createQuestionGuide({
messages,
model
model,
customPrompt
}: {
messages: ChatCompletionMessageParam[];
model: string;
}) {
customPrompt?: string;
}): Promise<{
result: string[];
tokens: number;
}> {
const concatMessages: ChatCompletionMessageParam[] = [
...messages,
{
role: 'user',
content: Prompt_QuestionGuide
content: `${customPrompt || PROMPT_QUESTION_GUIDE}\n${PROMPT_QUESTION_GUIDE_FOOTER}`
}
];
@@ -53,6 +54,7 @@ export async function createQuestionGuide({
const tokens = await countGptMessagesTokens(concatMessages);
if (start === -1 || end === -1) {
addLog.warn('Create question guide error', { answer });
return {
result: [],
tokens: 0
@@ -66,10 +68,12 @@ export async function createQuestionGuide({
try {
return {
result: JSON.parse(jsonStr),
result: json5.parse(jsonStr),
tokens
};
} catch (error) {
console.log(error);
return {
result: [],
tokens: 0

View File

@@ -11,7 +11,7 @@ export const AppCollectionName = 'apps';
export const chatConfigType = {
welcomeText: String,
variables: Array,
questionGuide: Boolean,
questionGuide: Object,
ttsConfig: Object,
whisperConfig: Object,
scheduledTriggerConfig: Object,

View File

@@ -72,6 +72,7 @@ const ChatSchema = new Schema({
type: Object,
default: {}
},
pluginInputs: Array,
metadata: {
//For special storage
type: Object,

View File

@@ -10,6 +10,7 @@ import { getAppChatConfig, getGuideModule } from '@fastgpt/global/core/workflow/
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
import { mergeChatResponseData } from '@fastgpt/global/core/chat/utils';
import { pushChatLog } from './pushChatLog';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
type Props = {
chatId: string;
@@ -62,6 +63,9 @@ export async function saveChat({
systemConfigNode: getGuideModule(nodes),
isPublicFetch: false
});
const pluginInputs = nodes?.find(
(node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput
)?.inputs;
await mongoSessionRun(async (session) => {
const [{ _id: chatItemIdHuman }, { _id: chatItemIdAi }] = await MongoChatItem.insertMany(
@@ -89,6 +93,7 @@ export async function saveChat({
variableList,
welcomeText,
variables: variables || {},
pluginInputs,
title: newTitle,
source,
shareId,

View File

@@ -7,8 +7,9 @@ import { TextSplitProps, splitText2Chunks } from '@fastgpt/global/common/string/
import axios from 'axios';
import { readRawContentByFileBuffer } from '../../common/file/read/utils';
import { parseFileExtensionFromUrl } from '@fastgpt/global/common/string/tools';
import { APIFileServer } from '@fastgpt/global/core/dataset/apiDataset';
import { APIFileServer, FeishuServer, YuqueServer } from '@fastgpt/global/core/dataset/apiDataset';
import { useApiDatasetRequest } from './apiDataset/api';
import { POST } from '../../common/api/plusRequest';
export const readFileRawTextByUrl = async ({
teamId,
@@ -53,7 +54,9 @@ export const readDatasetSourceRawText = async ({
isQAImport,
selector,
externalFileId,
apiServer
apiServer,
feishuServer,
yuqueServer
}: {
teamId: string;
type: DatasetSourceReadTypeEnum;
@@ -63,6 +66,8 @@ export const readDatasetSourceRawText = async ({
selector?: string; // link selector
externalFileId?: string; // external file dataset
apiServer?: APIFileServer; // api dataset
feishuServer?: FeishuServer; // feishu dataset
yuqueServer?: YuqueServer; // yuque dataset
}): Promise<string> => {
if (type === DatasetSourceReadTypeEnum.fileLocal) {
const { rawText } = await readFileContentFromMongo({
@@ -88,28 +93,45 @@ export const readDatasetSourceRawText = async ({
});
return rawText;
} else if (type === DatasetSourceReadTypeEnum.apiFile) {
if (!apiServer) return Promise.reject('apiServer not found');
const rawText = await readApiServerFileContent({
apiServer,
feishuServer,
yuqueServer,
apiFileId: sourceId,
teamId
});
return rawText;
}
return '';
};
export const readApiServerFileContent = async ({
apiServer,
feishuServer,
yuqueServer,
apiFileId,
teamId
}: {
apiServer: APIFileServer;
apiServer?: APIFileServer;
feishuServer?: FeishuServer;
yuqueServer?: YuqueServer;
apiFileId: string;
teamId: string;
}) => {
return useApiDatasetRequest({ apiServer }).getFileContent({ teamId, apiFileId });
if (apiServer) {
return useApiDatasetRequest({ apiServer }).getFileContent({ teamId, apiFileId });
}
if (feishuServer || yuqueServer) {
return POST<string>(`/core/dataset/systemApiDataset`, {
type: 'content',
feishuServer,
yuqueServer,
apiFileId
});
}
return Promise.reject('No apiServer or feishuServer or yuqueServer');
};
export const rawText2Chunks = ({

View File

@@ -90,6 +90,12 @@ const DatasetSchema = new Schema({
apiServer: {
type: Object
},
feishuServer: {
type: Object
},
yuqueServer: {
type: Object
},
autoSync: Boolean,

View File

@@ -42,8 +42,7 @@ import {
filterWorkflowEdges,
checkNodeRunStatus,
textAdaptGptResponse,
replaceEditorVariable,
formatVariableValByType
replaceEditorVariable
} from '@fastgpt/global/core/workflow/runtime/utils';
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
import { dispatchRunTools } from './agent/runTool/index';
@@ -73,7 +72,6 @@ import { dispatchLoopEnd } from './loop/runLoopEnd';
import { dispatchLoopStart } from './loop/runLoopStart';
import { dispatchFormInput } from './interactive/formInput';
import { dispatchToolParams } from './agent/runTool/toolParams';
import { AppChatConfigType } from '@fastgpt/global/core/app/type';
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
@@ -635,7 +633,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
const entryNodes = runtimeNodes.filter((item) => item.isEntry);
// reset entry
runtimeNodes.forEach((item) => {
// Interactive node is not the entry node, return interactive result
// Interactively nodes will use the "isEntry", which does not need to be updated
if (
item.flowNodeType !== FlowNodeTypeEnum.userSelect &&
item.flowNodeType !== FlowNodeTypeEnum.formInput &&

View File

@@ -172,7 +172,7 @@ export async function authDatasetCollection({
collection: CollectionWithDatasetType;
}
> {
const { teamId, tmbId, isRoot: isRootFromHeader } = await parseHeaderCert(props);
const { teamId, tmbId, userId, isRoot: isRootFromHeader } = await parseHeaderCert(props);
const collection = await getCollectionWithDataset(collectionId);
if (!collection) {
@@ -187,6 +187,7 @@ export async function authDatasetCollection({
});
return {
userId,
teamId,
tmbId,
collection,

View File

@@ -24,6 +24,7 @@ type authModeType = {
export type AuthModeType = RequireAtLeastOne<authModeType, 'authApiKey' | 'authRoot' | 'authToken'>;
export type AuthResponseType<T extends Permission = Permission> = {
userId: string;
teamId: string;
tmbId: string;
authType?: `${AuthUserTypeEnum}`;

View File

@@ -49,11 +49,7 @@ const UserSchema = new Schema({
type: String,
default: defaultAvatars[Math.floor(Math.random() * defaultAvatars.length)]
},
inviterId: {
// 谁邀请注册的
type: Schema.Types.ObjectId,
ref: userCollectionName
},
promotionRate: {
type: Number,
default: 15
@@ -71,9 +67,14 @@ const UserSchema = new Schema({
lastLoginTmbId: {
type: Schema.Types.ObjectId
},
fastgpt_sem: {
type: Object
}
inviterId: {
// 谁邀请注册的
type: Schema.Types.ObjectId,
ref: userCollectionName
},
fastgpt_sem: Object,
sourceDomain: String
});
try {

View File

@@ -91,6 +91,7 @@ export const iconPaths = {
'common/voiceLight': () => import('./icons/common/voiceLight.svg'),
'common/warn': () => import('./icons/common/warn.svg'),
'common/wechatFill': () => import('./icons/common/wechatFill.svg'),
'common/dingtalkFill': () => import('./icons/common/dingtalkFill.svg'),
configmap: () => import('./icons/configmap.svg'),
copy: () => import('./icons/copy.svg'),
'core/app/aiFill': () => import('./icons/core/app/aiFill.svg'),
@@ -169,6 +170,9 @@ export const iconPaths = {
import('./icons/core/dataset/externalDatasetColor.svg'),
'core/dataset/externalDatasetOutline': () =>
import('./icons/core/dataset/externalDatasetOutline.svg'),
'core/dataset/feishuDatasetColor': () => import('./icons/core/dataset/feishuDatasetColor.svg'),
'core/dataset/feishuDatasetOutline': () =>
import('./icons/core/dataset/feishuDatasetOutline.svg'),
'core/dataset/fileCollection': () => import('./icons/core/dataset/fileCollection.svg'),
'core/dataset/fullTextRecall': () => import('./icons/core/dataset/fullTextRecall.svg'),
'core/dataset/manualCollection': () => import('./icons/core/dataset/manualCollection.svg'),
@@ -182,6 +186,8 @@ export const iconPaths = {
'core/dataset/websiteDatasetColor': () => import('./icons/core/dataset/websiteDatasetColor.svg'),
'core/dataset/websiteDatasetOutline': () =>
import('./icons/core/dataset/websiteDatasetOutline.svg'),
'core/dataset/yuqueDatasetColor': () => import('./icons/core/dataset/yuqueDatasetColor.svg'),
'core/dataset/yuqueDatasetOutline': () => import('./icons/core/dataset/yuqueDatasetOutline.svg'),
'core/modules/basicNode': () => import('./icons/core/modules/basicNode.svg'),
'core/modules/fixview': () => import('./icons/core/modules/fixview.svg'),
'core/modules/flowLight': () => import('./icons/core/modules/flowLight.svg'),
@@ -250,6 +256,7 @@ export const iconPaths = {
'core/workflow/template/formInput': () => import('./icons/core/workflow/template/formInput.svg'),
'core/workflow/template/getTime': () => import('./icons/core/workflow/template/getTime.svg'),
'core/workflow/template/google': () => import('./icons/core/workflow/template/google.svg'),
'core/workflow/template/searxng': () => import('./icons/core/workflow/template/searxng.svg'),
'core/workflow/template/httpRequest': () =>
import('./icons/core/workflow/template/httpRequest.svg'),
'core/workflow/template/ifelse': () => import('./icons/core/workflow/template/ifelse.svg'),
@@ -341,7 +348,9 @@ export const iconPaths = {
'phoneTabbar/me': () => import('./icons/phoneTabbar/me.svg'),
'phoneTabbar/tool': () => import('./icons/phoneTabbar/tool.svg'),
'phoneTabbar/toolFill': () => import('./icons/phoneTabbar/toolFill.svg'),
'plugins/dingding': () => import('./icons/plugins/dingding.svg'),
'plugins/doc2x': () => import('./icons/plugins/doc2x.svg'),
'plugins/qiwei': () => import('./icons/plugins/qiwei.svg'),
'plugins/textEditor': () => import('./icons/plugins/textEditor.svg'),
point: () => import('./icons/point.svg'),
preview: () => import('./icons/preview.svg'),

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1734408223570" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1236" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M512.00341333 19.34222222C239.90613333 19.34222222 19.34222222 239.90613333 19.34222222 512.00341333 19.34222222 784.09386667 239.90613333 1004.65777778 512.00341333 1004.65777778 784.09386667 1004.65777778 1004.65777778 784.09386667 1004.65777778 512.00341333 1004.65777778 239.90613333 784.09386667 19.34222222 512.00341333 19.34222222z m227.64088889 426.68259556c-0.98645333 4.28259555-3.54645333 10.63480889-7.09290667 18.21809777h0.09898667l-0.39480889 0.73728c-20.68821333 44.21404445-74.67349333 130.96732445-74.67349333 130.96732445l-0.24462222-0.59164445-15.76504889 27.47392h76.00355556L572.37390222 815.78666667l32.99783111-131.26314667h-59.84483555l20.7872-86.80106667c-16.7936 4.03911111-36.69674667 9.59829333-60.23964445 17.18044445 0 0-31.82023111 18.61404445-91.71285333-35.84 0 0-40.39224889-35.60106667-16.94264889-44.46208 9.94872889-3.7888 48.31687111-8.61639111 78.51121778-12.65436445 40.88035555-5.51253333 65.95128889-8.46620445 65.95128889-8.46620444s-125.84618667 1.86936889-155.69464889-2.80803556c-29.85187555-4.67626667-67.72622222-54.50524445-75.80558222-98.27783111 0 0-12.46208-24.02645333 26.84586666-12.65436444 39.30680889 11.37777778 201.99537778 44.31644445 201.99537778 44.31644444s-211.55043555-64.84423111-225.6896-80.70144c-14.08682667-15.75367111-41.42193778-86.35960889-37.87548444-129.68504889 0 0 1.52803555-10.83278222 12.66005333-7.88024888 0 0 156.43306667 71.39555555 263.36711111 110.53738666 106.98296889 39.14296889 199.97582222 59.0336 187.96088889 109.69770667z" fill="#3AA2EB" p-id="1237"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1 +1,10 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1698504394130" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4081" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M928 448h-64a19.2 19.2 0 0 1 0-38.4h64a19.2 19.2 0 0 1 0 38.4zM797.1072 738.4064l-45.2608-45.2608a19.2 19.2 0 0 1 27.1488-27.1488l45.3248 45.2608a19.2 19.2 0 0 1-27.2128 27.1488zM779.008 204.4032a19.2 19.2 0 0 1-27.1488-27.1488l45.2608-45.2608a19.2 19.2 0 0 1 27.2 27.1488z m-121.216 472.0128a282.368 282.368 0 0 0-17.2032 77.5808v20.8A37.7856 37.7856 0 0 1 614.4 810.6752V819.2H409.6v-8.5248a37.7856 37.7856 0 0 1-26.1888-35.84v-23.9488a290.0352 290.0352 0 0 0-16.9344-74.24A279.04 279.04 0 0 1 243.2 443.5968C243.2 290.56 363.52 166.4 512 166.4s268.8 124.16 268.8 277.1968a279.04 279.04 0 0 1-123.008 232.8192zM505.6 691.2a19.2 19.2 0 1 0-19.2-19.2 19.2 19.2 0 0 0 19.2 19.2z m6.4-358.4a115.2 115.2 0 0 0-114.4448 102.4h6.5024a17.728 17.728 0 1 0 20.9024 0h8.6656A79.8848 79.8848 0 0 1 512 368.64a77.7216 77.7216 0 0 1 76.8 79.36c0.8064 45.6064-64 76.8-64 76.8a97.4976 97.4976 0 0 0-34.432 46.4768 18.7392 18.7392 0 0 0-3.968 11.1232v7.68a56.6784 56.6784 0 0 0 0 11.52v6.4a19.2 19.2 0 0 0 38.4 0v-14.4768a18.6496 18.6496 0 0 1 0.384-4.6336C533.3632 557.9904 588.8 524.8 588.8 524.8c36.2368-23.296 38.4-76.8 38.4-76.8a115.2 115.2 0 0 0-115.2-115.2z m6.4-230.4A19.2 19.2 0 0 1 499.2 83.2v-64a19.2 19.2 0 1 1 38.4 0v64A19.2 19.2 0 0 1 518.4 102.4z m-264.3456 92.9536l-45.2608-45.2608A19.2 19.2 0 1 1 235.9424 122.88l45.2608 45.248a19.2 19.2 0 0 1-27.1488 27.2256zM160 448h-64a19.2 19.2 0 0 1 0-38.4h64a19.2 19.2 0 0 1 0 38.4z m94.0544 227.0464a19.2 19.2 0 0 1 27.1488 27.1488L235.9424 747.52a19.2 19.2 0 0 1-27.1488-27.1488zM652.8 846.9376a8.384 8.384 0 0 1 0.384 1.9072V870.4a8.4096 8.4096 0 0 1-0.384 1.9072V883.2H371.2v-51.2h281.6v14.9376zM627.2 947.2H396.8v-51.2h230.4v51.2z m-183.6672 23.9104H579.84a8.5248 8.5248 0 0 1 4.8896 1.6896H601.6v38.4H422.4v-38.4h16.2432a8.5248 8.5248 0 0 1 4.8896-1.6896z" fill="#1296db" p-id="4082"></path></svg>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.13063 2.05868C9.13063 1.57855 9.51985 1.18933 9.99998 1.18933C10.4801 1.18933 10.8693 1.57855 10.8693 2.05868V3.21982C10.8693 3.69994 10.4801 4.08916 9.99998 4.08916C9.51985 4.08916 9.13063 3.69994 9.13063 3.21982V2.05868Z" fill="#219BF4"/>
<path d="M3.38076 9.1859C3.86089 9.1859 4.25011 9.57512 4.25011 10.0552C4.25011 10.5354 3.86089 10.9246 3.38076 10.9246H2.22333C1.74321 10.9246 1.35399 10.5354 1.35399 10.0552C1.35399 9.57512 1.74321 9.1859 2.22333 9.1859H3.38076Z" fill="#219BF4"/>
<path d="M17.7767 9.1859C18.2568 9.1859 18.646 9.57512 18.646 10.0552C18.646 10.5354 18.2568 10.9246 17.7767 10.9246H16.6144C16.1342 10.9246 15.745 10.5354 15.745 10.0552C15.745 9.57512 16.1342 9.1859 16.6144 9.1859H17.7767Z" fill="#219BF4"/>
<path d="M11.9605 15.5135C12.3425 15.5135 12.6522 15.8231 12.6522 16.2051C12.6522 16.5871 12.3425 16.8968 11.9605 16.8968H8.01907C7.63707 16.8968 7.3274 16.5871 7.3274 16.2051C7.3274 15.8231 7.63707 15.5135 8.01907 15.5135H11.9605Z" fill="#219BF4"/>
<path d="M10.9742 17.5941C11.3102 17.5941 11.5825 17.8664 11.5825 18.2024C11.5825 18.5384 11.3102 18.8107 10.9742 18.8107H9.00533C8.66936 18.8107 8.397 18.5384 8.397 18.2024C8.397 17.8664 8.66936 17.5941 9.00533 17.5941H10.9742Z" fill="#219BF4"/>
<path d="M14.8373 9.83534C14.8373 12.5069 12.6715 14.6726 10 14.6726C7.32845 14.6726 5.16274 12.5069 5.16274 9.83534C5.16274 7.16379 7.32845 4.99808 10 4.99808C12.6715 4.99808 14.8373 7.16379 14.8373 9.83534Z" fill="#219BF4"/>
<path d="M15.3181 5.79775C14.9786 6.13725 14.4282 6.13725 14.0887 5.79775C13.7492 5.45825 13.7492 4.90781 14.0887 4.56831L14.9091 3.7479C15.2486 3.4084 15.799 3.4084 16.1385 3.7479C16.478 4.0874 16.478 4.63784 16.1385 4.97734L15.3181 5.79775Z" fill="#219BF4"/>
<path d="M4.68184 5.80161C5.02134 6.14111 5.57178 6.14111 5.91128 5.80161C6.25078 5.46211 6.25078 4.91167 5.91128 4.57217L5.09091 3.7518C4.75141 3.4123 4.20097 3.4123 3.86147 3.7518C3.52197 4.0913 3.52197 4.64174 3.86147 4.98124L4.68184 5.80161Z" fill="#219BF4"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1 @@
<svg t="1733810815616" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8843" width="200" height="200"><path d="M816.512 399.317333c-42.965333 5.205333-105.6 32.341333-186.666667 127.658667L597.333333 499.328l32.512 27.648C559.36 609.834667 462.848 661.333333 362.666667 661.333333a42.666667 42.666667 0 1 1 0-85.333333c70.485333 0 144.64-36.650667 202.154666-104.32 89.6-105.344 170.154667-148.48 241.450667-157.098667 66.816-8.106667 117.845333 15.616 145.706667 28.586667l4.48 2.048a42.666667 42.666667 0 0 1 2.645333 76.245333c-41.045333 22.357333-55.552 64.853333-81.365333 141.226667-24.32 71.850667-56.576 161.706667-146.090667 237.824-107.946667 91.776-222.890667 117.162667-326.442667 116.821333-151.210667-0.469333-281.173333-74.88-347.008-129.066666A42.666667 42.666667 0 0 1 42.666667 755.328V362.666667a42.666667 42.666667 0 0 1 85.333333 0v371.882666c59.861333 44.458667 162.986667 97.109333 277.461333 97.450667 88.192 0.256 181.845333-20.778667 270.933334-96.512 70.485333-59.946667 96.853333-130.048 120.533333-200.149333l4.352-13.056c13.44-40.277333 28.288-84.906667 55.893333-122.026667a140.8 140.8 0 0 0-40.661333-0.938667z" p-id="8844"></path><path d="M120.490667 338.474667a42.666667 42.666667 0 1 0-70.314667 48.384l70.314667-48.384z m647.552 423.765333a42.666667 42.666667 0 1 0-42.752-73.813333L768 762.197333zM50.176 386.858667c61.696 89.685333 180.224 213.546667 310.058667 300.586666 65.024 43.562667 135.04 79.402667 204.032 96.170667 69.205333 16.853333 140.714667 15.146667 203.776-21.333333l-42.752-73.898667c-38.272 22.186667-85.461333 25.813333-140.885334 12.330667-55.68-13.568-116.352-43.733333-176.64-84.138667-120.832-80.981333-231.637333-197.12-287.274666-278.101333L50.176 386.858667z" p-id="8845"></path><path d="M208 132.864a42.666667 42.666667 0 0 1 39.338667-26.197333h341.333333a42.666667 42.666667 0 0 1 28.586667 10.965333c78.08 70.4 123.306667 180.906667 139.946666 231.68a42.666667 42.666667 0 1 1-81.066666 26.666667c-14.506667-44.16-50.048-128.256-104.576-183.978667H357.717333c25.045333 22.016 52.650667 46.506667 80.554667 73.344 63.36 61.013333 130.133333 135.978667 175.914667 227.584a42.666667 42.666667 0 0 1-76.373334 38.144c-39.509333-79.061333-98.432-146.218667-158.72-204.245333a2505.642667 2505.642667 0 0 0-87.893333-79.658667l-0.896-0.768c-27.050667-23.722667-52.906667-46.378667-73.344-67.114667a42.666667 42.666667 0 0 1-8.96-46.421333z" p-id="8846"></path></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

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