From 0720bbe4da17ef047a57a6fcae515dea1a5e78e7 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Sat, 26 Apr 2025 16:17:21 +0800 Subject: [PATCH] V4.9.7 feature (#4669) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update doc * feat: Add coupon redemption feature for team subscriptions (#4595) * feat: Add coupon redemption feature for team subscriptions - Introduced `TeamCouponSub` and `TeamCouponSchema` types - Added `redeemCoupon` API endpoint - Updated UI to include a modal for coupon redemption - Added new icon and translations for "Redeem coupon" * perf: remove field teamId * perf: use dynamic import * refactor: move to page component * perf: coupon code * perf: mcp server * perf: test * auto layout (#4634) * fix 4.9.6 (#4631) * fix debug quote list * delete next text node match * fix extract default boolean value * export latest 100 chat items * fix quote item ui * doc * fix doc * feat: auto layout * perf: auto layout * fix: auto layout null * add start node --------- Co-authored-by: heheer * fix: share link (#4644) * Add workflow run duration;Get audio duration (#4645) * add duration * get audio duration * Custom config path (#4649) * feat: 通过环境变量DATA_PATH获取配置文件目录 (#4622) 通过环境变量DATA_PATH获取配置文件目录,以应对不同的部署方式的多样化需求 * feat: custom configjson path * doc --------- Co-authored-by: John Chen * 程序api调用场景下,如果大量调用带有图片或视频,产生的聊天记录会导致后台mongo数据库异常。这个修改给api客户端一个禁止生成聊天记录的选项,避免这个后果。 (#3964) * update special chatId * perf: vector db rename * update operationLog (#4647) * update operationLog * combine operationLogMap * solve operationI18nLogMap bug * remoce log * feat: Rerank usage (#4654) * refresh concat when update (#4655) * fix: refresh code * perf: timer lock * Fix operationLog (#4657) * perf: http streamable mcp * add alipay (#4630) * perf: subplan ui * perf: pay code * hiden bank tip * Fix: pay error (#4665) * fix quote number (#4666) * remove log --------- Co-authored-by: a.e. <49438478+I-Info@users.noreply.github.com> Co-authored-by: heheer Co-authored-by: John Chen Co-authored-by: gaord Co-authored-by: gggaaallleee <91131304+gggaaallleee@users.noreply.github.com> --- .../zh-cn/docs/development/upgrading/497.md | 20 +- env.d.ts | 22 +- .../global/common/system/types/index.d.ts | 7 + packages/global/core/app/utils.ts | 2 +- packages/global/core/chat/type.d.ts | 3 +- packages/global/core/chat/utils.ts | 16 +- .../global/core/workflow/runtime/constants.ts | 1 + .../global/core/workflow/runtime/type.d.ts | 6 + packages/global/support/mcp/type.d.ts | 2 +- .../global/support/operationLog/constants.ts | 1 + packages/global/support/wallet/bill/api.d.ts | 20 +- .../global/support/wallet/bill/constants.ts | 38 +- packages/global/support/wallet/bill/type.d.ts | 5 +- .../global/support/wallet/sub/constants.ts | 10 +- .../support/wallet/sub/coupon/type.d.ts | 16 + packages/global/support/wallet/sub/type.d.ts | 2 +- packages/global/tsconfig.json | 2 +- .../service/common/system/timerLock/utils.ts | 18 +- .../{vectorStore => vectorDB}/constants.ts | 0 .../{vectorStore => vectorDB}/controller.d.ts | 0 .../{vectorStore => vectorDB}/controller.ts | 6 +- .../class.ts => vectorDB/milvus/index.ts} | 2 +- .../oceanbase/controller.ts} | 0 .../class.ts => vectorDB/oceanbase/index.ts} | 4 +- .../pg/index.ts => vectorDB/pg/controller.ts} | 0 .../pg/class.ts => vectorDB/pg/index.ts} | 4 +- .../{vectorStore => vectorDB}/type.d.ts | 0 .../service/core/ai/audio/transcriptions.ts | 3 +- packages/service/core/ai/rerank/index.ts | 35 +- packages/service/core/app/mcp.ts | 68 ++-- packages/service/core/chat/chatItemSchema.ts | 3 +- packages/service/core/chat/saveChat.ts | 65 ++-- .../core/dataset/collection/controller.ts | 2 +- packages/service/core/dataset/controller.ts | 2 +- .../service/core/dataset/search/controller.ts | 40 +- .../core/workflow/dispatch/dataset/search.ts | 48 ++- .../service/core/workflow/dispatch/index.ts | 56 ++- .../core/workflow/dispatch/plugin/runTool.ts | 16 +- .../service/core/workflow/dispatch/type.d.ts | 1 + packages/service/support/mcp/schema.ts | 10 +- .../support/operationLog/addOperationLog.ts | 1 - .../service/support/operationLog/constants.ts | 73 ++-- .../service/support/permission/teamLimit.ts | 11 - .../service/support/wallet/coupon/schema.ts | 33 ++ packages/service/support/wallet/sub/schema.ts | 2 +- packages/service/support/wallet/sub/utils.ts | 2 +- .../service/support/wallet/usage/utils.ts | 2 +- .../web/components/common/Icon/constants.ts | 24 +- .../common/Icon/icons/alignLeft.svg | 1 + .../common/Icon/icons/common/alipay.svg | 5 + .../common/Icon/icons/common/wechat.svg | 8 + .../Icon/icons/support/account/coupon.svg | 9 + packages/web/hooks/useLinkedScroll.tsx | 1 - packages/web/i18n/en/account_bill.json | 6 +- packages/web/i18n/en/account_info.json | 3 +- packages/web/i18n/en/account_team.json | 2 + packages/web/i18n/en/chat.json | 3 + packages/web/i18n/en/common.json | 19 +- packages/web/i18n/en/dashboard_mcp.json | 4 +- packages/web/i18n/en/workflow.json | 1 + packages/web/i18n/zh-CN/account_bill.json | 6 +- packages/web/i18n/zh-CN/account_info.json | 5 +- packages/web/i18n/zh-CN/account_team.json | 44 ++- packages/web/i18n/zh-CN/chat.json | 3 + packages/web/i18n/zh-CN/common.json | 19 +- packages/web/i18n/zh-CN/dashboard_mcp.json | 4 +- packages/web/i18n/zh-CN/workflow.json | 1 + packages/web/i18n/zh-Hant/account_bill.json | 6 +- packages/web/i18n/zh-Hant/account_info.json | 5 +- packages/web/i18n/zh-Hant/account_team.json | 2 + packages/web/i18n/zh-Hant/chat.json | 3 + packages/web/i18n/zh-Hant/common.json | 19 +- packages/web/i18n/zh-Hant/dashboard_mcp.json | 4 +- packages/web/i18n/zh-Hant/workflow.json | 1 + pnpm-lock.yaml | 46 ++- projects/app/.env.template | 11 +- projects/app/package.json | 1 + projects/app/public/imgs/modal/wallet.svg | 9 + projects/app/src/components/Markdown/A.tsx | 121 +++--- .../components/core/ai/ModelTable/index.tsx | 13 +- .../core/app/DatasetParamsModal.tsx | 7 +- .../ChatBox/components/ChatItem.tsx | 69 +++- .../ChatBox/components/QuoteList.tsx | 20 +- .../ChatBox/components/ResponseTags.tsx | 69 +--- .../core/chat/ChatContainer/ChatBox/index.tsx | 10 +- .../core/chat/ChatContainer/type.d.ts | 1 + .../chat/components/WholeResponseModal.tsx | 42 +- .../user/inform/UpdateContactModal.tsx | 12 +- .../support/wallet/QRCodePayModal.tsx | 219 +++++++++-- .../wallet/StandardPlanContentList.tsx | 18 +- projects/app/src/global/core/chat/utils.ts | 3 - projects/app/src/instrumentation.ts | 2 +- .../pageComponents/account/bill/BillTable.tsx | 54 +-- .../account/bill/InvoiceHeaderForm.tsx | 2 +- .../account/bill/InvoiceTable.tsx | 1 + .../account/info/RedeemCouponModal.tsx | 57 +++ .../account/model/AddModelBox.tsx | 4 +- .../account/model/ModelConfigTable.tsx | 13 +- .../account/team/EditInfoModal.tsx | 5 +- .../account/team/OperationLog/index.tsx | 6 +- .../app/detail/SimpleApp/EditForm.tsx | 2 +- .../Flow/components/ContextMenu.tsx | 364 +++++++++++++++--- .../detail/WorkflowComponents/Flow/index.tsx | 3 +- .../RenderInput/templates/SelectDataset.tsx | 2 +- .../templates/SelectDatasetParams.tsx | 2 +- .../context/workflowStatusContext.tsx | 117 ++++-- .../dashboard/mcp/EditModal.tsx | 26 +- .../pageComponents/dataset/detail/Test.tsx | 2 +- .../src/pageComponents/price/ExtraPlan.tsx | 113 +++--- .../app/src/pageComponents/price/Standard.tsx | 14 +- projects/app/src/pages/account/info/index.tsx | 30 +- projects/app/src/pages/account/team/index.tsx | 23 +- projects/app/src/pages/api/admin/initv471.ts | 2 +- projects/app/src/pages/api/admin/initv4823.ts | 2 +- projects/app/src/pages/api/admin/initv490.ts | 4 +- .../app/src/pages/api/admin/resetMilvus.ts | 4 +- .../app/src/pages/api/core/chat/chatTest.ts | 77 ++-- .../api/core/chat/getPaginationRecords.ts | 6 +- .../api/core/dataset/collection/detail.ts | 3 +- .../src/pages/api/core/dataset/searchTest.ts | 39 +- .../pages/api/support/mcp/client/getTools.ts | 11 +- .../pages/api/support/mcp/client/runTool.ts | 11 +- .../pages/api/support/mcp/server/toolCall.ts | 54 +-- .../pages/api/support/mcp/server/toolList.ts | 15 +- .../src/pages/api/v1/audio/transcriptions.ts | 11 +- .../app/src/pages/api/v1/chat/completions.ts | 83 ++-- .../app/src/pages/api/v2/chat/completions.ts | 88 ++--- .../app/src/service/common/system/cronTask.ts | 2 +- .../app/src/service/common/system/index.ts | 8 +- projects/app/src/service/core/app/utils.ts | 57 +-- .../service/core/dataset/data/controller.ts | 4 +- .../app/src/service/events/generateVector.ts | 2 +- .../src/service/support/wallet/usage/push.ts | 36 ++ projects/app/src/web/common/api/fetch.ts | 14 +- .../app/src/web/common/hooks/useSpeech.ts | 27 +- projects/app/src/web/common/utils/eventbus.ts | 3 +- projects/app/src/web/support/user/team/api.ts | 3 + .../app/src/web/support/wallet/bill/api.ts | 33 +- test/cases/global/core/chat/utils.test.ts | 49 +-- .../api/support/mcp/server/toolList.test.ts | 107 +---- test/datas/users.ts | 1 + test/mocks/request.ts | 1 + vitest.config.mts | 2 +- 143 files changed, 2067 insertions(+), 1093 deletions(-) create mode 100644 packages/global/support/wallet/sub/coupon/type.d.ts rename packages/service/common/{vectorStore => vectorDB}/constants.ts (100%) rename packages/service/common/{vectorStore => vectorDB}/controller.d.ts (100%) rename packages/service/common/{vectorStore => vectorDB}/controller.ts (94%) rename packages/service/common/{vectorStore/milvus/class.ts => vectorDB/milvus/index.ts} (99%) rename packages/service/common/{vectorStore/oceanbase/index.ts => vectorDB/oceanbase/controller.ts} (100%) rename packages/service/common/{vectorStore/oceanbase/class.ts => vectorDB/oceanbase/index.ts} (98%) rename packages/service/common/{vectorStore/pg/index.ts => vectorDB/pg/controller.ts} (100%) rename packages/service/common/{vectorStore/pg/class.ts => vectorDB/pg/index.ts} (99%) rename packages/service/common/{vectorStore => vectorDB}/type.d.ts (100%) create mode 100644 packages/service/support/wallet/coupon/schema.ts create mode 100644 packages/web/components/common/Icon/icons/alignLeft.svg create mode 100644 packages/web/components/common/Icon/icons/common/alipay.svg create mode 100644 packages/web/components/common/Icon/icons/common/wechat.svg create mode 100644 packages/web/components/common/Icon/icons/support/account/coupon.svg create mode 100644 projects/app/public/imgs/modal/wallet.svg create mode 100644 projects/app/src/pageComponents/account/info/RedeemCouponModal.tsx diff --git a/docSite/content/zh-cn/docs/development/upgrading/497.md b/docSite/content/zh-cn/docs/development/upgrading/497.md index e716214cc..6b966525b 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/497.md +++ b/docSite/content/zh-cn/docs/development/upgrading/497.md @@ -9,11 +9,21 @@ weight: 793 ## 🚀 新增内容 +1. MCP 工具支持 HTTP Streamable 协议。 +2. MCP server 支持编辑工具名,适配部分客户端不支持中文名问题。 +3. 工作流右键可自动对齐节点。 +4. 支持生产环境自定义`config.json`路径。 +5. API 调用,支持传递一个特殊 chatId(`NO_RECORD_HISTORIES`),使得系统不会进行历史记录存储。 +6. 支持 Rerank 模型按量计费。 +7. 套餐兑换码功能 +8. 支付宝支付 ## ⚙️ 优化 1. Doc2x 文档解析,增加报错信息捕获,增加超时时长。 2. 调整 PG vector 查询语句,强制使用向量索引。 +3. 对话时间统计,准确返回工作流整体运行时间。 +4. 从 ai_proxy 获取音频解析时长。 ## 🐛 修复 @@ -21,8 +31,10 @@ weight: 793 2. 使用记录仪表盘,无法获取指定成员的使用统计。 3. 仪表盘接口,因未考虑时区问题,统计异常。 4. LLM 模型测试接口,无法测试未启用的 LLM。同时修复,模型测试接口会把模型自定义请求地址去除问题。 -5. 导出对话记录,限制单条对话记录消息上限 1000 组,避免导出失败。 -6. 工作流变量下一段文本仍是工作流变量,不触发渲染。 -7. 调试知识库检索模块,提示无权操作知识库。 -8. 文本内容提取节点,默认值赋值逻辑。 +5. Copy app 权限问题。 +6. 导出对话记录,限制单条对话记录消息上限 1000 组,避免导出失败。 +7. 工作流变量下一段文本仍是工作流变量,不触发渲染。 +8. 调试知识库检索模块,提示无权操作知识库。 +9. 文本内容提取节点,默认值赋值逻辑。 +10. 分享链接中,会强制返回嵌套应用中的引用内容。 diff --git a/env.d.ts b/env.d.ts index 6492948b4..1430a3a44 100644 --- a/env.d.ts +++ b/env.d.ts @@ -23,16 +23,18 @@ declare global { FE_DOMAIN: string; FILE_DOMAIN: string; NEXT_PUBLIC_BASE_URL: string; - LOG_LEVEL: string; - STORE_LOG_LEVEL: string; - USE_IP_LIMIT: string; - WORKFLOW_MAX_RUN_TIMES: string; - WORKFLOW_MAX_LOOP_TIMES: string; - CHECK_INTERNAL_IP: string; - CHAT_LOG_URL: string; - CHAT_LOG_INTERVAL: string; - CHAT_LOG_SOURCE_ID_PREFIX: string; - ALLOWED_ORIGINS: string; + LOG_LEVEL?: string; + STORE_LOG_LEVEL?: string; + USE_IP_LIMIT?: string; + WORKFLOW_MAX_RUN_TIMES?: string; + WORKFLOW_MAX_LOOP_TIMES?: string; + CHECK_INTERNAL_IP?: string; + CHAT_LOG_URL?: string; + CHAT_LOG_INTERVAL?: string; + CHAT_LOG_SOURCE_ID_PREFIX?: string; + ALLOWED_ORIGINS?: string; + SHOW_COUPON?: string; + CONFIG_JSON_PATH?: string; } } } diff --git a/packages/global/common/system/types/index.d.ts b/packages/global/common/system/types/index.d.ts index 861ff74d9..102188f85 100644 --- a/packages/global/common/system/types/index.d.ts +++ b/packages/global/common/system/types/index.d.ts @@ -60,6 +60,7 @@ export type FastGPTFeConfigsType = { show_team_chat?: boolean; show_compliance_copywriting?: boolean; show_aiproxy?: boolean; + show_coupon?: boolean; concatMd?: string; concatMd?: string; @@ -106,6 +107,12 @@ export type FastGPTFeConfigsType = { lafEnv?: string; navbarItems?: NavbarItemType[]; externalProviderWorkflowVariables?: ExternalProviderWorkflowVarType[]; + + payConfig?: { + wx?: boolean; + alipay?: boolean; + bank?: boolean; + }; }; export type SystemEnvType = { diff --git a/packages/global/core/app/utils.ts b/packages/global/core/app/utils.ts index 92e1d1dc8..ddbcaaed8 100644 --- a/packages/global/core/app/utils.ts +++ b/packages/global/core/app/utils.ts @@ -26,7 +26,7 @@ export const getDefaultAppForm = (): AppSimpleEditFormType => { similarity: 0.4, limit: 3000, searchMode: DatasetSearchModeEnum.embedding, - usingReRank: false, + usingReRank: true, rerankModel: '', rerankWeight: 0.5, datasetSearchUsingExtensionQuery: true, diff --git a/packages/global/core/chat/type.d.ts b/packages/global/core/chat/type.d.ts index 8594a0c16..e7310a589 100644 --- a/packages/global/core/chat/type.d.ts +++ b/packages/global/core/chat/type.d.ts @@ -110,6 +110,7 @@ export type ChatItemSchema = (UserChatItemType | SystemChatItemType | AIChatItem tmbId: string; appId: string; time: Date; + durationSeconds?: number; }; export type AdminFbkType = { @@ -122,7 +123,6 @@ export type AdminFbkType = { /* --------- chat item ---------- */ export type ResponseTagItemType = { - totalRunningTime?: number; totalQuoteList?: SearchDataResponseItemType[]; llmModuleAccount?: number; historyPreviewLength?: number; @@ -141,6 +141,7 @@ export type ChatSiteItemType = (UserChatItemType | SystemChatItemType | AIChatIt ttsBuffer?: Uint8Array; responseData?: ChatHistoryItemResType[]; time?: Date; + durationSeconds?: number; } & ChatBoxInputType & ResponseTagItemType; diff --git a/packages/global/core/chat/utils.ts b/packages/global/core/chat/utils.ts index a946c7c10..5423d39ff 100644 --- a/packages/global/core/chat/utils.ts +++ b/packages/global/core/chat/utils.ts @@ -77,13 +77,6 @@ export const getHistoryPreview = ( }); }; -export const filterModuleTypeList: any[] = [ - FlowNodeTypeEnum.pluginModule, - FlowNodeTypeEnum.datasetSearchNode, - FlowNodeTypeEnum.tools, - FlowNodeTypeEnum.pluginOutput -]; - export const filterPublicNodeResponseData = ({ flowResponses = [], responseDetail = false @@ -91,12 +84,19 @@ export const filterPublicNodeResponseData = ({ flowResponses?: ChatHistoryItemResType[]; responseDetail?: boolean; }) => { + const publicNodeMap: Record = { + [FlowNodeTypeEnum.pluginModule]: true, + [FlowNodeTypeEnum.datasetSearchNode]: true, + [FlowNodeTypeEnum.tools]: true, + [FlowNodeTypeEnum.pluginOutput]: true + }; + const filedList = responseDetail ? ['quoteList', 'moduleType', 'pluginOutput', 'runningTime'] : ['moduleType', 'pluginOutput', 'runningTime']; return flowResponses - .filter((item) => filterModuleTypeList.includes(item.moduleType)) + .filter((item) => publicNodeMap[item.moduleType]) .map((item) => { const obj: DispatchNodeResponseType = {}; for (let key in item) { diff --git a/packages/global/core/workflow/runtime/constants.ts b/packages/global/core/workflow/runtime/constants.ts index 0293d0b0c..5c2859786 100644 --- a/packages/global/core/workflow/runtime/constants.ts +++ b/packages/global/core/workflow/runtime/constants.ts @@ -2,6 +2,7 @@ import { FlowNodeInputTypeEnum } from '../node/constant'; export enum SseResponseEventEnum { error = 'error', + workflowDuration = 'workflowDuration', // workflow duration answer = 'answer', // animation stream fastAnswer = 'fastAnswer', // direct answer text, not animation flowNodeStatus = 'flowNodeStatus', // update node status diff --git a/packages/global/core/workflow/runtime/type.d.ts b/packages/global/core/workflow/runtime/type.d.ts index be2885f10..6631cd297 100644 --- a/packages/global/core/workflow/runtime/type.d.ts +++ b/packages/global/core/workflow/runtime/type.d.ts @@ -24,6 +24,7 @@ import { AiChatQuoteRoleType } from '../template/system/aiChat/type'; import { LafAccountType, OpenaiAccountType } from '../../../support/user/team/type'; import { CompletionFinishReason } from '../../ai/type'; import { WorkflowInteractiveResponseType } from '../template/system/interactive/type'; +import { SearchDataResponseItemType } from '../../dataset/type'; export type ExternalProviderType = { openaiAccount?: OpenaiAccountType; externalWorkflowVariables?: Record; @@ -62,6 +63,8 @@ export type ChatDispatchProps = { workflowStreamResponse?: WorkflowResponseType; workflowDispatchDeep?: number; version?: 'v1' | 'v2'; + + responseAllData?: boolean; responseDetail?: boolean; }; @@ -136,12 +139,15 @@ export type DispatchNodeResponseType = { finishReason?: CompletionFinishReason; // dataset search + embeddingModel?: string; + embeddingTokens?: number; similarity?: number; limit?: number; searchMode?: `${DatasetSearchModeEnum}`; embeddingWeight?: number; rerankModel?: string; rerankWeight?: number; + reRankInputTokens?: number; searchUsingReRank?: boolean; queryExtensionResult?: { model: string; diff --git a/packages/global/support/mcp/type.d.ts b/packages/global/support/mcp/type.d.ts index 3575be1a0..f2d0b7770 100644 --- a/packages/global/support/mcp/type.d.ts +++ b/packages/global/support/mcp/type.d.ts @@ -9,7 +9,7 @@ export type McpKeyType = { export type McpAppType = { appId: string; + appName?: string; toolName: string; - toolAlias?: string; description: string; }; diff --git a/packages/global/support/operationLog/constants.ts b/packages/global/support/operationLog/constants.ts index 9052e79b7..6f3a00e97 100644 --- a/packages/global/support/operationLog/constants.ts +++ b/packages/global/support/operationLog/constants.ts @@ -4,6 +4,7 @@ export enum OperationLogEventEnum { JOIN_TEAM = 'JOIN_TEAM', CHANGE_MEMBER_NAME = 'CHANGE_MEMBER_NAME', KICK_OUT_TEAM = 'KICK_OUT_TEAM', + RECOVER_TEAM_MEMBER = 'RECOVER_TEAM_MEMBER', CREATE_DEPARTMENT = 'CREATE_DEPARTMENT', CHANGE_DEPARTMENT = 'CHANGE_DEPARTMENT', DELETE_DEPARTMENT = 'DELETE_DEPARTMENT', diff --git a/packages/global/support/wallet/bill/api.d.ts b/packages/global/support/wallet/bill/api.d.ts index 1e9bca452..e67332f9d 100644 --- a/packages/global/support/wallet/bill/api.d.ts +++ b/packages/global/support/wallet/bill/api.d.ts @@ -1,5 +1,11 @@ import { StandardSubLevelEnum, SubModeEnum } from '../sub/constants'; -import { BillTypeEnum } from './constants'; +import { BillTypeEnum, DrawBillQRItem } from './constants'; + +export type CreateOrderResponse = { + qrCode?: string; + iframeCode?: string; + markdown?: string; +}; export type CreateStandPlanBill = { type: BillTypeEnum.standSubPlan; @@ -22,6 +28,16 @@ export type CreateBillProps = export type CreateBillResponse = { billId: string; - codeUrl: string; readPrice: number; + payment: BillPayWayEnum; +} & CreateOrderResponse; + +export type UpdatePaymentProps = { + billId: string; + payWay: BillPayWayEnum; +}; + +export type CheckPayResultResponse = { + status: BillStatusEnum; + description?: string; }; diff --git a/packages/global/support/wallet/bill/constants.ts b/packages/global/support/wallet/bill/constants.ts index 1a02f59b4..9d68174cb 100644 --- a/packages/global/support/wallet/bill/constants.ts +++ b/packages/global/support/wallet/bill/constants.ts @@ -1,3 +1,5 @@ +import { i18nT } from '../../../../web/i18n/utils'; + export enum BillTypeEnum { balance = 'balance', standSubPlan = 'standSubPlan', @@ -6,16 +8,16 @@ export enum BillTypeEnum { } export const billTypeMap = { [BillTypeEnum.balance]: { - label: 'support.wallet.subscription.type.balance' + label: i18nT('common:support.wallet.subscription.type.balance') }, [BillTypeEnum.standSubPlan]: { - label: 'support.wallet.subscription.type.standard' + label: i18nT('common:support.wallet.subscription.type.standard') }, [BillTypeEnum.extraDatasetSub]: { - label: 'support.wallet.subscription.type.extraDatasetSize' + label: i18nT('common:support.wallet.subscription.type.extraDatasetSize') }, [BillTypeEnum.extraPoints]: { - label: 'support.wallet.subscription.type.extraPoints' + label: i18nT('common:support.wallet.subscription.type.extraPoints') } }; @@ -27,32 +29,46 @@ export enum BillStatusEnum { } export const billStatusMap = { [BillStatusEnum.SUCCESS]: { - label: 'support.wallet.bill.status.success' + label: i18nT('common:support.wallet.bill.status.success') }, [BillStatusEnum.REFUND]: { - label: 'support.wallet.bill.status.refund' + label: i18nT('common:support.wallet.bill.status.refund') }, [BillStatusEnum.NOTPAY]: { - label: 'support.wallet.bill.status.notpay' + label: i18nT('common:support.wallet.bill.status.notpay') }, [BillStatusEnum.CLOSED]: { - label: 'support.wallet.bill.status.closed' + label: i18nT('common:support.wallet.bill.status.closed') } }; export enum BillPayWayEnum { balance = 'balance', - wx = 'wx' + wx = 'wx', + alipay = 'alipay', + bank = 'bank', + coupon = 'coupon' } export const billPayWayMap = { [BillPayWayEnum.balance]: { - label: 'support.wallet.bill.payWay.balance' + label: i18nT('common:support.wallet.bill.payWay.balance') }, [BillPayWayEnum.wx]: { - label: 'support.wallet.bill.payWay.wx' + label: i18nT('common:support.wallet.bill.payWay.wx') + }, + [BillPayWayEnum.alipay]: { + label: i18nT('common:support.wallet.bill.payWay.alipay') + }, + [BillPayWayEnum.bank]: { + label: i18nT('common:support.wallet.bill.payWay.bank') + }, + [BillPayWayEnum.coupon]: { + label: i18nT('account_bill:payway_coupon') } }; export const SUB_DATASET_SIZE_RATE = 1000; export const SUB_EXTRA_POINT_RATE = 1000; +export const MAX_WX_PAY_AMOUNT = 6000; +export const QR_CODE_SIZE = 210; diff --git a/packages/global/support/wallet/bill/type.d.ts b/packages/global/support/wallet/bill/type.d.ts index 1a97e29c3..0b667d3ba 100644 --- a/packages/global/support/wallet/bill/type.d.ts +++ b/packages/global/support/wallet/bill/type.d.ts @@ -1,6 +1,7 @@ import { StandardSubLevelEnum, SubModeEnum, SubTypeEnum } from '../sub/constants'; -import { BillPayWayEnum, BillTypeEnum } from './constants'; +import { BillPayWayEnum, BillStatusEnum, BillTypeEnum } from './constants'; import { TeamInvoiceHeaderType } from '../../user/team/type'; + export type BillSchemaType = { _id: string; userId: string; @@ -8,7 +9,7 @@ export type BillSchemaType = { tmbId: string; createTime: Date; orderId: string; - status: 'SUCCESS' | 'REFUND' | 'NOTPAY' | 'CLOSED'; + status: `${BillStatusEnum}`; type: BillTypeEnum; price: number; hasInvoice: boolean; diff --git a/packages/global/support/wallet/sub/constants.ts b/packages/global/support/wallet/sub/constants.ts index 9072ae24f..32c5a2efe 100644 --- a/packages/global/support/wallet/sub/constants.ts +++ b/packages/global/support/wallet/sub/constants.ts @@ -1,4 +1,5 @@ import { i18nT } from '../../../../web/i18n/utils'; +import { BillTypeEnum } from '../bill/constants'; export enum SubTypeEnum { standard = 'standard', @@ -9,15 +10,18 @@ export enum SubTypeEnum { export const subTypeMap = { [SubTypeEnum.standard]: { label: 'support.wallet.subscription.type.standard', - icon: 'support/account/plans' + icon: 'support/account/plans', + orderType: BillTypeEnum.standSubPlan }, [SubTypeEnum.extraDatasetSize]: { label: 'support.wallet.subscription.type.extraDatasetSize', - icon: 'core/dataset/datasetLight' + icon: 'core/dataset/datasetLight', + orderType: BillTypeEnum.extraDatasetSub }, [SubTypeEnum.extraPoints]: { label: 'support.wallet.subscription.type.extraPoints', - icon: 'core/chat/chatLight' + icon: 'core/chat/chatLight', + orderType: BillTypeEnum.extraPoints } }; diff --git a/packages/global/support/wallet/sub/coupon/type.d.ts b/packages/global/support/wallet/sub/coupon/type.d.ts new file mode 100644 index 000000000..2753ed4e4 --- /dev/null +++ b/packages/global/support/wallet/sub/coupon/type.d.ts @@ -0,0 +1,16 @@ +import { SubTypeEnum, StandardSubLevelEnum } from '../constants'; + +export type TeamCouponSub = { + type: `${SubTypeEnum}`; // Sub type + durationDay: number; // Duration day + level?: `${StandardSubLevelEnum}`; // Standard sub level + extraDatasetSize?: number; // Extra dataset size + totalPoints?: number; // Total points(Extrapoints or Standard sub) +}; + +export type TeamCouponSchema = { + key: string; + subscriptions: TeamCouponSub[]; + redeemedAt?: Date; + expiredAt?: Date; +}; diff --git a/packages/global/support/wallet/sub/type.d.ts b/packages/global/support/wallet/sub/type.d.ts index 9054487e0..a3e1f92e5 100644 --- a/packages/global/support/wallet/sub/type.d.ts +++ b/packages/global/support/wallet/sub/type.d.ts @@ -15,7 +15,7 @@ export type TeamStandardSubPlanItemType = { permissionCustomApiKey: boolean; permissionCustomCopyright: boolean; // feature permissionWebsiteSync: boolean; - permissionReRank: boolean; + permissionTeamOperationLog: boolean; }; export type StandSubPlanLevelMapType = Record< diff --git a/packages/global/tsconfig.json b/packages/global/tsconfig.json index 718300055..6f5dee2ff 100644 --- a/packages/global/tsconfig.json +++ b/packages/global/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "baseUrl": "." }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts", "../service/core/app/mcp.ts"] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts"] } diff --git a/packages/service/common/system/timerLock/utils.ts b/packages/service/common/system/timerLock/utils.ts index 9662096f8..df50c79dc 100644 --- a/packages/service/common/system/timerLock/utils.ts +++ b/packages/service/common/system/timerLock/utils.ts @@ -1,3 +1,4 @@ +import { ClientSession } from '../../mongo'; import { MongoTimerLock } from './schema'; import { addMinutes } from 'date-fns'; @@ -6,16 +7,23 @@ import { addMinutes } from 'date-fns'; */ export const checkTimerLock = async ({ timerId, - lockMinuted + lockMinuted, + session }: { timerId: string; lockMinuted: number; + session?: ClientSession; }) => { try { - await MongoTimerLock.create({ - timerId, - expiredTime: addMinutes(new Date(), lockMinuted) - }); + await MongoTimerLock.create( + [ + { + timerId, + expiredTime: addMinutes(new Date(), lockMinuted) + } + ], + { session, ordered: true } + ); return true; } catch (error) { diff --git a/packages/service/common/vectorStore/constants.ts b/packages/service/common/vectorDB/constants.ts similarity index 100% rename from packages/service/common/vectorStore/constants.ts rename to packages/service/common/vectorDB/constants.ts diff --git a/packages/service/common/vectorStore/controller.d.ts b/packages/service/common/vectorDB/controller.d.ts similarity index 100% rename from packages/service/common/vectorStore/controller.d.ts rename to packages/service/common/vectorDB/controller.d.ts diff --git a/packages/service/common/vectorStore/controller.ts b/packages/service/common/vectorDB/controller.ts similarity index 94% rename from packages/service/common/vectorStore/controller.ts rename to packages/service/common/vectorDB/controller.ts index db4d7a00f..638d5f346 100644 --- a/packages/service/common/vectorStore/controller.ts +++ b/packages/service/common/vectorDB/controller.ts @@ -1,11 +1,11 @@ /* vector crud */ -import { PgVectorCtrl } from './pg/class'; -import { ObVectorCtrl } from './oceanbase/class'; +import { PgVectorCtrl } from './pg'; +import { ObVectorCtrl } from './oceanbase'; import { getVectorsByText } from '../../core/ai/embedding'; import { DelDatasetVectorCtrlProps, InsertVectorProps } from './controller.d'; import { EmbeddingModelItemType } from '@fastgpt/global/core/ai/model.d'; import { MILVUS_ADDRESS, PG_ADDRESS, OCEANBASE_ADDRESS } from './constants'; -import { MilvusCtrl } from './milvus/class'; +import { MilvusCtrl } from './milvus'; import { setRedisCache, getRedisCache, delRedisCache, CacheKeyEnum } from '../redis/cache'; import { throttle } from 'lodash'; import { retryFn } from '@fastgpt/global/common/system/utils'; diff --git a/packages/service/common/vectorStore/milvus/class.ts b/packages/service/common/vectorDB/milvus/index.ts similarity index 99% rename from packages/service/common/vectorStore/milvus/class.ts rename to packages/service/common/vectorDB/milvus/index.ts index e7f8c5425..4656134d4 100644 --- a/packages/service/common/vectorStore/milvus/class.ts +++ b/packages/service/common/vectorDB/milvus/index.ts @@ -12,7 +12,7 @@ import type { InsertVectorControllerProps } from '../controller.d'; import { delay } from '@fastgpt/global/common/system/utils'; -import { addLog } from '../../../common/system/log'; +import { addLog } from '../../system/log'; import { customNanoid } from '@fastgpt/global/common/string/tools'; export class MilvusCtrl { diff --git a/packages/service/common/vectorStore/oceanbase/index.ts b/packages/service/common/vectorDB/oceanbase/controller.ts similarity index 100% rename from packages/service/common/vectorStore/oceanbase/index.ts rename to packages/service/common/vectorDB/oceanbase/controller.ts diff --git a/packages/service/common/vectorStore/oceanbase/class.ts b/packages/service/common/vectorDB/oceanbase/index.ts similarity index 98% rename from packages/service/common/vectorStore/oceanbase/class.ts rename to packages/service/common/vectorDB/oceanbase/index.ts index 5d2e196a8..7b4c93aca 100644 --- a/packages/service/common/vectorStore/oceanbase/class.ts +++ b/packages/service/common/vectorDB/oceanbase/index.ts @@ -1,8 +1,8 @@ /* oceanbase vector crud */ import { DatasetVectorTableName } from '../constants'; import { delay } from '@fastgpt/global/common/system/utils'; -import { ObClient } from './index'; -import { RowDataPacket, ResultSetHeader } from 'mysql2/promise'; +import { ObClient } from './controller'; +import { RowDataPacket } from 'mysql2/promise'; import { DelDatasetVectorCtrlProps, EmbeddingRecallCtrlProps, diff --git a/packages/service/common/vectorStore/pg/index.ts b/packages/service/common/vectorDB/pg/controller.ts similarity index 100% rename from packages/service/common/vectorStore/pg/index.ts rename to packages/service/common/vectorDB/pg/controller.ts diff --git a/packages/service/common/vectorStore/pg/class.ts b/packages/service/common/vectorDB/pg/index.ts similarity index 99% rename from packages/service/common/vectorStore/pg/class.ts rename to packages/service/common/vectorDB/pg/index.ts index cb18440e9..26999717c 100644 --- a/packages/service/common/vectorStore/pg/class.ts +++ b/packages/service/common/vectorDB/pg/index.ts @@ -1,9 +1,9 @@ /* pg vector crud */ import { DatasetVectorTableName } from '../constants'; import { delay } from '@fastgpt/global/common/system/utils'; -import { PgClient, connectPg } from './index'; +import { PgClient, connectPg } from './controller'; import { PgSearchRawType } from '@fastgpt/global/core/dataset/api'; -import { +import type { DelDatasetVectorCtrlProps, EmbeddingRecallCtrlProps, EmbeddingRecallResponse, diff --git a/packages/service/common/vectorStore/type.d.ts b/packages/service/common/vectorDB/type.d.ts similarity index 100% rename from packages/service/common/vectorStore/type.d.ts rename to packages/service/common/vectorDB/type.d.ts diff --git a/packages/service/core/ai/audio/transcriptions.ts b/packages/service/core/ai/audio/transcriptions.ts index 4cf7dc70f..e13ea2e74 100644 --- a/packages/service/core/ai/audio/transcriptions.ts +++ b/packages/service/core/ai/audio/transcriptions.ts @@ -2,7 +2,6 @@ import fs from 'fs'; import { getAxiosConfig } from '../config'; import axios from 'axios'; import FormData from 'form-data'; -import { getSTTModel } from '../model'; import { STTModelType } from '@fastgpt/global/core/ai/model.d'; export const aiTranscriptions = async ({ @@ -24,7 +23,7 @@ export const aiTranscriptions = async ({ const aiAxiosConfig = getAxiosConfig(); - const { data: result } = await axios<{ text: string }>({ + const { data: result } = await axios<{ text: string; usage?: { total_tokens: number } }>({ method: 'post', ...(modelData.requestUrl ? { url: modelData.requestUrl } diff --git a/packages/service/core/ai/rerank/index.ts b/packages/service/core/ai/rerank/index.ts index 2811f7086..91f2e981e 100644 --- a/packages/service/core/ai/rerank/index.ts +++ b/packages/service/core/ai/rerank/index.ts @@ -3,6 +3,7 @@ import { POST } from '../../../common/api/serverRequest'; import { getDefaultRerankModel } from '../model'; import { getAxiosConfig } from '../config'; import { RerankModelItemType } from '@fastgpt/global/core/ai/model.d'; +import { countPromptTokens } from '../../../common/string/tiktoken'; type PostReRankResponse = { id: string; @@ -10,8 +11,17 @@ type PostReRankResponse = { index: number; relevance_score: number; }[]; + meta?: { + tokens: { + input_tokens: number; + output_tokens: number; + }; + }; +}; +type ReRankCallResult = { + results: { id: string; score?: number }[]; + inputTokens: number; }; -type ReRankCallResult = { id: string; score?: number }[]; export function reRankRecall({ model = getDefaultRerankModel(), @@ -28,18 +38,22 @@ export function reRankRecall({ return Promise.reject('no rerank model'); } if (documents.length === 0) { - return Promise.resolve([]); + return Promise.resolve({ + results: [], + inputTokens: 0 + }); } const { baseUrl, authorization } = getAxiosConfig(); let start = Date.now(); + const documentsTextArray = documents.map((doc) => doc.text); return POST( model.requestUrl ? model.requestUrl : `${baseUrl}/rerank`, { model: model.model, query, - documents: documents.map((doc) => doc.text) + documents: documentsTextArray }, { headers: { @@ -49,17 +63,22 @@ export function reRankRecall({ timeout: 30000 } ) - .then((data) => { + .then(async (data) => { addLog.info('ReRank finish:', { time: Date.now() - start }); if (!data?.results || data?.results?.length === 0) { addLog.error('ReRank error, empty result', data); } - return data?.results?.map((item) => ({ - id: documents[item.index].id, - score: item.relevance_score - })); + return { + results: data?.results?.map((item) => ({ + id: documents[item.index].id, + score: item.relevance_score + })), + inputTokens: + data?.meta?.tokens?.input_tokens || + (await countPromptTokens(documentsTextArray.join('\n') + query, '')) + }; }) .catch((err) => { addLog.error('rerank error', err); diff --git a/packages/service/core/app/mcp.ts b/packages/service/core/app/mcp.ts index c8f643ae7..0deb0686e 100644 --- a/packages/service/core/app/mcp.ts +++ b/packages/service/core/app/mcp.ts @@ -2,50 +2,38 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'; import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; import { ToolType } from '@fastgpt/global/core/app/type'; +import { addLog } from '../../common/system/log'; +import { retryFn } from '@fastgpt/global/common/system/utils'; export class MCPClient { - private client: Client | null = null; + private client: Client; private url: string; constructor(config: { url: string }) { this.url = config.url; + this.client = new Client({ + name: 'FastGPT-MCP-client', + version: '1.0.0' + }); } private async getConnection(): Promise { - if (this.client) { - return this.client; - } - try { - const client = new Client({ - name: 'FastGPT-MCP-http-client', - version: '1.0.0' - }); const transport = new StreamableHTTPClientTransport(new URL(this.url)); - await client.connect(transport); - this.client = client; - return client; + await this.client.connect(transport); + return this.client; } catch (error) { - const client = new Client({ - name: 'FastGPT-MCP-sse-client', - version: '1.0.0' - }); - const sseTransport = new SSEClientTransport(new URL(this.url)); - await client.connect(sseTransport); - this.client = client; - return client; + await this.client.connect(new SSEClientTransport(new URL(this.url))); + return this.client; } } // 内部方法:关闭连接 private async closeConnection() { - if (this.client) { - try { - await this.client.close(); - this.client = null; - } catch (error) { - console.error('Failed to close MCP client:', error); - } + try { + await retryFn(() => this.client.close(), 3); + } catch (error) { + addLog.error('[MCP Client] Failed to close connection:', error); } } @@ -58,7 +46,11 @@ export class MCPClient { const client = await this.getConnection(); const response = await client.listTools(); - const tools = (response.tools || []).map((tool: any) => ({ + if (!Array.isArray(response.tools)) { + return Promise.reject('[MCP Client] Get tools response is not an array'); + } + + const tools = response.tools.map((tool) => ({ name: tool.name, description: tool.description || '', inputSchema: tool.inputSchema || { @@ -67,9 +59,10 @@ export class MCPClient { } })); + // @ts-ignore return tools; } catch (error) { - console.error('Failed to get MCP tools:', error); + addLog.error('[MCP Client] Failed to get tools:', error); return Promise.reject(error); } finally { await this.closeConnection(); @@ -85,28 +78,17 @@ export class MCPClient { public async toolCall(toolName: string, params: Record): Promise { try { const client = await this.getConnection(); - console.log(`Call tool: ${toolName}`, params); + addLog.debug(`[MCP Client] Call tool: ${toolName}`, params); - const result = await client.callTool({ + return await client.callTool({ name: toolName, arguments: params }); - - return result; } catch (error) { - console.error(`Failed to call tool ${toolName}:`, error); + addLog.error(`[MCP Client] Failed to call tool ${toolName}:`, error); return Promise.reject(error); } finally { await this.closeConnection(); } } } - -/** - * Create MCP client - * @param config Client configuration, containing url - * @returns MCPClient instance - */ -export default function getMCPClient(config: { url: string }): MCPClient { - return new MCPClient(config); -} diff --git a/packages/service/core/chat/chatItemSchema.ts b/packages/service/core/chat/chatItemSchema.ts index a18065330..a69211eb1 100644 --- a/packages/service/core/chat/chatItemSchema.ts +++ b/packages/service/core/chat/chatItemSchema.ts @@ -82,7 +82,8 @@ const ChatItemSchema = new Schema({ [DispatchNodeResponseKeyEnum.nodeResponse]: { type: Array, default: [] - } + }, + durationSeconds: Number }); try { diff --git a/packages/service/core/chat/saveChat.ts b/packages/service/core/chat/saveChat.ts index 685ea2250..0a56edec5 100644 --- a/packages/service/core/chat/saveChat.ts +++ b/packages/service/core/chat/saveChat.ts @@ -34,6 +34,7 @@ type Props = { outLinkUid?: string; content: [UserChatItemType & { dataId?: string }, AIChatItemType & { dataId?: string }]; metadata?: Record; + durationSeconds: number; //s }; export async function saveChat({ @@ -51,8 +52,11 @@ export async function saveChat({ shareId, outLinkUid, content, + durationSeconds, metadata = {} }: Props) { + if (!chatId || chatId === 'NO_RECORD_HISTORIES') return; + try { const chat = await MongoChat.findOne( { @@ -78,34 +82,33 @@ export async function saveChat({ // Format save chat content: Remove quote q/a const processedContent = content.map((item) => { if (item.obj === ChatRoleEnum.AI) { - const nodeResponse = item[DispatchNodeResponseKeyEnum.nodeResponse]; + const nodeResponse = item[DispatchNodeResponseKeyEnum.nodeResponse]?.map((responseItem) => { + if ( + responseItem.moduleType === FlowNodeTypeEnum.datasetSearchNode && + responseItem.quoteList + ) { + return { + ...responseItem, + quoteList: responseItem.quoteList.map((quote: any) => ({ + id: quote.id, + chunkIndex: quote.chunkIndex, + datasetId: quote.datasetId, + collectionId: quote.collectionId, + sourceId: quote.sourceId, + sourceName: quote.sourceName, + score: quote.score, + tokens: quote.tokens + })) + }; + } + return responseItem; + }); - if (nodeResponse) { - return { - ...item, - [DispatchNodeResponseKeyEnum.nodeResponse]: nodeResponse.map((responseItem) => { - if ( - responseItem.moduleType === FlowNodeTypeEnum.datasetSearchNode && - responseItem.quoteList - ) { - return { - ...responseItem, - quoteList: responseItem.quoteList.map((quote: any) => ({ - id: quote.id, - chunkIndex: quote.chunkIndex, - datasetId: quote.datasetId, - collectionId: quote.collectionId, - sourceId: quote.sourceId, - sourceName: quote.sourceName, - score: quote.score, - tokens: quote.tokens - })) - }; - } - return responseItem; - }) - }; - } + return { + ...item, + [DispatchNodeResponseKeyEnum.nodeResponse]: nodeResponse, + durationSeconds + }; } return item; }); @@ -175,13 +178,15 @@ export const updateInteractiveChat = async ({ appId, userInteractiveVal, aiResponse, - newVariables + newVariables, + durationSeconds }: { chatId: string; appId: string; userInteractiveVal: string; aiResponse: AIChatItemType & { dataId?: string }; newVariables?: Record; + durationSeconds: number; }) => { if (!chatId) return; @@ -246,6 +251,10 @@ export const updateInteractiveChat = async ({ chatItem.value = chatItem.value ? [...chatItem.value, ...aiResponse.value] : aiResponse.value; } + chatItem.durationSeconds = chatItem.durationSeconds + ? +(chatItem.durationSeconds + durationSeconds).toFixed(2) + : durationSeconds; + await mongoSessionRun(async (session) => { await chatItem.save({ session }); await MongoChat.updateOne( diff --git a/packages/service/core/dataset/collection/controller.ts b/packages/service/core/dataset/collection/controller.ts index 14c1c0bcd..079483019 100644 --- a/packages/service/core/dataset/collection/controller.ts +++ b/packages/service/core/dataset/collection/controller.ts @@ -9,7 +9,7 @@ import { DatasetCollectionSchemaType, DatasetSchemaType } from '@fastgpt/global/ import { MongoDatasetTraining } from '../training/schema'; import { MongoDatasetData } from '../data/schema'; import { delImgByRelatedId } from '../../../common/file/image/controller'; -import { deleteDatasetDataVector } from '../../../common/vectorStore/controller'; +import { deleteDatasetDataVector } from '../../../common/vectorDB/controller'; import { delFileByFileIdList } from '../../../common/file/gridfs/controller'; import { BucketNameEnum } from '@fastgpt/global/common/file/constants'; import { ClientSession } from '../../../common/mongo'; diff --git a/packages/service/core/dataset/controller.ts b/packages/service/core/dataset/controller.ts index 6cda361ac..ac09c3ec0 100644 --- a/packages/service/core/dataset/controller.ts +++ b/packages/service/core/dataset/controller.ts @@ -5,7 +5,7 @@ import { delCollectionRelatedSource } from './collection/controller'; import { ClientSession } from '../../common/mongo'; import { MongoDatasetTraining } from './training/schema'; import { MongoDatasetData } from './data/schema'; -import { deleteDatasetDataVector } from '../../common/vectorStore/controller'; +import { deleteDatasetDataVector } from '../../common/vectorDB/controller'; import { MongoDatasetDataText } from './data/dataTextSchema'; import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset'; import { retryFn } from '@fastgpt/global/common/system/utils'; diff --git a/packages/service/core/dataset/search/controller.ts b/packages/service/core/dataset/search/controller.ts index 1b13db592..61ea515ce 100644 --- a/packages/service/core/dataset/search/controller.ts +++ b/packages/service/core/dataset/search/controller.ts @@ -3,7 +3,7 @@ import { DatasetSearchModeMap, SearchScoreTypeEnum } from '@fastgpt/global/core/dataset/constants'; -import { recallFromVectorStore } from '../../../common/vectorStore/controller'; +import { recallFromVectorStore } from '../../../common/vectorDB/controller'; import { getVectorsByText } from '../../ai/embedding'; import { getEmbeddingModel, getDefaultRerankModel, getLLMModel } from '../../ai/model'; import { MongoDatasetData } from '../data/schema'; @@ -62,7 +62,8 @@ export type SearchDatasetDataProps = { export type SearchDatasetDataResponse = { searchRes: SearchDataResponseItemType[]; - tokens: number; + embeddingTokens: number; + reRankInputTokens: number; searchMode: `${DatasetSearchModeEnum}`; limit: number; similarity: number; @@ -86,8 +87,11 @@ export const datasetDataReRank = async ({ rerankModel?: RerankModelItemType; data: SearchDataResponseItemType[]; query: string; -}): Promise => { - const results = await reRankRecall({ +}): Promise<{ + results: SearchDataResponseItemType[]; + inputTokens: number; +}> => { + const { results, inputTokens } = await reRankRecall({ model: rerankModel, query, documents: data.map((item) => ({ @@ -114,7 +118,10 @@ export const datasetDataReRank = async ({ }) .filter(Boolean) as SearchDataResponseItemType[]; - return mergeResult; + return { + results: mergeResult, + inputTokens + }; }; export const filterDatasetDataByMaxTokens = async ( data: SearchDataResponseItemType[], @@ -694,14 +701,23 @@ export async function searchDatasetData( const { embeddingLimit, fullTextLimit } = countRecallLimit(); // recall - const { embeddingRecallResults, fullTextRecallResults, tokens } = await multiQueryRecall({ + const { + embeddingRecallResults, + fullTextRecallResults, + tokens: embeddingTokens + } = await multiQueryRecall({ embeddingLimit, fullTextLimit }); // ReRank results - const reRankResults = await (async () => { - if (!usingReRank) return []; + const { results: reRankResults, inputTokens: reRankInputTokens } = await (async () => { + if (!usingReRank) { + return { + results: [], + inputTokens: 0 + }; + } set = new Set(embeddingRecallResults.map((item) => item.id)); const concatRecallResults = embeddingRecallResults.concat( @@ -725,7 +741,10 @@ export async function searchDatasetData( }); } catch (error) { usingReRank = false; - return []; + return { + results: [], + inputTokens: 0 + }; } })(); @@ -790,7 +809,8 @@ export async function searchDatasetData( return { searchRes: filterMaxTokensResult, - tokens, + embeddingTokens, + reRankInputTokens, searchMode, limit: maxTokens, similarity, diff --git a/packages/service/core/workflow/dispatch/dataset/search.ts b/packages/service/core/workflow/dispatch/dataset/search.ts index 3d3996240..82473e2ff 100644 --- a/packages/service/core/workflow/dispatch/dataset/search.ts +++ b/packages/service/core/workflow/dispatch/dataset/search.ts @@ -12,7 +12,6 @@ import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workfl import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants'; import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants'; import { ChatNodeUsageType } from '@fastgpt/global/support/wallet/bill/type'; -import { checkTeamReRankPermission } from '../../../../support/permission/teamLimit'; import { MongoDataset } from '../../../dataset/schema'; import { i18nT } from '../../../../../web/i18n/utils'; import { filterDatasetsByTmbId } from '../../../dataset/utils'; @@ -119,6 +118,8 @@ export async function dispatchDatasetSearch( const vectorModel = getEmbeddingModel( (await MongoDataset.findById(datasets[0].datasetId, 'vectorModel').lean())?.vectorModel ); + // Get Rerank Model + const rerankModelData = getRerankModel(rerankModel); // start search const searchData = { @@ -132,14 +133,15 @@ export async function dispatchDatasetSearch( datasetIds, searchMode, embeddingWeight, - usingReRank: usingReRank && (await checkTeamReRankPermission(teamId)), - rerankModel: getRerankModel(rerankModel), + usingReRank, + rerankModel: rerankModelData, rerankWeight, collectionFilterMatch }; const { searchRes, - tokens, + embeddingTokens, + reRankInputTokens, usingSimilarityFilter, usingReRank: searchUsingReRank, queryExtensionResult, @@ -164,17 +166,29 @@ export async function dispatchDatasetSearch( const { totalPoints: embeddingTotalPoints, modelName: embeddingModelName } = formatModelChars2Points({ model: vectorModel.model, - inputTokens: tokens, + inputTokens: embeddingTokens, modelType: ModelTypeEnum.embedding }); nodeDispatchUsages.push({ totalPoints: embeddingTotalPoints, moduleName: node.name, model: embeddingModelName, - inputTokens: tokens + inputTokens: embeddingTokens + }); + // Rerank + const { totalPoints: reRankTotalPoints, modelName: reRankModelName } = formatModelChars2Points({ + model: rerankModelData.model, + inputTokens: reRankInputTokens, + modelType: ModelTypeEnum.rerank + }); + nodeDispatchUsages.push({ + totalPoints: reRankTotalPoints, + moduleName: node.name, + model: reRankModelName, + inputTokens: reRankInputTokens }); // Query extension - const { totalPoints: queryExtensionTotalPoints } = (() => { + (() => { if (queryExtensionResult) { const { totalPoints, modelName } = formatModelChars2Points({ model: queryExtensionResult.model, @@ -198,7 +212,7 @@ export async function dispatchDatasetSearch( }; })(); // Deep search - const { totalPoints: deepSearchTotalPoints } = (() => { + (() => { if (deepSearchResult) { const { totalPoints, modelName } = formatModelChars2Points({ model: deepSearchResult.model, @@ -221,20 +235,26 @@ export async function dispatchDatasetSearch( totalPoints: 0 }; })(); - const totalPoints = embeddingTotalPoints + queryExtensionTotalPoints + deepSearchTotalPoints; + + const totalPoints = nodeDispatchUsages.reduce((acc, item) => acc + item.totalPoints, 0); const responseData: DispatchNodeResponseType & { totalPoints: number } = { totalPoints, query: userChatInput, - model: vectorModel.model, - inputTokens: tokens, + embeddingModel: vectorModel.name, + embeddingTokens, similarity: usingSimilarityFilter ? similarity : undefined, limit, searchMode, embeddingWeight: searchMode === DatasetSearchModeEnum.mixedRecall ? embeddingWeight : undefined, - rerankModel: usingReRank ? getRerankModel(rerankModel)?.name : undefined, - rerankWeight: usingReRank ? rerankWeight : undefined, - searchUsingReRank: searchUsingReRank, + // Rerank + ...(searchUsingReRank && { + rerankModel: rerankModelData?.name, + rerankWeight: rerankWeight, + reRankInputTokens + }), + searchUsingReRank, + // Results quoteList: searchRes, queryExtensionResult, deepSearchResult diff --git a/packages/service/core/workflow/dispatch/index.ts b/packages/service/core/workflow/dispatch/index.ts index ef1e819ce..df421b0f7 100644 --- a/packages/service/core/workflow/dispatch/index.ts +++ b/packages/service/core/workflow/dispatch/index.ts @@ -74,7 +74,7 @@ import { dispatchLoopStart } from './loop/runLoopStart'; import { dispatchFormInput } from './interactive/formInput'; import { dispatchToolParams } from './agent/runTool/toolParams'; import { getErrText } from '@fastgpt/global/common/error/utils'; -import { filterModuleTypeList } from '@fastgpt/global/core/chat/utils'; +import { filterPublicNodeResponseData } from '@fastgpt/global/core/chat/utils'; import { dispatchRunTool } from './plugin/runTool'; const callbackMap: Record = { @@ -137,8 +137,10 @@ export async function dispatchWorkFlow(data: Props): Promise res.end()); + res.on('error', () => { + addLog.error('Request error'); + res.end(); + }); + res.setHeader('Content-Type', 'text/event-stream;charset=utf-8'); res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('X-Accel-Buffering', 'no'); @@ -191,13 +201,14 @@ export async function dispatchWorkFlow(data: Props): Promise; type RunToolResponse = DispatchNodeResultType<{ - [NodeOutputKeyEnum.rawResponse]: any; + [NodeOutputKeyEnum.rawResponse]?: any; }>; export const dispatchRunTool = async (props: RunToolProps): Promise => { @@ -26,7 +27,7 @@ export const dispatchRunTool = async (props: RunToolProps): Promise; + durationSeconds: number; }; export type WorkflowResponseType = ({ diff --git a/packages/service/support/mcp/schema.ts b/packages/service/support/mcp/schema.ts index 942abd179..005ed78e7 100644 --- a/packages/service/support/mcp/schema.ts +++ b/packages/service/support/mcp/schema.ts @@ -38,14 +38,14 @@ const McpKeySchema = new Schema({ ref: AppCollectionName, required: true }, + appName: String, toolName: { - type: String - }, - toolAlias: { - type: String + type: String, + required: true }, description: { - type: String + type: String, + required: true } } ], diff --git a/packages/service/support/operationLog/addOperationLog.ts b/packages/service/support/operationLog/addOperationLog.ts index af692b7ca..53fb51754 100644 --- a/packages/service/support/operationLog/addOperationLog.ts +++ b/packages/service/support/operationLog/addOperationLog.ts @@ -14,7 +14,6 @@ export function addOperationLog({ event: T; params?: TemplateParamsMap[T]; }) { - console.log('Insert log'); retryFn(() => MongoOperationLog.create({ tmbId: tmbId, diff --git a/packages/service/support/operationLog/constants.ts b/packages/service/support/operationLog/constants.ts index 4f20a5b3a..20925d105 100644 --- a/packages/service/support/operationLog/constants.ts +++ b/packages/service/support/operationLog/constants.ts @@ -1,85 +1,74 @@ import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants'; import { i18nT } from '../../../web/i18n/utils'; -export const operationLogI18nMap = { +export const operationLogMap = { [OperationLogEventEnum.LOGIN]: { content: i18nT('account_team:log_login'), - typeLabel: i18nT('account_team:login') + typeLabel: i18nT('account_team:login'), + params: {} as { name?: string } }, [OperationLogEventEnum.CREATE_INVITATION_LINK]: { content: i18nT('account_team:log_create_invitation_link'), - typeLabel: i18nT('account_team:create_invitation_link') + typeLabel: i18nT('account_team:create_invitation_link'), + params: {} as { name?: string; link: string } }, [OperationLogEventEnum.JOIN_TEAM]: { content: i18nT('account_team:log_join_team'), - typeLabel: i18nT('account_team:join_team') + typeLabel: i18nT('account_team:join_team'), + params: {} as { name?: string; link: string } }, [OperationLogEventEnum.CHANGE_MEMBER_NAME]: { content: i18nT('account_team:log_change_member_name'), - typeLabel: i18nT('account_team:change_member_name') + typeLabel: i18nT('account_team:change_member_name'), + params: {} as { name?: string; memberName: string; newName: string } }, [OperationLogEventEnum.KICK_OUT_TEAM]: { content: i18nT('account_team:log_kick_out_team'), - typeLabel: i18nT('account_team:kick_out_team') + typeLabel: i18nT('account_team:kick_out_team'), + params: {} as { name?: string; memberName: string } + }, + [OperationLogEventEnum.RECOVER_TEAM_MEMBER]: { + content: i18nT('account_team:log_recover_team_member'), + typeLabel: i18nT('account_team:recover_team_member'), + params: {} as { name?: string; memberName: string } }, [OperationLogEventEnum.CREATE_DEPARTMENT]: { content: i18nT('account_team:log_create_department'), - typeLabel: i18nT('account_team:create_department') + typeLabel: i18nT('account_team:create_department'), + params: {} as { name?: string; departmentName: string } }, [OperationLogEventEnum.CHANGE_DEPARTMENT]: { content: i18nT('account_team:log_change_department'), - typeLabel: i18nT('account_team:change_department_name') + typeLabel: i18nT('account_team:change_department_name'), + params: {} as { name?: string; departmentName: string } }, [OperationLogEventEnum.DELETE_DEPARTMENT]: { content: i18nT('account_team:log_delete_department'), - typeLabel: i18nT('account_team:delete_department') + typeLabel: i18nT('account_team:delete_department'), + params: {} as { name?: string; departmentName: string } }, [OperationLogEventEnum.RELOCATE_DEPARTMENT]: { content: i18nT('account_team:log_relocate_department'), - typeLabel: i18nT('account_team:relocate_department') + typeLabel: i18nT('account_team:relocate_department'), + params: {} as { name?: string; departmentName: string } }, [OperationLogEventEnum.CREATE_GROUP]: { content: i18nT('account_team:log_create_group'), - typeLabel: i18nT('account_team:create_group') + typeLabel: i18nT('account_team:create_group'), + params: {} as { name?: string; groupName: string } }, [OperationLogEventEnum.DELETE_GROUP]: { content: i18nT('account_team:log_delete_group'), - typeLabel: i18nT('account_team:delete_group') + typeLabel: i18nT('account_team:delete_group'), + params: {} as { name?: string; groupName: string } }, [OperationLogEventEnum.ASSIGN_PERMISSION]: { content: i18nT('account_team:log_assign_permission'), - typeLabel: i18nT('account_team:assign_permission') + typeLabel: i18nT('account_team:assign_permission'), + params: {} as { name?: string; objectName: string; permission: string } } } as const; export type TemplateParamsMap = { - [OperationLogEventEnum.LOGIN]: { name?: string }; - [OperationLogEventEnum.CREATE_INVITATION_LINK]: { name?: string; link: string }; - [OperationLogEventEnum.JOIN_TEAM]: { name?: string; link: string }; - [OperationLogEventEnum.CHANGE_MEMBER_NAME]: { - name?: string; - memberName: string; - newName: string; - }; - [OperationLogEventEnum.KICK_OUT_TEAM]: { - name?: string; - memberName: string; - }; - [OperationLogEventEnum.CREATE_DEPARTMENT]: { name?: string; departmentName: string }; - [OperationLogEventEnum.CHANGE_DEPARTMENT]: { - name?: string; - departmentName: string; - }; - [OperationLogEventEnum.DELETE_DEPARTMENT]: { name?: string; departmentName: string }; - [OperationLogEventEnum.RELOCATE_DEPARTMENT]: { - name?: string; - departmentName: string; - }; - [OperationLogEventEnum.CREATE_GROUP]: { name?: string; groupName: string }; - [OperationLogEventEnum.DELETE_GROUP]: { name?: string; groupName: string }; - [OperationLogEventEnum.ASSIGN_PERMISSION]: { - name?: string; - objectName: string; - permission: string; - }; + [K in OperationLogEventEnum]: (typeof operationLogMap)[K]['params']; }; diff --git a/packages/service/support/permission/teamLimit.ts b/packages/service/support/permission/teamLimit.ts index d53e016e0..3345ac739 100644 --- a/packages/service/support/permission/teamLimit.ts +++ b/packages/service/support/permission/teamLimit.ts @@ -74,14 +74,3 @@ export const checkTeamAppLimit = async (teamId: string, amount = 1) => { return Promise.reject(TeamErrEnum.appAmountNotEnough); } }; - -export const checkTeamReRankPermission = async (teamId: string) => { - const { standardConstants } = await getTeamStandPlan({ - teamId - }); - - if (standardConstants && !standardConstants?.permissionReRank) { - return false; - } - return true; -}; diff --git a/packages/service/support/wallet/coupon/schema.ts b/packages/service/support/wallet/coupon/schema.ts new file mode 100644 index 000000000..88ec96a5d --- /dev/null +++ b/packages/service/support/wallet/coupon/schema.ts @@ -0,0 +1,33 @@ +import { addDays } from 'date-fns'; +import { connectionMongo, getMongoModel } from '../../../common/mongo'; +const { Schema } = connectionMongo; +import type { TeamCouponSchema } from '@fastgpt/global/support/wallet/sub/coupon/type'; + +export const couponCollectionName = 'team_sub_coupons'; + +const CouponSchema = new Schema({ + key: { + type: String, + required: true + }, + subscriptions: { + type: [Object], + required: true + }, + redeemedAt: { + type: Date, + default: undefined + }, + expiredAt: { + type: Date, + default: () => addDays(new Date(), 7) + } +}); + +try { + CouponSchema.index({ key: 1 }, { unique: true }); +} catch (error) { + console.log(error); +} + +export const MongoTeamCoupon = getMongoModel(couponCollectionName, CouponSchema); diff --git a/packages/service/support/wallet/sub/schema.ts b/packages/service/support/wallet/sub/schema.ts index c731410fb..8cd1d1bdc 100644 --- a/packages/service/support/wallet/sub/schema.ts +++ b/packages/service/support/wallet/sub/schema.ts @@ -1,4 +1,4 @@ -/* +/* user sub plan 1. type=standard: There will only be 1, and each team will have one 2. type=extraDatasetSize/extraPoints: Can buy multiple diff --git a/packages/service/support/wallet/sub/utils.ts b/packages/service/support/wallet/sub/utils.ts index 5eb8255de..dc70c9f9b 100644 --- a/packages/service/support/wallet/sub/utils.ts +++ b/packages/service/support/wallet/sub/utils.ts @@ -6,7 +6,7 @@ import { } from '@fastgpt/global/support/wallet/sub/constants'; import { MongoTeamSub } from './schema'; import { FeTeamPlanStatusType, TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type.d'; -import { getVectorCountByTeamId } from '../../../common/vectorStore/controller'; +import { getVectorCountByTeamId } from '../../../common/vectorDB/controller'; import dayjs from 'dayjs'; import { ClientSession } from '../../../common/mongo'; import { addMonths } from 'date-fns'; diff --git a/packages/service/support/wallet/usage/utils.ts b/packages/service/support/wallet/usage/utils.ts index fef3ce934..20d2e3c82 100644 --- a/packages/service/support/wallet/usage/utils.ts +++ b/packages/service/support/wallet/usage/utils.ts @@ -22,7 +22,7 @@ export const formatModelChars2Points = ({ }; } - const isIOPriceType = typeof modelData.inputPrice === 'number'; + const isIOPriceType = typeof modelData.inputPrice === 'number' && modelData.inputPrice > 0; const totalPoints = isIOPriceType ? (modelData.inputPrice || 0) * (inputTokens / multiple) + diff --git a/packages/web/components/common/Icon/constants.ts b/packages/web/components/common/Icon/constants.ts index 7b783907f..1965fece3 100644 --- a/packages/web/components/common/Icon/constants.ts +++ b/packages/web/components/common/Icon/constants.ts @@ -1,6 +1,7 @@ // @ts-nocheck export const iconPaths = { + alignLeft: () => import('./icons/alignLeft.svg'), book: () => import('./icons/book.svg'), change: () => import('./icons/change.svg'), chatSend: () => import('./icons/chatSend.svg'), @@ -17,6 +18,7 @@ export const iconPaths = { 'common/addLight': () => import('./icons/common/addLight.svg'), 'common/addUser': () => import('./icons/common/addUser.svg'), 'common/administrator': () => import('./icons/common/administrator.svg'), + 'common/alipay': () => import('./icons/common/alipay.svg'), 'common/app': () => import('./icons/common/app.svg'), 'common/arrowLeft': () => import('./icons/common/arrowLeft.svg'), 'common/arrowRight': () => import('./icons/common/arrowRight.svg'), @@ -105,15 +107,16 @@ 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'), 'common/voiceLight': () => import('./icons/common/voiceLight.svg'), 'common/wallet': () => import('./icons/common/wallet.svg'), 'common/warn': () => import('./icons/common/warn.svg'), + 'common/wechat': () => import('./icons/common/wechat.svg'), 'common/wechatFill': () => import('./icons/common/wechatFill.svg'), 'common/wecom': () => import('./icons/common/wecom.svg'), configmap: () => import('./icons/configmap.svg'), @@ -143,8 +146,6 @@ 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'), @@ -154,6 +155,8 @@ 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'), @@ -172,7 +175,6 @@ 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'), @@ -189,6 +191,7 @@ 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'), @@ -274,13 +277,12 @@ 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/codeRun': () => import('./icons/core/workflow/template/codeRun.svg'), 'core/workflow/template/customFeedback': () => @@ -296,6 +298,7 @@ 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'), @@ -325,12 +328,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'), @@ -388,10 +391,10 @@ 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/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'), @@ -439,6 +442,7 @@ export const iconPaths = { save: () => import('./icons/save.svg'), sliderTag: () => import('./icons/sliderTag.svg'), stop: () => import('./icons/stop.svg'), + 'support/account/coupon': () => import('./icons/support/account/coupon.svg'), 'support/account/laf': () => import('./icons/support/account/laf.svg'), 'support/account/loginoutLight': () => import('./icons/support/account/loginoutLight.svg'), 'support/account/plans': () => import('./icons/support/account/plans.svg'), diff --git a/packages/web/components/common/Icon/icons/alignLeft.svg b/packages/web/components/common/Icon/icons/alignLeft.svg new file mode 100644 index 000000000..5be101e2d --- /dev/null +++ b/packages/web/components/common/Icon/icons/alignLeft.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/web/components/common/Icon/icons/common/alipay.svg b/packages/web/components/common/Icon/icons/common/alipay.svg new file mode 100644 index 000000000..9184d7bc8 --- /dev/null +++ b/packages/web/components/common/Icon/icons/common/alipay.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/web/components/common/Icon/icons/common/wechat.svg b/packages/web/components/common/Icon/icons/common/wechat.svg new file mode 100644 index 000000000..9c110783d --- /dev/null +++ b/packages/web/components/common/Icon/icons/common/wechat.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/web/components/common/Icon/icons/support/account/coupon.svg b/packages/web/components/common/Icon/icons/support/account/coupon.svg new file mode 100644 index 000000000..131a86e32 --- /dev/null +++ b/packages/web/components/common/Icon/icons/support/account/coupon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/web/hooks/useLinkedScroll.tsx b/packages/web/hooks/useLinkedScroll.tsx index 40e8ae317..5e0e10434 100644 --- a/packages/web/hooks/useLinkedScroll.tsx +++ b/packages/web/hooks/useLinkedScroll.tsx @@ -65,7 +65,6 @@ export function useLinkedScroll< let scroolSign = useRef(false); const { runAsync: loadInitData } = useRequest2( async ({ scrollWhenFinish, refresh } = { scrollWhenFinish: true, refresh: false }) => { - console.log('loadInitData', params); if (!currentData || isLoading) return; const item = dataList.find((item) => item._id === currentData.id); diff --git a/packages/web/i18n/en/account_bill.json b/packages/web/i18n/en/account_bill.json index b6b9205e6..0e34a8cff 100644 --- a/packages/web/i18n/en/account_bill.json +++ b/packages/web/i18n/en/account_bill.json @@ -11,6 +11,7 @@ "confirm": "confirm", "contact_phone": "Contact phone number", "contact_phone_void": "Contact phone number format error", + "day": "sky", "default_header": "Default header", "detail": "Details", "email_address": "Email address", @@ -22,6 +23,7 @@ "invoice_detail": "Invoice details", "invoice_sending_info": "The invoice will be sent to your mailbox within 3-7 working days, please be patient.", "mm": "mm", + "month": "moon", "need_special_invoice": "Do you need a special ticket?", "no": "no", "no_invoice_record": "No bill record~", @@ -30,14 +32,16 @@ "order_type": "Order type", "organization_name": "Organization name", "payment_method": "Payment method", + "payway_coupon": "Redeem code", "save": "save", "save_failed": "Save exception", "save_success": "Saved successfully", "status": "state", + "sub_mode_custom": "Customize", "submit_failed": "Submission failed", "submit_success": "Submission successful", "submitted": "Submitted", - "subscription_mode_month": "by month", + "subscription_mode_month": "Duration", "subscription_package": "Subscription package", "subscription_period": "Subscription cycle", "support_wallet_amount": "Amount", diff --git a/packages/web/i18n/en/account_info.json b/packages/web/i18n/en/account_info.json index 3c3558be1..7c2f75a68 100644 --- a/packages/web/i18n/en/account_info.json +++ b/packages/web/i18n/en/account_info.json @@ -74,5 +74,6 @@ "user_team_team_name": "Team", "verification_code": "Verification code", "you_can_convert": "you can redeem", - "yuan": "Yuan" + "yuan": "Yuan", + "redeem_coupon": "Redeem coupon" } diff --git a/packages/web/i18n/en/account_team.json b/packages/web/i18n/en/account_team.json index b7e1a4744..bddc21b32 100644 --- a/packages/web/i18n/en/account_team.json +++ b/packages/web/i18n/en/account_team.json @@ -59,6 +59,7 @@ "log_join_team": "【{{name}}】Join the team through the invitation link 【{{link}}】", "log_kick_out_team": "{{name}} removed member {{memberName}}", "log_login": "【{{name}}】Logined in the system", + "log_recover_team_member": "【{{name}}】Restored member【{{memberName}}】", "log_relocate_department": "【{{name}}】Displayed department【{{departmentName}}】", "log_time": "Operation time", "log_type": "Operation Type", @@ -83,6 +84,7 @@ "permission_datasetCreate_Tip": "Can create knowledge bases in the root directory (creation permissions in folders are controlled by the folder)", "permission_manage": "Admin", "permission_manage_tip": "Can manage members, create groups, manage all groups, and assign permissions to groups and members", + "recover_team_member": "Member Recovery", "relocate_department": "Department Mobile", "remark": "remark", "remove_tip": "Confirm to remove {{username}} from the team?", diff --git a/packages/web/i18n/en/chat.json b/packages/web/i18n/en/chat.json index 4b8803b7f..8ae4c80ea 100644 --- a/packages/web/i18n/en/chat.json +++ b/packages/web/i18n/en/chat.json @@ -63,7 +63,10 @@ "response.child total points": "Sub-workflow point consumption", "response.dataset_concat_length": "Combined total", "response.node_inputs": "Node Inputs", + "response_embedding_model": "Vector model", + "response_embedding_model_tokens": "Vector Model Tokens", "response_hybrid_weight": "Embedding : Full text = {{emb}} : {{text}}", + "response_rerank_tokens": "Rearrange Model Tokens", "select": "Select", "select_file": "Upload File", "select_file_img": "Upload file / image", diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index bb90ae8a4..69bbaf4bf 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -36,12 +36,18 @@ "Warning": "Warning", "add_new": "Add New", "add_new_param": "Add new param", + "all_quotes": "Quote all", "app.templateMarket.templateTags.Image_generation": "Image generation", "app.templateMarket.templateTags.Office_services": "Office Services", "app.templateMarket.templateTags.Roleplay": "role play", "app.templateMarket.templateTags.Web_search": "Search online", "app.templateMarket.templateTags.Writing": "Writing", "back": "Back", + "bill_already_processed": "Order has been processed", + "bill_expired": "Order expired", + "bill_not_pay_processed": "Non-online orders", + "button.extra_dataset_size_tip": "You are purchasing [Extra Knowledge Base Capacity]", + "button.extra_points_tip": "You are purchasing [Extra AI Points]", "can_copy_content_tip": "It is not possible to copy automatically using the browser, please manually copy the following content", "chose_condition": "Choose Condition", "chosen": "Chosen", @@ -977,14 +983,22 @@ "no": "No", "no_laf_env": "System Not Configured with Laf Environment", "not_model_config": "No related model configured", + "not_permission": "The current subscription package does not support team operation logs", "not_yet_introduced": "No Introduction Yet", "option": "Option", "pay.amount": "Amount", + "pay.error_desc": "There was a problem when converting payment routes", + "pay.noclose": "After payment is completed, please wait for the system to update automatically", "pay.package_tip.buy": "The package you purchased is lower than the current package. This package will take effect after the current package expires.\nYou can view the package usage in Account - Personal Information - Package Details.", "pay.package_tip.renewal": "You are renewing the package. You can view the package usage in Account - Personal Information - Package Details.", "pay.package_tip.upgrade": "The package you purchased is higher than the current package. This package will take effect immediately, and the current package will take effect later. You can view the package usage in Account - Personal Information - Package Details.", "pay.wechat": "Please scan the QR code on WeChat to pay: {{price}} yuan\n\nPlease do not close the page before payment is completed", + "pay.wx_payment": "WeChat Payment", "pay.yuan": "{{amount}} Yuan", + "pay_alipay_payment": "Alipay Payment", + "pay_corporate_payment": "Payment to the public", + "pay_money": "Amount payable", + "pay_success": "Payment successfully", "permission.Collaborator": "Collaborator", "permission.Default permission": "Default Permission", "permission.Manage": "Manage", @@ -1038,6 +1052,7 @@ "required": "Required", "rerank_weight": "Rearrange weights", "resume_failed": "Resume Failed", + "scan_code": "Scan the QR code to pay", "select_reference_variable": "Select Reference Variable", "share_link": "Share Link", "support.account.Individuation": "Personalization", @@ -1120,7 +1135,9 @@ "support.wallet.bill.Status": "Status", "support.wallet.bill.Type": "Order Type", "support.wallet.bill.payWay.Way": "Payment Method", + "support.wallet.bill.payWay.alipay": "Alipay Payment", "support.wallet.bill.payWay.balance": "Balance Payment", + "support.wallet.bill.payWay.bank": "Bank Transfer", "support.wallet.bill.payWay.wx": "WeChat Payment", "support.wallet.bill.status.closed": "Closed", "support.wallet.bill.status.notpay": "Unpaid", @@ -1181,7 +1198,6 @@ "support.wallet.subscription.mode.Year": "Yearly", "support.wallet.subscription.mode.Year sale": "Two Months Free", "support.wallet.subscription.point": "Points", - "support.wallet.subscription.rerank": "Result Re-rank", "support.wallet.subscription.standardSubLevel.custom": "Custom", "support.wallet.subscription.standardSubLevel.enterprise": "Enterprise", "support.wallet.subscription.standardSubLevel.enterprise_desc": "Suitable for small and medium-sized enterprises to build Dataset applications in production environments", @@ -1194,6 +1210,7 @@ "support.wallet.subscription.status.active": "Active", "support.wallet.subscription.status.expired": "Expired", "support.wallet.subscription.status.inactive": "Inactive", + "support.wallet.subscription.team_operation_log": "Record team operation logs", "support.wallet.subscription.token_compute": "Click to View Online Tokens Calculator", "support.wallet.subscription.type.balance": "Balance Recharge", "support.wallet.subscription.type.extraDatasetSize": "Dataset Expansion", diff --git a/packages/web/i18n/en/dashboard_mcp.json b/packages/web/i18n/en/dashboard_mcp.json index 9c0f7da5e..0624471aa 100644 --- a/packages/web/i18n/en/dashboard_mcp.json +++ b/packages/web/i18n/en/dashboard_mcp.json @@ -2,7 +2,6 @@ "app_alias_name": "Tool name", "app_description": "Application Description", "app_name": "Application name", - "app_tool_name": "Tool alias", "apps": "Exposed applications", "create_mcp": "Create an MCP service", "create_mcp_server": "Create a new service", @@ -19,5 +18,8 @@ "search_app": "Search for apps", "select_app": "Application selection", "start_use": "Get started", + "tool_name": "Tool name", + "tool_name_placeholder": "It is recommended to use an English name", + "tool_name_tip": "Some Clients only support English, and you can modify this value to the tool name in English.", "usage_way": "MCP service usage" } diff --git a/packages/web/i18n/en/workflow.json b/packages/web/i18n/en/workflow.json index 8354ac10f..94ffbd9da 100644 --- a/packages/web/i18n/en/workflow.json +++ b/packages/web/i18n/en/workflow.json @@ -15,6 +15,7 @@ "assigned_reply": "Assigned Reply", "auth_tmb_id": "Auth member", "auth_tmb_id_tip": "After it is turned on, when the application is released to the outside world, the knowledge base will be filtered based on whether the user has permission to the knowledge base.\n\nIf it is not enabled, the configured knowledge base will be searched directly without permission filtering.", + "auto_align": "Automatic alignment", "can_not_loop": "This node can't loop.", "choose_another_application_to_call": "Select another application to call", "classification_result": "Classification Result", diff --git a/packages/web/i18n/zh-CN/account_bill.json b/packages/web/i18n/zh-CN/account_bill.json index 9d0e80af8..544283d12 100644 --- a/packages/web/i18n/zh-CN/account_bill.json +++ b/packages/web/i18n/zh-CN/account_bill.json @@ -11,6 +11,7 @@ "confirm": "确认", "contact_phone": "联系电话", "contact_phone_void": "联系电话格式错误", + "day": "天", "default_header": "默认抬头", "detail": "详情", "email_address": "邮箱地址", @@ -22,6 +23,7 @@ "invoice_detail": "发票详情", "invoice_sending_info": "发票将在 3-7 个工作日内发送至邮箱,请耐心等待", "mm": "毫米", + "month": "月", "need_special_invoice": "是否需要专票", "no": "否", "no_invoice_record": "无账单记录~", @@ -30,14 +32,16 @@ "order_type": "订单类型", "organization_name": "组织名称", "payment_method": "支付方式", + "payway_coupon": "兑换码", "save": "保存", "save_failed": "保存异常", "save_success": "保存成功", "status": "状态", + "sub_mode_custom": "自定义", "submit_failed": "提交失败", "submit_success": "提交成功", "submitted": "已提交", - "subscription_mode_month": "按月", + "subscription_mode_month": "时长", "subscription_package": "订阅套餐", "subscription_period": "订阅周期", "support_wallet_amount": "金额", diff --git a/packages/web/i18n/zh-CN/account_info.json b/packages/web/i18n/zh-CN/account_info.json index 2205a14ab..ac5e29244 100644 --- a/packages/web/i18n/zh-CN/account_info.json +++ b/packages/web/i18n/zh-CN/account_info.json @@ -73,5 +73,6 @@ "user_team_team_name": "团队", "verification_code": "验证码", "you_can_convert": "您可以兑换", - "yuan": "元" -} \ No newline at end of file + "yuan": "元", + "redeem_coupon": "兑换码" +} diff --git a/packages/web/i18n/zh-CN/account_team.json b/packages/web/i18n/zh-CN/account_team.json index a98318bd4..fe522fb9f 100644 --- a/packages/web/i18n/zh-CN/account_team.json +++ b/packages/web/i18n/zh-CN/account_team.json @@ -53,7 +53,20 @@ "label_sync": "标签同步", "leave": "已离职", "leave_team_failed": "离开团队异常", + "log_assign_permission": "【{{name}}】更新了【{{objectName}}】的权限:[应用创建:【{{appCreate}}】, 知识库:【{{datasetCreate}}】, API密钥:【{{apiKeyCreate}}】, 管理:【{{manage}}】]", + "log_change_department": "【{{name}}】更新了部门【{{departmentName}}】", + "log_change_member_name": "【{{name}}】将成员【{{memberName}}】重命名为【{{newName}}】", + "log_create_department": "【{{name}}】创建了部门【{{departmentName}}】", + "log_create_group": "【{{name}}】创建了群组【{{groupName}}】", + "log_create_invitation_link": "【{{name}}】创建了邀请链接【{{link}}】", + "log_delete_department": "【{{name}}】删除了部门【{{departmentName}}】", + "log_delete_group": "【{{name}}】删除了群组【{{groupName}}】", "log_details": "详情", + "log_join_team": "【{{name}}】通过邀请链接【{{link}}】加入团队", + "log_kick_out_team": "【{{name}}】移除了成员【{{memberName}}】", + "log_login": "【{{name}}】登录了系统", + "log_recover_team_member": "【{{name}}】恢复了成员【{{memberName}}】", + "log_relocate_department": "【{{name}}】移动了部门【{{departmentName}}】", "log_time": "操作时间", "log_type": "操作类型", "log_user": "操作人员", @@ -70,7 +83,16 @@ "org_name": "部门名称", "owner": "所有者", "permission": "权限", + "permission_apikeyCreate": "创建 API 密钥", + "permission_apikeyCreate_Tip": "可以创建全局的 APIKey", + "permission_appCreate": "创建应用", + "permission_appCreate_tip": "可以在根目录创建应用,(文件夹下的创建权限由文件夹控制)", + "permission_datasetCreate": "创建知识库", + "permission_datasetCreate_Tip": "可以在根目录创建知识库,(文件夹下的创建权限由文件夹控制)", + "permission_manage": "管理员", + "permission_manage_tip": "可以管理成员、创建群组、管理所有群组、为群组和成员分配权限", "please_bind_contact": "请绑定联系方式", + "recover_team_member": "成员恢复", "relocate_department": "部门移动", "remark": "备注", "remove_tip": "确认将 {{username}} 移出团队?成员将被标记为“已离职”,不删除操作数据,账号下资源自动转让给团队所有者。", @@ -93,25 +115,5 @@ "user_team_invite_member": "邀请成员", "user_team_leave_team": "离开团队", "user_team_leave_team_failed": "离开团队失败", - "waiting": "待接受", - "permission_appCreate": "创建应用", - "permission_datasetCreate": "创建知识库", - "permission_apikeyCreate": "创建 API 密钥", - "permission_appCreate_tip": "可以在根目录创建应用,(文件夹下的创建权限由文件夹控制)", - "permission_datasetCreate_Tip": "可以在根目录创建知识库,(文件夹下的创建权限由文件夹控制)", - "permission_apikeyCreate_Tip": "可以创建全局的 APIKey", - "permission_manage": "管理员", - "permission_manage_tip": "可以管理成员、创建群组、管理所有群组、为群组和成员分配权限", - "log_login": "【{{name}}】登录了系统", - "log_create_invitation_link": "【{{name}}】创建了邀请链接【{{link}}】", - "log_join_team": "【{{name}}】通过邀请链接【{{link}}】加入团队", - "log_change_member_name": "【{{name}}】将成员【{{memberName}}】重命名为【{{newName}}】", - "log_kick_out_team": "【{{name}}】移除了成员【{{memberName}}】", - "log_create_department": "【{{name}}】创建了部门【{{departmentName}}】", - "log_change_department": "【{{name}}】更新了部门【{{departmentName}}】", - "log_delete_department": "【{{name}}】删除了部门【{{departmentName}}】", - "log_relocate_department": "【{{name}}】移动了部门【{{departmentName}}】", - "log_create_group": "【{{name}}】创建了群组【{{groupName}}】", - "log_delete_group": "【{{name}}】删除了群组【{{groupName}}】", - "log_assign_permission": "【{{name}}】更新了【{{objectName}}】的权限:[应用创建:【{{appCreate}}】, 知识库:【{{datasetCreate}}】, API密钥:【{{apiKeyCreate}}】, 管理:【{{manage}}】]" + "waiting": "待接受" } diff --git a/packages/web/i18n/zh-CN/chat.json b/packages/web/i18n/zh-CN/chat.json index 421b77861..9c2af1944 100644 --- a/packages/web/i18n/zh-CN/chat.json +++ b/packages/web/i18n/zh-CN/chat.json @@ -63,7 +63,10 @@ "response.child total points": "子工作流积分消耗", "response.dataset_concat_length": "合并后总数", "response.node_inputs": "节点输入", + "response_embedding_model": "向量模型", + "response_embedding_model_tokens": "向量模型 Tokens", "response_hybrid_weight": "语义检索 : 全文检索 = {{emb}} : {{text}}", + "response_rerank_tokens": "重排模型 Tokens", "select": "选择", "select_file": "上传文件", "select_file_img": "上传文件/图片", diff --git a/packages/web/i18n/zh-CN/common.json b/packages/web/i18n/zh-CN/common.json index 81c815794..3e90030cc 100644 --- a/packages/web/i18n/zh-CN/common.json +++ b/packages/web/i18n/zh-CN/common.json @@ -36,12 +36,18 @@ "Warning": "提示", "add_new": "新增", "add_new_param": "新增参数", + "all_quotes": "全部引用", "app.templateMarket.templateTags.Image_generation": "图片生成", "app.templateMarket.templateTags.Office_services": "办公服务", "app.templateMarket.templateTags.Roleplay": "角色扮演", "app.templateMarket.templateTags.Web_search": "联网搜索", "app.templateMarket.templateTags.Writing": "文本创作", "back": "返回", + "bill_already_processed": "订单已处理", + "bill_expired": "订单已过期", + "bill_not_pay_processed": "非在线订单", + "button.extra_dataset_size_tip": "您正在购买【额外知识库容量】", + "button.extra_points_tip": "您正在购买【额外 AI 积分】", "can_copy_content_tip": "无法使用浏览器自动复制,请手动复制下面内容", "chose_condition": "选择条件", "chosen": "已选", @@ -976,14 +982,22 @@ "no": "否", "no_laf_env": "系统未配置Laf环境", "not_model_config": "未配置相关模型", + "not_permission": "当前订阅套餐不支持团队操作日志", "not_yet_introduced": "暂无介绍", "option": "选项", "pay.amount": "金额", + "pay.error_desc": "转换支付途径时出现了问题", + "pay.noclose": "支付完成后,请等待系统自动更新", "pay.package_tip.buy": "您购买的套餐等级低于当前套餐,该套餐将在当前套餐过期后生效。\n您可在账号—个人信息—套餐详情里,查看套餐使用情况。", "pay.package_tip.renewal": "您正在续费套餐。您可在账号—个人信息—套餐详情里,查看套餐使用情况。", "pay.package_tip.upgrade": "您购买的套餐等级高于当前套餐,该套餐将即刻生效,当前套餐将延后生效。您可在账号—个人信息—套餐详情里,查看套餐使用情况。", "pay.wechat": "请微信扫码支付: {{price}}元\n支付完成前,请勿关闭页面", + "pay.wx_payment": "微信支付", "pay.yuan": "{{amount}}元", + "pay_alipay_payment": "支付宝支付", + "pay_corporate_payment": "对公支付", + "pay_money": "应付金额", + "pay_success": "支付成功", "permission.Collaborator": "协作者", "permission.Default permission": "默认权限", "permission.Manage": "管理", @@ -1037,6 +1051,7 @@ "required": "必须", "rerank_weight": "重排权重", "resume_failed": "恢复失败", + "scan_code": "扫码支付", "select_reference_variable": "选择引用变量", "share_link": "分享链接", "support.account.Individuation": "个性化", @@ -1119,7 +1134,9 @@ "support.wallet.bill.Status": "状态", "support.wallet.bill.Type": "订单类型", "support.wallet.bill.payWay.Way": "支付方式", + "support.wallet.bill.payWay.alipay": "支付宝支付", "support.wallet.bill.payWay.balance": "余额支付", + "support.wallet.bill.payWay.bank": "对公支付", "support.wallet.bill.payWay.wx": "微信支付", "support.wallet.bill.status.closed": "已关闭", "support.wallet.bill.status.notpay": "未支付", @@ -1180,7 +1197,6 @@ "support.wallet.subscription.mode.Year": "按年", "support.wallet.subscription.mode.Year sale": "赠送两个月", "support.wallet.subscription.point": "积分", - "support.wallet.subscription.rerank": "检索结果重排", "support.wallet.subscription.standardSubLevel.custom": "自定义版", "support.wallet.subscription.standardSubLevel.enterprise": "企业版", "support.wallet.subscription.standardSubLevel.enterprise_desc": "适合中小企业在生产环境构建知识库应用", @@ -1193,6 +1209,7 @@ "support.wallet.subscription.status.active": "生效中", "support.wallet.subscription.status.expired": "已过期", "support.wallet.subscription.status.inactive": "待使用", + "support.wallet.subscription.team_operation_log": "记录团队操作日志", "support.wallet.subscription.token_compute": "点击查看在线 Tokens 计算器", "support.wallet.subscription.type.balance": "余额充值", "support.wallet.subscription.type.extraDatasetSize": "知识库扩容", diff --git a/packages/web/i18n/zh-CN/dashboard_mcp.json b/packages/web/i18n/zh-CN/dashboard_mcp.json index 5b31a85e4..02c49b6f3 100644 --- a/packages/web/i18n/zh-CN/dashboard_mcp.json +++ b/packages/web/i18n/zh-CN/dashboard_mcp.json @@ -2,7 +2,6 @@ "app_alias_name": "工具名", "app_description": "应用描述", "app_name": "应用名", - "app_tool_name": "工具别名", "apps": "暴露的应用", "create_mcp": "创建 MCP 服务", "create_mcp_server": "新建服务", @@ -19,5 +18,8 @@ "search_app": "搜索应用", "select_app": "应用选择", "start_use": "开始使用", + "tool_name": "工具名", + "tool_name_placeholder": "建议使用英文名", + "tool_name_tip": "部分 Client 仅支持英文,可以将该值修改成英文的工具名", "usage_way": "MCP 服务使用" } diff --git a/packages/web/i18n/zh-CN/workflow.json b/packages/web/i18n/zh-CN/workflow.json index 7d2d2229b..831e3665c 100644 --- a/packages/web/i18n/zh-CN/workflow.json +++ b/packages/web/i18n/zh-CN/workflow.json @@ -15,6 +15,7 @@ "assigned_reply": "指定回复", "auth_tmb_id": "使用者鉴权", "auth_tmb_id_tip": "开启后,对外发布该应用时,还会根据用户是否有该知识库权限进行知识库过滤。\n若未开启,则直接按配置的知识库进行检索,不进行权限过滤。", + "auto_align": "自动对齐", "can_not_loop": "该节点不支持循环嵌套", "choose_another_application_to_call": "选择一个其他应用进行调用", "classification_result": "分类结果", diff --git a/packages/web/i18n/zh-Hant/account_bill.json b/packages/web/i18n/zh-Hant/account_bill.json index b7cf452d8..3450e3030 100644 --- a/packages/web/i18n/zh-Hant/account_bill.json +++ b/packages/web/i18n/zh-Hant/account_bill.json @@ -11,6 +11,7 @@ "confirm": "確認", "contact_phone": "聯絡電話", "contact_phone_void": "聯絡電話格式錯誤", + "day": "天", "default_header": "預設抬頭", "detail": "詳細資訊", "email_address": "郵件地址", @@ -22,6 +23,7 @@ "invoice_detail": "發票詳細資訊", "invoice_sending_info": "發票將在 3-7 個工作天內傳送至郵箱,請耐心等待", "mm": "毫米", + "month": "月", "need_special_invoice": "是否需要專票", "no": "否", "no_invoice_record": "無帳單記錄~", @@ -30,14 +32,16 @@ "order_type": "訂單類型", "organization_name": "組織名稱", "payment_method": "支付方式", + "payway_coupon": "兌換碼", "save": "儲存", "save_failed": "儲存異常", "save_success": "儲存成功", "status": "狀態", + "sub_mode_custom": "自定義", "submit_failed": "提交失敗", "submit_success": "提交成功", "submitted": "已提交", - "subscription_mode_month": "按月", + "subscription_mode_month": "時長", "subscription_package": "訂閱套餐", "subscription_period": "訂閱週期", "support_wallet_amount": "金額", diff --git a/packages/web/i18n/zh-Hant/account_info.json b/packages/web/i18n/zh-Hant/account_info.json index 01a4a252d..76c4f4a5d 100644 --- a/packages/web/i18n/zh-Hant/account_info.json +++ b/packages/web/i18n/zh-Hant/account_info.json @@ -74,5 +74,6 @@ "user_team_team_name": "團隊", "verification_code": "驗證碼", "you_can_convert": "您可以兌換", - "yuan": "元" -} \ No newline at end of file + "yuan": "元", + "redeem_coupon": "兌換代碼" +} diff --git a/packages/web/i18n/zh-Hant/account_team.json b/packages/web/i18n/zh-Hant/account_team.json index 8b55a9276..ef22aa482 100644 --- a/packages/web/i18n/zh-Hant/account_team.json +++ b/packages/web/i18n/zh-Hant/account_team.json @@ -59,6 +59,7 @@ "log_join_team": "【{{name}}】通過邀請鏈接【{{link}}】加入團隊", "log_kick_out_team": "{{name}} 移除了成員 {{memberName}}", "log_login": "【{{name}}】登錄了系統", + "log_recover_team_member": "【{{name}}】恢復了成員【{{memberName}}】", "log_relocate_department": "【{{name}}】移動了部門【{{departmentName}}】", "log_time": "操作時間", "log_type": "操作類型", @@ -83,6 +84,7 @@ "permission_datasetCreate_Tip": "可以在根目錄建立知識庫,(資料夾下的建立權限由資料夾控制)", "permission_manage": "管理員", "permission_manage_tip": "可以管理成員、建立群組、管理所有群組、為群組和成員分配權限", + "recover_team_member": "成員恢復", "relocate_department": "部門移動", "remark": "備註", "remove_tip": "確認將 {{username}} 移出團隊?", diff --git a/packages/web/i18n/zh-Hant/chat.json b/packages/web/i18n/zh-Hant/chat.json index 47ab06f0b..40761b20f 100644 --- a/packages/web/i18n/zh-Hant/chat.json +++ b/packages/web/i18n/zh-Hant/chat.json @@ -61,7 +61,10 @@ "response.child total points": "子工作流程點數消耗", "response.dataset_concat_length": "合併總數", "response.node_inputs": "節點輸入", + "response_embedding_model": "向量模型", + "response_embedding_model_tokens": "向量模型 Tokens", "response_hybrid_weight": "語義檢索 : 全文檢索 = {{emb}} : {{text}}", + "response_rerank_tokens": "重排模型 Tokens", "select": "選取", "select_file": "上傳檔案", "select_file_img": "上傳檔案 / 圖片", diff --git a/packages/web/i18n/zh-Hant/common.json b/packages/web/i18n/zh-Hant/common.json index 88e1eaf33..ea88eeacd 100644 --- a/packages/web/i18n/zh-Hant/common.json +++ b/packages/web/i18n/zh-Hant/common.json @@ -36,12 +36,18 @@ "Warning": "警告", "add_new": "新增", "add_new_param": "新增參數", + "all_quotes": "全部引用", "app.templateMarket.templateTags.Image_generation": "圖片生成", "app.templateMarket.templateTags.Office_services": "辦公服務", "app.templateMarket.templateTags.Roleplay": "角色扮演", "app.templateMarket.templateTags.Web_search": "聯網搜索", "app.templateMarket.templateTags.Writing": "文字創作", "back": "返回", + "bill_already_processed": "訂單已處理", + "bill_expired": "訂單已過期", + "bill_not_pay_processed": "非在線訂單", + "button.extra_dataset_size_tip": "您正在購買【額外知識庫容量】", + "button.extra_points_tip": "您正在購買【額外 AI 積分】", "can_copy_content_tip": "無法使用瀏覽器自動複製,請手動複製下面內容", "chose_condition": "選擇條件", "chosen": "已選擇", @@ -976,14 +982,22 @@ "no": "否", "no_laf_env": "系統未設定 LAF 環境", "not_model_config": "未設定相關模型", + "not_permission": "當前訂閱套餐不支持團隊操作日誌", "not_yet_introduced": "暫無介紹", "option": "選項", "pay.amount": "金額", + "pay.error_desc": "轉換支付途徑時出現了問題", + "pay.noclose": "支付完成後,請等待系統自動更新", "pay.package_tip.buy": "您購買的方案等級低於目前方案,該方案將在目前方案過期後生效。\n您可在帳戶 - 個人資訊 - 方案詳細資訊中檢視方案使用情況。", "pay.package_tip.renewal": "您正在續約方案。您可在帳戶 - 個人資訊 - 方案詳細資訊中檢視方案使用情況。", "pay.package_tip.upgrade": "您購買的方案等級高於目前方案,該方案將立即生效,目前方案將延後生效。您可在帳戶 - 個人資訊 - 方案詳細資訊中檢視方案使用情況。", "pay.wechat": "請微信掃碼付款:{{price}}元\n\n付款完成前,請勿關閉頁面", + "pay.wx_payment": "微信支付", "pay.yuan": "{{amount}} 元", + "pay_alipay_payment": "支付寶支付", + "pay_corporate_payment": "對公支付", + "pay_money": "應付金額", + "pay_success": "支付成功", "permission.Collaborator": "協作者", "permission.Default permission": "預設權限", "permission.Manage": "管理", @@ -1037,6 +1051,7 @@ "required": "必填", "rerank_weight": "重排權重", "resume_failed": "恢復失敗", + "scan_code": "掃碼支付", "select_reference_variable": "選擇引用變數", "share_link": "分享連結", "support.account.Individuation": "個人化", @@ -1119,7 +1134,9 @@ "support.wallet.bill.Status": "狀態", "support.wallet.bill.Type": "訂單類型", "support.wallet.bill.payWay.Way": "付款方式", + "support.wallet.bill.payWay.alipay": "支付寶支付", "support.wallet.bill.payWay.balance": "餘額支付", + "support.wallet.bill.payWay.bank": "對公支付", "support.wallet.bill.payWay.wx": "微信支付", "support.wallet.bill.status.closed": "已關閉", "support.wallet.bill.status.notpay": "未付款", @@ -1180,7 +1197,6 @@ "support.wallet.subscription.mode.Year": "按年", "support.wallet.subscription.mode.Year sale": "贈送兩個月", "support.wallet.subscription.point": "點數", - "support.wallet.subscription.rerank": "結果重新排名", "support.wallet.subscription.standardSubLevel.custom": "客製版", "support.wallet.subscription.standardSubLevel.enterprise": "企業版", "support.wallet.subscription.standardSubLevel.enterprise_desc": "適合中小企業在正式環境建構知識庫應用", @@ -1193,6 +1209,7 @@ "support.wallet.subscription.status.active": "使用中", "support.wallet.subscription.status.expired": "已過期", "support.wallet.subscription.status.inactive": "未使用", + "support.wallet.subscription.team_operation_log": "記錄團隊操作日誌", "support.wallet.subscription.token_compute": "點選檢視線上 Token 計算機", "support.wallet.subscription.type.balance": "餘額儲值", "support.wallet.subscription.type.extraDatasetSize": "知識庫擴充容量", diff --git a/packages/web/i18n/zh-Hant/dashboard_mcp.json b/packages/web/i18n/zh-Hant/dashboard_mcp.json index 2119c1611..1de5466ee 100644 --- a/packages/web/i18n/zh-Hant/dashboard_mcp.json +++ b/packages/web/i18n/zh-Hant/dashboard_mcp.json @@ -2,7 +2,6 @@ "app_alias_name": "工具名", "app_description": "應用描述", "app_name": "應用名", - "app_tool_name": "工具別名", "apps": "暴露的應用", "create_mcp": "創建 MCP 服務", "create_mcp_server": "新建服務", @@ -19,5 +18,8 @@ "search_app": "搜索應用", "select_app": "應用選擇", "start_use": "開始使用", + "tool_name": "工具名", + "tool_name_placeholder": "建議使用英文名", + "tool_name_tip": "部分 Client 僅支持英文,可以將該值修改成英文的工具名", "usage_way": "MCP 服務使用" } diff --git a/packages/web/i18n/zh-Hant/workflow.json b/packages/web/i18n/zh-Hant/workflow.json index 0681d61cb..866979c03 100644 --- a/packages/web/i18n/zh-Hant/workflow.json +++ b/packages/web/i18n/zh-Hant/workflow.json @@ -15,6 +15,7 @@ "assigned_reply": "指定回覆", "auth_tmb_id": "使用者鑑權", "auth_tmb_id_tip": "開啟後,對外發布應用程式時,也會根據使用者是否有該知識庫權限進行知識庫過濾。\n\n若未開啟,則直接按設定的知識庫進行檢索,不進行權限過濾。", + "auto_align": "自動對齊", "can_not_loop": "這個節點不能迴圈。", "choose_another_application_to_call": "選擇另一個應用程式來呼叫", "classification_result": "分類結果", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0b7911c42..f7a5411a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,7 +34,7 @@ importers: version: 10.1.4(socks@2.8.4) next-i18next: specifier: 15.4.2 - version: 15.4.2(i18next@23.16.8)(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 15.4.2(i18next@23.16.8)(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) prettier: specifier: 3.2.4 version: 3.2.4 @@ -246,7 +246,7 @@ importers: version: 3.13.0 next: specifier: 14.2.26 - version: 14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1) + version: 14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1) nextjs-cors: specifier: ^2.2.0 version: 2.2.0(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1)) @@ -331,7 +331,7 @@ importers: version: 2.1.1(@chakra-ui/system@2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1))(react@18.3.1) '@chakra-ui/next-js': specifier: 2.4.2 - version: 2.4.2(@chakra-ui/react@2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react@18.3.1) + version: 2.4.2(@chakra-ui/react@2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react@18.3.1) '@chakra-ui/react': specifier: 2.10.7 version: 2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -394,7 +394,7 @@ importers: version: 4.17.21 next-i18next: specifier: 15.4.2 - version: 15.4.2(i18next@23.16.8)(next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 15.4.2(i18next@23.16.8)(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) papaparse: specifier: ^5.4.1 version: 5.4.1 @@ -465,6 +465,9 @@ importers: '@chakra-ui/system': specifier: 2.6.1 version: 2.6.1(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(react@18.3.1) + '@dagrejs/dagre': + specifier: ^1.1.4 + version: 1.1.4 '@emotion/react': specifier: 11.11.1 version: 11.11.1(@types/react@18.3.1)(react@18.3.1) @@ -1661,6 +1664,13 @@ packages: '@dabh/diagnostics@2.0.3': resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} + '@dagrejs/dagre@1.1.4': + resolution: {integrity: sha512-QUTc54Cg/wvmlEUxB+uvoPVKFazM1H18kVHBQNmK2NbrDR5ihOCR6CXLnDSZzMcSQKJtabPUWridBOlJM3WkDg==} + + '@dagrejs/graphlib@2.2.4': + resolution: {integrity: sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==} + engines: {node: '>17.0.0'} + '@emnapi/core@1.3.1': resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==} @@ -11010,6 +11020,14 @@ snapshots: next: 14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1) react: 18.3.1 + '@chakra-ui/next-js@2.4.2(@chakra-ui/react@2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react@18.3.1)': + dependencies: + '@chakra-ui/react': 2.10.7(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(react@18.3.1))(@types/react@18.3.1)(framer-motion@9.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@emotion/cache': 11.14.0 + '@emotion/react': 11.11.1(@types/react@18.3.1)(react@18.3.1) + next: 14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1) + react: 18.3.1 + '@chakra-ui/object-utils@2.1.0': {} '@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.3.1)': @@ -11136,6 +11154,12 @@ snapshots: enabled: 2.0.0 kuler: 2.0.0 + '@dagrejs/dagre@1.1.4': + dependencies: + '@dagrejs/graphlib': 2.2.4 + + '@dagrejs/graphlib@2.2.4': {} + '@emnapi/core@1.3.1': dependencies: '@emnapi/wasi-threads': 1.0.1 @@ -18109,6 +18133,18 @@ snapshots: react: 18.3.1 react-i18next: 14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next-i18next@15.4.2(i18next@23.16.8)(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1))(react-i18next@14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + dependencies: + '@babel/runtime': 7.26.10 + '@types/hoist-non-react-statics': 3.3.6 + core-js: 3.41.0 + hoist-non-react-statics: 3.3.2 + i18next: 23.16.8 + i18next-fs-backend: 2.6.0 + next: 14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1) + react: 18.3.1 + react-i18next: 14.1.2(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next@14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1): dependencies: '@next/env': 14.2.26 @@ -18164,7 +18200,7 @@ snapshots: nextjs-cors@2.2.0(next@14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1)): dependencies: cors: 2.8.5 - next: 14.2.26(@babel/core@7.26.10)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1) + next: 14.2.26(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.85.1) node-abi@3.74.0: dependencies: diff --git a/projects/app/.env.template b/projects/app/.env.template index 2b8cf8807..02737cbd1 100644 --- a/projects/app/.env.template +++ b/projects/app/.env.template @@ -62,6 +62,14 @@ WORKFLOW_MAX_LOOP_TIMES=50 # 启用内网 IP 检查 CHECK_INTERNAL_IP=false +# 特殊配置 +# 自定义跨域,不配置时,默认都允许跨域(逗号分割) +ALLOWED_ORIGINS= +# 是否展示兑换码功能 +SHOW_COUPON=false +# 自定义 config.json 路径 +CONFIG_JSON_PATH= + # 对话日志推送服务 # # 日志服务地址 # CHAT_LOG_URL=http://localhost:8080 @@ -69,5 +77,4 @@ CHECK_INTERNAL_IP=false # CHAT_LOG_INTERVAL=10000 # # 日志来源ID前缀 # CHAT_LOG_SOURCE_ID_PREFIX=fastgpt- -# 自定义跨域,不配置时,默认都允许跨域(逗号分割) -ALLOWED_ORIGINS= + diff --git a/projects/app/package.json b/projects/app/package.json index fb18bea80..44fcc22b8 100644 --- a/projects/app/package.json +++ b/projects/app/package.json @@ -15,6 +15,7 @@ "@chakra-ui/react": "2.10.7", "@chakra-ui/styled-system": "2.9.1", "@chakra-ui/system": "2.6.1", + "@dagrejs/dagre": "^1.1.4", "@emotion/react": "11.11.1", "@emotion/styled": "11.11.0", "@fastgpt/global": "workspace:*", diff --git a/projects/app/public/imgs/modal/wallet.svg b/projects/app/public/imgs/modal/wallet.svg new file mode 100644 index 000000000..c6d82fc0d --- /dev/null +++ b/projects/app/public/imgs/modal/wallet.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/projects/app/src/components/Markdown/A.tsx b/projects/app/src/components/Markdown/A.tsx index 14bb9d110..3230ea784 100644 --- a/projects/app/src/components/Markdown/A.tsx +++ b/projects/app/src/components/Markdown/A.tsx @@ -8,7 +8,8 @@ import { PopoverBody, PopoverArrow, Box, - Flex + Flex, + useDisclosure } from '@chakra-ui/react'; import MyIcon from '@fastgpt/web/components/common/Icon'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; @@ -32,6 +33,8 @@ const A = ({ children, ...props }: any) => { manual: true }); + const { isOpen, onOpen, onClose } = useDisclosure(); + // empty href link if (!props.href && typeof children?.[0] === 'string') { const text = useMemo(() => String(children), [children]); @@ -71,77 +74,95 @@ const A = ({ children, ...props }: any) => { direction="rtl" placement="bottom" strategy={'fixed'} - onOpen={() => runAsync(String(children))} + isOpen={isOpen} + onClose={onClose} + onOpen={() => { + onOpen(); + runAsync(String(children)); + }} + gutter={4} > - - + + - - - + + - {index} - - - - - {sourceData.sourceName} - - - - + {index} + + + + + {sourceData.sourceName} + + + + + + {quoteData?.a && } diff --git a/projects/app/src/components/core/ai/ModelTable/index.tsx b/projects/app/src/components/core/ai/ModelTable/index.tsx index e88bc6341..daa9e727a 100644 --- a/projects/app/src/components/core/ai/ModelTable/index.tsx +++ b/projects/app/src/components/core/ai/ModelTable/index.tsx @@ -94,6 +94,7 @@ const ModelTable = () => { typeLabel: t('common:model.type.embedding'), priceLabel: ( + {`${t('common:common.Input')}: `} {item.charsPointsPrice || 0} @@ -131,7 +132,17 @@ const ModelTable = () => { const formatRerankModelList = reRankModelList.map((item) => ({ ...item, typeLabel: t('common:model.type.reRank'), - priceLabel: - , + priceLabel: item.charsPointsPrice ? ( + + {`${t('common:common.Input')}: `} + + {item.charsPointsPrice} + + {` ${t('common:support.wallet.subscription.point')} / 1K Tokens`} + + ) : ( + '-' + ), tagColor: 'red' })); diff --git a/projects/app/src/components/core/app/DatasetParamsModal.tsx b/projects/app/src/components/core/app/DatasetParamsModal.tsx index f55465bf8..5e35d38f2 100644 --- a/projects/app/src/components/core/app/DatasetParamsModal.tsx +++ b/projects/app/src/components/core/app/DatasetParamsModal.tsx @@ -78,7 +78,7 @@ const DatasetParamsModal = ({ defaultValues: { searchMode, embeddingWeight: embeddingWeight || 0.5, - usingReRank: !!usingReRank && teamPlanStatus?.standardConstants?.permissionReRank !== false, + usingReRank: usingReRank || true, rerankModel: rerankModel || defaultModels?.rerank?.model, rerankWeight: rerankWeight || 0.5, limit, @@ -246,11 +246,6 @@ const DatasetParamsModal = ({ {t('common:core.ai.Not deploy rerank model')} - ) : teamPlanStatus?.standardConstants && - !teamPlanStatus?.standardConstants?.permissionReRank ? ( - - {t('common:support.team.limit.No permission rerank')} - ) : ( )} diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatItem.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatItem.tsx index cd0392d09..930004adf 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatItem.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ChatItem.tsx @@ -1,5 +1,5 @@ import { Box, BoxProps, Card, Flex } from '@chakra-ui/react'; -import React, { useMemo, useRef } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import ChatController, { type ChatControllerProps } from './ChatController'; import ChatAvatar from './ChatAvatar'; import { MessageCardStyle } from '../constants'; @@ -26,6 +26,8 @@ import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { formatTimeToChatItemTime } from '@fastgpt/global/common/string/time'; import dayjs from 'dayjs'; import { ChatItemContext } from '@/web/core/chat/context/chatItemContext'; +import { eventBus, EventNameEnum } from '@/web/common/utils/eventbus'; +import { addStatisticalDataToHistoryItem } from '@/global/core/chat/utils'; const colorMap = { [ChatStatusEnum.loading]: { @@ -141,6 +143,18 @@ const ChatItem = (props: Props) => { const isChatting = useContextSelector(ChatBoxContext, (v) => v.isChatting); const chatType = useContextSelector(ChatBoxContext, (v) => v.chatType); const showNodeStatus = useContextSelector(ChatItemContext, (v) => v.showNodeStatus); + + const setQuoteData = useContextSelector(ChatItemContext, (v) => v.setQuoteData); + const appId = useContextSelector(ChatBoxContext, (v) => v.appId); + const chatId = useContextSelector(ChatBoxContext, (v) => v.chatId); + const outLinkAuthData = useContextSelector(ChatBoxContext, (v) => v.outLinkAuthData); + const isShowReadRawSource = useContextSelector(ChatItemContext, (v) => v.isShowReadRawSource); + + const { totalQuoteList: quoteList = [] } = useMemo( + () => addStatisticalDataToHistoryItem(chat), + [chat] + ); + const isChatLog = chatType === 'log'; const { copyData } = useCopyData(); @@ -208,6 +222,59 @@ const ChatItem = (props: Props) => { return groupedValues; }, [chat.obj, chat.value, isChatting]); + const handleOpenQuoteReader = useCallback( + ({ + collectionId, + sourceId, + sourceName, + datasetId + }: { + collectionId?: string; + sourceId?: string; + sourceName?: string; + datasetId?: string; + }) => { + if (!setQuoteData) return; + + const collectionIdList = collectionId + ? [collectionId] + : [...new Set(quoteList.map((item) => item.collectionId))]; + + setQuoteData({ + rawSearch: quoteList, + metadata: + collectionId && isShowReadRawSource + ? { + appId: appId, + chatId: chatId, + chatItemDataId: chat.dataId, + collectionId: collectionId, + sourceId: sourceId || '', + sourceName: sourceName || '', + datasetId: datasetId || '', + outLinkAuthData + } + : { + appId: appId, + chatId: chatId, + chatItemDataId: chat.dataId, + collectionIdList, + sourceId: sourceId, + sourceName: sourceName, + outLinkAuthData + } + }); + }, + [setQuoteData, quoteList, isShowReadRawSource, appId, chatId, chat.dataId, outLinkAuthData] + ); + + useEffect(() => { + eventBus.on(EventNameEnum.openQuoteReader, handleOpenQuoteReader); + return () => { + eventBus.off(EventNameEnum.openQuoteReader); + }; + }, [handleOpenQuoteReader]); + return ( - await getQuoteDataList({ - datasetDataIdList: rawSearch.map((item) => item.id), - collectionIdList: [...new Set(rawSearch.map((item) => item.collectionId))], - chatItemDataId, - appId, - chatId: RawSourceBoxProps.chatId, - ...outLinkAuthData - }), + !!chatItemDataId + ? await getQuoteDataList({ + datasetDataIdList: rawSearch.map((item) => item.id), + collectionIdList: [...new Set(rawSearch.map((item) => item.collectionId))], + chatItemDataId, + appId, + chatId: RawSourceBoxProps.chatId, + ...outLinkAuthData + }) + : [], { refreshDeps: [rawSearch, RawSourceBoxProps.chatId], - manual: !chatItemDataId + manual: false } ); diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ResponseTags.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ResponseTags.tsx index cab6e1b90..24fec2117 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ResponseTags.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ResponseTags.tsx @@ -14,7 +14,7 @@ import { addStatisticalDataToHistoryItem } from '@/global/core/chat/utils'; import { useSize } from 'ahooks'; import { useContextSelector } from 'use-context-selector'; import { ChatBoxContext } from '../Provider'; -import { ChatItemContext } from '@/web/core/chat/context/chatItemContext'; +import { eventBus, EventNameEnum } from '@/web/common/utils/eventbus'; const ContextModal = dynamic(() => import('./ContextModal')); const WholeResponseModal = dynamic(() => import('../../../components/WholeResponseModal')); @@ -30,23 +30,18 @@ const ResponseTags = ({ const { t } = useTranslation(); const quoteListRef = React.useRef(null); const dataId = historyItem.dataId; - const chatTime = historyItem.time || new Date(); + const chatTime = historyItem.time || new Date(); + const durationSeconds = historyItem.durationSeconds || 0; const { totalQuoteList: quoteList = [], llmModuleAccount = 0, - totalRunningTime: runningTime = 0, historyPreviewLength = 0 } = useMemo(() => addStatisticalDataToHistoryItem(historyItem), [historyItem]); const [quoteFolded, setQuoteFolded] = useState(true); const chatType = useContextSelector(ChatBoxContext, (v) => v.chatType); - const appId = useContextSelector(ChatBoxContext, (v) => v.appId); - const chatId = useContextSelector(ChatBoxContext, (v) => v.chatId); - const outLinkAuthData = useContextSelector(ChatBoxContext, (v) => v.outLinkAuthData); - - const setQuoteData = useContextSelector(ChatItemContext, (v) => v.setQuoteData); const notSharePage = useMemo(() => chatType !== 'share', [chatType]); @@ -66,7 +61,6 @@ const ResponseTags = ({ ? quoteListRef.current.scrollHeight > (isPc ? 50 : 55) : true; - const isShowReadRawSource = useContextSelector(ChatItemContext, (v) => v.isShowReadRawSource); const sourceList = useMemo(() => { return Object.values( quoteList.reduce((acc: Record, cur) => { @@ -86,11 +80,20 @@ const ResponseTags = ({ })); }, [quoteList]); + const openQuoteReader = (item?: { + collectionId?: string; + sourceId?: string; + sourceName?: string; + datasetId?: string; + }) => { + eventBus.emit(EventNameEnum.openQuoteReader, item); + }; + const notEmptyTags = quoteList.length > 0 || (llmModuleAccount === 1 && notSharePage) || (llmModuleAccount > 1 && notSharePage) || - (isPc && runningTime > 0) || + (isPc && durationSeconds > 0) || notSharePage; return !showTags ? null : ( @@ -158,35 +161,7 @@ const ResponseTags = ({ cursor={'pointer'} onClick={(e) => { e.stopPropagation(); - - if (isShowReadRawSource) { - setQuoteData({ - rawSearch: quoteList, - metadata: { - appId, - chatId, - chatItemDataId: dataId, - collectionId: item.collectionId, - sourceId: item.sourceId || '', - sourceName: item.sourceName, - datasetId: item.datasetId, - outLinkAuthData - } - }); - } else { - setQuoteData({ - rawSearch: quoteList, - metadata: { - appId, - chatId, - chatItemDataId: dataId, - collectionIdList: [item.collectionId], - sourceId: item.sourceId || '', - sourceName: item.sourceName, - outLinkAuthData - } - }); - } + openQuoteReader(item); }} height={6} > @@ -241,17 +216,7 @@ const ResponseTags = ({ cursor={'pointer'} onClick={(e) => { e.stopPropagation(); - - setQuoteData({ - rawSearch: quoteList, - metadata: { - appId, - chatId, - chatItemDataId: dataId, - collectionIdList: [...new Set(quoteList.map((item) => item.collectionId))], - outLinkAuthData - } - }); + openQuoteReader(); }} > {t('chat:citations', { num: quoteList.length })} @@ -279,10 +244,10 @@ const ResponseTags = ({ {t('chat:multiple_AI_conversations')} )} - {isPc && runningTime > 0 && ( + {isPc && durationSeconds > 0 && ( - {runningTime}s + {durationSeconds.toFixed(2)}s )} diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx index 69c9f6dc4..918e03285 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx @@ -221,7 +221,8 @@ const ChatBox = ({ interactive, autoTTSResponse, variables, - nodeResponse + nodeResponse, + durationSeconds }: generatingMessageProps & { autoTTSResponse?: boolean }) => { setChatRecords((state) => state.map((item, index) => { @@ -342,6 +343,13 @@ const ChatBox = ({ ...item, value: item.value.concat(val) }; + } else if (event === SseResponseEventEnum.workflowDuration && durationSeconds) { + return { + ...item, + durationSeconds: item.durationSeconds + ? +(item.durationSeconds + durationSeconds).toFixed(2) + : durationSeconds + }; } return item; diff --git a/projects/app/src/components/core/chat/ChatContainer/type.d.ts b/projects/app/src/components/core/chat/ChatContainer/type.d.ts index d7d0e5340..2838203a9 100644 --- a/projects/app/src/components/core/chat/ChatContainer/type.d.ts +++ b/projects/app/src/components/core/chat/ChatContainer/type.d.ts @@ -17,6 +17,7 @@ export type generatingMessageProps = { interactive?: WorkflowInteractiveResponseType; variables?: Record; nodeResponse?: ChatHistoryItemResType; + durationSeconds?: number; }; export type StartChatFnProps = { diff --git a/projects/app/src/components/core/chat/components/WholeResponseModal.tsx b/projects/app/src/components/core/chat/components/WholeResponseModal.tsx index 8b01d7d76..7aaa9104f 100644 --- a/projects/app/src/components/core/chat/components/WholeResponseModal.tsx +++ b/projects/app/src/components/core/chat/components/WholeResponseModal.tsx @@ -252,29 +252,39 @@ export const WholeResponseContent = ({ } /> )} - + + {activeModule?.searchUsingReRank !== undefined && ( - - {activeModule?.searchUsingReRank ? ( - activeModule?.rerankModel ? ( - {`${activeModule.rerankModel}: ${activeModule.rerankWeight}`} + <> + + {activeModule?.searchUsingReRank ? ( + activeModule?.rerankModel ? ( + {`${activeModule.rerankModel}: ${activeModule.rerankWeight}`} + ) : ( + 'True' + ) ) : ( - 'True' - ) - ) : ( - `False` - )} - - } - /> + `False` + )} + + } + /> + + )} {activeModule.queryExtensionResult && ( <> diff --git a/projects/app/src/components/support/user/inform/UpdateContactModal.tsx b/projects/app/src/components/support/user/inform/UpdateContactModal.tsx index 883024abd..65299c789 100644 --- a/projects/app/src/components/support/user/inform/UpdateContactModal.tsx +++ b/projects/app/src/components/support/user/inform/UpdateContactModal.tsx @@ -17,9 +17,11 @@ type FormType = { const UpdateContactModal = ({ onClose, + onSuccess, mode }: { onClose: () => void; + onSuccess?: (val: string) => void; mode: 'contact' | 'notification_account'; }) => { const { t } = useTranslation(); @@ -37,20 +39,22 @@ const UpdateContactModal = ({ const verifyCode = watch('verifyCode'); const { runAsync: onSubmit, loading: isLoading } = useRequest2( - (data: FormType) => { + async (data: FormType) => { if (mode === 'contact') { - return updateContact(data); + await updateContact(data); } else { - return updateNotificationAccount({ + await updateNotificationAccount({ account: data.contact, verifyCode: data.verifyCode }); } + return data.contact; }, { - onSuccess() { + onSuccess(data) { initUserInfo(); onClose(); + onSuccess?.(data); }, successToast: t('common:support.user.info.bind_notification_success'), errorToast: t('common:support.user.info.bind_notification_error') diff --git a/projects/app/src/components/support/wallet/QRCodePayModal.tsx b/projects/app/src/components/support/wallet/QRCodePayModal.tsx index 306ab1a34..33af5e532 100644 --- a/projects/app/src/components/support/wallet/QRCodePayModal.tsx +++ b/projects/app/src/components/support/wallet/QRCodePayModal.tsx @@ -1,36 +1,98 @@ import MyModal from '@fastgpt/web/components/common/MyModal'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'next-i18next'; -import { Box, ModalBody } from '@chakra-ui/react'; -import { checkBalancePayResult } from '@/web/support/wallet/bill/api'; -import { useToast } from '@fastgpt/web/hooks/useToast'; +import { Box, ModalBody, Flex, Button } from '@chakra-ui/react'; +import { checkBalancePayResult, putUpdatePayment } from '@/web/support/wallet/bill/api'; import LightTip from '@fastgpt/web/components/common/LightTip'; import QRCode from 'qrcode'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; +import { + BillPayWayEnum, + BillStatusEnum, + QR_CODE_SIZE +} from '@fastgpt/global/support/wallet/bill/constants'; +import { useSystemStore } from '@/web/common/system/useSystemStore'; +import Markdown from '@/components/Markdown'; +import MyIcon from '@fastgpt/web/components/common/Icon'; +import { useToast } from '@fastgpt/web/hooks/useToast'; +import { CreateBillResponse } from '@fastgpt/global/support/wallet/bill/api'; -export type QRPayProps = { - readPrice: number; - codeUrl: string; - billId: string; +export type QRPayProps = CreateBillResponse & { + tip?: string; }; -const qrCodeSize = 168; - const QRCodePayModal = ({ tip, readPrice, - codeUrl, billId, + payment, + qrCode, + iframeCode, + markdown, onSuccess }: QRPayProps & { tip?: string; onSuccess?: () => any }) => { const { t } = useTranslation(); - const { toast } = useToast(); const canvasRef = useRef(null); + const toast = useToast(); + const { feConfigs } = useSystemStore(); + const isAlipayConfigured = feConfigs.payConfig?.alipay; + const isWxConfigured = feConfigs.payConfig?.wx; + const isBankConfigured = feConfigs.payConfig?.bank; + + const [payWayRenderData, setPayWayRenderData] = useState<{ + qrCode?: string; + iframeCode?: string; + markdown?: string; + }>({ + qrCode, + iframeCode, + markdown + }); + + const [selectedPayment, setSelectedPayment] = useState(payment); + const { runAsync: handlePaymentChange, loading: isUpdating } = useRequest2( + async (newPayment: BillPayWayEnum) => { + if (newPayment === selectedPayment) { + return; + } + + const response = await putUpdatePayment({ billId, payWay: newPayment }); + setPayWayRenderData(response); + setSelectedPayment(newPayment); + }, + { + refreshDeps: [billId, selectedPayment] + } + ); + + // Check pay result + useRequest2(() => checkBalancePayResult(billId), { + manual: false, + pollingInterval: 2000, + onSuccess: ({ status, description }) => { + if (status === BillStatusEnum.SUCCESS) { + toast.toast({ + description: t('common:pay_success'), + status: 'success', + duration: 2000 + }); + onSuccess?.(); + } else { + console.log(status, description); + } + } + }); + + // UI render + // Draw QR code const drawCode = useCallback(() => { + if (!payWayRenderData.qrCode) return; + const canvas = document.createElement('canvas'); - QRCode.toCanvas(canvas, codeUrl, { - width: qrCodeSize, + + QRCode.toCanvas(canvas, payWayRenderData.qrCode, { + width: QR_CODE_SIZE, margin: 0, color: { dark: '#000000', @@ -41,38 +103,125 @@ const QRCodePayModal = ({ if (canvasRef.current) { canvasRef.current.innerHTML = ''; canvasRef.current.appendChild(canvas); - } else { - drawCode(); } }) - .catch((err) => { - console.error('QRCode generation error:', err); - }); - }, [codeUrl]); - + .catch(console.error); + }, [payWayRenderData.qrCode]); useEffect(() => { drawCode(); }, [drawCode]); - - useRequest2(() => checkBalancePayResult(billId), { - manual: false, - pollingInterval: 2000, - onSuccess: (res) => { - if (res) { - onSuccess?.(); + // Payment Button + const getPaymentButtonStyles = (isActive: boolean) => ({ + baseStyle: { + display: 'flex', + padding: '13px 22px 13px 19px', + justifyContent: 'center', + alignItems: 'center', + flex: '1 0 0', + borderRadius: '7.152px', + border: isActive ? '1px solid #3370FF' : '1px solid #E8EBF0', + background: '#FFF', + _hover: { + background: isActive ? '#FFF' : '#F7F8FA', + border: isActive ? '1px solid #3370FF' : '1px solid #E8EBF0' + }, + _active: { + background: '#FFF', + borderColor: '#3370FF' } - }, - errorToast: '' + } }); + const renderPaymentContent = () => { + if (payWayRenderData.qrCode) { + return ; + } + if (payWayRenderData.iframeCode) { + return ( +