Compare commits
20 Commits
v4.8
...
v4.8.1-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a14a8ae627 | ||
|
|
fb368a581c | ||
|
|
8e8ceb7439 | ||
|
|
e35ce2caa0 | ||
|
|
fd31a0b763 | ||
|
|
ba517b6a73 | ||
|
|
2f93dedfb6 | ||
|
|
67c52992d7 | ||
|
|
2d1ec9b3ad | ||
|
|
6067f5aff3 | ||
|
|
c6d9b15897 | ||
|
|
d5073f98ab | ||
|
|
8386f707cd | ||
|
|
cd876251b7 | ||
|
|
fb04889a31 | ||
|
|
b779e2806d | ||
|
|
240f60c0ca | ||
|
|
8d2230f24f | ||
|
|
610ebded3b | ||
|
|
80a84a5733 |
3
.vscode/i18n-ally-custom-framework.yml
vendored
3
.vscode/i18n-ally-custom-framework.yml
vendored
@@ -23,6 +23,9 @@ usageMatchRegex:
|
|||||||
- "[^\\w\\d]datasetT\\(['\"`]({key})['\"`]"
|
- "[^\\w\\d]datasetT\\(['\"`]({key})['\"`]"
|
||||||
- "[^\\w\\d]fileT\\(['\"`]({key})['\"`]"
|
- "[^\\w\\d]fileT\\(['\"`]({key})['\"`]"
|
||||||
- "[^\\w\\d]publishT\\(['\"`]({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
|
# 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
|
# and works like how the i18next framework identifies the namespace scope from the
|
||||||
|
|||||||
33
.vscode/nextapi.code-snippets
vendored
33
.vscode/nextapi.code-snippets
vendored
@@ -10,14 +10,19 @@
|
|||||||
"scope": "javascript,typescript",
|
"scope": "javascript,typescript",
|
||||||
"prefix": "nextapi",
|
"prefix": "nextapi",
|
||||||
"body": [
|
"body": [
|
||||||
"import type { NextApiRequest, NextApiResponse } from 'next';",
|
"import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';",
|
||||||
"import { NextAPI } from '@/service/middle/entry';",
|
"import { NextAPI } from '@/service/middleware/entry';",
|
||||||
"",
|
"",
|
||||||
"type Props = {};",
|
"export type ${TM_FILENAME_BASE}Query = {};",
|
||||||
"",
|
"",
|
||||||
"type Response = {};",
|
"export type ${TM_FILENAME_BASE}Body = {};",
|
||||||
"",
|
"",
|
||||||
"async function handler(req: NextApiRequest, res: NextApiResponse<any>): Promise<Response> {",
|
"export type ${TM_FILENAME_BASE}Response = {};",
|
||||||
|
"",
|
||||||
|
"async function handler(",
|
||||||
|
" req: ApiRequestProps<${TM_FILENAME_BASE}Body, ${TM_FILENAME_BASE}Query>,",
|
||||||
|
" res: ApiResponseType<any>",
|
||||||
|
"): Promise<${TM_FILENAME_BASE}Response> {",
|
||||||
" $1",
|
" $1",
|
||||||
" return {}",
|
" return {}",
|
||||||
"}",
|
"}",
|
||||||
@@ -25,5 +30,23 @@
|
|||||||
"export default NextAPI(handler);"
|
"export default NextAPI(handler);"
|
||||||
],
|
],
|
||||||
"description": "FastGPT Next API template"
|
"description": "FastGPT Next API template"
|
||||||
|
},
|
||||||
|
"use context template": {
|
||||||
|
"scope": "typescriptreact",
|
||||||
|
"prefix": "context",
|
||||||
|
"body": [
|
||||||
|
"import { ReactNode } from 'react';",
|
||||||
|
"import { createContext } from 'use-context-selector';",
|
||||||
|
"",
|
||||||
|
"type ContextType = {$1};",
|
||||||
|
"",
|
||||||
|
"export const Context = createContext<ContextType>({});",
|
||||||
|
"",
|
||||||
|
"export const ContextProvider = ({ children }: { children: ReactNode }) => {",
|
||||||
|
" const contextValue: ContextType = {};",
|
||||||
|
" return <Context.Provider value={contextValue}>{children}</Context.Provider>;",
|
||||||
|
"};",
|
||||||
|
],
|
||||||
|
"description": "FastGPT usecontext template"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -11,5 +11,6 @@
|
|||||||
"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.extract.targetPickingStrategy": "most-similar-by-key"
|
||||||
}
|
}
|
||||||
13
Dockerfile
13
Dockerfile
@@ -11,7 +11,7 @@ RUN apk add --no-cache libc6-compat && npm install -g pnpm@8.6.0
|
|||||||
RUN [ -z "$proxy" ] || pnpm config set registry https://registry.npmmirror.com
|
RUN [ -z "$proxy" ] || pnpm config set registry https://registry.npmmirror.com
|
||||||
|
|
||||||
# copy packages and one project
|
# copy packages and one project
|
||||||
COPY pnpm-lock.yaml pnpm-workspace.yaml ./
|
COPY pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
|
||||||
COPY ./packages ./packages
|
COPY ./packages ./packages
|
||||||
COPY ./projects/$name/package.json ./projects/$name/package.json
|
COPY ./projects/$name/package.json ./projects/$name/package.json
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ ARG name
|
|||||||
ARG proxy
|
ARG proxy
|
||||||
|
|
||||||
# copy common node_modules and one project node_modules
|
# copy common node_modules and one project node_modules
|
||||||
COPY package.json pnpm-workspace.yaml ./
|
COPY package.json pnpm-workspace.yaml .npmrc ./
|
||||||
COPY --from=mainDeps /app/node_modules ./node_modules
|
COPY --from=mainDeps /app/node_modules ./node_modules
|
||||||
COPY --from=mainDeps /app/packages ./packages
|
COPY --from=mainDeps /app/packages ./packages
|
||||||
COPY ./projects/$name ./projects/$name
|
COPY ./projects/$name ./projects/$name
|
||||||
@@ -36,6 +36,8 @@ COPY --from=mainDeps /app/projects/$name/node_modules ./projects/$name/node_modu
|
|||||||
RUN [ -z "$proxy" ] || sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
|
RUN [ -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@8.6.0
|
||||||
|
|
||||||
|
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||||
RUN pnpm --filter=$name build
|
RUN pnpm --filter=$name build
|
||||||
|
|
||||||
# --------- runner -----------
|
# --------- runner -----------
|
||||||
@@ -62,6 +64,11 @@ COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/static /app/
|
|||||||
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/server/chunks /app/projects/$name/.next/server/chunks
|
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/server/chunks /app/projects/$name/.next/server/chunks
|
||||||
# copy worker
|
# copy worker
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/server/worker /app/projects/$name/.next/server/worker
|
COPY --from=builder --chown=nextjs:nodejs /app/projects/$name/.next/server/worker /app/projects/$name/.next/server/worker
|
||||||
|
|
||||||
|
# copy tiktoken but not copy ./node_modules/tiktoken/encoders
|
||||||
|
COPY --from=mainDeps /app/node_modules/tiktoken ./node_modules/tiktoken
|
||||||
|
RUN rm -rf ./node_modules/tiktoken/encoders
|
||||||
|
|
||||||
# copy package.json to version file
|
# copy package.json to version file
|
||||||
COPY --from=builder /app/projects/$name/package.json ./package.json
|
COPY --from=builder /app/projects/$name/package.json ./package.json
|
||||||
# copy config
|
# copy config
|
||||||
@@ -79,4 +86,4 @@ USER nextjs
|
|||||||
|
|
||||||
ENV serverPath=./projects/$name/server.js
|
ENV serverPath=./projects/$name/server.js
|
||||||
|
|
||||||
ENTRYPOINT ["sh","-c","node ${serverPath}"]
|
ENTRYPOINT ["sh","-c","node --max-old-space-size=4096 ${serverPath}"]
|
||||||
BIN
docSite/assets/imgs/external_file0.png
Normal file
BIN
docSite/assets/imgs/external_file0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 163 KiB |
BIN
docSite/assets/imgs/external_file1.png
Normal file
BIN
docSite/assets/imgs/external_file1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
BIN
docSite/assets/imgs/external_file2.png
Normal file
BIN
docSite/assets/imgs/external_file2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
BIN
docSite/assets/imgs/questionGuide.png
Normal file
BIN
docSite/assets/imgs/questionGuide.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
50
docSite/content/docs/course/chat_input_guide.md
Normal file
50
docSite/content/docs/course/chat_input_guide.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
title: "对话问题引导"
|
||||||
|
description: "FastGPT 对话问题引导"
|
||||||
|
icon: "code"
|
||||||
|
draft: false
|
||||||
|
toc: true
|
||||||
|
weight: 350
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 什么是自定义问题引导
|
||||||
|
|
||||||
|
你可以为你的应用提前预设一些问题,用户在输入时,会根据输入的内容,动态搜索这些问题作为提示,从而引导用户更快的进行提问。
|
||||||
|
|
||||||
|
你可以直接在 FastGPT 中配置词库,或者提供自定义词库接口。
|
||||||
|
|
||||||
|
## 自定义词库接口
|
||||||
|
|
||||||
|
需要保证这个接口可以被用户浏览器访问。
|
||||||
|
|
||||||
|
**请求:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --location --request GET 'http://localhost:3000/api/core/chat/inputGuide/query?appId=663c75302caf8315b1c00194&searchKey=你'
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"statusText": "",
|
||||||
|
"message": "",
|
||||||
|
"data": [
|
||||||
|
"是你",
|
||||||
|
"你是谁呀",
|
||||||
|
"你好好呀",
|
||||||
|
"你好呀",
|
||||||
|
"你是谁!",
|
||||||
|
"你好"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
**参数说明:**
|
||||||
|
|
||||||
|
- appId - 应用ID
|
||||||
|
- searchKey - 搜索关键字
|
||||||
26
docSite/content/docs/course/externalFile.md
Normal file
26
docSite/content/docs/course/externalFile.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
title: '外部文件知识库'
|
||||||
|
description: 'FastGPT 外部文件知识库功能介绍和使用方式'
|
||||||
|
icon: 'language'
|
||||||
|
draft: false
|
||||||
|
toc: true
|
||||||
|
weight: 107
|
||||||
|
---
|
||||||
|
|
||||||
|
外部文件库是 FastGPT 商业版特有功能。它允许接入你现在的文件系统,无需将文件再导入一份到 FastGPT 中。
|
||||||
|
|
||||||
|
并且,阅读权限可以通过你的文件系统进行控制。
|
||||||
|
|
||||||
|
| | | |
|
||||||
|
| --------------------- | --------------------- | --------------------- |
|
||||||
|
|  |  |  |
|
||||||
|
|
||||||
|
|
||||||
|
## 导入参数说明
|
||||||
|
|
||||||
|
- 外部预览地址:用于跳转你的文件阅读地址,会携带“文件阅读ID”进行访问。
|
||||||
|
- 文件访问URL:文件可访问的地址。
|
||||||
|
- 文件阅读ID:通常情况下,文件访问URL是临时的。如果希望永久可以访问,你需要使用该文件阅读ID,并配合上“外部预览地址”,跳转至新的阅读地址进行原文件访问。
|
||||||
|
- 文件名:默认会自动解析文件访问URL上的文件名。如果你手动填写,将会以手动填写的值为准。
|
||||||
|
|
||||||
|
[点击查看API导入文档](/docs/development/openapi/dataset/#创建一个外部文件库集合商业版)
|
||||||
@@ -118,4 +118,5 @@ OneAPI 的 API Key 配置错误,需要修改`OPENAI_API_KEY`环境变量,并
|
|||||||
### bad_response_status_code bad response status code 503
|
### bad_response_status_code bad response status code 503
|
||||||
|
|
||||||
1. 模型服务不可用
|
1. 模型服务不可用
|
||||||
2. ....
|
2. 模型接口参数异常(温度、max token等可能不适配)
|
||||||
|
3. ....
|
||||||
@@ -133,3 +133,57 @@ FastGPT 在`pnpm i`后会执行`postinstall`脚本,用于自动生成`ChakraUI
|
|||||||
遇到困难了吗?有任何问题吗? 加入微信群与开发者和用户保持沟通。
|
遇到困难了吗?有任何问题吗? 加入微信群与开发者和用户保持沟通。
|
||||||
|
|
||||||
<img width="400px" src="https://oss.laf.run/htr4n1-images/fastgpt-qr-code.jpg" class="medium-zoom-image" />
|
<img width="400px" src="https://oss.laf.run/htr4n1-images/fastgpt-qr-code.jpg" class="medium-zoom-image" />
|
||||||
|
|
||||||
|
## 代码结构说明
|
||||||
|
|
||||||
|
### nextjs
|
||||||
|
|
||||||
|
FastGPT 使用了 nextjs 的 page route 作为框架。为了区分好前后端代码,在目录分配上会分成 global, service, web 3个自目录,分别对应着 `前后端共用`、`后端专用`、`前端专用`的代码。
|
||||||
|
|
||||||
|
### monorepo
|
||||||
|
FastGPT 采用 pnpm workspace 方式构建 monorepo 项目,主要分为两个部分:
|
||||||
|
|
||||||
|
- projects/app - FastGPT 主项目
|
||||||
|
- packages/ - 子模块
|
||||||
|
- global - 共用代码,通常是放一些前后端都能执行的函数、类型声明、常量。
|
||||||
|
- service - 服务端代码
|
||||||
|
- web - 前端代码
|
||||||
|
- plugin - 工作流自定义插件的代码
|
||||||
|
|
||||||
|
### 领域驱动模式(DDD)
|
||||||
|
|
||||||
|
FastGPT 在代码模块划分时,按DDD的思想进行划分,主要分为以下几个领域:
|
||||||
|
|
||||||
|
core - 核心功能(知识库,工作流,应用,对话)
|
||||||
|
support - 支撑功能(用户体系,计费,鉴权等)
|
||||||
|
common - 基础功能(日志管理,文件读写等)
|
||||||
|
|
||||||
|
{{% details title="代码结构说明" closed="true" %}}
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── .github // github 相关配置
|
||||||
|
├── .husky // 格式化配置
|
||||||
|
├── docSite // 文档
|
||||||
|
├── files // 一些外部文件,例如 docker-compose, helm
|
||||||
|
├── packages // 子包
|
||||||
|
│ ├── global // 前后端通用子包
|
||||||
|
│ ├── plugins // 工作流插件(需要自定义包时候使用到)
|
||||||
|
│ ├── service // 后端子包
|
||||||
|
│ └── web // 前端子包
|
||||||
|
├── projects
|
||||||
|
│ └── app // FastGPT 主项目
|
||||||
|
├── python // 存放一些模型代码,和 FastGPT 本身无关
|
||||||
|
└── scripts // 一些自动化脚本
|
||||||
|
├── icon // icon预览脚本,可以在顶层 pnpm initIcon(把svg写入到代码中), pnpm previewIcon(预览icon)
|
||||||
|
└── postinstall.sh // chakraUI自定义theme初始化 ts 类型
|
||||||
|
├── package.json // 顶层monorepo
|
||||||
|
├── pnpm-lock.yaml
|
||||||
|
├── pnpm-workspace.yaml // monorepo 声明
|
||||||
|
├── Dockerfile
|
||||||
|
├── LICENSE
|
||||||
|
├── README.md
|
||||||
|
├── README_en.md
|
||||||
|
├── README_ja.md
|
||||||
|
├── dev.md
|
||||||
|
```
|
||||||
|
{{% /details %}}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
---
|
---
|
||||||
weight: 762
|
|
||||||
title: "Docker Mongo迁移(dump模式)"
|
title: "Docker Mongo迁移(dump模式)"
|
||||||
description: "FastGPT Docker Mongo迁移"
|
description: "FastGPT Docker Mongo迁移"
|
||||||
icon: database
|
icon: database
|
||||||
draft: false
|
draft: false
|
||||||
images: []
|
weight: 762
|
||||||
---
|
---
|
||||||
|
|
||||||
## 作者
|
## 作者
|
||||||
|
|||||||
@@ -295,6 +295,24 @@ curl --location --request DELETE 'http://localhost:3000/api/core/dataset/delete?
|
|||||||
|
|
||||||
## 集合
|
## 集合
|
||||||
|
|
||||||
|
### 通用创建参数说明
|
||||||
|
|
||||||
|
**入参**
|
||||||
|
|
||||||
|
| 参数 | 说明 | 必填 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| datasetId | 知识库ID | ✅ |
|
||||||
|
| parentId: | 父级ID,不填则默认为根目录 | |
|
||||||
|
| trainingType | 训练模式。chunk: 按文本长度进行分割;qa: QA拆分;auto: 增强训练 | ✅ |
|
||||||
|
| chunkSize | 预估块大小 | |
|
||||||
|
| chunkSplitter | 自定义最高优先分割符号 | |
|
||||||
|
| qaPrompt | qa拆分提示词 | |
|
||||||
|
|
||||||
|
**出参**
|
||||||
|
|
||||||
|
- collectionId - 新建的集合ID
|
||||||
|
- insertLen:插入的块数量
|
||||||
|
|
||||||
### 创建一个空的集合
|
### 创建一个空的集合
|
||||||
|
|
||||||
{{< tabs tabTotal="3" >}}
|
{{< tabs tabTotal="3" >}}
|
||||||
@@ -500,7 +518,7 @@ data 为集合的 ID。
|
|||||||
{{< /tab >}}
|
{{< /tab >}}
|
||||||
{{< /tabs >}}
|
{{< /tabs >}}
|
||||||
|
|
||||||
### 创建一个文件集合(商业版)
|
### 创建一个文件集合
|
||||||
|
|
||||||
传入一个文件,创建一个集合,会读取文件内容进行分割。目前支持:pdf, docx, md, txt, html, csv。
|
传入一个文件,创建一个集合,会读取文件内容进行分割。目前支持:pdf, docx, md, txt, html, csv。
|
||||||
|
|
||||||
@@ -509,7 +527,7 @@ data 为集合的 ID。
|
|||||||
{{< markdownify >}}
|
{{< markdownify >}}
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl --location --request POST 'http://localhost:3000/api/proApi/core/dataset/collection/create/file' \
|
curl --location --request POST 'http://localhost:3000/api/core/dataset/collection/create/localFile' \
|
||||||
--header 'Authorization: Bearer {{authorization}}' \
|
--header 'Authorization: Bearer {{authorization}}' \
|
||||||
--form 'file=@"C:\\Users\\user\\Desktop\\fastgpt测试文件\\index.html"' \
|
--form 'file=@"C:\\Users\\user\\Desktop\\fastgpt测试文件\\index.html"' \
|
||||||
--form 'data="{\"datasetId\":\"6593e137231a2be9c5603ba7\",\"parentId\":null,\"trainingType\":\"chunk\",\"chunkSize\":512,\"chunkSplitter\":\"\",\"qaPrompt\":\"\",\"metadata\":{}}"'
|
--form 'data="{\"datasetId\":\"6593e137231a2be9c5603ba7\",\"parentId\":null,\"trainingType\":\"chunk\",\"chunkSize\":512,\"chunkSplitter\":\"\",\"qaPrompt\":\"\",\"metadata\":{}}"'
|
||||||
@@ -565,6 +583,68 @@ data 为集合的 ID。
|
|||||||
{{< /tab >}}
|
{{< /tab >}}
|
||||||
{{< /tabs >}}
|
{{< /tabs >}}
|
||||||
|
|
||||||
|
### 创建一个外部文件库集合(商业版)
|
||||||
|
|
||||||
|
{{< tabs tabTotal="3" >}}
|
||||||
|
{{< tab tabName="请求示例" >}}
|
||||||
|
{{< markdownify >}}
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --location --request POST 'http://localhost:3000/api/proApi/core/dataset/collection/create/externalFileUrl' \
|
||||||
|
--header 'Authorization: Bearer {{authorization}}' \
|
||||||
|
--header 'User-Agent: Apifox/1.0.0 (https://apifox.com)' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-raw '{
|
||||||
|
"externalFileUrl":"https://image.xxxxx.com/fastgpt-dev/%E6%91%82.pdf",
|
||||||
|
"externalFileId":"1111",
|
||||||
|
"filename":"自定义文件名",
|
||||||
|
"datasetId":"6642d105a5e9d2b00255b27b",
|
||||||
|
"parentId": null,
|
||||||
|
|
||||||
|
"trainingType": "chunk",
|
||||||
|
"chunkSize":512,
|
||||||
|
"chunkSplitter":"",
|
||||||
|
"qaPrompt":""
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< /markdownify >}}
|
||||||
|
{{< /tab >}}
|
||||||
|
|
||||||
|
{{< tab tabName="参数说明" >}}
|
||||||
|
{{< markdownify >}}
|
||||||
|
|
||||||
|
| 参数 | 说明 | 必填 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| externalFileUrl | 文件访问链接(可以是临时链接) | ✅ |
|
||||||
|
| externalFileId | 外部文件ID | |
|
||||||
|
| filename | 自定义文件名 | |
|
||||||
|
|
||||||
|
|
||||||
|
{{< /markdownify >}}
|
||||||
|
{{< /tab >}}
|
||||||
|
|
||||||
|
{{< tab tabName="响应示例" >}}
|
||||||
|
{{< markdownify >}}
|
||||||
|
|
||||||
|
data 为集合的 ID。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"statusText": "",
|
||||||
|
"message": "",
|
||||||
|
"data": {
|
||||||
|
"collectionId": "6646fcedfabd823cdc6de746",
|
||||||
|
"insertLen": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< /markdownify >}}
|
||||||
|
{{< /tab >}}
|
||||||
|
{{< /tabs >}}
|
||||||
|
|
||||||
### 获取集合列表
|
### 获取集合列表
|
||||||
|
|
||||||
{{< tabs tabTotal="3" >}}
|
{{< tabs tabTotal="3" >}}
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ curl --location --request POST '{{host}}/shareAuth/finish' \
|
|||||||
|
|
||||||
```ts
|
```ts
|
||||||
type ResponseType = {
|
type ResponseType = {
|
||||||
moduleType: `${FlowNodeTypeEnum}`; // 模块类型
|
moduleType: FlowNodeTypeEnum; // 模块类型
|
||||||
moduleName: string; // 模块名
|
moduleName: string; // 模块名
|
||||||
moduleLogo?: string; // logo
|
moduleLogo?: string; // logo
|
||||||
runningTime?: number; // 运行时间
|
runningTime?: number; // 运行时间
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 'V4.8(开发中)'
|
title: 'V4.8'
|
||||||
description: 'FastGPT V4.8 更新说明'
|
description: 'FastGPT V4.8 更新说明'
|
||||||
icon: 'upgrade'
|
icon: 'upgrade'
|
||||||
draft: false
|
draft: false
|
||||||
|
|||||||
45
docSite/content/docs/development/upgrading/481.md
Normal file
45
docSite/content/docs/development/upgrading/481.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
title: 'V4.8.1(进行中)'
|
||||||
|
description: 'FastGPT V4.8.1 更新说明'
|
||||||
|
icon: 'upgrade'
|
||||||
|
draft: false
|
||||||
|
toc: true
|
||||||
|
weight: 823
|
||||||
|
---
|
||||||
|
|
||||||
|
## 初始化脚本
|
||||||
|
|
||||||
|
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`;{{host}} 替换成FastGPT的域名。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --location --request POST 'https://{{host}}/api/admin/initv481' \
|
||||||
|
--header 'rootkey: {{rootkey}}' \
|
||||||
|
--header 'Content-Type: application/json'
|
||||||
|
```
|
||||||
|
|
||||||
|
由于之前集合名不规范,该初始化会重置表名。请在初始化前,确保 dataset.trainings 表没有数据。
|
||||||
|
最好更新该版本时,暂停所有进行中业务,再进行初始化,避免数据冲突。
|
||||||
|
|
||||||
|
## 执行脏数据清理
|
||||||
|
|
||||||
|
从任意终端,发起 1 个 HTTP 请求。其中 {{rootkey}} 替换成环境变量里的 `rootkey`;{{host}} 替换成FastGPT的域名。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --location --request POST 'https://{{host}}/api/admin/clearInvalidData' \
|
||||||
|
--header 'rootkey: {{rootkey}}' \
|
||||||
|
--header 'Content-Type: application/json'
|
||||||
|
```
|
||||||
|
|
||||||
|
初始化完后,可以执行这个命令。之前定时清理的定时器有些问题,部分数据没被清理,可以手动执行清理。
|
||||||
|
|
||||||
|
## V4.8.1 更新说明
|
||||||
|
|
||||||
|
1. 新增 - 知识库重新选择向量模型重建
|
||||||
|
2. 新增 - 对话框支持问题模糊检索提示,可自定义预设问题词库。
|
||||||
|
3. 新增 - 工作流节点版本变更提示,并可以同步最新版本配置,避免存在隐藏脏数据。
|
||||||
|
4. 新增 - 开放文件导入知识库接口到开源版, [点击插件文档](/docs/development/openapi/dataset/#创建一个文件集合)
|
||||||
|
5. 新增 - 外部文件源知识库, [点击查看文档](/docs/course/externalfile/)
|
||||||
|
6. 优化 - 插件输入的 debug 模式,支持全量参数输入渲染。
|
||||||
|
7. 修复 - 插件输入默认值被清空问题。
|
||||||
|
8. 修复 - 工作流删除节点的动态输入和输出时候,没有正确的删除连接线,导致可能出现逻辑异常。
|
||||||
|
9. 修复 - 定时器清理脏数据任务
|
||||||
@@ -9,6 +9,9 @@ type SplitProps = {
|
|||||||
overlapRatio?: number;
|
overlapRatio?: number;
|
||||||
customReg?: string[];
|
customReg?: string[];
|
||||||
};
|
};
|
||||||
|
export type TextSplitProps = Omit<SplitProps, 'text' | 'chunkLen'> & {
|
||||||
|
chunkLen?: number;
|
||||||
|
};
|
||||||
|
|
||||||
type SplitResponse = {
|
type SplitResponse = {
|
||||||
chunks: string[];
|
chunks: string[];
|
||||||
@@ -49,6 +52,7 @@ const strIsMdTable = (str: string) => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
const markdownTableSplit = (props: SplitProps): SplitResponse => {
|
const markdownTableSplit = (props: SplitProps): SplitResponse => {
|
||||||
@@ -77,6 +81,10 @@ ${mdSplitString}
|
|||||||
chunk += `${splitText2Lines[i]}\n`;
|
chunk += `${splitText2Lines[i]}\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chunk) {
|
||||||
|
chunks.push(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chunks,
|
chunks,
|
||||||
chars: chunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
chars: chunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
||||||
|
|||||||
@@ -6,6 +6,42 @@ export const formatTime2YMDHM = (time?: Date) =>
|
|||||||
export const formatTime2YMD = (time?: Date) => (time ? dayjs(time).format('YYYY-MM-DD') : '');
|
export const formatTime2YMD = (time?: Date) => (time ? dayjs(time).format('YYYY-MM-DD') : '');
|
||||||
export const formatTime2HM = (time: Date = new Date()) => dayjs(time).format('HH:mm');
|
export const formatTime2HM = (time: Date = new Date()) => dayjs(time).format('HH:mm');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间成聊天格式
|
||||||
|
*/
|
||||||
|
export const formatTimeToChatTime = (time: Date) => {
|
||||||
|
const now = dayjs();
|
||||||
|
const target = dayjs(time);
|
||||||
|
|
||||||
|
// 如果传入时间小于60秒,返回刚刚
|
||||||
|
if (now.diff(target, 'second') < 60) {
|
||||||
|
return '刚刚';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果时间是今天,展示几时:几分
|
||||||
|
if (now.isSame(target, 'day')) {
|
||||||
|
return target.format('HH:mm');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是昨天,展示昨天
|
||||||
|
if (now.subtract(1, 'day').isSame(target, 'day')) {
|
||||||
|
return '昨天';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是前天,展示前天
|
||||||
|
if (now.subtract(2, 'day').isSame(target, 'day')) {
|
||||||
|
return '前天';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是今年,展示某月某日
|
||||||
|
if (now.isSame(target, 'year')) {
|
||||||
|
return target.format('MM/DD');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是更久之前,展示某年某月某日
|
||||||
|
return target.format('YYYY/M/D');
|
||||||
|
};
|
||||||
|
|
||||||
/* cron time parse */
|
/* cron time parse */
|
||||||
export const cronParser2Fields = (cronString: string) => {
|
export const cronParser2Fields = (cronString: string) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ export type SystemEnvType = {
|
|||||||
vectorMaxProcess: number;
|
vectorMaxProcess: number;
|
||||||
qaMaxProcess: number;
|
qaMaxProcess: number;
|
||||||
pgHNSWEfSearch: number;
|
pgHNSWEfSearch: number;
|
||||||
|
tokenWorkers: number; // token count max worker
|
||||||
|
|
||||||
oneapiUrl?: string;
|
oneapiUrl?: string;
|
||||||
chatApiKey?: string;
|
chatApiKey?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AppWhisperConfigType } from './type';
|
import { AppTTSConfigType, AppWhisperConfigType } from './type';
|
||||||
|
|
||||||
export enum AppTypeEnum {
|
export enum AppTypeEnum {
|
||||||
simple = 'simple',
|
simple = 'simple',
|
||||||
@@ -13,8 +13,16 @@ export const AppTypeMap = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const defaultTTSConfig: AppTTSConfigType = { type: 'web' };
|
||||||
|
|
||||||
export const defaultWhisperConfig: AppWhisperConfigType = {
|
export const defaultWhisperConfig: AppWhisperConfigType = {
|
||||||
open: false,
|
open: false,
|
||||||
autoSend: false,
|
autoSend: false,
|
||||||
autoTTSResponse: false
|
autoTTSResponse: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const defaultChatInputGuideConfig = {
|
||||||
|
open: false,
|
||||||
|
textList: [],
|
||||||
|
customUrl: ''
|
||||||
|
};
|
||||||
|
|||||||
45
packages/global/core/app/type.d.ts
vendored
45
packages/global/core/app/type.d.ts
vendored
@@ -8,7 +8,7 @@ import { DatasetSearchModeEnum } from '../dataset/constants';
|
|||||||
import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
|
import { TeamTagSchema as TeamTagsSchemaType } from '@fastgpt/global/support/user/team/type.d';
|
||||||
import { StoreEdgeItemType } from '../workflow/type/edge';
|
import { StoreEdgeItemType } from '../workflow/type/edge';
|
||||||
|
|
||||||
export interface AppSchema {
|
export type AppSchema = {
|
||||||
_id: string;
|
_id: string;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
tmbId: string;
|
tmbId: string;
|
||||||
@@ -23,13 +23,14 @@ export interface AppSchema {
|
|||||||
edges: StoreEdgeItemType[];
|
edges: StoreEdgeItemType[];
|
||||||
|
|
||||||
// App system config
|
// App system config
|
||||||
|
chatConfig: AppChatConfigType;
|
||||||
scheduledTriggerConfig?: AppScheduledTriggerConfigType | null;
|
scheduledTriggerConfig?: AppScheduledTriggerConfigType | null;
|
||||||
scheduledTriggerNextTime?: Date;
|
scheduledTriggerNextTime?: Date;
|
||||||
|
|
||||||
permission: `${PermissionTypeEnum}`;
|
permission: `${PermissionTypeEnum}`;
|
||||||
inited?: boolean;
|
inited?: boolean;
|
||||||
teamTags: string[];
|
teamTags: string[];
|
||||||
}
|
};
|
||||||
|
|
||||||
export type AppListItemType = {
|
export type AppListItemType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
@@ -66,32 +67,19 @@ export type AppSimpleEditFormType = {
|
|||||||
datasetSearchExtensionBg?: string;
|
datasetSearchExtensionBg?: string;
|
||||||
};
|
};
|
||||||
selectedTools: FlowNodeTemplateType[];
|
selectedTools: FlowNodeTemplateType[];
|
||||||
userGuide: {
|
chatConfig: AppChatConfigType;
|
||||||
welcomeText: string;
|
|
||||||
variables: {
|
|
||||||
id: string;
|
|
||||||
key: string;
|
|
||||||
label: string;
|
|
||||||
type: `${VariableInputEnum}`;
|
|
||||||
required: boolean;
|
|
||||||
maxLen: number;
|
|
||||||
enums: {
|
|
||||||
value: string;
|
|
||||||
}[];
|
|
||||||
}[];
|
|
||||||
questionGuide: boolean;
|
|
||||||
tts: {
|
|
||||||
type: 'none' | 'web' | 'model';
|
|
||||||
model?: string | undefined;
|
|
||||||
voice?: string | undefined;
|
|
||||||
speed?: number | undefined;
|
|
||||||
};
|
|
||||||
whisper: AppWhisperConfigType;
|
|
||||||
scheduleTrigger: AppScheduledTriggerConfigType | null;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* app function config */
|
/* app chat config type */
|
||||||
|
export type AppChatConfigType = {
|
||||||
|
welcomeText?: string;
|
||||||
|
variables?: VariableItemType[];
|
||||||
|
questionGuide?: boolean;
|
||||||
|
ttsConfig?: AppTTSConfigType;
|
||||||
|
whisperConfig?: AppWhisperConfigType;
|
||||||
|
scheduledTriggerConfig?: AppScheduledTriggerConfigType;
|
||||||
|
chatInputGuide?: ChatInputGuideConfigType;
|
||||||
|
};
|
||||||
export type SettingAIDataType = {
|
export type SettingAIDataType = {
|
||||||
model: string;
|
model: string;
|
||||||
temperature: number;
|
temperature: number;
|
||||||
@@ -123,6 +111,11 @@ export type AppWhisperConfigType = {
|
|||||||
autoSend: boolean;
|
autoSend: boolean;
|
||||||
autoTTSResponse: boolean;
|
autoTTSResponse: boolean;
|
||||||
};
|
};
|
||||||
|
// question guide text
|
||||||
|
export type ChatInputGuideConfigType = {
|
||||||
|
open: boolean;
|
||||||
|
customUrl: string;
|
||||||
|
};
|
||||||
// interval timer
|
// interval timer
|
||||||
export type AppScheduledTriggerConfigType = {
|
export type AppScheduledTriggerConfigType = {
|
||||||
cronString: string;
|
cronString: string;
|
||||||
|
|||||||
@@ -1,49 +1,42 @@
|
|||||||
import type { AppSimpleEditFormType } from '../app/type';
|
import type { AppChatConfigType, AppSimpleEditFormType } from '../app/type';
|
||||||
import { FlowNodeTypeEnum } from '../workflow/node/constant';
|
import { FlowNodeTypeEnum } from '../workflow/node/constant';
|
||||||
import { NodeInputKeyEnum, FlowNodeTemplateTypeEnum } from '../workflow/constants';
|
import { NodeInputKeyEnum, FlowNodeTemplateTypeEnum } from '../workflow/constants';
|
||||||
import type { FlowNodeInputItemType } from '../workflow/type/io.d';
|
import type { FlowNodeInputItemType } from '../workflow/type/io.d';
|
||||||
import { getGuideModule, splitGuideModule } from '../workflow/utils';
|
import { getAppChatConfig } from '../workflow/utils';
|
||||||
import { StoreNodeItemType } from '../workflow/type';
|
import { StoreNodeItemType } from '../workflow/type';
|
||||||
import { DatasetSearchModeEnum } from '../dataset/constants';
|
import { DatasetSearchModeEnum } from '../dataset/constants';
|
||||||
import { defaultWhisperConfig } from './constants';
|
|
||||||
|
|
||||||
export const getDefaultAppForm = (): AppSimpleEditFormType => {
|
export const getDefaultAppForm = (): AppSimpleEditFormType => ({
|
||||||
return {
|
aiSettings: {
|
||||||
aiSettings: {
|
model: 'gpt-3.5-turbo',
|
||||||
model: 'gpt-3.5-turbo',
|
systemPrompt: '',
|
||||||
systemPrompt: '',
|
temperature: 0,
|
||||||
temperature: 0,
|
isResponseAnswerText: true,
|
||||||
isResponseAnswerText: true,
|
maxHistories: 6,
|
||||||
maxHistories: 6,
|
maxToken: 4000
|
||||||
maxToken: 4000
|
},
|
||||||
},
|
dataset: {
|
||||||
dataset: {
|
datasets: [],
|
||||||
datasets: [],
|
similarity: 0.4,
|
||||||
similarity: 0.4,
|
limit: 1500,
|
||||||
limit: 1500,
|
searchMode: DatasetSearchModeEnum.embedding,
|
||||||
searchMode: DatasetSearchModeEnum.embedding,
|
usingReRank: false,
|
||||||
usingReRank: false,
|
datasetSearchUsingExtensionQuery: true,
|
||||||
datasetSearchUsingExtensionQuery: true,
|
datasetSearchExtensionBg: ''
|
||||||
datasetSearchExtensionBg: ''
|
},
|
||||||
},
|
selectedTools: [],
|
||||||
selectedTools: [],
|
chatConfig: {}
|
||||||
userGuide: {
|
});
|
||||||
welcomeText: '',
|
|
||||||
variables: [],
|
|
||||||
questionGuide: false,
|
|
||||||
tts: {
|
|
||||||
type: 'web'
|
|
||||||
},
|
|
||||||
whisper: defaultWhisperConfig,
|
|
||||||
scheduleTrigger: null
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/* format app nodes to edit form */
|
/* format app nodes to edit form */
|
||||||
export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
|
export const appWorkflow2Form = ({
|
||||||
|
nodes,
|
||||||
|
chatConfig
|
||||||
|
}: {
|
||||||
|
nodes: StoreNodeItemType[];
|
||||||
|
chatConfig: AppChatConfigType;
|
||||||
|
}) => {
|
||||||
const defaultAppForm = getDefaultAppForm();
|
const defaultAppForm = getDefaultAppForm();
|
||||||
|
|
||||||
const findInputValueByKey = (inputs: FlowNodeInputItemType[], key: string) => {
|
const findInputValueByKey = (inputs: FlowNodeInputItemType[], key: string) => {
|
||||||
return inputs.find((item) => item.key === key)?.value;
|
return inputs.find((item) => item.key === key)?.value;
|
||||||
};
|
};
|
||||||
@@ -102,24 +95,6 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
|
|||||||
node.inputs,
|
node.inputs,
|
||||||
NodeInputKeyEnum.datasetSearchExtensionBg
|
NodeInputKeyEnum.datasetSearchExtensionBg
|
||||||
);
|
);
|
||||||
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
|
|
||||||
const {
|
|
||||||
welcomeText,
|
|
||||||
variableNodes,
|
|
||||||
questionGuide,
|
|
||||||
ttsConfig,
|
|
||||||
whisperConfig,
|
|
||||||
scheduledTriggerConfig
|
|
||||||
} = splitGuideModule(getGuideModule(nodes));
|
|
||||||
|
|
||||||
defaultAppForm.userGuide = {
|
|
||||||
welcomeText: welcomeText,
|
|
||||||
variables: variableNodes,
|
|
||||||
questionGuide: questionGuide,
|
|
||||||
tts: ttsConfig,
|
|
||||||
whisper: whisperConfig,
|
|
||||||
scheduleTrigger: scheduledTriggerConfig
|
|
||||||
};
|
|
||||||
} else if (node.flowNodeType === FlowNodeTypeEnum.pluginModule) {
|
} else if (node.flowNodeType === FlowNodeTypeEnum.pluginModule) {
|
||||||
if (!node.pluginId) return;
|
if (!node.pluginId) return;
|
||||||
|
|
||||||
@@ -131,10 +106,17 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
|
|||||||
intro: node.intro || '',
|
intro: node.intro || '',
|
||||||
flowNodeType: node.flowNodeType,
|
flowNodeType: node.flowNodeType,
|
||||||
showStatus: node.showStatus,
|
showStatus: node.showStatus,
|
||||||
|
version: '481',
|
||||||
inputs: node.inputs,
|
inputs: node.inputs,
|
||||||
outputs: node.outputs,
|
outputs: node.outputs,
|
||||||
templateType: FlowNodeTemplateTypeEnum.other
|
templateType: FlowNodeTemplateTypeEnum.other
|
||||||
});
|
});
|
||||||
|
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
|
||||||
|
defaultAppForm.chatConfig = getAppChatConfig({
|
||||||
|
chatConfig,
|
||||||
|
systemConfigNode: node,
|
||||||
|
isPublicFetch: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
2
packages/global/core/app/version.d.ts
vendored
2
packages/global/core/app/version.d.ts
vendored
@@ -1,5 +1,6 @@
|
|||||||
import { StoreNodeItemType } from '../workflow/type';
|
import { StoreNodeItemType } from '../workflow/type';
|
||||||
import { StoreEdgeItemType } from '../workflow/type/edge';
|
import { StoreEdgeItemType } from '../workflow/type/edge';
|
||||||
|
import { AppChatConfigType } from './type';
|
||||||
|
|
||||||
export type AppVersionSchemaType = {
|
export type AppVersionSchemaType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
@@ -7,4 +8,5 @@ export type AppVersionSchemaType = {
|
|||||||
time: Date;
|
time: Date;
|
||||||
nodes: StoreNodeItemType[];
|
nodes: StoreNodeItemType[];
|
||||||
edges: StoreEdgeItemType[];
|
edges: StoreEdgeItemType[];
|
||||||
|
chatConfig: AppChatConfigType;
|
||||||
};
|
};
|
||||||
|
|||||||
5
packages/global/core/chat/inputGuide/type.d.ts
vendored
Normal file
5
packages/global/core/chat/inputGuide/type.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export type ChatInputGuideSchemaType = {
|
||||||
|
_id: string;
|
||||||
|
appId: string;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
4
packages/global/core/chat/type.d.ts
vendored
4
packages/global/core/chat/type.d.ts
vendored
@@ -10,7 +10,7 @@ import {
|
|||||||
import { FlowNodeTypeEnum } from '../workflow/node/constant';
|
import { FlowNodeTypeEnum } from '../workflow/node/constant';
|
||||||
import { NodeOutputKeyEnum } from '../workflow/constants';
|
import { NodeOutputKeyEnum } from '../workflow/constants';
|
||||||
import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
|
import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
|
||||||
import { 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 { ChatBoxInputType } from '../../../../projects/app/src/components/ChatBox/type';
|
||||||
@@ -139,7 +139,7 @@ export type ChatHistoryItemType = HistoryItemType & {
|
|||||||
/* ------- response data ------------ */
|
/* ------- response data ------------ */
|
||||||
export type ChatHistoryItemResType = DispatchNodeResponseType & {
|
export type ChatHistoryItemResType = DispatchNodeResponseType & {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
moduleType: `${FlowNodeTypeEnum}`;
|
moduleType: FlowNodeTypeEnum;
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
24
packages/global/core/dataset/api.d.ts
vendored
24
packages/global/core/dataset/api.d.ts
vendored
@@ -11,31 +11,42 @@ export type DatasetUpdateBody = {
|
|||||||
intro?: string;
|
intro?: string;
|
||||||
permission?: DatasetSchemaType['permission'];
|
permission?: DatasetSchemaType['permission'];
|
||||||
agentModel?: LLMModelItemType;
|
agentModel?: LLMModelItemType;
|
||||||
websiteConfig?: DatasetSchemaType['websiteConfig'];
|
|
||||||
status?: DatasetSchemaType['status'];
|
status?: DatasetSchemaType['status'];
|
||||||
|
|
||||||
|
websiteConfig?: DatasetSchemaType['websiteConfig'];
|
||||||
|
externalReadUrl?: DatasetSchemaType['externalReadUrl'];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ================= collection ===================== */
|
/* ================= collection ===================== */
|
||||||
export type DatasetCollectionChunkMetadataType = {
|
export type DatasetCollectionChunkMetadataType = {
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
trainingType?: `${TrainingModeEnum}`;
|
trainingType?: TrainingModeEnum;
|
||||||
chunkSize?: number;
|
chunkSize?: number;
|
||||||
chunkSplitter?: string;
|
chunkSplitter?: string;
|
||||||
qaPrompt?: string;
|
qaPrompt?: string;
|
||||||
metadata?: Record<string, any>;
|
metadata?: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// create collection params
|
||||||
export type CreateDatasetCollectionParams = DatasetCollectionChunkMetadataType & {
|
export type CreateDatasetCollectionParams = DatasetCollectionChunkMetadataType & {
|
||||||
datasetId: string;
|
datasetId: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: `${DatasetCollectionTypeEnum}`;
|
type: DatasetCollectionTypeEnum;
|
||||||
|
|
||||||
|
tags?: string[];
|
||||||
|
|
||||||
fileId?: string;
|
fileId?: string;
|
||||||
rawLink?: string;
|
rawLink?: string;
|
||||||
|
externalFileId?: string;
|
||||||
|
|
||||||
|
externalFileUrl?: string;
|
||||||
rawTextLength?: number;
|
rawTextLength?: number;
|
||||||
hashRawText?: string;
|
hashRawText?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ApiCreateDatasetCollectionParams = DatasetCollectionChunkMetadataType & {
|
export type ApiCreateDatasetCollectionParams = DatasetCollectionChunkMetadataType & {
|
||||||
datasetId: string;
|
datasetId: string;
|
||||||
|
tags?: string[];
|
||||||
};
|
};
|
||||||
export type TextCreateDatasetCollectionParams = ApiCreateDatasetCollectionParams & {
|
export type TextCreateDatasetCollectionParams = ApiCreateDatasetCollectionParams & {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -56,6 +67,11 @@ export type CsvTableCreateDatasetCollectionParams = {
|
|||||||
parentId?: string;
|
parentId?: string;
|
||||||
fileId: string;
|
fileId: string;
|
||||||
};
|
};
|
||||||
|
export type ExternalFileCreateDatasetCollectionParams = ApiCreateDatasetCollectionParams & {
|
||||||
|
externalFileId?: string;
|
||||||
|
externalFileUrl: string;
|
||||||
|
filename?: string;
|
||||||
|
};
|
||||||
|
|
||||||
/* ================= data ===================== */
|
/* ================= data ===================== */
|
||||||
export type PgSearchRawType = {
|
export type PgSearchRawType = {
|
||||||
@@ -78,7 +94,7 @@ export type PostWebsiteSyncParams = {
|
|||||||
export type PushDatasetDataProps = {
|
export type PushDatasetDataProps = {
|
||||||
collectionId: string;
|
collectionId: string;
|
||||||
data: PushDatasetDataChunkProps[];
|
data: PushDatasetDataChunkProps[];
|
||||||
trainingMode: `${TrainingModeEnum}`;
|
trainingMode: TrainingModeEnum;
|
||||||
prompt?: string;
|
prompt?: string;
|
||||||
billId?: string;
|
billId?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
6
packages/global/core/dataset/collection/constants.ts
Normal file
6
packages/global/core/dataset/collection/constants.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/* sourceId = prefix-id; id=fileId;link url;externalFileId */
|
||||||
|
export enum CollectionSourcePrefixEnum {
|
||||||
|
local = 'local',
|
||||||
|
link = 'link',
|
||||||
|
external = 'external'
|
||||||
|
}
|
||||||
14
packages/global/core/dataset/collection/utils.ts
Normal file
14
packages/global/core/dataset/collection/utils.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { CollectionWithDatasetType, DatasetCollectionSchemaType } from '../type';
|
||||||
|
|
||||||
|
export const getCollectionSourceData = (
|
||||||
|
collection?: CollectionWithDatasetType | DatasetCollectionSchemaType
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
sourceId:
|
||||||
|
collection?.fileId ||
|
||||||
|
collection?.rawLink ||
|
||||||
|
collection?.externalFileId ||
|
||||||
|
collection?.externalFileUrl,
|
||||||
|
sourceName: collection?.name || ''
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -2,23 +2,29 @@
|
|||||||
export enum DatasetTypeEnum {
|
export enum DatasetTypeEnum {
|
||||||
folder = 'folder',
|
folder = 'folder',
|
||||||
dataset = 'dataset',
|
dataset = 'dataset',
|
||||||
websiteDataset = 'websiteDataset' // depp link
|
websiteDataset = 'websiteDataset', // depp link
|
||||||
|
externalFile = 'externalFile'
|
||||||
}
|
}
|
||||||
export const DatasetTypeMap = {
|
export const DatasetTypeMap = {
|
||||||
[DatasetTypeEnum.folder]: {
|
[DatasetTypeEnum.folder]: {
|
||||||
icon: 'common/folderFill',
|
icon: 'common/folderFill',
|
||||||
label: 'core.dataset.Folder Dataset',
|
label: 'Folder Dataset',
|
||||||
collectionLabel: 'common.Folder'
|
collectionLabel: 'common.Folder'
|
||||||
},
|
},
|
||||||
[DatasetTypeEnum.dataset]: {
|
[DatasetTypeEnum.dataset]: {
|
||||||
icon: 'core/dataset/commonDataset',
|
icon: 'core/dataset/commonDataset',
|
||||||
label: 'core.dataset.Common Dataset',
|
label: 'Common Dataset',
|
||||||
collectionLabel: 'common.File'
|
collectionLabel: 'common.File'
|
||||||
},
|
},
|
||||||
[DatasetTypeEnum.websiteDataset]: {
|
[DatasetTypeEnum.websiteDataset]: {
|
||||||
icon: 'core/dataset/websiteDataset',
|
icon: 'core/dataset/websiteDataset',
|
||||||
label: 'core.dataset.Website Dataset',
|
label: 'Website Dataset',
|
||||||
collectionLabel: 'common.Website'
|
collectionLabel: 'common.Website'
|
||||||
|
},
|
||||||
|
[DatasetTypeEnum.externalFile]: {
|
||||||
|
icon: 'core/dataset/externalDataset',
|
||||||
|
label: 'External File',
|
||||||
|
collectionLabel: 'common.File'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,9 +44,11 @@ export const DatasetStatusMap = {
|
|||||||
/* ------------ collection -------------- */
|
/* ------------ collection -------------- */
|
||||||
export enum DatasetCollectionTypeEnum {
|
export enum DatasetCollectionTypeEnum {
|
||||||
folder = 'folder',
|
folder = 'folder',
|
||||||
|
virtual = 'virtual',
|
||||||
|
|
||||||
file = 'file',
|
file = 'file',
|
||||||
link = 'link', // one link
|
link = 'link', // one link
|
||||||
virtual = 'virtual'
|
externalFile = 'externalFile'
|
||||||
}
|
}
|
||||||
export const DatasetCollectionTypeMap = {
|
export const DatasetCollectionTypeMap = {
|
||||||
[DatasetCollectionTypeEnum.folder]: {
|
[DatasetCollectionTypeEnum.folder]: {
|
||||||
@@ -49,6 +57,9 @@ export const DatasetCollectionTypeMap = {
|
|||||||
[DatasetCollectionTypeEnum.file]: {
|
[DatasetCollectionTypeEnum.file]: {
|
||||||
name: 'core.dataset.file'
|
name: 'core.dataset.file'
|
||||||
},
|
},
|
||||||
|
[DatasetCollectionTypeEnum.externalFile]: {
|
||||||
|
name: 'core.dataset.externalFile'
|
||||||
|
},
|
||||||
[DatasetCollectionTypeEnum.link]: {
|
[DatasetCollectionTypeEnum.link]: {
|
||||||
name: 'core.dataset.link'
|
name: 'core.dataset.link'
|
||||||
},
|
},
|
||||||
@@ -77,7 +88,8 @@ export enum ImportDataSourceEnum {
|
|||||||
fileLocal = 'fileLocal',
|
fileLocal = 'fileLocal',
|
||||||
fileLink = 'fileLink',
|
fileLink = 'fileLink',
|
||||||
fileCustom = 'fileCustom',
|
fileCustom = 'fileCustom',
|
||||||
csvTable = 'csvTable'
|
csvTable = 'csvTable',
|
||||||
|
externalFile = 'externalFile'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TrainingModeEnum {
|
export enum TrainingModeEnum {
|
||||||
@@ -163,3 +175,10 @@ export const SearchScoreTypeMap = {
|
|||||||
|
|
||||||
export const CustomCollectionIcon = 'common/linkBlue';
|
export const CustomCollectionIcon = 'common/linkBlue';
|
||||||
export const LinkCollectionIcon = 'common/linkBlue';
|
export const LinkCollectionIcon = 'common/linkBlue';
|
||||||
|
|
||||||
|
/* source prefix */
|
||||||
|
export enum DatasetSourceReadTypeEnum {
|
||||||
|
fileLocal = 'fileLocal',
|
||||||
|
link = 'link',
|
||||||
|
externalFile = 'externalFile'
|
||||||
|
}
|
||||||
|
|||||||
14
packages/global/core/dataset/read.ts
Normal file
14
packages/global/core/dataset/read.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { DatasetSourceReadTypeEnum, ImportDataSourceEnum } from './constants';
|
||||||
|
|
||||||
|
export const importType2ReadType = (type: ImportDataSourceEnum) => {
|
||||||
|
if (type === ImportDataSourceEnum.csvTable || type === ImportDataSourceEnum.fileLocal) {
|
||||||
|
return DatasetSourceReadTypeEnum.fileLocal;
|
||||||
|
}
|
||||||
|
if (type === ImportDataSourceEnum.fileLink) {
|
||||||
|
return DatasetSourceReadTypeEnum.link;
|
||||||
|
}
|
||||||
|
if (type === ImportDataSourceEnum.externalFile) {
|
||||||
|
return DatasetSourceReadTypeEnum.externalFile;
|
||||||
|
}
|
||||||
|
return DatasetSourceReadTypeEnum.link;
|
||||||
|
};
|
||||||
29
packages/global/core/dataset/type.d.ts
vendored
29
packages/global/core/dataset/type.d.ts
vendored
@@ -22,13 +22,16 @@ export type DatasetSchemaType = {
|
|||||||
vectorModel: string;
|
vectorModel: string;
|
||||||
agentModel: string;
|
agentModel: string;
|
||||||
intro: string;
|
intro: string;
|
||||||
type: `${DatasetTypeEnum}`;
|
type: DatasetTypeEnum;
|
||||||
status: `${DatasetStatusEnum}`;
|
status: `${DatasetStatusEnum}`;
|
||||||
permission: `${PermissionTypeEnum}`;
|
permission: `${PermissionTypeEnum}`;
|
||||||
|
|
||||||
|
// metadata
|
||||||
websiteConfig?: {
|
websiteConfig?: {
|
||||||
url: string;
|
url: string;
|
||||||
selector: string;
|
selector: string;
|
||||||
};
|
};
|
||||||
|
externalReadUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DatasetCollectionSchemaType = {
|
export type DatasetCollectionSchemaType = {
|
||||||
@@ -38,20 +41,24 @@ export type DatasetCollectionSchemaType = {
|
|||||||
datasetId: string;
|
datasetId: string;
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: `${DatasetCollectionTypeEnum}`;
|
type: DatasetCollectionTypeEnum;
|
||||||
createTime: Date;
|
createTime: Date;
|
||||||
updateTime: Date;
|
updateTime: Date;
|
||||||
|
|
||||||
trainingType: `${TrainingModeEnum}`;
|
trainingType: TrainingModeEnum;
|
||||||
chunkSize: number;
|
chunkSize: number;
|
||||||
chunkSplitter?: string;
|
chunkSplitter?: string;
|
||||||
qaPrompt?: string;
|
qaPrompt?: string;
|
||||||
|
|
||||||
fileId?: string;
|
tags?: string[];
|
||||||
rawLink?: string;
|
|
||||||
|
fileId?: string; // local file id
|
||||||
|
rawLink?: string; // link url
|
||||||
|
externalFileId?: string; //external file id
|
||||||
|
|
||||||
rawTextLength?: number;
|
rawTextLength?: number;
|
||||||
hashRawText?: string;
|
hashRawText?: string;
|
||||||
|
externalFileUrl?: string; // external import url
|
||||||
metadata?: {
|
metadata?: {
|
||||||
webPageSelector?: string;
|
webPageSelector?: string;
|
||||||
relatedImgId?: string; // The id of the associated image collections
|
relatedImgId?: string; // The id of the associated image collections
|
||||||
@@ -80,6 +87,7 @@ export type DatasetDataSchemaType = {
|
|||||||
a: string; // answer or custom content
|
a: string; // answer or custom content
|
||||||
fullTextToken: string;
|
fullTextToken: string;
|
||||||
indexes: DatasetDataIndexItemType[];
|
indexes: DatasetDataIndexItemType[];
|
||||||
|
rebuilding?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DatasetTrainingSchemaType = {
|
export type DatasetTrainingSchemaType = {
|
||||||
@@ -92,9 +100,10 @@ export type DatasetTrainingSchemaType = {
|
|||||||
billId: string;
|
billId: string;
|
||||||
expireAt: Date;
|
expireAt: Date;
|
||||||
lockTime: Date;
|
lockTime: Date;
|
||||||
mode: `${TrainingModeEnum}`;
|
mode: TrainingModeEnum;
|
||||||
model: string;
|
model: string;
|
||||||
prompt: string;
|
prompt: string;
|
||||||
|
dataId?: string;
|
||||||
q: string;
|
q: string;
|
||||||
a: string;
|
a: string;
|
||||||
chunkIndex: number;
|
chunkIndex: number;
|
||||||
@@ -110,13 +119,19 @@ export type DatasetDataWithCollectionType = Omit<DatasetDataSchemaType, 'collect
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* ================= dataset ===================== */
|
/* ================= dataset ===================== */
|
||||||
|
export type DatasetSimpleItemType = {
|
||||||
|
_id: string;
|
||||||
|
avatar: string;
|
||||||
|
name: string;
|
||||||
|
vectorModel: VectorModelItemType;
|
||||||
|
};
|
||||||
export type DatasetListItemType = {
|
export type DatasetListItemType = {
|
||||||
_id: string;
|
_id: string;
|
||||||
parentId: string;
|
parentId: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
name: string;
|
name: string;
|
||||||
intro: string;
|
intro: string;
|
||||||
type: `${DatasetTypeEnum}`;
|
type: DatasetTypeEnum;
|
||||||
isOwner: boolean;
|
isOwner: boolean;
|
||||||
canWrite: boolean;
|
canWrite: boolean;
|
||||||
permission: `${PermissionTypeEnum}`;
|
permission: `${PermissionTypeEnum}`;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { getFileIcon } from '../../common/file/icon';
|
|||||||
import { strIsLink } from '../../common/string/tools';
|
import { strIsLink } from '../../common/string/tools';
|
||||||
|
|
||||||
export function getCollectionIcon(
|
export function getCollectionIcon(
|
||||||
type: `${DatasetCollectionTypeEnum}` = DatasetCollectionTypeEnum.file,
|
type: DatasetCollectionTypeEnum = DatasetCollectionTypeEnum.file,
|
||||||
name = ''
|
name = ''
|
||||||
) {
|
) {
|
||||||
if (type === DatasetCollectionTypeEnum.folder) {
|
if (type === DatasetCollectionTypeEnum.folder) {
|
||||||
@@ -24,13 +24,13 @@ export function getSourceNameIcon({
|
|||||||
sourceName: string;
|
sourceName: string;
|
||||||
sourceId?: string;
|
sourceId?: string;
|
||||||
}) {
|
}) {
|
||||||
if (strIsLink(sourceId)) {
|
const fileIcon = getFileIcon(decodeURIComponent(sourceName), '');
|
||||||
return 'common/linkBlue';
|
|
||||||
}
|
|
||||||
const fileIcon = getFileIcon(sourceName, '');
|
|
||||||
if (fileIcon) {
|
if (fileIcon) {
|
||||||
return fileIcon;
|
return fileIcon;
|
||||||
}
|
}
|
||||||
|
if (strIsLink(sourceId)) {
|
||||||
|
return 'common/linkBlue';
|
||||||
|
}
|
||||||
|
|
||||||
return 'file/fill/manual';
|
return 'file/fill/manual';
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ export function getDefaultIndex(props?: { q?: string; a?: string; dataId?: strin
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const predictDataLimitLength = (mode: `${TrainingModeEnum}`, data: any[]) => {
|
export const predictDataLimitLength = (mode: TrainingModeEnum, data: any[]) => {
|
||||||
if (mode === TrainingModeEnum.qa) return data.length * 20;
|
if (mode === TrainingModeEnum.qa) return data.length * 20;
|
||||||
if (mode === TrainingModeEnum.auto) return data.length * 5;
|
if (mode === TrainingModeEnum.auto) return data.length * 5;
|
||||||
return data.length;
|
return data.length;
|
||||||
|
|||||||
@@ -282,6 +282,7 @@ export const httpApiSchema2Plugins = async ({
|
|||||||
x: 616.4226348688949,
|
x: 616.4226348688949,
|
||||||
y: -165.05298493910115
|
y: -165.05298493910115
|
||||||
},
|
},
|
||||||
|
version: PluginInputModule.version,
|
||||||
inputs: pluginInputs,
|
inputs: pluginInputs,
|
||||||
outputs: pluginOutputs
|
outputs: pluginOutputs
|
||||||
},
|
},
|
||||||
@@ -296,6 +297,7 @@ export const httpApiSchema2Plugins = async ({
|
|||||||
x: 1607.7142331269126,
|
x: 1607.7142331269126,
|
||||||
y: -151.8669210746189
|
y: -151.8669210746189
|
||||||
},
|
},
|
||||||
|
version: PluginOutputModule.version,
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
key: pluginOutputKey,
|
key: pluginOutputKey,
|
||||||
@@ -334,6 +336,7 @@ export const httpApiSchema2Plugins = async ({
|
|||||||
x: 1042.549746602742,
|
x: 1042.549746602742,
|
||||||
y: -447.77496332641647
|
y: -447.77496332641647
|
||||||
},
|
},
|
||||||
|
version: HttpModule468.version,
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.addInputParam,
|
key: NodeInputKeyEnum.addInputParam,
|
||||||
|
|||||||
2
packages/global/core/plugin/type.d.ts
vendored
2
packages/global/core/plugin/type.d.ts
vendored
@@ -23,6 +23,7 @@ export type PluginItemSchema = {
|
|||||||
customHeaders?: string;
|
customHeaders?: string;
|
||||||
};
|
};
|
||||||
version?: 'v1' | 'v2';
|
version?: 'v1' | 'v2';
|
||||||
|
nodeVersion?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* plugin template */
|
/* plugin template */
|
||||||
@@ -32,6 +33,7 @@ export type PluginTemplateType = PluginRuntimeType & {
|
|||||||
source: `${PluginSourceEnum}`;
|
source: `${PluginSourceEnum}`;
|
||||||
templateType: FlowNodeTemplateType['templateType'];
|
templateType: FlowNodeTemplateType['templateType'];
|
||||||
intro: string;
|
intro: string;
|
||||||
|
nodeVersion: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PluginRuntimeType = {
|
export type PluginRuntimeType = {
|
||||||
|
|||||||
2
packages/global/core/workflow/api.d.ts
vendored
2
packages/global/core/workflow/api.d.ts
vendored
@@ -1,7 +1,7 @@
|
|||||||
import { VectorModelItemType } from '../ai/model.d';
|
import { VectorModelItemType } from '../ai/model.d';
|
||||||
import { NodeInputKeyEnum } from './constants';
|
import { NodeInputKeyEnum } from './constants';
|
||||||
|
|
||||||
export type SelectedDatasetType = { datasetId: string; vectorModel: VectorModelItemType }[];
|
export type SelectedDatasetType = { datasetId: string }[];
|
||||||
|
|
||||||
export type HttpBodyType<T = Record<string, any>> = {
|
export type HttpBodyType<T = Record<string, any>> = {
|
||||||
[NodeInputKeyEnum.addInputParam]: Record<string, any>;
|
[NodeInputKeyEnum.addInputParam]: Record<string, any>;
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export enum NodeInputKeyEnum {
|
|||||||
whisper = 'whisper',
|
whisper = 'whisper',
|
||||||
variables = 'variables',
|
variables = 'variables',
|
||||||
scheduleTrigger = 'scheduleTrigger',
|
scheduleTrigger = 'scheduleTrigger',
|
||||||
|
chatInputGuide = 'chatInputGuide',
|
||||||
|
|
||||||
// entry
|
// entry
|
||||||
userChatInput = 'userChatInput',
|
userChatInput = 'userChatInput',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ChatCompletionRequestMessageRoleEnum } from '../../ai/constants';
|
import { ChatCompletionRequestMessageRoleEnum } from '../../ai/constants';
|
||||||
import { NodeOutputKeyEnum } from '../constants';
|
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '../constants';
|
||||||
import { FlowNodeTypeEnum } from '../node/constant';
|
import { FlowNodeTypeEnum } from '../node/constant';
|
||||||
import { StoreNodeItemType } from '../type';
|
import { StoreNodeItemType } from '../type';
|
||||||
import { StoreEdgeItemType } from '../type/edge';
|
import { StoreEdgeItemType } from '../type/edge';
|
||||||
@@ -8,6 +8,23 @@ import { VARIABLE_NODE_ID } from '../constants';
|
|||||||
import { isReferenceValue } from '../utils';
|
import { isReferenceValue } from '../utils';
|
||||||
import { ReferenceValueProps } from '../type/io';
|
import { ReferenceValueProps } from '../type/io';
|
||||||
|
|
||||||
|
export const getMaxHistoryLimitFromNodes = (nodes: StoreNodeItemType[]): number => {
|
||||||
|
let limit = 10;
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
node.inputs.forEach((input) => {
|
||||||
|
if (
|
||||||
|
(input.key === NodeInputKeyEnum.history ||
|
||||||
|
input.key === NodeInputKeyEnum.historyMaxAmount) &&
|
||||||
|
typeof input.value === 'number'
|
||||||
|
) {
|
||||||
|
limit = Math.max(limit, input.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return limit * 2;
|
||||||
|
};
|
||||||
|
|
||||||
export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeItemType[] => {
|
export const initWorkflowEdgeStatus = (edges: StoreEdgeItemType[]): RuntimeEdgeItemType[] => {
|
||||||
return (
|
return (
|
||||||
edges?.map((edge) => ({
|
edges?.map((edge) => ({
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export const AiChatModule: FlowNodeTemplateType = {
|
|||||||
intro: 'AI 大模型对话',
|
intro: 'AI 大模型对话',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
isTool: true,
|
isTool: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
Input_Template_SettingAiModel,
|
Input_Template_SettingAiModel,
|
||||||
// --- settings modal
|
// --- settings modal
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export const AssignedAnswerModule: FlowNodeTemplateType = {
|
|||||||
name: '指定回复',
|
name: '指定回复',
|
||||||
intro:
|
intro:
|
||||||
'该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。',
|
'该模块可以直接回复一段指定的内容。常用于引导、提示。非字符串内容传入时,会转成字符串进行输出。',
|
||||||
|
version: '481',
|
||||||
|
isTool: true,
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.answerText,
|
key: NodeInputKeyEnum.answerText,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
|
|||||||
name: '问题分类',
|
name: '问题分类',
|
||||||
intro: `根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题`,
|
intro: `根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于商品“使用”问题\n类型3: 关于商品“购买”问题\n类型4: 其他问题`,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
...Input_Template_SelectAIModel,
|
...Input_Template_SelectAIModel,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export const ContextExtractModule: FlowNodeTemplateType = {
|
|||||||
intro: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等',
|
intro: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
isTool: true,
|
isTool: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
...Input_Template_SelectAIModel,
|
...Input_Template_SelectAIModel,
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
|
|||||||
name: '知识库搜索引用合并',
|
name: '知识库搜索引用合并',
|
||||||
intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。',
|
intro: '可以将多个知识库搜索结果进行合并输出。使用 RRF 的合并方式进行最终排序输出。',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.datasetMaxTokens,
|
key: NodeInputKeyEnum.datasetMaxTokens,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
|
|||||||
intro: Dataset_SEARCH_DESC,
|
intro: Dataset_SEARCH_DESC,
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
isTool: true,
|
isTool: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.datasetSelectList,
|
key: NodeInputKeyEnum.datasetSelectList,
|
||||||
@@ -35,7 +36,6 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
|
|||||||
label: 'core.module.input.label.Select dataset',
|
label: 'core.module.input.label.Select dataset',
|
||||||
value: [],
|
value: [],
|
||||||
valueType: WorkflowIOValueTypeEnum.selectDataset,
|
valueType: WorkflowIOValueTypeEnum.selectDataset,
|
||||||
list: [],
|
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export const EmptyNode: FlowNodeTemplateType = {
|
|||||||
avatar: '',
|
avatar: '',
|
||||||
name: '',
|
name: '',
|
||||||
intro: '',
|
intro: '',
|
||||||
|
version: '481',
|
||||||
inputs: [],
|
inputs: [],
|
||||||
outputs: []
|
outputs: []
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import { FlowNodeTemplateTypeEnum, WorkflowIOValueTypeEnum } from '../../constants';
|
|
||||||
import { getHandleConfig } from '../utils';
|
|
||||||
import { FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
|
|
||||||
import { VariableItemType } from '../../../app/type';
|
|
||||||
import { FlowNodeTemplateType } from '../../type';
|
|
||||||
|
|
||||||
export const getGlobalVariableNode = ({
|
|
||||||
id,
|
|
||||||
variables
|
|
||||||
}: {
|
|
||||||
id: string;
|
|
||||||
variables: VariableItemType[];
|
|
||||||
}): FlowNodeTemplateType => {
|
|
||||||
return {
|
|
||||||
id,
|
|
||||||
templateType: FlowNodeTemplateTypeEnum.other,
|
|
||||||
flowNodeType: FlowNodeTypeEnum.systemConfig,
|
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
|
||||||
avatar: '/imgs/workflow/variable.png',
|
|
||||||
name: '全局变量',
|
|
||||||
intro: '',
|
|
||||||
inputs: [],
|
|
||||||
outputs: variables.map((item) => ({
|
|
||||||
id: item.key,
|
|
||||||
key: item.key,
|
|
||||||
valueType: WorkflowIOValueTypeEnum.string,
|
|
||||||
type: FlowNodeOutputTypeEnum.static,
|
|
||||||
label: item.label
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -25,6 +25,7 @@ export const HttpModule468: FlowNodeTemplateType = {
|
|||||||
intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
|
intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
isTool: true,
|
isTool: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
...Input_Template_DynamicInput,
|
...Input_Template_DynamicInput,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export const IfElseNode: FlowNodeTemplateType = {
|
|||||||
name: '判断器',
|
name: '判断器',
|
||||||
intro: '根据一定的条件,执行不同的分支。',
|
intro: '根据一定的条件,执行不同的分支。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.ifElseList,
|
key: NodeInputKeyEnum.ifElseList,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export const LafModule: FlowNodeTemplateType = {
|
|||||||
intro: '可以调用Laf账号下的云函数。',
|
intro: '可以调用Laf账号下的云函数。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
isTool: true,
|
isTool: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
...Input_Template_DynamicInput,
|
...Input_Template_DynamicInput,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const PluginInputModule: FlowNodeTemplateType = {
|
|||||||
name: '自定义插件输入',
|
name: '自定义插件输入',
|
||||||
intro: '自定义配置外部输入,使用插件时,仅暴露自定义配置的输入',
|
intro: '自定义配置外部输入,使用插件时,仅暴露自定义配置的输入',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
|
version: '481',
|
||||||
inputs: [],
|
inputs: [],
|
||||||
outputs: []
|
outputs: []
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const PluginOutputModule: FlowNodeTemplateType = {
|
|||||||
name: '自定义插件输出',
|
name: '自定义插件输出',
|
||||||
intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出',
|
intro: '自定义配置外部输出,使用插件时,仅暴露自定义配置的输出',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
|
version: '481',
|
||||||
inputs: [],
|
inputs: [],
|
||||||
outputs: []
|
outputs: []
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export const AiQueryExtension: FlowNodeTemplateType = {
|
|||||||
intro:
|
intro:
|
||||||
'使用问题优化功能,可以提高知识库连续对话时搜索的精度。使用该功能后,会先利用 AI 根据上下文构建一个或多个新的检索词,这些检索词更利于进行知识库搜索。该模块已内置在知识库搜索模块中,如果您仅进行一次知识库搜索,可直接使用知识库内置的补全功能。',
|
'使用问题优化功能,可以提高知识库连续对话时搜索的精度。使用该功能后,会先利用 AI 根据上下文构建一个或多个新的检索词,这些检索词更利于进行知识库搜索。该模块已内置在知识库搜索模块中,如果您仅进行一次知识库搜索,可直接使用知识库内置的补全功能。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
...Input_Template_SelectAIModel,
|
...Input_Template_SelectAIModel,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export const RunAppModule: FlowNodeTemplateType = {
|
|||||||
name: '应用调用',
|
name: '应用调用',
|
||||||
intro: '可以选择一个其他应用进行调用',
|
intro: '可以选择一个其他应用进行调用',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.runAppSelectApp,
|
key: NodeInputKeyEnum.runAppSelectApp,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export const RunPluginModule: FlowNodeTemplateType = {
|
|||||||
name: '',
|
name: '',
|
||||||
showStatus: false,
|
showStatus: false,
|
||||||
isTool: true,
|
isTool: true,
|
||||||
|
version: '481',
|
||||||
inputs: [], // [{key:'pluginId'},...]
|
inputs: [], // [{key:'pluginId'},...]
|
||||||
outputs: []
|
outputs: []
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export const StopToolNode: FlowNodeTemplateType = {
|
|||||||
name: '工具调用终止',
|
name: '工具调用终止',
|
||||||
intro:
|
intro:
|
||||||
'该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。',
|
'该模块需配置工具调用使用。当该模块被执行时,本次工具调用将会强制结束,并且不再调用AI针对工具调用结果回答问题。',
|
||||||
|
version: '481',
|
||||||
inputs: [],
|
inputs: [],
|
||||||
outputs: []
|
outputs: []
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
|
import { FlowNodeTypeEnum } from '../../node/constant';
|
||||||
import { FlowNodeTemplateType } from '../../type/index.d';
|
import { FlowNodeTemplateType } from '../../type/index.d';
|
||||||
import {
|
import { FlowNodeTemplateTypeEnum, WorkflowIOValueTypeEnum } from '../../constants';
|
||||||
WorkflowIOValueTypeEnum,
|
|
||||||
NodeInputKeyEnum,
|
|
||||||
FlowNodeTemplateTypeEnum
|
|
||||||
} from '../../constants';
|
|
||||||
import { getHandleConfig } from '../utils';
|
import { getHandleConfig } from '../utils';
|
||||||
|
|
||||||
export const SystemConfigNode: FlowNodeTemplateType = {
|
export const SystemConfigNode: FlowNodeTemplateType = {
|
||||||
@@ -18,44 +14,7 @@ export const SystemConfigNode: FlowNodeTemplateType = {
|
|||||||
intro: '可以配置应用的系统参数。',
|
intro: '可以配置应用的系统参数。',
|
||||||
unique: true,
|
unique: true,
|
||||||
forbidDelete: true,
|
forbidDelete: true,
|
||||||
inputs: [
|
version: '481',
|
||||||
{
|
inputs: [],
|
||||||
key: NodeInputKeyEnum.welcomeText,
|
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
|
||||||
valueType: WorkflowIOValueTypeEnum.string,
|
|
||||||
label: 'core.app.Welcome Text'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: NodeInputKeyEnum.variables,
|
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
|
||||||
valueType: WorkflowIOValueTypeEnum.any,
|
|
||||||
label: 'core.module.Variable',
|
|
||||||
value: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: NodeInputKeyEnum.questionGuide,
|
|
||||||
valueType: WorkflowIOValueTypeEnum.boolean,
|
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
|
||||||
label: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: NodeInputKeyEnum.tts,
|
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
|
||||||
valueType: WorkflowIOValueTypeEnum.any,
|
|
||||||
label: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: NodeInputKeyEnum.whisper,
|
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
|
||||||
valueType: WorkflowIOValueTypeEnum.any,
|
|
||||||
label: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: NodeInputKeyEnum.scheduleTrigger,
|
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
|
||||||
valueType: WorkflowIOValueTypeEnum.any,
|
|
||||||
label: ''
|
|
||||||
}
|
|
||||||
],
|
|
||||||
outputs: []
|
outputs: []
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export const ToolModule: FlowNodeTemplateType = {
|
|||||||
name: '工具调用(实验)',
|
name: '工具调用(实验)',
|
||||||
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
intro: '通过AI模型自动选择一个或多个功能块进行调用,也可以对插件进行调用。',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
...Input_Template_SettingAiModel,
|
...Input_Template_SettingAiModel,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
|
|||||||
intro: '可以更新指定节点的输出值或更新全局变量',
|
intro: '可以更新指定节点的输出值或更新全局变量',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
isTool: false,
|
isTool: false,
|
||||||
|
version: '481',
|
||||||
inputs: [
|
inputs: [
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.updateList,
|
key: NodeInputKeyEnum.updateList,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export const WorkflowStart: FlowNodeTemplateType = {
|
|||||||
intro: '',
|
intro: '',
|
||||||
forbidDelete: true,
|
forbidDelete: true,
|
||||||
unique: true,
|
unique: true,
|
||||||
|
version: '481',
|
||||||
inputs: [{ ...Input_Template_UserChatInput, toolDescription: '用户问题' }],
|
inputs: [{ ...Input_Template_UserChatInput, toolDescription: '用户问题' }],
|
||||||
outputs: [
|
outputs: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,12 +22,13 @@ import { RuntimeEdgeItemType, StoreEdgeItemType } from './edge';
|
|||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
|
|
||||||
export type FlowNodeCommonType = {
|
export type FlowNodeCommonType = {
|
||||||
flowNodeType: `${FlowNodeTypeEnum}`; // render node card
|
flowNodeType: FlowNodeTypeEnum; // render node card
|
||||||
|
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
name: string;
|
name: string;
|
||||||
intro?: string; // template list intro
|
intro?: string; // template list intro
|
||||||
showStatus?: boolean; // chatting response step status
|
showStatus?: boolean; // chatting response step status
|
||||||
|
version: string;
|
||||||
|
|
||||||
// data
|
// data
|
||||||
inputs: FlowNodeInputItemType[];
|
inputs: FlowNodeInputItemType[];
|
||||||
@@ -63,6 +64,7 @@ export type FlowNodeTemplateType = FlowNodeCommonType & {
|
|||||||
// action
|
// action
|
||||||
forbidDelete?: boolean; // forbid delete
|
forbidDelete?: boolean; // forbid delete
|
||||||
unique?: boolean;
|
unique?: boolean;
|
||||||
|
nodeVersion?: string;
|
||||||
};
|
};
|
||||||
export type FlowNodeItemType = FlowNodeTemplateType & {
|
export type FlowNodeItemType = FlowNodeTemplateType & {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './node/constant';
|
import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from './node/constant';
|
||||||
import {
|
import {
|
||||||
WorkflowIOValueTypeEnum,
|
WorkflowIOValueTypeEnum,
|
||||||
NodeInputKeyEnum,
|
NodeInputKeyEnum,
|
||||||
@@ -11,10 +11,16 @@ import type {
|
|||||||
VariableItemType,
|
VariableItemType,
|
||||||
AppTTSConfigType,
|
AppTTSConfigType,
|
||||||
AppWhisperConfigType,
|
AppWhisperConfigType,
|
||||||
AppScheduledTriggerConfigType
|
AppScheduledTriggerConfigType,
|
||||||
|
ChatInputGuideConfigType,
|
||||||
|
AppChatConfigType
|
||||||
} from '../app/type';
|
} from '../app/type';
|
||||||
import { EditorVariablePickerType } from '../../../web/components/common/Textarea/PromptEditor/type';
|
import { EditorVariablePickerType } from '../../../web/components/common/Textarea/PromptEditor/type';
|
||||||
import { defaultWhisperConfig } from '../app/constants';
|
import {
|
||||||
|
defaultChatInputGuideConfig,
|
||||||
|
defaultTTSConfig,
|
||||||
|
defaultWhisperConfig
|
||||||
|
} from '../app/constants';
|
||||||
import { IfElseResultEnum } from './template/system/ifElse/constant';
|
import { IfElseResultEnum } from './template/system/ifElse/constant';
|
||||||
|
|
||||||
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
|
export const getHandleId = (nodeId: string, type: 'source' | 'target', key: string) => {
|
||||||
@@ -22,15 +28,9 @@ export const getHandleId = (nodeId: string, type: 'source' | 'target', key: stri
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const checkInputIsReference = (input: FlowNodeInputItemType) => {
|
export const checkInputIsReference = (input: FlowNodeInputItemType) => {
|
||||||
const value = input.value;
|
if (input.renderTypeList?.[input?.selectedTypeIndex || 0] === FlowNodeInputTypeEnum.reference)
|
||||||
if (
|
|
||||||
Array.isArray(value) &&
|
|
||||||
value.length === 2 &&
|
|
||||||
typeof value[0] === 'string' &&
|
|
||||||
typeof value[1] === 'string'
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,63 +46,78 @@ export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
|
|||||||
const welcomeText: string =
|
const welcomeText: string =
|
||||||
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.welcomeText)?.value || '';
|
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.welcomeText)?.value || '';
|
||||||
|
|
||||||
const variableNodes: VariableItemType[] =
|
const variables: VariableItemType[] =
|
||||||
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value || [];
|
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value || [];
|
||||||
|
|
||||||
const questionGuide: boolean =
|
const questionGuide: boolean =
|
||||||
!!guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.questionGuide)?.value ||
|
!!guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.questionGuide)?.value ||
|
||||||
false;
|
false;
|
||||||
|
|
||||||
const ttsConfig: AppTTSConfigType = guideModules?.inputs?.find(
|
const ttsConfig: AppTTSConfigType =
|
||||||
(item) => item.key === NodeInputKeyEnum.tts
|
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.tts)?.value ||
|
||||||
)?.value || { type: 'web' };
|
defaultTTSConfig;
|
||||||
|
|
||||||
const whisperConfig: AppWhisperConfigType =
|
const whisperConfig: AppWhisperConfigType =
|
||||||
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.whisper)?.value ||
|
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.whisper)?.value ||
|
||||||
defaultWhisperConfig;
|
defaultWhisperConfig;
|
||||||
|
|
||||||
const scheduledTriggerConfig: AppScheduledTriggerConfigType | null =
|
const scheduledTriggerConfig: AppScheduledTriggerConfigType = guideModules?.inputs?.find(
|
||||||
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.scheduleTrigger)?.value ??
|
(item) => item.key === NodeInputKeyEnum.scheduleTrigger
|
||||||
null;
|
)?.value;
|
||||||
|
|
||||||
|
const chatInputGuide: ChatInputGuideConfigType =
|
||||||
|
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.chatInputGuide)?.value ||
|
||||||
|
defaultChatInputGuideConfig;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
welcomeText,
|
welcomeText,
|
||||||
variableNodes,
|
variables,
|
||||||
questionGuide,
|
questionGuide,
|
||||||
ttsConfig,
|
ttsConfig,
|
||||||
whisperConfig,
|
whisperConfig,
|
||||||
scheduledTriggerConfig
|
scheduledTriggerConfig,
|
||||||
|
chatInputGuide
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export const replaceAppChatConfig = ({
|
export const getAppChatConfig = ({
|
||||||
node,
|
chatConfig,
|
||||||
variableList,
|
systemConfigNode,
|
||||||
welcomeText
|
storeVariables,
|
||||||
|
storeWelcomeText,
|
||||||
|
isPublicFetch = false
|
||||||
}: {
|
}: {
|
||||||
node?: StoreNodeItemType;
|
chatConfig?: AppChatConfigType;
|
||||||
variableList?: VariableItemType[];
|
systemConfigNode?: StoreNodeItemType;
|
||||||
welcomeText?: string;
|
storeVariables?: VariableItemType[];
|
||||||
}): StoreNodeItemType | undefined => {
|
storeWelcomeText?: string;
|
||||||
if (!node) return;
|
isPublicFetch: boolean;
|
||||||
return {
|
}): AppChatConfigType => {
|
||||||
...node,
|
const {
|
||||||
inputs: node.inputs.map((input) => {
|
welcomeText,
|
||||||
if (input.key === NodeInputKeyEnum.variables && variableList) {
|
variables,
|
||||||
return {
|
questionGuide,
|
||||||
...input,
|
ttsConfig,
|
||||||
value: variableList
|
whisperConfig,
|
||||||
};
|
scheduledTriggerConfig,
|
||||||
}
|
chatInputGuide
|
||||||
if (input.key === NodeInputKeyEnum.welcomeText && welcomeText) {
|
} = splitGuideModule(systemConfigNode);
|
||||||
return {
|
|
||||||
...input,
|
|
||||||
value: welcomeText
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return input;
|
const config: AppChatConfigType = {
|
||||||
})
|
questionGuide,
|
||||||
|
ttsConfig,
|
||||||
|
whisperConfig,
|
||||||
|
scheduledTriggerConfig,
|
||||||
|
chatInputGuide,
|
||||||
|
...chatConfig,
|
||||||
|
variables: storeVariables ?? chatConfig?.variables ?? variables,
|
||||||
|
welcomeText: storeWelcomeText ?? chatConfig?.welcomeText ?? welcomeText
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!isPublicFetch) {
|
||||||
|
config.scheduledTriggerConfig = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getOrInitModuleInputValue = (input: FlowNodeInputItemType) => {
|
export const getOrInitModuleInputValue = (input: FlowNodeInputItemType) => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"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": "13.5.2",
|
"next": "14.2.3",
|
||||||
"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"
|
||||||
|
|||||||
@@ -20,3 +20,9 @@ export const PermissionTypeMap = {
|
|||||||
label: 'permission.Public'
|
label: 'permission.Public'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum ResourceTypeEnum {
|
||||||
|
team = 'team',
|
||||||
|
app = 'app',
|
||||||
|
dataset = 'dataset'
|
||||||
|
}
|
||||||
|
|||||||
9
packages/global/support/permission/type.d.ts
vendored
9
packages/global/support/permission/type.d.ts
vendored
@@ -1,5 +1,7 @@
|
|||||||
import { AuthUserTypeEnum } from './constant';
|
import { AuthUserTypeEnum } from './constant';
|
||||||
|
|
||||||
|
export type PermissionValueType = number;
|
||||||
|
|
||||||
export type AuthResponseType = {
|
export type AuthResponseType = {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
tmbId: string;
|
tmbId: string;
|
||||||
@@ -9,3 +11,10 @@ export type AuthResponseType = {
|
|||||||
appId?: string;
|
appId?: string;
|
||||||
apikey?: string;
|
apikey?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ResourcePermissionType = {
|
||||||
|
teamId: string;
|
||||||
|
tmbId: string;
|
||||||
|
resourceType: ResourceType;
|
||||||
|
permission: PermissionValueType;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export const TeamCollectionName = 'teams';
|
export const TeamCollectionName = 'teams';
|
||||||
export const TeamMemberCollectionName = 'team.members';
|
export const TeamMemberCollectionName = 'team_members';
|
||||||
export const TeamTagsCollectionName = 'team.tags';
|
export const TeamTagsCollectionName = 'team_tags';
|
||||||
|
|
||||||
export enum TeamMemberRoleEnum {
|
export enum TeamMemberRoleEnum {
|
||||||
owner = 'owner',
|
owner = 'owner',
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { PermissionValueType } from 'support/permission/type';
|
||||||
import { TeamMemberRoleEnum } from './constant';
|
import { TeamMemberRoleEnum } from './constant';
|
||||||
import { LafAccountType, TeamMemberSchema } from './type';
|
import { LafAccountType, TeamMemberSchema } from './type';
|
||||||
|
|
||||||
@@ -44,3 +45,9 @@ export type InviteMemberResponse = Record<
|
|||||||
'invite' | 'inValid' | 'inTeam',
|
'invite' | 'inValid' | 'inTeam',
|
||||||
{ username: string; userId: string }[]
|
{ username: string; userId: string }[]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
export type UpdateTeamMemberPermissionProps = {
|
||||||
|
teamId: string;
|
||||||
|
memberIds: string[];
|
||||||
|
permission: PermissionValueType;
|
||||||
|
};
|
||||||
|
|||||||
5
packages/global/support/user/team/type.d.ts
vendored
5
packages/global/support/user/team/type.d.ts
vendored
@@ -1,6 +1,7 @@
|
|||||||
import type { UserModelSchema } from '../type';
|
import type { UserModelSchema } from '../type';
|
||||||
import type { TeamMemberRoleEnum, TeamMemberStatusEnum } from './constant';
|
import type { TeamMemberRoleEnum, TeamMemberStatusEnum } from './constant';
|
||||||
import { LafAccountType } from './type';
|
import { LafAccountType } from './type';
|
||||||
|
import { PermissionValueType, ResourcePermissionType } from '../../permission/type';
|
||||||
|
|
||||||
export type TeamSchema = {
|
export type TeamSchema = {
|
||||||
_id: string;
|
_id: string;
|
||||||
@@ -15,6 +16,7 @@ export type TeamSchema = {
|
|||||||
lastWebsiteSyncTime: Date;
|
lastWebsiteSyncTime: Date;
|
||||||
};
|
};
|
||||||
lafAccount: LafAccountType;
|
lafAccount: LafAccountType;
|
||||||
|
defaultPermission: PermissionValueType;
|
||||||
};
|
};
|
||||||
export type tagsType = {
|
export type tagsType = {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -61,6 +63,7 @@ export type TeamItemType = {
|
|||||||
status: `${TeamMemberStatusEnum}`;
|
status: `${TeamMemberStatusEnum}`;
|
||||||
canWrite: boolean;
|
canWrite: boolean;
|
||||||
lafAccount?: LafAccountType;
|
lafAccount?: LafAccountType;
|
||||||
|
defaultPermission: PermissionValueType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TeamMemberItemType = {
|
export type TeamMemberItemType = {
|
||||||
@@ -69,8 +72,10 @@ export type TeamMemberItemType = {
|
|||||||
teamId: string;
|
teamId: string;
|
||||||
memberName: string;
|
memberName: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
|
// TODO: this should be deprecated.
|
||||||
role: `${TeamMemberRoleEnum}`;
|
role: `${TeamMemberRoleEnum}`;
|
||||||
status: `${TeamMemberStatusEnum}`;
|
status: `${TeamMemberStatusEnum}`;
|
||||||
|
permission: PermissionValueType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TeamTagItemType = {
|
export type TeamTagItemType = {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { connectionMongo, type Model } from '../../mongo';
|
|||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import { RawTextBufferSchemaType } from './type';
|
import { RawTextBufferSchemaType } from './type';
|
||||||
|
|
||||||
export const collectionName = 'buffer.rawText';
|
export const collectionName = 'buffer_rawtexts';
|
||||||
|
|
||||||
const RawTextBufferSchema = new Schema({
|
const RawTextBufferSchema = new Schema({
|
||||||
sourceId: {
|
sourceId: {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { connectionMongo, type Model } from '../../../common/mongo';
|
|||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import { TTSBufferSchemaType } from './type.d';
|
import { TTSBufferSchemaType } from './type.d';
|
||||||
|
|
||||||
export const collectionName = 'buffer.tts';
|
export const collectionName = 'buffer_tts';
|
||||||
|
|
||||||
const TTSBufferSchema = new Schema({
|
const TTSBufferSchema = new Schema({
|
||||||
bufferId: {
|
bufferId: {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { MongoFileSchema } from './schema';
|
|||||||
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
||||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||||
import { MongoRawTextBuffer } from '../../buffer/rawText/schema';
|
import { MongoRawTextBuffer } from '../../buffer/rawText/schema';
|
||||||
import { readFileRawContent } from '../read/utils';
|
import { readRawContentByFileBuffer } from '../read/utils';
|
||||||
import { PassThrough } from 'stream';
|
import { PassThrough } from 'stream';
|
||||||
|
|
||||||
export function getGFSCollection(bucket: `${BucketNameEnum}`) {
|
export function getGFSCollection(bucket: `${BucketNameEnum}`) {
|
||||||
@@ -151,12 +151,12 @@ export const readFileContentFromMongo = async ({
|
|||||||
teamId,
|
teamId,
|
||||||
bucketName,
|
bucketName,
|
||||||
fileId,
|
fileId,
|
||||||
csvFormat = false
|
isQAImport = false
|
||||||
}: {
|
}: {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
bucketName: `${BucketNameEnum}`;
|
bucketName: `${BucketNameEnum}`;
|
||||||
fileId: string;
|
fileId: string;
|
||||||
csvFormat?: boolean;
|
isQAImport?: boolean;
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
rawText: string;
|
rawText: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
@@ -196,9 +196,9 @@ export const readFileContentFromMongo = async ({
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const { rawText } = await readFileRawContent({
|
const { rawText } = await readRawContentByFileBuffer({
|
||||||
extension,
|
extension,
|
||||||
csvFormat,
|
isQAImport,
|
||||||
teamId,
|
teamId,
|
||||||
buffer: fileBuffers,
|
buffer: fileBuffers,
|
||||||
encoding,
|
encoding,
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { markdownProcess, simpleMarkdownText } from '@fastgpt/global/common/string/markdown';
|
import { markdownProcess } from '@fastgpt/global/common/string/markdown';
|
||||||
import { uploadMongoImg } from '../image/controller';
|
import { uploadMongoImg } from '../image/controller';
|
||||||
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
|
import { MongoImageTypeEnum } from '@fastgpt/global/common/file/image/constants';
|
||||||
import { addHours } from 'date-fns';
|
import { addHours } from 'date-fns';
|
||||||
|
|
||||||
import { WorkerNameEnum, runWorker } from '../../../worker/utils';
|
import { WorkerNameEnum, runWorker } from '../../../worker/utils';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { detectFileEncoding } from '@fastgpt/global/common/file/tools';
|
||||||
import { ReadFileResponse } from '../../../worker/file/type';
|
import { ReadFileResponse } from '../../../worker/file/type';
|
||||||
|
|
||||||
export const initMarkdownText = ({
|
export const initMarkdownText = ({
|
||||||
@@ -27,42 +29,71 @@ export const initMarkdownText = ({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
export const readFileRawContent = async ({
|
export type readRawTextByLocalFileParams = {
|
||||||
|
teamId: string;
|
||||||
|
path: string;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
};
|
||||||
|
export const readRawTextByLocalFile = async (params: readRawTextByLocalFileParams) => {
|
||||||
|
const { path } = params;
|
||||||
|
|
||||||
|
const extension = path?.split('.')?.pop()?.toLowerCase() || '';
|
||||||
|
|
||||||
|
const buffer = fs.readFileSync(path);
|
||||||
|
const encoding = detectFileEncoding(buffer);
|
||||||
|
|
||||||
|
const { rawText } = await readRawContentByFileBuffer({
|
||||||
|
extension,
|
||||||
|
isQAImport: false,
|
||||||
|
teamId: params.teamId,
|
||||||
|
encoding,
|
||||||
|
buffer,
|
||||||
|
metadata: params.metadata
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
rawText
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const readRawContentByFileBuffer = async ({
|
||||||
extension,
|
extension,
|
||||||
csvFormat,
|
isQAImport,
|
||||||
teamId,
|
teamId,
|
||||||
buffer,
|
buffer,
|
||||||
encoding,
|
encoding,
|
||||||
metadata
|
metadata
|
||||||
}: {
|
}: {
|
||||||
csvFormat?: boolean;
|
isQAImport?: boolean;
|
||||||
extension: string;
|
extension: string;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
buffer: Buffer;
|
buffer: Buffer;
|
||||||
encoding: string;
|
encoding: string;
|
||||||
metadata?: Record<string, any>;
|
metadata?: Record<string, any>;
|
||||||
}) => {
|
}) => {
|
||||||
const result = await runWorker<ReadFileResponse>(WorkerNameEnum.readFile, {
|
let { rawText, formatText } = await runWorker<ReadFileResponse>(WorkerNameEnum.readFile, {
|
||||||
extension,
|
extension,
|
||||||
csvFormat,
|
|
||||||
encoding,
|
encoding,
|
||||||
buffer
|
buffer
|
||||||
});
|
});
|
||||||
|
|
||||||
// markdown data format
|
// markdown data format
|
||||||
if (['md', 'html', 'docx'].includes(extension)) {
|
if (['md', 'html', 'docx'].includes(extension)) {
|
||||||
result.rawText = await initMarkdownText({
|
rawText = await initMarkdownText({
|
||||||
teamId: teamId,
|
teamId: teamId,
|
||||||
md: result.rawText,
|
md: rawText,
|
||||||
metadata: metadata
|
metadata: metadata
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
if (['csv', 'xlsx'].includes(extension)) {
|
||||||
};
|
// qa data
|
||||||
|
if (isQAImport) {
|
||||||
|
rawText = rawText || '';
|
||||||
|
} else {
|
||||||
|
rawText = formatText || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const htmlToMarkdown = async (html?: string | null) => {
|
return { rawText };
|
||||||
const md = await runWorker<string>(WorkerNameEnum.htmlStr2Md, { html: html || '' });
|
|
||||||
|
|
||||||
return simpleMarkdownText(md);
|
|
||||||
};
|
};
|
||||||
|
|||||||
44
packages/service/common/middle/entry.ts
Normal file
44
packages/service/common/middle/entry.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { jsonRes } from '../response';
|
||||||
|
import type { NextApiResponse } from 'next';
|
||||||
|
import { withNextCors } from './cors';
|
||||||
|
import { ApiRequestProps } from '../../type/next';
|
||||||
|
import { addLog } from '../system/log';
|
||||||
|
|
||||||
|
export type NextApiHandler<T = any> = (
|
||||||
|
req: ApiRequestProps,
|
||||||
|
res: NextApiResponse<T>
|
||||||
|
) => unknown | Promise<unknown>;
|
||||||
|
|
||||||
|
export const NextEntry = ({ beforeCallback = [] }: { beforeCallback?: Promise<any>[] }) => {
|
||||||
|
return (...args: NextApiHandler[]): NextApiHandler => {
|
||||||
|
return async function api(req: ApiRequestProps, res: NextApiResponse) {
|
||||||
|
const start = Date.now();
|
||||||
|
addLog.info(`Request start ${req.url}`);
|
||||||
|
try {
|
||||||
|
await Promise.all([withNextCors(req, res), ...beforeCallback]);
|
||||||
|
|
||||||
|
let response = null;
|
||||||
|
for (const handler of args) {
|
||||||
|
response = await handler(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentType = res.getHeader('Content-Type');
|
||||||
|
|
||||||
|
addLog.info(`Request finish ${req.url}, time: ${Date.now() - start}ms`);
|
||||||
|
|
||||||
|
if ((!contentType || contentType === 'application/json') && !res.writableFinished) {
|
||||||
|
return jsonRes(res, {
|
||||||
|
code: 200,
|
||||||
|
data: response
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return jsonRes(res, {
|
||||||
|
code: 500,
|
||||||
|
error,
|
||||||
|
url: req.url
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -12,8 +12,6 @@ export const mongoSessionRun = async <T = unknown>(fn: (session: ClientSession)
|
|||||||
|
|
||||||
return result as T;
|
return result as T;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
|
||||||
|
|
||||||
await session.abortTransaction();
|
await session.abortTransaction();
|
||||||
await session.endSession();
|
await session.endSession();
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { UrlFetchParams, UrlFetchResponse } from '@fastgpt/global/common/file/api';
|
import { UrlFetchParams, UrlFetchResponse } from '@fastgpt/global/common/file/api';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { htmlToMarkdown } from '../file/read/utils';
|
import { htmlToMarkdown } from './utils';
|
||||||
|
|
||||||
export const cheerioToHtml = ({
|
export const cheerioToHtml = ({
|
||||||
fetchUrl,
|
fetchUrl,
|
||||||
@@ -77,9 +77,8 @@ export const urlsFetch = async ({
|
|||||||
$,
|
$,
|
||||||
selector
|
selector
|
||||||
});
|
});
|
||||||
console.log('html====', html);
|
|
||||||
const md = await htmlToMarkdown(html);
|
const md = await htmlToMarkdown(html);
|
||||||
console.log('html====', md);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url,
|
url,
|
||||||
|
|||||||
@@ -12,27 +12,34 @@ import { getNanoid } from '@fastgpt/global/common/string/tools';
|
|||||||
import { addLog } from '../../system/log';
|
import { addLog } from '../../system/log';
|
||||||
|
|
||||||
export const getTiktokenWorker = () => {
|
export const getTiktokenWorker = () => {
|
||||||
if (global.tiktokenWorker) {
|
const maxWorkers = global.systemEnv?.tokenWorkers || 20;
|
||||||
return global.tiktokenWorker;
|
|
||||||
|
if (!global.tiktokenWorkers) {
|
||||||
|
global.tiktokenWorkers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (global.tiktokenWorkers.length >= maxWorkers) {
|
||||||
|
return global.tiktokenWorkers[Math.floor(Math.random() * global.tiktokenWorkers.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const worker = getWorker(WorkerNameEnum.countGptMessagesTokens);
|
const worker = getWorker(WorkerNameEnum.countGptMessagesTokens);
|
||||||
|
|
||||||
|
const i = global.tiktokenWorkers.push({
|
||||||
|
index: global.tiktokenWorkers.length,
|
||||||
|
worker,
|
||||||
|
callbackMap: {}
|
||||||
|
});
|
||||||
|
|
||||||
worker.on('message', ({ id, data }: { id: string; data: number }) => {
|
worker.on('message', ({ id, data }: { id: string; data: number }) => {
|
||||||
const callback = global.tiktokenWorker?.callbackMap?.[id];
|
const callback = global.tiktokenWorkers[i - 1]?.callbackMap?.[id];
|
||||||
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback?.(data);
|
callback?.(data);
|
||||||
delete global.tiktokenWorker.callbackMap[id];
|
delete global.tiktokenWorkers[i - 1].callbackMap[id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
global.tiktokenWorker = {
|
return global.tiktokenWorkers[i - 1];
|
||||||
worker,
|
|
||||||
callbackMap: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
return global.tiktokenWorker;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const countGptMessagesTokens = (
|
export const countGptMessagesTokens = (
|
||||||
@@ -40,32 +47,46 @@ export const countGptMessagesTokens = (
|
|||||||
tools?: ChatCompletionTool[],
|
tools?: ChatCompletionTool[],
|
||||||
functionCall?: ChatCompletionCreateParams.Function[]
|
functionCall?: ChatCompletionCreateParams.Function[]
|
||||||
) => {
|
) => {
|
||||||
return new Promise<number>((resolve) => {
|
return new Promise<number>(async (resolve) => {
|
||||||
const start = Date.now();
|
try {
|
||||||
|
const start = Date.now();
|
||||||
|
|
||||||
const { worker, callbackMap } = getTiktokenWorker();
|
const { worker, callbackMap } = getTiktokenWorker();
|
||||||
const id = getNanoid();
|
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
const id = getNanoid();
|
||||||
|
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
console.log('Count token Time out');
|
||||||
|
resolve(
|
||||||
|
messages.reduce((sum, item) => {
|
||||||
|
if (item.content) {
|
||||||
|
return sum + item.content.length * 0.5;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}, 0)
|
||||||
|
);
|
||||||
|
delete callbackMap[id];
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
callbackMap[id] = (data) => {
|
||||||
|
// 检测是否有内存泄漏
|
||||||
|
addLog.info(`Count token time: ${Date.now() - start}, token: ${data}`);
|
||||||
|
// console.log(process.memoryUsage());
|
||||||
|
|
||||||
|
resolve(data);
|
||||||
|
clearTimeout(timer);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 可以进一步优化(传递100w token数据,实际需要300ms,较慢)
|
||||||
|
worker.postMessage({
|
||||||
|
id,
|
||||||
|
messages,
|
||||||
|
tools,
|
||||||
|
functionCall
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
resolve(0);
|
resolve(0);
|
||||||
delete callbackMap[id];
|
}
|
||||||
}, 300);
|
|
||||||
|
|
||||||
callbackMap[id] = (data) => {
|
|
||||||
resolve(data);
|
|
||||||
clearTimeout(timer);
|
|
||||||
|
|
||||||
// 检测是否有内存泄漏
|
|
||||||
// addLog.info(`Count token time: ${Date.now() - start}, token: ${data}`);
|
|
||||||
// console.log(process.memoryUsage());
|
|
||||||
};
|
|
||||||
|
|
||||||
worker.postMessage({
|
|
||||||
id,
|
|
||||||
messages,
|
|
||||||
tools,
|
|
||||||
functionCall
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
8
packages/service/common/string/utils.ts
Normal file
8
packages/service/common/string/utils.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { simpleMarkdownText } from '@fastgpt/global/common/string/markdown';
|
||||||
|
import { WorkerNameEnum, runWorker } from '../../worker/utils';
|
||||||
|
|
||||||
|
export const htmlToMarkdown = async (html?: string | null) => {
|
||||||
|
const md = await runWorker<string>(WorkerNameEnum.htmlStr2Md, { html: html || '' });
|
||||||
|
|
||||||
|
return simpleMarkdownText(md);
|
||||||
|
};
|
||||||
@@ -20,3 +20,15 @@ export const initFastGPTConfig = (config?: FastGPTConfigFileType) => {
|
|||||||
global.whisperModel = config.whisperModel;
|
global.whisperModel = config.whisperModel;
|
||||||
global.reRankModels = config.reRankModels;
|
global.reRankModels = config.reRankModels;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const systemStartCb = () => {
|
||||||
|
process.on('uncaughtException', (err) => {
|
||||||
|
console.error('Uncaught Exception:', err);
|
||||||
|
// process.exit(1); // 退出进程
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, promise) => {
|
||||||
|
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
||||||
|
// process.exit(1); // 退出进程
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -98,12 +98,15 @@ export const deleteDatasetDataVector = async (
|
|||||||
return `${teamIdWhere} ${datasetIdWhere}`;
|
return `${teamIdWhere} ${datasetIdWhere}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('idList' in props && props.idList) {
|
if ('idList' in props && Array.isArray(props.idList)) {
|
||||||
|
if (props.idList.length === 0) return;
|
||||||
return `${teamIdWhere} id IN (${props.idList.map((id) => `'${String(id)}'`).join(',')})`;
|
return `${teamIdWhere} id IN (${props.idList.map((id) => `'${String(id)}'`).join(',')})`;
|
||||||
}
|
}
|
||||||
return Promise.reject('deleteDatasetData: no where');
|
return Promise.reject('deleteDatasetData: no where');
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
if (!where) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await PgClient.delete(PgDatasetTableName, {
|
await PgClient.delete(PgDatasetTableName, {
|
||||||
where: [where]
|
where: [where]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { AppSchema } from '@fastgpt/global/core/app/type';
|
|||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { getLLMModel } from '../ai/model';
|
import { getLLMModel } from '../ai/model';
|
||||||
import { MongoAppVersion } from './versionSchema';
|
import { MongoAppVersion } from './version/schema';
|
||||||
|
|
||||||
export const beforeUpdateAppFormat = <T extends AppSchema['modules'] | undefined>({
|
export const beforeUpdateAppFormat = <T extends AppSchema['modules'] | undefined>({
|
||||||
nodes
|
nodes
|
||||||
@@ -55,11 +55,13 @@ export const getAppLatestVersion = async (appId: string, app?: AppSchema) => {
|
|||||||
if (version) {
|
if (version) {
|
||||||
return {
|
return {
|
||||||
nodes: version.nodes,
|
nodes: version.nodes,
|
||||||
edges: version.edges
|
edges: version.edges,
|
||||||
|
chatConfig: version.chatConfig || app?.chatConfig || {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
nodes: app?.modules || [],
|
nodes: app?.modules || [],
|
||||||
edges: app?.edges || []
|
edges: app?.edges || [],
|
||||||
|
chatConfig: app?.chatConfig || {}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,16 @@ import {
|
|||||||
|
|
||||||
export const AppCollectionName = 'apps';
|
export const AppCollectionName = 'apps';
|
||||||
|
|
||||||
|
export const chatConfigType = {
|
||||||
|
welcomeText: String,
|
||||||
|
variables: Array,
|
||||||
|
questionGuide: Boolean,
|
||||||
|
ttsConfig: Object,
|
||||||
|
whisperConfig: Object,
|
||||||
|
scheduledTriggerConfig: Object,
|
||||||
|
chatInputGuide: Object
|
||||||
|
};
|
||||||
|
|
||||||
const AppSchema = new Schema({
|
const AppSchema = new Schema({
|
||||||
teamId: {
|
teamId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
@@ -47,6 +57,16 @@ const AppSchema = new Schema({
|
|||||||
default: () => new Date()
|
default: () => new Date()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// role and auth
|
||||||
|
permission: {
|
||||||
|
type: String,
|
||||||
|
enum: Object.keys(PermissionTypeMap),
|
||||||
|
default: PermissionTypeEnum.private
|
||||||
|
},
|
||||||
|
teamTags: {
|
||||||
|
type: [String]
|
||||||
|
},
|
||||||
|
|
||||||
// tmp store
|
// tmp store
|
||||||
modules: {
|
modules: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@@ -56,6 +76,10 @@ const AppSchema = new Schema({
|
|||||||
type: Array,
|
type: Array,
|
||||||
default: []
|
default: []
|
||||||
},
|
},
|
||||||
|
chatConfig: {
|
||||||
|
type: chatConfigType,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
|
||||||
scheduledTriggerConfig: {
|
scheduledTriggerConfig: {
|
||||||
cronString: {
|
cronString: {
|
||||||
@@ -74,14 +98,6 @@ const AppSchema = new Schema({
|
|||||||
|
|
||||||
inited: {
|
inited: {
|
||||||
type: Boolean
|
type: Boolean
|
||||||
},
|
|
||||||
permission: {
|
|
||||||
type: String,
|
|
||||||
enum: Object.keys(PermissionTypeMap),
|
|
||||||
default: PermissionTypeEnum.private
|
|
||||||
},
|
|
||||||
teamTags: {
|
|
||||||
type: [String]
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { connectionMongo, type Model } from '../../common/mongo';
|
import { connectionMongo, type Model } from '../../../common/mongo';
|
||||||
const { Schema, model, models } = connectionMongo;
|
const { Schema, model, models } = connectionMongo;
|
||||||
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
||||||
|
import { chatConfigType } from '../schema';
|
||||||
|
|
||||||
export const AppVersionCollectionName = 'app.versions';
|
export const AppVersionCollectionName = 'app_versions';
|
||||||
|
|
||||||
const AppVersionSchema = new Schema({
|
const AppVersionSchema = new Schema({
|
||||||
appId: {
|
appId: {
|
||||||
@@ -21,6 +22,10 @@ const AppVersionSchema = new Schema({
|
|||||||
edges: {
|
edges: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: []
|
default: []
|
||||||
|
},
|
||||||
|
chatConfig: {
|
||||||
|
type: chatConfigType,
|
||||||
|
default: {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ export async function getChatItems({
|
|||||||
|
|
||||||
return { history };
|
return { history };
|
||||||
}
|
}
|
||||||
/* 临时适配旧的对话记录,清洗完数据后可删除(4.30刪除) */
|
/* 临时适配旧的对话记录 */
|
||||||
export const adaptStringValue = (value: any): ChatItemValueItemType[] => {
|
export const adaptStringValue = (value: any): ChatItemValueItemType[] => {
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
return [
|
return [
|
||||||
|
|||||||
29
packages/service/core/chat/inputGuide/schema.ts
Normal file
29
packages/service/core/chat/inputGuide/schema.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { AppCollectionName } from '../../app/schema';
|
||||||
|
import { connectionMongo, type Model } from '../../../common/mongo';
|
||||||
|
const { Schema, model, models } = connectionMongo;
|
||||||
|
import type { ChatInputGuideSchemaType } from '@fastgpt/global/core/chat/inputGuide/type.d';
|
||||||
|
|
||||||
|
export const ChatInputGuideCollectionName = 'chat_input_guides';
|
||||||
|
|
||||||
|
const ChatInputGuideSchema = new Schema({
|
||||||
|
appId: {
|
||||||
|
type: Schema.Types.ObjectId,
|
||||||
|
ref: AppCollectionName,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
ChatInputGuideSchema.index({ appId: 1, text: 1 }, { unique: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MongoChatInputGuide: Model<ChatInputGuideSchemaType> =
|
||||||
|
models[ChatInputGuideCollectionName] || model(ChatInputGuideCollectionName, ChatInputGuideSchema);
|
||||||
|
|
||||||
|
MongoChatInputGuide.syncIndexes();
|
||||||
@@ -32,6 +32,9 @@ export async function createOneCollection({
|
|||||||
fileId,
|
fileId,
|
||||||
rawLink,
|
rawLink,
|
||||||
|
|
||||||
|
externalFileId,
|
||||||
|
externalFileUrl,
|
||||||
|
|
||||||
hashRawText,
|
hashRawText,
|
||||||
rawTextLength,
|
rawTextLength,
|
||||||
metadata = {},
|
metadata = {},
|
||||||
@@ -61,6 +64,8 @@ export async function createOneCollection({
|
|||||||
|
|
||||||
fileId,
|
fileId,
|
||||||
rawLink,
|
rawLink,
|
||||||
|
externalFileId,
|
||||||
|
externalFileUrl,
|
||||||
|
|
||||||
rawTextLength,
|
rawTextLength,
|
||||||
hashRawText,
|
hashRawText,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
TeamMemberCollectionName
|
TeamMemberCollectionName
|
||||||
} from '@fastgpt/global/support/user/team/constant';
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
|
||||||
export const DatasetColCollectionName = 'dataset.collections';
|
export const DatasetColCollectionName = 'dataset_collections';
|
||||||
|
|
||||||
const DatasetCollectionSchema = new Schema({
|
const DatasetCollectionSchema = new Schema({
|
||||||
parentId: {
|
parentId: {
|
||||||
@@ -16,11 +16,6 @@ const DatasetCollectionSchema = new Schema({
|
|||||||
ref: DatasetColCollectionName,
|
ref: DatasetColCollectionName,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
userId: {
|
|
||||||
// abandoned
|
|
||||||
type: Schema.Types.ObjectId,
|
|
||||||
ref: 'user'
|
|
||||||
},
|
|
||||||
teamId: {
|
teamId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: TeamCollectionName,
|
ref: TeamCollectionName,
|
||||||
@@ -54,6 +49,7 @@ const DatasetCollectionSchema = new Schema({
|
|||||||
default: () => new Date()
|
default: () => new Date()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// chunk filed
|
||||||
trainingType: {
|
trainingType: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: Object.keys(TrainingTypeMap),
|
enum: Object.keys(TrainingTypeMap),
|
||||||
@@ -70,20 +66,25 @@ const DatasetCollectionSchema = new Schema({
|
|||||||
type: String
|
type: String
|
||||||
},
|
},
|
||||||
|
|
||||||
|
tags: {
|
||||||
|
type: [String],
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
|
||||||
|
// local file collection
|
||||||
fileId: {
|
fileId: {
|
||||||
type: Schema.Types.ObjectId,
|
type: Schema.Types.ObjectId,
|
||||||
ref: 'dataset.files'
|
ref: 'dataset.files'
|
||||||
},
|
},
|
||||||
rawLink: {
|
// web link collection
|
||||||
type: String
|
rawLink: String,
|
||||||
},
|
// external collection
|
||||||
|
externalFileId: String,
|
||||||
|
|
||||||
rawTextLength: {
|
// metadata
|
||||||
type: Number
|
rawTextLength: Number,
|
||||||
},
|
hashRawText: String,
|
||||||
hashRawText: {
|
externalFileUrl: String, // external import url
|
||||||
type: String
|
|
||||||
},
|
|
||||||
metadata: {
|
metadata: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {}
|
default: {}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
import { DatasetCollectionName } from '../schema';
|
import { DatasetCollectionName } from '../schema';
|
||||||
import { DatasetColCollectionName } from '../collection/schema';
|
import { DatasetColCollectionName } from '../collection/schema';
|
||||||
|
|
||||||
export const DatasetDataCollectionName = 'dataset.datas';
|
export const DatasetDataCollectionName = 'dataset_datas';
|
||||||
|
|
||||||
const DatasetDataSchema = new Schema({
|
const DatasetDataSchema = new Schema({
|
||||||
teamId: {
|
teamId: {
|
||||||
@@ -73,7 +73,8 @@ const DatasetDataSchema = new Schema({
|
|||||||
},
|
},
|
||||||
inited: {
|
inited: {
|
||||||
type: Boolean
|
type: Boolean
|
||||||
}
|
},
|
||||||
|
rebuilding: Boolean
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -90,10 +91,13 @@ try {
|
|||||||
{ background: true }
|
{ background: true }
|
||||||
);
|
);
|
||||||
DatasetDataSchema.index({ updateTime: 1 }, { background: true });
|
DatasetDataSchema.index({ updateTime: 1 }, { background: true });
|
||||||
|
// rebuild data
|
||||||
|
DatasetDataSchema.index({ rebuilding: 1, teamId: 1, datasetId: 1 }, { background: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MongoDatasetData: Model<DatasetDataSchemaType> =
|
export const MongoDatasetData: Model<DatasetDataSchemaType> =
|
||||||
models[DatasetDataCollectionName] || model(DatasetDataCollectionName, DatasetDataSchema);
|
models[DatasetDataCollectionName] || model(DatasetDataCollectionName, DatasetDataSchema);
|
||||||
|
|
||||||
MongoDatasetData.syncIndexes();
|
MongoDatasetData.syncIndexes();
|
||||||
|
|||||||
112
packages/service/core/dataset/read.ts
Normal file
112
packages/service/core/dataset/read.ts
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
|
||||||
|
import { DatasetSourceReadTypeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||||
|
import { readFileContentFromMongo } from '../../common/file/gridfs/controller';
|
||||||
|
import { urlsFetch } from '../../common/string/cheerio';
|
||||||
|
import { parseCsvTable2Chunks } from './training/utils';
|
||||||
|
import { TextSplitProps, splitText2Chunks } from '@fastgpt/global/common/string/textSplitter';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { readRawContentByFileBuffer } from '../../common/file/read/utils';
|
||||||
|
|
||||||
|
export const readFileRawTextByUrl = async ({
|
||||||
|
teamId,
|
||||||
|
url,
|
||||||
|
relatedId
|
||||||
|
}: {
|
||||||
|
teamId: string;
|
||||||
|
url: string;
|
||||||
|
relatedId?: string;
|
||||||
|
}) => {
|
||||||
|
const response = await axios({
|
||||||
|
method: 'get',
|
||||||
|
url: url,
|
||||||
|
responseType: 'arraybuffer'
|
||||||
|
});
|
||||||
|
const extension = url.split('.')?.pop()?.toLowerCase() || '';
|
||||||
|
|
||||||
|
const buffer = Buffer.from(response.data, 'binary');
|
||||||
|
|
||||||
|
const { rawText } = await readRawContentByFileBuffer({
|
||||||
|
extension,
|
||||||
|
teamId,
|
||||||
|
buffer,
|
||||||
|
encoding: 'utf-8',
|
||||||
|
metadata: {
|
||||||
|
relatedId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return rawText;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
fileId - local file, read from mongo
|
||||||
|
link - request
|
||||||
|
externalFile = request read
|
||||||
|
*/
|
||||||
|
export const readDatasetSourceRawText = async ({
|
||||||
|
teamId,
|
||||||
|
type,
|
||||||
|
sourceId,
|
||||||
|
isQAImport,
|
||||||
|
selector,
|
||||||
|
relatedId
|
||||||
|
}: {
|
||||||
|
teamId: string;
|
||||||
|
type: DatasetSourceReadTypeEnum;
|
||||||
|
sourceId: string;
|
||||||
|
isQAImport?: boolean;
|
||||||
|
selector?: string;
|
||||||
|
relatedId?: string;
|
||||||
|
}): Promise<string> => {
|
||||||
|
if (type === DatasetSourceReadTypeEnum.fileLocal) {
|
||||||
|
const { rawText } = await readFileContentFromMongo({
|
||||||
|
teamId,
|
||||||
|
bucketName: BucketNameEnum.dataset,
|
||||||
|
fileId: sourceId,
|
||||||
|
isQAImport
|
||||||
|
});
|
||||||
|
return rawText;
|
||||||
|
} else if (type === DatasetSourceReadTypeEnum.link) {
|
||||||
|
const result = await urlsFetch({
|
||||||
|
urlList: [sourceId],
|
||||||
|
selector
|
||||||
|
});
|
||||||
|
|
||||||
|
return result[0]?.content || '';
|
||||||
|
} else if (type === DatasetSourceReadTypeEnum.externalFile) {
|
||||||
|
const rawText = await readFileRawTextByUrl({
|
||||||
|
teamId,
|
||||||
|
url: sourceId,
|
||||||
|
relatedId
|
||||||
|
});
|
||||||
|
return rawText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const rawText2Chunks = ({
|
||||||
|
rawText,
|
||||||
|
isQAImport,
|
||||||
|
chunkLen = 512,
|
||||||
|
...splitProps
|
||||||
|
}: {
|
||||||
|
rawText: string;
|
||||||
|
isQAImport?: boolean;
|
||||||
|
} & TextSplitProps) => {
|
||||||
|
if (isQAImport) {
|
||||||
|
const { chunks } = parseCsvTable2Chunks(rawText);
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { chunks } = splitText2Chunks({
|
||||||
|
text: rawText,
|
||||||
|
chunkLen,
|
||||||
|
...splitProps
|
||||||
|
});
|
||||||
|
|
||||||
|
return chunks.map((item) => ({
|
||||||
|
q: item,
|
||||||
|
a: ''
|
||||||
|
}));
|
||||||
|
};
|
||||||
@@ -89,7 +89,8 @@ const DatasetSchema = new Schema({
|
|||||||
default: 'body'
|
default: 'body'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
externalReadUrl: String
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { countPromptTokens } from '../../../common/string/tiktoken/index';
|
|||||||
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
|
import { datasetSearchResultConcat } from '@fastgpt/global/core/dataset/search/utils';
|
||||||
import { hashStr } from '@fastgpt/global/common/string/tools';
|
import { hashStr } from '@fastgpt/global/common/string/tools';
|
||||||
import { jiebaSplit } from '../../../common/string/jieba';
|
import { jiebaSplit } from '../../../common/string/jieba';
|
||||||
|
import { getCollectionSourceData } from '@fastgpt/global/core/dataset/collection/utils';
|
||||||
|
|
||||||
type SearchDatasetDataProps = {
|
type SearchDatasetDataProps = {
|
||||||
teamId: string;
|
teamId: string;
|
||||||
@@ -98,7 +99,7 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
},
|
},
|
||||||
'datasetId collectionId q a chunkIndex indexes'
|
'datasetId collectionId q a chunkIndex indexes'
|
||||||
)
|
)
|
||||||
.populate('collectionId', 'name fileId rawLink')
|
.populate('collectionId', 'name fileId rawLink externalFileId externalFileUrl')
|
||||||
.lean()) as DatasetDataWithCollectionType[];
|
.lean()) as DatasetDataWithCollectionType[];
|
||||||
|
|
||||||
// add score to data(It's already sorted. The first one is the one with the most points)
|
// add score to data(It's already sorted. The first one is the one with the most points)
|
||||||
@@ -130,8 +131,7 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
chunkIndex: data.chunkIndex,
|
chunkIndex: data.chunkIndex,
|
||||||
datasetId: String(data.datasetId),
|
datasetId: String(data.datasetId),
|
||||||
collectionId: String(data.collectionId?._id),
|
collectionId: String(data.collectionId?._id),
|
||||||
sourceName: data.collectionId?.name || '',
|
...getCollectionSourceData(data.collectionId),
|
||||||
sourceId: data.collectionId?.fileId || data.collectionId?.rawLink,
|
|
||||||
score: [{ type: SearchScoreTypeEnum.embedding, value: data.score, index }]
|
score: [{ type: SearchScoreTypeEnum.embedding, value: data.score, index }]
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -205,8 +205,7 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
id: String(item._id),
|
id: String(item._id),
|
||||||
datasetId: String(item.datasetId),
|
datasetId: String(item.datasetId),
|
||||||
collectionId: String(item.collectionId),
|
collectionId: String(item.collectionId),
|
||||||
sourceName: collection?.name || '',
|
...getCollectionSourceData(collection),
|
||||||
sourceId: collection?.fileId || collection?.rawLink,
|
|
||||||
q: item.q,
|
q: item.q,
|
||||||
a: item.a,
|
a: item.a,
|
||||||
chunkIndex: item.chunkIndex,
|
chunkIndex: item.chunkIndex,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { LLMModelItemType } from '@fastgpt/global/core/ai/model.d';
|
|||||||
import { queryExtension } from '../../ai/functions/queryExtension';
|
import { queryExtension } from '../../ai/functions/queryExtension';
|
||||||
import { ChatItemType } from '@fastgpt/global/core/chat/type';
|
import { ChatItemType } from '@fastgpt/global/core/chat/type';
|
||||||
import { hashStr } from '@fastgpt/global/common/string/tools';
|
import { hashStr } from '@fastgpt/global/common/string/tools';
|
||||||
|
import { chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt';
|
||||||
|
|
||||||
export const datasetSearchQueryExtension = async ({
|
export const datasetSearchQueryExtension = async ({
|
||||||
query,
|
query,
|
||||||
@@ -33,11 +34,11 @@ export const datasetSearchQueryExtension = async ({
|
|||||||
histories.length > 0
|
histories.length > 0
|
||||||
? `${histories
|
? `${histories
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return `${item.obj}: ${item.value}`;
|
return `${item.obj}: ${chatValue2RuntimePrompt(item.value).text}`;
|
||||||
})
|
})
|
||||||
.join('\n')}
|
.join('\n')}
|
||||||
Human: ${query}
|
Human: ${query}
|
||||||
`
|
`
|
||||||
: query;
|
: query;
|
||||||
|
|
||||||
/* if query already extension, direct parse */
|
/* if query already extension, direct parse */
|
||||||
|
|||||||
@@ -168,13 +168,14 @@ export async function pushDataListToTrainingQueue({
|
|||||||
indexes: item.indexes
|
indexes: item.indexes
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
session
|
session,
|
||||||
|
ordered: false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
addLog.error(`Insert error`, error);
|
addLog.error(`Insert error`, error);
|
||||||
// 如果有错误,将失败的文档添加到失败列表中
|
// 如果有错误,将失败的文档添加到失败列表中
|
||||||
error.writeErrors.forEach((writeError: any) => {
|
error.writeErrors?.forEach((writeError: any) => {
|
||||||
failedDocuments.push(data[writeError.index]);
|
failedDocuments.push(data[writeError.index]);
|
||||||
});
|
});
|
||||||
console.log('failed', failedDocuments);
|
console.log('failed', failedDocuments);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
TeamMemberCollectionName
|
TeamMemberCollectionName
|
||||||
} from '@fastgpt/global/support/user/team/constant';
|
} from '@fastgpt/global/support/user/team/constant';
|
||||||
|
|
||||||
export const DatasetTrainingCollectionName = 'dataset.trainings';
|
export const DatasetTrainingCollectionName = 'dataset_trainings';
|
||||||
|
|
||||||
const TrainingDataSchema = new Schema({
|
const TrainingDataSchema = new Schema({
|
||||||
teamId: {
|
teamId: {
|
||||||
@@ -35,8 +35,7 @@ const TrainingDataSchema = new Schema({
|
|||||||
},
|
},
|
||||||
billId: {
|
billId: {
|
||||||
// concat bill
|
// concat bill
|
||||||
type: String,
|
type: String
|
||||||
default: ''
|
|
||||||
},
|
},
|
||||||
mode: {
|
mode: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -78,6 +77,9 @@ const TrainingDataSchema = new Schema({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
},
|
},
|
||||||
|
dataId: {
|
||||||
|
type: Schema.Types.ObjectId
|
||||||
|
},
|
||||||
indexes: {
|
indexes: {
|
||||||
type: [
|
type: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> =>
|
|||||||
nodes: item.modules,
|
nodes: item.modules,
|
||||||
edges: item.edges,
|
edges: item.edges,
|
||||||
templateType: FlowNodeTemplateTypeEnum.personalPlugin,
|
templateType: FlowNodeTemplateTypeEnum.personalPlugin,
|
||||||
isTool: true
|
isTool: true,
|
||||||
|
nodeVersion: item?.nodeVersion || ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return Promise.reject('plugin not found');
|
return Promise.reject('plugin not found');
|
||||||
@@ -72,6 +73,8 @@ export async function getPluginPreviewNode({ id }: { id: string }): Promise<Flow
|
|||||||
intro: plugin.intro,
|
intro: plugin.intro,
|
||||||
showStatus: plugin.showStatus,
|
showStatus: plugin.showStatus,
|
||||||
isTool: plugin.isTool,
|
isTool: plugin.isTool,
|
||||||
|
nodeVersion: plugin.nodeVersion,
|
||||||
|
version: '481',
|
||||||
sourceHandle: getHandleConfig(true, true, true, true),
|
sourceHandle: getHandleConfig(true, true, true, true),
|
||||||
targetHandle: getHandleConfig(true, true, true, true),
|
targetHandle: getHandleConfig(true, true, true, true),
|
||||||
...pluginData2FlowNodeIO(plugin.nodes)
|
...pluginData2FlowNodeIO(plugin.nodes)
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ const PluginSchema = new Schema({
|
|||||||
version: {
|
version: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['v1', 'v2']
|
enum: ['v1', 'v2']
|
||||||
|
},
|
||||||
|
nodeVersion: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { getHistories } from '../utils';
|
|||||||
import { datasetSearchQueryExtension } from '../../../dataset/search/utils';
|
import { datasetSearchQueryExtension } from '../../../dataset/search/utils';
|
||||||
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type';
|
||||||
import { checkTeamReRankPermission } from '../../../../support/permission/teamLimit';
|
import { checkTeamReRankPermission } from '../../../../support/permission/teamLimit';
|
||||||
|
import { MongoDataset } from '../../../dataset/schema';
|
||||||
|
|
||||||
type DatasetSearchProps = ModuleDispatchProps<{
|
type DatasetSearchProps = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.datasetSelectList]: SelectedDatasetType;
|
[NodeInputKeyEnum.datasetSelectList]: SelectedDatasetType;
|
||||||
@@ -79,7 +80,9 @@ export async function dispatchDatasetSearch(
|
|||||||
// console.log(concatQueries, rewriteQuery, aiExtensionResult);
|
// console.log(concatQueries, rewriteQuery, aiExtensionResult);
|
||||||
|
|
||||||
// get vector
|
// get vector
|
||||||
const vectorModel = getVectorModel(datasets[0]?.vectorModel?.model);
|
const vectorModel = getVectorModel(
|
||||||
|
(await MongoDataset.findById(datasets[0].datasetId, 'vectorModel').lean())?.vectorModel
|
||||||
|
);
|
||||||
|
|
||||||
// start search
|
// start search
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -44,8 +44,9 @@ import { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
|||||||
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
import { dispatchSystemConfig } from './init/systemConfig';
|
import { dispatchSystemConfig } from './init/systemConfig';
|
||||||
import { dispatchUpdateVariable } from './tools/runUpdateVar';
|
import { dispatchUpdateVariable } from './tools/runUpdateVar';
|
||||||
|
import { addLog } from '../../../common/system/log';
|
||||||
|
|
||||||
const callbackMap: Record<`${FlowNodeTypeEnum}`, Function> = {
|
const callbackMap: Record<FlowNodeTypeEnum, Function> = {
|
||||||
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
|
||||||
[FlowNodeTypeEnum.answerNode]: dispatchAnswer,
|
[FlowNodeTypeEnum.answerNode]: dispatchAnswer,
|
||||||
[FlowNodeTypeEnum.chatNode]: dispatchChatCompletion,
|
[FlowNodeTypeEnum.chatNode]: dispatchChatCompletion,
|
||||||
@@ -137,7 +138,6 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
}
|
}
|
||||||
if (nodeDispatchUsages) {
|
if (nodeDispatchUsages) {
|
||||||
chatNodeUsages = chatNodeUsages.concat(nodeDispatchUsages);
|
chatNodeUsages = chatNodeUsages.concat(nodeDispatchUsages);
|
||||||
props.maxRunTimes -= nodeDispatchUsages.length;
|
|
||||||
}
|
}
|
||||||
if (toolResponses !== undefined) {
|
if (toolResponses !== undefined) {
|
||||||
if (Array.isArray(toolResponses) && toolResponses.length === 0) return;
|
if (Array.isArray(toolResponses) && toolResponses.length === 0) return;
|
||||||
@@ -213,9 +213,11 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (status === 'run') {
|
if (status === 'run') {
|
||||||
|
addLog.info(`[dispatchWorkFlow] nodeRunWithActive: ${node.name}`);
|
||||||
return nodeRunWithActive(node);
|
return nodeRunWithActive(node);
|
||||||
}
|
}
|
||||||
if (status === 'skip') {
|
if (status === 'skip') {
|
||||||
|
addLog.info(`[dispatchWorkFlow] nodeRunWithActive: ${node.name}`);
|
||||||
return nodeRunWithSkip(node);
|
return nodeRunWithSkip(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +277,8 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
props.maxRunTimes--;
|
||||||
|
|
||||||
// get node running params
|
// get node running params
|
||||||
const params = getNodeRunParams(node);
|
const params = getNodeRunParams(node);
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise<H
|
|||||||
chatId,
|
chatId,
|
||||||
responseChatItemId,
|
responseChatItemId,
|
||||||
...variables,
|
...variables,
|
||||||
histories: histories.slice(-10),
|
histories: histories?.slice(-10) || [],
|
||||||
...body,
|
...body,
|
||||||
...dynamicInput
|
...dynamicInput
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const dispatchLafRequest = async (props: LafRequestProps): Promise<LafRes
|
|||||||
appId,
|
appId,
|
||||||
chatId,
|
chatId,
|
||||||
responseChatItemId,
|
responseChatItemId,
|
||||||
histories: histories.slice(0, 10)
|
histories: histories?.slice(0, 10)
|
||||||
},
|
},
|
||||||
variables,
|
variables,
|
||||||
...dynamicInput,
|
...dynamicInput,
|
||||||
|
|||||||
@@ -62,7 +62,10 @@ export const valueTypeFormat = (value: any, type?: WorkflowIOValueTypeEnum) => {
|
|||||||
return JSON.stringify(value);
|
return JSON.stringify(value);
|
||||||
}
|
}
|
||||||
if (type === 'number') return Number(value);
|
if (type === 'number') return Number(value);
|
||||||
if (type === 'boolean') return Boolean(value);
|
if (type === 'boolean') {
|
||||||
|
if (typeof value === 'string') return value === 'true';
|
||||||
|
return Boolean(value);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (type === WorkflowIOValueTypeEnum.datasetQuote && !Array.isArray(value)) {
|
if (type === WorkflowIOValueTypeEnum.datasetQuote && !Array.isArray(value)) {
|
||||||
return JSON.parse(value);
|
return JSON.parse(value);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user