diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index 8a2e6d653..47307b491 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -114,10 +114,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64 build-args: | - NEXT_PUBLIC_SEARCH_APPKEY=c4708d48f2de6ac5d2f0f443979ef92a - NEXT_PUBLIC_SEARCH_APPID=HZAF4C2T88 FASTGPT_HOME_DOMAIN=${{ matrix.domain_config.domain }} - SEARCH_APPWRITEKEY=${{ secrets.SEARCH_APPWRITEKEY }} - name: Build and push Docker images (IO) if: matrix.domain_config.suffix == 'io' @@ -130,8 +127,6 @@ jobs: labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64 build-args: | - NEXT_PUBLIC_SEARCH_APPKEY=c4708d48f2de6ac5d2f0f443979ef92a - NEXT_PUBLIC_SEARCH_APPID=HZAF4C2T88 FASTGPT_HOME_DOMAIN=${{ matrix.domain_config.domain }} update-images: diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml index e885420cc..2045a54c6 100644 --- a/.github/workflows/docs-preview.yml +++ b/.github/workflows/docs-preview.yml @@ -53,8 +53,6 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | - NEXT_PUBLIC_SEARCH_APPKEY=c4708d48f2de6ac5d2f0f443979ef92a - NEXT_PUBLIC_SEARCH_APPID=HZAF4C2T88 FASTGPT_HOME_DOMAIN=https://fastgpt.io outputs: tags: ${{ steps.datetime.outputs.datetime }} diff --git a/document/.env.template b/document/.env.template index 605aa3640..39d1843cd 100644 --- a/document/.env.template +++ b/document/.env.template @@ -1,4 +1 @@ -NEXT_PUBLIC_SEARCH_APPKEY= -SEARCH_APPWRITEKEY= -NEXT_PUBLIC_SEARCH_APPID= FASTGPT_HOME_DOMAIN= \ No newline at end of file diff --git a/document/Dockerfile b/document/Dockerfile index 32e5ee2ca..81a2c2299 100644 --- a/document/Dockerfile +++ b/document/Dockerfile @@ -19,26 +19,14 @@ RUN apk add --no-cache \ fontconfig WORKDIR /app -ARG NEXT_PUBLIC_SEARCH_APPKEY -ARG NEXT_PUBLIC_SEARCH_APPID -ARG SEARCH_APPWRITEKEY ARG FASTGPT_HOME_DOMAIN -ENV NEXT_PUBLIC_SEARCH_APPKEY=$NEXT_PUBLIC_SEARCH_APPKEY -ENV NEXT_PUBLIC_SEARCH_APPID=$NEXT_PUBLIC_SEARCH_APPID -ENV SEARCH_APPWRITEKEY=$SEARCH_APPWRITEKEY ENV FASTGPT_HOME_DOMAIN=$FASTGPT_HOME_DOMAIN COPY . . RUN npm install RUN npm run build -# Update search index if SEARCH_APPWRITEKEY is provided -RUN if [ -n "$SEARCH_APPWRITEKEY" ]; then \ - echo "SEARCH_APPWRITEKEY found, updating search index..." && \ - (npm run update-index-action || echo "Search index update failed, but continuing..."); \ - else \ - echo "SEARCH_APPWRITEKEY not provided, skipping search index update"; \ - fi + FROM base AS runner RUN apk add --no-cache curl diff --git a/document/README.md b/document/README.md index dbb3fb370..dfc05e4eb 100644 --- a/document/README.md +++ b/document/README.md @@ -1,29 +1,11 @@ # FastGPT 文档 这是FastGPT的官方文档,采用fumadoc框架。 - -## 配置文档搜索 - -点击[Algolia](https://dashboard.algolia.com/account/overview),进行注册账号,注册成功后需要点击页面的搜索,然后查看应用,默认会有一个应用。 - -![](./public/readme/algolia.png) - -拥有应用后点击个人头像,点击设置,点击`API Keys`查看自己的应用id和key。 - -![](./public/readme/algolia2.png) - -页面中的`Application ID`和`Search API Key`,`Write API KEY`就是环境变量对应的`NEXT_PUBLIC_SEARCH_APPID`和`NEXT_PUBLIC_SEARCH_APPKEY`,`SEARCH_APPWRITEKEY` - -![](./public/readme/algolia3.png) - ## 运行项目 要运行文档,首先需要进行环境变量配置,在文档的根目录下创建`.env.local`文件,填写以下环境变量: ```bash -SEARCH_APPWRITEKEY = #这是上面获取的Write api key -NEXT_PUBLIC_SEARCH_APPKEY = #这是上面获取的搜索key -NEXT_PUBLIC_SEARCH_APPID = #这是上面的搜索id FASTGPT_HOME_DOMAIN = #要跳转的FastGPT项目的域名,默认海外版 ``` diff --git a/document/app/api/search/route.ts b/document/app/api/search/route.ts index 4fadc43d1..0a5b94c16 100644 --- a/document/app/api/search/route.ts +++ b/document/app/api/search/route.ts @@ -1,7 +1,21 @@ import { source } from '@/lib/source'; +import { enhancedTokenizer } from '@/lib/tokenizer'; import { createFromSource } from 'fumadocs-core/search/server'; export const { GET } = createFromSource(source, { - // https://docs.orama.com/open-source/supported-languages - language: 'english' + // 使用中文分词器时不能设置 language 选项 + localeMap: { + en: { + language: 'english' + }, + 'zh-CN': { + components: { + tokenizer: enhancedTokenizer() + }, + search: { + threshold: 0, + tolerance: 0 + } + } + } }); diff --git a/document/clean-frontmatter.js b/document/clean-frontmatter.js deleted file mode 100644 index f0bcd3956..000000000 --- a/document/clean-frontmatter.js +++ /dev/null @@ -1,43 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const matter = require('gray-matter'); - -// ✅ 设置要处理的根目录(可修改为你的文档目录) -const rootDir = path.resolve(__dirname, 'content/docs'); - -// ✅ 仅保留的 frontmatter 字段 -const KEEP_FIELDS = ['title', 'description']; - -function cleanFrontmatter(filePath) { - const raw = fs.readFileSync(filePath, 'utf-8'); - const parsed = matter(raw); - - // 仅保留需要的字段 - const newData = {}; - for (const key of KEEP_FIELDS) { - if (parsed.data[key] !== undefined) { - newData[key] = parsed.data[key]; - } - } - - const cleaned = matter.stringify(parsed.content, newData); - fs.writeFileSync(filePath, cleaned, 'utf-8'); - console.log(`✔ Cleaned: ${path.relative(rootDir, filePath)}`); -} - -function walk(dir) { - const entries = fs.readdirSync(dir); - for (const entry of entries) { - const fullPath = path.join(dir, entry); - const stat = fs.statSync(fullPath); - - if (stat.isDirectory()) { - walk(fullPath); // 🔁 递归子目录 - } else if (entry.endsWith('.mdx')) { - cleanFrontmatter(fullPath); - } - } -} - -// 🚀 开始执行 -walk(rootDir); diff --git a/document/components/CustomSearchDialog.tsx b/document/components/CustomSearchDialog.tsx index cb41f594c..4e11d9ca0 100644 --- a/document/components/CustomSearchDialog.tsx +++ b/document/components/CustomSearchDialog.tsx @@ -1,6 +1,5 @@ 'use client'; // components/CustomSearchDialog.tsx -import { liteClient } from 'algoliasearch/lite'; import { useDocsSearch } from 'fumadocs-core/search/client'; import { SearchDialog, @@ -15,21 +14,11 @@ import { } from 'fumadocs-ui/components/dialog/search'; import { useI18n } from 'fumadocs-ui/contexts/i18n'; -if (!process.env.NEXT_PUBLIC_SEARCH_APPID || !process.env.NEXT_PUBLIC_SEARCH_APPKEY) { - throw new Error('NEXT_PUBLIC_SEARCH_APPID and NEXT_PUBLIC_SEARCH_APPKEY are not set'); -} - -const client = liteClient( - process.env.NEXT_PUBLIC_SEARCH_APPID, - process.env.NEXT_PUBLIC_SEARCH_APPKEY -); - export default function CustomSearchDialog(props: SharedProps) { const { locale } = useI18n(); const { search, setSearch, query } = useDocsSearch({ - type: 'algolia', - client, - indexName: 'document', + type: 'fetch', + api: '/api/search', locale }); diff --git a/document/content/docs/faq/other.mdx b/document/content/docs/faq/other.mdx index 7ebe6a974..3ba00f355 100644 --- a/document/content/docs/faq/other.mdx +++ b/document/content/docs/faq/other.mdx @@ -8,4 +8,4 @@ title: 其他问题 ## 想做多用户 -开源版未支持多用户,仅商业版支持。 +社区版未支持多用户,仅商业版支持。 diff --git a/document/content/docs/introduction/commercial.mdx b/document/content/docs/introduction/commercial.mdx index c9be5d806..619973e61 100644 --- a/document/content/docs/introduction/commercial.mdx +++ b/document/content/docs/introduction/commercial.mdx @@ -7,11 +7,11 @@ import { Alert } from '@/components/docs/Alert'; ## 简介 -FastGPT 商业版是基于 FastGPT 开源版的增强版本,增加了一些独有的功能。只需安装一个商业版镜像,并在开源版基础上填写对应的内网地址,即可快速使用商业版。 +FastGPT 商业版是基于 FastGPT 社区版的增强版本,增加了一些独有的功能。只需安装一个商业版镜像,并在社区版基础上填写对应的内网地址,即可快速使用商业版。 ## 功能差异 -| | 开源版 | 商业版 | Saas 版 | +| | 社区版 | 商业版 | Saas 版 | | ------------------------------ | ------------------------------------------ | ------ | ------- | | **应用构建** | | | | | 工作流编排 | ✅ | ✅ | ✅ | @@ -89,13 +89,13 @@ FastGPT 商业版软件根据不同的部署方式,分为 3 类收费模式。 ### 如何交付? -完整版应用 = 开源版镜像 + 商业版镜像 +完整版应用 = 社区版镜像 + 商业版镜像 我们会提供一个商业版镜像给你使用,该镜像需要一个 License 启动。 ### 二次开发如何操作? -可以修改开源版部分代码,不支持修改商业版镜像。完整版本=开源版+商业版镜像,所以是可以修改部分内容的。但是如果二开了,后续则需要自己进行代码合并升级。 +可以修改社区版部分代码,不支持修改商业版镜像。完整版本=社区版+商业版镜像,所以是可以修改部分内容的。但是如果二开了,后续则需要自己进行代码合并升级。 ### Sealos 运行费用 diff --git a/document/content/docs/introduction/development/configuration.mdx b/document/content/docs/introduction/development/configuration.mdx index 6023b0999..a7df6484a 100644 --- a/document/content/docs/introduction/development/configuration.mdx +++ b/document/content/docs/introduction/development/configuration.mdx @@ -5,12 +5,14 @@ description: FastGPT 配置参数介绍 由于环境变量不利于配置复杂的内容,新版 FastGPT 采用了 ConfigMap 的形式挂载配置文件,你可以在 `projects/app/data/config.json` 看到默认的配置文件。可以参考 [docker-compose 快速部署](/docs/development/docker/) 来挂载配置文件。 -**开发环境下**,你需要将示例配置文件 `config.json` 复制成 `config.local.json` 文件才会生效。 +**开发环境下**,你需要将示例配置文件 `config.json` 复制成 `config.local.json` 文件才会生效。 下面配置文件示例中包含了系统参数和各个模型配置: ## 4.8.20+ 版本新配置文件示例 + > 从4.8.20版本开始,模型在页面中进行配置。 + ```json { "feConfigs": { @@ -22,7 +24,8 @@ description: FastGPT 配置参数介绍 "vlmMaxProcess": 15, // 图片理解模型最大处理进程 "tokenWorkers": 50, // Token 计算线程保持数,会持续占用内存,不能设置太大。 "hnswEfSearch": 100, // 向量搜索参数,仅对 PG 和 OB 生效。越大,搜索越精确,但是速度越慢。设置为100,有99%+精度。 - "customPdfParse": { // 4.9.0 新增配置 + "customPdfParse": { + // 4.9.0 新增配置 "url": "", // 自定义 PDF 解析服务地址 "key": "", // 自定义 PDF 解析服务密钥 "doc2xKey": "", // doc2x 服务密钥 @@ -57,7 +60,7 @@ description: FastGPT 配置参数介绍 #### 2. 修改 FastGPT 配置文件 -开源版用户在 `config.json` 文件中添加 `systemEnv.customPdfParse.doc2xKey` 配置,并填写上申请到的 API Key。并重启服务。 +社区版用户在 `config.json` 文件中添加 `systemEnv.customPdfParse.doc2xKey` 配置,并填写上申请到的 API Key。并重启服务。 商业版用户在 Admin 后台根据表单指引填写 Doc2x 服务密钥。 diff --git a/document/content/docs/introduction/development/custom-models/marker.mdx b/document/content/docs/introduction/development/custom-models/marker.mdx index 0c39ddcb4..6b6ea3a28 100644 --- a/document/content/docs/introduction/development/custom-models/marker.mdx +++ b/document/content/docs/introduction/development/custom-models/marker.mdx @@ -9,7 +9,7 @@ PDF 是一个相对复杂的文件格式,在 FastGPT 内置的 pdf 解析器 市面上目前有多种解析 PDF 的方法,比如使用 [Marker](https://github.com/VikParuchuri/marker),该项目使用了 Surya 模型,基于视觉解析,可以有效提取图片、表格、公式等复杂内容。 -在 `FastGPT v4.9.0` 版本中,开源版用户可以在`config.json`文件中添加`systemEnv.customPdfParse`配置,来使用 Marker 解析 PDF 文件。商业版用户直接在 Admin 后台根据表单指引填写即可。需重新拉取 Marker 镜像,接口格式已变动。 +在 `FastGPT v4.9.0` 版本中,社区版用户可以在`config.json`文件中添加`systemEnv.customPdfParse`配置,来使用 Marker 解析 PDF 文件。商业版用户直接在 Admin 后台根据表单指引填写即可。需重新拉取 Marker 镜像,接口格式已变动。 ## 使用教程 @@ -23,6 +23,7 @@ PDF 是一个相对复杂的文件格式,在 FastGPT 内置的 pdf 解析器 docker pull crpi-h3snc261q1dosroc.cn-hangzhou.personal.cr.aliyuncs.com/marker11/marker_images:v0.2 docker run --gpus all -itd -p 7231:7232 --name model_pdf_v2 -e PROCESSES_PER_GPU="2" crpi-h3snc261q1dosroc.cn-hangzhou.personal.cr.aliyuncs.com/marker11/marker_images:v0.2 ``` + ### 2. 添加 FastGPT 文件配置 ```json @@ -52,7 +53,7 @@ docker run --gpus all -itd -p 7231:7232 --name model_pdf_v2 -e PROCESSES_PER_GPU ``` [Info] 2024-12-05 15:04:42 Parsing files from an external service -[Info] 2024-12-05 15:07:08 Custom file parsing is complete, time: 1316ms +[Info] 2024-12-05 15:07:08 Custom file parsing is complete, time: 1316ms ``` 然后你就可以发现,通过 Marker 解析出来的 pdf 会携带图片链接: @@ -63,14 +64,13 @@ docker run --gpus all -itd -p 7231:7232 --name model_pdf_v2 -e PROCESSES_PER_GPU ![alt text](/imgs/marker3.png) - ## 效果展示 以清华的 [ChatDev Communicative Agents for Software Develop.pdf](https://arxiv.org/abs/2307.07924) 为例,展示 Marker 解析的效果: -| | | | -| --- | --- | --- | -| ![alt text](/imgs/image-11.png) | ![alt text](/imgs/image-12.png) | ![alt text](/imgs/image-13.png) | +| | | | +| ------------------------------- | ------------------------------- | ------------------------------- | +| ![alt text](/imgs/image-11.png) | ![alt text](/imgs/image-12.png) | ![alt text](/imgs/image-13.png) | | ![alt text](/imgs/image-14.png) | ![alt text](/imgs/image-15.png) | ![alt text](/imgs/image-16.png) | 上图是分块后的结果,下图是 pdf 原文。整体图片、公式、表格都可以提取出来,效果还是杠杠的。 @@ -95,5 +95,5 @@ CUSTOM_READ_FILE_URL=http://xxxx.com/v1/parse/file CUSTOM_READ_FILE_EXTENSION=pdf ``` -* CUSTOM_READ_FILE_URL - 自定义解析服务的地址, host改成解析服务的访问地址,path 不能变动。 -* CUSTOM_READ_FILE_EXTENSION - 支持的文件后缀,多个文件类型,可用逗号隔开。 +- CUSTOM_READ_FILE_URL - 自定义解析服务的地址, host改成解析服务的访问地址,path 不能变动。 +- CUSTOM_READ_FILE_EXTENSION - 支持的文件后缀,多个文件类型,可用逗号隔开。 diff --git a/document/content/docs/upgrading/4-8/462.mdx b/document/content/docs/upgrading/4-8/462.mdx index c233f050d..8363aabe6 100644 --- a/document/content/docs/upgrading/4-8/462.mdx +++ b/document/content/docs/upgrading/4-8/462.mdx @@ -16,11 +16,12 @@ curl --location --request POST 'https://{{host}}/api/admin/initv462' \ ``` 初始化说明: + 1. 初始化全文索引 ## V4.6.2 功能介绍 -1. 新增 - 全文索引(需配合 Rerank 模型,在看怎么放到开源版,模型接口比较特殊) +1. 新增 - 全文索引(需配合 Rerank 模型,在看怎么放到社区版,模型接口比较特殊) 2. 新增 - 插件来源(预计4.7/4.8版本会正式使用) 3. 优化 - PDF读取 4. 优化 - docx文件读取,转成 markdown 并保留其图片内容 diff --git a/document/content/docs/upgrading/4-8/47.mdx b/document/content/docs/upgrading/4-8/47.mdx index ccb48f21e..5cb4f65cd 100644 --- a/document/content/docs/upgrading/4-8/47.mdx +++ b/document/content/docs/upgrading/4-8/47.mdx @@ -18,6 +18,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initv47' \ ``` 脚本功能: + 1. 初始化插件的 parentId ## 3. 升级 ReRank 模型 @@ -31,18 +32,17 @@ cohere的重排模型对中文不是很好,感觉不如 bge 的好用,接入 ```json { - "reRankModels": [ - { - "model": "rerank-multilingual-v2.0", // 这里的 model 需要对应 cohere 的模型名 - "name": "检索重排", // 随意 - "requestUrl": "https://api.cohere.ai/v1/rerank", - "requestAuth": "Coherer上申请的key" - } - ] + "reRankModels": [ + { + "model": "rerank-multilingual-v2.0", // 这里的 model 需要对应 cohere 的模型名 + "name": "检索重排", // 随意 + "requestUrl": "https://api.cohere.ai/v1/rerank", + "requestAuth": "Coherer上申请的key" + } + ] } ``` - ## V4.7 更新说明 1. 新增 - 工具调用模块,可以让LLM模型根据用户意图,动态的选择其他模型或插件执行。 @@ -57,7 +57,7 @@ cohere的重排模型对中文不是很好,感觉不如 bge 的好用,接入 10. 优化 - 变量输入弹窗。 11. 优化 - docker 部署,自动初始化副本集。 12. 优化 - 浏览器读取文件自动推断编码,减少乱码情况。 -13. 修复 - 开源版重排选不上。 +13. 修复 - 社区版重排选不上。 14. 修复 - http 请求 body,不使用时,传入undefined。(会造成部分GET请求失败) 15. 新增 - 支持 http url 使用变量。 16. 修复 - 469 的提取的提示词容易造成幻觉。 diff --git a/document/content/docs/upgrading/4-9/4910.mdx b/document/content/docs/upgrading/4-9/4910.mdx index 96b36ea8d..8b05329d5 100644 --- a/document/content/docs/upgrading/4-9/4910.mdx +++ b/document/content/docs/upgrading/4-9/4910.mdx @@ -23,7 +23,7 @@ description: FastGPT V4.9.10 更新说明 2. 知识库预处理参数增加 “分块条件”,可控制某些情况下不进行分块处理。 3. 知识库预处理参数增加 “段落优先” 模式,可控制最大段落深度。原“长度优先”模式,不再内嵌段落优先逻辑。 4. 工作流调整为单向接入和接出,支持快速的添加下一步节点。 -5. 开放飞书和语雀知识库到开源版。 +5. 开放飞书和语雀知识库到社区版。 6. gemini 和 claude 最新模型预设。 ## ⚙️ 优化 diff --git a/document/content/docs/upgrading/4-9/496.mdx b/document/content/docs/upgrading/4-9/496.mdx index 3d4f8829e..aa7d839a2 100644 --- a/document/content/docs/upgrading/4-9/496.mdx +++ b/document/content/docs/upgrading/4-9/496.mdx @@ -29,6 +29,7 @@ description: FastGPT V4.9.6 更新说明 3. 连续工具调用,上下文截断异常 ## 升级指南 + ### 1. 做好数据备份 ### 2. 部署 MCP server 服务 @@ -39,15 +40,15 @@ description: FastGPT V4.9.6 更新说明 ```yml fastgpt-mcp-server: - container_name: fastgpt-mcp-server - image: ghcr.io/labring/fastgpt-mcp_server:v4.9.6 - ports: - - 3005:3000 - networks: - - fastgpt - restart: always - environment: - - FASTGPT_ENDPOINT=http://fastgpt:3000 + container_name: fastgpt-mcp-server + image: ghcr.io/labring/fastgpt-mcp_server:v4.9.6 + ports: + - 3005:3000 + networks: + - fastgpt + restart: always + environment: + - FASTGPT_ENDPOINT=http://fastgpt:3000 ``` #### Sealos 部署 @@ -56,14 +57,15 @@ fastgpt-mcp-server: ### 3. 修改 FastGPT 容器环境变量 -#### 开源版 +#### 社区版 修改`config.json`配置文件,增加: `"feconfigs.mcpServerProxyEndpoint": "fastgpt-mcp-server 的访问地址"`, 末尾不要携带/,例如: + ```json { "feConfigs": { "lafEnv": "https://laf.dev", - "mcpServerProxyEndpoint": "https://mcp.fastgpt.cn" + "mcpServerProxyEndpoint": "https://mcp.fastgpt.cn" } } ``` diff --git a/document/lib/tokenizer.ts b/document/lib/tokenizer.ts new file mode 100644 index 000000000..d86edfa65 --- /dev/null +++ b/document/lib/tokenizer.ts @@ -0,0 +1,338 @@ +import { createTokenizer } from '@orama/tokenizers/mandarin'; + +export const enhancedTokenizer = () => { + // 整词配置 - 需要保持完整的词汇 + const wholeWords = [ + // 产品相关 + 'fastgpt', + 'FastGPT', + '快速GPT', + 'Saas', + 'SaaS', + '云服务', + '社区版', + '商业版', + '开源版', + '企业版', + '专业版', + '智能对话系统', + 'AI应用平台', + '知识库问答系统', + + // 核心功能模块 + '知识库', + '工作流', + '应用构建', + '对话管理', + '可视化编排', + '拖拽式设计', + '零代码搭建', + '低代码开发', + '流程编排', + + // 工作流节点 + 'AI对话', + '知识库搜索', + '问题分类', + '内容提取', + '用户选择', + '表单输入', + '文本编辑', + '指定回复', + '文档解析', + 'HTTP请求', + '真假判断', + '变量更新', + '代码运行', + '循环', + '指代消解', + '自定义反馈', + '工具调用', + + // AI模型相关 + 'AI', + 'Agent', + 'LLM', + '大语言模型', + 'ChatGPT', + 'GPT-4', + 'GPT-3.5', + 'Claude', + '文心一言', + '通义千问', + 'DeepSeek', + 'Function Call', + 'Prompt', + '提示词', + '系统提示词', + 'Temperature', + '温度参数', + 'Token', + 'OpenAI', + 'Anthropic', + '百度', + '阿里云', + '智谱AI', + 'One-API', + 'AI-Proxy', + 'Ollama', + 'Xinference', + + // 技术术语 + 'API', + 'OpenAPI', + 'SSO', + 'MCP', + '向量数据库', + '语义搜索', + 'embedding', + 'RAG', + '检索增强生成', + 'PGVector', + 'Milvus', + 'MongoDB', + 'PostgreSQL', + 'Redis', + 'Docker', + 'Sealos', + 'Nginx', + 'Cloudflare', + + // 数据处理 + '数据集', + 'Dataset', + '文档导入', + '数据处理', + '索引模型', + '重排模型', + '分块策略', + '增强处理', + '问答拆分', + '向量化', + '文本分割', + '知识结构化', + '自动索引', + '图片标注', + 'OCR识别', + + // 集成相关 + 'Webhook', + '第三方集成', + '企业微信', + '钉钉', + 'DingTalk', + '飞书', + 'Feishu', + 'Lark', + '微信公众号', + + // 业务概念 + '沙盒', + 'Sandbox', + '插件', + 'Plugin', + '模板', + '权限管理', + '团队协作', + '用户角色', + '访问控制', + '数据安全', + '隐私保护', + + // 界面元素 + '工作台', + 'Dashboard', + '调试预览', + '发布分享', + '对话窗口', + '聊天界面', + '引用展示', + '猜你想问', + '文件上传', + '表单配置', + '系统配置', + '模型配置', + '参数设置', + '高级编排', + '简易模式', + '专业模式', + + // 搜索插件 + 'Bing搜索', + 'Google搜索', + 'SearXNG搜索', + 'Doc2x插件', + + // 文件格式 + 'PDF', + 'Word', + 'Excel', + 'CSV', + 'TXT', + 'Markdown', + 'JSON', + + // 部署运维 + '环境变量', + 'config.json', + '配置文件', + '负载均衡', + '高可用', + '容灾备份', + '监控告警', + '性能优化', + '响应速度', + '并发处理', + '缓存机制', + + // 多语言 + 'i18n', + '国际化', + '中文', + '英文', + '日文', + '多语言支持', + + // 版本管理 + '版本更新', + '升级指南', + '更新日志', + '兼容性', + '迁移指南' + ]; + + // 同义词配置 - 为整词添加相关的同义词 + const synonymsMap: Record = { + // 产品版本相关 + 开源版: ['社区版', '开源', '开源版', '免费版'], + 商业版: ['商业版', '付费版', '企业版', '专业版', '标准版', '高级版'], + 社区版: ['社区版', '开源版', '免费版'], + 企业版: ['企业版', '商业版', '付费版', '专业版'], + + // 核心功能 + 知识库: ['知识库', '知识体系', '数据库', '文档库', '资料库', '信息库', '语料库'], + 工作流: ['工作流', '流程', '工作流程', '业务流程', '可视化流程', '流程图', '编排', '组合'], + 应用构建: ['应用构建', '应用搭建', '应用创建', '搭建', '构建', '创建应用'], + 对话管理: ['对话管理', '聊天管理', '会话管理', '对话控制'], + + // AI相关 + AI: ['AI', '人工智能', '机器学习', '深度学习', '智能', '智能化'], + 大语言模型: ['大语言模型', 'LLM', '语言模型', '大模型', '生成式AI', '对话模型'], + Agent: ['Agent', '智能体', '代理', '智能助手', 'AI助理', '机器人'], + 提示词: ['提示词', 'Prompt', '指令', '命令', '提示', '指示'], + + // 技术概念 + API: ['API', '接口', '接口调用', '应用程序接口', '集成接口', '外部接口'], + 向量数据库: ['向量数据库', '向量存储', '向量索引', 'Vector Database'], + 语义搜索: [ + '语义搜索', + '语义检索', + '智能检索', + '相似度搜索', + '向量搜索', + '检索系统', + '搜索引擎' + ], + RAG: ['RAG', '检索增强生成', '检索增强', '知识检索'], + + // 数据处理 + 数据集: ['数据集', 'Dataset', '数据源', '数据', '资料'], + 文档导入: ['文档导入', '文件导入', '数据导入', '批量导入', '上传文档'], + 数据处理: ['数据处理', '文档处理', '内容处理', '文件解析', '信息提取', '结构化处理'], + 向量化: ['向量化', 'embedding', '向量转换', '特征提取'], + + // 界面相关 + 工作台: ['工作台', 'Dashboard', '控制台', '管理台', '操作台', '仪表板'], + 调试预览: ['调试预览', '预览', '调试', '测试', '试运行'], + 发布分享: ['发布分享', '发布', '分享', '部署', '上线'], + + // 插件相关 + 插件: ['插件', 'Plugin', '扩展', '组件', '模块', '附加功能', '外部工具', '第三方工具'], + 搜索插件: ['搜索插件', '搜索工具', '搜索扩展', '网络搜索'], + + // 集成相关 + 第三方集成: ['第三方集成', '外部集成', '平台集成', '系统对接', '接口集成'], + 企业微信: ['企业微信', '企微', 'WeWork'], + 钉钉: ['钉钉', 'DingTalk', '阿里钉钉'], + 飞书: ['飞书', 'Feishu', 'Lark', '字节飞书'], + + // 权限管理 + 权限管理: ['权限管理', '访问控制', '用户权限', '权限控制', '授权管理'], + 团队协作: ['团队协作', '多人协作', '协同工作', '团队管理'], + 用户角色: ['用户角色', '角色管理', '权限角色', '用户权限'], + + // 安全相关 + 数据安全: ['数据安全', '信息安全', '数据保护', '安全防护'], + 隐私保护: ['隐私保护', '数据隐私', '信息保护', '隐私安全'], + 访问控制: ['访问控制', '权限控制', '访问权限', '安全认证'], + + // 部署相关 + Docker: ['Docker', '容器', '容器化', '镜像部署'], + 环境变量: ['环境变量', '配置变量', '系统变量', '环境配置'], + 配置文件: ['配置文件', '配置', '设置文件', 'config'], + + // 性能相关 + 性能优化: ['性能优化', '系统优化', '速度提升', '效率优化', '性能调优'], + 响应速度: ['响应速度', '响应时间', '处理速度', '执行速度'], + 并发处理: ['并发处理', '并发', '多线程', '高并发'], + 缓存机制: ['缓存机制', '缓存', '内存缓存', '数据缓存'], + + // 多语言 + 国际化: ['国际化', 'i18n', '多语言', '本地化'], + 多语言支持: ['多语言支持', '多语言', '国际化支持', '语言切换'], + + // 版本管理 + 版本更新: ['版本更新', '系统更新', '功能更新', '补丁更新', '版本升级'], + 升级指南: ['升级指南', '更新指南', '迁移指南', '升级说明'], + 更新日志: ['更新日志', '版本日志', '修改日志', '发布日志'], + + // 工作流节点 + AI对话: ['AI对话', 'AI聊天', '智能对话', '机器人对话'], + 知识库搜索: ['知识库搜索', '文档搜索', '资料搜索', '内容搜索'], + 问题分类: ['问题分类', '意图识别', '分类器', '问题识别'], + 内容提取: ['内容提取', '信息提取', '文本提取', '数据提取'], + 用户选择: ['用户选择', '选择器', '用户输入', '交互选择'], + 表单输入: ['表单输入', '用户输入', '数据输入', '信息收集'], + 文档解析: ['文档解析', '文件解析', '内容解析', '格式转换'], + 代码运行: ['代码运行', '代码执行', '脚本执行', '沙盒执行'], + 工具调用: ['工具调用', '函数调用', 'Function Call', 'API调用'] + }; + + const baseTokenizer = createTokenizer(); + + return { + ...baseTokenizer, + tokenize: (text: string) => { + // 先处理整词,用特殊标记保护它们 + let processedText = text; + const protectedTokens = new Map(); + let tokenIndex = 0; + + wholeWords.forEach((word) => { + const regex = new RegExp(`\\b${word}\\b`, 'gi'); + processedText = processedText.replace(regex, (match) => { + const placeholder = `__PROTECTED_TOKEN_${tokenIndex}__`; + protectedTokens.set(placeholder, match.toLowerCase()); + tokenIndex++; + return placeholder; + }); + }); + + // 用基础分词器处理 + let tokens = baseTokenizer.tokenize(processedText); + + // 恢复被保护的整词,并添加同义词 + tokens = tokens + .map((token) => { + if (protectedTokens.has(token)) { + const originalWord = protectedTokens.get(token); + return synonymsMap[originalWord] || [originalWord]; + } + return token; + }) + .flat(); + + return [...new Set(tokens)]; // 去重 + } + }; +}; diff --git a/document/meta-order.js b/document/meta-order.js deleted file mode 100644 index b6abf0bbd..000000000 --- a/document/meta-order.js +++ /dev/null @@ -1,92 +0,0 @@ -import fs from 'fs-extra'; -import path from 'path'; - -// 从 mdx 文件中读取 weight -async function getWeightFromFile(filePath) { - const content = await fs.readFile(filePath, 'utf-8'); - const weightMatch = content.match(/weight:\s*(\d+)/); - return weightMatch ? parseInt(weightMatch[1], 10) : 0; -} - -// 从 meta.json 中读取最小 weight(用于子目录) -async function getWeightFromMeta(dir) { - const metaPath = path.join(dir, 'meta.json'); - if (!(await fs.pathExists(metaPath))) return Infinity; - - try { - const meta = await fs.readJson(metaPath); - const pages = meta.pages || []; - let minWeight = Infinity; - - for (const pageName of pages) { - const mdxPath = path.join(dir, `${pageName}.mdx`); - if (await fs.pathExists(mdxPath)) { - const w = await getWeightFromFile(mdxPath); - if (w < minWeight) minWeight = w; - } - } - return minWeight === Infinity ? 0 : minWeight; - } catch { - return 0; - } -} - -// 主函数,返回当前目录的最小 weight -async function generateMetaRecursive(dir) { - const entries = await fs.readdir(dir, { withFileTypes: true }); - const items = []; - - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - - if (entry.isDirectory()) { - const subWeight = await generateMetaRecursive(fullPath); - items.push({ name: entry.name, weight: subWeight }); - } else if ( - entry.isFile() && - entry.name.endsWith('.mdx') && - !entry.name.endsWith('.en.mdx') - ) { - const nameWithoutExt = entry.name.replace(/\.mdx$/, ''); - const weight = await getWeightFromFile(fullPath); - items.push({ name: nameWithoutExt, weight }); - } - } - - // 排序 pages - items.sort((a, b) => a.weight - b.weight); - const pages = items.map((item) => item.name); - - // 读取或创建 meta.json - const metaPath = path.join(dir, 'meta.json'); - let meta = { - title: 'FastGPT', - description: 'FastGPT Docs', - }; - - if (await fs.pathExists(metaPath)) { - try { - meta = await fs.readJson(metaPath); - } catch { - console.warn(`⚠️ Failed to parse existing meta.json at ${metaPath}, using defaults.`); - } - } - - meta.pages = pages; - - // 写入 meta.json,格式化为一行的 pages - const jsonString = JSON.stringify(meta, null, 2); - const oneLinePages = `"pages": ${JSON.stringify(pages)}`; - const finalJson = jsonString.replace(/"pages": \[[\s\S]*?\]/, oneLinePages); - await fs.writeFile(metaPath, finalJson, 'utf-8'); - console.log(`✅ Updated meta.json in ${dir}`); - - return items.length > 0 ? items[0].weight : 0; -} - -// 启动 -const targetDir = './content/docs/introduction/development/upgrading'; - -generateMetaRecursive(targetDir) - .then(() => console.log('🎉 All meta.json files generated/updated!')) - .catch((err) => console.error(err)); diff --git a/document/meta.js b/document/meta.js deleted file mode 100644 index 7b9b1aca7..000000000 --- a/document/meta.js +++ /dev/null @@ -1,59 +0,0 @@ -import fs from 'fs-extra'; -import path from 'path'; - -async function generateMeta(dir) { - const entries = await fs.readdir(dir, { withFileTypes: true }); - - const pages = []; - - for (const entry of entries) { - if (entry.isDirectory()) { - pages.push(entry.name); - } else if ( - entry.isFile() && - entry.name.endsWith('.mdx') && - !entry.name.endsWith('.en.mdx') - ) { - const nameWithoutExt = entry.name.replace(/\.mdx$/, ''); - pages.push(nameWithoutExt); - } - } - - const metaPath = path.join(dir, 'meta.json'); - - // 使用 JSON.stringify,spaces设为2,数组不换行 - // 通过 replacer 参数实现“pages”数组一行 - const jsonString = JSON.stringify( - { pages }, - (key, value) => { - if (key === 'pages') { - return value; // 保持pages数组原样 - } - return value; - }, - 2 - ); - - // 手动替换 pages 数组换行,变成一行显示 - const oneLinePages = `"pages": ${JSON.stringify(pages)}`; - const finalJson = jsonString.replace( - /"pages": \[[^\]]*\]/, - oneLinePages - ); - - await fs.writeFile(metaPath, finalJson, 'utf-8'); - console.log(`Generated meta.json in ${dir}`); - - // 递归处理子目录 - for (const entry of entries) { - if (entry.isDirectory()) { - await generateMeta(path.join(dir, entry.name)); - } - } -} - -const targetDir = './content/docs/development/openapi'; - -generateMeta(targetDir) - .then(() => console.log('All meta.json files generated!')) - .catch((err) => console.error(err)); diff --git a/document/package-lock.json b/document/package-lock.json index f1c0b08d1..42f7e78b6 100644 --- a/document/package-lock.json +++ b/document/package-lock.json @@ -11,7 +11,6 @@ "dependencies": { "@orama/orama": "^3.1.11", "@orama/tokenizers": "^3.1.11", - "algoliasearch": "^5.34.0", "fast-glob": "^3.3.3", "fs-extra": "^11.3.0", "fumadocs-core": "15.6.3", @@ -47,6 +46,8 @@ "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.34.0.tgz", "integrity": "sha512-d6ardhDtQsnMpyr/rPrS3YuIE9NYpY4rftkC7Ap9tyuhZ/+V3E/LH+9uEewPguKzVqduApdwJzYq2k+vAXVEbQ==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0", "@algolia/requester-browser-xhr": "5.34.0", @@ -62,6 +63,8 @@ "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.34.0.tgz", "integrity": "sha512-WXIByjHNA106JO1Dj6b4viSX/yMN3oIB4qXr2MmyEmNq0MgfuPfPw8ayLRIZPa9Dp27hvM3G8MWJ4RG978HYFw==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0", "@algolia/requester-browser-xhr": "5.34.0", @@ -77,6 +80,8 @@ "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.34.0.tgz", "integrity": "sha512-JeN1XJLZIkkv6yK0KT93CIXXk+cDPUGNg5xeH4fN9ZykYFDWYRyqgaDo+qvg4RXC3WWkdQ+hogQuuCk4Y3Eotw==", "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 14.0.0" } @@ -86,6 +91,8 @@ "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.34.0.tgz", "integrity": "sha512-gdFlcQa+TWXJUsihHDlreFWniKPFIQ15i5oynCY4m9K3DCex5g5cVj9VG4Hsquxf2t6Y0yv8w6MvVTGDO8oRLw==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0", "@algolia/requester-browser-xhr": "5.34.0", @@ -101,6 +108,8 @@ "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.34.0.tgz", "integrity": "sha512-g91NHhIZDkh1IUeNtsUd8V/ZxuBc2ByOfDqhCkoQY3Z/mZszhpn3Czn6AR5pE81fx793vMaiOZvQVB5QttArkQ==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0", "@algolia/requester-browser-xhr": "5.34.0", @@ -116,6 +125,8 @@ "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.34.0.tgz", "integrity": "sha512-cvRApDfFrlJ3Vcn37U4Nd/7S6T8cx7FW3mVLJPqkkzixv8DQ/yV+x4VLirxOtGDdq3KohcIbIGWbg1QuyOZRvQ==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0", "@algolia/requester-browser-xhr": "5.34.0", @@ -131,6 +142,8 @@ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.34.0.tgz", "integrity": "sha512-m9tK4IqJmn+flEPRtuxuHgiHmrKV0su5fuVwVpq8/es4DMjWMgX1a7Lg1PktvO8AbKaTp9kTtBAPnwXpuCwmEg==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0", "@algolia/requester-browser-xhr": "5.34.0", @@ -146,6 +159,8 @@ "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.34.0.tgz", "integrity": "sha512-2rxy4XoeRtIpzxEh5u5UgDC5HY4XbNdjzNgFx1eDrfFkSHpEVjirtLhISMy2N5uSFqYu1uUby5/NC1Soq8J7iw==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0", "@algolia/requester-browser-xhr": "5.34.0", @@ -161,6 +176,8 @@ "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.34.0.tgz", "integrity": "sha512-OJiDhlJX8ZdWAndc50Z6aUEW/YmnhFK2ul3rahMw5/c9Damh7+oY9SufoK2LimJejy+65Qka06YPG29v2G/vww==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0", "@algolia/requester-browser-xhr": "5.34.0", @@ -176,6 +193,8 @@ "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.34.0.tgz", "integrity": "sha512-fzNQZAdVxu/Gnbavy8KW5gurApwdYcPW6+pjO7Pw8V5drCR3eSqnOxSvp79rhscDX8ezwqMqqK4F3Hsq+KpRzg==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0", "@algolia/requester-browser-xhr": "5.34.0", @@ -191,6 +210,8 @@ "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.34.0.tgz", "integrity": "sha512-gEI0xjzA/xvMpEdYmgQnf6AQKllhgKRtnEWmwDrnct+YPIruEHlx1dd7nRJTy/33MiYcCxkB4khXpNrHuqgp3Q==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0" }, @@ -203,6 +224,8 @@ "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.34.0.tgz", "integrity": "sha512-5SwGOttpbACT4jXzfSJ3mnTcF46SVNSnZ1JjxC3qBa3qKi4U0CJGzuVVy3L798u8dG5H0SZ2MAB5v7180Gnqew==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0" }, @@ -215,6 +238,8 @@ "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.34.0.tgz", "integrity": "sha512-409XlyIyEXrxyGjWxd0q5RASizHSRVUU0AXPCEdqnbcGEzbCgL1n7oYI8YxzE/RqZLha+PNwWCcTVn7EE5tyyQ==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-common": "5.34.0" }, @@ -1466,7 +1491,6 @@ "version": "3.1.11", "resolved": "https://registry.npmjs.org/@orama/tokenizers/-/tokenizers-3.1.11.tgz", "integrity": "sha512-fwULrEdbP5/83gFjaX1X/l7lzdD7LxBT8YbAzcY89BmXjJcJETU/5qckp4ZNDMhRRjJUSGKH4bAXHsm6yu+ZPw==", - "license": "Apache-2.0", "dependencies": { "@orama/orama": "3.1.11" }, @@ -2723,6 +2747,8 @@ "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.34.0.tgz", "integrity": "sha512-wioVnf/8uuG8Bmywhk5qKIQ3wzCCtmdvicPRb0fa3kKYGGoewfgDqLEaET1MV2NbTc3WGpPv+AgauLVBp1nB9A==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@algolia/client-abtesting": "5.34.0", "@algolia/client-analytics": "5.34.0", diff --git a/document/package.json b/document/package.json index c68784b7e..312594179 100644 --- a/document/package.json +++ b/document/package.json @@ -4,8 +4,6 @@ "private": true, "scripts": { "build": "next build", - "update-index-action": "node ./update-index.mjs", - "update-index": "node --env-file=.env.local ./update-index.mjs", "dev": "next dev --turbo", "start": "next start", "postinstall": "fumadocs-mdx" @@ -13,7 +11,6 @@ "dependencies": { "@orama/orama": "^3.1.11", "@orama/tokenizers": "^3.1.11", - "algoliasearch": "^5.34.0", "fast-glob": "^3.3.3", "fs-extra": "^11.3.0", "fumadocs-core": "15.6.3", diff --git a/document/github.js b/document/script/initDocTime.js similarity index 100% rename from document/github.js rename to document/script/initDocTime.js diff --git a/document/update-index.mjs b/document/update-index.mjs deleted file mode 100644 index 1e809e3d0..000000000 --- a/document/update-index.mjs +++ /dev/null @@ -1,28 +0,0 @@ -import { algoliasearch } from 'algoliasearch'; -import { sync } from 'fumadocs-core/search/algolia'; -import * as fs from 'node:fs'; - -async function main() { - const content = fs.readFileSync('.next/server/app/static.json.body'); - - // now you can pass it to `sync` - /** @type {import('fumadocs-core/search/algolia').DocumentRecord[]} **/ - const records = JSON.parse(content.toString()); - - if (!process.env.NEXT_PUBLIC_SEARCH_APPID || !process.env.SEARCH_APPWRITEKEY || !process.env.SEARCH_APPWRITEKEY) { - console.log('NEXT_PUBLIC_SEARCH_APPID or SEARCH_APPWRITEKEY is not set'); - return; - } - - const client = algoliasearch( - process.env.NEXT_PUBLIC_SEARCH_APPID || '', - process.env.SEARCH_APPWRITEKEY || '' - ); - - void sync(client, { - indexName: 'document', - documents: records - }); -} - -main(); diff --git a/package.json b/package.json index 0bfb5ac0f..14ea30c9b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "prepare": "husky install", "format-code": "prettier --config \"./.prettierrc.js\" --write \"./**/src/**/*.{ts,tsx,scss}\"", "format-doc": "zhlint --dir ./document/ *.mdx --fix", - "initDocTime": "node ./document/github.js", + "initDocTime": "node ./document/script/initDocTime.js", "initDocToc": "node ./document/lib/generateToc.js", "gen:theme-typings": "chakra-cli tokens packages/web/styles/theme.ts --out node_modules/.pnpm/node_modules/@chakra-ui/styled-system/dist/theming.types.d.ts", "postinstall": "pnpm gen:theme-typings", diff --git a/packages/web/i18n/zh-CN/common.json b/packages/web/i18n/zh-CN/common.json index d4f1126c6..862994d0c 100644 --- a/packages/web/i18n/zh-CN/common.json +++ b/packages/web/i18n/zh-CN/common.json @@ -159,7 +159,7 @@ "code_error.outlink_error.un_auth_user": "身份校验失败", "code_error.plugin_error.not_exist": "工具不存在", "code_error.plugin_error.un_auth": "无权操作该工具", - "code_error.system_error.community_version_num_limit": "超出开源版数量限制,请升级商业版: https://fastgpt.in", + "code_error.system_error.community_version_num_limit": "超出社区版数量限制,请升级商业版: https://fastgpt.in", "code_error.system_error.license_app_amount_limit": "超出系统最大应用数量", "code_error.system_error.license_dataset_amount_limit": "超出系统最大知识库数量", "code_error.system_error.license_user_amount_limit": "超出系统最大用户数量",