V4.12.0 features (#5435)

* add logs chart (#5352)

* charts

* chart data

* log chart

* delete

* rename api

* fix

* move api

* fix

* fix

* pro config

* fix

* feat: Repository interaction (#5356)

* feat: 1好像功能没问题了,明天再测

* feat: 2 解决了昨天遗留的bug,但全选按钮又bug了

* feat: 3 第三版,解决了全选功能bug

* feat: 4 第四版,下面改小细节

* feat: 5 我勒个痘

* feat: 6

* feat: 6 pr

* feat: 7

* feat: 8

* feat: 9

* feat: 10

* feat: 11

* feat: 12

* perf: checkbox ui

* refactor: tweak login loyout (#5357)

Co-authored-by: Archer <545436317@qq.com>

* login ui

* app chat log chart pro display (#5392)

* app chat log chart pro display

* add canopen props

* perf: pro tag tip

* perf: pro tag tip

* feat: openrouter provider (#5406)

* perf: login ui

* feat: openrouter provider

* provider

* perf: custom error throw

* perf: emb batch (#5407)

* perf: emb batch

* perf: vector retry

* doc

* doc (#5411)

* doc

* fix: team folder will add to workflow

* fix: generateToc shell

* Tool price (#5376)

* resolve conflicts for cherry-pick

* fix i18n

* Enhance system plugin template data structure and update ToolSelectModal to include CostTooltip component

* refactor: update systemKeyCost type to support array of objects in plugin and workflow types

* refactor: simplify systemKeyCost type across plugin and workflow types to a single number

* refactor: streamline systemKeyCost handling in plugin and workflow components

* fix

* fix

* perf: toolset price config;fix: workflow array selector ui (#5419)

* fix: workflow array selector ui

* update default model tip

* perf: toolset price config

* doc

* fix: test

* Refactor/chat (#5418)

* refactor: add homepage configuration; add home chat page; add side bar animated collapse and layout

* fix: fix lint rules

* chore: improve logics and code

* chore: more clearer logics

* chore: adjust api

---------

Co-authored-by: Archer <545436317@qq.com>

* perf: chat setting code

* del history

* logo image

* perf: home chat ui

* feat: enhance chat response handling with external links and user info (#5427)

* feat: enhance chat response handling with external links and user info

* fix

* cite code

* perf: toolset add in workflow

* fix: test

* fix: search paraentId

* Fix/chat (#5434)

* wip: rebase了upstream

* wip: adapt mobile UI

* fix: fix chat page logic and UI

* fix: fix UI and improve some logics

* fix: model selector missing logo; vision model to retrieve file

* perf: role selector

* fix: chat ui

* optimize export app chat log (#5436)

* doc

* chore: move components to proper directory; fix the api to get app list (#5437)

* chore: improve team app panel display form (#5438)

* feat: add home chat log tab

* chore: improve team app panel display form

* chore: improve log panel

* fix: spec

* doc

* fix: log permission

* fix: dataset schema required

* add loading status

* remove ui weight

* manage log

* fix: log detail per

* doc

* fix: log menu

* rename permission

* bg color

* fix: app log per

* fix: log key selector

* fix: log

* doc

---------

Co-authored-by: heheer <zhiyu44@qq.com>
Co-authored-by: colnii <1286949794@qq.com>
Co-authored-by: 伍闲犬 <76519998+xqvvu@users.noreply.github.com>
Co-authored-by: Ctrlz <143257420+ctrlz526@users.noreply.github.com>
Co-authored-by: 伍闲犬 <whoeverimf5@gmail.com>
Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
Archer 2025-08-12 22:22:18 +08:00 committed by GitHub
parent c6e58291f7
commit c51395b2c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
239 changed files with 9336 additions and 3128 deletions

View File

@ -272,7 +272,7 @@ curl --location --request POST 'https://oneapi.xxx/v1/chat/completions' \
--header 'Authorization: Bearer sk-xxxx' \
--header 'Content-Type: application/json' \
--data-raw '{
"model": "gpt-4o-mini",
"model": "gpt-5",
"temperature": 0.01,
"max_tokens": 8000,
"stream": true,
@ -306,19 +306,13 @@ curl --location --request POST 'https://oneapi.xxx/v1/chat/completions' \
```json
{
"id": "chatcmpl-A7kwo1rZ3OHYSeIFgfWYxu8X2koN3",
"object": "chat.completion.chunk",
"created": 1726412126,
"model": "gpt-4o-mini-2024-07-18",
"system_fingerprint": "fp_483d39d857",
"choices": [
{
"index": 0,
"delta": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "chatcmpl-A7kwo1rZ3OHYSeIFgfWYxu8X2koN3",
"object": "chat.completion.chunk",
"created": 1726412126,
"model": "gpt-5",
"system_fingerprint": "fp_483d39d857",
"choices": [
{
"index": 0,
"id": "call_0n24eiFk8OUyIyrdEbLdirU7",
"type": "function",
@ -347,7 +341,7 @@ curl --location --request POST 'https://oneapi.xxxx/v1/chat/completions' \
--header 'Authorization: Bearer sk-xxx' \
--header 'Content-Type: application/json' \
--data-raw '{
"model": "gpt-4o-mini",
"model": "gpt-5",
"temperature": 0.01,
"max_tokens": 8000,
"stream": true,

View File

@ -94,8 +94,8 @@ import { Alert } from '@/components/docs/Alert';
"isCustom": true, // 是否为自定义模型
"isActive": true, // 是否启用
"provider": "OpenAI", // 模型提供商主要用于分类展示目前已经内置提供商包括https://github.com/labring/FastGPT/blob/main/packages/global/core/ai/provider.ts, 可 pr 提供新的提供商,或直接填写 Other
"model": "gpt-4o-mini", // 模型ID(对应OneAPI中渠道的模型名)
"name": "gpt-4o-mini", // 模型别名
"model": "gpt-5", // 模型ID(对应OneAPI中渠道的模型名)
"name": "gpt-5", // 模型别名
"maxContext": 125000, // 最大上下文
"maxResponse": 16000, // 最大回复
"quoteMaxToken": 120000, // 最大引用内容
@ -303,8 +303,8 @@ OneAPI 的语言识别接口,无法正确的识别其他模型(会始终识
"llmModels": [
{
"provider": "OpenAI", // 模型提供商主要用于分类展示目前已经内置提供商包括https://github.com/labring/FastGPT/blob/main/packages/global/core/ai/provider.ts, 可 pr 提供新的提供商,或直接填写 Other
"model": "gpt-4o-mini", // 模型名(对应OneAPI中渠道的模型名)
"name": "gpt-4o-mini", // 模型别名
"model": "gpt-5", // 模型名(对应OneAPI中渠道的模型名)
"name": "gpt-5", // 模型别名
"maxContext": 125000, // 最大上下文
"maxResponse": 16000, // 最大回复
"quoteMaxToken": 120000, // 最大引用内容

View File

@ -1249,7 +1249,7 @@ curl --location --request POST 'https://api.fastgpt.in/api/core/dataset/searchTe
"usingReRank": false,
"datasetSearchUsingExtensionQuery": true,
"datasetSearchExtensionModel": "gpt-4o-mini",
"datasetSearchExtensionModel": "gpt-5",
"datasetSearchExtensionBg": ""
}'
```

View File

@ -98,6 +98,7 @@ description: FastGPT 文档目录
- [/docs/upgrading/4-10/4101](/docs/upgrading/4-10/4101)
- [/docs/upgrading/4-11/4110](/docs/upgrading/4-11/4110)
- [/docs/upgrading/4-11/4111](/docs/upgrading/4-11/4111)
- [/docs/upgrading/4-12/4120](/docs/upgrading/4-12/4120)
- [/docs/upgrading/4-8/40](/docs/upgrading/4-8/40)
- [/docs/upgrading/4-8/41](/docs/upgrading/4-8/41)
- [/docs/upgrading/4-8/42](/docs/upgrading/4-8/42)

View File

@ -1,18 +0,0 @@
---
title: 'V4.11.2(进行中)'
description: 'FastGPT V4.11.2 更新说明'
---
## 🚀 新增内容
## ⚙️ 优化
1. 优化 3 处存在潜在内存泄露的代码。
2. 优化工作流部分递归检查,避免无限递归。
3. 优化文档阅读 Worker采用 ShareBuffer 避免数据拷贝。
## 🐛 修复
1. Doc2x API 更新,导致解析失败。
## 🔨 工具更新

View File

@ -1,5 +1,5 @@
{
"title": "4.11.x",
"title": "4.12.x",
"description": "",
"pages": ["4112", "4111", "4110"]
"pages": ["4120"]
}

View File

@ -0,0 +1,55 @@
---
title: 'V4.12.0(进行中)'
description: 'FastGPT V4.12.0 更新说明'
---
## 更新指南
### 1. 更新镜像:
### 2. 执行升级脚本
该脚本仅需商业版用户执行。
从任意终端,发起 1 个 HTTP 请求。其中 `{{rootkey}}` 替换成环境变量里的 `rootkey``{{host}}` 替换成**FastGPT 域名**。
```bash
curl --location --request POST 'https://{{host}}/api/admin/initv4120' \
--header 'rootkey: {{rootkey}}' \
--header 'Content-Type: application/json'
```
**脚本功能**
1. 初始化团队成员的应用对话日志权限。
## 🚀 新增内容
1. 商业版支持应用日志数据看板。
2. 商业版支持简易对话页,可直接选择模型和预设工具进行聊天,无需进行应用搭建。
3. 对话页,增加团队应用快速切换。
4. 权限表调整,采用 Role 映射 Permission 模式。
5. 应用可单独分配对话日志查看权限。
## ⚙️ 优化
1. 优化 3 处存在潜在内存泄露的代码。
2. 优化工作流部分递归检查,避免无限递归。
3. 优化文档阅读 Worker采用 ShareBuffer 避免数据拷贝。
4. 批量进行向量生成和入库,减少网络操作。
5. 知识库搜索,多 query 合并计算,减少数据库操作。
6. 选择知识库交互优化。
7. 登录页 UI 调整。
8. 工作流中,更严格检测工具集是否可被添加。
9. 对话日志导出,仅导出选中的表头,并修复部分表头无法导出的问题。
## 🐛 修复
1. Doc2x API 更新,导致解析失败。
2. 工作流中,团队应用目录也可以被加入工作流。
3. 工作流,数组选择器 UI 缺陷。
4. 成员同步存在权限未完成删除问题
## 🔨 工具更新
1. 系统工具可返回 citeLinks 响应值,从而在对话框实现引用链接展示。

View File

@ -0,0 +1,5 @@
{
"title": "4.11.x",
"description": "",
"pages": ["4112", "4111", "4110"]
}

View File

@ -5,39 +5,39 @@
"document/content/docs/faq/error.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/faq/external_channel_integration.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/faq/index.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/faq/other.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/faq/other.mdx": "2025-08-04T22:07:52+08:00",
"document/content/docs/faq/points_consumption.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/introduction/cloud.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/introduction/commercial.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/introduction/commercial.mdx": "2025-08-04T22:07:52+08:00",
"document/content/docs/introduction/development/community.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/introduction/development/configuration.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/configuration.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/custom-models/bge-rerank.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/custom-models/chatglm2-m3e.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/custom-models/chatglm2-m3e.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/custom-models/chatglm2.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/custom-models/m3e.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/custom-models/marker.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/custom-models/ollama.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/custom-models/xinference.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/custom-models/marker.mdx": "2025-08-04T22:07:52+08:00",
"document/content/docs/introduction/development/custom-models/ollama.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/custom-models/xinference.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/design/dataset.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/design/design_plugin.mdx": "2025-07-24T13:00:27+08:00",
"document/content/docs/introduction/development/docker.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/introduction/development/faq.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/intro.mdx": "2025-07-24T10:39:41+08:00",
"document/content/docs/introduction/development/docker.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/faq.mdx": "2025-08-09T14:20:10+08:00",
"document/content/docs/introduction/development/intro.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/migration/docker_db.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/migration/docker_mongo.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/modelConfig/ai-proxy.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/modelConfig/intro.mdx": "2025-08-01T16:08:20+08:00",
"document/content/docs/introduction/development/modelConfig/ai-proxy.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/modelConfig/intro.mdx": "2025-08-09T14:20:10+08:00",
"document/content/docs/introduction/development/modelConfig/one-api.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/modelConfig/ppio.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/modelConfig/siliconCloud.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/openapi/chat.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/openapi/dataset.mdx": "2025-08-04T18:04:39+08:00",
"document/content/docs/introduction/development/modelConfig/ppio.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/modelConfig/siliconCloud.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/openapi/chat.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/openapi/dataset.mdx": "2025-08-09T14:20:10+08:00",
"document/content/docs/introduction/development/openapi/intro.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/openapi/share.mdx": "2025-08-04T18:09:06+08:00",
"document/content/docs/introduction/development/openapi/share.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/development/proxy/cloudflare.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/proxy/http_proxy.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/proxy/nginx.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/development/sealos.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/introduction/development/sealos.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/guide/DialogBoxes/htmlRendering.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/DialogBoxes/quoteList.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/admin/sso.mdx": "2025-07-24T13:00:27+08:00",
@ -52,7 +52,7 @@
"document/content/docs/introduction/guide/dashboard/intro.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/dashboard/mcp_server.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/dashboard/mcp_tools.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/dashboard/workflow/ai_chat.mdx": "2025-07-24T13:00:27+08:00",
"document/content/docs/introduction/guide/dashboard/workflow/ai_chat.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/guide/dashboard/workflow/content_extract.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/dashboard/workflow/coreferenceResolution.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/dashboard/workflow/custom_feedback.mdx": "2025-07-23T21:35:03+08:00",
@ -78,7 +78,7 @@
"document/content/docs/introduction/guide/knowledge_base/lark_dataset.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/knowledge_base/template.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/knowledge_base/third_dataset.mdx": "2025-07-24T13:00:27+08:00",
"document/content/docs/introduction/guide/knowledge_base/websync.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/knowledge_base/websync.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/introduction/guide/knowledge_base/yuque_dataset.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/plugins/bing_search_plugin.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/guide/plugins/dev_system_tool.mdx": "2025-07-30T22:30:03+08:00",
@ -90,19 +90,19 @@
"document/content/docs/introduction/index.en.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/introduction/index.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/protocol/index.mdx": "2025-07-30T15:38:30+08:00",
"document/content/docs/protocol/open-source.en.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/protocol/open-source.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/protocol/open-source.en.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/protocol/open-source.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/protocol/privacy.en.mdx": "2025-08-03T22:37:45+08:00",
"document/content/docs/protocol/privacy.mdx": "2025-08-03T22:37:45+08:00",
"document/content/docs/protocol/terms.en.mdx": "2025-08-03T22:37:45+08:00",
"document/content/docs/protocol/terms.mdx": "2025-08-03T22:37:45+08:00",
"document/content/docs/toc.en.mdx": "2025-08-04T13:42:36+08:00",
"document/content/docs/toc.mdx": "2025-08-04T13:42:36+08:00",
"document/content/docs/toc.mdx": "2025-08-12T13:45:56+08:00",
"document/content/docs/upgrading/4-10/4100.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-10/4101.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-11/4110.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-11/4111.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-11/4112.mdx": "2025-08-03T22:37:45+08:00",
"document/content/docs/upgrading/4-11/4110.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-11/4111.mdx": "2025-08-07T22:49:09+08:00",
"document/content/docs/upgrading/4-12/4120.mdx": "2025-08-12T21:04:44+08:00",
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",
@ -114,21 +114,21 @@
"document/content/docs/upgrading/4-8/445.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/446.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/447.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/45.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/45.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/451.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/452.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/46.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/46.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/461.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/462.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/462.mdx": "2025-08-04T22:07:52+08:00",
"document/content/docs/upgrading/4-8/463.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/464.mdx": "2025-08-04T18:09:06+08:00",
"document/content/docs/upgrading/4-8/465.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/466.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/467.mdx": "2025-08-04T18:09:06+08:00",
"document/content/docs/upgrading/4-8/468.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/469.mdx": "2025-08-04T18:09:06+08:00",
"document/content/docs/upgrading/4-8/47.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/471.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/464.mdx": "2025-08-04T18:10:58+08:00",
"document/content/docs/upgrading/4-8/465.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/466.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/467.mdx": "2025-08-04T18:10:58+08:00",
"document/content/docs/upgrading/4-8/468.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/469.mdx": "2025-08-04T18:10:58+08:00",
"document/content/docs/upgrading/4-8/47.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/471.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/48.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/481.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4810.mdx": "2025-08-02T19:38:37+08:00",
@ -136,13 +136,13 @@
"document/content/docs/upgrading/4-8/4812.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4813.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4814.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4815.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4816.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4815.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/4816.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/4817.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4818.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4819.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/482.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4820.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4820.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-8/4821.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4822.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/4823.mdx": "2025-08-02T19:38:37+08:00",
@ -153,18 +153,18 @@
"document/content/docs/upgrading/4-8/487.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/488.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/489.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/490.mdx": "2025-08-04T18:09:06+08:00",
"document/content/docs/upgrading/4-9/490.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/upgrading/4-9/491.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/4910.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/4910.mdx": "2025-08-04T22:07:52+08:00",
"document/content/docs/upgrading/4-9/4911.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/4912.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/4913.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/4914.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/492.mdx": "2025-08-04T18:09:06+08:00",
"document/content/docs/upgrading/4-9/492.mdx": "2025-08-04T18:10:58+08:00",
"document/content/docs/upgrading/4-9/493.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/494.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/495.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/496.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/496.mdx": "2025-08-04T22:07:52+08:00",
"document/content/docs/upgrading/4-9/497.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/498.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-9/499.mdx": "2025-08-02T19:38:37+08:00",
@ -176,11 +176,11 @@
"document/content/docs/use-cases/app-cases/google_search.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/use-cases/app-cases/lab_appointment.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/use-cases/app-cases/multi_turn_translation_bot.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/use-cases/app-cases/submit_application_template.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/use-cases/app-cases/submit_application_template.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/use-cases/app-cases/translate-subtitle-using-gpt.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/use-cases/external-integration/dingtalk.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/use-cases/external-integration/feishu.mdx": "2025-07-24T14:23:04+08:00",
"document/content/docs/use-cases/external-integration/official_account.mdx": "2025-07-23T21:35:03+08:00",
"document/content/docs/use-cases/external-integration/openapi.mdx": "2025-08-04T18:09:06+08:00",
"document/content/docs/use-cases/external-integration/official_account.mdx": "2025-08-05T23:20:39+08:00",
"document/content/docs/use-cases/external-integration/openapi.mdx": "2025-08-04T18:10:58+08:00",
"document/content/docs/use-cases/index.mdx": "2025-07-24T14:23:04+08:00"
}

View File

@ -1,6 +1,6 @@
import * as fs from 'node:fs/promises';
import path from 'node:path';
import fg from 'fast-glob';
const fs = require('node:fs/promises');
const path = require('node:path');
const fg = require('fast-glob');
// 假设 i18n.defaultLanguage = 'zh-CN',这里不用 i18n 直接写两份逻辑即可
@ -15,8 +15,8 @@ const blacklist = [
];
function filePathToUrl(filePath, lang) {
const baseDir = path.resolve('../content/docs');
let relativePath = path.relative(baseDir, path.resolve(filePath)).replace(/\\/g, '/');
const baseDir = path.join(__dirname, '../content/docs');
let relativePath = filePath.replace(baseDir, '');
const basePath = lang === 'zh-CN' ? '/docs' : '/en/docs';
if (lang !== 'zh-CN' && relativePath.endsWith('.en.mdx')) {
@ -44,7 +44,7 @@ function isZhFile(file) {
async function generateToc() {
// 匹配所有 mdx 文件
const allFiles = await fg('../content/docs/**/*.mdx');
const allFiles = await fg(path.join(__dirname, '../content/docs/**/*.mdx'))
// 筛选中英文文件
const zhFiles = allFiles.filter(isZhFile);
@ -72,7 +72,7 @@ ${urls.map((url) => `- [${url}](${url})`).join('\n')}
`;
// 写文件路径
const baseDir = path.resolve('../content/docs');
const baseDir = path.join(__dirname, '../content/docs');
const zhOutputPath = path.join(baseDir, 'toc.mdx');
const enOutputPath = path.join(baseDir, 'toc.en.mdx');

View File

@ -10,7 +10,7 @@
"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",
"initIcon": "node ./scripts/icon/init.js",
"initIcon": "node ./scripts/icon/init.js && prettier --config \"./.prettierrc.js\" --write \"packages/web/components/common/Icon/constants.ts\"",
"previewIcon": "node ./scripts/icon/index.js",
"api:gen": "tsc ./scripts/openapi/index.ts && node ./scripts/openapi/index.js && npx @redocly/cli build-docs ./scripts/openapi/openapi.json -o ./projects/app/public/openapi/index.html",
"create:i18n": "node ./scripts/i18n/index.js",
@ -54,7 +54,12 @@
"mdast-util-gfm-autolink-literal": "2.0.0"
},
"engines": {
"node": ">=18.16.0",
"pnpm": ">=9.0.0"
"node": ">=20"
},
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": "9.15.9"
}
}
}

View File

@ -45,6 +45,7 @@ export type FastGPTFeConfigsType = {
show_workorder?: boolean;
show_emptyChat?: boolean;
isPlus?: boolean;
hideChatCopyrightSetting?: boolean;
register_method?: ['email' | 'phone' | 'sync'];
login_method?: ['email' | 'phone']; // Attention: login method is diffrent with oauth
find_password_method?: ['email' | 'phone'];

View File

@ -14,8 +14,8 @@ export const defaultQAModels: LLMModelItemType[] = [
{
type: ModelTypeEnum.llm,
provider: 'OpenAI',
model: 'gpt-4o-mini',
name: 'gpt-4o-mini',
model: 'gpt-5',
name: 'gpt-5',
maxContext: 16000,
maxResponse: 16000,
quoteMaxToken: 13000,

View File

@ -21,14 +21,19 @@ export type ModelProviderIdType =
| 'Hunyuan'
| 'Baichuan'
| 'StepFun'
| 'ai360'
| 'Yi'
| 'Siliconflow'
| 'PPIO'
| 'OpenRouter'
| 'Ollama'
| 'novita'
| 'vertexai'
| 'BAAI'
| 'FishAudio'
| 'Intern'
| 'Moka'
| 'Jina'
| 'Other';
export type ModelProviderType = {
@ -133,17 +138,16 @@ export const ModelProviderList: ModelProviderType[] = [
name: i18nT('common:model_stepfun'),
avatar: 'model/stepfun'
},
{
id: 'ai360',
name: '360 AI',
avatar: 'model/ai360'
},
{
id: 'Yi',
name: i18nT('common:model_yi'),
avatar: 'model/yi'
},
{
id: 'Ollama',
name: 'Ollama',
avatar: 'model/ollama'
},
{
id: 'BAAI',
name: i18nT('common:model_baai'),
@ -164,6 +168,31 @@ export const ModelProviderList: ModelProviderType[] = [
name: i18nT('common:model_moka'),
avatar: 'model/moka'
},
{
id: 'Ollama',
name: 'Ollama',
avatar: 'model/ollama'
},
{
id: 'OpenRouter',
name: 'OpenRouter',
avatar: 'model/openrouter'
},
{
id: 'vertexai',
name: 'vertexai',
avatar: 'model/vertexai'
},
{
id: 'novita',
name: 'novita',
avatar: 'model/novita'
},
{
id: 'Jina',
name: 'Jina',
avatar: 'model/jina'
},
{
id: 'AliCloud',
name: i18nT('common:model_alicloud'),

View File

@ -13,7 +13,8 @@ export enum AppTypeEnum {
plugin = 'plugin',
httpPlugin = 'httpPlugin',
toolSet = 'toolSet',
tool = 'tool'
tool = 'tool',
hidden = 'hidden'
}
export const AppFolderTypeList = [AppTypeEnum.folder, AppTypeEnum.httpPlugin];
@ -33,7 +34,7 @@ export const defaultWhisperConfig: AppWhisperConfigType = {
export const defaultQGConfig: AppQGConfigType = {
open: false,
model: 'gpt-4o-mini',
model: 'gpt-5',
customPrompt: ''
};

29
packages/global/core/app/logs/api.d.ts vendored Normal file
View File

@ -0,0 +1,29 @@
import type { AppLogTimespanEnum } from './constants';
import type { AppChatLogAppData, AppChatLogChatData, AppChatLogUserData } from './type';
export type getChartDataBody = {
appId: string;
dateStart: Date;
dateEnd: Date;
source?: ChatSourceEnum[];
offset: number;
userTimespan: AppLogTimespanEnum;
chatTimespan: AppLogTimespanEnum;
appTimespan: AppLogTimespanEnum;
};
export type getChartDataResponse = {
userData: AppChatLogUserData;
chatData: AppChatLogChatData;
appData: AppChatLogAppData;
};
export type getTotalDataQuery = {
appId: string;
};
export type getTotalDataResponse = {
totalUsers: number;
totalChats: number;
totalPoints: number;
};

View File

@ -47,3 +47,290 @@ export const DefaultAppLogKeys = [
{ key: AppLogKeysEnum.RESPONSE_TIME, enable: false },
{ key: AppLogKeysEnum.ERROR_COUNT, enable: false }
];
export enum AppLogTimespanEnum {
day = 'day',
week = 'week',
month = 'month',
quarter = 'quarter'
}
export const offsetOptions = [
{ label: 'T+1', value: '1' },
{ label: 'T+3', value: '3' },
{ label: 'T+7', value: '7' },
{ label: 'T+14', value: '14' }
];
export const fakeChartData = {
user: [
{
x: '07-30',
xLabel: '07-30',
userCount: 8,
newUserCount: 5,
retentionUserCount: 3,
points: 100,
sourceCountMap: {
test: 1,
online: 1,
share: 1,
api: 2,
cronJob: 0,
team: 1,
feishu: 0,
official_account: 1,
wecom: 1,
mcp: 0
}
},
{
x: '07-31',
xLabel: '07-31',
userCount: 12,
newUserCount: 8,
retentionUserCount: 4,
points: 160,
sourceCountMap: {
test: 2,
online: 2,
share: 2,
api: 3,
cronJob: 0,
team: 2,
feishu: 0,
official_account: 1,
wecom: 1,
mcp: 0
}
},
{
x: '08-01',
xLabel: '08-01',
userCount: 18,
newUserCount: 12,
retentionUserCount: 6,
points: 220,
sourceCountMap: {
test: 2,
online: 3,
share: 2,
api: 4,
cronJob: 1,
team: 2,
feishu: 0,
official_account: 1,
wecom: 1,
mcp: 0
}
},
{
x: '08-02',
xLabel: '08-02',
userCount: 15,
newUserCount: 7,
retentionUserCount: 8,
points: 180,
sourceCountMap: {
test: 1,
online: 2,
share: 2,
api: 3,
cronJob: 1,
team: 2,
feishu: 1,
official_account: 1,
wecom: 0,
mcp: 0
}
},
{
x: '08-03',
xLabel: '08-03',
userCount: 20,
newUserCount: 15,
retentionUserCount: 5,
points: 250,
sourceCountMap: {
test: 2,
online: 4,
share: 2,
api: 5,
cronJob: 1,
team: 2,
feishu: 1,
official_account: 1,
wecom: 0,
mcp: 0
}
},
{
x: '08-04',
xLabel: '08-04',
userCount: 14,
newUserCount: 6,
retentionUserCount: 8,
points: 170,
sourceCountMap: {
test: 1,
online: 3,
share: 1,
api: 4,
cronJob: 1,
team: 2,
feishu: 1,
official_account: 1,
wecom: 0,
mcp: 0
}
},
{
x: '08-05',
xLabel: '08-05',
userCount: 22,
newUserCount: 17,
retentionUserCount: 5,
points: 280,
sourceCountMap: {
test: 2,
online: 5,
share: 2,
api: 6,
cronJob: 1,
team: 2,
feishu: 1,
official_account: 1,
wecom: 0,
mcp: 0
}
}
],
chat: [
{
x: '07-30',
xLabel: '07-30',
chatItemCount: 20,
chatCount: 12,
pointsPerChat: 5.5,
errorCount: 2,
errorRate: 0.1
},
{
x: '07-31',
xLabel: '07-31',
chatItemCount: 35,
chatCount: 20,
pointsPerChat: 8.0,
errorCount: 1,
errorRate: 0.028
},
{
x: '08-01',
xLabel: '08-01',
chatItemCount: 50,
chatCount: 30,
pointsPerChat: 7.3,
errorCount: 3,
errorRate: 0.06
},
{
x: '08-02',
xLabel: '08-02',
chatItemCount: 28,
chatCount: 18,
pointsPerChat: 6.2,
errorCount: 1,
errorRate: 0.036
},
{
x: '08-03',
xLabel: '08-03',
chatItemCount: 60,
chatCount: 40,
pointsPerChat: 7.8,
errorCount: 4,
errorRate: 0.067
},
{
x: '08-04',
xLabel: '08-04',
chatItemCount: 32,
chatCount: 22,
pointsPerChat: 6.5,
errorCount: 2,
errorRate: 0.062
},
{
x: '08-05',
xLabel: '08-05',
chatItemCount: 55,
chatCount: 35,
pointsPerChat: 8.1,
errorCount: 1,
errorRate: 0.018
}
],
app: [
{
x: '07-30',
xLabel: '07-30',
goodFeedBackCount: 2,
badFeedBackCount: 1,
avgDuration: 2.5
},
{
x: '07-31',
xLabel: '07-31',
goodFeedBackCount: 5,
badFeedBackCount: 2,
avgDuration: 2.1
},
{
x: '08-01',
xLabel: '08-01',
goodFeedBackCount: 3,
badFeedBackCount: 1,
avgDuration: 2.8
},
{
x: '08-02',
xLabel: '08-02',
goodFeedBackCount: 6,
badFeedBackCount: 3,
avgDuration: 2.0
},
{
x: '08-03',
xLabel: '08-03',
goodFeedBackCount: 4,
badFeedBackCount: 2,
avgDuration: 2.7
},
{
x: '08-04',
xLabel: '08-04',
goodFeedBackCount: 7,
badFeedBackCount: 1,
avgDuration: 2.3
},
{
x: '08-05',
xLabel: '08-05',
goodFeedBackCount: 3,
badFeedBackCount: 2,
avgDuration: 2.9
}
],
cumulative: {
userCount: 109,
points: 1360,
chatItemCount: 280,
chatCount: 177,
pointsPerChat: 7.2,
errorCount: 14,
errorRate: 0.053,
goodFeedBackCount: 30,
badFeedBackCount: 12,
avgDuration: 2.47
}
};

View File

@ -1,3 +1,4 @@
import type { ChatSourceEnum } from '../../core/chat/constants';
import type { AppLogKeysEnum } from './constants';
export type AppLogKeysType = {
@ -10,3 +11,55 @@ export type AppLogKeysSchemaType = {
appId: string;
logKeys: AppLogKeysType[];
};
export type AppChatLogSchema = {
_id: string;
appId: string;
teamId: string;
chatId: string;
userId: string;
source: string;
sourceName?: string;
createTime: Date;
updateTime: Date;
chatItemCount: number;
errorCount: number;
totalPoints: number;
goodFeedbackCount: number;
badFeedbackCount: number;
totalResponseTime: number;
isFirstChat: boolean; // whether this is the user's first session in the app
};
export type AppChatLogUserData = {
timestamp: number;
summary: {
userCount: number;
newUserCount: number;
retentionUserCount: number;
points: number;
sourceCountMap: Record<ChatSourceEnum, number>;
};
}[];
export type AppChatLogChatData = {
timestamp: number;
summary: {
chatItemCount: number;
chatCount: number;
errorCount: number;
points: number;
};
}[];
export type AppChatLogAppData = {
timestamp: number;
summary: {
goodFeedBackCount: number;
badFeedBackCount: number;
chatCount: number;
totalResponseTime: number;
};
}[];

View File

@ -0,0 +1,59 @@
import dayjs from 'dayjs';
import { AppLogTimespanEnum } from './constants';
export const formatDateByTimespan = (timestamp: number, timespan: AppLogTimespanEnum) => {
const date = new Date(timestamp);
if (timespan === AppLogTimespanEnum.day) {
return {
date: dayjs(date).format('MM-DD'),
xLabel: dayjs(date).format('YYYY-MM-DD')
};
} else if (timespan === AppLogTimespanEnum.week) {
const startStr = dayjs(date).format('MM/DD');
const endStr = dayjs(date).add(6, 'day').format('MM/DD');
return {
date: `${startStr}-${endStr}`,
xLabel: `${startStr}-${endStr}`
};
} else if (timespan === AppLogTimespanEnum.month) {
return {
date: dayjs(date).format('YYYY-MM'),
xLabel: dayjs(date).format('YYYY-MM')
};
} else {
const year = date.getFullYear();
const quarter = Math.ceil((date.getMonth() + 1) / 3);
return {
date: `${year}Q${quarter}`,
xLabel: `${year}Q${quarter}`
};
}
};
export const calculateOffsetDates = (
start: Date,
end: Date,
offset: number,
timespan: AppLogTimespanEnum
) => {
const offsetStart = new Date(start);
const offsetEnd = new Date(end);
if (timespan === AppLogTimespanEnum.quarter) {
offsetStart.setMonth(offsetStart.getMonth() + offset * 3);
offsetEnd.setMonth(offsetEnd.getMonth() + offset * 3);
} else if (timespan === AppLogTimespanEnum.month) {
offsetStart.setMonth(offsetStart.getMonth() + offset);
offsetEnd.setMonth(offsetEnd.getMonth() + offset);
} else if (timespan === AppLogTimespanEnum.week) {
offsetStart.setDate(offsetStart.getDate() + offset * 7);
offsetEnd.setDate(offsetEnd.getDate() + offset * 7);
} else {
offsetStart.setDate(offsetStart.getDate() + offset);
offsetEnd.setDate(offsetEnd.getDate() + offset);
}
return { offsetStart, offsetEnd };
};

View File

@ -19,6 +19,7 @@ export type PluginRuntimeType = {
nodes: StoreNodeItemType[];
edges: StoreEdgeItemType[];
currentCost?: number;
systemKeyCost?: number;
hasTokenFee?: boolean;
};
@ -44,6 +45,7 @@ export type SystemPluginTemplateItemType = WorkflowTemplateType & {
// commercial plugin config
originCost?: number; // n points/one time
currentCost?: number;
systemKeyCost?: number;
hasTokenFee?: boolean;
pluginOrder?: number;
@ -52,6 +54,7 @@ export type SystemPluginTemplateItemType = WorkflowTemplateType & {
// Admin config
inputList?: FlowNodeInputItemType['inputList'];
inputListVal?: Record<string, any>;
hasSystemSecret?: boolean;
};

View File

@ -13,7 +13,7 @@ import pluginErrList from '../../common/error/code/plugin';
export const getDefaultAppForm = (): AppSimpleEditFormType => {
return {
aiSettings: {
model: 'gpt-4o-mini',
model: '',
systemPrompt: '',
temperature: 0,
isResponseAnswerText: true,

View File

@ -44,34 +44,44 @@ export enum ChatSourceEnum {
export const ChatSourceMap = {
[ChatSourceEnum.test]: {
name: i18nT('common:core.chat.logs.test')
name: i18nT('common:core.chat.logs.test'),
color: '#5E8FFF'
},
[ChatSourceEnum.online]: {
name: i18nT('common:core.chat.logs.online')
name: i18nT('common:core.chat.logs.online'),
color: '#47B2FF'
},
[ChatSourceEnum.share]: {
name: i18nT('common:core.chat.logs.share')
name: i18nT('common:core.chat.logs.share'),
color: '#9E8DFB'
},
[ChatSourceEnum.api]: {
name: i18nT('common:core.chat.logs.api')
name: i18nT('common:core.chat.logs.api'),
color: '#D389F6'
},
[ChatSourceEnum.cronJob]: {
name: i18nT('chat:source_cronJob')
name: i18nT('chat:source_cronJob'),
color: '#FF81AE'
},
[ChatSourceEnum.team]: {
name: i18nT('common:core.chat.logs.team')
name: i18nT('common:core.chat.logs.team'),
color: '#42CFC6'
},
[ChatSourceEnum.feishu]: {
name: i18nT('common:core.chat.logs.feishu')
name: i18nT('common:core.chat.logs.feishu'),
color: '#39CC83'
},
[ChatSourceEnum.official_account]: {
name: i18nT('common:core.chat.logs.official_account')
name: i18nT('common:core.chat.logs.official_account'),
color: '#FDB022'
},
[ChatSourceEnum.wecom]: {
name: i18nT('common:core.chat.logs.wecom')
name: i18nT('common:core.chat.logs.wecom'),
color: '#FD853A'
},
[ChatSourceEnum.mcp]: {
name: i18nT('common:core.chat.logs.mcp')
name: i18nT('common:core.chat.logs.mcp'),
color: '#F97066'
}
};

View File

@ -0,0 +1,28 @@
export type ChatSettingSchema = {
_id: string;
appId: string;
teamId: string;
slogan: string;
dialogTips: string;
homeTabTitle: string;
wideLogoUrl?: string;
squareLogoUrl?: string;
selectedTools: {
pluginId: string;
name: string;
avatar: string;
inputs?: Record<`${NodeInputKeyEnum}` | string, any>;
}[];
};
export type ChatSettingUpdateParams = {
slogan?: string;
dialogTips?: string;
homeTabTitle?: string;
wideLogoUrl?: string;
squareLogoUrl?: string;
selectedTools: {
pluginId: string;
inputs?: Record<`${NodeInputKeyEnum}` | string, any>;
}[];
};

View File

@ -8,7 +8,7 @@ import type {
ChatStatusEnum
} from './constants';
import type { FlowNodeTypeEnum } from '../workflow/node/constant';
import type { NodeOutputKeyEnum } from '../workflow/constants';
import type { NodeInputKeyEnum, NodeOutputKeyEnum } from '../workflow/constants';
import type { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
import type { AppSchema, VariableItemType } from '../app/type';
import { AppChatConfigType } from '../app/type';
@ -18,6 +18,7 @@ import type { DispatchNodeResponseType } from '../workflow/runtime/type.d';
import type { ChatBoxInputType } from '../../../../projects/app/src/components/core/chat/ChatContainer/ChatBox/type';
import type { WorkflowInteractiveResponseType } from '../workflow/template/system/interactive/type';
import type { FlowNodeInputItemType } from '../workflow/type/io';
import type { FlowNodeTemplateType } from '../workflow/type/node.d';
export type ChatSchema = {
_id: string;
@ -130,6 +131,7 @@ export type ResponseTagItemType = {
totalQuoteList?: SearchDataResponseItemType[];
llmModuleAccount?: number;
historyPreviewLength?: number;
toolCiteLinks?: ToolCiteLinksType[];
};
export type ChatItemType = (UserChatItemType | SystemChatItemType | AIChatItemType) & {
@ -149,7 +151,6 @@ export type ChatSiteItemType = (UserChatItemType | SystemChatItemType | AIChatIt
errorMsg?: string;
} & ChatBoxInputType &
ResponseTagItemType;
/* --------- team chat --------- */
export type ChatAppListSchema = {
apps: AppType[];
@ -196,6 +197,10 @@ export type ToolModuleResponseItemType = {
functionName: string;
};
export type ToolCiteLinksType = {
name: string;
url: string;
};
/* dispatch run time */
export type RuntimeUserPromptType = {
files: UserChatItemValueItemType['file'][];

View File

@ -26,7 +26,7 @@ export const getLLMDefaultChunkSize = (model?: LLMModelItemType) => {
export const getLLMMaxChunkSize = (model?: LLMModelItemType) => {
if (!model) return 8000;
return Math.max(model.maxContext - model.maxResponse, 2000);
return Math.max(model.maxContext, 4000);
};
// Index size

View File

@ -29,6 +29,7 @@ import type {
WorkflowInteractiveResponseType
} from '../template/system/interactive/type';
import type { SearchDataResponseItemType } from '../../dataset/type';
import type { localeType } from '../../../common/i18n/type';
export type ExternalProviderType = {
openaiAccount?: OpenaiAccountType;
externalWorkflowVariables?: Record<string, string>;
@ -37,6 +38,7 @@ export type ExternalProviderType = {
/* workflow props */
export type ChatDispatchProps = {
res?: NextApiResponse;
lang?: localeType;
requestOrigin?: string;
mode: 'test' | 'chat' | 'debug';
timezone: string;
@ -49,6 +51,10 @@ export type ChatDispatchProps = {
isChildApp?: boolean;
};
runningUserInfo: {
username: string;
teamName: string;
memberName: string;
contact: string;
teamId: string;
tmbId: string;
};

View File

@ -77,6 +77,7 @@ export type FlowNodeCommonType = {
// Not store, just computed
currentCost?: number;
systemKeyCost?: number;
hasTokenFee?: boolean;
hasSystemSecret?: boolean;
};
@ -135,6 +136,7 @@ export type NodeTemplateListItemType = {
author?: string;
unique?: boolean; // 唯一的
currentCost?: number; // 当前积分消耗
systemKeyCost?: number; // 系统密钥费用,统一为数字
hasTokenFee?: boolean; // 是否配置积分
instructions?: string; // 使用说明
courseUrl?: string; // 教程链接

View File

@ -22,6 +22,7 @@ export const AppPerList: PermissionListType<AppPermissionKeyEnum> = {
export const AppRoleList: RoleListType<AppPermissionKeyEnum> = {
[CommonPerKeyEnum.read]: {
...CommonRoleList[CommonPerKeyEnum.read],
name: i18nT('app:permission.name.read'),
description: i18nT('app:permission.des.read')
},
[CommonPerKeyEnum.write]: {
@ -36,18 +37,24 @@ export const AppRoleList: RoleListType<AppPermissionKeyEnum> = {
value: 0b1000,
checkBoxType: 'multiple',
name: i18nT('app:permission.name.readChatLog'),
description: i18nT('app:permission.des.readChatLog')
description: ''
}
};
export const AppRolePerMap: RolePerMapType = new Map([
...CommonRolePerMap,
[
AppRoleList[AppPermissionKeyEnum.ReadChatLog].value,
CommonRoleList[CommonPerKeyEnum.manage].value,
sumPer(
CommonPerList[CommonPerKeyEnum.read],
CommonPerList[CommonPerKeyEnum.write],
CommonPerList[CommonPerKeyEnum.manage],
AppPerList[AppPermissionKeyEnum.ReadChatLog]
) as PermissionValueType
)!
],
[
AppRoleList[AppPermissionKeyEnum.ReadChatLog].value,
sumPer(CommonPerList[CommonPerKeyEnum.read], AppPerList[AppPermissionKeyEnum.ReadChatLog])!
]
]);

View File

@ -5,6 +5,7 @@ import axios, {
type AxiosRequestConfig
} from 'axios';
import { FastGPTProUrl } from '../system/constants';
import { UserError } from '@fastgpt/global/common/error/utils';
interface ConfigType {
headers?: { [key: string]: string };
@ -78,7 +79,7 @@ instance.interceptors.response.use(responseSuccess, (err) => Promise.reject(err)
export function request(url: string, data: any, config: ConfigType, method: Method): any {
if (!FastGPTProUrl) {
console.log('未部署商业版接口', url);
return Promise.reject('The The request was denied...');
return Promise.reject(new UserError('The request was denied...'));
}
/* 去空 */

View File

@ -151,10 +151,6 @@ export async function getFileById({
_id: new Types.ObjectId(fileId)
});
// if (!file) {
// return Promise.reject('File not found');
// }
return file || undefined;
}

View File

@ -11,6 +11,7 @@ import { UserError } from '@fastgpt/global/common/error/utils';
export const maxImgSize = 1024 * 1024 * 12;
const base64MimeRegex = /data:image\/([^\)]+);base64/;
export async function uploadMongoImg({
base64Img,
teamId,
@ -22,13 +23,13 @@ export async function uploadMongoImg({
forever?: Boolean;
}) {
if (base64Img.length > maxImgSize) {
return Promise.reject('Image too large');
return Promise.reject(new UserError('Image too large'));
}
const [base64Mime, base64Data] = base64Img.split(',');
// Check if mime type is valid
if (!base64MimeRegex.test(base64Mime)) {
return Promise.reject('Invalid image base64');
return Promise.reject(new UserError('Invalid image base64'));
}
const mime = `image/${base64Mime.match(base64MimeRegex)?.[1] ?? 'image/jpeg'}`;
@ -39,7 +40,7 @@ export async function uploadMongoImg({
}
if (!extension || !imageFileType.includes(`.${extension}`)) {
return Promise.reject(`Invalid image file type: ${mime}`);
return Promise.reject(new UserError(`Invalid image file type: ${mime}`));
}
const { _id } = await retryFn(() =>

View File

@ -4,6 +4,7 @@ import path from 'path';
import type { BucketNameEnum } from '@fastgpt/global/common/file/constants';
import { bucketNameMap } from '@fastgpt/global/common/file/constants';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import { UserError } from '@fastgpt/global/common/error/utils';
export type FileType = {
fieldname: string;
@ -61,7 +62,7 @@ export const getUploadModel = ({ maxSize = 500 }: { maxSize?: number }) => {
// check bucket name
const bucketName = (req.body?.bucketName || originBucketName) as `${BucketNameEnum}`;
if (bucketName && !bucketNameMap[bucketName]) {
return reject('BucketName is invalid');
return reject(new UserError('BucketName is invalid'));
}
// @ts-ignore

View File

@ -17,8 +17,7 @@ export type InsertVectorProps = {
collectionId: string;
};
export type InsertVectorControllerProps = InsertVectorProps & {
vector: number[];
retry?: number;
vectors: number[][];
};
export type EmbeddingRecallProps = {

View File

@ -2,7 +2,12 @@
import { PgVectorCtrl } from './pg';
import { ObVectorCtrl } from './oceanbase';
import { getVectorsByText } from '../../core/ai/embedding';
import { type DelDatasetVectorCtrlProps, type InsertVectorProps } from './controller.d';
import type {
EmbeddingRecallCtrlProps} from './controller.d';
import {
type DelDatasetVectorCtrlProps,
type InsertVectorProps
} from './controller.d';
import { type EmbeddingModelItemType } from '@fastgpt/global/core/ai/model.d';
import { MILVUS_ADDRESS, PG_ADDRESS, OCEANBASE_ADDRESS } from './constants';
import { MilvusCtrl } from './milvus';
@ -35,7 +40,8 @@ const onIncrCache = (teamId: string) => incrValueToCache(getChcheKey(teamId), 1)
const Vector = getVectorObj();
export const initVectorStore = Vector.init;
export const recallFromVectorStore = Vector.embRecall;
export const recallFromVectorStore = (props: EmbeddingRecallCtrlProps) =>
retryFn(() => Vector.embRecall(props));
export const getVectorDataByTime = Vector.getVectorDataByTime;
export const getVectorCountByTeamId = async (teamId: string) => {
@ -58,34 +64,34 @@ export const getVectorCountByCollectionId = Vector.getVectorCountByCollectionId;
export const insertDatasetDataVector = async ({
model,
query,
inputs,
...props
}: InsertVectorProps & {
query: string;
inputs: string[];
model: EmbeddingModelItemType;
}) => {
return retryFn(async () => {
const { vectors, tokens } = await getVectorsByText({
model,
input: query,
type: 'db'
});
const { insertId } = await Vector.insert({
...props,
vector: vectors[0]
});
onIncrCache(props.teamId);
return {
tokens,
insertId
};
const { vectors, tokens } = await getVectorsByText({
model,
input: inputs,
type: 'db'
});
const { insertIds } = await retryFn(() =>
Vector.insert({
...props,
vectors
})
);
onIncrCache(props.teamId);
return {
tokens,
insertIds
};
};
export const deleteDatasetDataVector = async (props: DelDatasetVectorCtrlProps) => {
const result = await Vector.delete(props);
const result = await retryFn(() => Vector.delete(props));
onDelCache(props.teamId);
return result;
};

View File

@ -11,7 +11,7 @@ import type {
EmbeddingRecallResponse,
InsertVectorControllerProps
} from '../controller.d';
import { delay } from '@fastgpt/global/common/system/utils';
import { delay, retryFn } from '@fastgpt/global/common/system/utils';
import { addLog } from '../../system/log';
import { customNanoid } from '@fastgpt/global/common/string/tools';
@ -27,6 +27,7 @@ export class MilvusCtrl {
address: MILVUS_ADDRESS,
token: MILVUS_TOKEN
});
await global.milvusClient.connectPromise;
addLog.info(`Milvus connected`);
@ -124,9 +125,9 @@ export class MilvusCtrl {
}
};
insert = async (props: InsertVectorControllerProps): Promise<{ insertId: string }> => {
insert = async (props: InsertVectorControllerProps): Promise<{ insertIds: string[] }> => {
const client = await this.getClient();
const { teamId, datasetId, collectionId, vector, retry = 3 } = props;
const { teamId, datasetId, collectionId, vectors } = props;
const generateId = () => {
// in js, the max safe integer is 2^53 - 1: 9007199254740991
@ -136,45 +137,32 @@ export class MilvusCtrl {
const restDigits = customNanoid('1234567890', 15);
return Number(`${firstDigit}${restDigits}`);
};
const id = generateId();
try {
const result = await client.insert({
collection_name: DatasetVectorTableName,
data: [
{
id,
vector,
teamId: String(teamId),
datasetId: String(datasetId),
collectionId: String(collectionId),
createTime: Date.now()
}
]
});
const insertId = (() => {
if ('int_id' in result.IDs) {
return `${result.IDs.int_id.data?.[0]}`;
}
return `${result.IDs.str_id.data?.[0]}`;
})();
const result = await client.insert({
collection_name: DatasetVectorTableName,
data: vectors.map((vector) => ({
id: generateId(),
vector,
teamId: String(teamId),
datasetId: String(datasetId),
collectionId: String(collectionId),
createTime: Date.now()
}))
});
return {
insertId: insertId
};
} catch (error) {
if (retry <= 0) {
return Promise.reject(error);
const insertIds = (() => {
if ('int_id' in result.IDs) {
return result.IDs.int_id.data.map((id) => String(id));
}
await delay(500);
return this.insert({
...props,
retry: retry - 1
});
}
return result.IDs.str_id.data.map((id) => String(id));
})();
return {
insertIds
};
};
delete = async (props: DelDatasetVectorCtrlProps): Promise<any> => {
const { teamId, retry = 2 } = props;
const { teamId } = props;
const client = await this.getClient();
const teamIdWhere = `(teamId=="${String(teamId)}")`;
@ -206,33 +194,15 @@ export class MilvusCtrl {
const concatWhere = `${teamIdWhere} and ${where}`;
try {
await client.delete({
collection_name: DatasetVectorTableName,
filter: concatWhere
});
} catch (error) {
if (retry <= 0) {
return Promise.reject(error);
}
await delay(500);
return this.delete({
...props,
retry: retry - 1
});
}
await client.delete({
collection_name: DatasetVectorTableName,
filter: concatWhere
});
};
embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => {
const client = await this.getClient();
const {
teamId,
datasetIds,
vector,
limit,
forbidCollectionIdList,
filterCollectionIdList,
retry = 2
} = props;
const { teamId, datasetIds, vector, limit, forbidCollectionIdList, filterCollectionIdList } =
props;
// Forbid collection
const formatForbidCollectionIdList = (() => {
@ -262,37 +232,29 @@ export class MilvusCtrl {
return { results: [] };
}
try {
const { results } = await client.search({
const { results } = await retryFn(() =>
client.search({
collection_name: DatasetVectorTableName,
data: vector,
limit,
filter: `(teamId == "${teamId}") and (datasetId in [${datasetIds.map((id) => `"${id}"`).join(',')}]) ${collectionIdQuery} ${forbidColQuery}`,
output_fields: ['collectionId']
});
})
);
const rows = results as {
score: number;
id: string;
collectionId: string;
}[];
const rows = results as {
score: number;
id: string;
collectionId: string;
}[];
return {
results: rows.map((item) => ({
id: String(item.id),
collectionId: item.collectionId,
score: item.score
}))
};
} catch (error) {
if (retry <= 0) {
return Promise.reject(error);
}
return this.embRecall({
...props,
retry: retry - 1
});
}
return {
results: rows.map((item) => ({
id: String(item.id),
collectionId: item.collectionId,
score: item.score
}))
};
};
getVectorCountByTeamId = async (teamId: string) => {

View File

@ -1,6 +1,6 @@
/* oceanbase vector crud */
import { DatasetVectorTableName } from '../constants';
import { delay } from '@fastgpt/global/common/system/utils';
import { delay, retryFn } from '@fastgpt/global/common/system/utils';
import { ObClient } from './controller';
import { type RowDataPacket } from 'mysql2/promise';
import {
@ -42,41 +42,30 @@ export class ObVectorCtrl {
addLog.error('init oceanbase error', error);
}
};
insert = async (props: InsertVectorControllerProps): Promise<{ insertId: string }> => {
const { teamId, datasetId, collectionId, vector, retry = 3 } = props;
insert = async (props: InsertVectorControllerProps): Promise<{ insertIds: string[] }> => {
const { teamId, datasetId, collectionId, vectors } = props;
try {
const { rowCount, rows } = await ObClient.insert(DatasetVectorTableName, {
values: [
[
{ key: 'vector', value: `[${vector}]` },
{ key: 'team_id', value: String(teamId) },
{ key: 'dataset_id', value: String(datasetId) },
{ key: 'collection_id', value: String(collectionId) }
]
]
});
const values = vectors.map((vector) => [
{ key: 'vector', value: `[${vector}]` },
{ key: 'team_id', value: String(teamId) },
{ key: 'dataset_id', value: String(datasetId) },
{ key: 'collection_id', value: String(collectionId) }
]);
if (rowCount === 0) {
return Promise.reject('insertDatasetData: no insert');
}
const { rowCount, rows } = await ObClient.insert(DatasetVectorTableName, {
values
});
return {
insertId: rows[0].id
};
} catch (error) {
if (retry <= 0) {
return Promise.reject(error);
}
await delay(500);
return this.insert({
...props,
retry: retry - 1
});
if (rowCount === 0) {
return Promise.reject('insertDatasetData: no insert');
}
return {
insertIds: rows.map((row) => row.id)
};
};
delete = async (props: DelDatasetVectorCtrlProps): Promise<any> => {
const { teamId, retry = 2 } = props;
const { teamId } = props;
const teamIdWhere = `team_id='${String(teamId)}' AND`;
@ -106,31 +95,13 @@ export class ObVectorCtrl {
if (!where) return;
try {
await ObClient.delete(DatasetVectorTableName, {
where: [where]
});
} catch (error) {
if (retry <= 0) {
return Promise.reject(error);
}
await delay(500);
return this.delete({
...props,
retry: retry - 1
});
}
await ObClient.delete(DatasetVectorTableName, {
where: [where]
});
};
embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => {
const {
teamId,
datasetIds,
vector,
limit,
forbidCollectionIdList,
filterCollectionIdList,
retry = 2
} = props;
const { teamId, datasetIds, vector, limit, forbidCollectionIdList, filterCollectionIdList } =
props;
// Get forbid collection
const formatForbidCollectionIdList = (() => {
@ -161,15 +132,14 @@ export class ObVectorCtrl {
return { results: [] };
}
try {
const rows = await ObClient.query<
({
id: string;
collection_id: string;
score: number;
} & RowDataPacket)[][]
>(
`BEGIN;
const rows = await ObClient.query<
({
id: string;
collection_id: string;
score: number;
} & RowDataPacket)[][]
>(
`BEGIN;
SET ob_hnsw_ef_search = ${global.systemEnv?.hnswEfSearch || 100};
SELECT id, collection_id, inner_product(vector, [${vector}]) AS score
FROM ${DatasetVectorTableName}
@ -179,24 +149,15 @@ export class ObVectorCtrl {
${forbidCollectionSql}
ORDER BY score desc APPROXIMATE LIMIT ${limit};
COMMIT;`
).then(([rows]) => rows[2]);
).then(([rows]) => rows[2]);
return {
results: rows.map((item) => ({
id: String(item.id),
collectionId: item.collection_id,
score: item.score
}))
};
} catch (error) {
if (retry <= 0) {
return Promise.reject(error);
}
return this.embRecall({
...props,
retry: retry - 1
});
}
return {
results: rows.map((item) => ({
id: String(item.id),
collectionId: item.collection_id,
score: item.score
}))
};
};
getVectorDataByTime = async (start: Date, end: Date) => {
const rows = await ObClient.query<

View File

@ -1,6 +1,6 @@
/* pg vector crud */
import { DatasetVectorTableName } from '../constants';
import { delay } from '@fastgpt/global/common/system/utils';
import { delay, retryFn } from '@fastgpt/global/common/system/utils';
import { PgClient, connectPg } from './controller';
import { type PgSearchRawType } from '@fastgpt/global/core/dataset/api';
import type {
@ -65,41 +65,30 @@ export class PgVectorCtrl {
addLog.error('init pg error', error);
}
};
insert = async (props: InsertVectorControllerProps): Promise<{ insertId: string }> => {
const { teamId, datasetId, collectionId, vector, retry = 3 } = props;
insert = async (props: InsertVectorControllerProps): Promise<{ insertIds: string[] }> => {
const { teamId, datasetId, collectionId, vectors } = props;
try {
const { rowCount, rows } = await PgClient.insert(DatasetVectorTableName, {
values: [
[
{ key: 'vector', value: `[${vector}]` },
{ key: 'team_id', value: String(teamId) },
{ key: 'dataset_id', value: String(datasetId) },
{ key: 'collection_id', value: String(collectionId) }
]
]
});
const values = vectors.map((vector) => [
{ key: 'vector', value: `[${vector}]` },
{ key: 'team_id', value: String(teamId) },
{ key: 'dataset_id', value: String(datasetId) },
{ key: 'collection_id', value: String(collectionId) }
]);
if (rowCount === 0) {
return Promise.reject('insertDatasetData: no insert');
}
const { rowCount, rows } = await PgClient.insert(DatasetVectorTableName, {
values
});
return {
insertId: rows[0].id
};
} catch (error) {
if (retry <= 0) {
return Promise.reject(error);
}
await delay(500);
return this.insert({
...props,
retry: retry - 1
});
if (rowCount === 0) {
return Promise.reject('insertDatasetData: no insert');
}
return {
insertIds: rows.map((row) => row.id)
};
};
delete = async (props: DelDatasetVectorCtrlProps): Promise<any> => {
const { teamId, retry = 2 } = props;
const { teamId } = props;
const teamIdWhere = `team_id='${String(teamId)}' AND`;
@ -129,31 +118,13 @@ export class PgVectorCtrl {
if (!where) return;
try {
await PgClient.delete(DatasetVectorTableName, {
where: [where]
});
} catch (error) {
if (retry <= 0) {
return Promise.reject(error);
}
await delay(500);
return this.delete({
...props,
retry: retry - 1
});
}
await PgClient.delete(DatasetVectorTableName, {
where: [where]
});
};
embRecall = async (props: EmbeddingRecallCtrlProps): Promise<EmbeddingRecallResponse> => {
const {
teamId,
datasetIds,
vector,
limit,
forbidCollectionIdList,
filterCollectionIdList,
retry = 2
} = props;
const { teamId, datasetIds, vector, limit, forbidCollectionIdList, filterCollectionIdList } =
props;
// Get forbid collection
const formatForbidCollectionIdList = (() => {
@ -184,9 +155,8 @@ export class PgVectorCtrl {
return { results: [] };
}
try {
const results: any = await PgClient.query(
`BEGIN;
const results: any = await PgClient.query(
`BEGIN;
SET LOCAL hnsw.ef_search = ${global.systemEnv?.hnswEfSearch || 100};
SET LOCAL hnsw.max_scan_tuples = ${global.systemEnv?.hnswMaxScanTuples || 100000};
SET LOCAL hnsw.iterative_scan = relaxed_order;
@ -199,31 +169,22 @@ export class PgVectorCtrl {
order by score limit ${limit}
) SELECT id, collection_id, score FROM relaxed_results ORDER BY score;
COMMIT;`
);
const rows = results?.[results.length - 2]?.rows as PgSearchRawType[];
if (!Array.isArray(rows)) {
return {
results: []
};
}
);
const rows = results?.[results.length - 2]?.rows as PgSearchRawType[];
if (!Array.isArray(rows)) {
return {
results: rows.map((item) => ({
id: String(item.id),
collectionId: item.collection_id,
score: item.score * -1
}))
results: []
};
} catch (error) {
if (retry <= 0) {
return Promise.reject(error);
}
return this.embRecall({
...props,
retry: retry - 1
});
}
return {
results: rows.map((item) => ({
id: String(item.id),
collectionId: item.collection_id,
score: item.score * -1
}))
};
};
getVectorDataByTime = async (start: Date, end: Date) => {
const { rows } = await PgClient.query<{

View File

@ -3,6 +3,7 @@ import { getAxiosConfig } from '../config';
import axios from 'axios';
import FormData from 'form-data';
import { type STTModelType } from '@fastgpt/global/core/ai/model.d';
import { UserError } from '@fastgpt/global/common/error/utils';
export const aiTranscriptions = async ({
model: modelData,
@ -14,7 +15,7 @@ export const aiTranscriptions = async ({
headers?: Record<string, string>;
}) => {
if (!modelData) {
return Promise.reject('no model');
return Promise.reject(new UserError('no model'));
}
const data = new FormData();

View File

@ -6,7 +6,7 @@ import { addLog } from '../../../common/system/log';
type GetVectorProps = {
model: EmbeddingModelItemType;
input: string;
input: string[] | string;
type?: `${EmbeddingTypeEnm}`;
headers?: Record<string, string>;
};
@ -19,60 +19,85 @@ export async function getVectorsByText({ model, input, type, headers }: GetVecto
message: 'input is empty'
});
}
const ai = getAIApi();
const formatInput = Array.isArray(input) ? input : [input];
// 20 size every request
const chunkSize = 20;
const chunks = [];
for (let i = 0; i < formatInput.length; i += chunkSize) {
chunks.push(formatInput.slice(i, i + chunkSize));
}
try {
const ai = getAIApi();
// Process chunks sequentially
let totalTokens = 0;
const allVectors: number[][] = [];
// input text to vector
const result = await ai.embeddings
.create(
{
...model.defaultConfig,
...(type === EmbeddingTypeEnm.db && model.dbConfig),
...(type === EmbeddingTypeEnm.query && model.queryConfig),
model: model.model,
input: [input]
},
model.requestUrl
? {
path: model.requestUrl,
headers: {
...(model.requestAuth ? { Authorization: `Bearer ${model.requestAuth}` } : {}),
...headers
for (const chunk of chunks) {
// input text to vector
const result = await ai.embeddings
.create(
{
...model.defaultConfig,
...(type === EmbeddingTypeEnm.db && model.dbConfig),
...(type === EmbeddingTypeEnm.query && model.queryConfig),
model: model.model,
input: chunk
},
model.requestUrl
? {
path: model.requestUrl,
headers: {
...(model.requestAuth ? { Authorization: `Bearer ${model.requestAuth}` } : {}),
...headers
}
}
}
: { headers }
)
.then(async (res) => {
if (!res.data) {
addLog.error('Embedding API is not responding', res);
return Promise.reject('Embedding API is not responding');
}
if (!res?.data?.[0]?.embedding) {
console.log(res);
// @ts-ignore
return Promise.reject(res.data?.err?.message || 'Embedding API Error');
}
: { headers }
)
.then(async (res) => {
if (!res.data) {
addLog.error('Embedding API is not responding', res);
return Promise.reject('Embedding API is not responding');
}
if (!res?.data?.[0]?.embedding) {
console.log(res);
// @ts-ignore
return Promise.reject(res.data?.err?.message || 'Embedding API Error');
}
const [tokens, vectors] = await Promise.all([
countPromptTokens(input),
Promise.all(
res.data
.map((item) => unityDimensional(item.embedding))
.map((item) => {
if (model.normalization) return normalization(item);
return item;
})
)
]);
const [tokens, vectors] = await Promise.all([
(async () => {
if (res.usage) return res.usage.total_tokens;
return {
tokens,
vectors
};
});
const tokens = await Promise.all(chunk.map((item) => countPromptTokens(item)));
return tokens.reduce((sum, item) => sum + item, 0);
})(),
Promise.all(
res.data
.map((item) => unityDimensional(item.embedding))
.map((item) => {
if (model.normalization) return normalization(item);
return item;
})
)
]);
return result;
return {
tokens,
vectors
};
});
totalTokens += result.tokens;
allVectors.push(...result.vectors);
}
return {
tokens: totalTokens,
vectors: allVectors
};
} catch (error) {
addLog.error(`Embedding Error`, error);

View File

@ -0,0 +1,77 @@
import type { AppChatLogSchema } from '@fastgpt/global/core/app/logs/type';
import { getMongoLogModel, Schema } from '../../../common/mongo';
import { AppCollectionName } from '../schema';
export const ChatLogCollectionName = 'app_chat_logs';
const ChatLogSchema = new Schema({
appId: {
type: Schema.Types.ObjectId,
ref: AppCollectionName,
required: true
},
teamId: {
type: Schema.Types.ObjectId,
required: true
},
chatId: {
type: String,
required: true
},
userId: {
type: String,
required: true
},
source: {
type: String,
required: true
},
sourceName: {
type: String
},
createTime: {
type: Date,
required: true
},
updateTime: {
type: Date,
required: true
},
// 累计统计字段
chatItemCount: {
type: Number,
default: 0
},
errorCount: {
type: Number,
default: 0
},
totalPoints: {
type: Number,
default: 0
},
goodFeedbackCount: {
type: Number,
default: 0
},
badFeedbackCount: {
type: Number,
default: 0
},
totalResponseTime: {
type: Number,
default: 0
},
isFirstChat: {
type: Boolean,
default: false
}
});
ChatLogSchema.index({ teamId: 1, appId: 1, source: 1, updateTime: -1 });
ChatLogSchema.index({ userId: 1, appId: 1, source: 1, createTime: -1 });
export const MongoAppChatLog = getMongoLogModel<AppChatLogSchema>(
ChatLogCollectionName,
ChatLogSchema
);

View File

@ -46,6 +46,7 @@ import { getMCPParentId, getMCPToolRuntimeNode } from '@fastgpt/global/core/app/
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { getMCPChildren } from '../mcp';
import { cloneDeep } from 'lodash';
import { UserError } from '@fastgpt/global/common/error/utils';
type ChildAppType = SystemPluginTemplateItemType & {
teamId?: string;
@ -80,7 +81,7 @@ export const getSystemPluginByIdAndVersionId = async (
app
})
: await getAppLatestVersion(plugin.associatedPluginId, app);
if (!version.versionId) return Promise.reject('App version not found');
if (!version.versionId) return Promise.reject(new UserError('App version not found'));
const isLatest = version.versionId
? await checkIsLatestVersion({
appId: plugin.associatedPluginId,
@ -119,7 +120,7 @@ export const getSystemPluginByIdAndVersionId = async (
const versionList = (plugin.versionList as SystemPluginTemplateItemType['versionList']) || [];
if (versionList.length === 0) {
return Promise.reject('Can not find plugin version list');
return Promise.reject(new UserError('Can not find plugin version list'));
}
const version = versionId
@ -304,11 +305,13 @@ export async function getChildAppPreviewNode({
? {
systemToolSet: {
toolId: app.id,
toolList: children.map((item) => ({
toolId: item.id,
name: parseI18nString(item.name, lang),
description: parseI18nString(item.intro, lang)
}))
toolList: children
.filter((item) => item.isActive !== false)
.map((item) => ({
toolId: item.id,
name: parseI18nString(item.name, lang),
description: parseI18nString(item.intro, lang)
}))
}
}
: { systemTool: { toolId: app.id } })
@ -378,8 +381,10 @@ export async function getChildAppPreviewNode({
showTargetHandle: true,
currentCost: app.currentCost,
systemKeyCost: app.systemKeyCost,
hasTokenFee: app.hasTokenFee,
hasSystemSecret: app.hasSystemSecret,
isFolder: app.isFolder,
...nodeIOConfig,
outputs: nodeIOConfig.outputs.some((item) => item.type === FlowNodeOutputTypeEnum.error)
@ -432,6 +437,7 @@ export async function getChildAppRuntimeById({
originCost: 0,
currentCost: 0,
systemKeyCost: 0,
hasTokenFee: false,
pluginOrder: 0
};
@ -448,6 +454,7 @@ export async function getChildAppRuntimeById({
avatar: app.avatar || '',
showStatus: true,
currentCost: app.currentCost,
systemKeyCost: app.systemKeyCost,
nodes: app.workflow.nodes,
edges: app.workflow.edges,
hasTokenFee: app.hasTokenFee
@ -474,6 +481,7 @@ const dbPluginFormat = (item: SystemPluginConfigSchemaType): SystemPluginTemplat
currentCost: item.currentCost,
hasTokenFee: item.hasTokenFee,
pluginOrder: item.pluginOrder,
systemKeyCost: item.systemKeyCost,
associatedPluginId,
userGuide,
workflow: {
@ -515,61 +523,63 @@ export const getSystemTools = async (): Promise<SystemPluginTemplateItemType[]>
const tools = await APIGetSystemToolList();
// 从数据库里加载插件配置进行替换
const systemPluginsArray = await MongoSystemPlugin.find({}).lean();
const systemPlugins = new Map(systemPluginsArray.map((plugin) => [plugin.pluginId, plugin]));
const systemToolsArray = await MongoSystemPlugin.find({}).lean();
const systemTools = new Map(systemToolsArray.map((plugin) => [plugin.pluginId, plugin]));
tools.forEach((tool) => {
// 如果有插件的配置信息,则需要进行替换
const dbPluginConfig = systemPlugins.get(tool.id);
// tools.forEach((tool) => {
// // 如果有插件的配置信息,则需要进行替换
// const dbPluginConfig = systemTools.get(tool.id);
if (dbPluginConfig) {
const children = tools.filter((item) => item.parentId === tool.id);
const list = [tool, ...children];
list.forEach((item) => {
item.isActive = dbPluginConfig.isActive ?? item.isActive ?? true;
item.originCost = dbPluginConfig.originCost ?? 0;
item.currentCost = dbPluginConfig.currentCost ?? 0;
item.hasTokenFee = dbPluginConfig.hasTokenFee ?? false;
item.pluginOrder = dbPluginConfig.pluginOrder ?? 0;
});
}
});
// if (dbPluginConfig) {
// const children = tools.filter((item) => item.parentId === tool.id);
// const list = [tool, ...children];
// list.forEach((item) => {
// item.isActive = dbPluginConfig.isActive ?? item.isActive ?? true;
// item.originCost = dbPluginConfig.originCost ?? 0;
// item.currentCost = dbPluginConfig.currentCost ?? 0;
// item.hasTokenFee = dbPluginConfig.hasTokenFee ?? false;
// item.pluginOrder = dbPluginConfig.pluginOrder ?? 0;
// });
// }
// });
const formatTools = tools.map<SystemPluginTemplateItemType>((item) => {
const dbPluginConfig = systemPlugins.get(item.id);
const dbPluginConfig = systemTools.get(item.id);
const isFolder = tools.some((tool) => tool.parentId === item.id);
const versionList = (item.versionList as SystemPluginTemplateItemType['versionList']) || [];
return {
id: item.id,
parentId: item.parentId,
isFolder: tools.some((tool) => tool.parentId === item.id),
isFolder,
name: item.name,
avatar: item.avatar,
intro: item.description,
author: item.author,
courseUrl: item.courseUrl,
weight: item.weight,
workflow: {
nodes: [],
edges: []
},
versionList,
templateType: item.templateType,
showStatus: true,
isActive: item.isActive,
isActive: dbPluginConfig?.isActive ?? item.isActive ?? true,
inputList: item?.secretInputConfig,
hasSystemSecret: !!dbPluginConfig?.inputListVal
hasSystemSecret: !!dbPluginConfig?.inputListVal,
originCost: dbPluginConfig?.originCost ?? 0,
currentCost: dbPluginConfig?.currentCost ?? 0,
systemKeyCost: dbPluginConfig?.systemKeyCost ?? 0,
hasTokenFee: dbPluginConfig?.hasTokenFee ?? false,
pluginOrder: dbPluginConfig?.pluginOrder
};
});
// TODO: Check the app exists
const dbPlugins = systemPluginsArray
const dbPlugins = systemToolsArray
.filter((item) => item.customConfig?.associatedPluginId)
.map((item) => dbPluginFormat(item));

View File

@ -27,6 +27,10 @@ const SystemPluginSchema = new Schema({
pluginOrder: {
type: Number
},
systemKeyCost: {
type: Number,
default: 0
},
customConfig: Object,
inputListVal: Object,

View File

@ -1,6 +1,7 @@
import { SystemPluginListItemType } from '@fastgpt/global/core/app/type';
import { FlowNodeTemplateTypeEnum } from '@fastgpt/global/core/workflow/constants';
import type { WorkflowTemplateBasicType } from '@fastgpt/global/core/workflow/type';
import type { InputConfigType } from '@fastgpt/global/core/workflow/type/io';
export type SystemPluginConfigSchemaType = {
pluginId: string;
@ -10,6 +11,7 @@ export type SystemPluginConfigSchemaType = {
hasTokenFee: boolean;
isActive: boolean;
pluginOrder?: number;
systemKeyCost?: number;
customConfig?: {
name: string;

View File

@ -82,8 +82,10 @@ export async function rewriteAppWorkflowToDetail({
node.version = preview.version;
node.currentCost = preview.currentCost;
node.systemKeyCost = preview.systemKeyCost;
node.hasTokenFee = preview.hasTokenFee;
node.hasSystemSecret = preview.hasSystemSecret;
node.isFolder = preview.isFolder;
node.toolConfig = preview.toolConfig;

View File

@ -1,7 +1,7 @@
import { connectionMongo, getMongoModel } from '../../common/mongo';
const { Schema } = connectionMongo;
import { type ChatSchema as ChatType } from '@fastgpt/global/core/chat/type.d';
import { ChatSourceEnum, ChatSourceMap } from '@fastgpt/global/core/chat/constants';
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
import {
TeamCollectionName,
TeamMemberCollectionName

View File

@ -4,6 +4,7 @@ import { addLog } from '../../common/system/log';
import { delFileByFileIdList, getGFSCollection } from '../../common/file/gridfs/controller';
import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
import { MongoChat } from './chatSchema';
import { UserError } from '@fastgpt/global/common/error/utils';
export async function getChatItems({
appId,
@ -72,7 +73,8 @@ export const deleteChatFiles = async ({
chatIdList?: string[];
appId?: string;
}) => {
if (!appId && !chatIdList) return Promise.reject('appId or chatIdList is required');
if (!appId && !chatIdList)
return Promise.reject(new UserError('appId or chatIdList is required'));
const appChatIdList = await (async () => {
if (appId) {

View File

@ -14,6 +14,7 @@ import { pushChatLog } from './pushChatLog';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { extractDeepestInteractive } from '@fastgpt/global/core/workflow/runtime/utils';
import { MongoAppChatLog } from '../app/logs/chatLogsSchema';
type Props = {
chatId: string;
@ -163,6 +164,62 @@ export async function saveChat({
});
});
try {
const userId = outLinkUid || tmbId;
const now = new Date();
const fifteenMinutesAgo = new Date(now.getTime() - 15 * 60 * 1000);
const aiResponse = processedContent.find((item) => item.obj === ChatRoleEnum.AI);
const errorCount = aiResponse?.responseData?.some((item) => item.errorText) ? 1 : 0;
const totalPoints =
aiResponse?.responseData?.reduce(
(sum: number, item: any) => sum + (item.totalPoints || 0),
0
) || 0;
const hasHistoryChat = await MongoAppChatLog.exists({
appId,
userId,
createTime: { $lt: now }
});
await MongoAppChatLog.updateOne(
{
chatId,
appId,
updateTime: { $gte: fifteenMinutesAgo }
},
{
$inc: {
chatItemCount: 1,
errorCount,
totalPoints,
totalResponseTime: durationSeconds
},
$set: {
updateTime: now,
sourceName
},
$setOnInsert: {
appId,
teamId,
chatId,
userId,
source,
createTime: now,
goodFeedbackCount: 0,
badFeedbackCount: 0,
isFirstChat: !hasHistoryChat
}
},
{
upsert: true
}
);
} catch (error) {
addLog.error('update chat log error', error);
}
if (isUpdateUseTime) {
await MongoApp.findByIdAndUpdate(appId, {
updateTime: new Date()

View File

@ -0,0 +1,37 @@
import { connectionMongo, getMongoModel } from '../../../common/mongo';
import { type ChatSettingSchema as ChatSettingType } from '@fastgpt/global/core/chat/setting/type';
import { TeamCollectionName } from '@fastgpt/global/support/user/team/constant';
import { AppCollectionName } from '../../app/schema';
const { Schema } = connectionMongo;
export const ChatSettingCollectionName = 'chat_settings';
const ChatSettingSchema = new Schema({
teamId: {
type: Schema.Types.ObjectId,
ref: TeamCollectionName,
required: true
},
appId: {
type: Schema.Types.ObjectId,
ref: AppCollectionName,
required: true
},
slogan: String,
dialogTips: String,
selectedTools: {
type: Array,
default: []
},
homeTabTitle: String,
wideLogoUrl: String,
squareLogoUrl: String
});
ChatSettingSchema.index({ teamId: 1 });
export const MongoChatSetting = getMongoModel<ChatSettingType>(
ChatSettingCollectionName,
ChatSettingSchema
);

View File

@ -14,6 +14,7 @@ import { MongoDatasetCollectionTags } from './tag/schema';
import { removeDatasetSyncJobScheduler } from './datasetSync';
import { mongoSessionRun } from '../../common/mongo/sessionRun';
import { removeImageByPath } from '../../common/file/image/controller';
import { UserError } from '@fastgpt/global/common/error/utils';
/* ============= dataset ========== */
/* find all datasetId by top datasetId */
@ -50,7 +51,7 @@ export async function findDatasetAndAllChildren({
]);
if (!dataset) {
return Promise.reject('Dataset not found');
return Promise.reject(new UserError('Dataset not found'));
}
return [dataset, ...childDatasets];
@ -79,7 +80,7 @@ export async function delDatasetRelevantData({
const teamId = datasets[0].teamId;
if (!teamId) {
return Promise.reject('TeamId is required');
return Promise.reject(new UserError('TeamId is required'));
}
const datasetIds = datasets.map((item) => item._id);

View File

@ -16,6 +16,7 @@ import { text2Chunks } from '../../worker/function';
import { addLog } from '../../common/system/log';
import { retryFn } from '@fastgpt/global/common/system/utils';
import { getFileMaxSize } from '../../common/file/utils';
import { UserError } from '@fastgpt/global/common/error/utils';
export const readFileRawTextByUrl = async ({
teamId,
@ -200,7 +201,7 @@ export const readDatasetSourceRawText = async ({
rawText: content
};
} else if (type === DatasetSourceReadTypeEnum.externalFile) {
if (!externalFileId) return Promise.reject('FileId not found');
if (!externalFileId) return Promise.reject(new UserError('FileId not found'));
const rawText = await readFileRawTextByUrl({
teamId,
tmbId,

View File

@ -7,6 +7,10 @@ import { recallFromVectorStore } from '../../../common/vectorDB/controller';
import { getVectorsByText } from '../../ai/embedding';
import { getEmbeddingModel, getDefaultRerankModel, getLLMModel } from '../../ai/model';
import { MongoDatasetData } from '../data/schema';
import type {
DatasetCollectionSchemaType,
DatasetDataSchemaType
} from '@fastgpt/global/core/dataset/type';
import {
type DatasetDataTextSchemaType,
type SearchDataResponseItemType
@ -27,7 +31,6 @@ import { type ChatItemType } from '@fastgpt/global/core/chat/type';
import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { datasetSearchQueryExtension } from './utils';
import type { RerankModelItemType } from '@fastgpt/global/core/ai/model.d';
import { addLog } from '../../../common/system/log';
import { formatDatasetDataValue } from '../data/controller';
export type SearchDatasetDataProps = {
@ -435,214 +438,114 @@ export async function searchDatasetData(
} catch (error) {}
};
const embeddingRecall = async ({
query,
queries,
limit,
forbidCollectionIdList,
filterCollectionIdList
}: {
query: string;
queries: string[];
limit: number;
forbidCollectionIdList: string[];
filterCollectionIdList?: string[];
}) => {
}): Promise<{
embeddingRecallResults: SearchDataResponseItemType[][];
tokens: number;
}> => {
if (limit === 0) {
return {
embeddingRecallResults: [],
tokens: 0
};
}
const { vectors, tokens } = await getVectorsByText({
model: getEmbeddingModel(model),
input: query,
input: queries,
type: 'query'
});
const { results } = await recallFromVectorStore({
teamId,
datasetIds,
vector: vectors[0],
limit,
forbidCollectionIdList,
filterCollectionIdList
});
const recallResults = await Promise.all(
vectors.map(async (vector) => {
return await recallFromVectorStore({
teamId,
datasetIds,
vector,
limit,
forbidCollectionIdList,
filterCollectionIdList
});
})
);
// Get data and collections
const collectionIdList = Array.from(new Set(results.map((item) => item.collectionId)));
const [dataList, collections] = await Promise.all([
const collectionIdList = Array.from(
new Set(recallResults.map((item) => item.results.map((item) => item.collectionId)).flat())
);
const indexDataIds = Array.from(
new Set(recallResults.map((item) => item.results.map((item) => item.id?.trim())).flat())
);
const [dataMaps, collectionMaps] = await Promise.all([
MongoDatasetData.find(
{
teamId,
datasetId: { $in: datasetIds },
collectionId: { $in: collectionIdList },
'indexes.dataId': { $in: results.map((item) => item.id?.trim()) }
'indexes.dataId': { $in: indexDataIds }
},
datasetDataSelectField,
{ ...readFromSecondary }
).lean(),
)
.lean()
.then((res) => {
const map = new Map<string, DatasetDataSchemaType>();
res.forEach((item) => {
item.indexes.forEach((index) => {
map.set(String(index.dataId), item);
});
});
return map;
}),
MongoDatasetCollection.find(
{
_id: { $in: collectionIdList }
},
datsaetCollectionSelectField,
{ ...readFromSecondary }
).lean()
)
.lean()
.then((res) => {
const map = new Map<string, DatasetCollectionSchemaType>();
res.forEach((item) => {
map.set(String(item._id), item);
});
return map;
})
]);
const set = new Set<string>();
const formatResult = results
.map((item, index) => {
const collection = collections.find((col) => String(col._id) === String(item.collectionId));
if (!collection) {
console.log('Collection is not found', item);
return;
}
const data = dataList.find((data) =>
data.indexes.some((index) => index.dataId === item.id)
);
if (!data) {
console.log('Data is not found', item);
return;
}
const result: SearchDataResponseItemType = {
id: String(data._id),
updateTime: data.updateTime,
...formatDatasetDataValue({
teamId,
datasetId: data.datasetId,
q: data.q,
a: data.a,
imageId: data.imageId,
imageDescMap: data.imageDescMap
}),
chunkIndex: data.chunkIndex,
datasetId: String(data.datasetId),
collectionId: String(data.collectionId),
...getCollectionSourceData(collection),
score: [{ type: SearchScoreTypeEnum.embedding, value: item?.score || 0, index }]
};
return result;
})
.filter((item) => {
if (!item) return false;
if (set.has(item.id)) return false;
set.add(item.id);
return true;
})
.map((item, index) => {
if (!item) return;
return {
...item,
score: item.score.map((item) => ({ ...item, index }))
};
}) as SearchDataResponseItemType[];
return {
embeddingRecallResults: formatResult,
tokens
};
};
const fullTextRecall = async ({
query,
limit,
filterCollectionIdList,
forbidCollectionIdList
}: {
query: string;
limit: number;
filterCollectionIdList?: string[];
forbidCollectionIdList: string[];
}): Promise<{
fullTextRecallResults: SearchDataResponseItemType[];
tokenLen: number;
}> => {
if (limit === 0) {
return {
fullTextRecallResults: [],
tokenLen: 0
};
}
try {
const searchResults = (await MongoDatasetDataText.aggregate(
[
{
$match: {
teamId: new Types.ObjectId(teamId),
$text: { $search: await jiebaSplit({ text: query }) },
datasetId: { $in: datasetIds.map((id) => new Types.ObjectId(id)) },
...(filterCollectionIdList
? {
collectionId: {
$in: filterCollectionIdList
.filter((id) => !forbidCollectionIdList.includes(id))
.map((id) => new Types.ObjectId(id))
}
}
: forbidCollectionIdList?.length
? {
collectionId: {
$nin: forbidCollectionIdList.map((id) => new Types.ObjectId(id))
}
}
: {})
}
},
{
$sort: {
score: { $meta: 'textScore' }
}
},
{
$limit: limit
},
{
$project: {
_id: 1,
collectionId: 1,
dataId: 1,
score: { $meta: 'textScore' }
}
}
],
{
...readFromSecondary
}
)) as (DatasetDataTextSchemaType & { score: number })[];
// Get data and collections
const [dataList, collections] = await Promise.all([
MongoDatasetData.find(
{
_id: { $in: searchResults.map((item) => item.dataId) }
},
datasetDataSelectField,
{ ...readFromSecondary }
).lean(),
MongoDatasetCollection.find(
{
_id: { $in: searchResults.map((item) => item.collectionId) }
},
datsaetCollectionSelectField,
{ ...readFromSecondary }
).lean()
]);
return {
fullTextRecallResults: searchResults
const embeddingRecallResults = recallResults.map((item) => {
const set = new Set<string>();
return (
item.results
.map((item, index) => {
const collection = collections.find(
(col) => String(col._id) === String(item.collectionId)
);
const collection = collectionMaps.get(String(item.collectionId));
if (!collection) {
console.log('Collection is not found', item);
return;
}
const data = dataList.find((data) => String(data._id) === String(item.dataId));
const data = dataMaps.get(String(item.id));
if (!data) {
console.log('Data is not found', item);
return;
}
return {
const result: SearchDataResponseItemType = {
id: String(data._id),
datasetId: String(data.datasetId),
collectionId: String(data.collectionId),
updateTime: data.updateTime,
...formatDatasetDataValue({
teamId,
@ -653,37 +556,204 @@ export async function searchDatasetData(
imageDescMap: data.imageDescMap
}),
chunkIndex: data.chunkIndex,
indexes: data.indexes,
datasetId: String(data.datasetId),
collectionId: String(data.collectionId),
...getCollectionSourceData(collection),
score: [
{
type: SearchScoreTypeEnum.fullText,
value: item.score || 0,
index
}
]
score: [{ type: SearchScoreTypeEnum.embedding, value: item?.score || 0, index }]
};
return result;
})
// 多个向量对应一个数据,每一路召回,保障数据只有一份,并且取最高排名
.filter((item) => {
if (!item) return false;
if (set.has(item.id)) return false;
set.add(item.id);
return true;
})
.map((item, index) => {
if (!item) return;
return {
...item,
score: item.score.map((item) => ({ ...item, index }))
...item!,
score: item!.score.map((item) => ({ ...item, index }))
};
}) as SearchDataResponseItemType[],
tokenLen: 0
};
} catch (error) {
addLog.error('Full text search error', error);
}) as SearchDataResponseItemType[]
);
});
return {
embeddingRecallResults,
tokens
};
};
const fullTextRecall = async ({
queries,
limit,
filterCollectionIdList,
forbidCollectionIdList
}: {
queries: string[];
limit: number;
filterCollectionIdList?: string[];
forbidCollectionIdList: string[];
}): Promise<{
fullTextRecallResults: SearchDataResponseItemType[][];
}> => {
if (limit === 0) {
return {
fullTextRecallResults: [],
tokenLen: 0
fullTextRecallResults: []
};
}
const recallResults = await Promise.all(
queries.map(async (query) => {
return (await MongoDatasetDataText.aggregate(
[
{
$match: {
teamId: new Types.ObjectId(teamId),
$text: { $search: await jiebaSplit({ text: query }) },
datasetId: { $in: datasetIds.map((id) => new Types.ObjectId(id)) },
...(filterCollectionIdList
? {
collectionId: {
$in: filterCollectionIdList
.filter((id) => !forbidCollectionIdList.includes(id))
.map((id) => new Types.ObjectId(id))
}
}
: forbidCollectionIdList?.length
? {
collectionId: {
$nin: forbidCollectionIdList.map((id) => new Types.ObjectId(id))
}
}
: {})
}
},
{
$sort: {
score: { $meta: 'textScore' }
}
},
{
$limit: limit
},
{
$project: {
_id: 1,
collectionId: 1,
dataId: 1,
score: { $meta: 'textScore' }
}
}
],
{
...readFromSecondary
}
)) as (DatasetDataTextSchemaType & { score: number })[];
})
);
const dataIds = Array.from(
new Set(recallResults.map((item) => item.map((item) => item.dataId)).flat())
);
const collectionIds = Array.from(
new Set(recallResults.map((item) => item.map((item) => item.collectionId)).flat())
);
// Get data and collections
const [dataMaps, collectionMaps] = await Promise.all([
MongoDatasetData.find(
{
_id: { $in: dataIds }
},
datasetDataSelectField,
{ ...readFromSecondary }
)
.lean()
.then((res) => {
const map = new Map<string, DatasetDataSchemaType>();
res.forEach((item) => {
map.set(String(item._id), item);
});
return map;
}),
MongoDatasetCollection.find(
{
_id: { $in: collectionIds }
},
datsaetCollectionSelectField,
{ ...readFromSecondary }
)
.lean()
.then((res) => {
const map = new Map<string, DatasetCollectionSchemaType>();
res.forEach((item) => {
map.set(String(item._id), item);
});
return map;
})
]);
const fullTextRecallResults = recallResults.map((item) => {
return item
.map((item, index) => {
const collection = collectionMaps.get(String(item.collectionId));
if (!collection) {
console.log('Collection is not found', item);
return;
}
const data = dataMaps.get(String(item.dataId));
if (!data) {
console.log('Data is not found', item);
return;
}
return {
id: String(data._id),
datasetId: String(data.datasetId),
collectionId: String(data.collectionId),
updateTime: data.updateTime,
...formatDatasetDataValue({
teamId,
datasetId: data.datasetId,
q: data.q,
a: data.a,
imageId: data.imageId,
imageDescMap: data.imageDescMap
}),
chunkIndex: data.chunkIndex,
indexes: data.indexes,
...getCollectionSourceData(collection),
score: [
{
type: SearchScoreTypeEnum.fullText,
value: item.score || 0,
index
}
]
};
})
.filter((item) => {
if (!item) return false;
return true;
})
.map((item, index) => {
return {
...item,
score: item!.score.map((item) => ({ ...item, index }))
};
}) as SearchDataResponseItemType[];
});
return {
fullTextRecallResults
};
};
const multiQueryRecall = async ({
embeddingLimit,
@ -692,50 +762,36 @@ export async function searchDatasetData(
embeddingLimit: number;
fullTextLimit: number;
}) => {
// multi query recall
const embeddingRecallResList: SearchDataResponseItemType[][] = [];
const fullTextRecallResList: SearchDataResponseItemType[][] = [];
let totalTokens = 0;
const [{ forbidCollectionIdList }, filterCollectionIdList] = await Promise.all([
getForbidData(),
filterCollectionByMetadata()
]);
await Promise.all(
queries.map(async (query) => {
const [{ tokens, embeddingRecallResults }, { fullTextRecallResults }] = await Promise.all([
embeddingRecall({
query,
limit: embeddingLimit,
forbidCollectionIdList,
filterCollectionIdList
}),
// FullText tmp
fullTextRecall({
query,
limit: fullTextLimit,
filterCollectionIdList,
forbidCollectionIdList
})
]);
totalTokens += tokens;
embeddingRecallResList.push(embeddingRecallResults);
fullTextRecallResList.push(fullTextRecallResults);
const [{ tokens, embeddingRecallResults }, { fullTextRecallResults }] = await Promise.all([
embeddingRecall({
queries,
limit: embeddingLimit,
forbidCollectionIdList,
filterCollectionIdList
}),
fullTextRecall({
queries,
limit: fullTextLimit,
filterCollectionIdList,
forbidCollectionIdList
})
);
]);
// rrf concat
const rrfEmbRecall = datasetSearchResultConcat(
embeddingRecallResList.map((list) => ({ k: 60, list }))
embeddingRecallResults.map((list) => ({ k: 60, list }))
).slice(0, embeddingLimit);
const rrfFTRecall = datasetSearchResultConcat(
fullTextRecallResList.map((list) => ({ k: 60, list }))
fullTextRecallResults.map((list) => ({ k: 60, list }))
).slice(0, fullTextLimit);
return {
tokens: totalTokens,
tokens,
embeddingRecallResults: rrfEmbRecall,
fullTextRecallResults: rrfFTRecall
};

View File

@ -53,7 +53,7 @@ export async function pushDataListToTrainingQueue({
const { model, maxToken, weight } = await (async () => {
if (mode === TrainingModeEnum.chunk) {
return {
maxToken: getLLMMaxChunkSize(agentModelData),
maxToken: Infinity,
model: vectorModelData.model,
weight: vectorModelData.weight
};

View File

@ -21,6 +21,7 @@ import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { getAppVersionById } from '../../../app/version/controller';
import { parseUrlToFileType } from '@fastgpt/global/common/file/tools';
import { getUserChatInfoAndAuthTeamPoints } from '../../../../support/permission/auth/team';
import { getRunningUserInfoByTmbId } from '../../../../support/user/team/utils';
type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.userChatInput]: string;
@ -147,6 +148,7 @@ export const dispatchRunAppNode = async (props: Props): Promise<Response> => {
tmbId: String(appData.tmbId),
isChildApp: true
},
runningUserInfo: await getRunningUserInfoByTmbId(appData.tmbId),
runtimeNodes,
runtimeEdges,
histories: chatHistories,

View File

@ -90,6 +90,10 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
systemVar: {
user: {
id: variables.userId,
username: runningUserInfo.username,
contact: runningUserInfo.contact,
membername: runningUserInfo.memberName,
teamName: runningUserInfo.teamName,
teamId: runningUserInfo.teamId,
name: runningUserInfo.tmbId
},
@ -150,7 +154,7 @@ export const dispatchRunTool = async (props: RunToolProps): Promise<RunToolRespo
if (params.system_input_config?.type !== SystemToolInputTypeEnum.system) {
return 0;
}
return tool.currentCost ?? 0;
return (tool.systemKeyCost ?? 0) + (tool.currentCost ?? 0);
})();
pushTrack.runSystemTool({

View File

@ -152,7 +152,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
} = data;
const startTime = Date.now();
await rewriteRuntimeWorkFlow({ nodes: runtimeNodes, edges: runtimeEdges });
await rewriteRuntimeWorkFlow({ nodes: runtimeNodes, edges: runtimeEdges, lang: data.lang });
// 初始化深度和自动增加深度,避免无限嵌套
if (!props.workflowDispatchDeep) {

View File

@ -20,6 +20,7 @@ import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { MongoApp } from '../../../core/app/schema';
import { getMCPChildren } from '../../../core/app/mcp';
import { getSystemToolRunTimeNodeFromSystemToolset } from '../utils';
import type { localeType } from '@fastgpt/global/common/i18n/type';
export const getWorkflowResponseWrite = ({
res,
@ -161,10 +162,12 @@ export const formatHttpError = (error: any) => {
*/
export const rewriteRuntimeWorkFlow = async ({
nodes,
edges
edges,
lang
}: {
nodes: RuntimeNodeItemType[];
edges: RuntimeEdgeItemType[];
lang?: localeType;
}) => {
const toolSetNodes = nodes.filter((node) => node.flowNodeType === FlowNodeTypeEnum.toolSet);
@ -195,7 +198,8 @@ export const rewriteRuntimeWorkFlow = async ({
// systemTool
if (systemToolId) {
const children = await getSystemToolRunTimeNodeFromSystemToolset({
toolSetNode
toolSetNode,
lang
});
children.forEach((node) => {
nodes.push(node);

View File

@ -6,6 +6,7 @@ import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { parseI18nString } from '@fastgpt/global/common/i18n/utils';
import type { localeType } from '@fastgpt/global/common/i18n/type';
/* filter search result */
export const filterSearchResultsByMaxChars = async (
@ -31,9 +32,11 @@ export const filterSearchResultsByMaxChars = async (
};
export async function getSystemToolRunTimeNodeFromSystemToolset({
toolSetNode
toolSetNode,
lang = 'en'
}: {
toolSetNode: RuntimeNodeItemType;
lang?: localeType;
}): Promise<RuntimeNodeItemType[]> {
const systemToolId = toolSetNode.toolConfig?.systemToolSet?.toolId!;
@ -41,13 +44,14 @@ export async function getSystemToolRunTimeNodeFromSystemToolset({
(item) => item.key === NodeInputKeyEnum.systemInputConfig
);
const tools = await getSystemTools();
const children = tools.filter((item) => item.parentId === systemToolId);
const children = tools.filter(
(item) => item.parentId === systemToolId && item.isActive !== false
);
const nodes = await Promise.all(
children.map(async (child) => {
const toolListItem = toolSetNode.toolConfig?.systemToolSet?.toolList.find(
(item) => item.toolId === child.id
)!;
);
const tool = await getSystemPluginByIdAndVersionId(child.id);
@ -63,8 +67,8 @@ export async function getSystemToolRunTimeNodeFromSystemToolset({
...tool,
inputs,
outputs: tool.outputs ?? [],
name: toolListItem.name ?? parseI18nString(tool.name, 'en'),
intro: toolListItem.description ?? parseI18nString(tool.intro, 'en'),
name: toolListItem?.name || parseI18nString(tool.name, lang),
intro: toolListItem?.description || parseI18nString(tool.intro, lang),
flowNodeType: FlowNodeTypeEnum.tool,
nodeId: getNanoid(),
toolConfig: {

View File

@ -3,7 +3,7 @@
"version": "1.0.0",
"type": "module",
"dependencies": {
"@fastgpt-sdk/plugin": "^0.1.7",
"@fastgpt-sdk/plugin": "^0.1.8",
"@fastgpt/global": "workspace:*",
"@modelcontextprotocol/sdk": "^1.12.1",
"@node-rs/jieba": "2.0.1",
@ -15,7 +15,7 @@
"@opentelemetry/winston-transport": "^0.14.0",
"@vercel/otel": "^1.13.0",
"@xmldom/xmldom": "^0.8.10",
"@zilliz/milvus2-sdk-node": "2.4.2",
"@zilliz/milvus2-sdk-node": "2.4.10",
"axios": "^1.8.2",
"bullmq": "^5.52.2",
"chalk": "^5.3.0",

View File

@ -2,17 +2,22 @@
import { MongoApp } from '../../../core/app/schema';
import { type AppDetailType } from '@fastgpt/global/core/app/type.d';
import { parseHeaderCert } from '../controller';
import { PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
import {
PerResourceTypeEnum,
ReadPermissionVal,
ReadRoleVal
} from '@fastgpt/global/support/permission/constant';
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
import { getTmbInfoByTmbId } from '../../user/team/controller';
import { getResourcePermission } from '../controller';
import { AppPermission } from '@fastgpt/global/support/permission/app/controller';
import { type PermissionValueType } from '@fastgpt/global/support/permission/type';
import { AppFolderTypeList } from '@fastgpt/global/core/app/constants';
import { AppFolderTypeList, AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { type ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { PluginSourceEnum } from '@fastgpt/global/core/app/plugin/constants';
import { type AuthModeType, type AuthResponseType } from '../type';
import { splitCombinePluginId } from '@fastgpt/global/core/app/plugin/utils';
import { AppReadChatLogPerVal } from '@fastgpt/global/support/permission/app/constant';
export const authPluginByTmbId = async ({
tmbId,
@ -68,6 +73,21 @@ export const authAppByTmbId = async ({
return Promise.reject(AppErrEnum.unAuthApp);
}
if (app.type === AppTypeEnum.hidden) {
if (per === AppReadChatLogPerVal) {
if (!tmbPer.hasManagePer) {
return Promise.reject(AppErrEnum.unAuthApp);
}
} else if (per !== ReadPermissionVal) {
return Promise.reject(AppErrEnum.unAuthApp);
}
return {
...app,
permission: new AppPermission({ isOwner: false, role: ReadRoleVal })
};
}
const isOwner = tmbPer.isOwner || String(app.tmbId) === String(tmbId);
const { Per } = await (async () => {
@ -134,7 +154,7 @@ export const authApp = async ({
appId: ParentIdType;
per: PermissionValueType;
}): Promise<
AuthResponseType & {
AuthResponseType<AppPermission> & {
app: AppDetailType;
}
> => {

View File

@ -0,0 +1,35 @@
import { MongoTeamMember } from '../../user/team/teamMemberSchema';
import { type UserModelSchema } from '@fastgpt/global/support/user/type';
import { type TeamSchema } from '@fastgpt/global/support/user/team/type';
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
// TODO: 数据库优化
export async function getRunningUserInfoByTmbId(tmbId: string) {
if (tmbId) {
const tmb = await MongoTeamMember.findById(tmbId, 'teamId name userId') // team_members name is the user's name
.populate<{ team: TeamSchema; user: UserModelSchema }>([
{
path: 'team',
select: 'name'
},
{
path: 'user',
select: 'username contact'
}
])
.lean();
if (!tmb) return Promise.reject(TeamErrEnum.notUser);
return {
username: tmb.user.username,
teamName: tmb.team.name,
memberName: tmb.name,
contact: tmb.user.contact || '',
teamId: tmb.teamId,
tmbId: tmb._id
};
}
return Promise.reject(TeamErrEnum.notUser);
}

View File

@ -70,7 +70,7 @@
"renderTypeList": ["settingLLMModel", "reference"],
"label": "core.module.input.label.aiModel",
"valueType": "string",
"value": "gpt-4o-mini"
"value": "gpt-5"
},
{
"key": "temperature",
@ -189,7 +189,7 @@
"required": true,
"valueType": "string",
"llmModelType": "classify",
"value": "gpt-4o-mini"
"value": "gpt-5"
},
{
"key": "systemPrompt",

View File

@ -1428,7 +1428,7 @@
"description": "",
"debugLabel": "",
"toolDescription": "",
"value": "gpt-4o-mini"
"value": "gpt-5"
},
{
"key": "datasetSearchExtensionBg",

View File

@ -73,7 +73,7 @@
],
"label": "core.module.input.label.aiModel",
"valueType": "string",
"value": "gpt-4o-mini"
"value": "gpt-5"
},
{
"key": "temperature",

View File

@ -5,6 +5,7 @@ export const iconPaths = {
backup: () => import('./icons/backup.svg'),
book: () => import('./icons/book.svg'),
change: () => import('./icons/change.svg'),
chart: () => import('./icons/chart.svg'),
chatSend: () => import('./icons/chatSend.svg'),
check: () => import('./icons/check.svg'),
checkCircle: () => import('./icons/checkCircle.svg'),
@ -112,9 +113,9 @@ export const iconPaths = {
'common/tickFill': () => import('./icons/common/tickFill.svg'),
'common/toolkit': () => import('./icons/common/toolkit.svg'),
'common/trash': () => import('./icons/common/trash.svg'),
'common/upRightArrowLight': () => import('./icons/common/upRightArrowLight.svg'),
'common/uploadFileFill': () => import('./icons/common/uploadFileFill.svg'),
'common/upperRight': () => import('./icons/common/upperRight.svg'),
'common/upRightArrowLight': () => import('./icons/common/upRightArrowLight.svg'),
'common/userInfo': () => import('./icons/common/userInfo.svg'),
'common/variable': () => import('./icons/common/variable.svg'),
'common/viewLight': () => import('./icons/common/viewLight.svg'),
@ -151,6 +152,8 @@ export const iconPaths = {
'core/app/simpleMode/tts': () => import('./icons/core/app/simpleMode/tts.svg'),
'core/app/simpleMode/variable': () => import('./icons/core/app/simpleMode/variable.svg'),
'core/app/simpleMode/whisper': () => import('./icons/core/app/simpleMode/whisper.svg'),
'core/app/templates/TranslateRobot': () =>
import('./icons/core/app/templates/TranslateRobot.svg'),
'core/app/templates/animalLife': () => import('./icons/core/app/templates/animalLife.svg'),
'core/app/templates/chinese': () => import('./icons/core/app/templates/chinese.svg'),
'core/app/templates/divination': () => import('./icons/core/app/templates/divination.svg'),
@ -160,8 +163,6 @@ export const iconPaths = {
'core/app/templates/plugin-dalle': () => import('./icons/core/app/templates/plugin-dalle.svg'),
'core/app/templates/plugin-feishu': () => import('./icons/core/app/templates/plugin-feishu.svg'),
'core/app/templates/stock': () => import('./icons/core/app/templates/stock.svg'),
'core/app/templates/TranslateRobot': () =>
import('./icons/core/app/templates/TranslateRobot.svg'),
'core/app/toolCall': () => import('./icons/core/app/toolCall.svg'),
'core/app/ttsFill': () => import('./icons/core/app/ttsFill.svg'),
'core/app/type/httpPlugin': () => import('./icons/core/app/type/httpPlugin.svg'),
@ -180,6 +181,7 @@ export const iconPaths = {
'core/app/variable/input': () => import('./icons/core/app/variable/input.svg'),
'core/app/variable/select': () => import('./icons/core/app/variable/select.svg'),
'core/app/variable/textarea': () => import('./icons/core/app/variable/textarea.svg'),
'core/chat/QGFill': () => import('./icons/core/chat/QGFill.svg'),
'core/chat/backText': () => import('./icons/core/chat/backText.svg'),
'core/chat/cancelSpeak': () => import('./icons/core/chat/cancelSpeak.svg'),
'core/chat/chatFill': () => import('./icons/core/chat/chatFill.svg'),
@ -196,15 +198,19 @@ export const iconPaths = {
'core/chat/fileSelect': () => import('./icons/core/chat/fileSelect.svg'),
'core/chat/finishSpeak': () => import('./icons/core/chat/finishSpeak.svg'),
'core/chat/imgSelect': () => import('./icons/core/chat/imgSelect.svg'),
'core/chat/QGFill': () => import('./icons/core/chat/QGFill.svg'),
'core/chat/quoteFill': () => import('./icons/core/chat/quoteFill.svg'),
'core/chat/quoteSign': () => import('./icons/core/chat/quoteSign.svg'),
'core/chat/recordFill': () => import('./icons/core/chat/recordFill.svg'),
'core/chat/sendFill': () => import('./icons/core/chat/sendFill.svg'),
'core/chat/sendLight': () => import('./icons/core/chat/sendLight.svg'),
'core/chat/setTopLight': () => import('./icons/core/chat/setTopLight.svg'),
'core/chat/setting/share': () => import('./icons/core/chat/setting/share.svg'),
'core/chat/sideLine': () => import('./icons/core/chat/sideLine.svg'),
'core/chat/sidebar/expand': () => import('./icons/core/chat/sidebar/expand.svg'),
'core/chat/sidebar/fold': () => import('./icons/core/chat/sidebar/fold.svg'),
'core/chat/sidebar/home': () => import('./icons/core/chat/sidebar/home.svg'),
'core/chat/sidebar/logout': () => import('./icons/core/chat/sidebar/logout.svg'),
'core/chat/sidebar/menu': () => import('./icons/core/chat/sidebar/menu.svg'),
'core/chat/speaking': () => import('./icons/core/chat/speaking.svg'),
'core/chat/stopSpeech': () => import('./icons/core/chat/stopSpeech.svg'),
'core/chat/think': () => import('./icons/core/chat/think.svg'),
@ -285,12 +291,13 @@ export const iconPaths = {
'core/workflow/redo': () => import('./icons/core/workflow/redo.svg'),
'core/workflow/revertVersion': () => import('./icons/core/workflow/revertVersion.svg'),
'core/workflow/runError': () => import('./icons/core/workflow/runError.svg'),
'core/workflow/running': () => import('./icons/core/workflow/running.svg'),
'core/workflow/runSkip': () => import('./icons/core/workflow/runSkip.svg'),
'core/workflow/runSuccess': () => import('./icons/core/workflow/runSuccess.svg'),
'core/workflow/running': () => import('./icons/core/workflow/running.svg'),
'core/workflow/template/BI': () => import('./icons/core/workflow/template/BI.svg'),
'core/workflow/template/FileRead': () => import('./icons/core/workflow/template/FileRead.svg'),
'core/workflow/template/aiChat': () => import('./icons/core/workflow/template/aiChat.svg'),
'core/workflow/template/baseChart': () => import('./icons/core/workflow/template/baseChart.svg'),
'core/workflow/template/BI': () => import('./icons/core/workflow/template/BI.svg'),
'core/workflow/template/bing': () => import('./icons/core/workflow/template/bing.svg'),
'core/workflow/template/bocha': () => import('./icons/core/workflow/template/bocha.svg'),
'core/workflow/template/codeRun': () => import('./icons/core/workflow/template/codeRun.svg'),
@ -307,7 +314,6 @@ export const iconPaths = {
'core/workflow/template/extractJson': () =>
import('./icons/core/workflow/template/extractJson.svg'),
'core/workflow/template/fetchUrl': () => import('./icons/core/workflow/template/fetchUrl.svg'),
'core/workflow/template/FileRead': () => import('./icons/core/workflow/template/FileRead.svg'),
'core/workflow/template/formInput': () => import('./icons/core/workflow/template/formInput.svg'),
'core/workflow/template/getTime': () => import('./icons/core/workflow/template/getTime.svg'),
'core/workflow/template/google': () => import('./icons/core/workflow/template/google.svg'),
@ -337,12 +343,12 @@ export const iconPaths = {
'core/workflow/template/textConcat': () =>
import('./icons/core/workflow/template/textConcat.svg'),
'core/workflow/template/toolCall': () => import('./icons/core/workflow/template/toolCall.svg'),
'core/workflow/template/toolParams': () =>
import('./icons/core/workflow/template/toolParams.svg'),
'core/workflow/template/toolkitActive': () =>
import('./icons/core/workflow/template/toolkitActive.svg'),
'core/workflow/template/toolkitInactive': () =>
import('./icons/core/workflow/template/toolkitInactive.svg'),
'core/workflow/template/toolParams': () =>
import('./icons/core/workflow/template/toolParams.svg'),
'core/workflow/template/userSelect': () =>
import('./icons/core/workflow/template/userSelect.svg'),
'core/workflow/template/variable': () => import('./icons/core/workflow/template/variable.svg'),
@ -387,6 +393,7 @@ export const iconPaths = {
history: () => import('./icons/history.svg'),
image: () => import('./icons/image.svg'),
infoRounded: () => import('./icons/infoRounded.svg'),
invisible: () => import('./icons/invisible.svg'),
kbTest: () => import('./icons/kbTest.svg'),
key: () => import('./icons/key.svg'),
keyPrimary: () => import('./icons/keyPrimary.svg'),
@ -403,15 +410,17 @@ export const iconPaths = {
'modal/selectSource': () => import('./icons/modal/selectSource.svg'),
'modal/setting': () => import('./icons/modal/setting.svg'),
'modal/teamPlans': () => import('./icons/modal/teamPlans.svg'),
'model/BAAI': () => import('./icons/model/BAAI.svg'),
'model/ai360': () => import('./icons/model/ai360.svg'),
'model/alicloud': () => import('./icons/model/alicloud.svg'),
'model/aws': () => import('./icons/model/aws.svg'),
'model/azure': () => import('./icons/model/azure.svg'),
'model/BAAI': () => import('./icons/model/BAAI.svg'),
'model/baichuan': () => import('./icons/model/baichuan.svg'),
'model/chatglm': () => import('./icons/model/chatglm.svg'),
'model/claude': () => import('./icons/model/claude.svg'),
'model/cloudflare': () => import('./icons/model/cloudflare.svg'),
'model/cohere': () => import('./icons/model/cohere.svg'),
'model/coze': () => import('./icons/model/coze.svg'),
'model/deepseek': () => import('./icons/model/deepseek.svg'),
'model/doubao': () => import('./icons/model/doubao.svg'),
'model/ernie': () => import('./icons/model/ernie.svg'),
@ -428,13 +437,16 @@ export const iconPaths = {
'model/mistral': () => import('./icons/model/mistral.svg'),
'model/moka': () => import('./icons/model/moka.svg'),
'model/moonshot': () => import('./icons/model/moonshot.svg'),
'model/novita': () => import('./icons/model/novita.svg'),
'model/ollama': () => import('./icons/model/ollama.svg'),
'model/openai': () => import('./icons/model/openai.svg'),
'model/openrouter': () => import('./icons/model/openrouter.svg'),
'model/ppio': () => import('./icons/model/ppio.svg'),
'model/qwen': () => import('./icons/model/qwen.svg'),
'model/siliconflow': () => import('./icons/model/siliconflow.svg'),
'model/sparkDesk': () => import('./icons/model/sparkDesk.svg'),
'model/stepfun': () => import('./icons/model/stepfun.svg'),
'model/vertexai': () => import('./icons/model/vertexai.svg'),
'model/yi': () => import('./icons/model/yi.svg'),
more: () => import('./icons/more.svg'),
moreLine: () => import('./icons/moreLine.svg'),
@ -455,6 +467,7 @@ export const iconPaths = {
'price/right': () => import('./icons/price/right.svg'),
save: () => import('./icons/save.svg'),
sliderTag: () => import('./icons/sliderTag.svg'),
star: () => import('./icons/star.svg'),
stop: () => import('./icons/stop.svg'),
'support/account/coupon': () => import('./icons/support/account/coupon.svg'),
'support/account/laf': () => import('./icons/support/account/laf.svg'),
@ -485,8 +498,8 @@ export const iconPaths = {
'support/user/usersLight': () => import('./icons/support/user/usersLight.svg'),
text: () => import('./icons/text.svg'),
union: () => import('./icons/union.svg'),
upload: () => import('./icons/upload.svg'),
user: () => import('./icons/user.svg'),
visible: () => import('./icons/visible.svg'),
invisible: () => import('./icons/invisible.svg'),
wx: () => import('./icons/wx.svg')
};

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path d="M2.9584 3.12996C2.9584 2.66973 2.58531 2.29663 2.12507 2.29663C1.66483 2.29663 1.29174 2.66973 1.29174 3.12996L1.29174 15.5642C1.29171 15.7738 1.29168 15.9802 1.30671 16.1554C1.32334 16.3492 1.36277 16.5786 1.48565 16.8082C1.65503 17.1248 1.92112 17.3748 2.23901 17.529C2.46599 17.6392 2.69137 17.6745 2.88572 17.6896C3.06445 17.7035 3.27645 17.7035 3.49883 17.7035L17.875 17.7035C18.3352 17.7035 18.7083 17.3304 18.7083 16.8701C18.7083 16.4099 18.3352 16.0368 17.875 16.0368H3.52506C3.26694 16.0368 3.12109 16.0362 3.01502 16.028C2.99523 16.0264 2.97985 16.0248 2.96822 16.0233L2.96728 16.0129C2.95912 15.9178 2.9584 15.7846 2.9584 15.5368V3.12996Z"/>
<path d="M16.9187 5.51055C16.5893 5.20192 16.0721 5.21876 15.7634 5.54816L12.6451 8.87638L10.0927 7.55107L10.0622 7.53492C9.95289 7.47653 9.72586 7.35527 9.47286 7.33247C9.26053 7.31334 9.04688 7.34991 8.853 7.43856C8.622 7.54419 8.44823 7.73404 8.36455 7.82547L8.34115 7.85086L5.13814 11.2695C4.82951 11.5989 4.84635 12.1161 5.17575 12.4247C5.50516 12.7334 6.02239 12.7165 6.33102 12.3871L9.44934 9.0589L12.0018 10.3842L12.0322 10.4004C12.1416 10.4588 12.3686 10.58 12.6216 10.6028C12.8339 10.622 13.0476 10.5854 13.2414 10.4967C13.4725 10.3911 13.6462 10.2012 13.7299 10.1098L13.7533 10.0844L16.9563 6.66581C17.2649 6.33641 17.2481 5.81918 16.9187 5.51055Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.72906 1.85097L6.69706 1.85085C5.98971 1.84827 5.41291 1.84617 4.94529 1.88309C4.46218 1.92122 4.0274 2.00464 3.62397 2.21292C3.01771 2.52591 2.5262 3.01564 2.21101 3.62075C2.00144 4.02311 1.91634 4.45656 1.8764 4.93842C1.83778 5.40451 1.83778 5.97916 1.83779 6.68347V11.3274C1.83778 12.0263 1.83778 12.5969 1.87625 13.0602C1.91606 13.5396 2.0009 13.9708 2.20933 14.3721C2.52242 14.9748 3.01385 15.4662 3.61658 15.7793C4.01781 15.9877 4.44906 16.0726 4.92841 16.1124C5.39173 16.1509 5.96238 16.1508 6.66127 16.1508H11.3383C12.0372 16.1508 12.6078 16.1509 13.0711 16.1124C13.5505 16.0726 13.9817 15.9877 14.383 15.7793C14.9857 15.4662 15.4771 14.9748 15.7902 14.3721C15.9986 13.9708 16.0835 13.5396 16.1233 13.0602C16.1618 12.5969 16.1618 12.0263 16.1618 11.3274V9.50554C16.1618 9.09133 15.826 8.75554 15.4118 8.75554C14.9975 8.75554 14.6618 9.09133 14.6618 9.50554V11.2954C14.6618 12.0341 14.6612 12.5422 14.6284 12.9361C14.5965 13.321 14.5378 13.5291 14.4591 13.6806C14.2883 14.0094 14.0203 14.2774 13.6915 14.4482C13.5401 14.5269 13.3319 14.5856 12.947 14.6175C12.5531 14.6502 12.0449 14.6508 11.3063 14.6508H6.69329C5.9546 14.6508 5.44645 14.6502 5.05255 14.6175C4.66763 14.5856 4.45948 14.5269 4.30804 14.4482C3.97928 14.2774 3.71122 14.0094 3.54045 13.6806C3.46178 13.5291 3.40307 13.321 3.37111 12.9361C3.33839 12.5422 3.33779 12.034 3.33779 11.2953V6.71554C3.33779 5.97142 3.33839 5.45912 3.37128 5.06231C3.40345 4.67419 3.46254 4.46502 3.54137 4.31369C3.7136 3.98302 3.98078 3.71681 4.31207 3.54578C4.46337 3.46767 4.67323 3.40923 5.06333 3.37843C5.46189 3.34697 5.97654 3.34825 6.72362 3.35096C7.34582 3.35322 7.97156 3.35468 8.54741 3.35468C8.96163 3.35468 9.29741 3.0189 9.29741 2.60468C9.29741 2.19047 8.96163 1.85468 8.54741 1.85468C7.97394 1.85468 7.35012 1.85322 6.72906 1.85097ZM8.26244 8.66554C7.96954 8.95843 7.96954 9.4333 8.26244 9.7262C8.55533 10.0191 9.0302 10.0191 9.3231 9.72619L14.6618 4.38754V6.5054C14.6618 6.91962 14.9975 7.2554 15.4118 7.2554C15.826 7.2554 16.1618 6.91962 16.1618 6.5054V2.6698C16.1621 2.66102 16.1622 2.6522 16.1622 2.64334C16.1622 2.22913 15.8264 1.89334 15.4122 1.89334C15.4121 1.89334 15.4123 1.89334 15.4122 1.89334H11.5502C11.1359 1.89334 10.8002 2.22913 10.8002 2.64334C10.8002 3.05756 11.1359 3.39334 11.5502 3.39334H13.5346L8.26244 8.66554Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,4 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M10.167 8.77246C10.5026 8.38466 11.0886 8.34225 11.4766 8.67773L14.3096 11.127C14.559 11.3429 14.6642 11.6629 14.6191 11.9668C14.6208 12.2196 14.5221 12.4726 14.3223 12.6582L11.5889 15.1924C11.2107 15.543 10.6194 15.5214 10.2686 15.1436C9.91784 14.7654 9.94039 14.1741 10.3184 13.8232L12.3779 11.9121L10.2617 10.083C9.87373 9.74748 9.83152 9.16048 10.167 8.77246Z" fill="#667085"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.8086 2.53027C19.9789 2.6909 22.5 5.31226 22.5 8.52246V15.4785L22.4922 15.7871C22.3366 18.855 19.8766 21.3153 16.8086 21.4707L16.5 21.4785H7.5L7.19141 21.4707C4.12345 21.3153 1.66343 18.855 1.50781 15.7871L1.5 15.4785V8.52246C1.5 5.31226 4.02112 2.6909 7.19141 2.53027L7.5 2.52148H16.5L16.8086 2.53027ZM8.31055 19.4785H16.5C18.709 19.4785 20.4997 17.6874 20.5 15.4785V8.52246C20.5 6.31332 18.7091 4.52246 16.5 4.52246H8.31055V19.4785ZM6.4707 4.65625C4.82412 5.0935 3.59428 6.5545 3.50488 8.31641L3.5 8.52246V15.4785C3.50022 17.3315 4.76059 18.8896 6.4707 19.3438V4.65625Z" fill="#667085"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.9123 7.23183C11.2356 6.95242 11.724 6.98761 12.0036 7.31077C12.2829 7.63412 12.2479 8.12337 11.9246 8.40289L10.1611 9.92796L11.8774 11.5198C12.192 11.8122 12.2103 12.305 11.9181 12.62C11.6259 12.9347 11.1339 12.9531 10.8187 12.6615L8.54085 10.5497C8.37406 10.395 8.29205 10.1836 8.29346 9.97272C8.2559 9.7194 8.34339 9.45276 8.55143 9.27285L10.9123 7.23183Z" fill="#667085"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.0072 2.10813C16.6489 2.24207 18.7498 4.42667 18.75 7.10162V12.8983L18.7435 13.1555C18.614 15.7122 16.5638 17.7622 14.0072 17.8918L13.75 17.8983H6.25L5.99284 17.8918C3.43607 17.7623 1.38599 15.7123 1.25651 13.1555L1.25 12.8983V7.10162C1.25019 4.42661 3.35104 2.24198 5.99284 2.10813L6.25 2.10162H13.75L14.0072 2.10813ZM6.92546 16.2317H13.75C15.5909 16.2316 17.0833 14.7392 17.0833 12.8983V7.10162C17.0831 5.26091 15.5907 3.7684 13.75 3.76829H6.92546V16.2317ZM5.39225 3.87978C4.02015 4.24418 2.99539 5.46178 2.92074 6.92991L2.91667 7.10162V12.8983C2.91667 14.4426 3.96708 15.7408 5.39225 16.1194V3.87978Z" fill="#667085"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,6 @@
<svg width="20" height="20" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M7.42432 9.62695C8.12696 9.62697 8.69653 10.1968 8.69678 10.8994C8.69678 11.6022 8.12711 12.1719 7.42432 12.1719C6.72151 12.1719 6.15186 11.6022 6.15186 10.8994C6.1521 10.1968 6.72166 9.62695 7.42432 9.62695Z" />
<path d="M12.0005 9.62695C12.7031 9.62697 13.2727 10.1968 13.2729 10.8994C13.2729 11.6022 12.7033 12.1719 12.0005 12.1719C11.2977 12.1719 10.728 11.6022 10.728 10.8994C10.7283 10.1968 11.2978 9.62695 12.0005 9.62695Z" />
<path d="M16.5767 9.62695C17.2793 9.62704 17.8489 10.1969 17.8491 10.8994C17.8491 11.6022 17.2794 12.1718 16.5767 12.1719C15.8738 12.1719 15.3042 11.6022 15.3042 10.8994C15.3044 10.1968 15.874 9.62695 16.5767 9.62695Z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.5005 2.42969C19.814 2.42995 22.5005 5.11614 22.5005 8.42969V13.3711C22.5002 16.6845 19.813 19.3711 16.4995 19.3711H11.939C11.7612 19.3711 11.5865 19.4189 11.4331 19.5088L8.19678 21.4053C7.56444 21.7758 6.74974 21.4982 6.47607 20.8184L5.97607 19.5732C5.86216 19.2897 5.62243 19.0779 5.3374 18.9678C3.09265 18.1 1.49977 15.9219 1.49951 13.3711V8.42969C1.49951 5.11598 4.18678 2.42969 7.50049 2.42969H16.5005ZM7.50049 4.42969C5.29093 4.42969 3.49951 6.22097 3.49951 8.42969V13.3711C3.49976 15.0681 4.55902 16.5233 6.05713 17.1025L6.36279 17.2061L6.82666 17.3428C7.11977 17.4296 7.35739 17.646 7.47119 17.9297L7.65088 18.3789C7.82678 18.8166 8.35027 18.9952 8.75732 18.7568L10.8901 17.5078C11.0434 17.4181 11.2184 17.3711 11.396 17.3711H16.4995C18.6396 17.3711 20.388 15.69 20.4956 13.5771L20.5005 13.3711V8.42969C20.5005 6.29002 18.8199 4.54206 16.7065 4.43457L16.5005 4.42969H7.50049Z" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 6C2 5.44772 2.44772 5 3 5H21C21.5523 5 22 5.44772 22 6C22 6.55228 21.5523 7 21 7H3C2.44772 7 2 6.55228 2 6ZM2 12C2 11.4477 2.44772 11 3 11H21C21.5523 11 22 11.4477 22 12C22 12.5523 21.5523 13 21 13H3C2.44772 13 2 12.5523 2 12ZM2 18C2 17.4477 2.44772 17 3 17H21C21.5523 17 22 17.4477 22 18C22 18.5523 21.5523 19 21 19H3C2.44772 19 2 18.5523 2 18Z" />
</svg>

After

Width:  |  Height:  |  Size: 470 B

View File

@ -0,0 +1 @@
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>AI360</title><path clip-rule="evenodd" d="M12 0h.018c1.473-.002 2.88.261 4.179.754C20.755 2.456 24 6.85 24 12c0 6.627-5.373 12-12 12S0 18.627 0 12 5.373 0 12 0zm8.604 18.967A11.024 11.024 0 0023.07 12c0-1.717-.39-3.344-1.089-4.794a2.59 2.59 0 01-3.214.62 6.278 6.278 0 01-1.333-.992C16.283 5.73 15.109 4.66 13.696 3.9c-3.211-1.729-6.825-1.501-9.695.447A11.033 11.033 0 00.93 12c0 1.663.367 3.241 1.024 4.657.75-.973 2.131-1.346 3.232-.71.667.384 1.257.92 1.837 1.447l.176.16c1.365 1.234 2.794 2.355 4.558 2.965 3.053 1.053 6.356.437 8.847-1.552z" fill="url(#lobe-icons-ai360-fill-0)" fill-rule="evenodd"></path><path d="M5.643 10.312c-.83.11-1.401.766-1.408 1.618a1.715 1.715 0 001.45 1.72c.805.128 1.64-.426 1.87-1.26.046-.167.076-.338.106-.51.025-.14.05-.282.084-.42.318-1.317 1.237-1.95 2.788-1.93 1.086.013 1.318.271 1.68 1.855.017.076.043.151.07.226.26.714.976 1.17 1.67 1.065a1.647 1.647 0 001.38-1.438c.083-.729-.348-1.264-1.122-1.575-.34-.136-.664-.158-.995-.141-.726.037-1.121-.36-1.339-.977a3.359 3.359 0 01-.134-.65c-.014-.093-.027-.186-.043-.278-.156-.887-.835-1.51-1.669-1.532-.791-.02-1.464.551-1.665 1.418l-.06.27-.025.117c-.355 1.636-.974 2.205-2.638 2.422z" fill="url(#lobe-icons-ai360-fill-1)"></path><path d="M18.059 13.644c.989-.206 1.577-.838 1.592-1.697.015-.83-.624-1.582-1.46-1.724-.77-.13-1.599.383-1.844 1.18-.069.22-.117.448-.165.676-.06.29-.122.58-.225.854-.367.986-1.593 1.546-2.926 1.394-.824-.095-1.106-.446-1.342-1.674-.18-.938-.864-1.535-1.681-1.467-.85.07-1.515.829-1.468 1.673.05.892.678 1.44 1.705 1.489 1.375.064 1.75.396 1.926 1.787.067.531.267.967.685 1.288 1.02.783 2.407.208 2.66-1.108l.022-.114c.152-.796.3-1.577 1.04-2.101.36-.255.761-.326 1.166-.397.105-.019.21-.037.315-.06z" fill="url(#lobe-icons-ai360-fill-2)"></path><path d="M13.83 7.961a.755.755 0 11-1.51 0 .755.755 0 011.51 0z" fill="url(#lobe-icons-ai360-fill-3)"></path><path d="M10.809 16.678a.755.755 0 100-1.511.755.755 0 000 1.51z" fill="url(#lobe-icons-ai360-fill-4)"></path><defs><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-ai360-fill-0" x1="12" x2="12" y1="0" y2="24"><stop stop-color="#12B7FA"></stop><stop offset="1" stop-color="#006ffb"></stop></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-ai360-fill-1" x1="11.943" x2="11.943" y1="6.085" y2="17.778"><stop stop-color="#006ffb"></stop><stop offset="1" stop-color="#12B7FA"></stop></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-ai360-fill-2" x1="11.943" x2="11.943" y1="6.085" y2="17.778"><stop stop-color="#006ffb"></stop><stop offset="1" stop-color="#12B7FA"></stop></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-ai360-fill-3" x1="11.943" x2="11.943" y1="6.085" y2="17.778"><stop stop-color="#006ffb"></stop><stop offset="1" stop-color="#12B7FA"></stop></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-ai360-fill-4" x1="11.943" x2="11.943" y1="6.085" y2="17.778"><stop stop-color="#006ffb"></stop><stop offset="1" stop-color="#12B7FA"></stop></linearGradient></defs></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1 @@
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Coze</title><path clip-rule="evenodd" d="M3.908 9.096A8.092 8.092 0 0111.998 1h.006c4.468 0 8.09 3.628 8.09 8.096v3.392h1.942c2.23 0 2.732 3.126.615 3.828l-2.556.85v1.466a1.947 1.947 0 01-2.818 1.742l-1.42-.707c-.067-.03-.149 0-.17.071-1.147 3.587-6.225 3.587-7.373 0a.123.123 0 00-.169-.07l-1.42.706c-1.29.65-2.817-.292-2.817-1.742v-1.466l-2.557-.85c-2.122-.697-1.614-3.828.615-3.828h1.942V9.096zm4.571 2.613a.784.784 0 00-.784.784v1.568a.784.784 0 101.568 0v-1.568a.784.784 0 00-.784-.784zm7.045.779a.784.784 0 100 1.568.784.784 0 000-1.568zm-6.186 3.415a.78.78 0 00.17.254 3.517 3.517 0 004.98 0 .782.782 0 10-1.106-1.107 1.958 1.958 0 01-2.767 0 .78.78 0 00-1.277.254.78.78 0 000 .6z"></path></svg>

After

Width:  |  Height:  |  Size: 866 B

View File

@ -0,0 +1 @@
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Novita AI</title><path clip-rule="evenodd" d="M9.167 4.17v5.665L0 19.003h9.167v-5.666l5.666 5.666H24L9.167 4.17z" fill="#23D57C" fill-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 286 B

View File

@ -0,0 +1 @@
<svg width="100%" height="100%" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" class="size-4" fill="currentColor" stroke="currentColor" aria-label="Logo"><g clip-path="url(#clip0_205_3)"><path d="M3 248.945C18 248.945 76 236 106 219C136 202 136 202 198 158C276.497 102.293 332 120.945 423 120.945" stroke-width="90"></path><path d="M511 121.5L357.25 210.268L357.25 32.7324L511 121.5Z"></path><path d="M0 249C15 249 73 261.945 103 278.945C133 295.945 133 295.945 195 339.945C273.497 395.652 329 377 420 377" stroke-width="90"></path><path d="M508 376.445L354.25 287.678L354.25 465.213L508 376.445Z"></path></g><title style="display:none">OpenRouter</title><defs><clipPath id="clip0_205_3"><rect width="512" height="512" fill="white"></rect></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 773 B

View File

@ -0,0 +1 @@
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>VertexAI</title><path d="M11.995 20.216a1.892 1.892 0 100 3.785 1.892 1.892 0 000-3.785zm0 2.806a.927.927 0 11.927-.914.914.914 0 01-.927.914z" fill="#4285F4"></path><path clip-rule="evenodd" d="M21.687 14.144c.237.038.452.16.605.344a.978.978 0 01-.18 1.3l-8.24 6.082a1.892 1.892 0 00-1.147-1.508l8.28-6.08a.991.991 0 01.682-.138z" fill="#669DF6" fill-rule="evenodd"></path><path clip-rule="evenodd" d="M10.122 21.842l-8.217-6.066a.952.952 0 01-.206-1.287.978.978 0 011.287-.206l8.28 6.08a1.893 1.893 0 00-1.144 1.479z" fill="#AECBFA" fill-rule="evenodd"></path><path d="M4.273 4.475a.978.978 0 01-.965-.965V1.09a.978.978 0 111.943 0v2.42a.978.978 0 01-.978.965zM4.247 13.034a.978.978 0 100-1.956.978.978 0 000 1.956zM4.247 10.19a.978.978 0 100-1.956.978.978 0 000 1.956zM4.247 7.332a.978.978 0 100-1.956.978.978 0 000 1.956z" fill="#AECBFA"></path><path d="M19.718 7.307a.978.978 0 01-.965-.979v-2.42a.965.965 0 011.93 0v2.42a.964.964 0 01-.965.979zM19.743 13.047a.978.978 0 100-1.956.978.978 0 000 1.956zM19.743 10.151a.978.978 0 100-1.956.978.978 0 000 1.956zM19.743 2.068a.978.978 0 100-1.956.978.978 0 000 1.956z" fill="#4285F4"></path><path d="M11.995 15.917a.978.978 0 01-.965-.965v-2.459a.978.978 0 011.943 0v2.433a.976.976 0 01-.978.991zM11.995 18.762a.978.978 0 100-1.956.978.978 0 000 1.956zM11.995 10.64a.978.978 0 100-1.956.978.978 0 000 1.956zM11.995 7.783a.978.978 0 100-1.956.978.978 0 000 1.956z" fill="#669DF6"></path><path d="M15.856 10.177a.978.978 0 01-.965-.965v-2.42a.977.977 0 011.702-.763.979.979 0 01.241.763v2.42a.978.978 0 01-.978.965zM15.869 4.913a.978.978 0 100-1.956.978.978 0 000 1.956zM15.869 15.853a.978.978 0 100-1.956.978.978 0 000 1.956zM15.869 12.996a.978.978 0 100-1.956.978.978 0 000 1.956z" fill="#4285F4"></path><path d="M8.121 15.853a.978.978 0 100-1.956.978.978 0 000 1.956zM8.121 7.783a.978.978 0 100-1.956.978.978 0 000 1.956zM8.121 4.913a.978.978 0 100-1.957.978.978 0 000 1.957zM8.134 12.996a.978.978 0 01-.978-.94V9.611a.965.965 0 011.93 0v2.445a.966.966 0 01-.952.94z" fill="#AECBFA"></path></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.7185 4.26976C16.312 2.62616 18.6365 2.62614 19.23 4.26976L21.8714 11.5851L29.1468 14.247C30.7805 14.8447 30.7805 17.1553 29.1468 17.753L21.8714 20.4149L19.23 27.7302C18.6365 29.3738 16.312 29.3739 15.7185 27.7302L13.0771 20.4149L5.80169 17.753C4.168 17.1553 4.16799 14.8447 5.80169 14.247L13.0771 11.5851L15.7185 4.26976ZM17.4742 7.25928L15.4584 12.842C15.2708 13.3615 14.8628 13.7712 14.3441 13.961L8.77134 16L14.3441 18.039C14.8628 18.2288 15.2708 18.6385 15.4584 19.158L17.4742 24.7407L19.4901 19.158C19.6776 18.6385 20.0857 18.2288 20.6044 18.039L26.1771 16L20.6044 13.961C20.0857 13.7712 19.6776 13.3615 19.4901 12.842L17.4742 7.25928Z" fill="url(#paint0_linear_24949_213)"/>
<path d="M5.59038 3.55591C5.7622 3.09158 6.41894 3.09158 6.59075 3.55591L7.12584 5.00195C7.17985 5.14793 7.29495 5.26303 7.44094 5.31705L8.88697 5.85213C9.3513 6.02395 9.3513 6.68069 8.88697 6.8525L7.44094 7.38759C7.29495 7.4416 7.17985 7.5567 7.12584 7.70269L6.59075 9.14872C6.41894 9.61305 5.7622 9.61305 5.59038 9.14872L5.0553 7.70269C5.00128 7.5567 4.88618 7.44161 4.7402 7.38759L3.29416 6.8525C2.82983 6.68069 2.82983 6.02395 3.29416 5.85213L4.7402 5.31705C4.88618 5.26303 5.00128 5.14793 5.0553 5.00195L5.59038 3.55591Z" fill="url(#paint1_linear_24949_213)"/>
<path d="M5.59038 22.5037C5.7622 22.0394 6.41894 22.0394 6.59075 22.5037L7.12584 23.9498C7.17985 24.0957 7.29495 24.2108 7.44094 24.2649L8.88697 24.7999C9.3513 24.9718 9.3513 25.6285 8.88697 25.8003L7.44094 26.3354C7.29495 26.3894 7.17985 26.5045 7.12584 26.6505L6.59075 28.0965C6.41894 28.5609 5.7622 28.5609 5.59038 28.0965L5.0553 26.6505C5.00128 26.5045 4.88618 26.3894 4.7402 26.3354L3.29416 25.8003C2.82983 25.6285 2.82983 24.9718 3.29416 24.7999L4.7402 24.2649C4.88618 24.2108 5.00128 24.0957 5.0553 23.9498L5.59038 22.5037Z" fill="url(#paint2_linear_24949_213)"/>
<defs>
<linearGradient id="paint0_linear_24949_213" x1="16.659" y1="3.8788" x2="16.659" y2="28.1212" gradientUnits="userSpaceOnUse">
<stop stop-color="#499DFF"/>
<stop offset="0.432292" stop-color="#2770FF"/>
<stop offset="1" stop-color="#6E80FF"/>
</linearGradient>
<linearGradient id="paint1_linear_24949_213" x1="16.659" y1="3.8788" x2="16.659" y2="28.1212" gradientUnits="userSpaceOnUse">
<stop stop-color="#499DFF"/>
<stop offset="0.432292" stop-color="#2770FF"/>
<stop offset="1" stop-color="#6E80FF"/>
</linearGradient>
<linearGradient id="paint2_linear_24949_213" x1="16.659" y1="3.8788" x2="16.659" y2="28.1212" gradientUnits="userSpaceOnUse">
<stop stop-color="#499DFF"/>
<stop offset="0.432292" stop-color="#2770FF"/>
<stop offset="1" stop-color="#6E80FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,3 @@
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.8339 2.58684C12.2244 2.19631 12.8576 2.19631 13.2481 2.58684L17.2481 6.58684C17.6386 6.97736 17.6386 7.61053 17.2481 8.00105C16.8576 8.39158 16.2244 8.39158 15.8339 8.00105L13.541 5.70816V15.2939C13.541 15.8462 13.0933 16.2939 12.541 16.2939C11.9887 16.2939 11.541 15.8462 11.541 15.2939V5.70816L9.24812 8.00105C8.8576 8.39158 8.22443 8.39158 7.83391 8.00105C7.44339 7.61053 7.44339 6.97736 7.83391 6.58684L11.8339 2.58684ZM3.54102 11.2939C4.0933 11.2939 4.54102 11.7417 4.54102 12.2939V16.4939C4.54102 17.3505 4.54179 17.9328 4.57857 18.3829C4.61439 18.8213 4.67931 19.0455 4.759 19.2019C4.95075 19.5783 5.25671 19.8842 5.63303 20.076C5.78944 20.1556 6.01364 20.2206 6.45205 20.2564C6.90214 20.2932 7.48444 20.2939 8.34102 20.2939H16.741C17.5976 20.2939 18.1799 20.2932 18.63 20.2564C19.0684 20.2206 19.2926 20.1556 19.449 20.076C19.8253 19.8842 20.1313 19.5783 20.323 19.2019C20.4027 19.0455 20.4676 18.8213 20.5035 18.3829C20.5402 17.9328 20.541 17.3505 20.541 16.4939V12.2939C20.541 11.7417 20.9887 11.2939 21.541 11.2939C22.0933 11.2939 22.541 11.7417 22.541 12.2939V16.5353C22.541 17.3402 22.541 18.0046 22.4968 18.5458C22.4509 19.1079 22.3523 19.6246 22.105 20.1099C21.7215 20.8626 21.1096 21.4745 20.357 21.858C19.8716 22.1053 19.3549 22.2038 18.7928 22.2498C18.2517 22.294 17.5873 22.294 16.7823 22.2939H8.29969C7.49473 22.294 6.83038 22.294 6.28919 22.2498C5.72709 22.2038 5.21039 22.1053 4.72506 21.858C3.97241 21.4745 3.36048 20.8626 2.97699 20.1099C2.7297 19.6246 2.63114 19.1079 2.58521 18.5458C2.54099 18.0046 2.541 17.3402 2.54102 16.5352L2.54102 12.2939C2.54102 11.7417 2.98873 11.2939 3.54102 11.2939Z" fill="#3370FF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -55,7 +55,7 @@ const MyNumberInput = (props: Props) => {
}
}}
onChange={(e) => {
const numE = e === '' ? '' : e.endsWith('.') ? e : Number(e);
const numE = e === '' ? '' : e.endsWith('.') || /^\d+\.0+$/.test(e) ? e : Number(e);
if (onChange) {
if (numE === '') {
// @ts-ignore

View File

@ -23,6 +23,7 @@ export interface MyModalProps extends ModalContentProps {
onClose?: () => void;
closeOnOverlayClick?: boolean;
size?: 'md' | 'lg';
showCloseButton?: boolean;
}
const MyModal = ({
@ -38,6 +39,7 @@ const MyModal = ({
closeOnOverlayClick = true,
iconColor,
size = 'md',
showCloseButton = true,
...props
}: MyModalProps) => {
const { isPc } = useSystem();
@ -65,7 +67,7 @@ const MyModal = ({
boxShadow={'7'}
{...props}
>
{!title && onClose && <ModalCloseButton zIndex={1} />}
{!title && onClose && showCloseButton && <ModalCloseButton zIndex={1} />}
{!!title && (
<ModalHeader
display={'flex'}

View File

@ -162,7 +162,8 @@ const MySelect = <T = any,>(
: {
color: 'myGray.900'
})}
onClick={() => {
onClick={(e) => {
e.stopPropagation();
if (value !== item.value) {
onClickChange(item.value);
}
@ -172,7 +173,7 @@ const MySelect = <T = any,>(
display={'block'}
mb={0.5}
>
<Flex alignItems={'center'} fontWeight={value === item.value ? '600' : 'normal'}>
<Flex alignItems={'center'}>
{item.icon && (
<Avatar mr={2} src={item.icon as any} w={item.iconSize ?? '1rem'} />
)}
@ -303,6 +304,9 @@ const MySelect = <T = any,>(
zIndex={99}
maxH={'45vh'}
overflowY={'auto'}
onClick={(e) => {
e.stopPropagation();
}}
>
{ScrollData ? <ScrollData>{ListRender}</ScrollData> : ListRender}
</MenuList>

View File

@ -0,0 +1,226 @@
import React, { useCallback, useMemo, useState } from 'react';
import { Box, HStack, useTheme } from '@chakra-ui/react';
import {
ResponsiveContainer,
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
type TooltipProps
} from 'recharts';
import { type NameType, type ValueType } from 'recharts/types/component/DefaultTooltipContent';
import { formatNumber } from '@fastgpt/global/common/math/tools';
import FillRowTabs from '../Tabs/FillRowTabs';
import { useTranslation } from 'next-i18next';
import { cloneDeep } from 'lodash';
type AreaConfig = {
dataKey: string;
name: string;
color: string;
gradient?: boolean;
};
type TooltipItem = {
label: string;
dataKey: string;
color: string;
formatter?: (value: number) => string;
customValue?: (data: Record<string, any>) => number;
};
type AreaChartComponentProps = {
data: Record<string, any>[];
title: string;
HeaderLeftChildren?: React.ReactNode;
lines: AreaConfig[];
tooltipItems?: TooltipItem[];
defaultDisplayMode?: 'incremental' | 'cumulative';
enableIncremental?: boolean;
enableCumulative?: boolean;
enableTooltip?: boolean;
startDateValue?: number;
};
const CustomTooltip = ({
active,
payload,
tooltipItems
}: TooltipProps<ValueType, NameType> & { tooltipItems?: TooltipItem[] }) => {
const data = payload?.[0]?.payload;
if (!active || !data || !tooltipItems) {
return null;
}
return (
<Box bg="white" p={3} borderRadius="md" border="base" boxShadow="sm">
<Box fontSize="sm" color="myGray.900" mb={2}>
{data.xLabel || data.x}
</Box>
{tooltipItems.map((item, index) => {
const value = item.customValue ? item.customValue(data) : data[item.dataKey];
const displayValue = item.formatter ? item.formatter(value) : formatNumber(value);
return (
<HStack key={index} fontSize="sm" _notLast={{ mb: 1 }}>
<Box w={2} h={2} borderRadius="full" bg={item.color} />
<Box>{item.label}</Box>
<Box>{displayValue.toLocaleString()}</Box>
</HStack>
);
})}
</Box>
);
};
const AreaChartComponent = ({
data,
title,
HeaderLeftChildren,
lines,
tooltipItems,
defaultDisplayMode = 'incremental',
enableIncremental = true,
enableCumulative = true,
startDateValue = 0
}: AreaChartComponentProps) => {
const theme = useTheme();
const { t } = useTranslation();
const [displayMode, setDisplayMode] = useState<'incremental' | 'cumulative'>(defaultDisplayMode);
// Tab list constant
const tabList = useMemo(
() => [
...(enableIncremental
? [{ label: t('common:chart_mode_incremental'), value: 'incremental' as const }]
: []),
...(enableCumulative
? [{ label: t('common:chart_mode_cumulative'), value: 'cumulative' as const }]
: [])
],
[enableCumulative, enableIncremental, t]
);
// Y-axis number formatter function
const formatYAxisNumber = useCallback((value: number): string => {
if (value >= 1000000) {
return value / 1000000 + 'M';
} else if (value >= 1000) {
return value / 1000 + 'K';
}
return value.toString();
}, []);
// Process data based on display mode
const processedData = useMemo(() => {
if (displayMode === 'incremental') {
return data;
}
// Cumulative mode: accumulate values for each line's dataKey
const cloneData = cloneDeep(data);
const dataKeys = lines.map((item) => item.dataKey);
return cloneData.map((item, index) => {
if (index === 0) {
item[dataKeys[0]] = startDateValue + item[dataKeys[0]];
return item;
}
dataKeys.forEach((key) => {
if (typeof item[key] === 'number') {
item[key] += cloneData[index - 1][key];
}
});
return item;
});
}, [displayMode, data, lines, startDateValue]);
// Generate gradient definitions
const gradientDefs = useMemo(
() => (
<defs>
{lines.map((line) => (
<linearGradient
key={`gradient-${line.color}`}
id={`gradient-${line.color}`}
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop offset="0%" stopColor={line.color} stopOpacity={0.25} />
<stop offset="100%" stopColor={line.color} stopOpacity={0.01} />
</linearGradient>
))}
</defs>
),
[lines]
);
return (
<>
<HStack mb={4} justifyContent={'space-between'} alignItems={'flex-start'}>
<Box fontSize={'sm'} color={'myGray.900'} fontWeight={'medium'}>
{title}
</Box>
<HStack spacing={2}>
{HeaderLeftChildren}
{tabList.length > 1 && (
<FillRowTabs<'incremental' | 'cumulative'>
list={tabList}
py={0.5}
px={2}
value={displayMode}
onChange={setDisplayMode}
/>
)}
</HStack>
</HStack>
<ResponsiveContainer width="100%" height={'100%'}>
<AreaChart
data={processedData}
margin={{ top: 5, right: 30, left: 0, bottom: HeaderLeftChildren ? 20 : 15 }}
>
{gradientDefs}
<XAxis
dataKey="x"
tickMargin={10}
tick={{ fontSize: '12px', color: theme?.colors?.myGray['500'], fontWeight: '500' }}
interval="preserveStartEnd"
/>
<YAxis
axisLine={false}
tickSize={0}
tickMargin={10}
tick={{ fontSize: '12px', color: theme?.colors?.myGray['500'], fontWeight: '500' }}
interval="preserveStartEnd"
tickFormatter={formatYAxisNumber}
/>
<CartesianGrid strokeDasharray="3 3" horizontal={true} vertical={false} />
{tooltipItems && <Tooltip content={<CustomTooltip tooltipItems={tooltipItems} />} />}
{lines.map((line, index) => (
<Area
key={line.dataKey}
type="monotone"
name={line.name}
dataKey={line.dataKey}
stroke={line.color}
strokeWidth={2}
fill={`url(#gradient-${line.color})`}
dot={false}
/>
))}
</AreaChart>
</ResponsiveContainer>
</>
);
};
export default AreaChartComponent;

View File

@ -0,0 +1,152 @@
import React, { useCallback, useMemo } from 'react';
import { Box, Flex, HStack, useTheme } from '@chakra-ui/react';
import {
ResponsiveContainer,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
type TooltipProps,
BarChart,
Bar
} from 'recharts';
import { type NameType, type ValueType } from 'recharts/types/component/DefaultTooltipContent';
import { formatNumber } from '@fastgpt/global/common/math/tools';
import { useTranslation } from 'next-i18next';
import QuestionTip from '../MyTooltip/QuestionTip';
type BarConfig = {
dataKey: string;
name: string;
color: string;
stackId?: string;
};
type TooltipItem = {
label: string;
dataKey: string;
color: string;
formatter?: (value: number) => string;
customValue?: (data: Record<string, any>) => number;
};
type BarChartComponentProps = {
data: Record<string, any>[];
title: string;
description?: string;
HeaderRightChildren?: React.ReactNode;
bars: BarConfig[];
tooltipItems?: TooltipItem[];
blur?: boolean;
};
const CustomTooltip = ({
active,
payload,
tooltipItems
}: TooltipProps<ValueType, NameType> & { tooltipItems?: TooltipItem[] }) => {
const data = payload?.[0]?.payload;
if (!active || !data || !tooltipItems) {
return null;
}
return (
<Box bg="white" p={3} borderRadius="md" border="base" boxShadow="sm">
<Box fontSize="sm" color="myGray.900" mb={2}>
{data.xLabel || data.x}
</Box>
{tooltipItems.map((item, index) => {
const value = item.customValue ? item.customValue(data) : data[item.dataKey];
const displayValue = item.formatter ? item.formatter(value) : formatNumber(value);
return (
<HStack key={index} fontSize="sm" _notLast={{ mb: 1 }}>
<Box w={2} h={2} borderRadius="full" bg={item.color} />
<Box>{item.label}</Box>
<Box>{displayValue.toLocaleString()}</Box>
</HStack>
);
})}
</Box>
);
};
const BarChartComponent = ({
data,
title,
description,
HeaderRightChildren,
bars,
tooltipItems,
blur = false
}: BarChartComponentProps) => {
const theme = useTheme();
const { t } = useTranslation();
// Y-axis number formatter function
const formatYAxisNumber = useCallback((value: number): string => {
if (value >= 1000000) {
return value / 1000000 + 'M';
} else if (value >= 1000) {
return value / 1000 + 'K';
}
return value.toString();
}, []);
return (
<>
<Flex mb={4} h={6}>
<Flex flex={1} alignItems={'center'} gap={1}>
<Box fontSize={'sm'} color={'myGray.900'} fontWeight={'medium'}>
{title}
</Box>
<QuestionTip label={description} />
</Flex>
<Box filter={blur ? 'blur(7.5px)' : 'none'} pointerEvents={blur ? 'none' : 'auto'}>
{HeaderRightChildren}
</Box>
</Flex>
<ResponsiveContainer
width="100%"
height={'100%'}
style={{ filter: blur ? 'blur(7.5px)' : 'none' }}
>
<BarChart
data={data}
margin={{ top: 5, right: 30, left: 0, bottom: HeaderRightChildren ? 20 : 15 }}
>
<XAxis
dataKey="x"
tickMargin={10}
tick={{ fontSize: '12px', color: theme?.colors?.myGray['500'], fontWeight: '500' }}
interval="preserveStartEnd"
/>
<YAxis
axisLine={false}
tickSize={0}
tickMargin={10}
tick={{ fontSize: '12px', color: theme?.colors?.myGray['500'], fontWeight: '500' }}
interval="preserveStartEnd"
tickFormatter={formatYAxisNumber}
/>
<CartesianGrid strokeDasharray="3 3" horizontal={true} vertical={false} />
{tooltipItems && <Tooltip content={<CustomTooltip tooltipItems={tooltipItems} />} />}
{bars.map((bar) => (
<Bar
key={bar.dataKey}
name={bar.name}
dataKey={bar.dataKey}
fill={bar.color}
stackId={bar.stackId}
radius={[2, 2, 0, 0]}
maxBarSize={30}
/>
))}
</BarChart>
</ResponsiveContainer>
</>
);
};
export default BarChartComponent;

View File

@ -1,20 +1,20 @@
import React, { useCallback, useMemo, useState } from 'react';
import { Box, HStack, useTheme } from '@chakra-ui/react';
import React, { useCallback, useMemo } from 'react';
import { Box, Flex, HStack, useTheme } from '@chakra-ui/react';
import {
ResponsiveContainer,
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
type TooltipProps
type TooltipProps,
LineChart,
Line,
ReferenceLine
} from 'recharts';
import { type NameType, type ValueType } from 'recharts/types/component/DefaultTooltipContent';
import { formatNumber } from '@fastgpt/global/common/math/tools';
import FillRowTabs from '../Tabs/FillRowTabs';
import { useTranslation } from 'next-i18next';
import { cloneDeep } from 'lodash';
import QuestionTip from '../MyTooltip/QuestionTip';
type LineConfig = {
dataKey: string;
@ -34,15 +34,13 @@ type TooltipItem = {
type LineChartComponentProps = {
data: Record<string, any>[];
title: string;
HeaderLeftChildren?: React.ReactNode;
description?: string;
HeaderRightChildren?: React.ReactNode;
lines: LineConfig[];
tooltipItems?: TooltipItem[];
defaultDisplayMode?: 'incremental' | 'cumulative';
enableIncremental?: boolean;
enableCumulative?: boolean;
enableTooltip?: boolean;
startDateValue?: number;
showAverage?: boolean;
averageKey?: string;
blur?: boolean;
};
const CustomTooltip = ({
@ -57,8 +55,15 @@ const CustomTooltip = ({
}
return (
<Box bg="white" p={3} borderRadius="md" border="base" boxShadow="sm">
<Box fontSize="sm" color="myGray.900" mb={2}>
<Box
bg="white"
p={3}
borderRadius="md"
border="base"
boxShadow="sm"
{...(tooltipItems.length > 8 ? { position: 'relative', top: '-30px' } : {})}
>
<Box fontSize="sm" color="myGray.900" mb={tooltipItems.length > 5 ? 1 : 2}>
{data.xLabel || data.x}
</Box>
{tooltipItems.map((item, index) => {
@ -66,7 +71,7 @@ const CustomTooltip = ({
const displayValue = item.formatter ? item.formatter(value) : formatNumber(value);
return (
<HStack key={index} fontSize="sm" _notLast={{ mb: 1 }}>
<HStack key={index} fontSize="sm" _notLast={{ mb: tooltipItems.length > 5 ? 0 : 1 }}>
<Box w={2} h={2} borderRadius="full" bg={item.color} />
<Box>{item.label}</Box>
<Box>{displayValue.toLocaleString()}</Box>
@ -80,30 +85,15 @@ const CustomTooltip = ({
const LineChartComponent = ({
data,
title,
HeaderLeftChildren,
description,
HeaderRightChildren,
lines,
tooltipItems,
defaultDisplayMode = 'incremental',
enableIncremental = true,
enableCumulative = true,
startDateValue = 0
showAverage = false,
averageKey,
blur = false
}: LineChartComponentProps) => {
const theme = useTheme();
const { t } = useTranslation();
const [displayMode, setDisplayMode] = useState<'incremental' | 'cumulative'>(defaultDisplayMode);
// Tab list constant
const tabList = useMemo(
() => [
...(enableIncremental
? [{ label: t('common:chart_mode_incremental'), value: 'incremental' as const }]
: []),
...(enableCumulative
? [{ label: t('common:chart_mode_cumulative'), value: 'cumulative' as const }]
: [])
],
[enableCumulative, enableIncremental, t]
);
// Y-axis number formatter function
const formatYAxisNumber = useCallback((value: number): string => {
@ -115,32 +105,13 @@ const LineChartComponent = ({
return value.toString();
}, []);
// Process data based on display mode
const processedData = useMemo(() => {
if (displayMode === 'incremental') {
return data;
}
// Calculate average value
const averageValue = useMemo(() => {
if (!showAverage || !averageKey || data.length === 0) return null;
// Cumulative mode: accumulate values for each line's dataKey
const cloneData = cloneDeep(data);
const dataKeys = lines.map((item) => item.dataKey);
return cloneData.map((item, index) => {
if (index === 0) {
item[dataKeys[0]] = startDateValue + item[dataKeys[0]];
return item;
}
dataKeys.forEach((key) => {
if (typeof item[key] === 'number') {
item[key] += cloneData[index - 1][key];
}
});
return item;
});
}, [displayMode, data, lines, startDateValue]);
const sum = data.reduce((acc, item) => acc + (item[averageKey] || 0), 0);
return sum / data.length;
}, [showAverage, averageKey, data]);
// Generate gradient definitions
const gradientDefs = useMemo(
@ -165,28 +136,49 @@ const LineChartComponent = ({
);
return (
<>
<HStack mb={4} justifyContent={'space-between'} alignItems={'flex-start'}>
<Box fontSize={'sm'} color={'myGray.900'} fontWeight={'medium'}>
{title}
<Box
onMouseEnter={(e) => {
const chartElement = e.currentTarget.querySelector('.recharts-wrapper');
if (chartElement && showAverage && averageValue !== null) {
chartElement.classList.add('show-average');
}
}}
onMouseLeave={(e) => {
const chartElement = e.currentTarget.querySelector('.recharts-wrapper');
if (chartElement) {
chartElement.classList.remove('show-average');
}
}}
h="100%"
>
<style jsx global>{`
.recharts-wrapper .average-line {
opacity: 0;
transition: opacity 0.2s ease-in-out;
}
.recharts-wrapper.show-average .average-line {
opacity: 1;
}
`}</style>
<Flex mb={4} h={6}>
<Flex flex={1} alignItems={'center'} gap={1}>
<Box fontSize={'sm'} color={'myGray.900'} fontWeight={'medium'}>
{title}
</Box>
<QuestionTip label={description} />
</Flex>
<Box filter={blur ? 'blur(7.5px)' : 'none'} pointerEvents={blur ? 'none' : 'auto'}>
{HeaderRightChildren}
</Box>
<HStack spacing={2}>
{HeaderLeftChildren}
{tabList.length > 1 && (
<FillRowTabs<'incremental' | 'cumulative'>
list={tabList}
py={0.5}
px={2}
value={displayMode}
onChange={setDisplayMode}
/>
)}
</HStack>
</HStack>
<ResponsiveContainer width="100%" height={'100%'}>
<AreaChart
data={processedData}
margin={{ top: 5, right: 30, left: 0, bottom: HeaderLeftChildren ? 20 : 15 }}
</Flex>
<ResponsiveContainer
width="100%"
height={'100%'}
style={{ filter: blur ? 'blur(7.5px)' : 'none' }}
>
<LineChart
data={data}
margin={{ top: 5, right: 30, left: 0, bottom: HeaderRightChildren ? 20 : 15 }}
>
{gradientDefs}
<XAxis
@ -206,9 +198,8 @@ const LineChartComponent = ({
<CartesianGrid strokeDasharray="3 3" horizontal={true} vertical={false} />
{tooltipItems && <Tooltip content={<CustomTooltip tooltipItems={tooltipItems} />} />}
{lines.map((line, index) => (
<Area
<Line
key={line.dataKey}
type="monotone"
name={line.name}
dataKey={line.dataKey}
stroke={line.color}
@ -217,9 +208,24 @@ const LineChartComponent = ({
dot={false}
/>
))}
</AreaChart>
{showAverage && averageValue !== null && (
<ReferenceLine
y={averageValue}
stroke={theme.colors.primary?.['400']}
strokeDasharray="5 5"
strokeWidth={1}
className="average-line"
label={{
value: `${formatNumber(averageValue)}`,
position: 'insideTopRight',
fill: theme.colors.primary?.['400'],
fontSize: 12
}}
/>
)}
</LineChart>
</ResponsiveContainer>
</>
</Box>
);
};

View File

@ -1,8 +1,7 @@
import React, { type ReactNode, useMemo } from 'react';
import React, { type ReactNode, useMemo, useEffect } from 'react';
import { createContext } from 'use-context-selector';
import { useMediaQuery } from '@chakra-ui/react';
import Cookies from 'js-cookie';
import { useEffect } from 'react';
const CookieKey = 'NEXT_DEVICE_SIZE';
const setSize = (value: string) => {

View File

@ -1,6 +1,7 @@
{
"Click_to_delete_this_field": "Click to delete this field",
"Filed_is_deprecated": "This field is deprecated",
"Index": "Index",
"MCP_tools_debug": "debug",
"MCP_tools_detail": "check the details",
"MCP_tools_list": "Tool list",
@ -10,8 +11,11 @@
"MCP_tools_url": "MCP Address",
"MCP_tools_url_is_empty": "The MCP address cannot be empty",
"MCP_tools_url_placeholder": "After filling in the MCP address, click Analysis",
"No_selected_dataset": "No selected dataset",
"Role_setting": "Permission",
"Run": "Execute",
"Search_dataset": "Search dataset",
"Selected": "Selected",
"Team_Tags": "Team tags",
"ai_point_price": "Billing",
"ai_settings": "AI Configuration",
@ -54,13 +58,14 @@
"cron.every_month": "Run Monthly",
"cron.every_week": "Run Weekly",
"cron.interval": "Run at Intervals",
"dataset": "dataset",
"dataset_search_tool_description": "Call the \"Semantic Search\" and \"Full-text Search\" capabilities to find reference content that may be related to the problem from the \"Knowledge Base\". \nPrioritize calling this tool to assist in answering user questions.",
"day": "Day",
"deleted": "App deleted",
"document_quote": "Document Reference",
"document_quote_tip": "Usually used to accept user-uploaded document content (requires document parsing), and can also be used to reference other string data.",
"document_upload": "Document Upload",
"edit_app": "Edit Application",
"edit_app": "Application details",
"edit_info": "Edit",
"execute_time": "Execution Time",
"export_config_successful": "Configuration copied, some sensitive information automatically filtered. Please check for any remaining sensitive data.",
@ -89,12 +94,26 @@
"llm_not_support_vision": "This model does not support image recognition",
"llm_use_vision": "Vision",
"llm_use_vision_tip": "After clicking on the model selection, you can see whether the model supports image recognition and the ability to control whether to start image recognition. \nAfter starting image recognition, the model will read the image content in the file link, and if the user question is less than 500 words, it will automatically parse the image in the user question.",
"log_chat_logs": "Dialogue log",
"log_detail": "Log details",
"logs_app_data": "Data board",
"logs_app_result": "Application effect",
"logs_average_response_time": "Average run time",
"logs_average_response_time_description": "Average of total workflow run time",
"logs_chat_count": "Number of sessions",
"logs_chat_count_description": "How many new sessions does this application create? \nSession definition: When the interval between the previous message exceeds 15 minutes, it is considered to be a new session (this definition only takes effect here)",
"logs_chat_data": "chat data",
"logs_chat_item_count": "Number of conversations",
"logs_chat_item_count_description": "How many conversations does this app generate? \nDialogue definition: The workflow runs once, and counts as a round of conversations",
"logs_chat_user": "user",
"logs_date": "date",
"logs_empty": "No logs yet~",
"logs_error_count": "Error Count",
"logs_error_rate": "Dialogue error ratio",
"logs_error_rate_description": "The proportion of the total number of dialogues reported in error",
"logs_export_confirm_tip": "There are currently {{total}} conversation records, and each conversation can export up to 100 latest messages. \nConfirm export?",
"logs_export_title": "Time, source, user, contact, title, total number of messages, user good feedback, user bad feedback, custom feedback, labeled answers, conversation details",
"logs_good_feedback": "Like",
"logs_key_config": "Field Configuration",
"logs_keys_annotatedCount": "Annotated Answer Count",
"logs_keys_createdTime": "Created Time",
@ -110,11 +129,30 @@
"logs_keys_title": "Title",
"logs_keys_user": "User",
"logs_message_total": "Total Messages",
"logs_new_user_count": "New users",
"logs_points": "Points Consumed",
"logs_points_description": "Points consumed by this application",
"logs_points_per_chat": "Average points consumption for a single session",
"logs_points_per_chat_description": "How many points are consumed on average for a workflow operation",
"logs_response_time": "Average Response Time",
"logs_search_chat": "Search for session title or session ID",
"logs_source": "source",
"logs_source_count_description": "Number of users across channels",
"logs_title": "Title",
"logs_total": "Grand total",
"logs_total_avg_points": "Average consumption",
"logs_total_chat": "Cumulative conversation count",
"logs_total_error": "{{count}} errors were reported in total, and the error rate was: {{rate}} %",
"logs_total_points": "Accumulated points consumption",
"logs_total_tips": "Cumulative indicators are not affected by time filtering",
"logs_total_users": "Cumulative number of users",
"logs_user_count": "Number of users",
"logs_user_count_description": "Number of people who have a conversation with the app in unit time",
"logs_user_data": "User data",
"logs_user_feedback": "User feedback",
"logs_user_feedback_description": "Like: Number of likes from users\n\nStep on: Users step on the number of points",
"logs_user_retention": "User retention",
"logs_user_retention_description": "Number of users who have added new users during the T cycle and are active in the T 1 cycle",
"look_ai_point_price": "View all model billing standards",
"manual_secret": "Manual secret",
"mark_count": "Number of Marked Answers",
@ -142,14 +180,23 @@
"pdf_enhance_parse_tips": "Calling PDF recognition model for parsing, you can convert it into Markdown and retain pictures in the document. At the same time, you can also identify scanned documents, which will take a long time to identify them.",
"permission.des.manage": "Based on write permissions, you can configure publishing channels, view conversation logs, and assign permissions to the application.",
"permission.des.read": "Use the app to have conversations",
"permission.des.write": "Can view and edit apps",
"permission.des.readChatLog": "Can view chat logs",
"permission.des.write": "Can view and edit apps",
"permission.name.read": "Dialogue only",
"permission.name.readChatLog": "View chat logs",
"plugin.Instructions": "Instructions",
"plugin_cost_by_token": "Charged based on token usage",
"plugin_cost_folder_tip": "This tool set contains subordinate tools, and the call points are determined based on the actual calling tool",
"plugin_cost_per_times": "{{cost}} points/time",
"plugin_dispatch": "Plugin Invocation",
"plugin_dispatch_tip": "Adds extra capabilities to the model. The specific plugins to be invoked will be autonomously decided by the model.\nIf a plugin is selected, the Dataset invocation will automatically be treated as a special plugin.",
"pro_modal_feature_1": "External organization structure integration and multi-tenancy",
"pro_modal_feature_2": "Team-exclusive application showcase page",
"pro_modal_feature_3": "Knowledge base enhanced indexing",
"pro_modal_later_button": "Maybe Later",
"pro_modal_subtitle": "Join the business edition now to unlock more premium features",
"pro_modal_title": "Business Edition Exclusive!",
"pro_modal_unlock_button": "Unlock Now",
"publish_channel": "Publish",
"publish_success": "Publish Successful",
"question_guide_tip": "After the conversation, 3 guiding questions will be generated for you.",
@ -203,9 +250,11 @@
"tool_active_manual_config_desc": "The temporary key is saved in this application and is only for use by this application.",
"tool_active_system_config_desc": "Use the system configured key",
"tool_active_system_config_price_desc": "Additional payment for key price ({{price}} points/time)",
"tool_active_system_config_price_desc_folder": "The additional key price is required, and the fee will be deducted based on the actual use of the tool.",
"tool_detail": "Tool details",
"tool_input_param_tip": "This plugin requires configuration of related information to run properly.",
"tool_not_active": "This tool has not been activated yet",
"tool_run_free": "This tool runs without points consumption",
"tool_type_communication": "Communication",
"tool_type_design": "design",
"tool_type_entertainment": "Business",
@ -248,6 +297,7 @@
"type.Workflow bot": "Workflow",
"type.error.Workflow data is empty": "No workflow data was obtained",
"type.error.workflowresponseempty": "Response content is empty",
"type.hidden": "Hide app",
"type_not_recognized": "App type not recognized",
"un_auth": "No permission",
"upload_file_max_amount": "Maximum File Quantity",

View File

@ -39,6 +39,12 @@
"file_amount_over": "Exceeded maximum file quantity {{max}}",
"file_input": "File input",
"file_input_tip": "You can obtain the link to the corresponding file through the \"File Link\" of the [Plug-in Start] node",
"history_slider.home.title": "chat",
"home.chat_app": "HomeChat-{{name}}",
"home.chat_id": "Chat ID",
"home.no_available_tools": "No tools available",
"home.select_tools": "Select Tool",
"home.tools": "Tool: {{num}}",
"in_progress": "In Progress",
"input_guide": "Input Guide",
"input_guide_lexicon": "Lexicon",
@ -77,6 +83,43 @@
"select_file": "Upload File",
"select_file_img": "Upload file / image",
"select_img": "Upload Image",
"setting.copyright.basic_configuration": "Basic configuration",
"setting.copyright.copyright_configuration": "Copyright configuration",
"setting.copyright.diagram": "Schematic diagram",
"setting.copyright.file_size_exceeds_limit": "File size exceeds the limit, maximum support for {{maxSize}}",
"setting.copyright.immediate_upload_required": "Immediate upload is required for this feature",
"setting.copyright.logo": "Logo",
"setting.copyright.preview_fail": "File preview failed",
"setting.copyright.save_fail": "Logo failed to save",
"setting.copyright.save_success": "Logo Saved successfully",
"setting.copyright.select_logo_image": "Please select the logo image to upload first",
"setting.copyright.style_diagram": "Style diagram",
"setting.copyright.tips": "Suggested ratio 4:1",
"setting.copyright.tips.square": "Suggested ratio 1:1",
"setting.copyright.title": "Copyright",
"setting.copyright.upload_fail": "File upload failed",
"setting.data_dashboard.title": "Data board",
"setting.fastgpt_chat_diagram": "/imgs/chat/fastgpt_chat_diagram_en.png",
"setting.home.available_tools.add": "Add",
"setting.home.commercial_version": "Commercial version",
"setting.home.diagram": "Schematic diagram",
"setting.home.dialogue_tips": "Dialog prompt text",
"setting.home.dialogue_tips.default": "You can ask me any questions",
"setting.home.dialogue_tips_placeholder": "Please enter the prompt text of the dialog box",
"setting.home.home_tab_title": "Home Page Title",
"setting.home.home_tab_title_placeholder": "Please enter the title of the homepage",
"setting.home.slogan": "Slogan",
"setting.home.slogan.default": "Hello 👋, I am FastGPT! Is there anything I can help you?",
"setting.home.slogan_placeholder": "Please enter Slogan",
"setting.home.title": "Home",
"setting.incorrect_plan": "The current plan does not support this feature, please upgrade to the subscription plan",
"setting.incorrect_version": "This feature is not supported in the current version",
"setting.log_details.title": "Home Log",
"setting.logs.title": "Homepage log",
"setting.save": "Save",
"setting.save_success": "Save successfully",
"sidebar.home": "Home",
"sidebar.team_apps": "Team Apps",
"source_cronJob": "Scheduled execution",
"start_chat": "Start",
"stream_output": "Stream Output",

View File

@ -64,7 +64,6 @@
"Parse": "Analysis",
"Permission": "Permission",
"Permission_tip": "Individual permissions are greater than group permissions",
"permission_other": "Other permissions (multiple)",
"Preview": "Preview",
"Remove": "Remove",
"Rename": "Rename",
@ -129,11 +128,11 @@
"code_error.account_error": "Incorrect account name or password",
"code_error.account_exist": "Account has been registered",
"code_error.account_not_found": "User is not registered",
"code_error.app_error.can_not_edit_admin_permission": "Can not edit admin permission",
"code_error.app_error.invalid_app_type": "Invalid Application Type",
"code_error.app_error.invalid_owner": "Unauthorized Application Owner",
"code_error.app_error.not_exist": "Application Does Not Exist",
"code_error.app_error.un_auth_app": "Unauthorized to Operate This Application",
"code_error.app_error.can_not_edit_admin_permission": "Can not edit admin permission",
"code_error.chat_error.un_auth": "Unauthorized to Operate This Chat Record",
"code_error.error_code.400": "Request Failed",
"code_error.error_code.401": "No Access Permission",
@ -478,6 +477,7 @@
"core.dataset.embedding model tip": "The index model can convert natural language into vectors for semantic search.\nNote that different index models cannot be used together. Once an index model is selected, it cannot be changed.",
"core.dataset.error.Data not found": "Data Not Found or Deleted",
"core.dataset.error.Start Sync Failed": "Failed to Start Sync",
"core.dataset.error.canNotEditAdminPermission": "You cannot edit the admin permission",
"core.dataset.error.invalidVectorModelOrQAModel": "Invalid Vector Model or QA Model",
"core.dataset.error.unAuthDataset": "Unauthorized to Operate This Dataset",
"core.dataset.error.unAuthDatasetCollection": "Unauthorized to Operate This Dataset",
@ -486,7 +486,6 @@
"core.dataset.error.unCreateCollection": "Unauthorized to Operate This Data",
"core.dataset.error.unExistDataset": "The knowledge base does not exist",
"core.dataset.error.unLinkCollection": "Not a Web Link Collection",
"core.dataset.error.canNotEditAdminPermission": "You cannot edit the admin permission",
"core.dataset.externalFile": "External File Library",
"core.dataset.file": "File",
"core.dataset.folder": "Directory",
@ -670,6 +669,7 @@
"core.module.template.UnKnow Module": "Unknown Module",
"core.module.template.ai_chat": "AI conversation",
"core.module.template.ai_chat_intro": "AI large model dialogue",
"core.module.template.all_team_app": "All",
"core.module.template.config_params": "Can configure application system parameters",
"core.module.template.empty_plugin": "Blank plugin",
"core.module.template.empty_workflow": "Blank workflow",
@ -693,7 +693,6 @@
"core.module.variable.variable option is value is required": "Option Content Cannot Be Empty",
"core.module.variable.variable options": "Options",
"core.plugin.Custom headers": "Custom Request Headers",
"core.plugin.Free": "This plugin does not consume points",
"core.plugin.Get Plugin Module Detail Failed": "Failed to Retrieve Plugin Information",
"core.plugin.Http plugin intro placeholder": "For display only, no actual effect",
"core.plugin.cost": "Points Consumption:",
@ -981,6 +980,7 @@
"permission.manager": "administrator",
"permission.read": "Read permission",
"permission.write": "write permission",
"permission_other": "Other permissions (multiple)",
"please_input_name": "Please Enter a Name",
"plugin.App": "Select App",
"plugin.Currentapp": "Current App",
@ -998,7 +998,6 @@
"plugin.Path": "Path",
"plugin.Please bind laf accout first": "Please Bind Laf Account First",
"plugin.Plugin List": "Plugin List",
"plugin.Search plugin": "Search Plugin",
"plugin.Search_app": "Search App",
"plugin.Set Name": "Name the Plugin",
"plugin.contribute": "Contribute Plugin",
@ -1019,10 +1018,11 @@
"required": "Required",
"rerank_weight": "Rearrange weights",
"resume_failed": "Resume Failed",
"root_folder": "Root Folder",
"root_folder": "Root",
"save_failed": "save_failed",
"save_success": "Saved Successfully",
"scan_code": "Scan the QR code to pay",
"search_tool": "Search Tools",
"secret_key": "Secret",
"secret_tips": "The value will not return plaintext again after saving",
"select_file_failed": "File Selection Failed",
@ -1079,11 +1079,11 @@
"support.user.info.verification_code": "Verification Code",
"support.user.inform.System message": "System Message",
"support.user.login.Email": "Email",
"support.user.login.Github": "GitHub Login",
"support.user.login.Google": "Google Login",
"support.user.login.Microsoft": "Microsoft Login",
"support.user.login.Github": "GitHub",
"support.user.login.Google": "Google",
"support.user.login.Microsoft": "Microsoft",
"support.user.login.Password": "Password",
"support.user.login.Password login": "Password Login",
"support.user.login.Password login": "Password",
"support.user.login.Phone": "Phone Login",
"support.user.login.Phone number": "Phone Number",
"support.user.login.Provider error": "Login Error, Please Try Again",
@ -1250,6 +1250,7 @@
"unusable_variable": "No Usable Variables",
"update_failed": "Update Failed",
"update_success": "Updated Successfully",
"upgrade": "upgrade",
"upload_file": "Upload File",
"upload_file_error": "File Upload Failed",
"use_helper": "Use Helper",

View File

@ -15,6 +15,7 @@
"Please wait for all files to upload": "Please wait for all files to be uploaded to complete",
"bucket_chat": "Conversation Files",
"bucket_file": "Dataset Documents",
"bucket_image": "picture",
"click_to_view_raw_source": "Click to View Original Source",
"common.Some images failed to process": "Some images failed to process",
"common.dataset_data_input_image_support_format": "Support .jpg, .jpeg, .png, .gif, .webp formats",

View File

@ -9,7 +9,7 @@
"no_remind": "Don't remind again",
"password_condition": "Password maximum 60 characters",
"password_tip": "Password must be at least 8 characters long and contain at least two combinations: numbers, letters, or special characters",
"policy_tip": "By using this service, you agree to our",
"policy_tip": "By using it, you have read and agree to\n<div>our<termsLink> Terms </termsLink>&<privacyLink> Privacy Policy</privacyLink></div>",
"privacy": "Privacy Policy",
"privacy_policy": "Privacy Policy",
"redirect": "Jump",

View File

@ -1,6 +1,7 @@
{
"Click_to_delete_this_field": "点击删除该字段",
"Filed_is_deprecated": "该字段已弃用",
"Index": "索引",
"MCP_tools_debug": "调试",
"MCP_tools_detail": "查看详情",
"MCP_tools_list": "工具列表",
@ -10,8 +11,11 @@
"MCP_tools_url": "MCP 地址",
"MCP_tools_url_is_empty": "MCP 地址不能为空",
"MCP_tools_url_placeholder": "填入 MCP 地址后,点击解析",
"No_selected_dataset": "未选择知识库",
"Role_setting": "权限设置",
"Run": "运行",
"Search_dataset": "搜索知识库",
"Selected": "已选择",
"Team_Tags": "团队标签",
"ai_point_price": "AI积分计费",
"ai_settings": "AI 配置",
@ -54,13 +58,14 @@
"cron.every_month": "每月执行",
"cron.every_week": "每周执行",
"cron.interval": "间隔执行",
"dataset": "知识库",
"dataset_search_tool_description": "调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容。优先调用该工具来辅助回答用户的问题。",
"day": "日",
"deleted": "应用已删除",
"document_quote": "文档引用",
"document_quote_tip": "通常用于接受用户上传的文档内容(这需要文档解析),也可以用于引用其他字符串数据。",
"document_upload": "文档上传",
"edit_app": "编辑应用",
"edit_app": "应用详情",
"edit_info": "编辑信息",
"execute_time": "执行时间",
"export_config_successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据",
@ -89,12 +94,27 @@
"llm_not_support_vision": "该模型不支持图片识别",
"llm_use_vision": "图片识别",
"llm_use_vision_tip": "点击模型选择后,可以看到模型是否支持图片识别以及控制是否启动图片识别的能力。启动图片识别后,模型会读取文件链接里图片内容,并且如果用户问题少于 500 字,会自动解析用户问题中的图片。",
"log_chat_logs": "对话日志",
"log_detail": "日志详情",
"logs_app_data": "数据看板",
"logs_app_result": "应用效果",
"logs_average_response_time": "平均运行时长(s)",
"logs_average_response_time_description": "工作流总运行时间的平均值",
"logs_bad_feedback": "点踩",
"logs_chat_count": "会话次数",
"logs_chat_count_description": "该应用共新建多少个会话。 会话定义当与上条消息间隔超过15min认为是产生新会话该定义仅在此生效",
"logs_chat_data": "对话数据",
"logs_chat_item_count": "对话次数",
"logs_chat_item_count_description": "该应用共产生多少次对话。 对话定义:工作流运行一次,算一轮对话",
"logs_chat_user": "使用者",
"logs_date": "日期",
"logs_empty": "还没有日志噢~",
"logs_error_count": "报错数量",
"logs_error_rate": "对话报错比例",
"logs_error_rate_description": "报错对话占总对话数量的比例",
"logs_export_confirm_tip": "当前共有 {{total}} 条对话记录,每条对话最多可导出最新 100 条消息。确认导出?",
"logs_export_title": "时间,来源,使用者,联系方式,标题,消息总数,用户赞同反馈,用户反对反馈,自定义反馈,标注答案,对话详情",
"logs_good_feedback": "点赞",
"logs_key_config": "字段配置",
"logs_keys_annotatedCount": "标注答案数量",
"logs_keys_createdTime": "创建时间",
@ -110,11 +130,38 @@
"logs_keys_title": "标题",
"logs_keys_user": "使用者",
"logs_message_total": "消息总数",
"logs_new_user_count": "新增用户",
"logs_points": "积分消耗",
"logs_points_description": "该应用消耗的积分",
"logs_points_per_chat": "单次会话平均积分消耗",
"logs_points_per_chat_description": "工作流运行一次平均消耗多少积分",
"logs_response_time": "平均响应时长",
"logs_search_chat": "搜索会话标题或会话 ID",
"logs_source": "来源",
"logs_source_count": "渠道用户",
"logs_source_count_description": "各渠道用户的数量",
"logs_timespan_day": "按日",
"logs_timespan_month": "按月",
"logs_timespan_quarter": "按季",
"logs_timespan_week": "按周",
"logs_title": "标题",
"logs_total": "累计",
"logs_total_avg_duration": "平均时长",
"logs_total_avg_points": "平均消耗",
"logs_total_chat": "累计对话数",
"logs_total_error": "共 {{count}} 次报错,报错率: {{rate}} %",
"logs_total_feedback": "共 {{goodFeedBack}} 赞 共 {{badFeedBack}} 踩",
"logs_total_points": "累计积分消耗",
"logs_total_tips": "累计指标不受时间筛选影响",
"logs_total_users": "累计用户数",
"logs_user_callback": "用户反馈",
"logs_user_count": "用户数",
"logs_user_count_description": "单位时间内与该应用产生对话的人数",
"logs_user_data": "用户数据",
"logs_user_feedback": "用户反馈",
"logs_user_feedback_description": "赞:用户点赞数量 \n踩用户点踩数量",
"logs_user_retention": "用户留存",
"logs_user_retention_description": "T周期新增用户且在T+1周期活跃的用户数",
"look_ai_point_price": "查看所有模型计费标准",
"manual_secret": "临时密钥",
"mark_count": "标注答案数量",
@ -142,14 +189,23 @@
"pdf_enhance_parse_tips": "调用 PDF 识别模型进行解析,可以将其转换成 Markdown 并保留文档中的图片,同时也可以对扫描件进行识别,识别时间较长。",
"permission.des.manage": "写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限",
"permission.des.read": "可使用该应用进行对话",
"permission.des.write": "可查看和编辑应用",
"permission.des.readChatLog": "可查看对话日志",
"permission.des.write": "可查看和编辑应用",
"permission.name.read": "仅对话",
"permission.name.readChatLog": "查看对话日志",
"plugin.Instructions": "使用说明",
"plugin_cost_by_token": "依据 token 消耗计费",
"plugin_cost_folder_tip": "该工具集包含下属工具,调用积分依据实际调用工具决定",
"plugin_cost_per_times": "{{cost}} 积分/次",
"plugin_dispatch": "插件调用",
"plugin_dispatch_tip": "给模型附加获取外部数据的能力,具体调用哪些插件,将由模型自主决定,所有插件都将以非流模式运行。\n若选择了插件知识库调用将自动作为一个特殊的插件。",
"pro_modal_feature_1": "外部组织架构接入与多租户",
"pro_modal_feature_2": "团队专属的应用展示页",
"pro_modal_feature_3": "知识库增强索引",
"pro_modal_later_button": "我再想想",
"pro_modal_subtitle": "即刻加入商业版,解锁更多高级功能",
"pro_modal_title": "商业版专享!",
"pro_modal_unlock_button": "去解锁",
"publish_channel": "发布渠道",
"publish_success": "发布成功",
"question_guide_tip": "对话结束后,会为你生成 3 个引导性问题。",
@ -203,9 +259,11 @@
"tool_active_manual_config_desc": "临时密钥保存在本应用中,仅供该应用使用",
"tool_active_system_config_desc": "使用系统已配置好的密钥",
"tool_active_system_config_price_desc": "需额外支付密钥价格( {{price}} 积分/次)",
"tool_active_system_config_price_desc_folder": "需额外支付密钥价格,依据实际使用工具扣费。",
"tool_detail": "工具详情",
"tool_input_param_tip": "该插件正常运行需要配置相关信息",
"tool_not_active": "该工具尚未激活",
"tool_run_free": "该工具运行无积分消耗",
"tool_type_communication": "通讯",
"tool_type_design": "设计",
"tool_type_entertainment": "商业",
@ -248,6 +306,7 @@
"type.Workflow bot": "工作流",
"type.error.Workflow data is empty": "没有获取到工作流数据",
"type.error.workflowresponseempty": "响应内容为空",
"type.hidden": "隐藏应用",
"type_not_recognized": "未识别到应用类型",
"un_auth": "无权限",
"upload_file_max_amount": "最大文件数量",

View File

@ -39,6 +39,11 @@
"file_amount_over": "超出最大文件数量 {{max}}",
"file_input": "系统文件",
"file_input_tip": "可通过【插件开始】节点的“文件链接”获取对应文件的链接",
"history_slider.home.title": "聊天",
"home.chat_app": "首页聊天-{{name}}",
"home.no_available_tools": "暂无可用工具",
"home.select_tools": "选择工具",
"home.tools": "工具:{{num}}",
"in_progress": "进行中",
"input_guide": "输入引导",
"input_guide_lexicon": "词库",
@ -77,6 +82,46 @@
"select_file": "上传文件",
"select_file_img": "上传文件/图片",
"select_img": "上传图片",
"setting.copyright.basic_configuration": "基础配置",
"setting.copyright.copyright_configuration": "版权配置",
"setting.copyright.diagram": "示意图",
"setting.copyright.file_size_exceeds_limit": "文件大小超出限制,最大支持 {{maxSize}}",
"setting.copyright.immediate_upload_required": "此功能需要立即上传",
"setting.copyright.logo": "Logo",
"setting.copyright.preview_fail": "文件预览失败",
"setting.copyright.save_fail": "Logo 保存失败",
"setting.copyright.save_success": "Logo 保存成功",
"setting.copyright.select_logo_image": "请先选择要上传的 Logo 图片",
"setting.copyright.style_diagram": "样式示意图",
"setting.copyright.tips": "建议比例 4:1",
"setting.copyright.tips.square": "建议比例 1:1",
"setting.copyright.title": "版权信息",
"setting.copyright.upload_fail": "文件上传失败",
"setting.data_dashboard.title": "数据看板",
"setting.fastgpt_chat_diagram": "/imgs/chat/fastgpt_chat_diagram.png",
"setting.home.available_tools": "可用工具",
"setting.home.available_tools.add": "添加",
"setting.home.commercial_version": "商业版",
"setting.home.diagram": "示意图",
"setting.home.dialogue_tips": "对话框提示文字",
"setting.home.dialogue_tips.default": "你可以问我任何问题",
"setting.home.dialogue_tips_placeholder": "请输入对话框提示文字",
"setting.home.home_tab_title": "首页标题",
"setting.home.home_tab_title_placeholder": "请输入首页标题",
"setting.home.slogan": "Slogan",
"setting.home.slogan.default": "你好👋,我是 FastGPT ! 请问有什么可以帮你?",
"setting.home.slogan_placeholder": "请输入 Slogan",
"setting.home.title": "首页配置",
"setting.incorrect_plan": "当前套餐不支持该功能,请升级订阅套餐",
"setting.incorrect_version": "当前版本不支持该功能",
"setting.log_details.title": "首页日志",
"setting.logs.title": "首页日志",
"setting.save": "保存",
"setting.save_success": "保存成功",
"setting.share": "分享",
"home.chat_id": "会话ID",
"sidebar.home": "首页",
"sidebar.team_apps": "团队应用",
"source_cronJob": "定时执行",
"start_chat": "开始对话",
"stream_output": "流输出",

View File

@ -64,7 +64,6 @@
"Parse": "解析",
"Permission": "权限",
"Permission_tip": "个人权限大于群组权限",
"permission_other": "其他权限(多选)",
"Preview": "预览",
"Remove": "移除",
"Rename": "重命名",
@ -129,12 +128,12 @@
"code_error.account_error": "账号名或密码错误",
"code_error.account_exist": "账号已注册",
"code_error.account_not_found": "用户未注册",
"code_error.app_error.can_not_edit_admin_permission": "不能编辑管理员权限",
"code_error.app_error.invalid_app_type": "错误的应用类型",
"code_error.app_error.invalid_owner": "非法的应用所有者",
"code_error.app_error.not_exist": "应用不存在",
"code_error.app_error.un_auth_app": "无权操作该应用",
"code_error.chat_error.un_auth": "没有权限操作此对话记录",
"code_error.app_error.can_not_edit_admin_permission": "不能编辑管理员权限",
"code_error.error_code.400": "请求失败",
"code_error.error_code.401": "无访问权限",
"code_error.error_code.403": "紧张访问",
@ -343,7 +342,7 @@
"core.chat.Feedback Submit": "提交反馈",
"core.chat.Feedback Success": "反馈成功!",
"core.chat.Finish Speak": "语音输入完成",
"core.chat.History": "历史记录",
"core.chat.History": "记录",
"core.chat.History Amount": "{{amount}} 条记录",
"core.chat.Mark": "标注预期回答",
"core.chat.Mark Description": "当前标注功能为测试版。\n\n点击添加标注后需要选择一个知识库以便存储标注数据。你可以通过该功能快速的标注问题和预期回答以便引导模型下次的回答。\n\n目前标注功能同知识库其他数据一样受模型的影响不代表标注后 100% 符合预期。\n\n标注数据仅单向与知识库同步如果知识库修改了该标注数据日志展示的标注数据无法同步。",
@ -478,6 +477,7 @@
"core.dataset.embedding model tip": "索引模型可以将自然语言转成向量,用于进行语义检索。\n注意不同索引模型无法一起使用选择完索引模型后将无法修改。",
"core.dataset.error.Data not found": "数据不存在或已被删除",
"core.dataset.error.Start Sync Failed": "开始同步失败",
"core.dataset.error.canNotEditAdminPermission": "无法修改管理员权限",
"core.dataset.error.invalidVectorModelOrQAModel": "VectorModel 或 QA 模型错误",
"core.dataset.error.unAuthDataset": "无权操作该知识库",
"core.dataset.error.unAuthDatasetCollection": "无权操作该数据集",
@ -486,7 +486,6 @@
"core.dataset.error.unCreateCollection": "无权操作该数据",
"core.dataset.error.unExistDataset": "知识库不存在",
"core.dataset.error.unLinkCollection": "不是网络链接集合",
"core.dataset.error.canNotEditAdminPermission": "无法修改管理员权限",
"core.dataset.externalFile": "外部文件库",
"core.dataset.file": "文件",
"core.dataset.folder": "目录",
@ -667,6 +666,7 @@
"core.module.template.System Plugin": "系统插件",
"core.module.template.System input module": "系统输入",
"core.module.template.Team app": "团队应用",
"core.module.template.all_team_app": "全部",
"core.module.template.UnKnow Module": "未知模块",
"core.module.template.ai_chat": "AI 对话",
"core.module.template.ai_chat_intro": "AI 大模型对话",
@ -693,7 +693,6 @@
"core.module.variable.variable option is value is required": "选项内容不能为空",
"core.module.variable.variable options": "选项",
"core.plugin.Custom headers": "自定义请求头",
"core.plugin.Free": "该插件无需积分消耗~",
"core.plugin.Get Plugin Module Detail Failed": "加载插件异常",
"core.plugin.Http plugin intro placeholder": "仅做展示,无实际效果",
"core.plugin.cost": "积分消耗:",
@ -981,6 +980,7 @@
"permission.manager": "管理员",
"permission.read": "读权限",
"permission.write": "写权限",
"permission_other": "其他权限(多选)",
"please_input_name": "请输入名称",
"plugin.App": "选择应用",
"plugin.Currentapp": "当前应用",
@ -998,7 +998,6 @@
"plugin.Path": "路径",
"plugin.Please bind laf accout first": "请先绑定 laf 账号",
"plugin.Plugin List": "插件列表",
"plugin.Search plugin": "搜索插件",
"plugin.Search_app": "搜索应用",
"plugin.Set Name": "给插件取个名字",
"plugin.contribute": "贡献插件",
@ -1023,6 +1022,7 @@
"save_failed": "保存异常",
"save_success": "保存成功",
"scan_code": "扫码支付",
"search_tool": "搜索工具",
"secret_key": "密钥",
"secret_tips": "值保存后不会再次明文返回",
"select_file_failed": "选择文件异常",
@ -1251,6 +1251,7 @@
"unusable_variable": "无可用变量",
"update_failed": "更新异常",
"update_success": "更新成功",
"upgrade": "升级",
"upload_file": "上传文件",
"upload_file_error": "上传文件失败",
"use_helper": "使用帮助",

View File

@ -15,6 +15,7 @@
"Please wait for all files to upload": "请等待所有文件上传完成",
"bucket_chat": "对话文件",
"bucket_file": "知识库文件",
"bucket_image": "图片",
"click_to_view_raw_source": "点击查看来源",
"common.Some images failed to process": "部分图片处理失败",
"common.dataset_data_input_image_support_format": "支持 .jpg, .jpeg, .png, .gif, .webp 格式",

View File

@ -9,7 +9,7 @@
"no_remind": "不再提醒",
"password_condition": "密码最多 60 位",
"password_tip": "密码至少 8 位,且至少包含两种组合:数字、字母或特殊字符",
"policy_tip": "使用即代表你同意我们的",
"policy_tip": "使用即代表您已阅读并同意<termsLink> 服务协议 </termsLink>和<privacyLink> 隐私协议</privacyLink>",
"privacy": "隐私协议",
"privacy_policy": "隐私政策",
"redirect": "跳转",

View File

@ -1,6 +1,7 @@
{
"Click_to_delete_this_field": "點擊刪除該字段",
"Filed_is_deprecated": "該字段已棄用",
"Index": "索引",
"MCP_tools_debug": "偵錯",
"MCP_tools_detail": "查看詳情",
"MCP_tools_list": "工具列表",
@ -10,8 +11,11 @@
"MCP_tools_url": "MCP 地址",
"MCP_tools_url_is_empty": "MCP 地址不能為空",
"MCP_tools_url_placeholder": "填入 MCP 地址後,點擊解析",
"No_selected_dataset": "未選擇知識庫",
"Role_setting": "權限設定",
"Run": "執行",
"Search_dataset": "搜尋知識庫",
"Selected": "已選擇",
"Team_Tags": "團隊標籤",
"ai_point_price": "AI 積分計費",
"ai_settings": "AI 設定",
@ -54,13 +58,14 @@
"cron.every_month": "每月執行",
"cron.every_week": "每週執行",
"cron.interval": "間隔執行",
"dataset": "知識庫",
"dataset_search_tool_description": "呼叫「語意搜尋」和「全文搜尋」功能,從「知識庫」中尋找可能與問題相關的參考內容。優先呼叫這個工具來協助回答使用者的問題。",
"day": "日",
"deleted": "應用已刪除",
"document_quote": "文件引用",
"document_quote_tip": "通常用於接受使用者上傳的文件內容(這需要文件解析),也可以用於引用其他字串資料。",
"document_upload": "文件上傳",
"edit_app": "編輯應用程式",
"edit_app": "應用詳情",
"edit_info": "編輯資訊",
"execute_time": "執行時間",
"export_config_successful": "已複製設定,自動過濾部分敏感資訊,請注意檢查是否仍有敏感資料",
@ -89,12 +94,26 @@
"llm_not_support_vision": "這個模型不支援圖片辨識",
"llm_use_vision": "圖片辨識",
"llm_use_vision_tip": "點選模型選擇後,可以看到模型是否支援圖片辨識以及控制是否啟用圖片辨識的功能。啟用圖片辨識後,模型會讀取檔案連結中的圖片內容,並且如果使用者問題少於 500 字,會自動解析使用者問題中的圖片。",
"log_chat_logs": "對話日誌",
"log_detail": "日誌詳情",
"logs_app_data": "數據看板",
"logs_app_result": "應用效果",
"logs_average_response_time": "平均運行時長",
"logs_average_response_time_description": "工作流總運行時間的平均值",
"logs_chat_count": "會話次數",
"logs_chat_count_description": "該應用共新建多少個會話。 \n會話定義當與上條消息間隔超過15min認為是產生新會話該定義僅在此生效",
"logs_chat_data": "對話數據",
"logs_chat_item_count": "對話次數",
"logs_chat_item_count_description": "該應用共產生多少次對話。 \n對話定義工作流運行一次算一輪對話",
"logs_chat_user": "使用者",
"logs_date": "日期",
"logs_empty": "還沒有紀錄喔~",
"logs_error_count": "錯誤數量",
"logs_error_rate": "對話報錯比例",
"logs_error_rate_description": "報錯對話佔總對話數量的比例",
"logs_export_confirm_tip": "當前共有 {{total}} 條對話記錄,每條對話最多可導出最新 100 條消息。\n確認導出",
"logs_export_title": "時間,來源,使用者,聯絡方式,標題,訊息總數,使用者贊同回饋,使用者反對回饋,自定義回饋,標註答案,對話詳細資訊",
"logs_good_feedback": "點贊",
"logs_key_config": "字段配置",
"logs_keys_annotatedCount": "標記答案數量",
"logs_keys_createdTime": "建立時間",
@ -110,11 +129,30 @@
"logs_keys_title": "標題",
"logs_keys_user": "使用者",
"logs_message_total": "訊息總數",
"logs_new_user_count": "新增用戶",
"logs_points": "積分消耗",
"logs_points_description": "該應用消耗的積分",
"logs_points_per_chat": "單次會話平均積分消耗",
"logs_points_per_chat_description": "工作流運行一次平均消耗多少積分",
"logs_response_time": "平均回應時長",
"logs_search_chat": "搜索會話標題或會話 ID",
"logs_source": "來源",
"logs_source_count_description": "各渠道用戶的數量",
"logs_title": "標題",
"logs_total": "累計",
"logs_total_avg_points": "平均消耗",
"logs_total_chat": "累計對話數",
"logs_total_error": "共 {{count}} 次報錯,報錯率: {{rate}} %",
"logs_total_points": "累計積分消耗",
"logs_total_tips": "累計指標不受時間篩選影響",
"logs_total_users": "累計用戶數",
"logs_user_count": "用戶數",
"logs_user_count_description": "單位時間內與該應用產生對話的人數",
"logs_user_data": "用戶數據",
"logs_user_feedback": "用戶反饋",
"logs_user_feedback_description": "贊:用戶點贊數量 \n踩用戶點踩數量",
"logs_user_retention": "用戶留存",
"logs_user_retention_description": "T週期新增用戶且在T 1週期活躍的用戶數",
"look_ai_point_price": "檢視所有模型計費標準",
"manual_secret": "臨時密鑰",
"mark_count": "標記答案數量",
@ -142,14 +180,23 @@
"pdf_enhance_parse_tips": "呼叫 PDF 識別模型進行解析,可以將其轉換成 Markdown 並保留文件中的圖片,同時也可以對掃描件進行識別,識別時間較長。",
"permission.des.manage": "在寫入權限基礎上,可以設定發布通道、檢視對話紀錄、分配這個應用程式的權限",
"permission.des.read": "可以使用這個應用程式進行對話",
"permission.des.write": "可以檢視和編輯應用程式",
"permission.des.readChatLog": "可以檢視對話紀錄",
"permission.des.write": "可以檢視和編輯應用程式",
"permission.name.read": "僅對話",
"permission.name.readChatLog": "檢視對話紀錄",
"plugin.Instructions": "使用說明",
"plugin_cost_by_token": "根據 token 消耗計費",
"plugin_cost_folder_tip": "該工具集包含下屬工具,調用積分依據實際調用工具決定",
"plugin_cost_per_times": "{{cost}} 積分/次",
"plugin_dispatch": "外掛呼叫",
"plugin_dispatch_tip": "賦予模型取得外部資料的能力,具體呼叫哪些外掛,將由模型自主決定,所有外掛都將以非串流模式執行。\n若選擇了外掛知識庫呼叫將自動作為一個特殊的外掛。",
"pro_modal_feature_1": "外部組織架構接入與多租戶",
"pro_modal_feature_2": "團隊專屬的應用展示頁",
"pro_modal_feature_3": "知識庫增強索引",
"pro_modal_later_button": "我再想想",
"pro_modal_subtitle": "即刻加入商業版,解鎖更多高級功能",
"pro_modal_title": "商業版專享!",
"pro_modal_unlock_button": "去解鎖",
"publish_channel": "發布通道",
"publish_success": "發布成功",
"question_guide_tip": "對話結束後,會為你產生 3 個引導性問題。",
@ -203,9 +250,11 @@
"tool_active_manual_config_desc": "臨時密鑰保存在本應用中,僅供該應用使用",
"tool_active_system_config_desc": "使用系統已配置好的密鑰",
"tool_active_system_config_price_desc": "需額外支付密鑰價格( {{price}} 積分/次)",
"tool_active_system_config_price_desc_folder": "需額外支付密鑰價格,依據實際使用工具扣費。",
"tool_detail": "工具詳情",
"tool_input_param_tip": "這個外掛正常執行需要設定相關資訊",
"tool_not_active": "該工具尚未激活",
"tool_run_free": "該工具運行無積分消耗",
"tool_type_communication": "通訊",
"tool_type_design": "設計",
"tool_type_entertainment": "商業",
@ -248,6 +297,7 @@
"type.Workflow bot": "工作流程",
"type.error.Workflow data is empty": "沒有獲取到工作流數據",
"type.error.workflowresponseempty": "響應內容為空",
"type.hidden": "隱藏應用",
"type_not_recognized": "未識別到應用程式類型",
"un_auth": "無權限",
"upload_file_max_amount": "最大檔案數量",

View File

@ -39,6 +39,12 @@
"file_amount_over": "超出檔案數量上限 {{max}}",
"file_input": "檔案輸入",
"file_input_tip": "可透過「外掛程式啟動」節點的「檔案連結」取得對應檔案的連結",
"history_slider.home.title": "聊天",
"home.chat_app": "首页聊天-{{name}}",
"home.chat_id": "會話ID",
"home.no_available_tools": "暫無可用工具",
"home.select_tools": "選擇工具",
"home.tools": "工具:{{num}}",
"in_progress": "進行中",
"input_guide": "輸入導引",
"input_guide_lexicon": "詞彙庫",
@ -77,6 +83,42 @@
"select_file": "上傳檔案",
"select_file_img": "上傳檔案 / 圖片",
"select_img": "上傳圖片",
"setting.copyright.basic_configuration": "基礎配置",
"setting.copyright.copyright_configuration": "版權配置",
"setting.copyright.diagram": "示意圖",
"setting.copyright.file_size_exceeds_limit": "文件大小超出限制,最大支持 {{maxSize}}",
"setting.copyright.immediate_upload_required": "此功能需要立即上傳",
"setting.copyright.logo": "Logo",
"setting.copyright.preview_fail": "文件預覽失敗",
"setting.copyright.save_fail": "Logo 保存失敗",
"setting.copyright.select_logo_image": "請先選擇要上傳的 Logo 圖片",
"setting.copyright.style_diagram": "樣式示意圖",
"setting.copyright.tips": "建議比例 4:1",
"setting.copyright.tips.square": "建議比例 1:1",
"setting.copyright.title": "版權信息",
"setting.copyright.upload_fail": "文件上傳失敗",
"setting.data_dashboard.title": "數據看板",
"setting.fastgpt_chat_diagram": "/imgs/chat/fastgpt_chat_diagram_zh-Hant.png",
"setting.home.available_tools.add": "添加",
"setting.home.commercial_version": "商業版",
"setting.home.diagram": "示意圖",
"setting.home.dialogue_tips": "對話框提示文字",
"setting.home.dialogue_tips.default": "你可以問我任何問題",
"setting.home.dialogue_tips_placeholder": "請輸入對話框提示文字",
"setting.home.home_tab_title": "首頁標題",
"setting.home.home_tab_title_placeholder": "請輸入首頁標題",
"setting.home.slogan": "Slogan",
"setting.home.slogan.default": "你好👋,我是 FastGPT ! 請問有什麼可以幫你?",
"setting.home.slogan_placeholder": "請輸入 Slogan",
"setting.home.title": "首頁配置",
"setting.incorrect_plan": "當前套餐不支持該功能,請升級訂閱套餐",
"setting.incorrect_version": "當前版本不支持該功能",
"setting.log_details.title": "首頁日誌",
"setting.logs.title": "首頁日誌",
"setting.save": "保存",
"setting.save_success": "保存成功",
"sidebar.home": "首頁",
"sidebar.team_apps": "團隊應用",
"source_cronJob": "定時執行",
"start_chat": "開始對話",
"stream_output": "串流輸出",

View File

@ -64,7 +64,6 @@
"Parse": "解析",
"Permission": "權限",
"Permission_tip": "個人權限大於群組權限",
"permission_other": "其他權限(多選)",
"Preview": "預覽",
"Remove": "移除",
"Rename": "重新命名",
@ -129,12 +128,12 @@
"code_error.account_error": "帳號名稱或密碼錯誤",
"code_error.account_exist": "賬號已註冊",
"code_error.account_not_found": "使用者未註冊",
"code_error.app_error.can_not_edit_admin_permission": "不能編輯管理員權限",
"code_error.app_error.invalid_app_type": "無效的應用程式類型",
"code_error.app_error.invalid_owner": "非法的應用程式擁有者",
"code_error.app_error.not_exist": "應用程式不存在",
"code_error.app_error.un_auth_app": "無權操作此應用程式",
"code_error.chat_error.un_auth": "沒有權限操作此對話記錄",
"code_error.app_error.can_not_edit_admin_permission": "不能編輯管理員權限",
"code_error.error_code.400": "請求失敗",
"code_error.error_code.401": "無存取權限",
"code_error.error_code.403": "禁止存取",
@ -343,7 +342,7 @@
"core.chat.Feedback Submit": "送出回饋",
"core.chat.Feedback Success": "回饋成功!",
"core.chat.Finish Speak": "語音輸入完成",
"core.chat.History": "歷史記錄",
"core.chat.History": "記錄",
"core.chat.History Amount": "{{amount}} 筆記錄",
"core.chat.Mark": "標記預期回答",
"core.chat.Mark Description": "目前標記功能為測試版。\n\n點選新增標記後需要選擇一個知識庫來儲存標記資料。您可以透過此功能快速標記問題和預期回答以引導模型下次的回答。\n\n目前標記功能與知識庫中的其他資料一樣會受到模型的影響不保證標記後一定 100% 符合預期。\n\n標記資料僅單向與知識庫同步。如果知識庫修改了標記資料日誌中顯示的標記資料將無法同步。",
@ -424,7 +423,6 @@
"core.chat.response.text output": "文字輸出",
"core.chat.response.update_var_result": "變數更新結果(依序顯示多個變數更新結果)",
"core.chat.response.user_select_result": "使用者選擇結果",
"core.chat.retry": "重新產生",
"core.chat.tts.Stop Speech": "停止",
"core.dataset.Choose Dataset": "關聯知識庫",
"core.dataset.Collection": "資料集",
@ -478,6 +476,7 @@
"core.dataset.embedding model tip": "索引模型可以將自然語言轉換成向量,用於進行語意搜尋。\n注意不同索引模型無法一起使用。選擇索引模型後就無法修改。",
"core.dataset.error.Data not found": "資料不存在或已被刪除",
"core.dataset.error.Start Sync Failed": "開始同步失敗",
"core.dataset.error.canNotEditAdminPermission": "無法修改管理員權限",
"core.dataset.error.invalidVectorModelOrQAModel": "向量模型或問答模型錯誤",
"core.dataset.error.unAuthDataset": "無權操作此知識庫",
"core.dataset.error.unAuthDatasetCollection": "無權操作此資料集",
@ -486,7 +485,6 @@
"core.dataset.error.unCreateCollection": "無權操作此資料",
"core.dataset.error.unExistDataset": "知識庫不存在",
"core.dataset.error.unLinkCollection": "不是網路連結集合",
"core.dataset.error.canNotEditAdminPermission": "無法修改管理員權限",
"core.dataset.externalFile": "外部檔案庫",
"core.dataset.file": "檔案",
"core.dataset.folder": "目錄",
@ -670,6 +668,7 @@
"core.module.template.UnKnow Module": "未知模組",
"core.module.template.ai_chat": "AI 對話",
"core.module.template.ai_chat_intro": "AI 大型模型對話",
"core.module.template.all_team_app": "全部",
"core.module.template.config_params": "可以設定應用程式的系統參數",
"core.module.template.empty_plugin": "空白外掛程式",
"core.module.template.empty_workflow": "空白工作流程",
@ -693,7 +692,6 @@
"core.module.variable.variable option is value is required": "選項內容不能為空",
"core.module.variable.variable options": "選項",
"core.plugin.Custom headers": "自訂請求標頭",
"core.plugin.Free": "此外掛程式不需消耗點數",
"core.plugin.Get Plugin Module Detail Failed": "取得外掛程式資訊失敗",
"core.plugin.Http plugin intro placeholder": "僅供展示,無實際效果",
"core.plugin.cost": "點數消耗:",
@ -981,6 +979,7 @@
"permission.manager": "管理員",
"permission.read": "讀取權限",
"permission.write": "寫入權限",
"permission_other": "其他權限(多選)",
"please_input_name": "請輸入名稱",
"plugin.App": "選擇應用程式",
"plugin.Currentapp": "目前應用程式",
@ -998,7 +997,6 @@
"plugin.Path": "路徑",
"plugin.Please bind laf accout first": "請先綁定 LAF 帳戶",
"plugin.Plugin List": "外掛程式列表",
"plugin.Search plugin": "搜尋外掛程式",
"plugin.Search_app": "搜尋應用程式",
"plugin.Set Name": "為外掛程式命名",
"plugin.contribute": "貢獻外掛程式",
@ -1023,6 +1021,7 @@
"save_failed": "儲存失敗",
"save_success": "儲存成功",
"scan_code": "掃碼支付",
"search_tool": "搜索工具",
"secret_key": "密鑰",
"secret_tips": "值保存後不會再次明文返回",
"select_file_failed": "選擇檔案失敗",
@ -1250,6 +1249,7 @@
"unusable_variable": "無可用變數",
"update_failed": "更新失敗",
"update_success": "更新成功",
"upgrade": "升級",
"upload_file": "上傳檔案",
"upload_file_error": "上傳檔案失敗",
"use_helper": "使用說明",

View File

@ -15,6 +15,7 @@
"Please wait for all files to upload": "請等待所有文件上傳完成",
"bucket_chat": "對話檔案",
"bucket_file": "知識庫檔案",
"bucket_image": "圖片",
"click_to_view_raw_source": "點選檢視原始來源",
"common.Some images failed to process": "部分圖片處理失敗",
"common.dataset_data_input_image_support_format": "支持 .jpg, .jpeg, .png, .gif, .webp 格式",

View File

@ -9,7 +9,7 @@
"no_remind": "不再提醒",
"password_condition": "密碼最多 60 個字元",
"password_tip": "密碼至少 8 位,且至少包含兩種組合:數字、字母或特殊字元",
"policy_tip": "使用即代表您同意我們的",
"policy_tip": "使用即代表您已閱讀並同意<termsLink> 服務協議 </termsLink>和<privacyLink> 隱私協議</privacyLink>",
"privacy": "隱私權政策",
"privacy_policy": "隱私權政策",
"redirect": "跳轉",

View File

@ -545,7 +545,30 @@ const Checkbox = checkBoxMultiStyle({
borderColor: 'primary.400'
}
}
})
}),
sizes: {
sm: checkBoxPart({
control: {
width: '18px',
height: '18px',
borderWidth: '2px'
}
}),
md: checkBoxPart({
control: {
width: '20px',
height: '20px',
borderWidth: '2px'
}
}),
lg: checkBoxPart({
control: {
width: '24px',
height: '24px',
borderWidth: '2px'
}
})
}
});
const Modal = modalMultiStyle({

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