Compare commits
12 Commits
v4.8.6-alp
...
v4.8.7-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36f8755d09 | ||
|
|
fc96bb99cc | ||
|
|
1e4ffc2481 | ||
|
|
ee7496467b | ||
|
|
b5c98a4f63 | ||
|
|
090c880860 | ||
|
|
dd2a9bdee5 | ||
|
|
8d60ef505f | ||
|
|
b14514c105 | ||
|
|
11ffaaf2c5 | ||
|
|
e2ae571d15 | ||
|
|
f548e24e7d |
1
.npmrc
1
.npmrc
@@ -1,2 +1,3 @@
|
|||||||
public-hoist-pattern[]=*tiktoken*
|
public-hoist-pattern[]=*tiktoken*
|
||||||
public-hoist-pattern[]=*@zilliz/milvus2-sdk-node*
|
public-hoist-pattern[]=*@zilliz/milvus2-sdk-node*
|
||||||
|
registry=https://registry.npmjs.org/
|
||||||
46
.vscode/i18n-ally-custom-framework.yml
vendored
46
.vscode/i18n-ally-custom-framework.yml
vendored
@@ -1,46 +0,0 @@
|
|||||||
# .vscode/i18n-ally-custom-framework.yml
|
|
||||||
|
|
||||||
# An array of strings which contain Language Ids defined by VS Code
|
|
||||||
# You can check available language ids here: https://code.visualstudio.com/docs/languages/identifiers
|
|
||||||
languageIds:
|
|
||||||
- javascript
|
|
||||||
- typescript
|
|
||||||
- javascriptreact
|
|
||||||
- typescriptreact
|
|
||||||
|
|
||||||
# An array of RegExes to find the key usage. **The key should be captured in the first match group**.
|
|
||||||
# You should unescape RegEx strings in order to fit in the YAML file
|
|
||||||
# To help with this, you can use https://www.freeformatter.com/json-escape.html
|
|
||||||
usageMatchRegex:
|
|
||||||
# The following example shows how to detect `t("your.i18n.keys")`
|
|
||||||
# the `{key}` will be placed by a proper keypath matching regex,
|
|
||||||
# you can ignore it and use your own matching rules as well
|
|
||||||
- "[^\\w\\d]t\\(['\"`]({key})['\"`]"
|
|
||||||
- "[^\\w\\d]commonT\\(['\"`]({key})['\"`]"
|
|
||||||
# 支持 appT("your.i18n.keys")
|
|
||||||
- "[^\\w\\d]appT\\(['\"`]({key})['\"`]"
|
|
||||||
# 支持 datasetT("your.i18n.keys")
|
|
||||||
- "[^\\w\\d]datasetT\\(['\"`]({key})['\"`]"
|
|
||||||
- "[^\\w\\d]fileT\\(['\"`]({key})['\"`]"
|
|
||||||
- "[^\\w\\d]publishT\\(['\"`]({key})['\"`]"
|
|
||||||
- "[^\\w\\d]workflowT\\(['\"`]({key})['\"`]"
|
|
||||||
- "[^\\w\\d]userT\\(['\"`]({key})['\"`]"
|
|
||||||
- "[^\\w\\d]chatT\\(['\"`]({key})['\"`]"
|
|
||||||
|
|
||||||
# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
|
|
||||||
# and works like how the i18next framework identifies the namespace scope from the
|
|
||||||
# useTranslation() hook.
|
|
||||||
# You should unescape RegEx strings in order to fit in the YAML file
|
|
||||||
# To help with this, you can use https://www.freeformatter.com/json-escape.html
|
|
||||||
scopeRangeRegex: "useTranslation\\(\\s*\\[?\\s*['\"`](.*?)['\"`]"
|
|
||||||
|
|
||||||
# An array of strings containing refactor templates.
|
|
||||||
# The "$1" will be replaced by the keypath specified.
|
|
||||||
# Optional: uncomment the following two lines to use
|
|
||||||
|
|
||||||
# refactorTemplates:
|
|
||||||
# - i18n.get("$1")
|
|
||||||
|
|
||||||
|
|
||||||
# If set to true, only enables this custom framework (will disable all built-in frameworks)
|
|
||||||
monopoly: true
|
|
||||||
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@@ -7,11 +7,18 @@
|
|||||||
"i18n-ally.localesPaths": [
|
"i18n-ally.localesPaths": [
|
||||||
"packages/web/i18n",
|
"packages/web/i18n",
|
||||||
],
|
],
|
||||||
"i18n-ally.enabledParsers": ["json", "yaml", "js", "ts"],
|
"i18n-ally.enabledParsers": [
|
||||||
|
"json",
|
||||||
|
"yaml",
|
||||||
|
"js",
|
||||||
|
"ts"
|
||||||
|
],
|
||||||
"i18n-ally.keystyle": "nested",
|
"i18n-ally.keystyle": "nested",
|
||||||
"i18n-ally.sortKeys": true,
|
"i18n-ally.sortKeys": true,
|
||||||
"i18n-ally.keepFulfilled": false,
|
"i18n-ally.keepFulfilled": false,
|
||||||
"i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译其他语言文件的变量和内容
|
"i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译其他语言文件的变量和内容
|
||||||
"i18n-ally.displayLanguage": "zh", // 显示语言
|
"i18n-ally.displayLanguage": "zh", // 显示语言
|
||||||
|
"i18n-ally.namespace": true,
|
||||||
|
"i18n-ally.pathMatcher": "{locale}/{namespaces}.json",
|
||||||
"i18n-ally.extract.targetPickingStrategy": "most-similar-by-key"
|
"i18n-ally.extract.targetPickingStrategy": "most-similar-by-key"
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,6 @@ weight: 707
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
{{% alert icon="🤖" context="success" %}}
|
{{% alert icon="🤖" context="success" %}}
|
||||||
|
|
||||||
- MongoDB:用于存储除了向量外的各类数据
|
- MongoDB:用于存储除了向量外的各类数据
|
||||||
@@ -105,13 +104,11 @@ brew install orbstack
|
|||||||
{{< /tab >}}
|
{{< /tab >}}
|
||||||
{{< /tabs >}}
|
{{< /tabs >}}
|
||||||
|
|
||||||
|
|
||||||
## 开始部署
|
## 开始部署
|
||||||
|
|
||||||
### 1. 下载 docker-compose.yml
|
### 1. 下载 docker-compose.yml
|
||||||
|
|
||||||
|
非 Linux 环境或无法访问外网环境,可手动创建一个目录,并下载配置文件和对应版本的`docker-compose.yml`,在这个文件夹中依据下载的配置文件运行docker,若作为本地开发使用推荐`docker-compose-pgvector`版本,并且自行拉取并运行`sandbox`和`fastgpt`,并在docker配置文件中注释掉`sandbox`和`fastgpt`的部分
|
||||||
非 Linux 环境或无法访问外网环境,可手动创建一个目录,并下载配置文件和对应版本的`docker-compose.yml`
|
|
||||||
|
|
||||||
- [config.json](https://github.com/labring/FastGPT/blob/main/projects/app/data/config.json)
|
- [config.json](https://github.com/labring/FastGPT/blob/main/projects/app/data/config.json)
|
||||||
- [docker-compose.yml](https://github.com/labring/FastGPT/blob/main/files/docker) (注意,不同向量库版本的文件不一样)
|
- [docker-compose.yml](https://github.com/labring/FastGPT/blob/main/files/docker) (注意,不同向量库版本的文件不一样)
|
||||||
@@ -271,7 +268,6 @@ rs.status()
|
|||||||
|
|
||||||
默认是写了OneAPi的连接地址和密钥,可以通过修改`docker-compose.yml`中,fastgpt容器的环境变量实现。
|
默认是写了OneAPi的连接地址和密钥,可以通过修改`docker-compose.yml`中,fastgpt容器的环境变量实现。
|
||||||
|
|
||||||
|
|
||||||
`OPENAI_BASE_URL`(API 接口的地址,需要加/v1)
|
`OPENAI_BASE_URL`(API 接口的地址,需要加/v1)
|
||||||
`CHAT_API_KEY`(API 接口的凭证)。
|
`CHAT_API_KEY`(API 接口的凭证)。
|
||||||
|
|
||||||
@@ -315,8 +311,7 @@ docker-compose up -d
|
|||||||
1. `docker exec -it fastgpt sh` 进入 FastGPT 容器。
|
1. `docker exec -it fastgpt sh` 进入 FastGPT 容器。
|
||||||
2. 直接输入`env`命令查看所有环境变量。
|
2. 直接输入`env`命令查看所有环境变量。
|
||||||
|
|
||||||
|
### 为什么无法连接`本地模型`镜像
|
||||||
### 为什么无法连接`本地模型`镜像。
|
|
||||||
|
|
||||||
`docker-compose.yml`中使用了桥接的模式建立了`fastgpt`网络,如想通过0.0.0.0或镜像名访问其它镜像,需将其它镜像也加入到网络中。
|
`docker-compose.yml`中使用了桥接的模式建立了`fastgpt`网络,如想通过0.0.0.0或镜像名访问其它镜像,需将其它镜像也加入到网络中。
|
||||||
|
|
||||||
@@ -368,8 +363,8 @@ mongo连接失败,查看mongo的运行状态**对应日志**。
|
|||||||
|
|
||||||
由于服务初始化错误,系统重启导致。
|
由于服务初始化错误,系统重启导致。
|
||||||
|
|
||||||
* 90%是由于配置文件写不对,导致 JSON 解析报错
|
- 90%是由于配置文件写不对,导致 JSON 解析报错
|
||||||
* 剩下的基本是因为向量数据库连不上
|
- 剩下的基本是因为向量数据库连不上
|
||||||
|
|
||||||
### 如何修改密码
|
### 如何修改密码
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ toc: true
|
|||||||
weight: 705
|
weight: 705
|
||||||
---
|
---
|
||||||
|
|
||||||
本文档介绍了如何设置开发环境以构建和测试 [FastGPT](https://fastgpt.in)。
|
本文档介绍了如何设置开发环境以构建和测试 [FastGPT](https://fastgpt.in),。
|
||||||
|
|
||||||
|
|
||||||
## 前置依赖项
|
## 前置依赖项
|
||||||
|
|
||||||
@@ -16,13 +15,14 @@ weight: 705
|
|||||||
|
|
||||||
- [Git](http://git-scm.com/)
|
- [Git](http://git-scm.com/)
|
||||||
- [Docker](https://www.docker.com/)(构建镜像)
|
- [Docker](https://www.docker.com/)(构建镜像)
|
||||||
- [Node.js v18.17 / v20.x](http://nodejs.org)
|
- [Node.js v18.17 / v20.x](http://nodejs.org)(版本尽量一样,可以使用nvm管理node版本)
|
||||||
- [pnpm](https://pnpm.io/) 版本 8.6.0 (目前官方的开发环境)
|
- [pnpm](https://pnpm.io/) 版本 8.6.0 (目前官方的开发环境)
|
||||||
- make命令: 根据不同平台,百度安装 (官方是GNU Make 4.3)
|
- make命令: 根据不同平台,百度安装 (官方是GNU Make 4.3)
|
||||||
|
|
||||||
## 开始本地开发
|
## 开始本地开发
|
||||||
|
|
||||||
{{% alert context="success" %}}
|
{{% alert context="success" %}}
|
||||||
|
|
||||||
1. 用户默认的时区为 `Asia/Shanghai`,非 linux 环境时候,获取系统时间会异常,本地开发时候,可以将用户的时区调整成 UTC(+0)。
|
1. 用户默认的时区为 `Asia/Shanghai`,非 linux 环境时候,获取系统时间会异常,本地开发时候,可以将用户的时区调整成 UTC(+0)。
|
||||||
2. 建议先服务器装好**数据库**,再进行本地开发。
|
2. 建议先服务器装好**数据库**,再进行本地开发。
|
||||||
{{% /alert %}}
|
{{% /alert %}}
|
||||||
@@ -47,9 +47,10 @@ git clone git@github.com:<github_username>/FastGPT.git
|
|||||||
|
|
||||||
### 3. 安装数据库
|
### 3. 安装数据库
|
||||||
|
|
||||||
第一次开发,需要先部署数据库,建议本地开发可以随便找一台 2C2G 的轻量小数据库实践。数据库部署教程:[Docker 快速部署](/docs/development/docker/)。部署完了,可以本地访问其数据库。
|
第一次开发,需要先部署数据库,建议本地开发可以随便找一台 2C2G 的轻量小数据库实践,或者新建文件夹并配置相关文件用以运行docker。数据库部署教程:[Docker 快速部署](/docs/development/docker/)。部署完了,可以本地访问其数据库。
|
||||||
|
{{% alert context="warning" %}}
|
||||||
Mongo 数据库需要注意,需要注意在连接地址中增加 `directConnection=true` 参数,才能连接上副本集的数据库。
|
Mongo 数据库需要注意,需要注意在连接地址中增加 `directConnection=true` 参数,才能连接上副本集的数据库。
|
||||||
|
{{% /alert %}}
|
||||||
|
|
||||||
### 4. 初始配置
|
### 4. 初始配置
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ Mongo 数据库需要注意,需要注意在连接地址中增加 `directConnec
|
|||||||
|
|
||||||
**1. 环境变量**
|
**1. 环境变量**
|
||||||
|
|
||||||
复制`.env.template`文件,在同级目录下生成一个`.env.local` 文件,修改`.env.local` 里内容才是有效的变量。变量说明见 .env.template
|
复制`.env.template`文件,在同级目录下生成一个`.env.local` 文件,修改`.env.local` 里内容才是有效的变量。变量说明见 .env.template,主要需要修改`API_KEY`和数据库的地址与端口以及数据库账号的用户名和密码,具体配置需要和docker配置文件相同,其中用户名和密码如需修改需要修改docker配置文件、数据库和`.env.local`文件,不能只改一处。
|
||||||
|
|
||||||
**2. config 配置文件**
|
**2. config 配置文件**
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ Mongo 数据库需要注意,需要注意在连接地址中增加 `directConnec
|
|||||||
|
|
||||||
### 5. 运行
|
### 5. 运行
|
||||||
|
|
||||||
可参考项目根目录下的 `dev.md`
|
可参考项目根目录下的 `dev.md`,第一次编译运行可能会有点慢,需要点耐心哦
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 给自动化脚本代码执行权限(非 linux 系统, 可以手动执行里面的 postinstall.sh 文件内容)
|
# 给自动化脚本代码执行权限(非 linux 系统, 可以手动执行里面的 postinstall.sh 文件内容)
|
||||||
@@ -114,7 +115,6 @@ make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8
|
|||||||
|
|
||||||
如果遇到问题,比如合并冲突或不知道如何打开拉取请求,请查看 GitHub 的[拉取请求教程](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests),了解如何解决合并冲突和其他问题。一旦您的 PR 被合并,您将自豪地被列为[贡献者表](https://github.com/labring/FastGPT/graphs/contributors)中的一员。
|
如果遇到问题,比如合并冲突或不知道如何打开拉取请求,请查看 GitHub 的[拉取请求教程](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests),了解如何解决合并冲突和其他问题。一旦您的 PR 被合并,您将自豪地被列为[贡献者表](https://github.com/labring/FastGPT/graphs/contributors)中的一员。
|
||||||
|
|
||||||
|
|
||||||
## QA
|
## QA
|
||||||
|
|
||||||
### 本地数据库无法连接
|
### 本地数据库无法连接
|
||||||
@@ -130,6 +130,7 @@ make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8
|
|||||||
FastGPT 在`pnpm i`后会执行`postinstall`脚本,用于自动生成`ChakraUI`的`Type`。如果没有权限,可以先执行`chmod -R +x ./scripts/`,再执行`pnpm i`。
|
FastGPT 在`pnpm i`后会执行`postinstall`脚本,用于自动生成`ChakraUI`的`Type`。如果没有权限,可以先执行`chmod -R +x ./scripts/`,再执行`pnpm i`。
|
||||||
|
|
||||||
仍不可行的话,可以手动执行`./scripts/postinstall.sh`里的内容。
|
仍不可行的话,可以手动执行`./scripts/postinstall.sh`里的内容。
|
||||||
|
*如果是Windows下的话,可以使用git bash给`postinstall`脚本添加执行权限并执行sh脚本*
|
||||||
|
|
||||||
### TypeError: Cannot read properties of null (reading 'useMemo' )
|
### TypeError: Cannot read properties of null (reading 'useMemo' )
|
||||||
|
|
||||||
@@ -141,6 +142,9 @@ FastGPT 在`pnpm i`后会执行`postinstall`脚本,用于自动生成`ChakraUI
|
|||||||
4. `cd projects/app`
|
4. `cd projects/app`
|
||||||
5. `pnpm dev`
|
5. `pnpm dev`
|
||||||
|
|
||||||
|
### Error response from daemon: error while creating mount source path 'XXX': mkdir XXX: file exists
|
||||||
|
|
||||||
|
这个错误可能是之前停止容器时有文件残留导致的,首先需要确认相关镜像都全部关闭,然后手动删除相关文件或者重启docker即可
|
||||||
|
|
||||||
## 加入社区
|
## 加入社区
|
||||||
|
|
||||||
@@ -155,6 +159,7 @@ FastGPT 在`pnpm i`后会执行`postinstall`脚本,用于自动生成`ChakraUI
|
|||||||
FastGPT 使用了 nextjs 的 page route 作为框架。为了区分好前后端代码,在目录分配上会分成 global, service, web 3个自目录,分别对应着 `前后端共用`、`后端专用`、`前端专用`的代码。
|
FastGPT 使用了 nextjs 的 page route 作为框架。为了区分好前后端代码,在目录分配上会分成 global, service, web 3个自目录,分别对应着 `前后端共用`、`后端专用`、`前端专用`的代码。
|
||||||
|
|
||||||
### monorepo
|
### monorepo
|
||||||
|
|
||||||
FastGPT 采用 pnpm workspace 方式构建 monorepo 项目,主要分为两个部分:
|
FastGPT 采用 pnpm workspace 方式构建 monorepo 项目,主要分为两个部分:
|
||||||
|
|
||||||
- projects/app - FastGPT 主项目
|
- projects/app - FastGPT 主项目
|
||||||
@@ -173,6 +178,7 @@ support - 支撑功能(用户体系,计费,鉴权等)
|
|||||||
common - 基础功能(日志管理,文件读写等)
|
common - 基础功能(日志管理,文件读写等)
|
||||||
|
|
||||||
{{% details title="代码结构说明" closed="true" %}}
|
{{% details title="代码结构说明" closed="true" %}}
|
||||||
|
|
||||||
```
|
```
|
||||||
.
|
.
|
||||||
├── .github // github 相关配置
|
├── .github // github 相关配置
|
||||||
@@ -200,4 +206,5 @@ common - 基础功能(日志管理,文件读写等)
|
|||||||
├── README_ja.md
|
├── README_ja.md
|
||||||
├── dev.md
|
├── dev.md
|
||||||
```
|
```
|
||||||
|
|
||||||
{{% /details %}}
|
{{% /details %}}
|
||||||
|
|||||||
@@ -7,18 +7,22 @@ toc: true
|
|||||||
weight: 852
|
weight: 852
|
||||||
---
|
---
|
||||||
|
|
||||||
## 发起对话
|
|
||||||
|
|
||||||
{{% alert icon="🤖 " context="success" %}}
|
{{% alert icon="🤖 " context="success" %}}
|
||||||
该接口的 API Key 需使用`应用特定的 key`,否则会报错。
|
该接口的 API Key 需使用`应用特定的 key`,否则会报错。
|
||||||
|
|
||||||
有些包调用时,`BaseUrl`需要添加`v1`路径,有些不需要,如果出现404情况,可补充`v1`重试。
|
有些包调用时,`BaseUrl`需要添加`v1`路径,有些不需要,如果出现404情况,可补充`v1`重试。
|
||||||
{{% /alert %}}
|
{{% /alert %}}
|
||||||
|
|
||||||
|
## 发起对话(简易应用和工作流)
|
||||||
|
|
||||||
**对话接口兼容`GPT`的接口!如果你的项目使用的是标准的`GPT`官方接口,可以直接通过修改`BaseUrl`和 `Authorization`来访问 FastGpt 应用。**
|
对话接口兼容`GPT`的接口!如果你的项目使用的是标准的`GPT`官方接口,可以直接通过修改`BaseUrl`和 `Authorization`来访问 FastGpt 应用,不过需要注意下面几个规则:
|
||||||
|
|
||||||
## 请求
|
{{% alert icon="🤖 " context="success" %}}
|
||||||
|
* 传入的`model`,`temperature`等参数字段均无效,这些字段由编排决定。
|
||||||
|
* 不会返回实际消耗`Token`值,如果需要,可以设置`detail=true`,并手动计算 `responseData` 里的`tokens`值。
|
||||||
|
{{% /alert %}}
|
||||||
|
|
||||||
|
### 请求
|
||||||
|
|
||||||
{{< tabs tabTotal="2" >}}
|
{{< tabs tabTotal="2" >}}
|
||||||
{{< tab tabName="请求示例" >}}
|
{{< tab tabName="请求示例" >}}
|
||||||
@@ -67,7 +71,7 @@ curl --location --request POST 'https://api.fastgpt.in/api/v1/chat/completions'
|
|||||||
{{< /tab >}}
|
{{< /tab >}}
|
||||||
{{< /tabs >}}
|
{{< /tabs >}}
|
||||||
|
|
||||||
## 响应
|
### 响应
|
||||||
|
|
||||||
{{< tabs tabTotal="5" >}}
|
{{< tabs tabTotal="5" >}}
|
||||||
{{< tab tabName="detail=false,stream=false 响应" >}}
|
{{< tab tabName="detail=false,stream=false 响应" >}}
|
||||||
@@ -245,7 +249,7 @@ data: [{"moduleName":"知识库搜索","moduleType":"datasetSearchNode","running
|
|||||||
{{< /markdownify >}}
|
{{< /markdownify >}}
|
||||||
{{< /tab >}}
|
{{< /tab >}}
|
||||||
|
|
||||||
{{< tab tabName="detail=true,stream=true 时,event值" >}}
|
{{< tab tabName="event值" >}}
|
||||||
{{< markdownify >}}
|
{{< markdownify >}}
|
||||||
|
|
||||||
event取值:
|
event取值:
|
||||||
@@ -265,6 +269,192 @@ event取值:
|
|||||||
{{< /tabs >}}
|
{{< /tabs >}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 请求插件
|
||||||
|
|
||||||
|
插件的接口与对话接口一致,仅请求参数略有区别,有以下规定:
|
||||||
|
|
||||||
|
* 调用插件类型的应用时,接口默认为`detail`模式。
|
||||||
|
* 无需传入 `chatId`,因为插件只能运行一轮。
|
||||||
|
* 无需传入`messages`。
|
||||||
|
* 通过传递`variables`来代表插件的输入。
|
||||||
|
* 通过获取`pluginData`来获取插件输出。
|
||||||
|
|
||||||
|
### 请求示例
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --location --request POST 'http://localhost:3000/api/v1/chat/completions' \
|
||||||
|
--header 'Authorization: Bearer test-xxxxx' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"stream": false,
|
||||||
|
"chatId": "test",
|
||||||
|
"variables": {
|
||||||
|
"query":"你好" # 我的插件输入有一个参数,变量名叫 query
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 响应示例
|
||||||
|
|
||||||
|
{{< tabs tabTotal="3" >}}
|
||||||
|
|
||||||
|
{{< tab tabName="detail=true,stream=false 响应" >}}
|
||||||
|
{{< markdownify >}}
|
||||||
|
|
||||||
|
* 插件的输出可以通过查找`responseData`中, `moduleType=pluginOutput`的元素,其`pluginOutput`是插件的输出。
|
||||||
|
* 流输出,仍可以通过`choices`进行获取。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"responseData": [
|
||||||
|
{
|
||||||
|
"nodeId": "fdDgXQ6SYn8v",
|
||||||
|
"moduleName": "AI 对话",
|
||||||
|
"moduleType": "chatNode",
|
||||||
|
"totalPoints": 0.685,
|
||||||
|
"model": "FastAI-3.5",
|
||||||
|
"tokens": 685,
|
||||||
|
"query": "你好",
|
||||||
|
"maxToken": 2000,
|
||||||
|
"historyPreview": [
|
||||||
|
{
|
||||||
|
"obj": "Human",
|
||||||
|
"value": "你好"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"obj": "AI",
|
||||||
|
"value": "你好!有什么可以帮助你的吗?欢迎向我提问。"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contextTotalLen": 14,
|
||||||
|
"runningTime": 1.73
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nodeId": "pluginOutput",
|
||||||
|
"moduleName": "自定义插件输出",
|
||||||
|
"moduleType": "pluginOutput",
|
||||||
|
"totalPoints": 0,
|
||||||
|
"pluginOutput": {
|
||||||
|
"result": "你好!有什么可以帮助你的吗?欢迎向我提问。"
|
||||||
|
},
|
||||||
|
"runningTime": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"newVariables": {
|
||||||
|
"query": "你好"
|
||||||
|
},
|
||||||
|
"id": "safsafsa",
|
||||||
|
"model": "",
|
||||||
|
"usage": {
|
||||||
|
"prompt_tokens": 1,
|
||||||
|
"completion_tokens": 1,
|
||||||
|
"total_tokens": 1
|
||||||
|
},
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"message": {
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "你好!有什么可以帮助你的吗?欢迎向我提问。"
|
||||||
|
},
|
||||||
|
"finish_reason": "stop",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< /markdownify >}}
|
||||||
|
{{< /tab >}}
|
||||||
|
|
||||||
|
|
||||||
|
{{< tab tabName="detail=true,stream=true 响应" >}}
|
||||||
|
{{< markdownify >}}
|
||||||
|
|
||||||
|
* 插件的输出可以通过获取`event=flowResponses`中的字符串,并将其反序列化后得到一个数组。同样的,查找 `moduleType=pluginOutput`的元素,其`pluginOutput`是插件的输出。
|
||||||
|
* 流输出,仍和对话接口一样获取。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
event: flowNodeStatus
|
||||||
|
data: {"status":"running","name":"AI 对话"}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":""},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"你"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"好"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"!"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"有"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"什"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"么"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"可以"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"帮"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"助"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"你"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"的"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"吗"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":"?"},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{"role":"assistant","content":""},"index":0,"finish_reason":null}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: {"id":"","object":"","created":0,"model":"","choices":[{"delta":{},"index":0,"finish_reason":"stop"}]}
|
||||||
|
|
||||||
|
event: answer
|
||||||
|
data: [DONE]
|
||||||
|
|
||||||
|
event: flowResponses
|
||||||
|
data: [{"nodeId":"fdDgXQ6SYn8v","moduleName":"AI 对话","moduleType":"chatNode","totalPoints":0.033,"model":"FastAI-3.5","tokens":33,"query":"你好","maxToken":2000,"historyPreview":[{"obj":"Human","value":"你好"},{"obj":"AI","value":"你好!有什么可以帮助你的吗?"}],"contextTotalLen":2,"runningTime":1.42},{"nodeId":"pluginOutput","moduleName":"自定义插件输出","moduleType":"pluginOutput","totalPoints":0,"pluginOutput":{"result":"你好!有什么可以帮助你的吗?"},"runningTime":0}]
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< /markdownify >}}
|
||||||
|
{{< /tab >}}
|
||||||
|
|
||||||
|
{{< tab tabName="输出获取" >}}
|
||||||
|
{{< markdownify >}}
|
||||||
|
|
||||||
|
event取值:
|
||||||
|
|
||||||
|
- answer: 返回给客户端的文本(最终会算作回答)
|
||||||
|
- fastAnswer: 指定回复返回给客户端的文本(最终会算作回答)
|
||||||
|
- toolCall: 执行工具
|
||||||
|
- toolParams: 工具参数
|
||||||
|
- toolResponse: 工具返回
|
||||||
|
- flowNodeStatus: 运行到的节点状态
|
||||||
|
- flowResponses: 节点完整响应
|
||||||
|
- updateVariables: 更新变量
|
||||||
|
- error: 报错
|
||||||
|
|
||||||
|
{{< /markdownify >}}
|
||||||
|
{{< /tab >}}
|
||||||
|
{{< /tabs >}}
|
||||||
|
|
||||||
## 使用案例
|
## 使用案例
|
||||||
|
|
||||||
- [接入 NextWeb/ChatGPT web 等应用](/docs/use-cases/openapi)
|
- [接入 NextWeb/ChatGPT web 等应用](/docs/use-cases/openapi)
|
||||||
|
|||||||
@@ -128,8 +128,12 @@ curl --location --request POST 'http://localhost:3000/api/core/dataset/create' \
|
|||||||
{{< markdownify >}}
|
{{< markdownify >}}
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --location --request GET 'http://localhost:3000/api/core/dataset/list?parentId=' \
|
curl --location --request POST 'http://localhost:3000/api/core/dataset/list?parentId=' \
|
||||||
--header 'Authorization: Bearer {{authorization}}' \
|
--header 'Authorization: Bearer xxxx' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"parentId":""
|
||||||
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
{{< /markdownify >}}
|
{{< /markdownify >}}
|
||||||
@@ -139,7 +143,7 @@ curl --location --request GET 'http://localhost:3000/api/core/dataset/list?paren
|
|||||||
{{< markdownify >}}
|
{{< markdownify >}}
|
||||||
|
|
||||||
{{% alert icon=" " context="success" %}}
|
{{% alert icon=" " context="success" %}}
|
||||||
- parentId - 父级ID,不传或为空,代表获取根目录下的知识库
|
- parentId - 父级ID,传空字符串或者null,代表获取根目录下的知识库
|
||||||
{{% /alert %}}
|
{{% /alert %}}
|
||||||
|
|
||||||
{{< /markdownify >}}
|
{{< /markdownify >}}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 'V4.8.6(进行中)'
|
title: 'V4.8.6(需要初始化)'
|
||||||
description: 'FastGPT V4.8.6 更新说明'
|
description: 'FastGPT V4.8.6 更新说明'
|
||||||
icon: 'upgrade'
|
icon: 'upgrade'
|
||||||
draft: false
|
draft: false
|
||||||
@@ -13,9 +13,9 @@ weight: 818
|
|||||||
|
|
||||||
### 2. 修改镜像
|
### 2. 修改镜像
|
||||||
|
|
||||||
- fastgpt 镜像 tag 修改成 v4.8.6-alpha
|
- fastgpt 镜像 tag 修改成 v4.8.6
|
||||||
- fastgpt-sandbox 镜像 tag 修改成 v4.8.6-alpha
|
- fastgpt-sandbox 镜像 tag 修改成 v4.8.6
|
||||||
- 商业版镜像 tag 修改成 v4.8.6-alpha
|
- 商业版镜像 tag 修改成 v4.8.6
|
||||||
|
|
||||||
### 3. 执行初始化
|
### 3. 执行初始化
|
||||||
|
|
||||||
@@ -33,12 +33,19 @@ curl --location --request POST 'https://{{host}}/api/admin/initv486' \
|
|||||||
|
|
||||||
## V4.8.6 更新说明
|
## V4.8.6 更新说明
|
||||||
|
|
||||||
1. 新增 - 知识库支持单个集合禁用功能
|
1. 新增 - 应用权限继承
|
||||||
2. 新增 - 文件夹权限继承
|
2. 新增 - 知识库支持单个集合禁用功能
|
||||||
3. 新增 - 网页抓取和数学计算器系统插件
|
3. 新增 - 系统插件模式变更,新增链接读取和数学计算器插件,正式版会更新如何自定义系统插件
|
||||||
4. 新增 - 移动文本加工和自定义反馈到基础节点中
|
4. 新增 - 代码沙盒运行参数
|
||||||
5. 优化 - Read file 默认选中从节点,实现 MongoDB 读写分离,减轻主节点压力
|
5. 新增 - AI对话时隐藏头部的功能,主要是适配移动端
|
||||||
6. 优化 - 知识库导入接口,返回值对齐
|
6. 优化 - 文件读取,Mongo 默认使用从节点,减轻主节点压力
|
||||||
7. 修复 - 工作流中团队插件加载异常
|
7. 优化 - 提示词模板
|
||||||
8. 修复 - 知识库集合目录导航失效
|
8. 优化 - Mongo model 重复加载
|
||||||
9. 修复 - 通过 API 调用 chat 接口,传递 System 异常
|
9. 修复 - 创建链接集合未返回 id
|
||||||
|
10. 修复 - 文档接口说明
|
||||||
|
11. 修复 - api system 提示合并
|
||||||
|
12. 修复 - 团队插件目录内的内容无法加载
|
||||||
|
13. 修复 - 知识库集合目录面包屑无法加载
|
||||||
|
14. 修复 - Markdown 导出对话异常
|
||||||
|
15. 修复 - 提示模板结束标签错误
|
||||||
|
16. 修复 - 文档描述
|
||||||
|
|||||||
29
docSite/content/zh-cn/docs/development/upgrading/487.md
Normal file
29
docSite/content/zh-cn/docs/development/upgrading/487.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
title: 'V4.8.7(进行中)'
|
||||||
|
description: 'FastGPT V4.8.7 更新说明'
|
||||||
|
icon: 'upgrade'
|
||||||
|
draft: false
|
||||||
|
toc: true
|
||||||
|
weight: 817
|
||||||
|
---
|
||||||
|
|
||||||
|
## 升级指南
|
||||||
|
|
||||||
|
### 1. 做好数据库备份
|
||||||
|
|
||||||
|
### 2. 修改镜像
|
||||||
|
|
||||||
|
- fastgpt 镜像 tag 修改成 v4.8.7-alpha
|
||||||
|
- 商业版镜像 tag 修改成 v4.8.7-alpha
|
||||||
|
|
||||||
|
-------
|
||||||
|
|
||||||
|
## V4.8.7 更新说明
|
||||||
|
|
||||||
|
1. 新增 - 插件支持独立运行,发布和日志查看
|
||||||
|
2. 新增 - 应用搜索
|
||||||
|
3. 优化 - 对话框代码
|
||||||
|
4. 优化 - 升级 Dockerfile node 和 pnpm 版本
|
||||||
|
5. 优化 - local 域名部署,也可以正常使用 vision 模式
|
||||||
|
6. 修复 - 简易模式无法变更全局变量
|
||||||
|
7. 修复 - gpt4o 无法同时使用工具和图片
|
||||||
@@ -78,7 +78,7 @@ weight: 404
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nodeId": "u6IAOEssxoZT",
|
"nodeId": "u6IAOEssxoZT",
|
||||||
"name": "工具调用(实验)",
|
"name": "工具调用",
|
||||||
"intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。",
|
"intro": "通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。",
|
||||||
"avatar": "/imgs/workflow/tool.svg",
|
"avatar": "/imgs/workflow/tool.svg",
|
||||||
"flowNodeType": "tools",
|
"flowNodeType": "tools",
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.8.5 # git
|
image: ghcr.io/labring/fastgpt:v4.8.6 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.5 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.6 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.8.5 # git
|
image: ghcr.io/labring/fastgpt:v4.8.6 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.5 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.6 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
fastgpt:
|
fastgpt:
|
||||||
container_name: fastgpt
|
container_name: fastgpt
|
||||||
image: ghcr.io/labring/fastgpt:v4.8.5 # git
|
image: ghcr.io/labring/fastgpt:v4.8.6 # git
|
||||||
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.5 # 阿里云
|
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.6 # 阿里云
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -14,11 +14,11 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@chakra-ui/cli": "^2.4.1",
|
"@chakra-ui/cli": "^2.4.1",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"i18next": "23.10.0",
|
|
||||||
"lint-staged": "^13.3.0",
|
"lint-staged": "^13.3.0",
|
||||||
"next-i18next": "15.2.0",
|
"i18next": "23.11.5",
|
||||||
|
"next-i18next": "15.3.0",
|
||||||
|
"react-i18next": "14.1.2",
|
||||||
"prettier": "3.2.4",
|
"prettier": "3.2.4",
|
||||||
"react-i18next": "13.5.0",
|
|
||||||
"zhlint": "^0.7.4"
|
"zhlint": "^0.7.4"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"./docSite/**/**/*.md": "npm run format-doc"
|
"./docSite/**/**/*.md": "npm run format-doc"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0",
|
"node": ">=18.16.0",
|
||||||
"pnpm": ">=8.6.0"
|
"pnpm": ">=9.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1
packages/global/common/file/image/type.d.ts
vendored
1
packages/global/common/file/image/type.d.ts
vendored
@@ -9,6 +9,7 @@ export type MongoImageSchemaType = {
|
|||||||
type: `${MongoImageTypeEnum}`;
|
type: `${MongoImageTypeEnum}`;
|
||||||
|
|
||||||
metadata?: {
|
metadata?: {
|
||||||
|
mime?: string; // image mime type.
|
||||||
relatedId?: string; // This id is associated with a set of images
|
relatedId?: string; // This id is associated with a set of images
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -70,9 +70,3 @@ export type SystemEnvType = {
|
|||||||
oneapiUrl?: string;
|
oneapiUrl?: string;
|
||||||
chatApiKey?: string;
|
chatApiKey?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// declare global {
|
|
||||||
// var feConfigs: FastGPTFeConfigsType;
|
|
||||||
// var systemEnv: SystemEnvType;
|
|
||||||
// var systemInitd: boolean;
|
|
||||||
// }
|
|
||||||
|
|||||||
10
packages/global/core/app/plugin/utils.ts
Normal file
10
packages/global/core/app/plugin/utils.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { StoreNodeItemType } from '../../workflow/type/node';
|
||||||
|
import { FlowNodeInputItemType } from '../../workflow/type/io';
|
||||||
|
import { FlowNodeTypeEnum } from '../../workflow/node/constant';
|
||||||
|
|
||||||
|
export const getPluginInputsFromStoreNodes = (nodes: StoreNodeItemType[]) => {
|
||||||
|
return nodes.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)?.inputs || [];
|
||||||
|
};
|
||||||
|
export const getPluginRunContent = (e: { pluginInputs: FlowNodeInputItemType[] }) => {
|
||||||
|
return JSON.stringify(e);
|
||||||
|
};
|
||||||
1
packages/global/core/app/type.d.ts
vendored
1
packages/global/core/app/type.d.ts
vendored
@@ -21,6 +21,7 @@ export type AppSchema = {
|
|||||||
name: string;
|
name: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
intro: string;
|
intro: string;
|
||||||
|
|
||||||
updateTime: Date;
|
updateTime: Date;
|
||||||
|
|
||||||
modules: StoreNodeItemType[];
|
modules: StoreNodeItemType[];
|
||||||
|
|||||||
@@ -56,7 +56,10 @@ export const chats2GPTMessages = ({
|
|||||||
text: item.text?.content || ''
|
text: item.text?.content || ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (item.type === 'file' && item.file?.type === ChatFileTypeEnum.image) {
|
if (
|
||||||
|
item.type === ChatItemValueTypeEnum.file &&
|
||||||
|
item.file?.type === ChatFileTypeEnum.image
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
type: 'image_url',
|
type: 'image_url',
|
||||||
image_url: {
|
image_url: {
|
||||||
@@ -64,7 +67,6 @@ export const chats2GPTMessages = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
})
|
})
|
||||||
.filter(Boolean) as ChatCompletionContentPart[];
|
.filter(Boolean) as ChatCompletionContentPart[];
|
||||||
|
|
||||||
@@ -166,7 +168,7 @@ export const GPTMessages2Chats = (
|
|||||||
} else if (item.type === 'image_url') {
|
} else if (item.type === 'image_url') {
|
||||||
value.push({
|
value.push({
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
type: 'file',
|
type: ChatItemValueTypeEnum.file,
|
||||||
file: {
|
file: {
|
||||||
type: ChatFileTypeEnum.image,
|
type: ChatFileTypeEnum.image,
|
||||||
name: '',
|
name: '',
|
||||||
@@ -175,7 +177,6 @@ export const GPTMessages2Chats = (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// @ts-ignore
|
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
obj === ChatRoleEnum.AI &&
|
obj === ChatRoleEnum.AI &&
|
||||||
|
|||||||
@@ -56,7 +56,4 @@ export enum ChatStatusEnum {
|
|||||||
finish = 'finish'
|
finish = 'finish'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const IMG_BLOCK_KEY = 'img-block';
|
|
||||||
export const FILE_BLOCK_KEY = 'file-block';
|
|
||||||
|
|
||||||
export const MARKDOWN_QUOTE_SIGN = 'QUOTE SIGN';
|
export const MARKDOWN_QUOTE_SIGN = 'QUOTE SIGN';
|
||||||
|
|||||||
3
packages/global/core/chat/type.d.ts
vendored
3
packages/global/core/chat/type.d.ts
vendored
@@ -13,8 +13,8 @@ import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
|
|||||||
import { AppChatConfigType, AppSchema, VariableItemType } from '../app/type';
|
import { AppChatConfigType, AppSchema, VariableItemType } from '../app/type';
|
||||||
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
|
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
|
||||||
import { DatasetSearchModeEnum } from '../dataset/constants';
|
import { DatasetSearchModeEnum } from '../dataset/constants';
|
||||||
import { ChatBoxInputType } from '../../../../projects/app/src/components/ChatBox/type';
|
|
||||||
import { DispatchNodeResponseType } from '../workflow/runtime/type.d';
|
import { DispatchNodeResponseType } from '../workflow/runtime/type.d';
|
||||||
|
import { ChatBoxInputType } from '../../../../projects/app/src/components/core/chat/ChatContainer/ChatBox/type';
|
||||||
|
|
||||||
export type ChatSchema = {
|
export type ChatSchema = {
|
||||||
_id: string;
|
_id: string;
|
||||||
@@ -115,6 +115,7 @@ export type ChatSiteItemType = (UserChatItemType | SystemChatItemType | AIChatIt
|
|||||||
status: `${ChatStatusEnum}`;
|
status: `${ChatStatusEnum}`;
|
||||||
moduleName?: string;
|
moduleName?: string;
|
||||||
ttsBuffer?: Uint8Array;
|
ttsBuffer?: Uint8Array;
|
||||||
|
responseData?: ChatHistoryItemResType[];
|
||||||
} & ChatBoxInputType;
|
} & ChatBoxInputType;
|
||||||
|
|
||||||
/* --------- team chat --------- */
|
/* --------- team chat --------- */
|
||||||
|
|||||||
@@ -65,11 +65,12 @@ export const filterPublicNodeResponseData = ({
|
|||||||
}: {
|
}: {
|
||||||
flowResponses?: ChatHistoryItemResType[];
|
flowResponses?: ChatHistoryItemResType[];
|
||||||
}) => {
|
}) => {
|
||||||
const filedList = ['quoteList', 'moduleType'];
|
const filedList = ['quoteList', 'moduleType', 'pluginOutput'];
|
||||||
const filterModuleTypeList: any[] = [
|
const filterModuleTypeList: any[] = [
|
||||||
FlowNodeTypeEnum.pluginModule,
|
FlowNodeTypeEnum.pluginModule,
|
||||||
FlowNodeTypeEnum.datasetSearchNode,
|
FlowNodeTypeEnum.datasetSearchNode,
|
||||||
FlowNodeTypeEnum.tools
|
FlowNodeTypeEnum.tools,
|
||||||
|
FlowNodeTypeEnum.pluginOutput
|
||||||
];
|
];
|
||||||
|
|
||||||
return flowResponses
|
return flowResponses
|
||||||
@@ -89,14 +90,22 @@ export const filterPublicNodeResponseData = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeEmptyUserInput = (input: UserChatItemValueItemType[]) => {
|
export const removeEmptyUserInput = (input?: UserChatItemValueItemType[]) => {
|
||||||
return input.filter((item) => {
|
return (
|
||||||
if (item.type === ChatItemValueTypeEnum.text && !item.text?.content?.trim()) {
|
input?.filter((item) => {
|
||||||
return false;
|
if (item.type === ChatItemValueTypeEnum.text && !item.text?.content?.trim()) {
|
||||||
}
|
return false;
|
||||||
if (item.type === ChatItemValueTypeEnum.file && !item.file?.url) {
|
}
|
||||||
return false;
|
if (item.type === ChatItemValueTypeEnum.file && !item.file?.url) {
|
||||||
}
|
return false;
|
||||||
return true;
|
}
|
||||||
});
|
return true;
|
||||||
|
}) || []
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPluginOutputsFromChatResponses = (responses: ChatHistoryItemResType[]) => {
|
||||||
|
const outputs =
|
||||||
|
responses.find((item) => item.moduleType === FlowNodeTypeEnum.pluginOutput)?.pluginOutput ?? {};
|
||||||
|
return outputs;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -142,6 +142,9 @@ export type DispatchNodeResponseType = {
|
|||||||
|
|
||||||
// code
|
// code
|
||||||
codeLog?: string;
|
codeLog?: string;
|
||||||
|
|
||||||
|
// plugin
|
||||||
|
pluginOutput?: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DispatchNodeResultType<T> = {
|
export type DispatchNodeResultType<T> = {
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ export const checkNodeRunStatus = ({
|
|||||||
(item) => item.target === node.nodeId
|
(item) => item.target === node.nodeId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Entry
|
||||||
if (workflowEdges.length === 0) {
|
if (workflowEdges.length === 0) {
|
||||||
return 'run';
|
return 'run';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,10 @@ export const Output_Template_AddOutput: FlowNodeOutputItemType = {
|
|||||||
key: NodeOutputKeyEnum.addOutputParam,
|
key: NodeOutputKeyEnum.addOutputParam,
|
||||||
type: FlowNodeOutputTypeEnum.dynamic,
|
type: FlowNodeOutputTypeEnum.dynamic,
|
||||||
valueType: WorkflowIOValueTypeEnum.dynamic,
|
valueType: WorkflowIOValueTypeEnum.dynamic,
|
||||||
label: ''
|
label: '',
|
||||||
|
customFieldConfig: {
|
||||||
|
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
|
||||||
|
showDescription: false,
|
||||||
|
showDefaultValue: false
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -82,12 +82,7 @@ export const HttpNode468: FlowNodeTemplateType = {
|
|||||||
],
|
],
|
||||||
outputs: [
|
outputs: [
|
||||||
{
|
{
|
||||||
...Output_Template_AddOutput,
|
...Output_Template_AddOutput
|
||||||
customFieldConfig: {
|
|
||||||
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
|
|
||||||
showDescription: false,
|
|
||||||
showDefaultValue: true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: NodeOutputKeyEnum.error,
|
id: NodeOutputKeyEnum.error,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { LLMModelTypeEnum } from '../../../ai/constants';
|
|||||||
import { getHandleConfig } from '../utils';
|
import { getHandleConfig } from '../utils';
|
||||||
|
|
||||||
export const AiQueryExtension: FlowNodeTemplateType = {
|
export const AiQueryExtension: FlowNodeTemplateType = {
|
||||||
id: FlowNodeTypeEnum.chatNode,
|
id: FlowNodeTypeEnum.queryExtension,
|
||||||
templateType: FlowNodeTemplateTypeEnum.other,
|
templateType: FlowNodeTemplateTypeEnum.other,
|
||||||
flowNodeType: FlowNodeTypeEnum.queryExtension,
|
flowNodeType: FlowNodeTypeEnum.queryExtension,
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
|
|||||||
@@ -36,6 +36,32 @@ export const CodeNode: FlowNodeTemplateType = {
|
|||||||
showDefaultValue: true
|
showDefaultValue: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||||
|
valueType: WorkflowIOValueTypeEnum.string,
|
||||||
|
canEdit: true,
|
||||||
|
key: 'data1',
|
||||||
|
label: 'data1',
|
||||||
|
customInputConfig: {
|
||||||
|
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
|
||||||
|
showDescription: false,
|
||||||
|
showDefaultValue: true
|
||||||
|
},
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
renderTypeList: [FlowNodeInputTypeEnum.reference],
|
||||||
|
valueType: WorkflowIOValueTypeEnum.string,
|
||||||
|
canEdit: true,
|
||||||
|
key: 'data2',
|
||||||
|
label: 'data2',
|
||||||
|
customInputConfig: {
|
||||||
|
selectValueTypeList: Object.values(WorkflowIOValueTypeEnum),
|
||||||
|
showDescription: false,
|
||||||
|
showDefaultValue: true
|
||||||
|
},
|
||||||
|
required: true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.codeType,
|
key: NodeInputKeyEnum.codeType,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
@@ -52,7 +78,7 @@ export const CodeNode: FlowNodeTemplateType = {
|
|||||||
outputs: [
|
outputs: [
|
||||||
{
|
{
|
||||||
...Output_Template_AddOutput,
|
...Output_Template_AddOutput,
|
||||||
description: '将代码中 return 的对象作为输出,传递给后续的节点'
|
description: '将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: NodeOutputKeyEnum.rawResponse,
|
id: NodeOutputKeyEnum.rawResponse,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export const ToolModule: FlowNodeTemplateType = {
|
|||||||
sourceHandle: getHandleConfig(true, true, false, true),
|
sourceHandle: getHandleConfig(true, true, false, true),
|
||||||
targetHandle: getHandleConfig(true, true, false, true),
|
targetHandle: getHandleConfig(true, true, false, true),
|
||||||
avatar: '/imgs/workflow/tool.svg',
|
avatar: '/imgs/workflow/tool.svg',
|
||||||
name: '工具调用(实验)',
|
name: '工具调用',
|
||||||
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
version: '481',
|
version: '481',
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
defaultWhisperConfig
|
defaultWhisperConfig
|
||||||
} from '../app/constants';
|
} from '../app/constants';
|
||||||
import { IfElseResultEnum } from './template/system/ifElse/constant';
|
import { IfElseResultEnum } from './template/system/ifElse/constant';
|
||||||
|
import { RuntimeNodeItemType } from './runtime/type';
|
||||||
|
|
||||||
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
|
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
|
||||||
return `${nodeId}-${type}-${key}`;
|
return `${nodeId}-${type}-${key}`;
|
||||||
@@ -190,3 +191,38 @@ export const isReferenceValue = (value: any): boolean => {
|
|||||||
export const getElseIFLabel = (i: number) => {
|
export const getElseIFLabel = (i: number) => {
|
||||||
return i === 0 ? IfElseResultEnum.IF : `${IfElseResultEnum.ELSE_IF} ${i}`;
|
return i === 0 ? IfElseResultEnum.IF : `${IfElseResultEnum.ELSE_IF} ${i}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// add value to plugin input node when run plugin
|
||||||
|
export const updatePluginInputByVariables = (
|
||||||
|
nodes: RuntimeNodeItemType[],
|
||||||
|
variables: Record<string, any>
|
||||||
|
) => {
|
||||||
|
return nodes.map((node) =>
|
||||||
|
node.flowNodeType === FlowNodeTypeEnum.pluginInput
|
||||||
|
? {
|
||||||
|
...node,
|
||||||
|
inputs: node.inputs.map((input) => {
|
||||||
|
const parseValue = (() => {
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
input.valueType === WorkflowIOValueTypeEnum.string ||
|
||||||
|
input.valueType === WorkflowIOValueTypeEnum.number ||
|
||||||
|
input.valueType === WorkflowIOValueTypeEnum.boolean
|
||||||
|
)
|
||||||
|
return variables[input.key];
|
||||||
|
|
||||||
|
return JSON.parse(variables[input.key]);
|
||||||
|
} catch (e) {
|
||||||
|
return variables[input.key];
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
value: parseValue ?? input.value
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
: node
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -10,13 +10,13 @@
|
|||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jschardet": "3.1.1",
|
"jschardet": "3.1.1",
|
||||||
"nanoid": "^4.0.1",
|
"nanoid": "^4.0.1",
|
||||||
"next": "14.2.3",
|
"next": "14.2.5",
|
||||||
"openai": "4.28.0",
|
"openai": "4.28.0",
|
||||||
"openapi-types": "^12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
"timezones-list": "^3.0.2"
|
"timezones-list": "^3.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/node": "^20.14.2"
|
"@types/node": "20.14.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fastgpt/global": "workspace:*",
|
"@fastgpt/global": "workspace:*",
|
||||||
"@fastgpt/service": "workspace:*",
|
"@fastgpt/service": "workspace:*",
|
||||||
"@types/node": "^20.14.2"
|
"@types/node": "20.14.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { SystemPluginResponseType } from '../../type';
|
import { urlsFetch } from '@fastgpt/service/common/string/cheerio';
|
||||||
import { urlsFetch } from '../../../service/common/string/cheerio';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
url: string;
|
url: string;
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ const instance = axios.create({
|
|||||||
'Cache-Control': 'no-cache'
|
'Cache-Control': 'no-cache'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
export const serverRequestBaseUrl = `http://${SERVICE_LOCAL_HOST}`;
|
||||||
|
|
||||||
/* 请求拦截 */
|
/* 请求拦截 */
|
||||||
instance.interceptors.request.use(requestStart, (err) => Promise.reject(err));
|
instance.interceptors.request.use(requestStart, (err) => Promise.reject(err));
|
||||||
@@ -79,7 +80,7 @@ export function request(url: string, data: any, config: ConfigType, method: Meth
|
|||||||
|
|
||||||
return instance
|
return instance
|
||||||
.request({
|
.request({
|
||||||
baseURL: `http://${SERVICE_LOCAL_HOST}`,
|
baseURL: serverRequestBaseUrl,
|
||||||
url,
|
url,
|
||||||
method,
|
method,
|
||||||
data: ['POST', 'PUT'].includes(method) ? data : null,
|
data: ['POST', 'PUT'].includes(method) ? data : null,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export function getMongoImgUrl(id: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const maxImgSize = 1024 * 1024 * 12;
|
export const maxImgSize = 1024 * 1024 * 12;
|
||||||
|
const base64MimeRegex = /data:image\/([^\)]+);base64/;
|
||||||
export async function uploadMongoImg({
|
export async function uploadMongoImg({
|
||||||
type,
|
type,
|
||||||
base64Img,
|
base64Img,
|
||||||
@@ -22,7 +23,8 @@ export async function uploadMongoImg({
|
|||||||
return Promise.reject('Image too large');
|
return Promise.reject('Image too large');
|
||||||
}
|
}
|
||||||
|
|
||||||
const base64Data = base64Img.split(',')[1];
|
const [base64Mime, base64Data] = base64Img.split(',')
|
||||||
|
const mime = `image/${base64Mime.match(base64MimeRegex)?.[1] ?? 'jpeg'}`
|
||||||
const binary = Buffer.from(base64Data, 'base64');
|
const binary = Buffer.from(base64Data, 'base64');
|
||||||
|
|
||||||
const { _id } = await MongoImage.create({
|
const { _id } = await MongoImage.create({
|
||||||
@@ -30,7 +32,7 @@ export async function uploadMongoImg({
|
|||||||
teamId,
|
teamId,
|
||||||
binary,
|
binary,
|
||||||
expiredTime,
|
expiredTime,
|
||||||
metadata,
|
metadata: Object.assign({ mime }, metadata),
|
||||||
shareId
|
shareId
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -42,7 +44,7 @@ export async function readMongoImg({ id }: { id: string }) {
|
|||||||
if (!data) {
|
if (!data) {
|
||||||
return Promise.reject('Image not found');
|
return Promise.reject('Image not found');
|
||||||
}
|
}
|
||||||
return data?.binary;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function delImgByRelatedId({
|
export async function delImgByRelatedId({
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { addLog } from '../../common/system/log';
|
import { addLog } from '../../common/system/log';
|
||||||
import mongoose, { Model } from 'mongoose';
|
import mongoose, { Model } from 'mongoose';
|
||||||
|
|
||||||
|
export default mongoose;
|
||||||
|
export * from 'mongoose';
|
||||||
|
|
||||||
export const connectionMongo = (() => {
|
export const connectionMongo = (() => {
|
||||||
if (!global.mongodb) {
|
if (!global.mongodb) {
|
||||||
global.mongodb = mongoose;
|
global.mongodb = mongoose;
|
||||||
@@ -9,9 +12,6 @@ export const connectionMongo = (() => {
|
|||||||
return global.mongodb;
|
return global.mongodb;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
export default mongoose;
|
|
||||||
export * from 'mongoose';
|
|
||||||
|
|
||||||
const addCommonMiddleware = (schema: mongoose.Schema) => {
|
const addCommonMiddleware = (schema: mongoose.Schema) => {
|
||||||
const operations = [
|
const operations = [
|
||||||
/^find/,
|
/^find/,
|
||||||
@@ -64,10 +64,13 @@ export const getMongoModel = <T>(name: string, schema: mongoose.Schema) => {
|
|||||||
addCommonMiddleware(schema);
|
addCommonMiddleware(schema);
|
||||||
|
|
||||||
const model = connectionMongo.model<T>(name, schema);
|
const model = connectionMongo.model<T>(name, schema);
|
||||||
try {
|
|
||||||
model.syncIndexes();
|
if (process.env.SYNC_INDEX !== '0') {
|
||||||
} catch (error) {
|
try {
|
||||||
addLog.error('Create index error', error);
|
model.syncIndexes({ background: true });
|
||||||
|
} catch (error) {
|
||||||
|
addLog.error('Create index error', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { exit } from 'process';
|
||||||
import { addLog } from '../system/log';
|
import { addLog } from '../system/log';
|
||||||
import { connectionMongo } from './index';
|
import { connectionMongo } from './index';
|
||||||
import type { Mongoose } from 'mongoose';
|
import type { Mongoose } from 'mongoose';
|
||||||
@@ -56,9 +57,13 @@ export async function connectMongo({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
afterHook && (await afterHook());
|
if (!global.systemInited) {
|
||||||
|
global.systemInited = true;
|
||||||
|
afterHook && (await afterHook());
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addLog.error('mongo connect after hook error', error);
|
addLog.error('Mongo connect after hook error', error);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return connectionMongo;
|
return connectionMongo;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { LogLevelEnum } from './log/constant';
|
import { LogLevelEnum } from './log/constant';
|
||||||
// import { MongoLog } from './log/schema';
|
import { connectionMongo } from '../mongo/index';
|
||||||
import connectionMongo from '../mongo/index';
|
import { getMongoLog } from './log/schema';
|
||||||
|
|
||||||
const logMap = {
|
const logMap = {
|
||||||
[LogLevelEnum.debug]: {
|
[LogLevelEnum.debug]: {
|
||||||
@@ -52,14 +52,14 @@ export const addLog = {
|
|||||||
level === LogLevelEnum.error && console.error(obj);
|
level === LogLevelEnum.error && console.error(obj);
|
||||||
|
|
||||||
// store
|
// store
|
||||||
// if (level >= STORE_LOG_LEVEL && connectionMongo.connection.readyState === 1) {
|
if (level >= STORE_LOG_LEVEL && connectionMongo.connection.readyState === 1) {
|
||||||
// // store log
|
// store log
|
||||||
// MongoLog.create({
|
getMongoLog().create({
|
||||||
// text: msg,
|
text: msg,
|
||||||
// level,
|
level,
|
||||||
// metadata: obj
|
metadata: obj
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
},
|
},
|
||||||
debug(msg: string, obj?: Record<string, any>) {
|
debug(msg: string, obj?: Record<string, any>) {
|
||||||
this.log(LogLevelEnum.debug, msg, obj);
|
this.log(LogLevelEnum.debug, msg, obj);
|
||||||
|
|||||||
@@ -4,24 +4,26 @@ import { LogLevelEnum } from './constant';
|
|||||||
|
|
||||||
export const LogCollectionName = 'system_logs';
|
export const LogCollectionName = 'system_logs';
|
||||||
|
|
||||||
const SystemLogSchema = new Schema({
|
export const getMongoLog = () => {
|
||||||
text: {
|
const SystemLogSchema = new Schema({
|
||||||
type: String,
|
text: {
|
||||||
required: true
|
type: String,
|
||||||
},
|
required: true
|
||||||
level: {
|
},
|
||||||
type: String,
|
level: {
|
||||||
required: true,
|
type: String,
|
||||||
enum: Object.values(LogLevelEnum)
|
required: true,
|
||||||
},
|
enum: Object.values(LogLevelEnum)
|
||||||
time: {
|
},
|
||||||
type: Date,
|
time: {
|
||||||
default: () => new Date()
|
type: Date,
|
||||||
},
|
default: () => new Date()
|
||||||
metadata: Object
|
},
|
||||||
});
|
metadata: Object
|
||||||
|
});
|
||||||
|
|
||||||
SystemLogSchema.index({ time: 1 }, { expires: '15d' });
|
SystemLogSchema.index({ time: 1 }, { expires: '15d' });
|
||||||
SystemLogSchema.index({ level: 1 });
|
SystemLogSchema.index({ level: 1 });
|
||||||
|
|
||||||
export const MongoLog = getMongoModel<SystemLogType>(LogCollectionName, SystemLogSchema);
|
return getMongoModel<SystemLogType>(LogCollectionName, SystemLogSchema);
|
||||||
|
};
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ const AppSchema = new Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
updateTime: {
|
updateTime: {
|
||||||
type: Date,
|
type: Date,
|
||||||
default: () => new Date()
|
default: () => new Date()
|
||||||
@@ -112,7 +113,7 @@ const AppSchema = new Schema({
|
|||||||
...getPermissionSchema(AppDefaultPermissionVal)
|
...getPermissionSchema(AppDefaultPermissionVal)
|
||||||
});
|
});
|
||||||
|
|
||||||
AppSchema.index({ updateTime: -1 });
|
AppSchema.index({ teamId: 1, updateTime: -1 });
|
||||||
AppSchema.index({ teamId: 1, type: 1 });
|
AppSchema.index({ teamId: 1, type: 1 });
|
||||||
AppSchema.index({ scheduledTriggerConfig: 1, intervalNextTime: -1 });
|
AppSchema.index({ scheduledTriggerConfig: 1, intervalNextTime: -1 });
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { IMG_BLOCK_KEY } from '@fastgpt/global/core/chat/constants';
|
|
||||||
import { countGptMessagesTokens } from '../../common/string/tiktoken/index';
|
import { countGptMessagesTokens } from '../../common/string/tiktoken/index';
|
||||||
import type {
|
import type {
|
||||||
ChatCompletionContentPart,
|
ChatCompletionContentPart,
|
||||||
@@ -7,6 +6,8 @@ import type {
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
|
import { ChatCompletionRequestMessageRoleEnum } from '@fastgpt/global/core/ai/constants';
|
||||||
import { guessBase64ImageType } from '../../common/file/utils';
|
import { guessBase64ImageType } from '../../common/file/utils';
|
||||||
|
import { serverRequestBaseUrl } from '../../common/api/serverRequest';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
|
||||||
/* slice chat context by tokens */
|
/* slice chat context by tokens */
|
||||||
const filterEmptyMessages = (messages: ChatCompletionMessageParam[]) => {
|
const filterEmptyMessages = (messages: ChatCompletionMessageParam[]) => {
|
||||||
@@ -120,137 +121,64 @@ export const formatGPTMessagesInRequestBefore = (messages: ChatCompletionMessage
|
|||||||
.filter(Boolean) as ChatCompletionMessageParam[];
|
.filter(Boolean) as ChatCompletionMessageParam[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/* Load user chat content.
|
||||||
string to vision model. Follow the markdown code block rule for interception:
|
Img: to base 64
|
||||||
|
*/
|
||||||
@rule:
|
|
||||||
```img-block
|
|
||||||
{src:""}
|
|
||||||
{src:""}
|
|
||||||
```
|
|
||||||
```file-block
|
|
||||||
{name:"",src:""},
|
|
||||||
{name:"",src:""}
|
|
||||||
```
|
|
||||||
@example:
|
|
||||||
What’s in this image?
|
|
||||||
```img-block
|
|
||||||
{src:"https://1.png"}
|
|
||||||
```
|
|
||||||
@return
|
|
||||||
[
|
|
||||||
{ type: 'text', text: 'What’s in this image?' },
|
|
||||||
{
|
|
||||||
type: 'image_url',
|
|
||||||
image_url: {
|
|
||||||
url: 'https://1.png'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
*/
|
|
||||||
export async function formatStr2ChatContent(str: string) {
|
|
||||||
const content: ChatCompletionContentPart[] = [];
|
|
||||||
let lastIndex = 0;
|
|
||||||
const regex = new RegExp(`\`\`\`(${IMG_BLOCK_KEY})\\n([\\s\\S]*?)\`\`\``, 'g');
|
|
||||||
|
|
||||||
const imgKey: 'image_url' = 'image_url';
|
|
||||||
|
|
||||||
let match;
|
|
||||||
|
|
||||||
while ((match = regex.exec(str)) !== null) {
|
|
||||||
// add previous text
|
|
||||||
if (match.index > lastIndex) {
|
|
||||||
const text = str.substring(lastIndex, match.index).trim();
|
|
||||||
if (text) {
|
|
||||||
content.push({ type: 'text', text });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const blockType = match[1].trim();
|
|
||||||
|
|
||||||
if (blockType === IMG_BLOCK_KEY) {
|
|
||||||
const blockContentLines = match[2].trim().split('\n');
|
|
||||||
const jsonLines = blockContentLines.map((item) => {
|
|
||||||
try {
|
|
||||||
return JSON.parse(item) as { src: string };
|
|
||||||
} catch (error) {
|
|
||||||
return { src: '' };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const item of jsonLines) {
|
|
||||||
if (!item.src) throw new Error("image block's content error");
|
|
||||||
}
|
|
||||||
|
|
||||||
content.push(
|
|
||||||
...jsonLines.map((item) => ({
|
|
||||||
type: imgKey,
|
|
||||||
image_url: {
|
|
||||||
url: item.src
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastIndex = regex.lastIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add remaining text
|
|
||||||
if (lastIndex < str.length) {
|
|
||||||
const remainingText = str.substring(lastIndex).trim();
|
|
||||||
if (remainingText) {
|
|
||||||
content.push({ type: 'text', text: remainingText });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continuous text type content, if type=text, merge them
|
|
||||||
for (let i = 0; i < content.length - 1; i++) {
|
|
||||||
const currentContent = content[i];
|
|
||||||
const nextContent = content[i + 1];
|
|
||||||
if (currentContent.type === 'text' && nextContent.type === 'text') {
|
|
||||||
currentContent.text += nextContent.text;
|
|
||||||
content.splice(i + 1, 1);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content.length === 1 && content[0].type === 'text') {
|
|
||||||
return content[0].text;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!content) return null;
|
|
||||||
// load img to base64
|
|
||||||
for await (const item of content) {
|
|
||||||
if (item.type === imgKey && item[imgKey]?.url) {
|
|
||||||
const response = await axios.get(item[imgKey].url, {
|
|
||||||
responseType: 'arraybuffer'
|
|
||||||
});
|
|
||||||
const base64 = Buffer.from(response.data).toString('base64');
|
|
||||||
item[imgKey].url = `data:${response.headers['content-type']};base64,${base64}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return content ? content : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadChatImgToBase64 = async (content: string | ChatCompletionContentPart[]) => {
|
export const loadChatImgToBase64 = async (content: string | ChatCompletionContentPart[]) => {
|
||||||
if (typeof content === 'string') {
|
if (typeof content === 'string') {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
content.map(async (item) => {
|
content.map(async (item) => {
|
||||||
if (item.type === 'text') return item;
|
if (item.type === 'text') return item;
|
||||||
// load image
|
|
||||||
const response = await axios.get(item.image_url.url, {
|
if (!item.image_url.url) return item;
|
||||||
responseType: 'arraybuffer'
|
|
||||||
});
|
/*
|
||||||
const base64 = Buffer.from(response.data).toString('base64');
|
1. From db: Get it from db
|
||||||
let imageType = response.headers['content-type'];
|
2. From web: Not update
|
||||||
if (imageType === undefined) {
|
*/
|
||||||
imageType = guessBase64ImageType(base64);
|
if (item.image_url.url.startsWith('/')) {
|
||||||
|
const response = await axios.get(item.image_url.url, {
|
||||||
|
baseURL: serverRequestBaseUrl,
|
||||||
|
responseType: 'arraybuffer'
|
||||||
|
});
|
||||||
|
const base64 = Buffer.from(response.data).toString('base64');
|
||||||
|
let imageType = response.headers['content-type'];
|
||||||
|
if (imageType === undefined) {
|
||||||
|
imageType = guessBase64ImageType(base64);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
image_url: {
|
||||||
|
...item.image_url,
|
||||||
|
url: `data:${imageType};base64,${base64}`
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
item.image_url.url = `data:${imageType};base64,${base64}`;
|
|
||||||
return item;
|
return item;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
export const loadRequestMessages = async (messages: ChatCompletionMessageParam[]) => {
|
||||||
|
if (messages.length === 0) {
|
||||||
|
return Promise.reject('core.chat.error.Messages empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadMessages = await Promise.all(
|
||||||
|
messages.map(async (item) => {
|
||||||
|
if (item.role === ChatCompletionRequestMessageRoleEnum.User) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
content: await loadChatImgToBase64(item.content)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return loadMessages;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||||
import { getAIApi } from '../../../../ai/config';
|
import { getAIApi } from '../../../../ai/config';
|
||||||
import { filterGPTMessageByMaxTokens } from '../../../../chat/utils';
|
import { filterGPTMessageByMaxTokens, loadRequestMessages } from '../../../../chat/utils';
|
||||||
import {
|
import {
|
||||||
ChatCompletion,
|
ChatCompletion,
|
||||||
StreamChatType,
|
StreamChatType,
|
||||||
@@ -88,6 +88,7 @@ export const runToolWithFunctionCall = async (
|
|||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
const requestMessages = await loadRequestMessages(formativeMessages);
|
||||||
|
|
||||||
/* Run llm */
|
/* Run llm */
|
||||||
const ai = getAIApi({
|
const ai = getAIApi({
|
||||||
@@ -99,7 +100,7 @@ export const runToolWithFunctionCall = async (
|
|||||||
model: toolModel.model,
|
model: toolModel.model,
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
stream,
|
stream,
|
||||||
messages: formativeMessages,
|
messages: requestMessages,
|
||||||
functions,
|
functions,
|
||||||
function_call: 'auto'
|
function_call: 'auto'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { ChatItemType } from '@fastgpt/global/core/chat/type';
|
|||||||
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
import {
|
import {
|
||||||
GPTMessages2Chats,
|
GPTMessages2Chats,
|
||||||
|
chatValue2RuntimePrompt,
|
||||||
chats2GPTMessages,
|
chats2GPTMessages,
|
||||||
getSystemPrompt,
|
getSystemPrompt,
|
||||||
runtimePrompt2ChatsValue
|
runtimePrompt2ChatsValue
|
||||||
@@ -29,10 +30,11 @@ type Response = DispatchNodeResultType<{
|
|||||||
|
|
||||||
export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<Response> => {
|
export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<Response> => {
|
||||||
const {
|
const {
|
||||||
node: { nodeId, name, outputs },
|
node: { nodeId, name },
|
||||||
runtimeNodes,
|
runtimeNodes,
|
||||||
runtimeEdges,
|
runtimeEdges,
|
||||||
histories,
|
histories,
|
||||||
|
query,
|
||||||
params: { model, systemPrompt, userChatInput, history = 6 }
|
params: { model, systemPrompt, userChatInput, history = 6 }
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ export const dispatchRunTools = async (props: DispatchToolModuleProps): Promise<
|
|||||||
obj: ChatRoleEnum.Human,
|
obj: ChatRoleEnum.Human,
|
||||||
value: runtimePrompt2ChatsValue({
|
value: runtimePrompt2ChatsValue({
|
||||||
text: userChatInput,
|
text: userChatInput,
|
||||||
files: []
|
files: chatValue2RuntimePrompt(query).files
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||||
import { getAIApi } from '../../../../ai/config';
|
import { getAIApi } from '../../../../ai/config';
|
||||||
import { filterGPTMessageByMaxTokens } from '../../../../chat/utils';
|
import { filterGPTMessageByMaxTokens, loadRequestMessages } from '../../../../chat/utils';
|
||||||
import {
|
import {
|
||||||
ChatCompletion,
|
ChatCompletion,
|
||||||
StreamChatType,
|
StreamChatType,
|
||||||
@@ -87,6 +87,8 @@ export const runToolWithPromptCall = async (
|
|||||||
messages,
|
messages,
|
||||||
maxTokens: toolModel.maxContext - 500 // filter token. not response maxToken
|
maxTokens: toolModel.maxContext - 500 // filter token. not response maxToken
|
||||||
});
|
});
|
||||||
|
const requestMessages = await loadRequestMessages(filterMessages);
|
||||||
|
|
||||||
// console.log(JSON.stringify(filterMessages, null, 2));
|
// console.log(JSON.stringify(filterMessages, null, 2));
|
||||||
/* Run llm */
|
/* Run llm */
|
||||||
const ai = getAIApi({
|
const ai = getAIApi({
|
||||||
@@ -98,7 +100,7 @@ export const runToolWithPromptCall = async (
|
|||||||
model: toolModel.model,
|
model: toolModel.model,
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
stream,
|
stream,
|
||||||
messages: filterMessages
|
messages: requestMessages
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
||||||
import { getAIApi } from '../../../../ai/config';
|
import { getAIApi } from '../../../../ai/config';
|
||||||
import { filterGPTMessageByMaxTokens } from '../../../../chat/utils';
|
import { filterGPTMessageByMaxTokens, loadRequestMessages } from '../../../../chat/utils';
|
||||||
import {
|
import {
|
||||||
ChatCompletion,
|
ChatCompletion,
|
||||||
ChatCompletionMessageToolCall,
|
ChatCompletionMessageToolCall,
|
||||||
@@ -99,6 +99,8 @@ export const runToolWithToolChoice = async (
|
|||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
const requestMessages = await loadRequestMessages(formativeMessages);
|
||||||
|
|
||||||
// console.log(
|
// console.log(
|
||||||
// JSON.stringify(
|
// JSON.stringify(
|
||||||
// {
|
// {
|
||||||
@@ -106,7 +108,7 @@ export const runToolWithToolChoice = async (
|
|||||||
// model: toolModel.model,
|
// model: toolModel.model,
|
||||||
// temperature: 0,
|
// temperature: 0,
|
||||||
// stream,
|
// stream,
|
||||||
// messages: formativeMessages,
|
// messages: requestMessages,
|
||||||
// tools,
|
// tools,
|
||||||
// tool_choice: 'auto'
|
// tool_choice: 'auto'
|
||||||
// },
|
// },
|
||||||
@@ -124,7 +126,7 @@ export const runToolWithToolChoice = async (
|
|||||||
model: toolModel.model,
|
model: toolModel.model,
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
stream,
|
stream,
|
||||||
messages: formativeMessages,
|
messages: requestMessages,
|
||||||
tools,
|
tools,
|
||||||
tool_choice: 'auto'
|
tool_choice: 'auto'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { NextApiResponse } from 'next';
|
|||||||
import {
|
import {
|
||||||
filterGPTMessageByMaxTokens,
|
filterGPTMessageByMaxTokens,
|
||||||
formatGPTMessagesInRequestBefore,
|
formatGPTMessagesInRequestBefore,
|
||||||
loadChatImgToBase64
|
loadRequestMessages
|
||||||
} from '../../../chat/utils';
|
} from '../../../chat/utils';
|
||||||
import type { ChatItemType, UserChatItemValueItemType } from '@fastgpt/global/core/chat/type.d';
|
import type { ChatItemType, UserChatItemValueItemType } from '@fastgpt/global/core/chat/type.d';
|
||||||
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
import { ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
@@ -151,22 +151,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
...formatGPTMessagesInRequestBefore(filterMessages)
|
...formatGPTMessagesInRequestBefore(filterMessages)
|
||||||
] as ChatCompletionMessageParam[];
|
] as ChatCompletionMessageParam[];
|
||||||
|
|
||||||
if (concatMessages.length === 0) {
|
const requestMessages = await loadRequestMessages(concatMessages);
|
||||||
return Promise.reject('core.chat.error.Messages empty');
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadMessages = await Promise.all(
|
|
||||||
concatMessages.map(async (item) => {
|
|
||||||
if (item.role === ChatCompletionRequestMessageRoleEnum.User) {
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
content: await loadChatImgToBase64(item.content)
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const requestBody = {
|
const requestBody = {
|
||||||
...modelConstantsData?.defaultConfig,
|
...modelConstantsData?.defaultConfig,
|
||||||
@@ -174,7 +159,7 @@ export const dispatchChatCompletion = async (props: ChatProps): Promise<ChatResp
|
|||||||
temperature,
|
temperature,
|
||||||
max_tokens,
|
max_tokens,
|
||||||
stream,
|
stream,
|
||||||
messages: loadMessages
|
messages: requestMessages
|
||||||
};
|
};
|
||||||
const response = await ai.chat.completions.create(requestBody, {
|
const response = await ai.chat.completions.create(requestBody, {
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"mammoth": "^1.6.0",
|
"mammoth": "^1.6.0",
|
||||||
"mongoose": "^7.0.2",
|
"mongoose": "^7.0.2",
|
||||||
"multer": "1.4.5-lts.1",
|
"multer": "1.4.5-lts.1",
|
||||||
"next": "14.2.3",
|
"next": "14.2.5",
|
||||||
"nextjs-cors": "^2.2.0",
|
"nextjs-cors": "^2.2.0",
|
||||||
"node-cron": "^3.0.3",
|
"node-cron": "^3.0.3",
|
||||||
"node-xlsx": "^0.23.0",
|
"node-xlsx": "^0.23.0",
|
||||||
|
|||||||
2
packages/service/type.d.ts
vendored
2
packages/service/type.d.ts
vendored
@@ -25,4 +25,6 @@ declare global {
|
|||||||
worker: Worker;
|
worker: Worker;
|
||||||
callbackMap: Record<string, (e: number) => void>;
|
callbackMap: Record<string, (e: number) => void>;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
|
var systemInited: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
DragStart,
|
DragStart,
|
||||||
DropResult
|
DropResult
|
||||||
} from 'react-beautiful-dnd';
|
} from 'react-beautiful-dnd';
|
||||||
|
export * from 'react-beautiful-dnd';
|
||||||
|
|
||||||
type Props<T = any> = {
|
type Props<T = any> = {
|
||||||
onDragEndCb: (result: T[]) => void;
|
onDragEndCb: (result: T[]) => void;
|
||||||
@@ -57,5 +58,3 @@ function DndDrag<T>({ children, renderClone, onDragEndCb, dataList }: Props<T>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default DndDrag;
|
export default DndDrag;
|
||||||
|
|
||||||
export * from 'react-beautiful-dnd';
|
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ const CloseIcon = (props: FlexProps) => {
|
|||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
cursor={'pointer'}
|
cursor={'pointer'}
|
||||||
w={'22px'}
|
w={'1.5rem'}
|
||||||
h={'22px'}
|
h={'1.5rem'}
|
||||||
alignItems={'center'}
|
alignItems={'center'}
|
||||||
justifyContent={'center'}
|
justifyContent={'center'}
|
||||||
borderRadius={'50%'}
|
borderRadius={'50%'}
|
||||||
_hover={{ bg: 'myGray.200' }}
|
_hover={{ bg: 'myGray.200' }}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<MyIcon name={'common/closeLight'} w={'12px'} color={'myGray.500'} />
|
<MyIcon name={'common/closeLight'} w={'80%'} h={'80%'} color={'myGray.500'} />
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import {
|
|||||||
ModalCloseButton,
|
ModalCloseButton,
|
||||||
ModalContentProps,
|
ModalContentProps,
|
||||||
Box,
|
Box,
|
||||||
Image,
|
Image
|
||||||
useMediaQuery
|
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import MyIcon from '../Icon';
|
import MyIcon from '../Icon';
|
||||||
import MyBox from '../MyBox';
|
import MyBox from '../MyBox';
|
||||||
|
import { useSystem } from '../../../hooks/useSystem';
|
||||||
|
|
||||||
export interface MyModalProps extends ModalContentProps {
|
export interface MyModalProps extends ModalContentProps {
|
||||||
iconSrc?: string;
|
iconSrc?: string;
|
||||||
@@ -34,7 +34,7 @@ const MyModal = ({
|
|||||||
maxW = ['90vw', '600px'],
|
maxW = ['90vw', '600px'],
|
||||||
...props
|
...props
|
||||||
}: MyModalProps) => {
|
}: MyModalProps) => {
|
||||||
const [isPc] = useMediaQuery('(min-width: 900px)');
|
const isPc = useSystem();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import MyPopover from './index';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import MyIcon from '../Icon';
|
import MyIcon from '../Icon';
|
||||||
import { useRequest2 } from '../../../hooks/useRequest';
|
import { useRequest2 } from '../../../hooks/useRequest';
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ const MultipleSelect = <T = any,>({
|
|||||||
borderRadius={'md'}
|
borderRadius={'md'}
|
||||||
border={'base'}
|
border={'base'}
|
||||||
userSelect={'none'}
|
userSelect={'none'}
|
||||||
minH={'40px'}
|
|
||||||
cursor={'pointer'}
|
cursor={'pointer'}
|
||||||
_active={{
|
_active={{
|
||||||
transform: 'none'
|
transform: 'none'
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
import React, { useRef, forwardRef, useMemo } from 'react';
|
import React, {
|
||||||
|
useRef,
|
||||||
|
forwardRef,
|
||||||
|
useMemo,
|
||||||
|
useEffect,
|
||||||
|
useImperativeHandle,
|
||||||
|
ForwardedRef
|
||||||
|
} from 'react';
|
||||||
import {
|
import {
|
||||||
Menu,
|
Menu,
|
||||||
MenuList,
|
MenuList,
|
||||||
@@ -28,17 +35,21 @@ export type SelectProps<T = any> = ButtonProps & {
|
|||||||
onchange?: (val: T) => void;
|
onchange?: (val: T) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MySelect = <T = any,>({
|
const MySelect = <T = any,>(
|
||||||
placeholder,
|
{
|
||||||
value,
|
placeholder,
|
||||||
width = '100%',
|
value,
|
||||||
list = [],
|
width = '100%',
|
||||||
onchange,
|
list = [],
|
||||||
isLoading = false,
|
onchange,
|
||||||
...props
|
isLoading = false,
|
||||||
}: SelectProps<T>) => {
|
...props
|
||||||
const ref = useRef<HTMLButtonElement>(null);
|
}: SelectProps<T>,
|
||||||
const { Loading } = useLoading();
|
ref: ForwardedRef<{
|
||||||
|
focus: () => void;
|
||||||
|
}>
|
||||||
|
) => {
|
||||||
|
const ButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
const menuItemStyles: MenuItemProps = {
|
const menuItemStyles: MenuItemProps = {
|
||||||
borderRadius: 'sm',
|
borderRadius: 'sm',
|
||||||
py: 2,
|
py: 2,
|
||||||
@@ -54,6 +65,12 @@ const MySelect = <T = any,>({
|
|||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const selectItem = useMemo(() => list.find((item) => item.value === value), [list, value]);
|
const selectItem = useMemo(() => list.find((item) => item.value === value), [list, value]);
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
focus() {
|
||||||
|
onOpen();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
css={css({
|
css={css({
|
||||||
@@ -72,7 +89,7 @@ const MySelect = <T = any,>({
|
|||||||
>
|
>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
as={Button}
|
as={Button}
|
||||||
ref={ref}
|
ref={ButtonRef}
|
||||||
width={width}
|
width={width}
|
||||||
px={3}
|
px={3}
|
||||||
rightIcon={<ChevronDownIcon />}
|
rightIcon={<ChevronDownIcon />}
|
||||||
@@ -98,7 +115,7 @@ const MySelect = <T = any,>({
|
|||||||
<MenuList
|
<MenuList
|
||||||
className={props.className}
|
className={props.className}
|
||||||
minW={(() => {
|
minW={(() => {
|
||||||
const w = ref.current?.clientWidth;
|
const w = ButtonRef.current?.clientWidth;
|
||||||
if (w) {
|
if (w) {
|
||||||
return `${w}px !important`;
|
return `${w}px !important`;
|
||||||
}
|
}
|
||||||
@@ -152,4 +169,6 @@ const MySelect = <T = any,>({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MySelect;
|
export default forwardRef(MySelect) as <T>(
|
||||||
|
props: SelectProps<T> & { ref?: React.Ref<HTMLSelectElement> }
|
||||||
|
) => JSX.Element;
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box, Tooltip, TooltipProps, css, useMediaQuery } from '@chakra-ui/react';
|
import { Box, Tooltip, TooltipProps } from '@chakra-ui/react';
|
||||||
|
import { useSystem } from '../../../hooks/useSystem';
|
||||||
|
|
||||||
interface Props extends TooltipProps {
|
interface Props extends TooltipProps {}
|
||||||
forceShow?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MyTooltip = ({ children, forceShow = false, shouldWrapChildren = true, ...props }: Props) => {
|
const MyTooltip = ({ children, shouldWrapChildren = true, ...props }: Props) => {
|
||||||
const [isPc] = useMediaQuery('(min-width: 900px)');
|
const { isPc } = useSystem();
|
||||||
|
|
||||||
return isPc || forceShow ? (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
className="chakra-tooltip"
|
className="chakra-tooltip"
|
||||||
bg={'white'}
|
bg={'white'}
|
||||||
@@ -27,8 +26,6 @@ const MyTooltip = ({ children, forceShow = false, shouldWrapChildren = true, ...
|
|||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
|
||||||
<>{children}</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ const LightRowTabs = <ValueType = string,>({
|
|||||||
borderRadius={'sm'}
|
borderRadius={'sm'}
|
||||||
fontSize={sizeMap.fontSize}
|
fontSize={sizeMap.fontSize}
|
||||||
overflowX={'auto'}
|
overflowX={'auto'}
|
||||||
|
userSelect={'none'}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{list.map((item) => (
|
{list.map((item) => (
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ type Props = Omit<BoxProps, 'resize' | 'onChange'> & {
|
|||||||
variables?: EditorVariablePickerType[];
|
variables?: EditorVariablePickerType[];
|
||||||
defaultHeight?: number;
|
defaultHeight?: number;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
isDisabled?: boolean;
|
||||||
|
isInvalid?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
@@ -55,6 +57,8 @@ const JSONEditor = ({
|
|||||||
variables = [],
|
variables = [],
|
||||||
placeholder,
|
placeholder,
|
||||||
defaultHeight = 100,
|
defaultHeight = 100,
|
||||||
|
isDisabled = false,
|
||||||
|
isInvalid = false,
|
||||||
...props
|
...props
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@@ -209,9 +213,9 @@ const JSONEditor = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
borderWidth={'1px'}
|
borderWidth={isInvalid ? '2px' : '1px'}
|
||||||
borderRadius={'md'}
|
borderRadius={'md'}
|
||||||
borderColor={'myGray.200'}
|
borderColor={isInvalid ? 'red.500' : 'myGray.200'}
|
||||||
py={2}
|
py={2}
|
||||||
height={height}
|
height={height}
|
||||||
position={'relative'}
|
position={'relative'}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
"Export Configs": "Export Configs",
|
"Export Configs": "Export Configs",
|
||||||
"Feedback Count": "User Feedback",
|
"Feedback Count": "User Feedback",
|
||||||
"Go to chat": "To chat",
|
"Go to chat": "To chat",
|
||||||
|
"Go to run": "Run",
|
||||||
"Import Configs": "Import Configs",
|
"Import Configs": "Import Configs",
|
||||||
"Import Configs Failed": "Failed to import configs, please ensure configs are valid!",
|
"Import Configs Failed": "Failed to import configs, please ensure configs are valid!",
|
||||||
"Input Field Settings": "Input Field Settings",
|
"Input Field Settings": "Input Field Settings",
|
||||||
@@ -39,8 +40,12 @@
|
|||||||
"My Apps": "My Apps",
|
"My Apps": "My Apps",
|
||||||
"Output Field Settings": "Output Field Settings",
|
"Output Field Settings": "Output Field Settings",
|
||||||
"Paste Config": "Paste Config",
|
"Paste Config": "Paste Config",
|
||||||
|
"Plugin dispatch": "Plugins",
|
||||||
|
"Plugin dispatch tip": "It is up to the model to decide which plug-ins to add additional capabilities to. If the plug-in is selected, the knowledge base call is also treated as a special plug-in.",
|
||||||
"Publish channel": "Publish channel",
|
"Publish channel": "Publish channel",
|
||||||
"Publish success": "Publish success",
|
"Publish success": "Publish success",
|
||||||
|
"Run": "Run",
|
||||||
|
"Search app": "Search app",
|
||||||
"Setting app": "Settings",
|
"Setting app": "Settings",
|
||||||
"Setting plugin": "Setting plugin",
|
"Setting plugin": "Setting plugin",
|
||||||
"To Chat": "Go to Chat",
|
"To Chat": "Go to Chat",
|
||||||
@@ -57,7 +62,7 @@
|
|||||||
},
|
},
|
||||||
"module": {
|
"module": {
|
||||||
"Combine Modules": "Combine Modules",
|
"Combine Modules": "Combine Modules",
|
||||||
"Confirm Sync": "Using the latest template will overwrite the existing one and may result in the loss of some previous configuration information. Please confirm.",
|
"Confirm Sync": "The template will be updated to the latest template configuration. Fields that do not exist in the template will be deleted (including all custom fields). You are advised to make a copy of the node and then update the original node version.",
|
||||||
"Custom Title Tip": "This title will be displayed during the conversation",
|
"Custom Title Tip": "This title will be displayed during the conversation",
|
||||||
"My Modules": "My Modules",
|
"My Modules": "My Modules",
|
||||||
"No Modules": "No plugins yet~",
|
"No Modules": "No plugins yet~",
|
||||||
|
|||||||
@@ -107,8 +107,10 @@
|
|||||||
"Rename Success": "Rename Success",
|
"Rename Success": "Rename Success",
|
||||||
"Request Error": "Request Error",
|
"Request Error": "Request Error",
|
||||||
"Require Input": "Required Input",
|
"Require Input": "Required Input",
|
||||||
|
"Restart": "Restart",
|
||||||
"Role": "Role",
|
"Role": "Role",
|
||||||
"Root folder": "Root folder",
|
"Root folder": "Root folder",
|
||||||
|
"Run": "Run",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save Failed": "Save Failed",
|
"Save Failed": "Save Failed",
|
||||||
"Save Success": "Save Success",
|
"Save Success": "Save Success",
|
||||||
@@ -595,8 +597,7 @@
|
|||||||
"success": "Start syncing"
|
"success": "Start syncing"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"training": {
|
"training": {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"Auxiliary Data": "Auxiliary data",
|
"Auxiliary Data": "Auxiliary data",
|
||||||
@@ -1068,7 +1069,7 @@
|
|||||||
"Debug": "Debug",
|
"Debug": "Debug",
|
||||||
"Debug Node": "Debug mode",
|
"Debug Node": "Debug mode",
|
||||||
"Failed": "Execution failed",
|
"Failed": "Execution failed",
|
||||||
"Not intro": "This node has no introduction~\\",
|
"Not intro": "This node has no introduction~",
|
||||||
"Run from here": "Run from here",
|
"Run from here": "Run from here",
|
||||||
"Run result": "Run result",
|
"Run result": "Run result",
|
||||||
"Running": "Running",
|
"Running": "Running",
|
||||||
@@ -1371,7 +1372,7 @@
|
|||||||
"Terms": "Terms of service",
|
"Terms": "Terms of service",
|
||||||
"Username": "Username",
|
"Username": "Username",
|
||||||
"Wechat": "Login with Wechat",
|
"Wechat": "Login with Wechat",
|
||||||
"Wx qr login": "Wechat QR code login"
|
"wx_qr_login": "Wechat QR code login"
|
||||||
},
|
},
|
||||||
"team": {
|
"team": {
|
||||||
"Dataset usage": "Knowledge base capacity",
|
"Dataset usage": "Knowledge base capacity",
|
||||||
@@ -1636,4 +1637,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"Tool input": "Tool",
|
"Tool input": "Tool",
|
||||||
"code": {
|
"code": {
|
||||||
"Reset template": "Reset template",
|
"Reset template": "Reset template",
|
||||||
"Reset template confirm": "Are you sure to restore the code template? Be careful to save the current code."
|
"Reset template confirm": "Are you sure to restore the code template? All input and output to template values will be reset, please be careful to save the current code."
|
||||||
},
|
},
|
||||||
"ifelse": {
|
"ifelse": {
|
||||||
"Input value": "Input",
|
"Input value": "Input",
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
"Export Configs": "导出配置",
|
"Export Configs": "导出配置",
|
||||||
"Feedback Count": "用户反馈",
|
"Feedback Count": "用户反馈",
|
||||||
"Go to chat": "去对话",
|
"Go to chat": "去对话",
|
||||||
|
"Go to run": "去运行",
|
||||||
"Import Configs": "导入配置",
|
"Import Configs": "导入配置",
|
||||||
"Import Configs Failed": "导入配置失败,请确保配置正常!",
|
"Import Configs Failed": "导入配置失败,请确保配置正常!",
|
||||||
"Input Field Settings": "输入字段编辑",
|
"Input Field Settings": "输入字段编辑",
|
||||||
@@ -38,8 +39,12 @@
|
|||||||
"My Apps": "我的应用",
|
"My Apps": "我的应用",
|
||||||
"Output Field Settings": "输出字段编辑",
|
"Output Field Settings": "输出字段编辑",
|
||||||
"Paste Config": "粘贴配置",
|
"Paste Config": "粘贴配置",
|
||||||
|
"Plugin dispatch": "插件调用",
|
||||||
|
"Plugin dispatch tip": "给模型附加额外的能力,具体调用哪些插件,将由模型自主决定。\n若选择了插件,知识库调用将自动作为一个特殊的插件。",
|
||||||
"Publish channel": "发布渠道",
|
"Publish channel": "发布渠道",
|
||||||
"Publish success": "发布成功",
|
"Publish success": "发布成功",
|
||||||
|
"Run": "运行",
|
||||||
|
"Search app": "搜索应用",
|
||||||
"Setting app": "应用配置",
|
"Setting app": "应用配置",
|
||||||
"Setting plugin": "插件配置",
|
"Setting plugin": "插件配置",
|
||||||
"To Chat": "前去对话",
|
"To Chat": "前去对话",
|
||||||
@@ -56,7 +61,7 @@
|
|||||||
},
|
},
|
||||||
"module": {
|
"module": {
|
||||||
"Combine Modules": "组合模块",
|
"Combine Modules": "组合模块",
|
||||||
"Confirm Sync": "将会使用最新模板进行覆盖,可能会丢失一些旧的配置信息,请确认",
|
"Confirm Sync": "将会更新至最新的模板配置,不存在模板中的字段将会被删除(包括所有自定义字段),建议您先复制一份节点,再更新原来节点的版本。",
|
||||||
"Custom Title Tip": "该标题名字会展示在对话过程中",
|
"Custom Title Tip": "该标题名字会展示在对话过程中",
|
||||||
"My Modules": "",
|
"My Modules": "",
|
||||||
"No Modules": "没找到插件",
|
"No Modules": "没找到插件",
|
||||||
|
|||||||
@@ -108,8 +108,10 @@
|
|||||||
"Rename Success": "重命名成功",
|
"Rename Success": "重命名成功",
|
||||||
"Request Error": "请求异常",
|
"Request Error": "请求异常",
|
||||||
"Require Input": "必填",
|
"Require Input": "必填",
|
||||||
|
"Restart": "重新开始",
|
||||||
"Role": "权限",
|
"Role": "权限",
|
||||||
"Root folder": "根目录",
|
"Root folder": "根目录",
|
||||||
|
"Run": "运行",
|
||||||
"Save": "保存",
|
"Save": "保存",
|
||||||
"Save Failed": "保存失败",
|
"Save Failed": "保存失败",
|
||||||
"Save Success": "保存成功",
|
"Save Success": "保存成功",
|
||||||
@@ -598,8 +600,7 @@
|
|||||||
"success": "开始同步"
|
"success": "开始同步"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"training": {
|
"training": {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"Auxiliary Data": "辅助数据",
|
"Auxiliary Data": "辅助数据",
|
||||||
@@ -1077,7 +1078,7 @@
|
|||||||
"Debug": "调试",
|
"Debug": "调试",
|
||||||
"Debug Node": "Debug 模式",
|
"Debug Node": "Debug 模式",
|
||||||
"Failed": "运行失败",
|
"Failed": "运行失败",
|
||||||
"Not intro": "这个节点没有介绍~\\",
|
"Not intro": "这个节点没有介绍~",
|
||||||
"Run from here": "从这里开始运行",
|
"Run from here": "从这里开始运行",
|
||||||
"Run result": "",
|
"Run result": "",
|
||||||
"Running": "运行中",
|
"Running": "运行中",
|
||||||
@@ -1380,7 +1381,7 @@
|
|||||||
"Terms": "服务协议",
|
"Terms": "服务协议",
|
||||||
"Username": "用户名",
|
"Username": "用户名",
|
||||||
"Wechat": "微信登录",
|
"Wechat": "微信登录",
|
||||||
"Wx qr login": "微信扫码登录"
|
"wx_qr_login": "微信扫码登录"
|
||||||
},
|
},
|
||||||
"team": {
|
"team": {
|
||||||
"Dataset usage": "知识库容量",
|
"Dataset usage": "知识库容量",
|
||||||
@@ -1645,4 +1646,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"Tool input": "工具参数",
|
"Tool input": "工具参数",
|
||||||
"code": {
|
"code": {
|
||||||
"Reset template": "还原模板",
|
"Reset template": "还原模板",
|
||||||
"Reset template confirm": "确认还原代码模板?请注意保存当前代码。"
|
"Reset template confirm": "确认还原代码模板?将会重置所有输入和输出至模板值,请注意保存当前代码。"
|
||||||
},
|
},
|
||||||
"ifelse": {
|
"ifelse": {
|
||||||
"Input value": "输入值",
|
"Input value": "输入值",
|
||||||
|
|||||||
@@ -21,25 +21,25 @@
|
|||||||
"ahooks": "^3.7.11",
|
"ahooks": "^3.7.11",
|
||||||
"date-fns": "2.30.0",
|
"date-fns": "2.30.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"i18next": "23.10.0",
|
|
||||||
"lexical": "0.12.6",
|
"lexical": "0.12.6",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"next-i18next": "15.2.0",
|
"i18next": "23.11.5",
|
||||||
|
"next-i18next": "15.3.0",
|
||||||
|
"react-i18next": "14.1.2",
|
||||||
"papaparse": "^5.4.1",
|
"papaparse": "^5.4.1",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
"react-day-picker": "^8.7.1",
|
"react-day-picker": "^8.7.1",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-hook-form": "7.43.1",
|
"react-hook-form": "7.43.1",
|
||||||
"react-i18next": "13.5.0",
|
|
||||||
"react-photo-view": "^1.2.6",
|
"react-photo-view": "^1.2.6",
|
||||||
"use-context-selector": "^1.4.4"
|
"use-context-selector": "^1.4.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash": "^4.14.191",
|
"@types/lodash": "^4.14.191",
|
||||||
"@types/papaparse": "^5.3.7",
|
"@types/papaparse": "^5.3.7",
|
||||||
"@types/react": "18.3.0",
|
"@types/react": "18.3.1",
|
||||||
"@types/react-beautiful-dnd": "^13.1.8",
|
"@types/react-beautiful-dnd": "^13.1.1",
|
||||||
"@types/react-dom": "18.3.0"
|
"@types/react-dom": "18.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,7 +314,7 @@ const Input: ComponentStyleConfig = {
|
|||||||
}),
|
}),
|
||||||
md: defineStyle({
|
md: defineStyle({
|
||||||
field: {
|
field: {
|
||||||
h: '40px',
|
h: '34px',
|
||||||
borderRadius: 'md'
|
borderRadius: 'md'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
4865
pnpm-lock.yaml
generated
4865
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@ MONGODB_URI=mongodb://username:password@0.0.0.0:27017/fastgpt?authSource=admin
|
|||||||
# 向量库优先级: pg > milvus
|
# 向量库优先级: pg > milvus
|
||||||
# PG 向量库连接参数
|
# PG 向量库连接参数
|
||||||
PG_URL=postgresql://username:password@host:port/postgres
|
PG_URL=postgresql://username:password@host:port/postgres
|
||||||
# mivlus 向量库连接参数
|
# milvus 向量库连接参数
|
||||||
MILVUS_ADDRESS=https://in03-78bd7f60e6e2a7c.api.gcp-us-west1.zillizcloud.com
|
MILVUS_ADDRESS=https://in03-78bd7f60e6e2a7c.api.gcp-us-west1.zillizcloud.com
|
||||||
MILVUS_TOKEN=133964348b00b4b4e4b51bef680a61350950385c8c64a3ec16b1ab92d3c67dcc4e0370fb9dd15791bcd6dadaf765e98a98735d0d
|
MILVUS_TOKEN=133964348b00b4b4e4b51bef680a61350950385c8c64a3ec16b1ab92d3c67dcc4e0370fb9dd15791bcd6dadaf765e98a98735d0d
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# --------- install dependence -----------
|
# --------- install dependence -----------
|
||||||
FROM node:18.17-alpine AS mainDeps
|
FROM node:20.14.0-alpine AS mainDeps
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ARG proxy
|
ARG proxy
|
||||||
|
|
||||||
RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
|
RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
|
||||||
RUN apk add --no-cache libc6-compat && npm install -g pnpm@8.6.0
|
RUN apk add --no-cache libc6-compat && npm install -g pnpm@9.4.0
|
||||||
# if proxy exists, set proxy
|
# if proxy exists, set proxy
|
||||||
RUN [ -z "$proxy" ] || pnpm config set registry https://registry.npmmirror.com
|
RUN [ -z "$proxy" ] || pnpm config set registry https://registry.npmmirror.com
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ RUN [ -f pnpm-lock.yaml ] || (echo "Lockfile not found." && exit 1)
|
|||||||
RUN pnpm i
|
RUN pnpm i
|
||||||
|
|
||||||
# --------- builder -----------
|
# --------- builder -----------
|
||||||
FROM node:18.17-alpine AS builder
|
FROM node:20.14.0-alpine AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ARG proxy
|
ARG proxy
|
||||||
@@ -33,13 +33,13 @@ COPY --from=mainDeps /app/projects/app/node_modules ./projects/app/node_modules
|
|||||||
|
|
||||||
RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
|
RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
|
||||||
|
|
||||||
RUN apk add --no-cache libc6-compat && npm install -g pnpm@8.6.0
|
RUN apk add --no-cache libc6-compat && npm install -g pnpm@9.4.0
|
||||||
|
|
||||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||||
RUN pnpm --filter=app build
|
RUN pnpm --filter=app build
|
||||||
|
|
||||||
# --------- runner -----------
|
# --------- runner -----------
|
||||||
FROM node:18.17-alpine AS runner
|
FROM node:20.14.0-alpine AS runner
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ARG proxy
|
ARG proxy
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ module.exports = {
|
|||||||
localePath:
|
localePath:
|
||||||
typeof window === 'undefined' ? require('path').resolve('../../packages/web/i18n') : '/i18n',
|
typeof window === 'undefined' ? require('path').resolve('../../packages/web/i18n') : '/i18n',
|
||||||
reloadOnPrerender: process.env.NODE_ENV === 'development'
|
reloadOnPrerender: process.env.NODE_ENV === 'development'
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "app",
|
"name": "app",
|
||||||
"version": "4.8.6",
|
"version": "4.8.7",
|
||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
@@ -35,23 +35,23 @@
|
|||||||
"formidable": "^2.1.1",
|
"formidable": "^2.1.1",
|
||||||
"framer-motion": "^9.0.6",
|
"framer-motion": "^9.0.6",
|
||||||
"hyperdown": "^2.4.29",
|
"hyperdown": "^2.4.29",
|
||||||
"i18next": "23.10.0",
|
|
||||||
"immer": "^9.0.19",
|
"immer": "^9.0.19",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mermaid": "^10.2.3",
|
"mermaid": "^10.2.3",
|
||||||
"nanoid": "^4.0.1",
|
"nanoid": "^4.0.1",
|
||||||
"next": "14.2.3",
|
"next": "14.2.5",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"next-i18next": "15.2.0",
|
|
||||||
"nextjs-node-loader": "^1.1.5",
|
"nextjs-node-loader": "^1.1.5",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-day-picker": "^8.7.1",
|
"react-day-picker": "^8.7.1",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-hook-form": "7.43.1",
|
"react-hook-form": "7.43.1",
|
||||||
"react-i18next": "13.5.0",
|
"i18next": "23.11.5",
|
||||||
|
"next-i18next": "15.3.0",
|
||||||
|
"react-i18next": "14.1.2",
|
||||||
"react-markdown": "^8.0.7",
|
"react-markdown": "^8.0.7",
|
||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"reactflow": "^11.7.4",
|
"reactflow": "^11.7.4",
|
||||||
@@ -72,13 +72,13 @@
|
|||||||
"@types/jsonwebtoken": "^9.0.3",
|
"@types/jsonwebtoken": "^9.0.3",
|
||||||
"@types/lodash": "^4.14.191",
|
"@types/lodash": "^4.14.191",
|
||||||
"@types/node": "^20.14.2",
|
"@types/node": "^20.14.2",
|
||||||
"@types/react": "18.3.0",
|
"@types/react": "18.3.1",
|
||||||
"@types/react-dom": "18.3.0",
|
"@types/react-dom": "18.3.0",
|
||||||
"@types/react-syntax-highlighter": "^15.5.6",
|
"@types/react-syntax-highlighter": "^15.5.6",
|
||||||
"@types/request-ip": "^0.0.37",
|
"@types/request-ip": "^0.0.37",
|
||||||
"eslint": "8.56.0",
|
"eslint": "8.56.0",
|
||||||
"eslint-config-next": "14.2.3",
|
"eslint-config-next": "14.2.3",
|
||||||
"nextjs-node-loader": "^1.1.5",
|
"nextjs-node-loader": "^1.1.5",
|
||||||
"typescript": "4.9.5"
|
"typescript": "^5.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,262 +0,0 @@
|
|||||||
import {
|
|
||||||
Box,
|
|
||||||
BoxProps,
|
|
||||||
Card,
|
|
||||||
Flex,
|
|
||||||
useTheme,
|
|
||||||
Accordion,
|
|
||||||
AccordionItem,
|
|
||||||
AccordionButton,
|
|
||||||
AccordionPanel,
|
|
||||||
AccordionIcon,
|
|
||||||
Image
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import React, { useMemo } from 'react';
|
|
||||||
import ChatController, { type ChatControllerProps } from './ChatController';
|
|
||||||
import ChatAvatar from './ChatAvatar';
|
|
||||||
import { MessageCardStyle } from '../constants';
|
|
||||||
import { formatChatValue2InputType } from '../utils';
|
|
||||||
import Markdown, { CodeClassName } from '@/components/Markdown';
|
|
||||||
import styles from '../index.module.scss';
|
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
|
||||||
import {
|
|
||||||
ChatItemValueTypeEnum,
|
|
||||||
ChatRoleEnum,
|
|
||||||
ChatStatusEnum
|
|
||||||
} from '@fastgpt/global/core/chat/constants';
|
|
||||||
import FilesBlock from './FilesBox';
|
|
||||||
import { ChatBoxContext } from '../Provider';
|
|
||||||
import Avatar from '@/components/Avatar';
|
|
||||||
import { useContextSelector } from 'use-context-selector';
|
|
||||||
|
|
||||||
const colorMap = {
|
|
||||||
[ChatStatusEnum.loading]: {
|
|
||||||
bg: 'myGray.100',
|
|
||||||
color: 'myGray.600'
|
|
||||||
},
|
|
||||||
[ChatStatusEnum.running]: {
|
|
||||||
bg: 'green.50',
|
|
||||||
color: 'green.700'
|
|
||||||
},
|
|
||||||
[ChatStatusEnum.finish]: {
|
|
||||||
bg: 'green.50',
|
|
||||||
color: 'green.700'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ChatItem = ({
|
|
||||||
type,
|
|
||||||
avatar,
|
|
||||||
statusBoxData,
|
|
||||||
children,
|
|
||||||
isLastChild,
|
|
||||||
questionGuides = [],
|
|
||||||
...chatControllerProps
|
|
||||||
}: {
|
|
||||||
type: ChatRoleEnum.Human | ChatRoleEnum.AI;
|
|
||||||
avatar?: string;
|
|
||||||
statusBoxData?: {
|
|
||||||
status: `${ChatStatusEnum}`;
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
questionGuides?: string[];
|
|
||||||
children?: React.ReactNode;
|
|
||||||
} & ChatControllerProps) => {
|
|
||||||
const styleMap: BoxProps =
|
|
||||||
type === ChatRoleEnum.Human
|
|
||||||
? {
|
|
||||||
order: 0,
|
|
||||||
borderRadius: '8px 0 8px 8px',
|
|
||||||
justifyContent: 'flex-end',
|
|
||||||
textAlign: 'right',
|
|
||||||
bg: 'primary.100'
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
order: 1,
|
|
||||||
borderRadius: '0 8px 8px 8px',
|
|
||||||
justifyContent: 'flex-start',
|
|
||||||
textAlign: 'left',
|
|
||||||
bg: 'myGray.50'
|
|
||||||
};
|
|
||||||
|
|
||||||
const isChatting = useContextSelector(ChatBoxContext, (v) => v.isChatting);
|
|
||||||
const { chat } = chatControllerProps;
|
|
||||||
|
|
||||||
const ContentCard = useMemo(() => {
|
|
||||||
if (type === 'Human') {
|
|
||||||
const { text, files = [] } = formatChatValue2InputType(chat.value);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{files.length > 0 && <FilesBlock files={files} />}
|
|
||||||
<Markdown source={text} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* AI */
|
|
||||||
return (
|
|
||||||
<Flex flexDirection={'column'} key={chat.dataId} gap={2}>
|
|
||||||
{chat.value.map((value, i) => {
|
|
||||||
const key = `${chat.dataId}-ai-${i}`;
|
|
||||||
|
|
||||||
if (value.text) {
|
|
||||||
let source = (value.text?.content || '').trim();
|
|
||||||
|
|
||||||
if (!source && chat.value.length > 1) return null;
|
|
||||||
|
|
||||||
if (
|
|
||||||
isLastChild &&
|
|
||||||
!isChatting &&
|
|
||||||
questionGuides.length > 0 &&
|
|
||||||
i === chat.value.length - 1
|
|
||||||
) {
|
|
||||||
source = `${source}
|
|
||||||
\`\`\`${CodeClassName.questionGuide}
|
|
||||||
${JSON.stringify(questionGuides)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Markdown
|
|
||||||
key={key}
|
|
||||||
source={source}
|
|
||||||
showAnimation={isLastChild && isChatting && i === chat.value.length - 1}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (value.type === ChatItemValueTypeEnum.tool && value.tools) {
|
|
||||||
return (
|
|
||||||
<Box key={key}>
|
|
||||||
{value.tools.map((tool) => {
|
|
||||||
const toolParams = (() => {
|
|
||||||
try {
|
|
||||||
return JSON.stringify(JSON.parse(tool.params), null, 2);
|
|
||||||
} catch (error) {
|
|
||||||
return tool.params;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
const toolResponse = (() => {
|
|
||||||
try {
|
|
||||||
return JSON.stringify(JSON.parse(tool.response), null, 2);
|
|
||||||
} catch (error) {
|
|
||||||
return tool.response;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box key={tool.id}>
|
|
||||||
<Accordion allowToggle>
|
|
||||||
<AccordionItem borderTop={'none'} borderBottom={'none'}>
|
|
||||||
<AccordionButton
|
|
||||||
w={'auto'}
|
|
||||||
bg={'white'}
|
|
||||||
borderRadius={'md'}
|
|
||||||
borderWidth={'1px'}
|
|
||||||
borderColor={'myGray.200'}
|
|
||||||
boxShadow={'1'}
|
|
||||||
_hover={{
|
|
||||||
bg: 'auto'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Avatar src={tool.toolAvatar} w={'1rem'} mr={2} />
|
|
||||||
<Box mr={1} fontSize={'sm'}>
|
|
||||||
{tool.toolName}
|
|
||||||
</Box>
|
|
||||||
{isChatting && !tool.response && (
|
|
||||||
<MyIcon name={'common/loading'} w={'14px'} />
|
|
||||||
)}
|
|
||||||
<AccordionIcon color={'myGray.600'} ml={5} />
|
|
||||||
</AccordionButton>
|
|
||||||
<AccordionPanel
|
|
||||||
py={0}
|
|
||||||
px={0}
|
|
||||||
mt={0}
|
|
||||||
borderRadius={'md'}
|
|
||||||
overflow={'hidden'}
|
|
||||||
maxH={'500px'}
|
|
||||||
overflowY={'auto'}
|
|
||||||
>
|
|
||||||
{toolParams && toolParams !== '{}' && (
|
|
||||||
<Markdown
|
|
||||||
source={`~~~json#Input
|
|
||||||
${toolParams}`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{toolResponse && (
|
|
||||||
<Markdown
|
|
||||||
source={`~~~json#Response
|
|
||||||
${toolResponse}`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</AccordionPanel>
|
|
||||||
</AccordionItem>
|
|
||||||
</Accordion>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}, [chat.dataId, chat.value, isChatting, isLastChild, questionGuides, type]);
|
|
||||||
|
|
||||||
const chatStatusMap = useMemo(() => {
|
|
||||||
if (!statusBoxData?.status) return;
|
|
||||||
return colorMap[statusBoxData.status];
|
|
||||||
}, [statusBoxData?.status]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/* control icon */}
|
|
||||||
<Flex w={'100%'} alignItems={'center'} gap={2} justifyContent={styleMap.justifyContent}>
|
|
||||||
{isChatting && type === ChatRoleEnum.AI && isLastChild ? null : (
|
|
||||||
<Box order={styleMap.order} ml={styleMap.ml}>
|
|
||||||
<ChatController {...chatControllerProps} isLastChild={isLastChild} />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<ChatAvatar src={avatar} type={type} />
|
|
||||||
|
|
||||||
{!!chatStatusMap && statusBoxData && isLastChild && (
|
|
||||||
<Flex
|
|
||||||
alignItems={'center'}
|
|
||||||
px={3}
|
|
||||||
py={'1.5px'}
|
|
||||||
borderRadius="md"
|
|
||||||
bg={chatStatusMap.bg}
|
|
||||||
fontSize={'sm'}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
className={styles.statusAnimation}
|
|
||||||
bg={chatStatusMap.color}
|
|
||||||
w="8px"
|
|
||||||
h="8px"
|
|
||||||
borderRadius={'50%'}
|
|
||||||
mt={'1px'}
|
|
||||||
/>
|
|
||||||
<Box ml={2} color={'myGray.600'}>
|
|
||||||
{statusBoxData.name}
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
{/* content */}
|
|
||||||
<Box mt={['6px', 2]} textAlign={styleMap.textAlign}>
|
|
||||||
<Card
|
|
||||||
className="markdown"
|
|
||||||
{...MessageCardStyle}
|
|
||||||
bg={styleMap.bg}
|
|
||||||
borderRadius={styleMap.borderRadius}
|
|
||||||
textAlign={'left'}
|
|
||||||
>
|
|
||||||
{ContentCard}
|
|
||||||
{children}
|
|
||||||
</Card>
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(ChatItem);
|
|
||||||
@@ -1,325 +0,0 @@
|
|||||||
import React, { useMemo, useState } from 'react';
|
|
||||||
import { Box, useTheme, Flex, Image, BoxProps } from '@chakra-ui/react';
|
|
||||||
import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
|
||||||
import { moduleTemplatesFlat } from '@fastgpt/global/core/workflow/template/constants';
|
|
||||||
|
|
||||||
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
|
|
||||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
|
||||||
import Markdown from '../../Markdown';
|
|
||||||
import { QuoteList } from './QuoteModal';
|
|
||||||
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
|
|
||||||
import { formatNumber } from '@fastgpt/global/common/math/tools';
|
|
||||||
import { useI18n } from '@/web/context/I18n';
|
|
||||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
|
||||||
|
|
||||||
function RowRender({
|
|
||||||
children,
|
|
||||||
mb,
|
|
||||||
label,
|
|
||||||
...props
|
|
||||||
}: { children: React.ReactNode; label: string } & BoxProps) {
|
|
||||||
return (
|
|
||||||
<Box mb={3}>
|
|
||||||
<Box fontSize={'sm'} mb={mb} flex={'0 0 90px'}>
|
|
||||||
{label}:
|
|
||||||
</Box>
|
|
||||||
<Box borderRadius={'sm'} fontSize={['xs', 'sm']} bg={'myGray.50'} {...props}>
|
|
||||||
{children}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function Row({
|
|
||||||
label,
|
|
||||||
value,
|
|
||||||
rawDom
|
|
||||||
}: {
|
|
||||||
label: string;
|
|
||||||
value?: string | number | boolean | object;
|
|
||||||
rawDom?: React.ReactNode;
|
|
||||||
}) {
|
|
||||||
const theme = useTheme();
|
|
||||||
const val = value || rawDom;
|
|
||||||
const isObject = typeof value === 'object';
|
|
||||||
|
|
||||||
const formatValue = useMemo(() => {
|
|
||||||
if (isObject) {
|
|
||||||
return `~~~json\n${JSON.stringify(value, null, 2)}`;
|
|
||||||
}
|
|
||||||
return `${value}`;
|
|
||||||
}, [isObject, value]);
|
|
||||||
|
|
||||||
if (rawDom) {
|
|
||||||
return (
|
|
||||||
<RowRender label={label} mb={1}>
|
|
||||||
{rawDom}
|
|
||||||
</RowRender>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val === undefined || val === '' || val === 'undefined') return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RowRender
|
|
||||||
label={label}
|
|
||||||
mb={isObject ? 0 : 1}
|
|
||||||
{...(isObject
|
|
||||||
? { transform: 'translateY(-3px)' }
|
|
||||||
: value
|
|
||||||
? { px: 3, py: 2, border: theme.borders.base }
|
|
||||||
: {})}
|
|
||||||
>
|
|
||||||
<Markdown source={formatValue} />
|
|
||||||
</RowRender>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const WholeResponseModal = ({
|
|
||||||
response,
|
|
||||||
showDetail,
|
|
||||||
onClose
|
|
||||||
}: {
|
|
||||||
response: ChatHistoryItemResType[];
|
|
||||||
showDetail: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MyModal
|
|
||||||
isCentered
|
|
||||||
isOpen={true}
|
|
||||||
onClose={onClose}
|
|
||||||
h={['90vh', '80vh']}
|
|
||||||
minW={['90vw', '600px']}
|
|
||||||
iconSrc="/imgs/modal/wholeRecord.svg"
|
|
||||||
title={
|
|
||||||
<Flex alignItems={'center'}>
|
|
||||||
{t('core.chat.response.Complete Response')}
|
|
||||||
<QuestionTip ml={2} label={'从左往右,为各个模块的响应顺序'}></QuestionTip>
|
|
||||||
</Flex>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Flex h={'100%'} flexDirection={'column'}>
|
|
||||||
<ResponseBox response={response} showDetail={showDetail} />
|
|
||||||
</Flex>
|
|
||||||
</MyModal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default WholeResponseModal;
|
|
||||||
|
|
||||||
export const ResponseBox = React.memo(function ResponseBox({
|
|
||||||
response,
|
|
||||||
showDetail,
|
|
||||||
hideTabs = false
|
|
||||||
}: {
|
|
||||||
response: ChatHistoryItemResType[];
|
|
||||||
showDetail: boolean;
|
|
||||||
hideTabs?: boolean;
|
|
||||||
}) {
|
|
||||||
const theme = useTheme();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { workflowT } = useI18n();
|
|
||||||
|
|
||||||
const list = useMemo(
|
|
||||||
() =>
|
|
||||||
response.map((item, i) => ({
|
|
||||||
label: (
|
|
||||||
<Flex alignItems={'center'} justifyContent={'center'} px={2}>
|
|
||||||
<Image
|
|
||||||
mr={2}
|
|
||||||
src={
|
|
||||||
item.moduleLogo ||
|
|
||||||
moduleTemplatesFlat.find((template) => item.moduleType === template.flowNodeType)
|
|
||||||
?.avatar
|
|
||||||
}
|
|
||||||
alt={''}
|
|
||||||
w={['14px', '16px']}
|
|
||||||
/>
|
|
||||||
{t(item.moduleName)}
|
|
||||||
</Flex>
|
|
||||||
),
|
|
||||||
value: `${i}`
|
|
||||||
})),
|
|
||||||
[response, t]
|
|
||||||
);
|
|
||||||
|
|
||||||
const [currentTab, setCurrentTab] = useState(`0`);
|
|
||||||
|
|
||||||
const activeModule = useMemo(() => response[Number(currentTab)], [currentTab, response]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{!hideTabs && (
|
|
||||||
<Box>
|
|
||||||
<LightRowTabs list={list} value={currentTab} onChange={setCurrentTab} />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<Box py={2} px={4} flex={'1 0 0'} overflow={'auto'}>
|
|
||||||
<>
|
|
||||||
<Row label={t('core.chat.response.module name')} value={t(activeModule.moduleName)} />
|
|
||||||
{activeModule?.totalPoints !== undefined && (
|
|
||||||
<Row
|
|
||||||
label={t('support.wallet.usage.Total points')}
|
|
||||||
value={formatNumber(activeModule.totalPoints)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.module time')}
|
|
||||||
value={`${activeModule?.runningTime || 0}s`}
|
|
||||||
/>
|
|
||||||
<Row label={t('core.chat.response.module model')} value={activeModule?.model} />
|
|
||||||
<Row label={t('core.chat.response.module tokens')} value={`${activeModule?.tokens}`} />
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.Tool call tokens')}
|
|
||||||
value={`${activeModule?.toolCallTokens}`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Row label={t('core.chat.response.module query')} value={activeModule?.query} />
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.context total length')}
|
|
||||||
value={activeModule?.contextTotalLen}
|
|
||||||
/>
|
|
||||||
<Row label={workflowT('response.Error')} value={activeModule?.error} />
|
|
||||||
</>
|
|
||||||
|
|
||||||
{/* ai chat */}
|
|
||||||
<>
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.module temperature')}
|
|
||||||
value={activeModule?.temperature}
|
|
||||||
/>
|
|
||||||
<Row label={t('core.chat.response.module maxToken')} value={activeModule?.maxToken} />
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.module historyPreview')}
|
|
||||||
rawDom={
|
|
||||||
activeModule.historyPreview ? (
|
|
||||||
<Box px={3} py={2} border={theme.borders.base} borderRadius={'md'}>
|
|
||||||
{activeModule.historyPreview?.map((item, i) => (
|
|
||||||
<Box
|
|
||||||
key={i}
|
|
||||||
_notLast={{
|
|
||||||
borderBottom: '1px solid',
|
|
||||||
borderBottomColor: 'myWhite.700',
|
|
||||||
mb: 2
|
|
||||||
}}
|
|
||||||
pb={2}
|
|
||||||
>
|
|
||||||
<Box fontWeight={'bold'}>{item.obj}</Box>
|
|
||||||
<Box whiteSpace={'pre-wrap'}>{item.value}</Box>
|
|
||||||
</Box>
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
|
|
||||||
{/* dataset search */}
|
|
||||||
<>
|
|
||||||
{activeModule?.searchMode && (
|
|
||||||
<Row
|
|
||||||
label={t('core.dataset.search.search mode')}
|
|
||||||
// @ts-ignore
|
|
||||||
value={t(DatasetSearchModeMap[activeModule.searchMode]?.title)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Row label={t('core.chat.response.module similarity')} value={activeModule?.similarity} />
|
|
||||||
<Row label={t('core.chat.response.module limit')} value={activeModule?.limit} />
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.search using reRank')}
|
|
||||||
value={`${activeModule?.searchUsingReRank}`}
|
|
||||||
/>
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.Extension model')}
|
|
||||||
value={activeModule?.extensionModel}
|
|
||||||
/>
|
|
||||||
<Row
|
|
||||||
label={t('support.wallet.usage.Extension result')}
|
|
||||||
value={`${activeModule?.extensionResult}`}
|
|
||||||
/>
|
|
||||||
{activeModule.quoteList && activeModule.quoteList.length > 0 && (
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.module quoteList')}
|
|
||||||
rawDom={<QuoteList showDetail={showDetail} rawSearch={activeModule.quoteList} />}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
|
|
||||||
{/* classify question */}
|
|
||||||
<>
|
|
||||||
<Row label={t('core.chat.response.module cq result')} value={activeModule?.cqResult} />
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.module cq')}
|
|
||||||
value={(() => {
|
|
||||||
if (!activeModule?.cqList) return '';
|
|
||||||
return activeModule.cqList.map((item) => `* ${item.value}`).join('\n');
|
|
||||||
})()}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
|
|
||||||
{/* if-else */}
|
|
||||||
<>
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.module if else Result')}
|
|
||||||
value={activeModule?.ifElseResult}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
|
|
||||||
{/* extract */}
|
|
||||||
<>
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.module extract description')}
|
|
||||||
value={activeModule?.extractDescription}
|
|
||||||
/>
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.module extract result')}
|
|
||||||
value={activeModule?.extractResult}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
|
|
||||||
{/* http */}
|
|
||||||
<>
|
|
||||||
<Row label={'Headers'} value={activeModule?.headers} />
|
|
||||||
<Row label={'Params'} value={activeModule?.params} />
|
|
||||||
<Row label={'Body'} value={activeModule?.body} />
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.module http result')}
|
|
||||||
value={activeModule?.httpResult}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
|
|
||||||
{/* plugin */}
|
|
||||||
<>
|
|
||||||
<Row label={t('core.chat.response.plugin output')} value={activeModule?.pluginOutput} />
|
|
||||||
{activeModule?.pluginDetail && activeModule?.pluginDetail.length > 0 && (
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.Plugin response detail')}
|
|
||||||
rawDom={<ResponseBox response={activeModule.pluginDetail} showDetail={showDetail} />}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
|
|
||||||
{/* text output */}
|
|
||||||
<Row label={t('core.chat.response.text output')} value={activeModule?.textOutput} />
|
|
||||||
|
|
||||||
{/* tool call */}
|
|
||||||
{activeModule?.toolDetail && activeModule?.toolDetail.length > 0 && (
|
|
||||||
<Row
|
|
||||||
label={t('core.chat.response.Tool call response detail')}
|
|
||||||
rawDom={<ResponseBox response={activeModule.toolDetail} showDetail={showDetail} />}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* code */}
|
|
||||||
<Row label={workflowT('response.Custom outputs')} value={activeModule?.customOutputs} />
|
|
||||||
<Row label={workflowT('response.Custom inputs')} value={activeModule?.customInputs} />
|
|
||||||
<Row label={workflowT('response.Code log')} value={activeModule?.codeLog} />
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -10,7 +10,12 @@ const CommunityModal = ({ onClose }: { onClose: () => void }) => {
|
|||||||
const { feConfigs } = useSystemStore();
|
const { feConfigs } = useSystemStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MyModal isOpen={true} onClose={onClose} iconSrc="modal/concat" title={t('system.Concat us')}>
|
<MyModal
|
||||||
|
isOpen={true}
|
||||||
|
onClose={onClose}
|
||||||
|
iconSrc="modal/concat"
|
||||||
|
title={t('common:system.Concat us')}
|
||||||
|
>
|
||||||
<ModalBody textAlign={'center'}>
|
<ModalBody textAlign={'center'}>
|
||||||
<Markdown source={feConfigs?.concatMd || ''} />
|
<Markdown source={feConfigs?.concatMd || ''} />
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const Auth = ({ children }: { children: JSX.Element }) => {
|
|||||||
);
|
);
|
||||||
toast({
|
toast({
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
title: t('support.user.Need to login')
|
title: t('common:support.user.Need to login')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { getUnreadCount } from '@/web/support/user/inform/api';
|
|||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
|
|
||||||
import Auth from './auth';
|
import Auth from './auth';
|
||||||
|
import { useSystem } from '@fastgpt/web/hooks/useSystem';
|
||||||
const Navbar = dynamic(() => import('./navbar'));
|
const Navbar = dynamic(() => import('./navbar'));
|
||||||
const NavbarPhone = dynamic(() => import('./navbarPhone'));
|
const NavbarPhone = dynamic(() => import('./navbarPhone'));
|
||||||
const UpdateInviteModal = dynamic(() => import('@/components/support/user/team/UpdateInviteModal'));
|
const UpdateInviteModal = dynamic(() => import('@/components/support/user/team/UpdateInviteModal'));
|
||||||
@@ -43,7 +44,8 @@ const phoneUnShowLayoutRoute: Record<string, boolean> = {
|
|||||||
const Layout = ({ children }: { children: JSX.Element }) => {
|
const Layout = ({ children }: { children: JSX.Element }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { Loading } = useLoading();
|
const { Loading } = useLoading();
|
||||||
const { loading, setScreenWidth, isPc, feConfigs, isNotSufficientModal } = useSystemStore();
|
const { loading, feConfigs, isNotSufficientModal } = useSystemStore();
|
||||||
|
const { isPc } = useSystem();
|
||||||
const { userInfo } = useUserStore();
|
const { userInfo } = useUserStore();
|
||||||
|
|
||||||
const isChatPage = useMemo(
|
const isChatPage = useMemo(
|
||||||
@@ -51,21 +53,6 @@ const Layout = ({ children }: { children: JSX.Element }) => {
|
|||||||
[router.pathname, router.query]
|
[router.pathname, router.query]
|
||||||
);
|
);
|
||||||
|
|
||||||
// listen screen width
|
|
||||||
useEffect(() => {
|
|
||||||
const resize = throttle(() => {
|
|
||||||
setScreenWidth(document.documentElement.clientWidth);
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
window.addEventListener('resize', resize);
|
|
||||||
|
|
||||||
resize();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('resize', resize);
|
|
||||||
};
|
|
||||||
}, [setScreenWidth]);
|
|
||||||
|
|
||||||
const { data, refetch: refetchUnRead } = useQuery(['getUnreadCount'], getUnreadCount, {
|
const { data, refetch: refetchUnRead } = useQuery(['getUnreadCount'], getUnreadCount, {
|
||||||
enabled: !!userInfo && !!feConfigs.isPlus,
|
enabled: !!userInfo && !!feConfigs.isPlus,
|
||||||
refetchInterval: 10000
|
refetchInterval: 10000
|
||||||
|
|||||||
@@ -27,28 +27,28 @@ const Navbar = ({ unread }: { unread: number }) => {
|
|||||||
const navbarList = useMemo(
|
const navbarList = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
label: t('navbar.Chat'),
|
label: t('common:navbar.Chat'),
|
||||||
icon: 'core/chat/chatLight',
|
icon: 'core/chat/chatLight',
|
||||||
activeIcon: 'core/chat/chatFill',
|
activeIcon: 'core/chat/chatFill',
|
||||||
link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
|
link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
|
||||||
activeLink: ['/chat']
|
activeLink: ['/chat']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('navbar.Studio'),
|
label: t('common:navbar.Studio'),
|
||||||
icon: 'core/app/aiLight',
|
icon: 'core/app/aiLight',
|
||||||
activeIcon: 'core/app/aiFill',
|
activeIcon: 'core/app/aiFill',
|
||||||
link: `/app/list`,
|
link: `/app/list`,
|
||||||
activeLink: ['/app/list', '/app/detail']
|
activeLink: ['/app/list', '/app/detail']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('navbar.Datasets'),
|
label: t('common:navbar.Datasets'),
|
||||||
icon: 'core/dataset/datasetLight',
|
icon: 'core/dataset/datasetLight',
|
||||||
activeIcon: 'core/dataset/datasetFill',
|
activeIcon: 'core/dataset/datasetFill',
|
||||||
link: `/dataset/list`,
|
link: `/dataset/list`,
|
||||||
activeLink: ['/dataset/list', '/dataset/detail']
|
activeLink: ['/dataset/list', '/dataset/detail']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('navbar.Account'),
|
label: t('common:navbar.Account'),
|
||||||
icon: 'support/user/userLight',
|
icon: 'support/user/userLight',
|
||||||
activeIcon: 'support/user/userFill',
|
activeIcon: 'support/user/userFill',
|
||||||
link: '/account',
|
link: '/account',
|
||||||
@@ -163,7 +163,7 @@ const Navbar = ({ unread }: { unread: number }) => {
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{(feConfigs?.docUrl || feConfigs?.chatbotUrl) && (
|
{(feConfigs?.docUrl || feConfigs?.chatbotUrl) && (
|
||||||
<MyTooltip label={t('common.system.Use Helper')} placement={'right-end'}>
|
<MyTooltip label={t('common:common.system.Use Helper')} placement={'right-end'}>
|
||||||
<Link
|
<Link
|
||||||
{...itemStyles}
|
{...itemStyles}
|
||||||
{...hoverStyle}
|
{...hoverStyle}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
|
|||||||
const navbarList = useMemo(
|
const navbarList = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
label: t('navbar.Chat'),
|
label: t('common:navbar.Chat'),
|
||||||
icon: 'core/chat/chatLight',
|
icon: 'core/chat/chatLight',
|
||||||
activeIcon: 'core/chat/chatFill',
|
activeIcon: 'core/chat/chatFill',
|
||||||
link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
|
link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
|
||||||
@@ -21,7 +21,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
|
|||||||
unread: 0
|
unread: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('navbar.Studio'),
|
label: t('common:navbar.Studio'),
|
||||||
icon: 'core/app/aiLight',
|
icon: 'core/app/aiLight',
|
||||||
activeIcon: 'core/app/aiFill',
|
activeIcon: 'core/app/aiFill',
|
||||||
link: `/app/list`,
|
link: `/app/list`,
|
||||||
@@ -29,7 +29,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
|
|||||||
unread: 0
|
unread: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('navbar.Tools'),
|
label: t('common:navbar.Tools'),
|
||||||
icon: 'phoneTabbar/tool',
|
icon: 'phoneTabbar/tool',
|
||||||
activeIcon: 'phoneTabbar/toolFill',
|
activeIcon: 'phoneTabbar/toolFill',
|
||||||
link: '/tools',
|
link: '/tools',
|
||||||
@@ -37,7 +37,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
|
|||||||
unread: 0
|
unread: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('navbar.Account'),
|
label: t('common:navbar.Account'),
|
||||||
icon: 'support/user/userLight',
|
icon: 'support/user/userLight',
|
||||||
activeIcon: 'support/user/userFill',
|
activeIcon: 'support/user/userFill',
|
||||||
link: '/account',
|
link: '/account',
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ const CodeLight = ({
|
|||||||
<Box flex={1}>{codeBoxName}</Box>
|
<Box flex={1}>{codeBoxName}</Box>
|
||||||
<Flex cursor={'pointer'} onClick={() => copyData(String(children))} alignItems={'center'}>
|
<Flex cursor={'pointer'} onClick={() => copyData(String(children))} alignItems={'center'}>
|
||||||
<Icon name={'copy'} width={15} height={15}></Icon>
|
<Icon name={'copy'} width={15} height={15}></Icon>
|
||||||
<Box ml={1}>{t('common.Copy')}</Box>
|
<Box ml={1}>{t('common:common.Copy')}</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<SyntaxHighlighter style={codeLight as any} language={match?.[1]} PreTag="pre">
|
<SyntaxHighlighter style={codeLight as any} language={match?.[1]} PreTag="pre">
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const QuestionGuide = ({ text }: { text: string }) => {
|
|||||||
|
|
||||||
return questionGuides.length > 0 ? (
|
return questionGuides.length > 0 ? (
|
||||||
<Box mt={2}>
|
<Box mt={2}>
|
||||||
<ChatBoxDivider icon="core/chat/QGFill" text={t('core.chat.Question Guide')} />
|
<ChatBoxDivider icon="core/chat/QGFill" text={t('common:core.chat.Question Guide')} />
|
||||||
<Flex alignItems={'center'} flexWrap={'wrap'} gap={2}>
|
<Flex alignItems={'center'} flexWrap={'wrap'} gap={2}>
|
||||||
{questionGuides.map((text) => (
|
{questionGuides.map((text) => (
|
||||||
<Flex
|
<Flex
|
||||||
@@ -60,7 +60,7 @@ const QuestionGuide = ({ text }: { text: string }) => {
|
|||||||
lineHeight={0}
|
lineHeight={0}
|
||||||
bg={`linear-gradient(to left, white,white min(60px,100%),rgba(255,255,255,0) 80%)`}
|
bg={`linear-gradient(to left, white,white min(60px,100%),rgba(255,255,255,0) 80%)`}
|
||||||
>
|
>
|
||||||
<MyTooltip label={t('core.chat.markdown.Edit Question')}>
|
<MyTooltip label={t('common:core.chat.markdown.Edit Question')}>
|
||||||
<MyIcon
|
<MyIcon
|
||||||
name={'edit'}
|
name={'edit'}
|
||||||
w={'14px'}
|
w={'14px'}
|
||||||
@@ -71,7 +71,7 @@ const QuestionGuide = ({ text }: { text: string }) => {
|
|||||||
onClick={() => eventBus.emit(EventNameEnum.editQuestion, { text })}
|
onClick={() => eventBus.emit(EventNameEnum.editQuestion, { text })}
|
||||||
/>
|
/>
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
<MyTooltip label={t('core.chat.markdown.Send Question')}>
|
<MyTooltip label={t('common:core.chat.markdown.Send Question')}>
|
||||||
<MyIcon
|
<MyIcon
|
||||||
ml={4}
|
ml={4}
|
||||||
name={'core/chat/sendLight'}
|
name={'core/chat/sendLight'}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ const A = React.memo(function A({ children, ...props }: any) {
|
|||||||
const text = useMemo(() => String(children), [children]);
|
const text = useMemo(() => String(children), [children]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MyTooltip label={t('core.chat.markdown.Quick Question')}>
|
<MyTooltip label={t('common:core.chat.markdown.Quick Question')}>
|
||||||
<Button
|
<Button
|
||||||
variant={'whitePrimary'}
|
variant={'whitePrimary'}
|
||||||
size={'xs'}
|
size={'xs'}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const AIModelSelector = ({ list, onchange, disableTip, ...props }: Props) => {
|
|||||||
label: (
|
label: (
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<Avatar borderRadius={'0'} mr={2} src={LOGO_ICON} w={'18px'} />
|
<Avatar borderRadius={'0'} mr={2} src={LOGO_ICON} w={'18px'} />
|
||||||
<Box>{t('support.user.Price')}</Box>
|
<Box>{t('common:support.user.Price')}</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
),
|
),
|
||||||
value: 'price'
|
value: 'price'
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ const EditResourceModal = ({
|
|||||||
setValue('avatar', src);
|
setValue('avatar', src);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
toast({
|
toast({
|
||||||
title: getErrText(err, t('common.error.Select avatar failed')),
|
title: getErrText(err, t('common:common.error.Select avatar failed')),
|
||||||
status: 'warning'
|
status: 'warning'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -76,9 +76,9 @@ const EditResourceModal = ({
|
|||||||
<MyModal isOpen onClose={onClose} iconSrc={avatar} title={title}>
|
<MyModal isOpen onClose={onClose} iconSrc={avatar} title={title}>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Box>
|
<Box>
|
||||||
<FormLabel mb={1}>{t('core.app.Name and avatar')}</FormLabel>
|
<FormLabel mb={1}>{t('common:core.app.Name and avatar')}</FormLabel>
|
||||||
<HStack spacing={4}>
|
<HStack spacing={4}>
|
||||||
<MyTooltip label={t('common.Set Avatar')}>
|
<MyTooltip label={t('common:common.Set Avatar')}>
|
||||||
<Avatar
|
<Avatar
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
src={avatar}
|
src={avatar}
|
||||||
@@ -98,13 +98,13 @@ const EditResourceModal = ({
|
|||||||
</HStack>
|
</HStack>
|
||||||
</Box>
|
</Box>
|
||||||
<Box mt={4}>
|
<Box mt={4}>
|
||||||
<FormLabel mb={1}>{t('common.Intro')}</FormLabel>
|
<FormLabel mb={1}>{t('common:common.Intro')}</FormLabel>
|
||||||
<Textarea {...register('intro')} bg={'myGray.50'} maxLength={200} />
|
<Textarea {...register('intro')} bg={'myGray.50'} maxLength={200} />
|
||||||
</Box>
|
</Box>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button isLoading={loading} onClick={handleSubmit(onSave)} px={6}>
|
<Button isLoading={loading} onClick={handleSubmit(onSave)} px={6}>
|
||||||
{t('common.Confirm')}
|
{t('common:common.Confirm')}
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const ParentPaths = (props: {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
paths = [],
|
paths = [],
|
||||||
rootName = t('common.folder.Root Path'),
|
rootName = t('common:common.folder.Root Path'),
|
||||||
FirstPathDom,
|
FirstPathDom,
|
||||||
onClick,
|
onClick,
|
||||||
fontSize
|
fontSize
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const MyTextarea = React.forwardRef<HTMLTextAreaElement, Props>(function MyTexta
|
|||||||
const TextareaRef = useRef<HTMLTextAreaElement>(null);
|
const TextareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { title = t('core.app.edit.Prompt Editor'), ...childProps } = props;
|
const { title = t('common:core.app.edit.Prompt Editor'), ...childProps } = props;
|
||||||
|
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ const MyTextarea = React.forwardRef<HTMLTextAreaElement, Props>(function MyTexta
|
|||||||
onClose();
|
onClose();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('common.Confirm')}
|
{t('common:common.Confirm')}
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</MyModal>
|
</MyModal>
|
||||||
@@ -85,7 +85,7 @@ const Editor = React.memo(function Editor({
|
|||||||
cursor={'pointer'}
|
cursor={'pointer'}
|
||||||
onClick={onOpenModal}
|
onClick={onOpenModal}
|
||||||
>
|
>
|
||||||
<MyTooltip label={t('common.ui.textarea.Magnifying')}>
|
<MyTooltip label={t('common:common.ui.textarea.Magnifying')}>
|
||||||
<MyIcon name={'common/fullScreenLight'} w={'14px'} color={'myGray.600'} />
|
<MyIcon name={'common/fullScreenLight'} w={'14px'} color={'myGray.600'} />
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const TagTextarea = ({ defaultValues, onUpdate, ...props }: Props) => {
|
|||||||
if (tags.includes(value)) {
|
if (tags.includes(value)) {
|
||||||
return toast({
|
return toast({
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
title: t('common.input.Repeat Value')
|
title: t('common:common.input.Repeat Value')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setTags([...tags, value]);
|
setTags([...tags, value]);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const MoveModal = ({ moveResourceId, title, server, onConfirm, onClose }: Props)
|
|||||||
setFolderList([
|
setFolderList([
|
||||||
{
|
{
|
||||||
id: rootId,
|
id: rootId,
|
||||||
name: t('common.folder.Root Path'),
|
name: t('common:common.folder.Root Path'),
|
||||||
open: true,
|
open: true,
|
||||||
children: data.map((item) => ({
|
children: data.map((item) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
@@ -156,7 +156,7 @@ const MoveModal = ({ moveResourceId, title, server, onConfirm, onClose }: Props)
|
|||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
onClose();
|
onClose();
|
||||||
},
|
},
|
||||||
successToast: t('common.folder.Move Success')
|
successToast: t('common:common.folder.Move Success')
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ const MoveModal = ({ moveResourceId, title, server, onConfirm, onClose }: Props)
|
|||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button isLoading={confirming} isDisabled={!selectedId} onClick={onConfirmSelect}>
|
<Button isLoading={confirming} isDisabled={!selectedId} onClick={onConfirmSelect}>
|
||||||
{t('common.Confirm')}
|
{t('common:common.Confirm')}
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</MyModal>
|
</MyModal>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const FolderPath = (props: {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
const {
|
||||||
paths,
|
paths,
|
||||||
rootName = t('common.folder.Root Path'),
|
rootName = t('common:common.folder.Root Path'),
|
||||||
FirstPathDom,
|
FirstPathDom,
|
||||||
onClick,
|
onClick,
|
||||||
fontSize,
|
fontSize,
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const SelectOneResource = ({
|
|||||||
id: rootId,
|
id: rootId,
|
||||||
open: true,
|
open: true,
|
||||||
avatar: FolderImgUrl,
|
avatar: FolderImgUrl,
|
||||||
name: t('common.folder.Root Path'),
|
name: t('common:common.folder.Root Path'),
|
||||||
isFolder: true,
|
isFolder: true,
|
||||||
children: dataList
|
children: dataList
|
||||||
};
|
};
|
||||||
@@ -155,7 +155,7 @@ const SelectOneResource = ({
|
|||||||
return loading ? (
|
return loading ? (
|
||||||
<Loading fixed={false} />
|
<Loading fixed={false} />
|
||||||
) : (
|
) : (
|
||||||
<Box maxH={maxH} overflow={'auto'}>
|
<Box maxH={maxH} h={'100%'} overflow={'auto'}>
|
||||||
<Render list={concatRoot} />
|
<Render list={concatRoot} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ const FolderSlideCard = ({
|
|||||||
<MyDivider my={6} />
|
<MyDivider my={6} />
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<FormLabel>{t('common.Operation')}</FormLabel>
|
<FormLabel>{t('common:common.Operation')}</FormLabel>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant={'transparentBase'}
|
variant={'transparentBase'}
|
||||||
@@ -101,7 +101,7 @@ const FolderSlideCard = ({
|
|||||||
mt={4}
|
mt={4}
|
||||||
onClick={onMove}
|
onClick={onMove}
|
||||||
>
|
>
|
||||||
{t('common.Move')}
|
{t('common:common.Move')}
|
||||||
</Button>
|
</Button>
|
||||||
{managePer.permission.isOwner && (
|
{managePer.permission.isOwner && (
|
||||||
<Button
|
<Button
|
||||||
@@ -118,7 +118,7 @@ const FolderSlideCard = ({
|
|||||||
openConfirm(onDelete)();
|
openConfirm(onDelete)();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('common.Delete folder')}
|
{t('common:common.Delete folder')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -130,7 +130,7 @@ const FolderSlideCard = ({
|
|||||||
<MyDivider my={6} />
|
<MyDivider my={6} />
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<FormLabel>{t('support.permission.Permission')}</FormLabel>
|
<FormLabel>{t('common:support.permission.Permission')}</FormLabel>
|
||||||
|
|
||||||
{!isInheritPermission && (
|
{!isInheritPermission && (
|
||||||
<Box mt={2}>
|
<Box mt={2}>
|
||||||
@@ -141,7 +141,7 @@ const FolderSlideCard = ({
|
|||||||
{managePer.permission.hasManagePer && (
|
{managePer.permission.hasManagePer && (
|
||||||
<Box mt={5}>
|
<Box mt={5}>
|
||||||
<Box fontSize={'sm'} color={'myGray.500'}>
|
<Box fontSize={'sm'} color={'myGray.500'}>
|
||||||
{t('permission.Default permission')}
|
{t('common:permission.Default permission')}
|
||||||
</Box>
|
</Box>
|
||||||
<DefaultPermissionList
|
<DefaultPermissionList
|
||||||
mt="1"
|
mt="1"
|
||||||
@@ -166,11 +166,11 @@ const FolderSlideCard = ({
|
|||||||
<>
|
<>
|
||||||
<Flex alignItems="center" justifyContent="space-between">
|
<Flex alignItems="center" justifyContent="space-between">
|
||||||
<Box fontSize={'sm'} color={'myGray.500'}>
|
<Box fontSize={'sm'} color={'myGray.500'}>
|
||||||
{t('permission.Collaborator')}
|
{t('common:permission.Collaborator')}
|
||||||
</Box>
|
</Box>
|
||||||
{managePer.permission.hasManagePer && (
|
{managePer.permission.hasManagePer && (
|
||||||
<HStack spacing={3}>
|
<HStack spacing={3}>
|
||||||
<MyTooltip label={t('permission.Manage')}>
|
<MyTooltip label={t('common:permission.Manage')}>
|
||||||
<MyIcon
|
<MyIcon
|
||||||
w="1rem"
|
w="1rem"
|
||||||
name="common/settingLight"
|
name="common/settingLight"
|
||||||
@@ -179,7 +179,7 @@ const FolderSlideCard = ({
|
|||||||
onClick={onOpenManageModal}
|
onClick={onOpenManageModal}
|
||||||
/>
|
/>
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
<MyTooltip label={t('common.Add')}>
|
<MyTooltip label={t('common:common.Add')}>
|
||||||
<MyIcon
|
<MyIcon
|
||||||
w="1rem"
|
w="1rem"
|
||||||
name="support/permission/collaborator"
|
name="support/permission/collaborator"
|
||||||
|
|||||||
@@ -32,20 +32,22 @@ export const useFolderDrag = ({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setTargetId(undefined);
|
setTargetId(undefined);
|
||||||
},
|
},
|
||||||
onDrop: async (e: DragEvent<HTMLDivElement>) => {
|
...(isFolder && {
|
||||||
e.preventDefault();
|
onDrop: async (e: DragEvent<HTMLDivElement>) => {
|
||||||
setTrue();
|
e.preventDefault();
|
||||||
|
setTrue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (targetId && dragId && targetId !== dragId) {
|
if (targetId && dragId && targetId !== dragId) {
|
||||||
await onDrop(dragId, targetId);
|
await onDrop(dragId, targetId);
|
||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
|
|
||||||
setTargetId(undefined);
|
setTargetId(undefined);
|
||||||
setDragId(undefined);
|
setDragId(undefined);
|
||||||
setFalse();
|
setFalse();
|
||||||
},
|
}
|
||||||
|
}),
|
||||||
...(activeStyles &&
|
...(activeStyles &&
|
||||||
targetId === dataId && {
|
targetId === dataId && {
|
||||||
...activeStyles
|
...activeStyles
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const AIChatSettingsModal = ({
|
|||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
{t('core.ai.AI settings')}
|
{t('common:core.ai.AI settings')}
|
||||||
{feConfigs?.docUrl && (
|
{feConfigs?.docUrl && (
|
||||||
<Link
|
<Link
|
||||||
href={getDocPath('/docs/course/ai_settings/')}
|
href={getDocPath('/docs/course/ai_settings/')}
|
||||||
@@ -85,7 +85,7 @@ const AIChatSettingsModal = ({
|
|||||||
fontWeight={'normal'}
|
fontWeight={'normal'}
|
||||||
fontSize={'md'}
|
fontSize={'md'}
|
||||||
>
|
>
|
||||||
{t('common.Read intro')}
|
{t('common:common.Read intro')}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
@@ -95,7 +95,7 @@ const AIChatSettingsModal = ({
|
|||||||
<ModalBody overflowY={'auto'}>
|
<ModalBody overflowY={'auto'}>
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<Box {...LabelStyles} mr={2}>
|
<Box {...LabelStyles} mr={2}>
|
||||||
{t('core.ai.Model')}
|
{t('common:core.ai.Model')}
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={'1 0 0'}>
|
<Box flex={'1 0 0'}>
|
||||||
<AIModelSelector
|
<AIModelSelector
|
||||||
@@ -112,7 +112,7 @@ const AIChatSettingsModal = ({
|
|||||||
{feConfigs && (
|
{feConfigs && (
|
||||||
<Flex mt={8}>
|
<Flex mt={8}>
|
||||||
<Box {...LabelStyles} mr={2}>
|
<Box {...LabelStyles} mr={2}>
|
||||||
{t('core.ai.Ai point price')}
|
{t('common:core.ai.Ai point price')}
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={1} ml={'10px'}>
|
<Box flex={1} ml={'10px'}>
|
||||||
{t('support.wallet.Ai point every thousand tokens', {
|
{t('support.wallet.Ai point every thousand tokens', {
|
||||||
@@ -123,7 +123,7 @@ const AIChatSettingsModal = ({
|
|||||||
)}
|
)}
|
||||||
<Flex mt={8}>
|
<Flex mt={8}>
|
||||||
<Box {...LabelStyles} mr={2}>
|
<Box {...LabelStyles} mr={2}>
|
||||||
{t('core.ai.Max context')}
|
{t('common:core.ai.Max context')}
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={1} ml={'10px'}>
|
<Box flex={1} ml={'10px'}>
|
||||||
{selectedModel?.maxContext || 4096}Tokens
|
{selectedModel?.maxContext || 4096}Tokens
|
||||||
@@ -131,8 +131,8 @@ const AIChatSettingsModal = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
<Flex mt={8}>
|
<Flex mt={8}>
|
||||||
<Box {...LabelStyles} mr={2}>
|
<Box {...LabelStyles} mr={2}>
|
||||||
{t('core.ai.Support tool')}
|
{t('common:core.ai.Support tool')}
|
||||||
<QuestionTip ml={1} label={t('core.module.template.AI support tool tip')} />
|
<QuestionTip ml={1} label={t('common:core.module.template.AI support tool tip')} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={1} ml={'10px'}>
|
<Box flex={1} ml={'10px'}>
|
||||||
{selectedModel?.toolChoice || selectedModel?.functionCall ? '支持' : '不支持'}
|
{selectedModel?.toolChoice || selectedModel?.functionCall ? '支持' : '不支持'}
|
||||||
@@ -140,13 +140,13 @@ const AIChatSettingsModal = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
<Flex mt={8}>
|
<Flex mt={8}>
|
||||||
<Box {...LabelStyles} mr={2}>
|
<Box {...LabelStyles} mr={2}>
|
||||||
{t('core.app.Temperature')}
|
{t('common:core.app.Temperature')}
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={1} ml={'10px'}>
|
<Box flex={1} ml={'10px'}>
|
||||||
<MySlider
|
<MySlider
|
||||||
markList={[
|
markList={[
|
||||||
{ label: t('core.app.deterministic'), value: 0 },
|
{ label: t('common:core.app.deterministic'), value: 0 },
|
||||||
{ label: t('core.app.Random'), value: 10 }
|
{ label: t('common:core.app.Random'), value: 10 }
|
||||||
]}
|
]}
|
||||||
width={'95%'}
|
width={'95%'}
|
||||||
min={0}
|
min={0}
|
||||||
@@ -161,7 +161,7 @@ const AIChatSettingsModal = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
<Flex mt={8}>
|
<Flex mt={8}>
|
||||||
<Box {...LabelStyles} mr={2}>
|
<Box {...LabelStyles} mr={2}>
|
||||||
{t('core.app.Max tokens')}
|
{t('common:core.app.Max tokens')}
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={1} ml={'10px'}>
|
<Box flex={1} ml={'10px'}>
|
||||||
<MySlider
|
<MySlider
|
||||||
@@ -184,7 +184,7 @@ const AIChatSettingsModal = ({
|
|||||||
{showMaxHistoriesSlider && (
|
{showMaxHistoriesSlider && (
|
||||||
<Flex mt={8}>
|
<Flex mt={8}>
|
||||||
<Box {...LabelStyles} mr={2}>
|
<Box {...LabelStyles} mr={2}>
|
||||||
{t('core.app.Max histories')}
|
{t('common:core.app.Max histories')}
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={1} ml={'10px'}>
|
<Box flex={1} ml={'10px'}>
|
||||||
<MySlider
|
<MySlider
|
||||||
@@ -207,10 +207,10 @@ const AIChatSettingsModal = ({
|
|||||||
{showResponseAnswerText && (
|
{showResponseAnswerText && (
|
||||||
<Flex mt={8} alignItems={'center'}>
|
<Flex mt={8} alignItems={'center'}>
|
||||||
<Box {...LabelStyles}>
|
<Box {...LabelStyles}>
|
||||||
{t('core.app.Ai response')}
|
{t('common:core.app.Ai response')}
|
||||||
<QuestionTip
|
<QuestionTip
|
||||||
ml={1}
|
ml={1}
|
||||||
label={t('core.module.template.AI response switch tip')}
|
label={t('common:core.module.template.AI response switch tip')}
|
||||||
></QuestionTip>
|
></QuestionTip>
|
||||||
</Box>
|
</Box>
|
||||||
<Box flex={1} ml={'10px'}>
|
<Box flex={1} ml={'10px'}>
|
||||||
@@ -228,10 +228,10 @@ const AIChatSettingsModal = ({
|
|||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button variant={'whiteBase'} onClick={onClose}>
|
<Button variant={'whiteBase'} onClick={onClose}>
|
||||||
{t('common.Close')}
|
{t('common:common.Close')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button ml={4} onClick={handleSubmit(onSuccess)}>
|
<Button ml={4} onClick={handleSubmit(onSuccess)}>
|
||||||
{t('common.Confirm')}
|
{t('common:common.Confirm')}
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</MyModal>
|
</MyModal>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ const SettingLLMModel = ({ llmModelType = LLMModelTypeEnum.all, defaultData, onC
|
|||||||
})}
|
})}
|
||||||
position={'relative'}
|
position={'relative'}
|
||||||
>
|
>
|
||||||
<MyTooltip label={t('core.app.Setting ai property')}>
|
<MyTooltip label={t('common:core.app.Setting ai property')}>
|
||||||
<Button
|
<Button
|
||||||
w={'100%'}
|
w={'100%'}
|
||||||
justifyContent={'flex-start'}
|
justifyContent={'flex-start'}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ const DatasetParamsModal = ({
|
|||||||
isOpen={true}
|
isOpen={true}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
iconSrc="/imgs/modal/params.svg"
|
iconSrc="/imgs/modal/params.svg"
|
||||||
title={t('core.dataset.search.Dataset Search Params')}
|
title={t('common:core.dataset.search.Dataset Search Params')}
|
||||||
w={['90vw', '550px']}
|
w={['90vw', '550px']}
|
||||||
>
|
>
|
||||||
<ModalBody flex={'auto'} overflow={'auto'}>
|
<ModalBody flex={'auto'} overflow={'auto'}>
|
||||||
@@ -132,16 +132,16 @@ const DatasetParamsModal = ({
|
|||||||
list={[
|
list={[
|
||||||
{
|
{
|
||||||
icon: 'modal/setting',
|
icon: 'modal/setting',
|
||||||
label: t('core.dataset.search.search mode'),
|
label: t('common:core.dataset.search.search mode'),
|
||||||
value: SearchSettingTabEnum.searchMode
|
value: SearchSettingTabEnum.searchMode
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'support/outlink/apikeyFill',
|
icon: 'support/outlink/apikeyFill',
|
||||||
label: t('core.dataset.search.Filter'),
|
label: t('common:core.dataset.search.Filter'),
|
||||||
value: SearchSettingTabEnum.limit
|
value: SearchSettingTabEnum.limit
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('core.module.template.Query extension'),
|
label: t('common:core.module.template.Query extension'),
|
||||||
value: SearchSettingTabEnum.queryExtension,
|
value: SearchSettingTabEnum.queryExtension,
|
||||||
icon: '/imgs/workflow/cfr.svg'
|
icon: '/imgs/workflow/cfr.svg'
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ const DatasetParamsModal = ({
|
|||||||
if (!showReRank) {
|
if (!showReRank) {
|
||||||
return toast({
|
return toast({
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
title: t('core.ai.Not deploy rerank model')
|
title: t('common:core.ai.Not deploy rerank model')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -191,7 +191,7 @@ const DatasetParamsModal = ({
|
|||||||
) {
|
) {
|
||||||
return toast({
|
return toast({
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
title: t('support.team.limit.No permission rerank')
|
title: t('common:support.team.limit.No permission rerank')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setValue('usingReRank', !getValues('usingReRank'));
|
setValue('usingReRank', !getValues('usingReRank'));
|
||||||
@@ -200,9 +200,9 @@ const DatasetParamsModal = ({
|
|||||||
>
|
>
|
||||||
<MyIcon name="core/dataset/rerank" w={'18px'} mr={'14px'} />
|
<MyIcon name="core/dataset/rerank" w={'18px'} mr={'14px'} />
|
||||||
<Box pr={2} color={'myGray.800'} flex={'1 0 0'}>
|
<Box pr={2} color={'myGray.800'} flex={'1 0 0'}>
|
||||||
<Box fontSize={'sm'}>{t('core.dataset.search.ReRank')}</Box>
|
<Box fontSize={'sm'}>{t('common:core.dataset.search.ReRank')}</Box>
|
||||||
<Box fontSize={'xs'} color={'myGray.500'}>
|
<Box fontSize={'xs'} color={'myGray.500'}>
|
||||||
{t('core.dataset.search.ReRank desc')}
|
{t('common:core.dataset.search.ReRank desc')}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box position={'relative'} w={'18px'} h={'18px'}>
|
<Box position={'relative'} w={'18px'} h={'18px'}>
|
||||||
@@ -218,10 +218,10 @@ const DatasetParamsModal = ({
|
|||||||
{limit !== undefined && (
|
{limit !== undefined && (
|
||||||
<Box display={['block', 'flex']}>
|
<Box display={['block', 'flex']}>
|
||||||
<Flex flex={'0 0 120px'} mb={[8, 0]}>
|
<Flex flex={'0 0 120px'} mb={[8, 0]}>
|
||||||
<FormLabel>{t('core.dataset.search.Max Tokens')}</FormLabel>
|
<FormLabel>{t('common:core.dataset.search.Max Tokens')}</FormLabel>
|
||||||
<QuestionTip
|
<QuestionTip
|
||||||
ml={1}
|
ml={1}
|
||||||
label={t('core.dataset.search.Max Tokens Tips')}
|
label={t('common:core.dataset.search.Max Tokens Tips')}
|
||||||
></QuestionTip>
|
></QuestionTip>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Box flex={1} mx={4}>
|
<Box flex={1} mx={4}>
|
||||||
@@ -244,10 +244,10 @@ const DatasetParamsModal = ({
|
|||||||
)}
|
)}
|
||||||
<Box display={['block', 'flex']} mt={10}>
|
<Box display={['block', 'flex']} mt={10}>
|
||||||
<Flex flex={'0 0 120px'} mb={[8, 0]}>
|
<Flex flex={'0 0 120px'} mb={[8, 0]}>
|
||||||
<FormLabel>{t('core.dataset.search.Min Similarity')}</FormLabel>
|
<FormLabel>{t('common:core.dataset.search.Min Similarity')}</FormLabel>
|
||||||
<QuestionTip
|
<QuestionTip
|
||||||
ml={1}
|
ml={1}
|
||||||
label={t('core.dataset.search.Min Similarity Tips')}
|
label={t('common:core.dataset.search.Min Similarity Tips')}
|
||||||
></QuestionTip>
|
></QuestionTip>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Box flex={1} mx={4}>
|
<Box flex={1} mx={4}>
|
||||||
@@ -267,7 +267,9 @@ const DatasetParamsModal = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Box color={'myGray.500'}>{t('core.dataset.search.No support similarity')}</Box>
|
<Box color={'myGray.500'}>
|
||||||
|
{t('common:core.dataset.search.No support similarity')}
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -276,16 +278,18 @@ const DatasetParamsModal = ({
|
|||||||
{currentTabType === SearchSettingTabEnum.queryExtension && (
|
{currentTabType === SearchSettingTabEnum.queryExtension && (
|
||||||
<Box>
|
<Box>
|
||||||
<Box transform={'translateY(-5px)'} fontSize={'xs'} color={'myGray.500'}>
|
<Box transform={'translateY(-5px)'} fontSize={'xs'} color={'myGray.500'}>
|
||||||
{t('core.dataset.Query extension intro')}
|
{t('common:core.dataset.Query extension intro')}
|
||||||
</Box>
|
</Box>
|
||||||
<Flex mt={3} alignItems={'center'}>
|
<Flex mt={3} alignItems={'center'}>
|
||||||
<FormLabel flex={'1 0 0'}>{t('core.dataset.search.Using query extension')}</FormLabel>
|
<FormLabel flex={'1 0 0'}>
|
||||||
|
{t('common:core.dataset.search.Using query extension')}
|
||||||
|
</FormLabel>
|
||||||
<Switch {...register('datasetSearchUsingExtensionQuery')} />
|
<Switch {...register('datasetSearchUsingExtensionQuery')} />
|
||||||
</Flex>
|
</Flex>
|
||||||
{datasetSearchUsingCfrForm === true && (
|
{datasetSearchUsingCfrForm === true && (
|
||||||
<>
|
<>
|
||||||
<Flex mt={4} alignItems={'center'}>
|
<Flex mt={4} alignItems={'center'}>
|
||||||
<FormLabel flex={['0 0 80px', '1 0 0']}>{t('core.ai.Model')}</FormLabel>
|
<FormLabel flex={['0 0 80px', '1 0 0']}>{t('common:core.ai.Model')}</FormLabel>
|
||||||
<Box flex={['1 0 0', '0 0 300px']}>
|
<Box flex={['1 0 0', '0 0 300px']}>
|
||||||
<SelectAiModel
|
<SelectAiModel
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
@@ -299,17 +303,19 @@ const DatasetParamsModal = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
<Box mt={3}>
|
<Box mt={3}>
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<FormLabel>{t('core.app.edit.Query extension background prompt')}</FormLabel>
|
<FormLabel>
|
||||||
|
{t('common:core.app.edit.Query extension background prompt')}
|
||||||
|
</FormLabel>
|
||||||
<QuestionTip
|
<QuestionTip
|
||||||
ml={1}
|
ml={1}
|
||||||
label={t('core.app.edit.Query extension background tip')}
|
label={t('common:core.app.edit.Query extension background tip')}
|
||||||
></QuestionTip>
|
></QuestionTip>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Box mt={1}>
|
<Box mt={1}>
|
||||||
<PromptEditor
|
<PromptEditor
|
||||||
h={200}
|
h={200}
|
||||||
showOpenModal={false}
|
showOpenModal={false}
|
||||||
placeholder={t('core.module.QueryExtension.placeholder')}
|
placeholder={t('common:core.module.QueryExtension.placeholder')}
|
||||||
value={cfbBgDesc}
|
value={cfbBgDesc}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setValue('datasetSearchExtensionBg', e);
|
setValue('datasetSearchExtensionBg', e);
|
||||||
@@ -324,7 +330,7 @@ const DatasetParamsModal = ({
|
|||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
|
<Button variant={'whiteBase'} mr={3} onClick={onClose}>
|
||||||
{t('common.Close')}
|
{t('common:common.Close')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -332,7 +338,7 @@ const DatasetParamsModal = ({
|
|||||||
handleSubmit(onSuccess)();
|
handleSubmit(onSuccess)();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('common.Done')}
|
{t('common:common.Done')}
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</MyModal>
|
</MyModal>
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export const DatasetSelectModal = ({
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
paths={paths}
|
paths={paths}
|
||||||
setParentId={setParentId}
|
setParentId={setParentId}
|
||||||
tips={t('dataset.Select Dataset Tips')}
|
tips={t('common:dataset.Select Dataset Tips')}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
>
|
>
|
||||||
<Flex h={'100%'} flexDirection={'column'} flex={'1 0 0'}>
|
<Flex h={'100%'} flexDirection={'column'} flex={'1 0 0'}>
|
||||||
@@ -124,8 +124,8 @@ export const DatasetSelectModal = ({
|
|||||||
key={item._id}
|
key={item._id}
|
||||||
label={
|
label={
|
||||||
item.type === DatasetTypeEnum.folder
|
item.type === DatasetTypeEnum.folder
|
||||||
? t('dataset.Select Folder')
|
? t('common:dataset.Select Folder')
|
||||||
: t('dataset.Select Dataset')
|
: t('common:dataset.Select Dataset')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Card
|
<Card
|
||||||
@@ -148,7 +148,7 @@ export const DatasetSelectModal = ({
|
|||||||
if (vectorModel && vectorModel !== item.vectorModel.model) {
|
if (vectorModel && vectorModel !== item.vectorModel.model) {
|
||||||
return toast({
|
return toast({
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
title: t('dataset.Select Dataset Tips')
|
title: t('common:dataset.Select Dataset Tips')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setSelectedDatasets((state) => [...state, { datasetId: item._id }]);
|
setSelectedDatasets((state) => [...state, { datasetId: item._id }]);
|
||||||
@@ -170,7 +170,7 @@ export const DatasetSelectModal = ({
|
|||||||
</Flex>
|
</Flex>
|
||||||
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
|
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
|
||||||
{item.type === DatasetTypeEnum.folder ? (
|
{item.type === DatasetTypeEnum.folder ? (
|
||||||
<Box color={'myGray.500'}>{t('Folder')}</Box>
|
<Box color={'myGray.500'}>{t('common:Folder')}</Box>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<MyIcon mr={1} name="kbTest" w={'12px'} />
|
<MyIcon mr={1} name="kbTest" w={'12px'} />
|
||||||
@@ -184,7 +184,9 @@ export const DatasetSelectModal = ({
|
|||||||
})()
|
})()
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
{filterDatasets.unSelected.length === 0 && <EmptyTip text={t('common.folder.empty')} />}
|
{filterDatasets.unSelected.length === 0 && (
|
||||||
|
<EmptyTip text={t('common:common.folder.empty')} />
|
||||||
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
@@ -199,7 +201,7 @@ export const DatasetSelectModal = ({
|
|||||||
onChange(filterDatasets);
|
onChange(filterDatasets);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('common.Done')}
|
{t('common:common.Done')}
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
|
|
||||||
|
|||||||
@@ -77,9 +77,9 @@ const InputGuideConfig = ({
|
|||||||
|
|
||||||
const formLabel = useMemo(() => {
|
const formLabel = useMemo(() => {
|
||||||
if (!isOpenQuestionGuide) {
|
if (!isOpenQuestionGuide) {
|
||||||
return t('core.app.whisper.Close');
|
return t('common:core.app.whisper.Close');
|
||||||
}
|
}
|
||||||
return t('core.app.whisper.Open');
|
return t('common:core.app.whisper.Open');
|
||||||
}, [t, isOpenQuestionGuide]);
|
}, [t, isOpenQuestionGuide]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -110,7 +110,7 @@ const InputGuideConfig = ({
|
|||||||
>
|
>
|
||||||
<ModalBody px={[5, 16]} py={[4, 8]}>
|
<ModalBody px={[5, 16]} py={[4, 8]}>
|
||||||
<Flex justifyContent={'space-between'} alignItems={'center'}>
|
<Flex justifyContent={'space-between'} alignItems={'center'}>
|
||||||
<FormLabel>{t('Is open')}</FormLabel>
|
<FormLabel>{t('common:Is open')}</FormLabel>
|
||||||
<Switch
|
<Switch
|
||||||
isChecked={isOpenQuestionGuide}
|
isChecked={isOpenQuestionGuide}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -231,7 +231,7 @@ const LexiconConfigModal = ({ appId, onClose }: { appId: string; onClose: () =>
|
|||||||
} else {
|
} else {
|
||||||
toast({
|
toast({
|
||||||
status: 'success',
|
status: 'success',
|
||||||
title: t('common.Add Success')
|
title: t('common:common.Add Success')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fetchData(1);
|
fetchData(1);
|
||||||
@@ -241,7 +241,7 @@ const LexiconConfigModal = ({ appId, onClose }: { appId: string; onClose: () =>
|
|||||||
onSuccess() {
|
onSuccess() {
|
||||||
setNewData(undefined);
|
setNewData(undefined);
|
||||||
},
|
},
|
||||||
errorToast: t('error.Create failed')
|
errorToast: t('common:error.Create failed')
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const QGSwitch = (props: SwitchProps) => {
|
|||||||
return (
|
return (
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<MyIcon name={'core/chat/QGFill'} mr={2} w={'20px'} />
|
<MyIcon name={'core/chat/QGFill'} mr={2} w={'20px'} />
|
||||||
<FormLabel>{t('core.app.Question Guide')}</FormLabel>
|
<FormLabel>{t('common:core.app.Question Guide')}</FormLabel>
|
||||||
<ChatFunctionTip type={'nextQuestion'} />
|
<ChatFunctionTip type={'nextQuestion'} />
|
||||||
<Box flex={1} />
|
<Box flex={1} />
|
||||||
<Switch {...props} />
|
<Switch {...props} />
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ const ScheduledTriggerConfig = ({
|
|||||||
// cron config to show label
|
// cron config to show label
|
||||||
const formatLabel = useMemo(() => {
|
const formatLabel = useMemo(() => {
|
||||||
if (!isOpenSchedule) {
|
if (!isOpenSchedule) {
|
||||||
return t('common.Not open');
|
return t('common:common.Not open');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cronField[0] === 'month') {
|
if (cronField[0] === 'month') {
|
||||||
@@ -239,7 +239,7 @@ const ScheduledTriggerConfig = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return t('common.Not open');
|
return t('common:common.Not open');
|
||||||
}, [cronField, isOpenSchedule, t]);
|
}, [cronField, isOpenSchedule, t]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -254,10 +254,10 @@ const ScheduledTriggerConfig = ({
|
|||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<MyIcon name={'core/app/schedulePlan'} w={'20px'} />
|
<MyIcon name={'core/app/schedulePlan'} w={'20px'} />
|
||||||
<HStack ml={2} flex={1} spacing={1}>
|
<HStack ml={2} flex={1} spacing={1}>
|
||||||
<FormLabel>{t('core.app.Interval timer run')}</FormLabel>
|
<FormLabel>{t('common:core.app.Interval timer run')}</FormLabel>
|
||||||
<QuestionTip label={t('core.app.Interval timer tip')} />
|
<QuestionTip label={t('common:core.app.Interval timer tip')} />
|
||||||
</HStack>
|
</HStack>
|
||||||
<MyTooltip label={t('core.app.Config schedule plan')}>
|
<MyTooltip label={t('common:core.app.Config schedule plan')}>
|
||||||
<Button
|
<Button
|
||||||
variant={'transparentBase'}
|
variant={'transparentBase'}
|
||||||
iconSpacing={1}
|
iconSpacing={1}
|
||||||
@@ -274,12 +274,15 @@ const ScheduledTriggerConfig = ({
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
iconSrc={'core/app/schedulePlan'}
|
iconSrc={'core/app/schedulePlan'}
|
||||||
title={t('core.app.Interval timer config')}
|
title={t('common:core.app.Interval timer config')}
|
||||||
overflow={'unset'}
|
overflow={'unset'}
|
||||||
>
|
>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Flex justifyContent={'space-between'} alignItems={'center'}>
|
<Flex justifyContent={'space-between'} alignItems={'center'}>
|
||||||
<FormLabel flex={'0 0 80px'}> {t('core.app.schedule.Open schedule')}</FormLabel>
|
<FormLabel flex={'0 0 80px'}>
|
||||||
|
{' '}
|
||||||
|
{t('common:core.app.schedule.Open schedule')}
|
||||||
|
</FormLabel>
|
||||||
<Switch
|
<Switch
|
||||||
isChecked={isOpenSchedule}
|
isChecked={isOpenSchedule}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -318,12 +321,12 @@ const ScheduledTriggerConfig = ({
|
|||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Box mt={5}>
|
<Box mt={5}>
|
||||||
<FormLabel mb={1}>{t('core.app.schedule.Default prompt')}</FormLabel>
|
<FormLabel mb={1}>{t('common:core.app.schedule.Default prompt')}</FormLabel>
|
||||||
<Textarea
|
<Textarea
|
||||||
value={defaultPrompt}
|
value={defaultPrompt}
|
||||||
rows={8}
|
rows={8}
|
||||||
bg={'myGray.50'}
|
bg={'myGray.50'}
|
||||||
placeholder={t('core.app.schedule.Default prompt placeholder')}
|
placeholder={t('common:core.app.schedule.Default prompt placeholder')}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onUpdate({ defaultPrompt: e.target.value });
|
onUpdate({ defaultPrompt: e.target.value });
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ const TTSSelect = ({
|
|||||||
|
|
||||||
const list = useMemo(
|
const list = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{ label: t('core.app.tts.Close'), value: TTSTypeEnum.none },
|
{ label: t('common:core.app.tts.Close'), value: TTSTypeEnum.none },
|
||||||
{ label: t('core.app.tts.Web'), value: TTSTypeEnum.web },
|
{ label: t('common:core.app.tts.Web'), value: TTSTypeEnum.web },
|
||||||
...audioSpeechModelList.map((item) => item?.voices || []).flat()
|
...audioSpeechModelList.map((item) => item?.voices || []).flat()
|
||||||
],
|
],
|
||||||
[audioSpeechModelList, t]
|
[audioSpeechModelList, t]
|
||||||
@@ -44,7 +44,7 @@ const TTSSelect = ({
|
|||||||
return value.voice;
|
return value.voice;
|
||||||
}, [value]);
|
}, [value]);
|
||||||
const formLabel = useMemo(
|
const formLabel = useMemo(
|
||||||
() => list.find((item) => item.value === formatValue)?.label || t('common.UnKnow'),
|
() => list.find((item) => item.value === formatValue)?.label || t('common:common.UnKnow'),
|
||||||
[formatValue, list, t]
|
[formatValue, list, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -82,10 +82,10 @@ const TTSSelect = ({
|
|||||||
return (
|
return (
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<MyIcon name={'core/app/simpleMode/tts'} mr={2} w={'20px'} />
|
<MyIcon name={'core/app/simpleMode/tts'} mr={2} w={'20px'} />
|
||||||
<FormLabel>{t('core.app.TTS')}</FormLabel>
|
<FormLabel>{t('common:core.app.TTS')}</FormLabel>
|
||||||
<ChatFunctionTip type={'tts'} />
|
<ChatFunctionTip type={'tts'} />
|
||||||
<Box flex={1} />
|
<Box flex={1} />
|
||||||
<MyTooltip label={t('core.app.Select TTS')}>
|
<MyTooltip label={t('common:core.app.Select TTS')}>
|
||||||
<Button
|
<Button
|
||||||
variant={'transparentBase'}
|
variant={'transparentBase'}
|
||||||
iconSpacing={1}
|
iconSpacing={1}
|
||||||
@@ -100,7 +100,7 @@ const TTSSelect = ({
|
|||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
<MyIcon name={'core/app/simpleMode/tts'} mr={2} w={'20px'} />
|
<MyIcon name={'core/app/simpleMode/tts'} mr={2} w={'20px'} />
|
||||||
{t('core.app.TTS')}
|
{t('common:core.app.TTS')}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
@@ -109,11 +109,11 @@ const TTSSelect = ({
|
|||||||
>
|
>
|
||||||
<ModalBody px={[5, 16]} py={[4, 8]}>
|
<ModalBody px={[5, 16]} py={[4, 8]}>
|
||||||
<Flex justifyContent={'space-between'} alignItems={'center'}>
|
<Flex justifyContent={'space-between'} alignItems={'center'}>
|
||||||
<FormLabel>{t('core.app.tts.Speech model')}</FormLabel>
|
<FormLabel>{t('common:core.app.tts.Speech model')}</FormLabel>
|
||||||
<MySelect w={'220px'} value={formatValue} list={list} onchange={onclickChange} />
|
<MySelect w={'220px'} value={formatValue} list={list} onchange={onclickChange} />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex mt={8} justifyContent={'space-between'}>
|
<Flex mt={8} justifyContent={'space-between'}>
|
||||||
<FormLabel>{t('core.app.tts.Speech speed')}</FormLabel>
|
<FormLabel>{t('common:core.app.tts.Speech speed')}</FormLabel>
|
||||||
<MySlider
|
<MySlider
|
||||||
markList={[
|
markList={[
|
||||||
{ label: '0.3', value: 0.3 },
|
{ label: '0.3', value: 0.3 },
|
||||||
@@ -145,7 +145,7 @@ const TTSSelect = ({
|
|||||||
leftIcon={<MyIcon name={'core/chat/stopSpeech'} w={'16px'} />}
|
leftIcon={<MyIcon name={'core/chat/stopSpeech'} w={'16px'} />}
|
||||||
onClick={cancelAudio}
|
onClick={cancelAudio}
|
||||||
>
|
>
|
||||||
{t('core.chat.tts.Stop Speech')}
|
{t('common:core.chat.tts.Stop Speech')}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
) : (
|
) : (
|
||||||
@@ -154,11 +154,11 @@ const TTSSelect = ({
|
|||||||
leftIcon={<MyIcon name={'core/app/headphones'} w={'16px'} />}
|
leftIcon={<MyIcon name={'core/app/headphones'} w={'16px'} />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
playAudioByText({
|
playAudioByText({
|
||||||
text: t('core.app.tts.Test Listen Text')
|
text: t('common:core.app.tts.Test Listen Text')
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('core.app.tts.Test Listen')}
|
{t('common:core.app.tts.Test Listen')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -25,26 +25,26 @@ const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => {
|
|||||||
},
|
},
|
||||||
[FnTypeEnum.nextQuestion]: {
|
[FnTypeEnum.nextQuestion]: {
|
||||||
icon: '/imgs/app/nextQuestion-icon.svg',
|
icon: '/imgs/app/nextQuestion-icon.svg',
|
||||||
title: t('core.app.Question Guide'),
|
title: t('common:core.app.Question Guide'),
|
||||||
desc: t('core.app.Question Guide Tip'),
|
desc: t('common:core.app.Question Guide Tip'),
|
||||||
imgUrl: '/imgs/app/nextQuestion.svg'
|
imgUrl: '/imgs/app/nextQuestion.svg'
|
||||||
},
|
},
|
||||||
[FnTypeEnum.tts]: {
|
[FnTypeEnum.tts]: {
|
||||||
icon: '/imgs/app/tts-icon.svg',
|
icon: '/imgs/app/tts-icon.svg',
|
||||||
title: t('core.app.TTS'),
|
title: t('common:core.app.TTS'),
|
||||||
desc: t('core.app.TTS Tip'),
|
desc: t('common:core.app.TTS Tip'),
|
||||||
imgUrl: '/imgs/app/tts.svg'
|
imgUrl: '/imgs/app/tts.svg'
|
||||||
},
|
},
|
||||||
[FnTypeEnum.variable]: {
|
[FnTypeEnum.variable]: {
|
||||||
icon: '/imgs/app/variable-icon.svg',
|
icon: '/imgs/app/variable-icon.svg',
|
||||||
title: t('core.module.Variable'),
|
title: t('common:core.module.Variable'),
|
||||||
desc: t('core.app.tip.variableTip'),
|
desc: t('common:core.app.tip.variableTip'),
|
||||||
imgUrl: '/imgs/app/variable.svg'
|
imgUrl: '/imgs/app/variable.svg'
|
||||||
},
|
},
|
||||||
[FnTypeEnum.welcome]: {
|
[FnTypeEnum.welcome]: {
|
||||||
icon: '/imgs/app/welcome-icon.svg',
|
icon: '/imgs/app/welcome-icon.svg',
|
||||||
title: t('core.app.Welcome Text'),
|
title: t('common:core.app.Welcome Text'),
|
||||||
desc: t('core.app.tip.welcomeTextTip'),
|
desc: t('common:core.app.tip.welcomeTextTip'),
|
||||||
imgUrl: '/imgs/app/welcome.svg'
|
imgUrl: '/imgs/app/welcome.svg'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ const VariableEdit = ({
|
|||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<MyIcon name={'core/app/simpleMode/variable'} w={'20px'} />
|
<MyIcon name={'core/app/simpleMode/variable'} w={'20px'} />
|
||||||
<FormLabel ml={2} fontWeight={'medium'}>
|
<FormLabel ml={2} fontWeight={'medium'}>
|
||||||
{t('core.module.Variable')}
|
{t('common:core.module.Variable')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<ChatFunctionTip type={'variable'} />
|
<ChatFunctionTip type={'variable'} />
|
||||||
<Box flex={1} />
|
<Box flex={1} />
|
||||||
@@ -112,7 +112,7 @@ const VariableEdit = ({
|
|||||||
onOpenEdit();
|
onOpenEdit();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('common.Add New')}
|
{t('common:common.Add New')}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
{formatVariables.length > 0 && (
|
{formatVariables.length > 0 && (
|
||||||
@@ -127,9 +127,9 @@ const VariableEdit = ({
|
|||||||
w={'18px !important'}
|
w={'18px !important'}
|
||||||
p={0}
|
p={0}
|
||||||
/>
|
/>
|
||||||
<Th fontSize={'mini'}>{t('core.module.variable.variable name')}</Th>
|
<Th fontSize={'mini'}>{t('common:core.module.variable.variable name')}</Th>
|
||||||
<Th fontSize={'mini'}>{t('core.module.variable.key')}</Th>
|
<Th fontSize={'mini'}>{t('common:core.module.variable.key')}</Th>
|
||||||
<Th fontSize={'mini'}>{t('common.Require Input')}</Th>
|
<Th fontSize={'mini'}>{t('common:common.Require Input')}</Th>
|
||||||
<Th fontSize={'mini'} borderRadius={'none !important'}></Th>
|
<Th fontSize={'mini'} borderRadius={'none !important'}></Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
@@ -171,7 +171,7 @@ const VariableEdit = ({
|
|||||||
)}
|
)}
|
||||||
<MyModal
|
<MyModal
|
||||||
iconSrc="core/app/simpleMode/variable"
|
iconSrc="core/app/simpleMode/variable"
|
||||||
title={t('core.module.Variable Setting')}
|
title={t('common:core.module.Variable Setting')}
|
||||||
isOpen={isOpenEdit}
|
isOpen={isOpenEdit}
|
||||||
onClose={onCloseEdit}
|
onClose={onCloseEdit}
|
||||||
maxW={['90vw', '500px']}
|
maxW={['90vw', '500px']}
|
||||||
@@ -179,29 +179,29 @@ const VariableEdit = ({
|
|||||||
<ModalBody>
|
<ModalBody>
|
||||||
{variableType !== VariableInputEnum.custom && (
|
{variableType !== VariableInputEnum.custom && (
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<FormLabel w={'70px'}>{t('common.Require Input')}</FormLabel>
|
<FormLabel w={'70px'}>{t('common:common.Require Input')}</FormLabel>
|
||||||
<Switch {...registerEdit('variable.required')} />
|
<Switch {...registerEdit('variable.required')} />
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
<Flex mt={5} alignItems={'center'}>
|
<Flex mt={5} alignItems={'center'}>
|
||||||
<FormLabel w={'80px'}>{t('core.module.variable.variable name')}</FormLabel>
|
<FormLabel w={'80px'}>{t('common:core.module.variable.variable name')}</FormLabel>
|
||||||
<Input
|
<Input
|
||||||
{...registerEdit('variable.label', {
|
{...registerEdit('variable.label', {
|
||||||
required: t('core.module.variable.variable name is required')
|
required: t('common:core.module.variable.variable name is required')
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex mt={5} alignItems={'center'}>
|
<Flex mt={5} alignItems={'center'}>
|
||||||
<FormLabel w={'80px'}>{t('core.module.variable.key')}</FormLabel>
|
<FormLabel w={'80px'}>{t('common:core.module.variable.key')}</FormLabel>
|
||||||
<Input
|
<Input
|
||||||
{...registerEdit('variable.key', {
|
{...registerEdit('variable.key', {
|
||||||
required: t('core.module.variable.key is required')
|
required: t('common:core.module.variable.key is required')
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<FormLabel mt={5} mb={2}>
|
<FormLabel mt={5} mb={2}>
|
||||||
{t('core.workflow.Variable.Variable type')}
|
{t('common:core.workflow.Variable.Variable type')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<MyRadio
|
<MyRadio
|
||||||
gridGap={4}
|
gridGap={4}
|
||||||
@@ -226,7 +226,7 @@ const VariableEdit = ({
|
|||||||
{variableType === VariableInputEnum.input && (
|
{variableType === VariableInputEnum.input && (
|
||||||
<>
|
<>
|
||||||
<FormLabel mt={5} mb={2}>
|
<FormLabel mt={5} mb={2}>
|
||||||
{t('core.module.variable.text max length')}
|
{t('common:core.module.variable.text max length')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<Box>
|
<Box>
|
||||||
<NumberInput max={500} min={1} step={1} position={'relative'}>
|
<NumberInput max={500} min={1} step={1} position={'relative'}>
|
||||||
@@ -250,7 +250,7 @@ const VariableEdit = ({
|
|||||||
{variableType === VariableInputEnum.select && (
|
{variableType === VariableInputEnum.select && (
|
||||||
<>
|
<>
|
||||||
<Box mt={5} mb={2}>
|
<Box mt={5} mb={2}>
|
||||||
{t('core.module.variable.variable options')}
|
{t('common:core.module.variable.variable options')}
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
{selectEnums.map((item, i) => (
|
{selectEnums.map((item, i) => (
|
||||||
@@ -258,7 +258,9 @@ const VariableEdit = ({
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
{...registerEdit(`variable.enums.${i}.value`, {
|
{...registerEdit(`variable.enums.${i}.value`, {
|
||||||
required: t('core.module.variable.variable option is value is required')
|
required: t(
|
||||||
|
'common:core.module.variable.variable option is value is required'
|
||||||
|
)
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -285,7 +287,7 @@ const VariableEdit = ({
|
|||||||
bg={'myGray.100 !important'}
|
bg={'myGray.100 !important'}
|
||||||
onClick={() => appendEnums({ value: '' })}
|
onClick={() => appendEnums({ value: '' })}
|
||||||
>
|
>
|
||||||
{t('core.module.variable add option')}
|
{t('common:core.module.variable add option')}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -293,7 +295,7 @@ const VariableEdit = ({
|
|||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button variant={'whiteBase'} mr={3} onClick={onCloseEdit}>
|
<Button variant={'whiteBase'} mr={3} onClick={onCloseEdit}>
|
||||||
{t('common.Close')}
|
{t('common:common.Close')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSubmitEdit(({ variable }) => {
|
onClick={handleSubmitEdit(({ variable }) => {
|
||||||
@@ -303,7 +305,7 @@ const VariableEdit = ({
|
|||||||
if (enums.length === 0) {
|
if (enums.length === 0) {
|
||||||
toast({
|
toast({
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
title: t('core.module.variable.variable option is required')
|
title: t('common:core.module.variable.variable option is required')
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -323,7 +325,9 @@ const VariableEdit = ({
|
|||||||
onCloseEdit();
|
onCloseEdit();
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{getValuesEdit('variable.id') ? t('common.Confirm Update') : t('common.Add New')}
|
{getValuesEdit('variable.id')
|
||||||
|
? t('common:common.Confirm Update')
|
||||||
|
: t('common:common.Add New')}
|
||||||
</Button>
|
</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</MyModal>
|
</MyModal>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user