Commit bd79e770 by Archer Committed by GitHub

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>
parent 82871be0
......@@ -10,14 +10,20 @@ weight: 808
## 完整更新内容
1.
1. 新增 - SearXNG 搜索插件[点击查看教程](/docs/guide/plugins/searxng_plugin_guide/)
2. 新增 - 商业版支持 API 知识库和链接集合定时同步。
3. 新增 - 猜你想问支持选择模型和自定义提示词。
4. 新增 - 钉钉和企微机器人 webhook 插件。
5. 新增 - sandbox 新增 createHmac 加密全局方法。
6. 优化 - 工作流/简易模式变量初始化代码,去除监听初始化,避免因渲染顺序不一致导致的失败。
7. 修复 - 无法自动切换默认语言。增加分享链接,强制执行一次切换默认语言。
8. 修复 - 数组选择器自动兼容 4.8.13 以前的数据。
9. 修复 - 站点同步知识库,链接同步时未使用选择器。
10. 修复 - 简易模式转工作流,没有把系统配置项转化。
11. 修复 - 插件独立运行,变量初始值未赋上。
\ No newline at end of file
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. 修复 - 插件调试时,日志未保存插件输入参数。
\ No newline at end of file
---
weight: 490
title: '商业版后台'
description: '商业版后台使用教程'
icon: 'chat_bubble'
draft: false
images: []
---
<!-- 470 ~ 500 -->
---
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)
\ No newline at end of file
---
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)
\ No newline at end of file
---
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)
\ No newline at end of file
---
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 调用时不会返回结果。
\ No newline at end of file
---
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)
......@@ -12,7 +12,8 @@ export enum DatasetErrEnum {
unLinkCollection = 'unLinkCollection',
invalidVectorModelOrQAModel = 'invalidVectorModelOrQAModel',
notSupportSync = 'notSupportSync',
sameApiCollection = 'sameApiCollection'
sameApiCollection = 'sameApiCollection',
noApiServer = 'noApiServer'
}
const datasetErr = [
{
......
export enum TrackEnum {
login = 'login',
createApp = 'createApp',
useAppTemplate = 'useAppTemplate',
createDataset = 'createDataset',
appNodes = 'appNodes'
}
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>;
};
......@@ -63,6 +63,7 @@ export type FastGPTFeConfigsType = {
github?: string;
google?: string;
wechat?: string;
dingtalk?: string;
microsoft?: {
clientId?: string;
tenantId?: string;
......
......@@ -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>;
};
......
......@@ -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;
......
......@@ -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;
};
......@@ -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'
}
};
......
......@@ -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;
......
......@@ -3,6 +3,7 @@ export enum PublishChannelEnum {
iframe = 'iframe',
apikey = 'apikey',
feishu = 'feishu',
dingtalk = 'dingtalk',
wecom = 'wecom',
officialAccount = 'official_account'
}
......@@ -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;
......
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;
......
......@@ -16,5 +16,6 @@ export enum OAuthEnum {
google = 'google',
wechat = 'wechat',
microsoft = 'microsoft',
dingtalk = 'dingtalk',
sso = 'sso'
}
......@@ -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;
......@@ -12,6 +12,7 @@ export type CreateTeamProps = {
avatar?: string;
defaultTeam?: boolean;
lafAccount?: LafAccountType;
memberName?: string;
};
export type UpdateTeamProps = {
name?: string;
......
......@@ -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')
}
};
......@@ -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;
}
......
......@@ -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",
......
......@@ -27,7 +27,8 @@ const packagePluginList = [
'wiki',
'databaseConnection',
'Doc2X',
'Doc2X/PDF2text'
'Doc2X/PDF2text',
'searchXNG'
];
export const list = [...staticPluginList, ...packagePluginList];
......
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;
{
"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"
}
}
}
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);
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) {}
}
};
......@@ -72,6 +72,7 @@ const ChatSchema = new Schema({
type: Object,
default: {}
},
pluginInputs: Array,
metadata: {
//For special storage
type: Object,
......
......@@ -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,
......
......@@ -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 = ({
......
......@@ -90,6 +90,12 @@ const DatasetSchema = new Schema({
apiServer: {
type: Object
},
feishuServer: {
type: Object
},
yuqueServer: {
type: Object
},
autoSync: Boolean,
......
......@@ -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';
......
......@@ -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,
......
......@@ -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}`;
......
......@@ -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 {
......
......@@ -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'),
......
<?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>
\ No newline at end of file
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="32" height="32" fill="url(#paint0_linear_15107_489)"/>
<g clip-path="url(#clip0_15107_489)">
<path d="M21.8638 13.1662C21.805 13.169 21.7896 13.1424 21.784 13.0864C21.777 13.0276 21.7812 12.9562 21.7518 12.91C21.6958 12.8218 21.7112 12.7182 21.6636 12.6272C21.6366 12.5793 21.6177 12.5272 21.6076 12.4732C21.6048 12.4396 21.6132 12.3948 21.5894 12.378C21.539 12.3416 21.5586 12.2814 21.5264 12.2338C21.4914 12.182 21.4886 12.1078 21.462 12.0448C21.434 11.979 21.4018 11.909 21.3948 11.8362C21.392 11.8012 21.3528 11.7998 21.3528 11.7648C21.357 11.706 21.3136 11.657 21.2996 11.601C21.28 11.5268 21.238 11.454 21.21 11.3812C21.1884 11.322 21.1637 11.2641 21.1358 11.2076C21.0952 11.1278 21.0616 11.0466 21.0154 10.9682C20.9706 10.8982 20.9594 10.81 20.9104 10.7344C20.8708 10.6721 20.8366 10.6065 20.8082 10.5384C20.762 10.4292 20.6934 10.334 20.6402 10.2304C20.5896 10.1275 20.535 10.0266 20.4764 9.928C20.4204 9.8342 20.3714 9.7348 20.3056 9.6438C20.279 9.606 20.2384 9.5696 20.2314 9.5276C20.2216 9.4674 20.1754 9.424 20.1474 9.3876C20.1068 9.3414 20.1054 9.256 20.027 9.2378C20.027 9.2378 20.0242 9.2308 20.0256 9.2266C20.0312 9.1636 19.9416 9.1454 19.95 9.0796C19.88 9.0558 19.901 8.955 19.8226 8.9354C19.8226 8.9354 19.8184 8.9298 19.8198 8.927C19.8268 8.8626 19.7638 8.8276 19.7372 8.7856C19.7016 8.73216 19.6613 8.68203 19.6168 8.6358C19.5958 8.6134 19.5608 8.5938 19.5538 8.5658C19.5258 8.4706 19.4348 8.423 19.3886 8.339C19.3452 8.262 19.2696 8.2116 19.2108 8.1472C19.1535 8.07963 19.0824 8.02519 19.0022 7.9876C18.928 7.9596 18.8678 7.898 18.7782 7.8924C18.6858 7.8882 18.5976 7.8336 18.501 7.8364C18.501 7.8154 18.494 7.8 18.4688 7.8H8.77098C8.74438 7.8 8.73878 7.8154 8.73878 7.8364C8.67438 7.8322 8.63938 7.8854 8.61838 7.9232C8.57078 8.0072 8.63938 8.1626 8.73178 8.2004C8.77098 8.2144 8.79198 8.2424 8.81858 8.2676C8.83258 8.2816 8.84658 8.304 8.86618 8.3012C8.90538 8.297 8.92218 8.325 8.93338 8.3474C8.94738 8.3782 8.97538 8.3894 8.99778 8.4006C9.06573 8.43549 9.12841 8.4798 9.18398 8.5322C9.26658 8.6092 9.35898 8.6722 9.44998 8.738C9.52418 8.7926 9.58438 8.864 9.66698 8.9088C9.72858 8.941 9.76218 9.0124 9.82098 9.0418C9.90498 9.0838 9.95118 9.1636 10.031 9.2042C10.0788 9.23218 10.1207 9.26928 10.1542 9.3134C10.1864 9.3498 10.2438 9.3526 10.2704 9.389C10.3446 9.501 10.4734 9.5514 10.5616 9.6522C10.647 9.7502 10.7688 9.809 10.8584 9.9126C10.9648 10.0358 11.1076 10.1226 11.2224 10.2388C11.3036 10.3186 11.3848 10.3928 11.466 10.4698C11.5304 10.53 11.5948 10.5888 11.655 10.6518C11.6998 10.6966 11.7572 10.7316 11.7992 10.7708C11.9028 10.8716 12.0232 10.9612 12.096 11.0914L12.1114 11.111C12.1912 11.1852 12.271 11.2608 12.3494 11.3378C12.4446 11.433 12.537 11.5366 12.6406 11.6276C12.6837 11.6591 12.7199 11.6992 12.747 11.7452C12.768 11.7942 12.803 11.825 12.8366 11.8572C12.9248 11.9412 13.02 12.0224 13.083 12.1316C13.1082 12.1764 13.1614 12.1918 13.188 12.2352C13.223 12.2898 13.2762 12.3276 13.3112 12.3864C13.363 12.4704 13.4512 12.5292 13.51 12.6174C13.5674 12.7042 13.6444 12.7868 13.7186 12.861C13.8012 12.945 13.8586 13.0458 13.9468 13.1214C13.993 13.1606 13.9972 13.2334 14.0574 13.2572C14.0868 13.2712 14.0966 13.2964 14.105 13.3174C14.1372 13.386 14.196 13.4336 14.2338 13.498C14.2702 13.561 14.3318 13.6016 14.3738 13.6646C14.4508 13.7822 14.539 13.8956 14.6342 14.0006C14.665 14.0356 14.6622 14.0902 14.707 14.107C14.7742 14.135 14.7854 14.2064 14.819 14.254C14.8652 14.317 14.9254 14.3702 14.959 14.4388C14.9954 14.5116 15.0556 14.5662 15.0934 14.6348C15.1298 14.695 15.1746 14.7496 15.211 14.8098C15.239 14.856 15.2642 14.9078 15.3034 14.9498C15.3454 14.9918 15.3594 15.0576 15.4098 15.0982C15.4546 15.1346 15.463 15.1934 15.505 15.2354C15.5484 15.283 15.5666 15.3544 15.6142 15.4006C15.6562 15.4398 15.6758 15.4944 15.7052 15.5406C15.7262 15.5728 15.7696 15.5924 15.7752 15.6358C15.7794 15.6834 15.8158 15.7128 15.8396 15.7478C15.876 15.8024 15.9236 15.8556 15.9446 15.9074C15.9838 16.004 16.0496 16.0768 16.0958 16.1636C16.1504 16.2588 16.2176 16.3554 16.2722 16.4548C16.3142 16.5262 16.3548 16.599 16.3996 16.6648C16.4192 16.6998 16.415 16.7446 16.4528 16.7698C16.4976 16.802 16.5074 16.8566 16.5326 16.9014C16.555 16.9406 16.5704 16.9896 16.6026 17.0162C16.6278 17.0386 16.6278 17.0582 16.6334 17.0862C16.6712 17.1002 16.6908 17.0708 16.7132 17.0498L16.8924 16.872L17.262 16.508C17.367 16.403 17.465 16.2924 17.5742 16.1916C17.766 16.0166 17.9424 15.8276 18.1342 15.6498C18.2588 15.5336 18.3708 15.4048 18.508 15.2998C18.6284 15.2088 18.7292 15.0926 18.8384 14.9862L19.0792 14.7454C19.1632 14.6614 19.271 14.6082 19.348 14.5186C19.3541 14.5098 19.3623 14.5026 19.3718 14.4976C19.453 14.4654 19.509 14.3996 19.5762 14.3506C19.6546 14.2946 19.733 14.2386 19.8086 14.1798C19.8478 14.149 19.8968 14.135 19.9304 14.1014C20.027 14.0048 20.1544 13.9614 20.2664 13.8942C20.3854 13.8242 20.5072 13.7542 20.6304 13.6954C20.72 13.6534 20.7984 13.5876 20.8936 13.5694C21.0056 13.5456 21.0854 13.4714 21.1904 13.4378C21.2226 13.4294 21.2618 13.4252 21.2912 13.4028C21.3514 13.3552 21.434 13.3552 21.5012 13.323C21.5334 13.3076 21.5698 13.2866 21.6062 13.281C21.6902 13.2712 21.763 13.232 21.8442 13.211C21.8652 13.2068 21.8834 13.1942 21.8638 13.1662Z" fill="#00D6B9"/>
<path d="M24.1668 19.028C24.1444 19.014 24.129 19.0336 24.115 19.0476C24.073 19.0868 24.0408 19.1372 24.0044 19.182L23.821 19.3976C23.695 19.5362 23.5578 19.6692 23.4206 19.7938C23.3128 19.8918 23.1938 19.9758 23.0776 20.0626C23.0356 20.0948 22.9922 20.1298 22.9474 20.1592C22.8984 20.1928 22.8564 20.2376 22.8032 20.26C22.7024 20.302 22.6128 20.365 22.519 20.4196C22.3566 20.5092 22.1872 20.5876 22.015 20.6548C21.917 20.6954 21.8204 20.7388 21.721 20.7696C21.6398 20.7948 21.5614 20.8298 21.4802 20.8494C21.4522 20.8564 21.4242 20.8536 21.3976 20.8634C21.3178 20.8928 21.2338 20.911 21.1498 20.932C21.0784 20.9502 21 20.9348 20.937 20.9642C20.8418 21.009 20.7326 20.967 20.643 21.0272C20.503 21.0272 20.3644 21.0412 20.2258 21.0538C19.9794 21.072 19.733 21.037 19.4866 21.03C19.3746 21.0272 19.2682 20.9712 19.1548 20.988C19.1514 20.9882 19.1481 20.9877 19.1449 20.9865C19.1418 20.9852 19.1389 20.9834 19.1366 20.981C19.1002 20.953 19.0568 20.953 19.0162 20.953C18.9294 20.953 18.8454 20.9348 18.7642 20.9194C18.6844 20.9026 18.6032 20.8718 18.5248 20.8452C18.4786 20.8298 18.4282 20.8382 18.3862 20.8172C18.3254 20.7882 18.2608 20.7679 18.1944 20.757C18.0404 20.7248 17.899 20.6604 17.7436 20.6352C17.6414 20.6184 17.5518 20.561 17.4496 20.54C17.3768 20.5232 17.3068 20.498 17.2382 20.4756C17.15 20.4476 17.0618 20.4168 16.9722 20.3944C16.8294 20.3552 16.6992 20.295 16.5592 20.2502C16.3926 20.1942 16.2316 20.1298 16.065 20.0738C15.967 20.0416 15.8802 19.9828 15.7738 19.966C15.7287 19.9582 15.6855 19.9421 15.6464 19.9184C15.568 19.8736 15.4784 19.8582 15.4 19.8204C15.3328 19.7868 15.2572 19.7714 15.1914 19.7392C15.0822 19.6832 14.9562 19.6664 14.8568 19.588C14.8497 19.5833 14.8414 19.5809 14.833 19.581C14.7532 19.5726 14.6818 19.5362 14.6118 19.5012C14.4606 19.427 14.2968 19.378 14.1484 19.2968C14.0294 19.231 13.8992 19.1932 13.7802 19.1288C13.7522 19.1232 13.7284 19.1288 13.7004 19.1148C13.6514 19.0896 13.6038 19.0504 13.5534 19.0364C13.4554 19.0098 13.3826 18.9384 13.286 18.9104C13.2314 18.895 13.1894 18.846 13.139 18.8334C13.0746 18.818 13.0214 18.7858 12.971 18.7564C12.887 18.7088 12.7946 18.6766 12.7092 18.6248C12.663 18.5954 12.6028 18.5856 12.5622 18.552C12.502 18.5016 12.4082 18.5044 12.3662 18.4274C12.264 18.419 12.1954 18.3406 12.1072 18.3042C12.0022 18.2622 11.9084 18.195 11.809 18.139C11.767 18.1152 11.7292 18.0718 11.6886 18.0648C11.5808 18.0424 11.5066 17.9654 11.417 17.9164C11.3123 17.8615 11.2109 17.8008 11.1132 17.7344C11.0964 17.7246 11.0726 17.726 11.0614 17.7134C10.9984 17.642 10.9074 17.6056 10.8276 17.5566C10.75 17.5109 10.673 17.4642 10.5966 17.4166C10.5014 17.3564 10.4048 17.2976 10.3152 17.2346C10.255 17.1912 10.1808 17.1646 10.129 17.1156C10.0912 17.0806 10.045 17.068 10.0058 17.0358C9.93578 16.9784 9.85318 16.9308 9.77758 16.879C9.74258 16.8552 9.69498 16.8328 9.67118 16.8062C9.62498 16.7558 9.56198 16.7292 9.51298 16.6886C9.43878 16.6256 9.34638 16.5822 9.27358 16.5164C9.23018 16.4786 9.16578 16.4716 9.13358 16.4184C9.12238 16.3974 9.10138 16.382 9.07338 16.375C9.02438 16.361 8.99078 16.3218 8.95158 16.2952C8.89278 16.2546 8.83958 16.2 8.77798 16.158C8.70518 16.109 8.64078 16.0432 8.56518 15.9984C8.48398 15.9494 8.42658 15.8724 8.34538 15.8262C8.29498 15.7954 8.26558 15.7394 8.21658 15.717C8.13118 15.6792 8.07938 15.6036 8.00098 15.5574C7.94078 15.5182 7.89878 15.4454 7.83438 15.4132C7.75878 15.3726 7.71398 15.3026 7.64678 15.2564C7.62858 15.2424 7.60478 15.2396 7.58798 15.2172C7.54598 15.1654 7.48578 15.1262 7.43678 15.08C7.38358 15.0324 7.31778 15.0002 7.26878 14.9428C7.23098 14.9008 7.19038 14.8448 7.14278 14.8252C7.06858 14.7972 7.03638 14.7328 6.97898 14.6908C6.90618 14.6404 6.85298 14.5662 6.78298 14.5102C6.73818 14.4752 6.68778 14.4472 6.65278 14.4024C6.59958 14.3352 6.53238 14.2778 6.47078 14.2204C6.39098 14.142 6.31398 14.0608 6.23278 13.9852C6.16838 13.9292 6.10958 13.8648 6.04378 13.806C5.98358 13.7528 5.92898 13.6912 5.86738 13.638C5.78618 13.5624 5.71198 13.4784 5.63638 13.4C5.56078 13.3216 5.47958 13.2474 5.40538 13.1662C5.34238 13.0948 5.27798 13.008 5.15478 13.0332C5.09318 13.0472 5.06518 13.085 5.04278 13.134C4.97978 13.141 5.00498 13.19 5.00498 13.2166V22.2774C5.00498 22.3138 5.00918 22.3488 5.00778 22.3838C5.00778 22.4118 5.01618 22.4244 5.04278 22.4258C5.02598 22.5098 5.08198 22.5756 5.09458 22.6526C5.10298 22.7086 5.13798 22.7534 5.15898 22.8052C5.18978 22.8752 5.24858 22.934 5.29058 23.0012C5.32765 23.0585 5.37513 23.1084 5.43058 23.1482C5.48938 23.1902 5.54818 23.2336 5.60978 23.2714C5.68398 23.3134 5.75398 23.3652 5.82258 23.4128C5.84358 23.4268 5.86738 23.4296 5.88978 23.4506C5.95816 23.5066 6.03344 23.5537 6.11378 23.5906C6.16698 23.6186 6.21738 23.655 6.27478 23.6788C6.40218 23.732 6.51138 23.8272 6.64298 23.879C6.71578 23.907 6.77178 23.9588 6.84738 23.9812C6.86418 23.9882 6.88518 23.9896 6.90058 23.9994C7.00558 24.0722 7.12458 24.1142 7.23938 24.1716C7.26318 24.1856 7.29398 24.1856 7.31218 24.1996C7.37293 24.2476 7.44459 24.2798 7.52078 24.2934C7.53478 24.2962 7.54598 24.2976 7.56138 24.3088C7.59218 24.3326 7.63138 24.3508 7.66918 24.3718C7.71118 24.3956 7.76578 24.3816 7.80358 24.4222C7.81758 24.439 7.85258 24.46 7.87918 24.4642C7.99118 24.4852 8.09478 24.5384 8.19978 24.579C8.23058 24.593 8.27258 24.579 8.29498 24.6042C8.33698 24.6462 8.39578 24.6462 8.44338 24.6672C8.51338 24.698 8.58758 24.7232 8.66738 24.7414C8.69958 24.7498 8.74578 24.7414 8.76678 24.7652C8.80738 24.81 8.86758 24.8128 8.91098 24.824C9.02578 24.852 9.13778 24.8884 9.24978 24.9262C9.33938 24.9584 9.44018 24.9654 9.53538 24.9934C9.61518 25.0158 9.69498 25.0424 9.77478 25.0564C9.81258 25.0634 9.86578 25.048 9.88678 25.0676C9.94838 25.1278 10.031 25.0928 10.0996 25.1264C10.1773 25.1595 10.2619 25.1729 10.346 25.1656C10.3628 25.1642 10.3866 25.16 10.395 25.1684C10.458 25.2328 10.5574 25.1684 10.619 25.2342C10.7618 25.2468 10.906 25.2538 11.0474 25.2944C11.1384 25.3224 11.2392 25.3084 11.3358 25.3294C11.452 25.3574 11.578 25.349 11.6998 25.3616C11.7796 25.3686 11.858 25.3658 11.9378 25.3672C11.9378 25.3924 11.9518 25.4022 11.977 25.4008H13.7046C13.7298 25.4008 13.7452 25.3924 13.7452 25.3672C13.937 25.377 14.126 25.3322 14.3164 25.3392H14.4214C14.448 25.3392 14.462 25.3294 14.4606 25.3028C14.546 25.2972 14.6314 25.2874 14.7168 25.2706C14.8512 25.2426 14.9912 25.2496 15.1256 25.2062C15.1928 25.1838 15.2698 25.188 15.3412 25.1698C15.4252 25.1502 15.5134 25.1278 15.6044 25.1348C15.6142 25.1348 15.6296 25.1348 15.6352 25.1306C15.68 25.0704 15.7542 25.0984 15.8144 25.0704C15.8797 25.0425 15.9506 25.0301 16.0216 25.034C16.0314 25.034 16.044 25.034 16.0538 25.0298C16.1165 24.9937 16.1862 24.9713 16.2582 24.964C16.3553 24.9496 16.4506 24.9247 16.5424 24.8898C16.6106 24.8651 16.6809 24.8463 16.7524 24.8338C16.7664 24.831 16.7846 24.831 16.793 24.8212C16.8336 24.7792 16.891 24.7792 16.9372 24.7652C17.0296 24.7414 17.1178 24.7064 17.2088 24.6784C17.2396 24.6714 17.2746 24.6798 17.2998 24.663C17.3706 24.6129 17.4521 24.5799 17.5378 24.5664C17.5518 24.566 17.5654 24.5616 17.577 24.5538C17.619 24.5286 17.6568 24.4978 17.71 24.4922C17.7828 24.4838 17.8542 24.4474 17.9172 24.4152C17.9732 24.3872 18.0334 24.3662 18.0894 24.3382C18.1314 24.3158 18.179 24.2878 18.2308 24.278C18.3064 24.2654 18.3568 24.201 18.4324 24.1842C18.4903 24.1696 18.5456 24.146 18.5962 24.1142C18.6774 24.0694 18.7628 24.0302 18.8454 23.991C18.8986 23.963 18.9588 23.9406 19.0022 23.9098C19.0676 23.8642 19.1375 23.8252 19.2108 23.7936C19.3032 23.7516 19.3858 23.6928 19.4768 23.6536C19.558 23.6158 19.6308 23.557 19.7092 23.5136C19.7498 23.4898 19.7862 23.4548 19.8254 23.4352C19.8688 23.4128 19.9122 23.3876 19.9528 23.361C20.0074 23.3232 20.0718 23.3008 20.118 23.2546C20.16 23.2126 20.216 23.1986 20.258 23.1608C20.3098 23.1174 20.3784 23.0964 20.426 23.0488C20.4428 23.032 20.4526 23.0166 20.475 23.0166C20.4873 23.0151 20.4991 23.0106 20.5094 23.0035C20.5196 22.9965 20.528 22.987 20.5338 22.976C20.549 22.9515 20.5715 22.9324 20.5982 22.9214C20.6738 22.8948 20.713 22.8234 20.783 22.787C20.8264 22.7674 20.8628 22.7268 20.9034 22.6974C20.9734 22.6498 21.0378 22.5994 21.1036 22.5476C21.14 22.5196 21.1722 22.4692 21.2086 22.458C21.2898 22.4328 21.3136 22.346 21.3878 22.3138C21.414 22.3008 21.4377 22.2833 21.4578 22.262C21.5138 22.199 21.5838 22.1472 21.6496 22.0856C21.6888 22.0436 21.7434 22.024 21.7826 21.9792C21.8277 21.9243 21.8779 21.8737 21.9324 21.828C21.9803 21.7884 22.0252 21.7454 22.0668 21.6992L22.3062 21.4612C22.386 21.3842 22.4616 21.3058 22.5414 21.2302C22.5891 21.1846 22.6323 21.1345 22.6702 21.0804C22.7114 21.0235 22.7599 20.9722 22.8144 20.9278C22.8564 20.8942 22.869 20.8438 22.9068 20.8088C22.964 20.762 23.0131 20.7062 23.0524 20.6436C23.0944 20.5694 23.1686 20.5232 23.2092 20.4476C23.2372 20.3944 23.2932 20.358 23.3268 20.3048C23.3618 20.2474 23.408 20.1956 23.4514 20.1438C23.499 20.0878 23.5536 20.0262 23.5858 19.9618C23.6194 19.8918 23.6796 19.8498 23.7118 19.7798C23.7473 19.717 23.7891 19.6579 23.8364 19.6034C23.8686 19.5628 23.8882 19.5194 23.9148 19.4774C23.9568 19.413 24.0016 19.3514 24.0464 19.2884C24.0632 19.2604 24.0674 19.2324 24.0912 19.2044C24.1332 19.1596 24.1822 19.1064 24.171 19.0322" fill="#3370FF"/>
<path d="M27.3672 13.582C27.3588 13.5694 27.349 13.5694 27.3364 13.5666C27.3 13.5554 27.2608 13.547 27.2286 13.5288C27.1935 13.5037 27.156 13.4821 27.1166 13.4644C27.0578 13.4406 26.9892 13.4322 26.9388 13.3972C26.8702 13.344 26.7848 13.3454 26.7106 13.3076C26.6581 13.2789 26.6014 13.2586 26.5426 13.2474C26.4992 13.2404 26.453 13.2194 26.4096 13.2054C26.3508 13.1872 26.2878 13.1662 26.2276 13.1494C26.1318 13.1263 26.037 13.0992 25.9434 13.0682C25.8792 13.0432 25.8106 13.0318 25.7418 13.0346C25.7264 12.9702 25.6732 13.008 25.6368 12.9996C25.5892 12.9996 25.5444 12.9758 25.4996 12.9688C25.354 12.9422 25.2056 12.938 25.0572 12.9044C24.941 12.8792 24.8136 12.8932 24.6932 12.8764C24.6204 12.8652 24.549 12.8722 24.4748 12.8708C24.4748 12.8428 24.4608 12.8358 24.4356 12.8358H23.7328C23.7076 12.8358 23.6922 12.8428 23.6922 12.8708C23.513 12.861 23.338 12.9002 23.1588 12.8988H23.0524C23.0272 12.8988 23.016 12.9086 23.0146 12.9324C22.9124 12.924 22.8158 12.9688 22.7136 12.9604C22.7071 12.9604 22.7008 12.9623 22.6954 12.966C22.617 13.022 22.5218 13.0024 22.4364 13.0304C22.3692 13.0528 22.288 13.05 22.2236 13.0738C22.1718 13.092 22.1144 13.106 22.064 13.127C22.001 13.1547 21.9326 13.1681 21.8638 13.1662C21.8652 13.1802 21.868 13.1942 21.8498 13.197C21.8106 13.1998 21.7742 13.2208 21.7378 13.2292C21.6328 13.2572 21.5334 13.2964 21.4312 13.3314C21.3416 13.3636 21.259 13.4112 21.1708 13.4322C21.07 13.456 21 13.5358 20.8936 13.5484C20.8609 13.5505 20.8294 13.5616 20.8026 13.5806C20.7737 13.6063 20.7406 13.6266 20.7046 13.6408C20.6481 13.6596 20.5944 13.686 20.545 13.7192C20.4722 13.7668 20.391 13.799 20.321 13.8452C20.293 13.8662 20.2496 13.8578 20.237 13.8788C20.1852 13.9684 20.0802 13.9698 20.0074 14.0258C19.9304 14.0846 19.8394 14.1294 19.7624 14.1868C19.6994 14.2358 19.6322 14.2806 19.5706 14.331C19.4908 14.401 19.404 14.4626 19.3186 14.5228C19.2752 14.555 19.2486 14.6152 19.201 14.6292C19.1282 14.6544 19.089 14.716 19.0414 14.7608C18.9938 14.8084 18.9392 14.8588 18.8902 14.9092C18.8174 14.9848 18.739 15.0548 18.662 15.1276C18.6046 15.1836 18.5542 15.2508 18.4912 15.2928C18.3946 15.3572 18.3232 15.4412 18.2448 15.5168C18.165 15.5924 18.0838 15.6708 18.0068 15.7492C17.9186 15.8402 17.8192 15.9214 17.7338 16.0152C17.661 16.0992 17.5756 16.172 17.4972 16.2476C17.4174 16.326 17.3432 16.41 17.2578 16.4856C17.1738 16.5612 17.0954 16.6396 17.0198 16.7222C16.9596 16.7852 16.8952 16.8482 16.8322 16.9084C16.7678 16.97 16.7132 17.0414 16.6334 17.0848C16.625 17.124 16.5928 17.1394 16.5634 17.159C16.4808 17.2108 16.415 17.2836 16.3436 17.3508C16.296 17.3928 16.2568 17.4516 16.2036 17.4824C16.1126 17.53 16.0496 17.6098 15.9698 17.6672C15.8732 17.7372 15.7738 17.81 15.6898 17.894C15.6478 17.9346 15.5834 17.9416 15.5568 17.9934C15.5344 18.0382 15.477 18.0284 15.449 18.0634C15.393 18.139 15.302 18.1698 15.2348 18.2314C15.1942 18.2678 15.1382 18.2972 15.0906 18.3266C15.0598 18.342 15.0262 18.3546 15.001 18.3784C14.9384 18.4341 14.8693 18.4821 14.7952 18.5212C14.763 18.5408 14.7196 18.5534 14.6958 18.5814C14.651 18.629 14.588 18.6514 14.5376 18.6934C14.4867 18.736 14.4296 18.7704 14.3682 18.7956C14.287 18.8264 14.2268 18.8824 14.1526 18.9188C14.0546 18.9664 13.9608 19.0252 13.8628 19.0728C13.8376 19.0868 13.7942 19.0952 13.7802 19.1288C13.7802 19.1526 13.79 19.1582 13.8082 19.1708C13.853 19.196 13.9006 19.2016 13.944 19.2198C14.014 19.252 14.0812 19.2912 14.1512 19.3206C14.2184 19.3486 14.2744 19.3934 14.3542 19.4004C14.3906 19.4074 14.4242 19.4242 14.4522 19.448C14.4998 19.49 14.5614 19.5054 14.6118 19.525C14.6566 19.5404 14.7 19.5698 14.7518 19.5796C14.784 19.5852 14.8274 19.5838 14.8526 19.6034C14.8974 19.6384 14.9478 19.658 14.9968 19.6874C15.029 19.7056 15.071 19.6804 15.0906 19.7084C15.1186 19.749 15.1676 19.756 15.1984 19.7672C15.2894 19.798 15.3734 19.8358 15.4644 19.8722C15.54 19.9044 15.6184 19.9268 15.694 19.9688C15.757 20.0024 15.8396 20.0038 15.911 20.0332C15.939 20.0472 15.953 20.0724 15.9838 20.0752C16.0538 20.0794 16.1196 20.1004 16.1798 20.134C16.1994 20.148 16.2204 20.1704 16.2442 20.176C16.3142 20.19 16.3842 20.2068 16.4528 20.2348C16.5158 20.2614 16.583 20.2908 16.6502 20.2992C16.688 20.3048 16.695 20.3412 16.7314 20.3412C16.793 20.3412 16.8434 20.3818 16.9022 20.3944C16.982 20.4126 17.0604 20.442 17.1388 20.4658C17.157 20.4714 17.1864 20.463 17.1948 20.4728C17.2424 20.5358 17.3222 20.5036 17.3866 20.5358C17.4566 20.5708 17.5462 20.5876 17.6274 20.6142C17.6988 20.6408 17.7702 20.6674 17.8472 20.6702C17.8598 20.6699 17.8721 20.6738 17.8822 20.6814C17.9353 20.7118 17.993 20.7336 18.053 20.7458C18.081 20.7514 18.109 20.757 18.137 20.7598C18.1888 20.7682 18.2294 20.8032 18.2798 20.806C18.3526 20.8102 18.4156 20.855 18.4926 20.8578C18.5206 20.8592 18.5696 20.855 18.5934 20.8788C18.6424 20.9278 18.7138 20.925 18.7698 20.939C18.8902 20.9712 19.0204 20.9642 19.145 21.0048C19.2178 21.03 19.299 21.0216 19.3788 21.0398C19.5062 21.0678 19.6448 21.0594 19.782 21.0678C20.034 21.0832 20.286 21.0776 20.5352 21.0482C20.5996 21.0398 20.6584 21.037 20.7214 21.0202C20.811 20.9978 20.902 20.9838 20.993 20.9768C21.0714 20.9698 21.1442 20.9362 21.224 20.9446C21.2296 20.9442 21.2349 20.9423 21.2394 20.939C21.3094 20.897 21.3892 20.897 21.4606 20.8718C21.5124 20.8564 21.5726 20.8578 21.6146 20.8326C21.6598 20.8052 21.7096 20.7863 21.7616 20.7766C21.8414 20.7626 21.8974 20.6968 21.9786 20.7024L21.9884 20.6968C22.043 20.6548 22.1102 20.6324 22.1704 20.6128C22.2376 20.589 22.302 20.5624 22.365 20.5316C22.449 20.4896 22.5274 20.435 22.6086 20.3874C22.6338 20.3734 22.6688 20.3944 22.6856 20.3552C22.6996 20.323 22.729 20.3076 22.7668 20.2992C22.8088 20.288 22.8564 20.2712 22.8732 20.2236C22.8816 20.204 22.897 20.2012 22.9138 20.204C22.9362 20.204 22.9558 20.1928 22.967 20.1732C23.0188 20.0962 23.107 20.0612 23.177 20.0094C23.2512 19.959 23.3086 19.8904 23.3856 19.8442C23.4766 19.791 23.5424 19.7056 23.6152 19.6328C23.6782 19.5684 23.737 19.5026 23.8028 19.4452C23.8546 19.4004 23.8784 19.3388 23.9288 19.294C23.9652 19.2632 24.0212 19.231 24.0352 19.182C24.0576 19.1078 24.1192 19.077 24.1696 19.0308C24.188 18.9918 24.2147 18.9574 24.248 18.93L24.2676 18.8992C24.2942 18.8838 24.2802 18.8432 24.3096 18.8264C24.36 18.7928 24.3796 18.7298 24.402 18.6822C24.437 18.608 24.479 18.5366 24.521 18.468C24.5658 18.3924 24.5938 18.3084 24.6498 18.2384C24.6918 18.1838 24.7184 18.1124 24.7478 18.048C24.8022 17.9366 24.8592 17.8264 24.9186 17.7176C24.9538 17.6526 24.9865 17.5863 25.0166 17.5188C25.0474 17.4488 25.0866 17.383 25.1202 17.3158C25.1524 17.2458 25.1972 17.1814 25.2224 17.1128C25.2546 17.0274 25.3022 16.956 25.3386 16.8748C25.3498 16.8454 25.347 16.8104 25.3666 16.7894C25.4083 16.7446 25.4394 16.691 25.4576 16.6326C25.4898 16.5486 25.5612 16.4814 25.5696 16.3876L25.5752 16.3848C25.6074 16.3596 25.6186 16.3204 25.6368 16.2868C25.6648 16.2336 25.6788 16.172 25.7138 16.123C25.7684 16.046 25.7992 15.9606 25.8412 15.878C25.8692 15.8276 25.8888 15.7702 25.9182 15.724C25.9658 15.6484 25.998 15.563 26.0442 15.4888C26.0757 15.4355 26.102 15.3792 26.1226 15.3208C26.1366 15.2816 26.1646 15.2438 26.1884 15.2088C26.2318 15.1416 26.2626 15.0646 26.3186 15.0044C26.3424 14.9792 26.341 14.9442 26.369 14.9148C26.418 14.8672 26.4432 14.8028 26.481 14.7468C26.509 14.7048 26.53 14.6544 26.5636 14.6222C26.6232 14.5607 26.6749 14.4921 26.7176 14.4178C26.761 14.3478 26.817 14.2862 26.8674 14.2274C26.9486 14.1294 27.0354 14.0314 27.1264 13.9334L27.37 13.6758C27.4176 13.6254 27.405 13.6142 27.37 13.5792" fill="#133C9A"/>
</g>
<defs>
<linearGradient id="paint0_linear_15107_489" x1="16" y1="0" x2="4.88889" y2="29.3333" gradientUnits="userSpaceOnUse">
<stop stop-color="#E5F8FF"/>
<stop offset="1" stop-color="#D9E4FF"/>
</linearGradient>
</defs>
</svg>
<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>
\ No newline at end of file
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="32" height="32" fill="url(#paint0_linear_15107_494)"/>
<path d="M9.26643 19.4365C9.26399 19.439 9.26154 19.4439 9.25909 19.4463C9.35449 19.3387 9.45478 19.2262 9.55263 19.1161C9.36917 19.3216 9.26643 19.4365 9.26643 19.4365Z" fill="#1590E9"/>
<path d="M25.5403 10.9779L26.1665 10.6086C26.4209 10.4594 26.3891 10.0827 26.1152 9.97504L25.8143 9.85763C25.374 9.68395 24.9777 9.41244 24.672 9.05041C24.2879 8.59789 23.5786 7.94722 22.4485 7.56319C21.1594 7.12289 18.953 7.21095 17.7226 7.30635C17.3337 7.3357 17.1111 7.75643 17.297 8.10133C18.339 10.024 17.7055 10.8972 17.1576 11.543C16.3186 12.5312 14.7751 14.2875 13.2267 16.034C13.7624 15.4347 14.2492 14.8892 14.6479 14.4416C15.5382 13.4436 16.8812 12.9373 18.1972 13.177C22.3922 13.9426 22.8692 19.3754 17.9721 22.6091C18.6105 22.5749 19.2588 22.5284 19.9094 22.4624C26.0883 21.8264 26.5775 16.785 25.2419 14.2948C24.7674 13.4118 24.6989 12.815 24.7502 12.2426C24.7992 11.7167 25.0878 11.2446 25.5403 10.9779Z" fill="#99C236"/>
<path d="M8.8775 20.9189C9.56975 20.1459 11.4019 18.0936 13.2291 16.0316C11.8935 17.5286 10.2498 19.3754 8.8775 20.9189Z" fill="#1590E9"/>
<path d="M8.96316 22.2422C8.48617 22.1811 8.27336 21.616 8.58401 21.2491C7.31938 22.6752 6.34094 23.7808 6.15993 24.0034C5.57042 24.725 12.2189 26.3981 17.9648 22.614C17.9672 22.6116 17.9721 22.6091 17.9746 22.6067C14.1464 22.8073 10.673 22.4624 8.96316 22.2422Z" fill="#CAC134"/>
<path d="M18.1996 13.1745C16.8836 12.9348 15.5407 13.4411 14.6503 14.4391C14.2516 14.8843 13.7648 15.4298 13.2291 16.0316C11.4019 18.0936 9.56975 20.1459 8.87751 20.9189C8.77722 21.0314 8.67937 21.1415 8.58397 21.2491C8.27332 21.6136 8.48613 22.1786 8.96312 22.2422C10.6729 22.4623 14.1464 22.8072 17.9721 22.6091C22.8692 19.3729 22.3946 13.9401 18.1996 13.1745Z" fill="#029F40"/>
<defs>
<linearGradient id="paint0_linear_15107_494" x1="16" y1="0" x2="4.88889" y2="29.3333" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2FFD2"/>
<stop offset="1" stop-color="#C6F6D9"/>
</linearGradient>
</defs>
</svg>
<svg t="1733816460969" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13871" width="200" height="200"><path d="M903.542857 350.4c-11.314286-45.028571 11.314286-116.8 83.885714-142.171429l-77.6-4.114285s-29.371429-102.857143-164.114285-112c-134.628571-9.257143-222.742857-3.428571-222.857143-3.428572 0.114286 0 99.885714 63.542857 59.885714 176.8-29.257143 60-75.2 109.257143-124.342857 165.371429-1.485714 1.485714-2.857143 2.971429-4 4.228571C291.885714 618.285714 36.571429 909.714286 36.571429 909.714286c281.028571 73.6 469.371429-7.2 580.8-104.114286 23.428571-0.228571 41.028571-0.342857 52.914285-0.342857 155.2 0 286.4-134.4 281.028572-283.885714-3.657143-102.742857-36.457143-125.942857-47.771429-170.971429z m-233.257143 381.714286c-12.114286 0-29.942857 0.114286-53.485714 0.342857l-26.971429 0.228571-20.342857 17.714286c-53.828571 46.857143-119.314286 81.714286-195.885714 100.114286-60 14.4-125.714286 18.514286-197.371429 10.971428 20.571429-23.428571 41.714286-47.542857 63.314286-72.114285 105.142857-119.542857 198.628571-225.714286 270.742857-306.857143l1.6-1.6 1.485715-1.714286c4.685714-5.257143 23.542857-26.628571 28.228571-32.114286 11.085714-12.685714 19.771429-22.742857 28-32.685714 35.085714-41.942857 59.657143-77.485714 78.857143-116.8l1.828571-3.771429 1.371429-3.885714c15.657143-44.342857 17.6-87.885714 7.085714-128.914286 25.714286 0.8 53.142857 2.171429 81.942857 4.114286 38.057143 2.628571 63.428571 14.742857 81.257143 33.371429 6.628571 6.857143 11.657143 14.285714 15.314286 21.371428 1.142857 2.285714 1.942857 4.114286 2.628571 5.714286l5.714286 20.228571c-17.942857 39.428571-22.742857 83.771429-13.028571 122.514286 3.428571 13.485714 7.885714 25.6 14.057142 39.314286 2.4 5.371429 10.857143 22.971429 12.571429 26.628571 11.771429 25.942857 17.6 49.142857 19.085714 89.942857 3.771429 108.114286-94.514286 207.885714-208 207.885715z" p-id="13872"></path></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="searxng.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
id="svg8"
version="1.1"
viewBox="0 0 225.86871 38.709602"
height="38.709602mm"
width="225.86871mm">
<defs
id="defs2" />
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="2149"
inkscape:window-x="-7"
inkscape:window-height="1346"
inkscape:window-width="2560"
fit-margin-bottom="0"
fit-margin-right="0"
fit-margin-left="0"
fit-margin-top="0"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="235.27775"
inkscape:cx="1236.8338"
inkscape:zoom="0.7"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-4.020089,-7.482607)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
transform="translate(-25.702381,-86.178571)"
style="font-style:normal;font-weight:normal;font-size:50.8px;line-height:1.25;font-family:sans-serif;fill:#487cff;fill-opacity:1;stroke:none;stroke-width:0.264583"
id="text884"
aria-label="SearXNG">
<path
id="path886"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.8px;font-family:'Libre Franklin';-inkscape-font-specification:'Libre Franklin';fill:#487cff;fill-opacity:1;stroke-width:0.264583"
d="m 56.494069,102.70358 q -1.1684,-1.2192 -3.047999,-2.032 -1.8796,-0.812802 -4.4196,-0.812802 -3.1496,0 -5.08,1.320802 -1.9304,1.27 -1.9304,3.4544 0,2.3368 3.7084,3.6068 l 7.6708,2.6416 q 3.962399,1.3208 5.841999,3.4036 1.8796,2.0828 1.8796,5.1308 0,4.064 -2.1844,7.0104 -2.1844,2.8956 -5.943599,4.4196 -3.7592,1.524 -8.4836,1.524 -5.334,0 -9.0424,-1.778 -3.7084,-1.8288 -5.5372,-5.1308 -0.2032,-0.3556 -0.2032,-0.7112 0,-0.3556 0.4064,-0.6096 l 4.0132,-2.4384 q 0.3556,-0.254 0.762,-0.254 0.6096,0 1.1176,0.6604 1.3208,1.6256 2.3876,2.54 1.1176,0.8636 2.6924,1.3208 1.6256,0.4572 4.1656,0.4572 3.2004,0 5.1816,-1.1684 1.9812,-1.2192 1.9812,-3.7592 0,-1.27 -0.9144,-2.0828 -0.9144,-0.8636 -2.9464,-1.5748 l -7.4168,-2.4892 q -3.6576,-1.2192 -5.588,-3.556 -1.8796,-2.3876 -1.8796,-5.4356 0,-3.7592 2.1336,-6.654802 2.1336,-2.8956 5.6896,-4.4704 3.6068,-1.5748 7.874,-1.5748 4.3688,0 7.670799,1.5748 3.3528,1.524 5.1816,3.9624 0.4064,0.508 0.4064,0.762 0,0.254002 -0.3556,0.457202 l -4.5212,2.9972 q -0.0508,0.0508 -0.2032,0.0508 -0.3048,0 -1.0668,-0.762 z" />
<path
id="path888"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.8px;font-family:'Libre Franklin';-inkscape-font-specification:'Libre Franklin';fill:#487cff;fill-opacity:1;stroke-width:0.264583"
d="m 77.003775,132.37078 q -3.6068,0 -6.4008,-1.4732 -2.794,-1.4732 -4.318,-4.1148 -1.524,-2.6924 -1.524,-6.1976 0,-4.1656 1.9812,-7.874 2.032,-3.7592 5.5372,-5.9944 3.556,-2.286 7.9248,-2.286 5.334,0 8.4836,3.1496 3.1496,3.1496 3.1496,8.6868 0,1.4732 -0.2032,2.8448 -0.1016,0.4064 -0.3556,0.6096 -0.2032,0.1524 -0.8128,0.1524 h -17.1196 q -0.8128,0 -0.8128,2.1844 0,2.3876 1.524,3.7084 1.5748,1.27 4.064,1.27 1.9304,0 3.6068,-0.8128 1.6764,-0.8128 3.302,-2.54 0.254,-0.254 0.508,-0.254 0.1524,0 0.6604,0.2032 l 3.3528,1.5748 q 0.6096,0.2032 0.6096,0.6604 0,0.254 -0.254,0.6604 -2.9464,3.302 -5.8928,4.572 -2.8956,1.27 -7.0104,1.27 z m 6.4516,-16.5608 q 1.2192,0 1.2192,-1.9812 0,-1.9304 -1.1684,-3.2512 -1.1684,-1.3716 -3.2512,-1.3716 -2.54,0 -4.5212,1.9304 -1.9304,1.8796 -2.2352,4.6736 z" />
<path
id="path890"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.8px;font-family:'Libre Franklin';-inkscape-font-specification:'Libre Franklin';fill:#487cff;fill-opacity:1;stroke-width:0.264583"
d="m 109.411,129.37358 q -3.048,2.9972 -8.3312,2.9972 -3.555996,0 -5.587996,-1.8288 -2.032,-1.8288 -2.032,-4.7752 0,-3.6068 2.3876,-5.8928 2.3876,-2.3368 5.994396,-3.3528 3.6576,-1.0668 7.5692,-1.1684 l 1.8288,-0.1524 q 0.9652,0 1.1176,-0.9652 l 0.1524,-1.0668 q 0.0508,-0.254 0.0508,-0.8128 0,-3.048 -3.5052,-3.048 -4.0132,0 -5.9436,3.1496 -0.254,0.3556 -0.6604,0.3556 -0.3048,0 -0.4572,-0.0508 l -4.927596,-1.1684 q -0.508,-0.1016 -0.508,-0.6604 0,-0.508 0.254,-1.016 3.352796,-5.4864 12.649196,-5.4864 5.4864,0 8.0264,1.9304 2.5908,1.9304 2.5908,5.334 0,0.4572 -0.1016,1.4732 l -2.54,17.78 q -0.0508,0.6604 -0.2032,0.8128 -0.1524,0.1016 -0.7112,0.1016 h -5.2324 q -0.508,0 -0.6604,-0.3048 -0.1524,-0.3048 -0.2032,-1.016 l 0.0508,-1.3208 q 0,-0.4064 -0.254,-0.4064 -0.254,0 -0.8128,0.5588 z m 2.1844,-9.7536 v -0.3048 q 0,-0.2032 -0.1016,-0.254 -0.1016,-0.1016 -0.4064,-0.0508 l -1.8288,0.1524 q -2.9464,0.2032 -5.4864,1.4732 -2.54,1.27 -2.54,3.9116 0,1.2192 0.8636,1.9812 0.9144,0.7112 2.4384,0.7112 1.3208,0 2.4892,-0.3556 1.1684,-0.4064 2.032,-1.0668 1.8796,-1.4224 2.0828,-2.8956 z" />
<path
id="path892"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.8px;font-family:'Libre Franklin';-inkscape-font-specification:'Libre Franklin';fill:#487cff;fill-opacity:1;stroke-width:0.264583"
d="m 123.8636,131.86278 q -0.6096,0 -0.9144,-0.3556 -0.254,-0.3556 -0.1524,-0.9144 l 3.5052,-24.9428 q 0.0508,-0.4572 0.1524,-0.5588 0.1524,-0.1524 0.5588,-0.1524 h 6.0452 q 0.9144,0 0.7112,1.0668 l -0.3556,2.286 v 0.2032 q 0,0.3556 0.2032,0.3556 0.1524,0 0.4572,-0.3048 1.778,-1.8796 3.9624,-2.9972 2.1844,-1.1176 3.9624,-1.1176 1.0668,0 1.5748,0.1524 0.508,0.1524 0.4572,0.6096 l -0.8128,5.6896 q -0.0508,0.5588 -0.2032,0.7112 -0.1016,0.1524 -0.4064,0.1016 -1.7272,-0.254 -3.4544,-0.254 -1.3208,0 -2.794,0.7112 -1.4732,0.6604 -2.54,1.778 -1.016,1.0668 -1.1684,2.1336 l -2.0828,14.8336 q -0.1016,0.6604 -0.3556,0.8128 -0.2032,0.1524 -0.9652,0.1524 z" />
<path
id="path894"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.8px;font-family:'Libre Franklin';-inkscape-font-specification:'Libre Franklin';fill:#487cff;fill-opacity:1;stroke-width:0.264583"
d="m 176.48129,130.08478 q 0.4572,0.8128 0.4572,1.2192 0,0.3048 -0.254,0.4572 -0.254,0.1016 -0.762,0.1016 h -7.0612 q -0.6096,0 -0.9652,-0.1524 -0.3048,-0.1524 -0.508,-0.6096 l -5.6388,-11.7348 q -0.254,-0.508 -0.508,-0.508 -0.1524,0 -0.5588,0.5588 l -9.0424,11.8364 q -0.254,0.4064 -0.6096,0.508 -0.3048,0.1016 -1.0668,0.1016 h -5.9436 q -1.016,0 -1.016,-0.6604 0,-0.4572 0.762,-1.524 l 13.0048,-16.3068 q 0.5588,-0.6096 0.5588,-1.0668 0,-0.3556 -0.1016,-0.5588 l -8.4836,-16.560802 q -0.1524,-0.254 -0.1524,-0.508 0,-0.508 0.762,-0.508 h 7.4168 q 0.6604,0 0.9144,0.1524 0.254,0.1524 0.508,0.6604 l 4.9276,10.363202 q 0.1524,0.4064 0.3556,0.4064 0.2032,0 0.508,-0.4064 l 8.0264,-10.566402 q 0.3048,-0.4064 0.5588,-0.508 0.3048,-0.1016 0.9652,-0.1016 h 6.5532 q 0.6096,0 0.6096,0.5588 0,0.4064 -0.3048,0.9144 l -12.5984,15.646402 q -0.508,0.6604 -0.508,0.9144 0,0.2032 0.1524,0.508 z" />
<path
id="path896"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.8px;font-family:'Libre Franklin';-inkscape-font-specification:'Libre Franklin';fill:#487cff;fill-opacity:1;stroke-width:0.264583"
d="m 218.11268,94.169178 q 0.3556,0 0.4572,0.2032 0.1016,0.1524 0.0508,0.5588 l -5.1308,36.372802 q -0.0508,0.3556 -0.254,0.4572 -0.1524,0.1016 -0.5588,0.1016 h -5.1816 q -0.6604,0 -1.1684,-0.8128 l -13.1064,-22.7076 q -0.1524,-0.254 -0.3048,-0.254 -0.3048,0 -0.3556,0.5588 l -3.1496,22.4028 q -0.1016,0.508 -0.3048,0.6604 -0.1524,0.1524 -0.7112,0.1524 h -5.588 q -0.8128,0 -0.7112,-1.1176 l 5.08,-35.814002 q 0.1016,-0.508 0.2032,-0.6096 0.1524,-0.1524 0.6604,-0.1524 h 6.1468 q 0.508,0 0.762,0.254 0.3048,0.2032 0.5588,0.7112 l 11.9888,21.183602 q 0.254,0.4064 0.508,0.4064 0.4064,0 0.4572,-0.6096 l 2.9464,-21.285202 q 0.0508,-0.4064 0.2032,-0.508 0.2032,-0.1524 0.6604,-0.1524 z" />
<path
id="path898"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.8px;font-family:'Libre Franklin';-inkscape-font-specification:'Libre Franklin';fill:#487cff;fill-opacity:1;stroke-width:0.264583"
d="m 236.43958,132.37078 q -4.572,0 -7.9248,-1.9304 -3.3528,-1.9304 -5.1308,-5.4356 -1.7272,-3.556 -1.7272,-8.3312 0,-6.2992 2.4892,-11.5316 2.4892,-5.283202 7.0612,-8.382002 4.572,-3.0988 10.5156,-3.0988 4.064,0 7.1628,1.5748 3.1496,1.5748 4.8768,4.1656 1.7272,2.540002 1.8288,5.435602 0,0.508 -0.1016,0.762 -0.0508,0.2032 -0.254,0.254 l -6.9596,1.016 h -0.0508 q -0.2032,0 -0.3556,-0.254 -0.1016,-0.254 -0.254,-1.016 -0.3556,-2.54 -1.9304,-4.1148 -1.524,-1.574802 -4.318,-1.574802 -3.6068,0 -5.9944,2.641602 -2.3368,2.6416 -3.4544,6.8072 -1.1176,4.1148 -1.1176,8.5852 0,4.3688 1.6256,6.2992 1.6764,1.8796 4.8768,1.8796 3.0988,0 5.2324,-1.7272 2.1336,-1.7272 3.1496,-4.2164 l 0.3048,-1.4224 q 0.1524,-0.254 0.1524,-0.3556 0,-0.3048 -0.6096,-0.3048 h -6.2484 q -0.3048,0 -0.4064,-0.1016 -0.1016,-0.1524 -0.0508,-0.5588 l 0.4572,-4.1656 q 0.0508,-0.5588 0.508,-0.5588 l 14.5288,0.0508 q 0.6096,0 0.762,0.2032 0.2032,0.1524 0.1016,0.6604 l -2.4892,17.5768 q -0.0508,0.6604 -0.8128,0.6604 h -1.524 q -0.4572,0 -0.7112,-0.1524 -0.2032,-0.1524 -0.3556,-0.6096 l -0.8636,-3.7084 q -0.0508,-0.254 -0.3556,-0.254 -0.3048,0 -0.6604,0.4064 -1.6764,2.0828 -4.3688,3.4544 -2.6924,1.3716 -6.604,1.3716 z" />
</g>
</g>
</svg>
<?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="1734061835557" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4251" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512.003 79C272.855 79 79 272.855 79 512.003 79 751.145 272.855 945 512.003 945 751.145 945 945 751.145 945 512.003 945 272.855 751.145 79 512.003 79z m200.075 375.014c-0.867 3.764-3.117 9.347-6.234 16.012h0.087l-0.347 0.648c-18.183 38.86-65.631 115.108-65.631 115.108l-0.215-0.52-13.856 24.147h66.8L565.063 779l29.002-115.368h-52.598l18.27-76.29c-14.76 3.55-32.253 8.436-52.945 15.1 0 0-27.967 16.36-80.607-31.5 0 0-35.501-31.29-14.891-39.078 8.744-3.33 42.466-7.573 69.004-11.122 35.93-4.845 57.965-7.441 57.965-7.441s-110.607 1.643-136.841-2.468c-26.237-4.11-59.525-47.905-66.626-86.377 0 0-10.953-21.117 23.595-11.122 34.547 10 177.535 38.95 177.535 38.95s-185.933-56.992-198.36-70.929c-12.381-13.846-36.406-75.902-33.289-113.981 0 0 1.343-9.521 11.127-6.926 0 0 137.49 62.75 231.475 97.152 94.028 34.403 175.76 51.885 165.2 96.414z" fill="#3AA2EB" p-id="4252"></path></svg>
\ No newline at end of file
<?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="1734061835557" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4251" xmlns:xlink="http://www.w3.org/1999/xlink" ><path d="M512.003 79C272.855 79 79 272.855 79 512.003 79 751.145 272.855 945 512.003 945 751.145 945 945 751.145 945 512.003 945 272.855 751.145 79 512.003 79z m200.075 375.014c-0.867 3.764-3.117 9.347-6.234 16.012h0.087l-0.347 0.648c-18.183 38.86-65.631 115.108-65.631 115.108l-0.215-0.52-13.856 24.147h66.8L565.063 779l29.002-115.368h-52.598l18.27-76.29c-14.76 3.55-32.253 8.436-52.945 15.1 0 0-27.967 16.36-80.607-31.5 0 0-35.501-31.29-14.891-39.078 8.744-3.33 42.466-7.573 69.004-11.122 35.93-4.845 57.965-7.441 57.965-7.441s-110.607 1.643-136.841-2.468c-26.237-4.11-59.525-47.905-66.626-86.377 0 0-10.953-21.117 23.595-11.122 34.547 10 177.535 38.95 177.535 38.95s-185.933-56.992-198.36-70.929c-12.381-13.846-36.406-75.902-33.289-113.981 0 0 1.343-9.521 11.127-6.926 0 0 137.49 62.75 231.475 97.152 94.028 34.403 175.76 51.885 165.2 96.414z" fill="#3AA2EB" p-id="4252"></path></svg>
\ No newline at end of file
......@@ -50,6 +50,8 @@ const MyModal = ({
autoFocus={false}
isCentered={isPc ? isCentered : true}
blockScrollOnMount={false}
allowPinchZoom
scrollBehavior={'inside'}
closeOnOverlayClick={closeOnOverlayClick}
>
<ModalOverlay />
......
......@@ -82,6 +82,7 @@
"month.unit": "Day",
"move.hint": "After moving, the selected application/folder will inherit the permission settings of the new folder, and the original permission settings will become invalid.",
"move_app": "Move Application",
"node_not_intro": "This node is not introduced",
"not_json_file": "Please select a JSON file",
"open_auto_execute": "Enable automatic execution",
"open_vision_function_tip": "Models with icon switches have image recognition capabilities. \nAfter being turned on, the model will parse the pictures in the file link and automatically parse the pictures in the user's question (user question ≤ 500 words).",
......
......@@ -33,6 +33,7 @@
"multiple_AI_conversations": "Multiple AI Conversations",
"new_input_guide_lexicon": "New Lexicon",
"no_workflow_response": "No workflow data",
"not_query": "Missing query content",
"not_select_file": "No file selected",
"plugins_output": "Plugin Output",
"question_tip": "From top to bottom, the response order of each module",
......
......@@ -841,7 +841,6 @@
"dataset.Create Folder": "Create Folder",
"dataset.Create manual collection": "Create Manual Dataset",
"dataset.Delete Dataset Error": "Delete Dataset Error",
"dataset.Edit API Service": "Edit API Service",
"dataset.Edit Folder": "Edit Folder",
"dataset.Edit Info": "Edit Information",
"dataset.Export": "Export",
......
......@@ -25,6 +25,7 @@
"dataset.Unsupported operation": "dataset.Unsupported operation",
"dataset.no_collections": "No datasets available",
"dataset.no_tags": "No tags available",
"edit_dataset_config": "Edit knowledge base configuration",
"error.collectionNotFound": "Collection not found~",
"external_file": "External File Library",
"external_file_dataset_desc": "Import files from an external file library to build a Dataset. The files will not be stored again.",
......@@ -32,6 +33,9 @@
"external_read_url": "External Preview URL",
"external_read_url_tip": "Configure the reading URL of your file library for user authentication. Use the {{fileId}} variable to refer to the external file ID.",
"external_url": "File Access URL",
"feishu_dataset": "Feishu Dataset",
"feishu_dataset_config": "Feishu Dataset Config",
"feishu_dataset_desc": "Can build a dataset using Feishu documents by configuring permissions, without secondary storage",
"file_model_function_tip": "Enhances indexing and QA generation",
"filename": "Filename",
"folder_dataset": "Folder",
......@@ -69,5 +73,8 @@
"training_mode": "Chunk mode",
"vector_model_max_tokens_tip": "Each chunk of data has a maximum length of 3000 tokens",
"website_dataset": "Website Sync",
"website_dataset_desc": "Website sync allows you to build a Dataset directly using a web link."
"website_dataset_desc": "Website sync allows you to build a Dataset directly using a web link.",
"yuque_dataset": "Yuque Dataset",
"yuque_dataset_config": "Yuque Dataset Config",
"yuque_dataset_desc": "Can build a dataset using Yuque documents by configuring permissions, without secondary storage"
}
......@@ -35,5 +35,11 @@
"wecom.bot_desc": "Connect to WeCom Bot directly via API",
"wecom.create_modal_title": "Create WeCom Bot",
"wecom.edit_modal_title": "Edit WeCom Bot",
"wecom.title": "Publish to WeCom Bot"
}
\ No newline at end of file
"wecom.title": "Publish to WeCom Bot",
"dingtalk.bot": "DingTalk Bot",
"dingtalk.bot_desc": "Connect to DingTalk Bot directly via API",
"dingtalk.create_modal_title": "Create DingTalk Bot",
"dingtalk.edit_modal_title": "Edit DingTalk Bot",
"dingtalk.title": "Publish to DingTalk Bot",
"dingtalk.api": "DingTalk API"
}
......@@ -26,6 +26,7 @@
"login.error": "Login Error",
"login.password_condition": "Password can be up to 60 characters",
"login.success": "Login Successful",
"login.Dingtalk": "DingTalk Login",
"manage_team": "Manage team",
"name": "Name",
"notification.Bind Notification Pipe Hint": "Please bind a notification receiving account to ensure you receive notifications such as plan expiration reminders, ensuring your service runs smoothly.",
......@@ -114,6 +115,7 @@
"team.no_collaborators": "No Collaborators",
"team.write_role_member": "",
"usage.feishu": "Feishu",
"usage.dingtalk": "DingTalk",
"usage.official_account": "Official Account",
"usage.share": "Share Link",
"usage.wecom": "WeCom"
......
......@@ -57,6 +57,7 @@
"field_required": "Required",
"field_used_as_tool_input": "Used as Tool Call Parameter",
"filter_description": "Currently supports filtering by tags and creation time. Fill in the format as follows:\n{\n \"tags\": {\n \"$and\": [\"Tag 1\",\"Tag 2\"],\n \"$or\": [\"When there are $and tags, and is effective, or is not effective\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm format, collection creation time greater than this time\",\n \"$lte\": \"YYYY-MM-DD HH:mm format, collection creation time less than this time, can be used with $gte\"\n }\n}",
"foldAll": "Collapse all",
"form_input_result": "User complete input result",
"form_input_result_tip": "an object containing the complete result",
"full_field_extraction": "Full Field Extraction",
......@@ -179,6 +180,7 @@
"tool_params.params_name_placeholder": "name/age/sql",
"tool_params.tool_params_result": "Parameter configuration results",
"trigger_after_application_completion": "Will be triggered after the application is fully completed",
"unFoldAll": "Expand all",
"update_link_error": "Error updating link",
"update_specified_node_output_or_global_variable": "Can update the output value of a specified node or update global variables",
"use_user_id": "User ID",
......
......@@ -82,6 +82,7 @@
"month.unit": "号",
"move.hint": "移动后,所选应用/文件夹将继承新文件夹的权限设置,原先的权限设置失效。",
"move_app": "移动应用",
"node_not_intro": "这个节点没有介绍",
"not_json_file": "请选择JSON文件",
"open_auto_execute": "启用自动执行",
"open_vision_function_tip": "有图示开关的模型即拥有图片识别能力。若开启,模型会解析文件链接里的图片,并自动解析用户问题中的图片(用户问题≤500字时生效)。",
......
......@@ -33,6 +33,7 @@
"multiple_AI_conversations": "多组 AI 对话",
"new_input_guide_lexicon": "新词库",
"no_workflow_response": "没有运行数据",
"not_query": "缺少查询内容",
"not_select_file": "未选择文件",
"plugins_output": "插件输出",
"question_tip": "从上到下,为各个模块的响应顺序",
......
......@@ -840,7 +840,6 @@
"dataset.Create Folder": "创建文件夹",
"dataset.Create manual collection": "创建手动数据集",
"dataset.Delete Dataset Error": "删除知识库异常",
"dataset.Edit API Service": "编辑 API 文件接口",
"dataset.Edit Folder": "编辑文件夹",
"dataset.Edit Info": "编辑信息",
"dataset.Export": "导出",
......
......@@ -25,6 +25,7 @@
"dataset.Unsupported operation": "操作不支持",
"dataset.no_collections": "暂无数据集",
"dataset.no_tags": "暂无标签",
"edit_dataset_config": "编辑知识库配置",
"error.collectionNotFound": "集合找不到了~",
"external_file": "外部文件库",
"external_file_dataset_desc": "可以从外部文件库导入文件构建知识库,文件不会进行二次存储",
......@@ -32,6 +33,9 @@
"external_read_url": "外部预览地址",
"external_read_url_tip": "可以配置你文件库的阅读地址。便于对用户进行阅读鉴权操作。目前可以使用 {{fileId}} 变量来指代外部文件 ID。",
"external_url": "文件访问 URL",
"feishu_dataset": "飞书知识库",
"feishu_dataset_config": "配置飞书知识库",
"feishu_dataset_desc": "可通过配置飞书文档权限,使用飞书文档构建知识库,文档不会进行二次存储",
"file_model_function_tip": "用于增强索引和 QA 生成",
"filename": "文件名",
"folder_dataset": "文件夹",
......@@ -69,5 +73,8 @@
"training_mode": "处理方式",
"vector_model_max_tokens_tip": "每个分块数据,最大长度为 3000 tokens",
"website_dataset": "Web 站点同步",
"website_dataset_desc": "Web 站点同步允许你直接使用一个网页链接构建知识库"
"website_dataset_desc": "Web 站点同步允许你直接使用一个网页链接构建知识库",
"yuque_dataset": "语雀知识库",
"yuque_dataset_config": "配置语雀知识库",
"yuque_dataset_desc": "可通过配置语雀文档权限,使用语雀文档构建知识库,文档不会进行二次存储"
}
......@@ -35,5 +35,11 @@
"wecom.bot_desc": "通过 API 直接接入企业微信机器人",
"wecom.create_modal_title": "创建企微机器人",
"wecom.edit_modal_title": "编辑企微机器人",
"wecom.title": "发布到企业微信机器人"
}
\ No newline at end of file
"wecom.title": "发布到企业微信机器人",
"dingtalk.bot": "钉钉机器人",
"dingtalk.bot_desc": "通过 API 直接接入钉钉机器人",
"dingtalk.create_modal_title": "创建钉钉机器人",
"dingtalk.edit_modal_title": "编辑钉钉机器人",
"dingtalk.title": "发布到钉钉机器人",
"dingtalk.api": "钉钉 API"
}
......@@ -26,6 +26,7 @@
"login.error": "登录异常",
"login.password_condition": "密码最多 60 位",
"login.success": "登录成功",
"login.Dingtalk": "钉钉登录",
"manage_team": "管理团队",
"name": "名称",
"notification.Bind Notification Pipe Hint": "请绑定通知接收账号,以确保您能正常接收套餐过期提醒等通知,保障您的服务正常运行。",
......@@ -114,6 +115,7 @@
"team.no_collaborators": "暂无协作者",
"team.write_role_member": "可写权限",
"usage.feishu": "飞书",
"usage.dingtalk": "钉钉",
"usage.official_account": "公众号",
"usage.share": "分享链接",
"usage.wecom": "企业微信"
......
......@@ -10,7 +10,6 @@
"Variable_name": "变量名",
"add_new_input": "新增输入",
"add_new_output": "新增输出",
"http_body_placeholder": "与 APIFox 类似的语法,可通过 / 来激活变量选择。字符串变量均需加双引号,其他类型变量无需加双引号。请严格检查是否符合 JSON 格式。",
"append_application_reply_to_history_as_new_context": "将该应用回复内容拼接到历史记录中,作为新的上下文返回",
"application_call": "应用调用",
"assigned_reply": "指定回复",
......@@ -58,6 +57,7 @@
"field_required": "必填",
"field_used_as_tool_input": "作为工具调用参数",
"filter_description": "目前支持标签和创建时间过滤,需按照以下格式填写:\n{\n \"tags\": {\n \"$and\": [\"标签 1\",\"标签 2\"],\n \"$or\": [\"有 $and 标签时,and 生效,or 不生效\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间大于该时间\",\n \"$lte\": \"YYYY-MM-DD HH:mm 格式即可,集合的创建时间小于该时间,可和 $gte 共同使用\"\n }\n}",
"foldAll": "全部折叠",
"form_input_result": "用户完整输入结果",
"form_input_result_tip": "一个包含完整结果的对象",
"full_field_extraction": "字段完全提取",
......@@ -65,6 +65,7 @@
"full_response_data": "完整响应数据",
"greater_than": "大于",
"greater_than_or_equal_to": "大于等于",
"http_body_placeholder": "与 APIFox 类似的语法,可通过 / 来激活变量选择。字符串变量均需加双引号,其他类型变量无需加双引号。请严格检查是否符合 JSON 格式。",
"http_extract_output": "输出字段提取",
"http_extract_output_description": "可以通过 JSONPath 语法来提取响应值中的指定字段",
"http_raw_response_description": "HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。",
......@@ -179,6 +180,7 @@
"tool_params.params_name_placeholder": "name/age/sql",
"tool_params.tool_params_result": "参数配置结果",
"trigger_after_application_completion": "将在应用完全结束后触发",
"unFoldAll": "全部展开",
"update_link_error": "更新链接异常",
"update_specified_node_output_or_global_variable": "可以更新指定节点的输出值或更新全局变量",
"use_user_id": "使用者 ID",
......
......@@ -82,6 +82,7 @@
"month.unit": "號",
"move.hint": "移動後,所選應用程式/資料夾將會繼承新資料夾的權限設定,原先的權限設定將會失效。",
"move_app": "移動應用程式",
"node_not_intro": "這個節點沒有介紹",
"not_json_file": "請選擇 JSON 檔案",
"open_auto_execute": "啟用自動執行",
"open_vision_function_tip": "有圖示開關的模型即擁有圖片辨識功能。若開啟,模型會解析檔案連結中的圖片,並自動解析使用者問題中的圖片(使用者問題 ≤ 500 字時生效)。",
......
......@@ -33,6 +33,7 @@
"multiple_AI_conversations": "多組 AI 對話",
"new_input_guide_lexicon": "新增詞彙庫",
"no_workflow_response": "無工作流程資料",
"not_query": "缺少查詢內容",
"not_select_file": "尚未選取檔案",
"plugins_output": "外掛程式輸出",
"question_tip": "由上至下,各個模組的回應順序",
......
......@@ -25,6 +25,7 @@
"dataset.Unsupported operation": "操作不支持",
"dataset.no_collections": "尚無資料集",
"dataset.no_tags": "尚無標籤",
"edit_dataset_config": "編輯知識庫配置",
"error.collectionNotFound": "找不到集合",
"external_file": "外部檔案庫",
"external_file_dataset_desc": "可以從外部檔案庫匯入檔案建立資料集,檔案不會進行二次儲存",
......@@ -32,6 +33,9 @@
"external_read_url": "外部預覽網址",
"external_read_url_tip": "可以設定您檔案庫的讀取網址,方便對使用者進行讀取權限驗證。目前可使用 {{fileId}} 變數來代表外部檔案識別碼。",
"external_url": "檔案存取網址",
"feishu_dataset": "飛書知識庫",
"feishu_dataset_config": "配置飛書知識庫",
"feishu_dataset_desc": "可通過配置飛書文檔權限,使用飛書文檔構建知識庫,文檔不會進行二次存儲",
"file_model_function_tip": "用於增強索引和問答生成",
"filename": "檔案名稱",
"folder_dataset": "資料夾",
......@@ -69,5 +73,8 @@
"training_mode": "分段模式",
"vector_model_max_tokens_tip": "每個分塊數據,最大長度為 3000 tokens",
"website_dataset": "網站同步",
"website_dataset_desc": "網站同步功能讓您可以直接使用網頁連結建立資料集"
"website_dataset_desc": "網站同步功能讓您可以直接使用網頁連結建立資料集",
"yuque_dataset": "語雀知識庫",
"yuque_dataset_config": "配置語雀知識庫",
"yuque_dataset_desc": "可通過配置語雀文檔權限,使用語雀文檔構建知識庫,文檔不會進行二次存儲"
}
......@@ -35,5 +35,11 @@
"wecom.bot_desc": "透過 API 直接連結企業微信聊天機器人",
"wecom.create_modal_title": "建立企業微信聊天機器人",
"wecom.edit_modal_title": "編輯企業微信聊天機器人",
"wecom.title": "發布至企業微信聊天機器人"
}
\ No newline at end of file
"wecom.title": "發布至企業微信聊天機器人",
"dingtalk.bot": "釘釘聊天機器人",
"dingtalk.bot_desc": "透過 API 直接連結釘釘聊天機器人",
"dingtalk.create_modal_title": "建立釘釘聊天機器人",
"dingtalk.edit_modal_title": "編輯釘釘聊天機器人",
"dingtalk.title": "發布至釘釘聊天機器人",
"dingtalk.api": "釘釘 API"
}
......@@ -26,6 +26,7 @@
"login.error": "登入失敗",
"login.password_condition": "密碼最多可輸入 60 個字元",
"login.success": "登入成功",
"login.Dingtalk": "釘釘登入",
"manage_team": "管理團隊",
"name": "名稱",
"notification.Bind Notification Pipe Hint": "請綁定通知接收帳號,以確保您能正常接收方案到期提醒等通知,保障您的服務正常運作。",
......@@ -114,6 +115,7 @@
"team.no_collaborators": "目前沒有協作者",
"team.write_role_member": "可寫入權限",
"usage.feishu": "飛書",
"usage.dingtalk": "釘釘",
"usage.official_account": "公眾號",
"usage.share": "分享連結",
"usage.wecom": "企業微信"
......
......@@ -57,6 +57,7 @@
"field_required": "必填",
"field_used_as_tool_input": "作為工具呼叫參數",
"filter_description": "目前支援標籤和建立時間篩選,需按照以下格式填寫:\n{\n \"tags\": {\n \"$and\": [\"標籤 1\",\"標籤 2\"],\n \"$or\": [\"當有 $and 標籤時,$and 才會生效,$or 不會生效\"]\n },\n \"createTime\": {\n \"$gte\": \"YYYY-MM-DD HH:mm 格式,資料集的建立時間大於這個時間\",\n \"$lte\": \"YYYY-MM-DD HH:mm 格式,資料集的建立時間小於這個時間,可以和 $gte 一起使用\"\n }\n}",
"foldAll": "全部折疊",
"form_input_result": "使用者完整輸入結果",
"form_input_result_tip": "一個包含完整結果的物件",
"full_field_extraction": "欄位完整擷取",
......@@ -179,6 +180,7 @@
"tool_params.params_name_placeholder": "name/age/sql",
"tool_params.tool_params_result": "參數設定結果",
"trigger_after_application_completion": "將會在應用程式完全結束後觸發",
"unFoldAll": "全部展開",
"update_link_error": "更新連結發生錯誤",
"update_specified_node_output_or_global_variable": "可以更新指定節點的輸出值或更新全域變數",
"use_user_id": "使用者 ID",
......
......@@ -580,9 +580,6 @@ importers:
'@svgr/webpack':
specifier: ^6.5.1
version: 6.5.1
'@types/faker':
specifier: ^6.6.9
version: 6.6.9
'@types/formidable':
specifier: ^2.0.5
version: 2.0.6
......@@ -3358,10 +3355,6 @@ packages:
'@types/express@5.0.0':
resolution: {integrity: sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==}
'@types/faker@6.6.9':
resolution: {integrity: sha512-Y9YYm5L//8ooiiknO++4Gr539zzdI0j3aXnOBjo1Vk+kTvffY10GuE2wn78AFPECwZ5MYGTjiDVw1naLLdDimw==}
deprecated: This is a stub types definition. faker provides its own type definitions, so you do not need this installed.
'@types/formidable@2.0.6':
resolution: {integrity: sha512-L4HcrA05IgQyNYJj6kItuIkXrInJvsXTPC5B1i64FggWKKqSL+4hgt7asiSNva75AoLQjq29oPxFfU4GAQ6Z2w==}
......@@ -5252,9 +5245,6 @@ packages:
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
engines: {node: '>=4'}
faker@6.6.6:
resolution: {integrity: sha512-9tCqYEDHI5RYFQigXFwF1hnCwcWCOJl/hmll0lr5D2Ljjb0o4wphb69wikeJDz5qCEzXCoPvG6ss5SDP6IfOdg==}
fast-content-type-parse@1.1.0:
resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==}
......@@ -12447,10 +12437,6 @@ snapshots:
'@types/qs': 6.9.16
'@types/serve-static': 1.15.7
'@types/faker@6.6.9':
dependencies:
faker: 6.6.6
'@types/formidable@2.0.6':
dependencies:
'@types/node': 20.14.11
......@@ -14827,8 +14813,6 @@ snapshots:
iconv-lite: 0.4.24
tmp: 0.0.33
faker@6.6.6: {}
fast-content-type-parse@1.1.0: {}
fast-decode-uri-component@1.0.1: {}
......
......@@ -75,7 +75,6 @@
"@faker-js/faker": "^9.0.3",
"@shelf/jest-mongodb": "^4.3.2",
"@svgr/webpack": "^6.5.1",
"@types/faker": "^6.6.9",
"@types/formidable": "^2.0.5",
"@types/js-yaml": "^4.0.9",
"@types/jsonwebtoken": "^9.0.3",
......
......@@ -2,7 +2,7 @@ import {
PushDatasetDataChunkProps,
PushDatasetDataResponse
} from '@fastgpt/global/core/dataset/api';
import { APIFileServer } from '@fastgpt/global/core/dataset/apiDataset';
import { APIFileServer, FeishuServer, YuqueServer } from '@fastgpt/global/core/dataset/apiDataset';
import {
DatasetSearchModeEnum,
DatasetSourceReadTypeEnum,
......@@ -27,6 +27,8 @@ export type CreateDatasetParams = {
vectorModel?: string;
agentModel?: string;
apiServer?: APIFileServer;
feishuServer?: FeishuServer;
yuqueServer?: YuqueServer;
};
export type RebuildEmbeddingProps = {
......
......@@ -29,7 +29,7 @@ async function handler(req: ApiRequestProps<PreviewContextProps>, res: NextApiRe
throw new Error('fileId is empty');
}
const { teamId, apiServer } = await (async () => {
const { teamId, apiServer, feishuServer, yuqueServer } = await (async () => {
if (type === DatasetSourceReadTypeEnum.fileLocal) {
const res = await authCollectionFile({
req,
......@@ -51,7 +51,9 @@ async function handler(req: ApiRequestProps<PreviewContextProps>, res: NextApiRe
});
return {
teamId: dataset.teamId,
apiServer: dataset.apiServer
apiServer: dataset.apiServer,
feishuServer: dataset.feishuServer,
yuqueServer: dataset.yuqueServer
};
})();
......@@ -62,6 +64,8 @@ async function handler(req: ApiRequestProps<PreviewContextProps>, res: NextApiRe
isQAImport,
selector,
apiServer,
feishuServer,
yuqueServer,
externalFileId
});
......
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { addLog } from '@fastgpt/service/common/system/log';
import { TrackEnum } from '@fastgpt/global/common/middle/tracks/constants';
import { TrackModel } from '@fastgpt/service/common/middle/tracks/schema';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { useReqFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequencyLimit';
export type pushQuery = {};
export type pushBody = {
event: TrackEnum;
data: any;
};
export type pushResponse = {};
async function handler(
req: ApiRequestProps<pushBody, pushQuery>,
res: ApiResponseType<any>
): Promise<pushResponse> {
if (!global.feConfigs?.isPlus) return {};
const { teamId, tmbId, userId } = await authCert({
req,
authToken: true
});
const data = {
teamId,
tmbId,
uid: userId,
event: req.body.event,
data: req.body.data
};
addLog.info('Push tracks', data);
return TrackModel.create(data);
}
export default NextAPI(useReqFrequencyLimit(1, 5), handler);
export const config = {
api: {
bodyParser: {
sizeLimit: '5kb'
}
}
};
......@@ -16,6 +16,7 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { MongoUser } from '@fastgpt/service/support/user/schema';
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
export type CreateAppBody = {
parentId?: ParentIdType;
......@@ -35,7 +36,7 @@ async function handler(req: ApiRequestProps<CreateAppBody>) {
}
// 凭证校验
const [{ teamId, tmbId }] = await Promise.all([
const [{ teamId, tmbId, userId }] = await Promise.all([
authUserPer({ req, authToken: true, per: WritePermissionVal }),
...(parentId
? [authApp({ req, appId: parentId, per: WritePermissionVal, authToken: true })]
......@@ -62,6 +63,13 @@ async function handler(req: ApiRequestProps<CreateAppBody>) {
username: user?.username
});
pushTrack.createApp({
type,
uid: userId,
teamId,
tmbId
});
return appId;
}
......
......@@ -16,6 +16,8 @@ import { findAppAndAllChildren } from '@fastgpt/service/core/app/controller';
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { ClientSession } from '@fastgpt/service/common/mongo';
import { deleteChatFiles } from '@fastgpt/service/core/chat/controller';
import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controller';
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string };
......@@ -25,12 +27,20 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
}
// Auth owner (folder owner, can delete all apps in the folder)
const { teamId } = await authApp({ req, authToken: true, appId, per: OwnerPermissionVal });
const { teamId, tmbId, userId, app } = await authApp({
req,
authToken: true,
appId,
per: OwnerPermissionVal
});
await onDelOneApp({
teamId,
appId
});
// Tracks
pushTrack.countAppNodes({ teamId, tmbId, uid: userId, appId });
}
export default NextAPI(handler);
......
......@@ -8,6 +8,7 @@ import { NextAPI } from '@/service/middleware/entry';
import { onCreateApp, type CreateAppBody } from '../create';
import { AppSchema } from '@fastgpt/global/core/app/type';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
export type createHttpPluginQuery = {};
......@@ -28,7 +29,11 @@ async function handler(
return Promise.reject('缺少参数');
}
const { teamId, tmbId } = await authUserPer({ req, authToken: true, per: WritePermissionVal });
const { teamId, tmbId, userId } = await authUserPer({
req,
authToken: true,
per: WritePermissionVal
});
await mongoSessionRun(async (session) => {
// create http plugin folder
......@@ -62,6 +67,13 @@ async function handler(
}
});
pushTrack.createApp({
type: AppTypeEnum.httpPlugin,
uid: userId,
teamId,
tmbId
});
return {};
}
......
......@@ -45,7 +45,9 @@ async function handler(
const { nodes, chatConfig } = await getAppLatestVersion(app._id, app);
const pluginInputs =
app?.modules?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)?.inputs ?? [];
chat?.pluginInputs ??
nodes?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)?.inputs ??
[];
return {
chatId,
......
......@@ -35,6 +35,10 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
}
const { nodes, chatConfig } = await getAppLatestVersion(app._id, app);
const pluginInputs =
chat?.pluginInputs ??
nodes?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)?.inputs ??
[];
jsonRes<InitChatResponse>(res, {
data: {
......@@ -56,9 +60,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
avatar: app.avatar,
intro: app.intro,
type: app.type,
pluginInputs:
app?.modules?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)
?.inputs ?? []
pluginInputs
}
}
});
......
......@@ -43,6 +43,10 @@ async function handler(req: ApiRequestProps<InitTeamChatProps>, res: NextApiResp
// get app and history
const { nodes, chatConfig } = await getAppLatestVersion(app._id, app);
const pluginInputs =
chat?.pluginInputs ??
nodes?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)?.inputs ??
[];
jsonRes<InitChatResponse>(res, {
data: {
......@@ -64,9 +68,7 @@ async function handler(req: ApiRequestProps<InitTeamChatProps>, res: NextApiResp
avatar: app.avatar,
intro: app.intro,
type: app.type,
pluginInputs:
app?.modules?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)
?.inputs ?? []
pluginInputs
}
}
});
......
import { getFeishuAndYuqueDatasetFileList } from '@/service/core/dataset/apiDataset/controller';
import { NextAPI } from '@/service/middleware/entry';
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
import { ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { APIFileItem } from '@fastgpt/global/core/dataset/apiDataset';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
......@@ -26,11 +28,21 @@ async function handler(req: NextApiRequest) {
});
const apiServer = dataset.apiServer;
if (!apiServer) {
return Promise.reject('apiServer is required');
const feishuServer = dataset.feishuServer;
const yuqueServer = dataset.yuqueServer;
if (apiServer) {
return useApiDatasetRequest({ apiServer }).listFiles({ searchKey, parentId });
}
if (feishuServer || yuqueServer) {
return getFeishuAndYuqueDatasetFileList({
feishuServer,
yuqueServer,
parentId
});
}
return useApiDatasetRequest({ apiServer }).listFiles({ searchKey, parentId });
return Promise.reject(DatasetErrEnum.noApiServer);
}
export default NextAPI(handler);
......@@ -34,12 +34,8 @@ async function handler(req: NextApiRequest): CreateCollectionResponse {
});
const apiServer = dataset.apiServer;
if (!apiServer) {
return Promise.reject('Api server not found');
}
if (!apiFileId) {
return Promise.reject('ApiFileId not found');
}
const feishuServer = dataset.feishuServer;
const yuqueServer = dataset.yuqueServer;
// Auth same apiFileId
const storeCol = await MongoDatasetCollection.findOne(
......@@ -57,6 +53,8 @@ async function handler(req: NextApiRequest): CreateCollectionResponse {
const content = await readApiServerFileContent({
apiServer,
feishuServer,
yuqueServer,
apiFileId,
teamId
});
......
......@@ -66,7 +66,9 @@ async function handler(
return {
type: DatasetSourceReadTypeEnum.apiFile,
sourceId: collection.apiFileId,
apiServer: collection.datasetId.apiServer
apiServer: collection.datasetId.apiServer,
feishuServer: collection.datasetId.feishuServer,
yuqueServer: collection.datasetId.yuqueServer
};
}
if (collection.type === DatasetCollectionTypeEnum.externalFile) {
......
......@@ -12,6 +12,7 @@ import { AIChatItemType, ChatHistoryItemResType } from '@fastgpt/global/core/cha
import { authChatCrud } from '@/service/support/permission/auth/chat';
import { getCollectionWithDataset } from '@fastgpt/service/core/dataset/controller';
import { useApiDatasetRequest } from '@fastgpt/service/core/dataset/apiDataset/api';
import { POST } from '@fastgpt/service/common/api/plusRequest';
export type readCollectionSourceQuery = {};
......@@ -148,11 +149,25 @@ async function handler(
}
if (collection.type === DatasetCollectionTypeEnum.apiFile && collection.apiFileId) {
const apiServer = collection.datasetId.apiServer;
if (!apiServer) return Promise.reject('apiServer not found');
const feishuServer = collection.datasetId.feishuServer;
const yuqueServer = collection.datasetId.yuqueServer;
return useApiDatasetRequest({ apiServer }).getFilePreviewUrl({
apiFileId: collection.apiFileId
});
if (apiServer) {
return useApiDatasetRequest({ apiServer }).getFilePreviewUrl({
apiFileId: collection.apiFileId
});
}
if (feishuServer || yuqueServer) {
return POST<string>(`/core/dataset/systemApiDataset`, {
type: 'read',
apiFileId: collection.apiFileId,
feishuServer,
yuqueServer
});
}
return '';
}
if (collection.type === DatasetCollectionTypeEnum.externalFile) {
if (collection.externalFileId && collection.datasetId.externalReadUrl) {
......
......@@ -10,6 +10,7 @@ import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { parseParentIdInMongo } from '@fastgpt/global/common/parentFolder/utils';
import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
export type DatasetCreateQuery = {};
export type DatasetCreateBody = CreateDatasetParams;
......@@ -26,11 +27,13 @@ async function handler(
avatar,
vectorModel = global.vectorModels[0].model,
agentModel = getDatasetModel().model,
apiServer
apiServer,
feishuServer,
yuqueServer
} = req.body;
// auth
const [{ teamId, tmbId }] = await Promise.all([
const [{ teamId, tmbId, userId }] = await Promise.all([
authUserPer({
req,
authToken: true,
......@@ -70,7 +73,16 @@ async function handler(
agentModel,
avatar,
type,
apiServer
apiServer,
feishuServer,
yuqueServer
});
pushTrack.createDataset({
type,
teamId,
tmbId,
uid: userId
});
return _id;
......
......@@ -36,6 +36,19 @@ async function handler(req: ApiRequestProps<Query>): Promise<DatasetItemType> {
authorization: ''
}
: undefined,
yuqueServer: dataset.yuqueServer
? {
userId: dataset.yuqueServer.userId,
token: ''
}
: undefined,
feishuServer: dataset.feishuServer
? {
appId: dataset.feishuServer.appId,
appSecret: '',
folderToken: dataset.feishuServer.folderToken
}
: undefined,
permission,
vectorModel: getVectorModel(dataset.vectorModel),
agentModel: getLLMModel(dataset.agentModel)
......
......@@ -50,7 +50,7 @@ async function handler(
throw new Error('chunkSize is too large, should be less than 30000');
}
const { teamId, apiServer } = await (async () => {
const { teamId, apiServer, feishuServer, yuqueServer } = await (async () => {
if (type === DatasetSourceReadTypeEnum.fileLocal) {
const res = await authCollectionFile({
req,
......@@ -72,7 +72,9 @@ async function handler(
});
return {
teamId: dataset.teamId,
apiServer: dataset.apiServer
apiServer: dataset.apiServer,
feishuServer: dataset.feishuServer,
yuqueServer: dataset.yuqueServer
};
})();
......@@ -83,6 +85,8 @@ async function handler(
selector,
isQAImport,
apiServer,
feishuServer,
yuqueServer,
externalFileId
});
......
......@@ -57,6 +57,8 @@ async function handler(
websiteConfig,
externalReadUrl,
apiServer,
yuqueServer,
feishuServer,
status,
autoSync
} = req.body;
......@@ -124,6 +126,13 @@ async function handler(
...(!!apiServer?.authorization && {
'apiServer.authorization': apiServer.authorization
}),
...(!!yuqueServer?.userId && { 'yuqueServer.userId': yuqueServer.userId }),
...(!!yuqueServer?.token && { 'yuqueServer.token': yuqueServer.token }),
...(!!feishuServer?.appId && { 'feishuServer.appId': feishuServer.appId }),
...(!!feishuServer?.appSecret && { 'feishuServer.appSecret': feishuServer.appSecret }),
...(!!feishuServer?.folderToken && {
'feishuServer.folderToken': feishuServer.folderToken
}),
...(isMove && { inheritPermission: true }),
...(typeof autoSync === 'boolean' && { autoSync })
},
......
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { POST } from '@fastgpt/service/common/api/plusRequest';
import { NextAPI } from '@/service/middleware/entry';
export type OutLinkDingtalkQuery = any;
export type OutLinkDingtalkBody = any;
export type OutLinkFeishuResponse = {};
async function handler(
req: ApiRequestProps<OutLinkDingtalkBody, OutLinkDingtalkQuery>,
res: ApiResponseType<any>
): Promise<any> {
if (req.method === 'GET') {
return {
success: true
};
}
// send to pro
const { token } = req.query;
const result = await POST<any>(`support/outLink/dingtalk/${token}`, req.body, {
headers: req.headers as any
});
return result;
}
export default NextAPI(handler);
......@@ -9,13 +9,11 @@ async function handler(
req: ApiRequestProps<OutLinkOffiAccountBody, OutLinkOffiAccountQuery>,
res: ApiResponseType<any>
): Promise<any> {
const { token, type } = req.query;
const { token } = req.query;
const result = await plusRequest({
method: req.method,
url: `support/outLink/offiaccount/${token}`,
params: {
...req.query,
type
},
params: req.query,
data: req.body
});
......
......@@ -6,6 +6,7 @@ import type { PostLoginProps } from '@fastgpt/global/support/user/api.d';
import { UserStatusEnum } from '@fastgpt/global/support/user/constant';
import { NextAPI } from '@/service/middleware/entry';
import { useReqFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequencyLimit';
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { username, password } = req.body as PostLoginProps;
......@@ -47,6 +48,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
lastLoginTmbId: userDetail.team.tmbId
});
pushTrack.login({
type: 'password',
uid: user._id,
teamId: userDetail.team.teamId,
tmbId: userDetail.team.tmbId
});
const token = createJWT({
...userDetail,
isRoot: username === 'root'
......
......@@ -10,7 +10,6 @@ import dynamic from 'next/dynamic';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import { PluginRunBoxTabEnum } from '@/components/core/chat/ChatContainer/PluginRunBox/constants';
import CloseIcon from '@fastgpt/web/components/common/Icon/close';
import ChatBox from '@/components/core/chat/ChatContainer/ChatBox';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { PcHeader } from '@/pages/chat/components/ChatHeader';
import { GetChatTypeEnum } from '@/global/core/chat/constants';
......@@ -22,6 +21,7 @@ import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useContextSelector } from 'use-context-selector';
const PluginRunBox = dynamic(() => import('@/components/core/chat/ChatContainer/PluginRunBox'));
const ChatBox = dynamic(() => import('@/components/core/chat/ChatContainer/ChatBox'));
type Props = {
appId: string;
......@@ -148,10 +148,12 @@ const DetailLogsModal = ({ appId, chatId, onClose }: Props) => {
)}
{/* Chat container */}
<Box pt={2} flex={'1 0 0'}>
<Box pt={2} flex={'1 0 0'} h={0}>
{isPlugin ? (
<Box px={5} pt={2} h={'100%'}>
<PluginRunBox appId={appId} chatId={chatId} />
<Box h={'100%'} overflow={'auto'}>
<Box px={5} py={2}>
<PluginRunBox appId={appId} chatId={chatId} />
</Box>
</Box>
) : (
<ChatBox
......
import React from 'react';
import { Flex, Box, Button, ModalBody, Input, Link } from '@chakra-ui/react';
import MyModal from '@fastgpt/web/components/common/MyModal';
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
import type { DingtalkAppType, OutLinkEditType } from '@fastgpt/global/support/outLink/type';
import { useTranslation } from 'next-i18next';
import { useForm } from 'react-hook-form';
import { createShareChat, updateShareChat } from '@/web/support/outLink/api';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import BasicInfo from '../components/BasicInfo';
import { getDocPath } from '@/web/common/system/doc';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyIcon from '@fastgpt/web/components/common/Icon';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
const DingTalkEditModal = ({
appId,
defaultData,
onClose,
onCreate,
onEdit,
isEdit = false
}: {
appId: string;
defaultData: OutLinkEditType<DingtalkAppType>;
onClose: () => void;
onCreate: (id: string) => void;
onEdit: () => void;
isEdit?: boolean;
}) => {
const { t } = useTranslation();
const {
register,
setValue,
handleSubmit: submitShareChat
} = useForm({
defaultValues: defaultData
});
const { runAsync: onclickCreate, loading: creating } = useRequest2(
(e: Omit<OutLinkEditType<DingtalkAppType>, 'appId' | 'type'>) =>
createShareChat({
...e,
appId,
type: PublishChannelEnum.dingtalk,
app: {
clientId: e?.app?.clientId?.trim(),
clientSecret: e.app?.clientSecret?.trim()
}
}),
{
errorToast: t('common:common.Create Failed'),
successToast: t('common:common.Create Success'),
onSuccess: onCreate
}
);
const { runAsync: onclickUpdate, loading: updating } = useRequest2(
(e) =>
updateShareChat({
...e,
app: {
clientId: e?.app?.clientId?.trim(),
clientSecret: e.app?.clientSecret?.trim()
}
}),
{
errorToast: t('common:common.Update Failed'),
successToast: t('common:common.Update Success'),
onSuccess: onEdit
}
);
const { feConfigs } = useSystemStore();
return (
<MyModal
iconSrc="common/dingtalkFill"
title={
isEdit ? t('publish:dingtalk.edit_modal_title') : t('publish:dingtalk.create_modal_title')
}
minW={['auto', '60rem']}
>
<ModalBody display={'grid'} gridTemplateColumns={['1fr', '1fr 1fr']} fontSize={'14px'} p={0}>
<Box p={8} h={['auto', '400px']} borderRight={'base'}>
<BasicInfo register={register} setValue={setValue} defaultData={defaultData} />
</Box>
<Flex p={8} h={['auto', '400px']} flexDirection="column" gap={6}>
<Flex alignItems="center">
<Box color="myGray.600">{t('publish:dingtalk.api')}</Box>
{feConfigs?.docUrl && (
<Link
href={
feConfigs.openAPIDocUrl ||
getDocPath('/docs/use-cases/external-integration/dingtalk/')
}
target={'_blank'}
ml={2}
color={'primary.500'}
fontSize={'sm'}
>
<Flex alignItems={'center'}>
<MyIcon w={'17px'} h={'17px'} name="book" mr="1" />
{t('common:common.Read document')}
</Flex>
</Link>
)}
</Flex>
<Flex alignItems={'center'}>
<FormLabel flex={'0 0 6.25rem'} required>
Client ID
</FormLabel>
<Input
placeholder={'Client ID'}
{...register('app.clientId', {
required: true
})}
/>
</Flex>
<Flex alignItems={'center'}>
<FormLabel flex={'0 0 6.25rem'} required>
Client Secret
</FormLabel>
<Input
placeholder={'Client Secret'}
{...register('app.clientSecret', {
required: true
})}
/>
</Flex>
<Box flex={1}></Box>
<Flex justifyContent={'end'}>
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
{t('common:common.Close')}
</Button>
<Button
isLoading={creating || updating}
onClick={submitShareChat((data) =>
isEdit ? onclickUpdate(data) : onclickCreate(data)
)}
>
{t('common:common.Confirm')}
</Button>
</Flex>
</Flex>
</ModalBody>
</MyModal>
);
};
export default DingTalkEditModal;
import React, { useMemo, useState } from 'react';
import {
Flex,
Box,
Button,
TableContainer,
Table,
Thead,
Tr,
Th,
Td,
Tbody,
useDisclosure,
Link,
HStack
} from '@chakra-ui/react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useLoading } from '@fastgpt/web/hooks/useLoading';
import { getShareChatList, delShareChatById } from '@/web/support/outLink/api';
import { formatTimeToChatTime } from '@fastgpt/global/common/string/time';
import { defaultDingtalkOutlinkForm } from '@/web/core/app/constants';
import type { DingtalkAppType, OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
import { PublishChannelEnum } from '@fastgpt/global/support/outLink/constant';
import { useTranslation } from 'next-i18next';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import dayjs from 'dayjs';
import dynamic from 'next/dynamic';
import MyMenu from '@fastgpt/web/components/common/MyMenu';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { getDocPath } from '@/web/common/system/doc';
const DingTalkEditModal = dynamic(() => import('./DingTalkEditModal'));
const ShowShareLinkModal = dynamic(() => import('../components/showShareLinkModal'));
const DingTalk = ({ appId }: { appId: string }) => {
const { t } = useTranslation();
const { Loading, setIsLoading } = useLoading();
const { feConfigs } = useSystemStore();
const [editDingTalkLinkData, setEditDingTalkLinkData] =
useState<OutLinkEditType<DingtalkAppType>>();
const [isEdit, setIsEdit] = useState<boolean>(false);
const baseUrl = useMemo(
() => feConfigs?.customApiDomain || `${location.origin}/api`,
[feConfigs?.customApiDomain]
);
const {
data: shareChatList = [],
loading: isFetching,
runAsync: refetchShareChatList
} = useRequest2(
() => getShareChatList<DingtalkAppType>({ appId, type: PublishChannelEnum.dingtalk }),
{
manual: false
}
);
const {
onOpen: openShowShareLinkModal,
isOpen: showShareLinkModalOpen,
onClose: closeShowShareLinkModal
} = useDisclosure();
const [showShareLink, setShowShareLink] = useState<string | null>(null);
return (
<Box position={'relative'} pt={3} px={5} minH={'50vh'}>
<Flex justifyContent={'space-between'} flexDirection="row">
<HStack>
<Box fontWeight={'bold'} fontSize={['md', 'lg']}>
{t('publish:dingtalk.title')}
</Box>
{feConfigs?.docUrl && (
<Link
href={
feConfigs.openAPIDocUrl ||
getDocPath('/docs/use-cases/external-integration/dingtalk/')
}
target={'_blank'}
color={'primary.500'}
fontSize={'sm'}
>
<Flex alignItems={'center'}>
<MyIcon name="book" mr="1" w={'1rem'} />
{t('common:common.Read document')}
</Flex>
</Link>
)}
</HStack>
<Button
variant={'primary'}
colorScheme={'blue'}
size={['sm', 'md']}
leftIcon={<MyIcon name={'common/addLight'} w="1.25rem" color="white" />}
ml={3}
{...(shareChatList.length >= 10
? {
isDisabled: true,
title: t('common:core.app.share.Amount limit tip')
}
: {})}
onClick={() => {
setEditDingTalkLinkData(defaultDingtalkOutlinkForm);
setIsEdit(false);
}}
>
{t('common:add_new')}
</Button>
</Flex>
<TableContainer mt={3}>
<Table variant={'simple'} w={'100%'} overflowX={'auto'} fontSize={'sm'}>
<Thead>
<Tr>
<Th>{t('common:common.Name')}</Th>
<Th>{t('common:support.outlink.Usage points')}</Th>
{feConfigs?.isPlus && (
<>
<Th>{t('common:core.app.share.Ip limit title')}</Th>
<Th>{t('common:common.Expired Time')}</Th>
</>
)}
<Th>{t('common:common.Last use time')}</Th>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{shareChatList.map((item) => (
<Tr key={item._id}>
<Td>{item.name}</Td>
<Td>
{Math.round(item.usagePoints)}
{feConfigs?.isPlus
? `${
item.limit?.maxUsagePoints && item.limit.maxUsagePoints > -1
? ` / ${item.limit.maxUsagePoints}`
: ` / ${t('common:common.Unlimited')}`
}`
: ''}
</Td>
{feConfigs?.isPlus && (
<>
<Td>{item?.limit?.QPM || '-'}</Td>
<Td>
{item?.limit?.expiredTime
? dayjs(item.limit?.expiredTime).format('YYYY/MM/DD\nHH:mm')
: '-'}
</Td>
</>
)}
<Td>
{item.lastTime
? t(formatTimeToChatTime(item.lastTime) as any).replace('#', ':')
: t('common:common.Un used')}
</Td>
<Td display={'flex'} alignItems={'center'}>
<Button
onClick={() => {
setShowShareLink(`${baseUrl}/support/outLink/dingtalk/${item.shareId}`);
openShowShareLinkModal();
}}
size={'sm'}
mr={3}
variant={'whitePrimary'}
>
{t('publish:request_address')}
</Button>
<MyMenu
Button={
<MyIcon
name={'more'}
_hover={{ bg: 'myGray.100' }}
cursor={'pointer'}
borderRadius={'md'}
w={'14px'}
p={2}
/>
}
menuList={[
{
children: [
{
label: t('common:common.Edit'),
icon: 'edit',
onClick: () => {
setEditDingTalkLinkData({
_id: item._id,
name: item.name,
limit: item.limit,
app: item.app,
responseDetail: item.responseDetail,
defaultResponse: item.defaultResponse,
immediateResponse: item.immediateResponse
});
setIsEdit(true);
}
},
{
label: t('common:common.Delete'),
icon: 'delete',
onClick: async () => {
setIsLoading(true);
try {
await delShareChatById(item._id);
refetchShareChatList();
} catch (error) {
console.log(error);
}
setIsLoading(false);
}
}
]
}
]}
/>
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
{editDingTalkLinkData && (
<DingTalkEditModal
appId={appId}
defaultData={editDingTalkLinkData}
onCreate={() => Promise.all([refetchShareChatList(), setEditDingTalkLinkData(undefined)])}
onEdit={() => Promise.all([refetchShareChatList(), setEditDingTalkLinkData(undefined)])}
onClose={() => setEditDingTalkLinkData(undefined)}
isEdit={isEdit}
/>
)}
{shareChatList.length === 0 && !isFetching && (
<EmptyTip text={t('common:core.app.share.Not share link')}></EmptyTip>
)}
<Loading loading={isFetching} fixed={false} />
{showShareLinkModalOpen && (
<ShowShareLinkModal
shareLink={showShareLink ?? ''}
onClose={closeShowShareLinkModal}
img="/imgs/outlink/dingtalk-copylink-instruction.png"
/>
)}
</Box>
);
};
export default React.memo(DingTalk);
......@@ -16,6 +16,7 @@ import { useToast } from '@fastgpt/web/hooks/useToast';
const Link = dynamic(() => import('./Link'));
const API = dynamic(() => import('./API'));
const FeiShu = dynamic(() => import('./FeiShu'));
const DingTalk = dynamic(() => import('./DingTalk'));
// const Wecom = dynamic(() => import('./Wecom'));
const OffiAccount = dynamic(() => import('./OffiAccount'));
......@@ -48,6 +49,13 @@ const OutLink = () => {
value: PublishChannelEnum.feishu,
isProFn: true
},
{
icon: 'common/dingtalkFill',
title: t('publish:dingtalk.bot'),
desc: t('publish:dingtalk.bot_desc'),
value: PublishChannelEnum.dingtalk,
isProFn: true
},
// {
// icon: 'core/app/publish/wecom',
// title: t('publish:wecom.bot'),
......@@ -114,6 +122,7 @@ const OutLink = () => {
)}
{linkType === PublishChannelEnum.apikey && <API appId={appId} />}
{linkType === PublishChannelEnum.feishu && <FeiShu appId={appId} />}
{linkType === PublishChannelEnum.dingtalk && <DingTalk appId={appId} />}
{/* {linkType === PublishChannelEnum.wecom && <Wecom appId={appId} />} */}
{linkType === PublishChannelEnum.officialAccount && <OffiAccount appId={appId} />}
</Flex>
......
import { Box, Flex } from '@chakra-ui/react';
import React from 'react';
import React, { useMemo } from 'react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import { nodeTemplate2FlowNode } from '@/web/core/workflow/utils';
......@@ -8,12 +8,14 @@ import { useContextSelector } from 'use-context-selector';
import { useReactFlow } from 'reactflow';
import { WorkflowNodeEdgeContext } from '../../context/workflowInitContext';
import { WorkflowEventContext } from '../../context/workflowEventContext';
import { WorkflowContext } from '../../context';
const ContextMenu = () => {
const { t } = useTranslation();
const setNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.setNodes);
const menu = useContextSelector(WorkflowEventContext, (v) => v.menu);
const setMenu = useContextSelector(WorkflowEventContext, (ctx) => ctx.setMenu);
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
const { screenToFlowPosition } = useReactFlow();
const newNode = nodeTemplate2FlowNode({
......@@ -22,38 +24,44 @@ const ContextMenu = () => {
t
});
return (
!!menu && (
<Box position="relative">
<Box
position="absolute"
top={`${menu.top - 6}px`}
left={`${menu.left + 10}px`}
width={0}
height={0}
borderLeft="6px solid transparent"
borderRight="6px solid transparent"
borderBottom="6px solid white"
zIndex={2}
filter="drop-shadow(0px -1px 2px rgba(0, 0, 0, 0.1))"
/>
const allUnFolded = useMemo(() => {
return !!menu ? nodeList.some((node) => node.isFolded) : false;
}, [nodeList, menu]);
return !!menu ? (
<Box position="relative">
<Box
position="absolute"
top={`${menu.top - 6}px`}
left={`${menu.left + 10}px`}
width={0}
height={0}
borderLeft="6px solid transparent"
borderRight="6px solid transparent"
borderBottom="6px solid white"
zIndex={2}
filter="drop-shadow(0px -1px 2px rgba(0, 0, 0, 0.1))"
/>
<Box
position={'absolute'}
top={menu.top}
left={menu.left}
bg={'white'}
w={'120px'}
rounded={'md'}
boxShadow={'0px 2px 4px 0px #A1A7B340'}
className="context-menu"
color={'myGray.600'}
p={1}
zIndex={10}
>
<Flex
position={'absolute'}
top={menu.top}
left={menu.left}
bg={'white'}
w={'120px'}
height={9}
p={1}
rounded={'md'}
boxShadow={'0px 2px 4px 0px #A1A7B340'}
className="context-menu"
alignItems={'center'}
color={'myGray.600'}
px={2}
py={1}
cursor={'pointer'}
_hover={{
color: 'primary.500'
}}
borderRadius={'sm'}
_hover={{ bg: 'myGray.50', color: 'primary.500' }}
onClick={() => {
setMenu(null);
setNodes((state) => {
......@@ -67,16 +75,41 @@ const ContextMenu = () => {
return newState;
});
}}
zIndex={1}
>
<MyIcon name="comment" w={'16px'} h={'16px'} ml={1} />
<MyIcon name="comment" w={'1rem'} ml={1} />
<Box fontSize={'12px'} fontWeight={'500'} ml={1.5}>
{t('workflow:context_menu.add_comment')}
</Box>
</Flex>
<Flex
mt={1}
alignItems={'center'}
px={2}
py={1}
cursor={'pointer'}
borderRadius={'sm'}
_hover={{ bg: 'myGray.50', color: 'primary.500' }}
onClick={() => {
setMenu(null);
setNodes((state) => {
return state.map((node) => ({
...node,
data: {
...node.data,
isFolded: !allUnFolded
}
}));
});
}}
>
<MyIcon name="common/select" w={'1rem'} ml={1} />
<Box fontSize={'12px'} fontWeight={'500'} ml={1.5}>
{allUnFolded ? t('workflow:unFoldAll') : t('workflow:foldAll')}
</Box>
</Flex>
</Box>
)
);
</Box>
) : null;
};
export default React.memo(ContextMenu);
......@@ -126,7 +126,6 @@ const Workflow = () => {
<NodeTemplatesModal isOpen={isOpenTemplate} onClose={onCloseTemplate} />
</>
<ContextMenu />
<ReactFlow
ref={reactFlowWrapper}
fitView
......@@ -162,6 +161,7 @@ const Workflow = () => {
: {})}
onNodeDragStop={onNodeDragStop}
>
<ContextMenu />
<FlowController />
<HelperLines horizontal={helperLineHorizontal} vertical={helperLineVertical} />
</ReactFlow>
......
......@@ -282,7 +282,7 @@ const NodeCard = (props: Props) => {
</MyTooltip>
)}
</Flex>
{intro && <NodeIntro nodeId={nodeId} intro={intro} />}
<NodeIntro nodeId={nodeId} intro={intro} />
</Box>
)}
<MenuRender nodeId={nodeId} menuForbid={menuForbid} nodeList={nodeList} />
......@@ -580,7 +580,7 @@ const NodeIntro = React.memo(function NodeIntro({
<>
<Flex alignItems={'center'}>
<Box fontSize={'sm'} color={'myGray.500'} flex={'1 0 0'}>
{t(intro as any)}
{t(intro as any) || t('app:node_not_intro')}
</Box>
{NodeIsTool && (
<Flex
......
......@@ -33,6 +33,7 @@ import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
import SearchInput from '../../../../../../../packages/web/components/common/Input/SearchInput/index';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { webPushTrack } from '@/web/common/middle/tracks/utils';
type TemplateAppType = AppTypeEnum | 'all';
......@@ -98,6 +99,13 @@ const TemplateMarketModal = ({
modules: templateDetail.workflow.nodes || [],
edges: templateDetail.workflow.edges || [],
chatConfig: templateDetail.workflow.chatConfig
}).then((res) => {
webPushTrack.useAppTemplate({
id,
name: templateDetail.name
});
return res;
});
},
{
......
import React from 'react';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { Flex, Input } from '@chakra-ui/react';
import { UseFormReturn } from 'react-hook-form';
import { useTranslation } from 'next-i18next';
import type {
APIFileServer,
FeishuServer,
YuqueServer
} from '@fastgpt/global/core/dataset/apiDataset';
const ApiDatasetForm = ({
type,
form
}: {
type: `${DatasetTypeEnum}`;
form: UseFormReturn<
{
apiServer?: APIFileServer;
feishuServer?: FeishuServer;
yuqueServer?: YuqueServer;
},
any
>;
}) => {
const { t } = useTranslation();
const { register } = form;
return (
<>
{type === DatasetTypeEnum.apiDataset && (
<>
<Flex mt={6}>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
{t('dataset:api_url')}
</Flex>
<Input
bg={'myWhite.600'}
placeholder={t('dataset:api_url')}
maxLength={200}
{...register('apiServer.baseUrl', { required: true })}
/>
</Flex>
<Flex mt={6}>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
Authorization
</Flex>
<Input
bg={'myWhite.600'}
placeholder={t('dataset:request_headers')}
maxLength={200}
{...register('apiServer.authorization')}
/>
</Flex>
</>
)}
{type === DatasetTypeEnum.feishu && (
<>
<Flex mt={6}>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
App ID
</Flex>
<Input
bg={'myWhite.600'}
placeholder={'App ID'}
maxLength={200}
{...register('feishuServer.appId', { required: true })}
/>
</Flex>
<Flex mt={6}>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
App Secret
</Flex>
<Input
bg={'myWhite.600'}
placeholder={'App Secret'}
maxLength={200}
{...register('feishuServer.appSecret', { required: true })}
/>
</Flex>
<Flex mt={6}>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
Folder Token
</Flex>
<Input
bg={'myWhite.600'}
placeholder={'Folder Token'}
maxLength={200}
{...register('feishuServer.folderToken', { required: true })}
/>
</Flex>
</>
)}
{type === DatasetTypeEnum.yuque && (
<>
<Flex mt={6}>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
User ID
</Flex>
<Input
bg={'myWhite.600'}
placeholder={'Token'}
maxLength={200}
{...register('yuqueServer.userId', { required: true })}
/>
</Flex>
<Flex mt={6}>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
Token
</Flex>
<Input
bg={'myWhite.600'}
placeholder={'Token'}
maxLength={200}
{...register('yuqueServer.token', { required: true })}
/>
</Flex>
</>
)}
</>
);
};
export default ApiDatasetForm;
......@@ -386,7 +386,9 @@ const Header = ({}: {}) => {
/>
)}
{/* apiDataset */}
{datasetDetail?.type === DatasetTypeEnum.apiDataset && (
{(datasetDetail?.type === DatasetTypeEnum.apiDataset ||
datasetDetail?.type === DatasetTypeEnum.feishu ||
datasetDetail?.type === DatasetTypeEnum.yuque) && (
<Flex
px={3.5}
py={2}
......
......@@ -177,8 +177,7 @@ const Upload = () => {
router.replace({
query: {
datasetId: datasetDetail._id,
currentTab: retrainNewCollectionId.current ? TabEnum.dataCard : TabEnum.collectionCard,
collectionId: retrainNewCollectionId.current
currentTab: TabEnum.collectionCard
}
});
},
......
......@@ -49,23 +49,26 @@ const CustomAPIFileInput = () => {
parentId: '',
parentName: ''
});
const [parentUuid, setParentUuid] = useState<string>('');
const [paths, setPaths] = useState<ParentTreePathItemType[]>([]);
const [searchKey, setSearchKey] = useState('');
const { data: fileList = [], loading } = useRequest2(
async () =>
datasetDetail?.apiServer
? getApiDatasetFileList({
datasetId: datasetDetail._id,
parentId: parent?.parentId,
searchKey: searchKey
})
: [],
async () => {
return getApiDatasetFileList({
datasetId: datasetDetail._id,
parentId: parent?.parentId,
searchKey: searchKey
});
},
{
refreshDeps: [datasetDetail._id, datasetDetail.apiServer, parent, searchKey],
throttleWait: 500,
manual: false
}
);
const { data: existIdList = [] } = useRequest2(
() => getApiDatasetFileListExistId({ datasetId: datasetDetail._id }),
{
......@@ -90,6 +93,7 @@ const CustomAPIFileInput = () => {
datasetId: datasetDetail._id,
parentId: file?.id
});
const subFiles = await getFilesRecursively(folderFiles);
allFiles.push(...subFiles);
} else {
......@@ -125,6 +129,7 @@ const CustomAPIFileInput = () => {
const handleItemClick = useCallback(
(item: APIFileItem) => {
if (item.type === 'folder') {
setPaths((state) => [...state, { parentId: item.id, parentName: item.name }]);
return setParent({
parentId: item.id,
parentName: item.name
......@@ -138,7 +143,7 @@ const CustomAPIFileInput = () => {
setSelectFiles((state) => [...state, item]);
}
},
[selectFiles, setSelectFiles]
[selectFiles]
);
const handleSelectAll = useCallback(() => {
......@@ -151,8 +156,6 @@ const CustomAPIFileInput = () => {
}
}, [fileList, selectFiles]);
const paths = useMemo(() => [parent || { parentId: '', parentName: '' }], [parent]);
return (
<MyBox isLoading={loading} position="relative" h="full">
<Flex flexDirection={'column'} h="full">
......@@ -160,21 +163,21 @@ const CustomAPIFileInput = () => {
<FolderPath
paths={paths}
onClick={(parentId) => {
if (parentId !== parent?.parentId) {
setParent({
parentId,
parentName: ''
});
}
const index = paths.findIndex((item) => item.parentId === parentId);
setParent(paths[index]);
setPaths(paths.slice(0, index + 1));
}}
/>
<Box w={'240px'}>
<SearchInput
value={searchKey}
onChange={(e) => setSearchKey(e.target.value)}
placeholder={t('common:core.workflow.template.Search')}
/>
</Box>
{datasetDetail.apiServer && (
<Box w={'240px'}>
<SearchInput
value={searchKey}
onChange={(e) => setSearchKey(e.target.value)}
placeholder={t('common:core.workflow.template.Search')}
/>
</Box>
)}
</Flex>
<Box flex={1} overflowY="auto" mb={16}>
<Box ml={2} mt={3}>
......
import React from 'react';
import { ModalFooter, ModalBody, Input, Button, Flex } from '@chakra-ui/react';
import { ModalFooter, ModalBody, Button, Flex } from '@chakra-ui/react';
import MyModal from '@fastgpt/web/components/common/MyModal/index';
import { useTranslation } from 'next-i18next';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useForm } from 'react-hook-form';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { APIFileServer } from '@fastgpt/global/core/dataset/apiDataset';
import { APIFileServer, FeishuServer, YuqueServer } from '@fastgpt/global/core/dataset/apiDataset';
import ApiDatasetForm from '@/pages/dataset/component/ApiDatasetForm';
import { useContextSelector } from 'use-context-selector';
import { DatasetPageContext } from '@/web/core/dataset/context/datasetPageContext';
import { datasetTypeCourseMap } from '@/web/core/dataset/constants';
import { getDocPath } from '@/web/common/system/doc';
import MyIcon from '@fastgpt/web/components/common/Icon';
export type EditAPIDatasetInfoFormType = {
id: string;
apiServer?: APIFileServer;
yuqueServer?: YuqueServer;
feishuServer?: FeishuServer;
};
const EditAPIDatasetInfoModal = ({
......@@ -24,7 +32,11 @@ const EditAPIDatasetInfoModal = ({
}) => {
const { t } = useTranslation();
const { toast } = useToast();
const { register, handleSubmit } = useForm<EditAPIDatasetInfoFormType>({
const datasetDetail = useContextSelector(DatasetPageContext, (v) => v.datasetDetail);
const type = datasetDetail.type;
const form = useForm<EditAPIDatasetInfoFormType>({
defaultValues: defaultForm
});
......@@ -44,43 +56,24 @@ const EditAPIDatasetInfoModal = ({
return (
<MyModal isOpen onClose={onClose} w={'450px'} iconSrc="modal/edit" title={title}>
<ModalBody>
<Flex>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
{t('dataset:api_url')}
</Flex>
<Input
bg={'myWhite.600'}
placeholder={t('dataset:api_url')}
maxLength={200}
{...register('apiServer.baseUrl', { required: true })}
/>
</Flex>
<Flex mt={6}>
{datasetTypeCourseMap[type] && (
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
justifyContent={'flex-end'}
color={'primary.600'}
fontSize={'sm'}
cursor={'pointer'}
onClick={() => window.open(getDocPath(datasetTypeCourseMap[type]), '_blank')}
>
Authorization
<MyIcon name={'book'} w={4} mr={0.5} />
{t('common:Instructions')}
</Flex>
<Input
bg={'myWhite.600'}
placeholder={t('dataset:request_headers')}
maxLength={200}
{...register('apiServer.authorization')}
/>
</Flex>
)}
{/* @ts-ignore */}
<ApiDatasetForm type={type} form={form} />
</ModalBody>
<ModalFooter>
<Button isLoading={loading} onClick={handleSubmit(onSave)} px={6}>
<Button isLoading={loading} onClick={form.handleSubmit(onSave)} px={6}>
{t('common:common.Confirm')}
</Button>
</ModalFooter>
......
......@@ -29,13 +29,12 @@ import {
} from '@/web/core/dataset/api/collaborator';
import DatasetTypeTag from '@/components/core/dataset/DatasetTypeTag';
import dynamic from 'next/dynamic';
import EditAPIDatasetInfoModal, {
EditAPIDatasetInfoFormType
} from './components/EditApiServiceModal';
import type { EditAPIDatasetInfoFormType } from './components/EditApiServiceModal';
import { EditResourceInfoFormType } from '@/components/common/Modal/EditResourceModal';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
const EditResourceModal = dynamic(() => import('@/components/common/Modal/EditResourceModal'));
const EditAPIDatasetInfoModal = dynamic(() => import('./components/EditApiServiceModal'));
const Info = ({ datasetId }: { datasetId: string }) => {
const { t } = useTranslation();
......@@ -326,6 +325,56 @@ const Info = ({ datasetId }: { datasetId: string }) => {
</Box>
</>
)}
{datasetDetail.type === DatasetTypeEnum.yuque && (
<>
<Box w={'100%'} alignItems={'center'} pt={4}>
<Flex justifyContent={'space-between'} mb={1}>
<FormLabel fontSize={'mini'} fontWeight={'500'}>
{t('dataset:yuque_dataset_config')}
</FormLabel>
<MyIcon
name={'edit'}
w={'14px'}
_hover={{ color: 'primary.600' }}
cursor={'pointer'}
onClick={() =>
setEditedAPIDataset({
id: datasetDetail._id,
yuqueServer: datasetDetail.yuqueServer
})
}
/>
</Flex>
<Box fontSize={'mini'}>{datasetDetail.yuqueServer?.userId}</Box>
</Box>
</>
)}
{datasetDetail.type === DatasetTypeEnum.feishu && (
<>
<Box w={'100%'} alignItems={'center'} pt={4}>
<Flex justifyContent={'space-between'} mb={1}>
<FormLabel fontSize={'mini'} fontWeight={'500'}>
{t('dataset:feishu_dataset_config')}
</FormLabel>
<MyIcon
name={'edit'}
w={'14px'}
_hover={{ color: 'primary.600' }}
cursor={'pointer'}
onClick={() =>
setEditedAPIDataset({
id: datasetDetail._id,
feishuServer: datasetDetail.feishuServer
})
}
/>
</Flex>
<Box fontSize={'mini'}>{datasetDetail.feishuServer?.folderToken}</Box>
</Box>
</>
)}
</Box>
{datasetDetail.permission.hasManagePer && (
......@@ -384,12 +433,14 @@ const Info = ({ datasetId }: { datasetId: string }) => {
{editedAPIDataset && (
<EditAPIDatasetInfoModal
{...editedAPIDataset}
title={t('common:dataset.Edit API Service')}
title={t('dataset:edit_dataset_config')}
onClose={() => setEditedAPIDataset(undefined)}
onEdit={(data) =>
updateDataset({
id: datasetId,
apiServer: data.apiServer
apiServer: data.apiServer,
yuqueServer: data.yuqueServer,
feishuServer: data.feishuServer
})
}
/>
......
......@@ -22,11 +22,15 @@ import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import ComplianceTip from '@/components/common/ComplianceTip/index';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { getDocPath } from '@/web/common/system/doc';
import { datasetTypeCourseMap } from '@/web/core/dataset/constants';
import ApiDatasetForm from '../../component/ApiDatasetForm';
export type CreateDatasetType =
| DatasetTypeEnum.dataset
| DatasetTypeEnum.apiDataset
| DatasetTypeEnum.websiteDataset;
| DatasetTypeEnum.websiteDataset
| DatasetTypeEnum.feishu
| DatasetTypeEnum.yuque;
const CreateModal = ({
onClose,
......@@ -43,35 +47,45 @@ const CreateModal = ({
const { vectorModelList, datasetModelList } = useSystemStore();
const { isPc } = useSystem();
const databaseNameMap = useMemo(() => {
const datasetTypeMap = useMemo(() => {
return {
[DatasetTypeEnum.dataset]: t('dataset:common_dataset'),
[DatasetTypeEnum.apiDataset]: t('dataset:api_file'),
[DatasetTypeEnum.websiteDataset]: t('dataset:website_dataset')
[DatasetTypeEnum.dataset]: {
name: t('dataset:common_dataset'),
icon: 'core/dataset/commonDatasetColor'
},
[DatasetTypeEnum.apiDataset]: {
name: t('dataset:api_file'),
icon: 'core/dataset/externalDatasetColor'
},
[DatasetTypeEnum.websiteDataset]: {
name: t('dataset:website_dataset'),
icon: 'core/dataset/websiteDatasetColor'
},
[DatasetTypeEnum.feishu]: {
name: t('dataset:feishu_dataset'),
icon: 'core/dataset/feishuDatasetColor'
},
[DatasetTypeEnum.yuque]: {
name: t('dataset:yuque_dataset'),
icon: 'core/dataset/yuqueDatasetColor'
}
};
}, [t]);
const iconMap = useMemo(() => {
return {
[DatasetTypeEnum.dataset]: 'core/dataset/commonDatasetColor',
[DatasetTypeEnum.apiDataset]: 'core/dataset/externalDatasetColor',
[DatasetTypeEnum.websiteDataset]: 'core/dataset/websiteDatasetColor'
};
}, []);
const filterNotHiddenVectorModelList = vectorModelList.filter((item) => !item.hidden);
const { register, setValue, handleSubmit, watch } = useForm<CreateDatasetParams>({
const form = useForm<CreateDatasetParams>({
defaultValues: {
parentId,
type: type || DatasetTypeEnum.dataset,
avatar: iconMap[type] || 'core/dataset/commonDatasetColor',
avatar: datasetTypeMap[type].icon,
name: '',
intro: '',
vectorModel: filterNotHiddenVectorModelList[0].model,
agentModel: datasetModelList[0].model
}
});
const { register, setValue, handleSubmit, watch } = form;
const avatar = watch('avatar');
const vectorModel = watch('vectorModel');
const agentModel = watch('agentModel');
......@@ -119,8 +133,14 @@ const CreateModal = ({
<MyModal
title={
<Flex alignItems={'center'} ml={-3}>
<Avatar w={'20px'} h={'20px'} borderRadius={'xs'} src={iconMap[type]} pr={'10px'} />
{t('common:core.dataset.Create dataset', { name: databaseNameMap[type] })}
<Avatar
w={'20px'}
h={'20px'}
borderRadius={'xs'}
src={datasetTypeMap[type].icon}
pr={'10px'}
/>
{t('common:core.dataset.Create dataset', { name: datasetTypeMap[type].name })}
</Flex>
}
isOpen
......@@ -134,16 +154,14 @@ const CreateModal = ({
<Box color={'myGray.900'} fontWeight={500} fontSize={'sm'}>
{t('common:common.Set Name')}
</Box>
{type === DatasetTypeEnum.apiDataset && (
{datasetTypeCourseMap[type] && (
<Flex
as={'span'}
alignItems={'center'}
color={'primary.600'}
fontSize={'sm'}
cursor={'pointer'}
onClick={() =>
window.open(getDocPath('/docs/guide/knowledge_base/api_dataset/'), '_blank')
}
onClick={() => window.open(getDocPath(datasetTypeCourseMap[type]), '_blank')}
>
<MyIcon name={'book'} w={4} mr={0.5} />
{t('common:Instructions')}
......@@ -242,44 +260,8 @@ const CreateModal = ({
</Box>
</Flex>
)}
{type === DatasetTypeEnum.apiDataset && (
<>
<Flex mt={6}>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
{t('dataset:api_url')}
</Flex>
<Input
bg={'myWhite.600'}
placeholder={t('dataset:api_url')}
maxLength={200}
{...register('apiServer.baseUrl', { required: true })}
/>
</Flex>
<Flex mt={6}>
<Flex
alignItems={'center'}
flex={['', '0 0 110px']}
color={'myGray.900'}
fontWeight={500}
fontSize={'sm'}
>
Authorization
</Flex>
<Input
bg={'myWhite.600'}
placeholder={t('dataset:request_headers')}
maxLength={200}
{...register('apiServer.authorization')}
/>
</Flex>
</>
)}
{/* @ts-ignore */}
<ApiDatasetForm type={type} form={form} />
</ModalBody>
<ModalFooter px={9}>
......
......@@ -24,6 +24,14 @@ const SideTag = ({ type, ...props }: { type: `${DatasetTypeEnum}` } & FlexProps)
[DatasetTypeEnum.apiDataset]: {
icon: 'core/dataset/externalDatasetOutline',
label: t('dataset:api_file')
},
[DatasetTypeEnum.feishu]: {
icon: 'core/dataset/feishuDatasetOutline',
label: t('dataset:feishu_dataset')
},
[DatasetTypeEnum.yuque]: {
icon: 'core/dataset/yuqueDatasetOutline',
label: t('dataset:yuque_dataset')
}
};
}, [t]);
......
......@@ -64,7 +64,10 @@ const Dataset = () => {
const onSelectDatasetType = useCallback(
(e: CreateDatasetType) => {
if (!feConfigs?.isPlus && e === DatasetTypeEnum.websiteDataset) {
if (
!feConfigs?.isPlus &&
[DatasetTypeEnum.websiteDataset, DatasetTypeEnum.feishu, DatasetTypeEnum.yuque].includes(e)
) {
return toast({
status: 'warning',
title: t('common:common.system.Commercial version function')
......@@ -168,6 +171,18 @@ const Dataset = () => {
label: t('dataset:website_dataset'),
description: t('dataset:website_dataset_desc'),
onClick: () => onSelectDatasetType(DatasetTypeEnum.websiteDataset)
},
{
icon: 'core/dataset/feishuDatasetColor',
label: t('dataset:feishu_dataset'),
description: t('dataset:feishu_dataset_desc'),
onClick: () => onSelectDatasetType(DatasetTypeEnum.feishu)
},
{
icon: 'core/dataset/yuqueDatasetColor',
label: t('dataset:yuque_dataset'),
description: t('dataset:yuque_dataset_desc'),
onClick: () => onSelectDatasetType(DatasetTypeEnum.yuque)
}
]
},
......
......@@ -6,7 +6,7 @@ import { OAuthEnum } from '@fastgpt/global/support/user/constant';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { customAlphabet } from 'nanoid';
import { useRouter } from 'next/router';
import { Dispatch, useRef } from 'react';
import { Dispatch, useMemo, useRef } from 'react';
import { useTranslation } from 'next-i18next';
import I18nLngSelector from '@/components/Select/I18nLngSelector';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
......@@ -42,6 +42,16 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
}
]
: []),
...(feConfigs?.oauth?.dingtalk
? [
{
label: t('user:login.Dingtalk'),
provider: OAuthEnum.dingtalk,
icon: 'common/dingtalkFill',
redirectUrl: `https://login.dingtalk.com/oauth2/auth?client_id=${feConfigs?.oauth?.dingtalk}&redirect_uri=${redirectUri}&state=${state.current}&response_type=code&scope=openid&prompt=consent`
}
]
: []),
...(feConfigs?.oauth?.google
? [
{
......@@ -85,8 +95,10 @@ const FormLayout = ({ children, setPageType, pageType }: Props) => {
: [])
];
const show_oauth =
!sessionStorage.getItem('bd_vid') && !!(feConfigs?.sso?.url || oAuthList.length > 0);
const show_oauth = useMemo(
() => !sessionStorage.getItem('bd_vid') && !!(feConfigs?.sso?.url || oAuthList.length > 0),
[feConfigs?.sso?.url, oAuthList.length]
);
return (
<Flex flexDirection={'column'} h={'100%'}>
......
......@@ -45,16 +45,6 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
const { runAsync: onclickRegister, loading: requesting } = useRequest2(
async ({ username, password, code }: RegisterType) => {
const fastgpt_sem = (() => {
try {
return sessionStorage.getItem('fastgpt_sem')
? JSON.parse(sessionStorage.getItem('fastgpt_sem')!)
: undefined;
} catch {
return undefined;
}
})();
loginSuccess(
await postRegister({
username,
......@@ -62,7 +52,16 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
password,
inviterId: localStorage.getItem('inviterId') || undefined,
bd_vid: sessionStorage.getItem('bd_vid') || undefined,
fastgpt_sem: fastgpt_sem
fastgpt_sem: (() => {
try {
return sessionStorage.getItem('fastgpt_sem')
? JSON.parse(sessionStorage.getItem('fastgpt_sem')!)
: undefined;
} catch {
return undefined;
}
})(),
sourceDomain: sessionStorage.getItem('sourceDomain') || undefined
})
);
......
......@@ -43,7 +43,18 @@ const provider = () => {
type: loginStore?.provider as `${OAuthEnum}`,
code,
callbackUrl: `${location.origin}/login/provider`,
inviterId: localStorage.getItem('inviterId') || undefined
inviterId: localStorage.getItem('inviterId') || undefined,
bd_vid: sessionStorage.getItem('bd_vid') || undefined,
fastgpt_sem: (() => {
try {
return sessionStorage.getItem('fastgpt_sem')
? JSON.parse(sessionStorage.getItem('fastgpt_sem')!)
: undefined;
} catch {
return undefined;
}
})(),
sourceDomain: sessionStorage.getItem('sourceDomain') || undefined
});
if (!res) {
......@@ -79,12 +90,8 @@ const provider = () => {
return;
}
if (
!code ||
!loginStore ||
(loginStore.provider !== OAuthEnum.sso && (!loginStore.state || !state))
)
return;
console.log('SSO', { loginStore, code, state });
if (!code || !loginStore) return;
if (isOauthLogging) return;
......
import { GetApiDatasetFileListResponse } from '@/pages/api/core/dataset/apiDataset/list';
import { FeishuServer, YuqueServer } from '@fastgpt/global/core/dataset/apiDataset';
import { POST } from '@fastgpt/service/common/api/plusRequest';
export const getFeishuAndYuqueDatasetFileList = async (data: {
feishuServer?: FeishuServer;
yuqueServer?: YuqueServer;
parentId?: string;
}) => {
const res = await POST<GetApiDatasetFileListResponse>('/core/dataset/systemApiDataset', {
type: 'list',
...data
});
return res;
};
import { POST } from '@/web/common/api/request';
import { TrackEnum } from '@fastgpt/global/common/middle/tracks/constants';
import { useSystemStore } from '../../system/useSystemStore';
const createTrack = ({ event, data }: { event: TrackEnum; data: any }) => {
if (!useSystemStore.getState()?.feConfigs?.isPlus) return;
return POST('/common/tracks/push', {
event,
data
});
};
export const webPushTrack = {
useAppTemplate: (data: { id: string; name: string }) => {
return createTrack({
event: TrackEnum.useAppTemplate,
data
});
}
};
......@@ -8,7 +8,12 @@ import { TrackEventName } from '../common/system/constants';
export const useInitApp = () => {
const router = useRouter();
const { hiId, bd_vid, k } = router.query as { hiId?: string; bd_vid?: string; k?: string };
const { hiId, bd_vid, k, sourceDomain } = router.query as {
hiId?: string;
bd_vid?: string;
k?: string;
sourceDomain?: string;
};
const { loadGitStar, setInitd, feConfigs } = useSystemStore();
const [scripts, setScripts] = useState<FastGPTFeConfigsType['scripts']>([]);
const [title, setTitle] = useState(process.env.SYSTEM_NAME || 'AI');
......@@ -61,7 +66,16 @@ export const useInitApp = () => {
hiId && localStorage.setItem('inviterId', hiId);
bd_vid && sessionStorage.setItem('bd_vid', bd_vid);
k && sessionStorage.setItem('fastgpt_sem', JSON.stringify({ keyword: k }));
}, [bd_vid, hiId, k]);
const formatSourceDomain = (() => {
if (sourceDomain) return sourceDomain;
return document.referrer;
})();
console.log(formatSourceDomain, '-=-=');
if (formatSourceDomain && !sessionStorage.getItem('sourceDomain')) {
sessionStorage.setItem('sourceDomain', formatSourceDomain);
}
}, [bd_vid, hiId, k, sourceDomain]);
return {
feConfigs,
......
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { AppDetailType } from '@fastgpt/global/core/app/type.d';
import type { FeishuAppType, OutLinkEditType } from '@fastgpt/global/support/outLink/type.d';
import type {
DingtalkAppType,
FeishuAppType,
OutLinkEditType
} from '@fastgpt/global/support/outLink/type.d';
import { AppPermission } from '@fastgpt/global/support/permission/app/controller';
export const defaultApp: AppDetailType = {
_id: '',
......@@ -39,6 +43,14 @@ export const defaultFeishuOutLinkForm: OutLinkEditType<FeishuAppType> = {
}
};
export const defaultDingtalkOutlinkForm: OutLinkEditType<DingtalkAppType> = {
name: '',
limit: {
QPM: 100,
maxUsagePoints: -1
}
};
export enum TTSTypeEnum {
none = 'none',
web = 'web',
......
......@@ -66,6 +66,7 @@ import type {
listExistIdQuery,
listExistIdResponse
} from '@/pages/api/core/dataset/apiDataset/listExistId';
import { FeishuServer, YuqueServer } from '@fastgpt/global/core/dataset/apiDataset';
/* ======================== dataset ======================= */
export const getDatasets = (data: GetDatasetListBody) =>
......
......@@ -65,3 +65,13 @@ export enum ImportProcessWayEnum {
auto = 'auto',
custom = 'custom'
}
export const datasetTypeCourseMap: Record<`${DatasetTypeEnum}`, string> = {
[DatasetTypeEnum.folder]: '',
[DatasetTypeEnum.dataset]: '',
[DatasetTypeEnum.apiDataset]: '/docs/guide/knowledge_base/api_dataset/',
[DatasetTypeEnum.websiteDataset]: '/docs/guide/knowledge_base/websync/',
[DatasetTypeEnum.feishu]: '/docs/guide/knowledge_base/lark_dataset/',
[DatasetTypeEnum.yuque]: '/docs/guide/knowledge_base/yuque_dataset/',
[DatasetTypeEnum.externalFile]: ''
};
......@@ -121,6 +121,19 @@ export const DatasetPageContextProvider = ({
baseUrl: data.apiServer.baseUrl,
authorization: ''
}
: undefined,
yuqueServer: data.yuqueServer
? {
userId: data.yuqueServer.userId,
token: ''
}
: undefined,
feishuServer: data.feishuServer
? {
appId: data.feishuServer.appId,
appSecret: '',
folderToken: data.feishuServer.folderToken
}
: undefined
}));
}
......
.react-flow {
overflow: visible;
}
.react-flow__panel.react-flow__attribution {
z-index: 0;
left: 0;
......
......@@ -9,7 +9,10 @@ import type {
OauthLoginProps,
PostLoginProps
} from '@fastgpt/global/support/user/api.d';
import { GetWXLoginQRResponse } from '@fastgpt/global/support/user/login/api.d';
import {
AccountRegisterBody,
GetWXLoginQRResponse
} from '@fastgpt/global/support/user/login/api.d';
export const sendAuthCode = (data: {
username: string;
......@@ -33,16 +36,7 @@ export const postRegister = ({
inviterId,
bd_vid,
fastgpt_sem
}: {
username: string;
code: string;
password: string;
inviterId?: string;
bd_vid?: string;
fastgpt_sem?: {
keyword: string;
};
}) =>
}: AccountRegisterBody) =>
POST<ResLogin>(`/proApi/support/user/account/register/emailAndPhone`, {
username,
code,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment