From 6a6719e93deb5ba69590390845999ca17bcf4a59 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Thu, 22 May 2025 18:40:29 +0800 Subject: [PATCH] perf: isPc check;perf: dataset max token checker (#4872) * perf: isPc check * perf: dataset max token checker * perf: dataset max token checker --- .../zh-cn/docs/development/upgrading/4910.md | 2 + packages/global/core/app/constants.ts | 2 - packages/service/core/app/controller.ts | 34 ----------- packages/web/common/system/utils.ts | 10 ++-- .../core/app/DatasetParamsModal.tsx | 37 +++++++----- .../ChatBox/Input/VoiceInput.tsx | 33 +++++------ .../Flow/nodes/NodeDatasetConcat.tsx | 56 +++++++++++++------ .../templates/SelectDatasetParams.tsx | 7 +-- 8 files changed, 91 insertions(+), 90 deletions(-) diff --git a/docSite/content/zh-cn/docs/development/upgrading/4910.md b/docSite/content/zh-cn/docs/development/upgrading/4910.md index c5122e77b..a7e248cdb 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/4910.md +++ b/docSite/content/zh-cn/docs/development/upgrading/4910.md @@ -17,6 +17,8 @@ weight: 790 1. LLM stream调用,默认超时调大。 2. 部分确认交互优化。 3. 纠正原先知识库的“表格数据集”名称,改成“备份导入”。同时支持知识库索引的导出和导入。 +4. 工作流知识库引用上限,如果工作流中没有相关 AI 节点,则交互模式改成纯手动输入,并且上限为 1000万。 +5. 语音输入,移动端判断逻辑,准确判断是否为手机,而不是小屏。 ## 🐛 修复 diff --git a/packages/global/core/app/constants.ts b/packages/global/core/app/constants.ts index af3f0a859..7a0cf126b 100644 --- a/packages/global/core/app/constants.ts +++ b/packages/global/core/app/constants.ts @@ -60,5 +60,3 @@ export enum AppTemplateTypeEnum { // special type contribute = 'contribute' } - -export const defaultDatasetMaxTokens = 16000; diff --git a/packages/service/core/app/controller.ts b/packages/service/core/app/controller.ts index 4cc307c82..78e22e24b 100644 --- a/packages/service/core/app/controller.ts +++ b/packages/service/core/app/controller.ts @@ -11,40 +11,6 @@ export const beforeUpdateAppFormat = { - if (nodes) { - // Check dataset maxTokens - if (isPlugin) { - let maxTokens = 16000; - - nodes.forEach((item) => { - if ( - item.flowNodeType === FlowNodeTypeEnum.chatNode || - item.flowNodeType === FlowNodeTypeEnum.tools - ) { - const model = - item.inputs.find((item) => item.key === NodeInputKeyEnum.aiModel)?.value || ''; - const chatModel = getLLMModel(model); - const quoteMaxToken = chatModel.quoteMaxToken || 16000; - - maxTokens = Math.max(maxTokens, quoteMaxToken); - } - }); - - nodes.forEach((item) => { - if (item.flowNodeType === FlowNodeTypeEnum.datasetSearchNode) { - item.inputs.forEach((input) => { - if (input.key === NodeInputKeyEnum.datasetMaxTokens) { - const val = input.value as number; - if (val > maxTokens) { - input.value = maxTokens; - } - } - }); - } - }); - } - } - return { nodes }; diff --git a/packages/web/common/system/utils.ts b/packages/web/common/system/utils.ts index ade6b690a..db05a54fb 100644 --- a/packages/web/common/system/utils.ts +++ b/packages/web/common/system/utils.ts @@ -18,10 +18,10 @@ export const getWebReqUrl = (url: string = '') => { }; export const isMobile = () => { - // 服务端渲染时返回 false + // SSR return false if (typeof window === 'undefined') return false; - // 1. 检查 User-Agent + // 1. Check User-Agent const userAgent = navigator.userAgent.toLowerCase(); const mobileKeywords = [ 'android', @@ -36,12 +36,12 @@ export const isMobile = () => { ]; const isMobileUA = mobileKeywords.some((keyword) => userAgent.includes(keyword)); - // 2. 检查屏幕宽度 + // 2. Check screen width const isMobileWidth = window.innerWidth <= 900; - // 3. 检查是否支持触摸事件(排除触控屏PC) + // 3. Check if touch events are supported (exclude touch screen PCs) const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0; - // 综合判断:满足以下任一条件即视为移动端 + // If any of the following conditions are met, it is considered a mobile device return isMobileUA || (isMobileWidth && isTouchDevice); }; diff --git a/projects/app/src/components/core/app/DatasetParamsModal.tsx b/projects/app/src/components/core/app/DatasetParamsModal.tsx index a1baa614d..fca020b45 100644 --- a/projects/app/src/components/core/app/DatasetParamsModal.tsx +++ b/projects/app/src/components/core/app/DatasetParamsModal.tsx @@ -25,11 +25,11 @@ import SelectAiModel from '@/components/Select/AIModelSelector'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import MyTextarea from '@/components/common/Textarea/MyTextarea'; -import { defaultDatasetMaxTokens } from '@fastgpt/global/core/app/constants'; import InputSlider from '@fastgpt/web/components/common/MySlider/InputSlider'; import LeftRadio from '@fastgpt/web/components/common/Radio/LeftRadio'; import { type AppDatasetSearchParamsType } from '@fastgpt/global/core/app/type'; import MyIcon from '@fastgpt/web/components/common/Icon'; +import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput'; enum SearchSettingTabEnum { searchMode = 'searchMode', @@ -48,7 +48,7 @@ const DatasetParamsModal = ({ datasetSearchUsingExtensionQuery, datasetSearchExtensionModel, datasetSearchExtensionBg, - maxTokens = defaultDatasetMaxTokens, + maxTokens, onClose, onSuccess }: AppDatasetSearchParamsType & { @@ -130,7 +130,7 @@ const DatasetParamsModal = ({ // 保证只有 80 左右个刻度。 const maxTokenStep = useMemo(() => { - if (maxTokens < 8000) return 80; + if (!maxTokens || maxTokens < 8000) return 80; return Math.ceil(maxTokens / 80 / 100) * 100; }, [maxTokens]); @@ -301,16 +301,27 @@ const DatasetParamsModal = ({ - { - setValue(NodeInputKeyEnum.datasetMaxTokens, val); - setRefresh(!refresh); - }} - /> + {maxTokens ? ( + { + setValue(NodeInputKeyEnum.datasetMaxTokens, val); + setRefresh(!refresh); + }} + /> + ) : ( + + )} )} diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/VoiceInput.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/VoiceInput.tsx index 04fe2e5c5..284f3cbf3 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/VoiceInput.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/VoiceInput.tsx @@ -214,7 +214,8 @@ const MobileVoiceInput = ({ const VoiceInput = forwardRef( ({ onSendMessage, resetInputVal }, ref) => { const { t } = useTranslation(); - const isPc = !isMobile(); + const isMobileDevice = isMobile(); + const { isPc } = useSystem(); const outLinkAuthData = useContextSelector(ChatBoxContext, (v) => v.outLinkAuthData); const appId = useContextSelector(ChatBoxContext, (v) => v.appId); @@ -265,10 +266,10 @@ const VoiceInput = forwardRef( return; } - if (isPc) { - renderAudioGraphPc(analyser, canvas); - } else { + if (isMobileDevice) { renderAudioGraphMobile(analyser, canvas); + } else { + renderAudioGraphPc(analyser, canvas); } animationFrameId = window.requestAnimationFrame(renderCurve); }; @@ -283,7 +284,7 @@ const VoiceInput = forwardRef( source.disconnect(); analyser.disconnect(); }; - }, [stream, canvasRef, renderAudioGraphPc, renderAudioGraphMobile, isPc]); + }, [stream, canvasRef, renderAudioGraphPc, renderAudioGraphMobile, isMobileDevice]); const onStartSpeak = useCallback(() => { const finishWhisperTranscription = (text: string) => { @@ -301,12 +302,12 @@ const VoiceInput = forwardRef( }, [autoTTSResponse, onSendMessage, resetInputVal, startSpeak, whisperConfig?.autoSend]); const onSpeach = useCallback(() => { - if (isPc) { - onStartSpeak(); - } else { + if (isMobileDevice) { setMobilePreSpeak(true); + } else { + onStartSpeak(); } - }, [isPc, onStartSpeak]); + }, [isMobileDevice, onStartSpeak]); useImperativeHandle(ref, () => ({ onSpeak: onSpeach })); @@ -328,13 +329,7 @@ const VoiceInput = forwardRef( borderRadius={isPc ? 'md' : ''} onContextMenu={(e) => e.preventDefault()} > - {isPc ? ( - - ) : ( + {isMobileDevice ? ( ( stopSpeak={stopSpeak} canvasRef={canvasRef} /> + ) : ( + )} {isTransCription && ( diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeDatasetConcat.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeDatasetConcat.tsx index 8ddaea171..76639cb0b 100644 --- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeDatasetConcat.tsx +++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeDatasetConcat.tsx @@ -24,6 +24,8 @@ import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel'; import ValueTypeLabel from './render/ValueTypeLabel'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { getWebLLMModel } from '@/web/common/system/utils'; +import InputSlider from '@fastgpt/web/components/common/MySlider/InputSlider'; +import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput'; const NodeDatasetConcat = ({ data, selected }: NodeProps) => { const { t } = useTranslation(); @@ -32,35 +34,58 @@ const NodeDatasetConcat = ({ data, selected }: NodeProps) => { const CustomComponent = useMemo(() => { const quoteList = inputs.filter((item) => item.canEdit); - const tokenLimit = (() => { - let maxTokens = 16000; + const maxTokens = (() => { + let maxTokens = 0; nodeList.forEach((item) => { if ([FlowNodeTypeEnum.chatNode, FlowNodeTypeEnum.tools].includes(item.flowNodeType)) { const model = item.inputs.find((item) => item.key === NodeInputKeyEnum.aiModel)?.value || ''; - const quoteMaxToken = getWebLLMModel(model)?.quoteMaxToken || 16000; + const quoteMaxToken = getWebLLMModel(model)?.quoteMaxToken || 0; maxTokens = Math.max(maxTokens, quoteMaxToken); } }); - return maxTokens; + return maxTokens ? maxTokens : undefined; + })(); + + const maxTokenStep = (() => { + if (!maxTokens || maxTokens < 8000) return 80; + return Math.ceil(maxTokens / 80 / 100) * 100; })(); return { - [NodeInputKeyEnum.datasetMaxTokens]: (item: FlowNodeInputItemType) => ( - - + maxTokens ? ( + + { + onChangeNode({ + nodeId, + type: 'updateInput', + key: item.key, + value: { + ...item, + value: e + } + }); + }} + /> + + ) : ( + { onChangeNode({ nodeId, @@ -73,8 +98,7 @@ const NodeDatasetConcat = ({ data, selected }: NodeProps) => { }); }} /> - - ), + ), [NodeInputKeyEnum.datasetQuoteList]: (item: FlowNodeInputItemType) => { return ( <> diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDatasetParams.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDatasetParams.tsx index 9968269b9..60b744122 100644 --- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDatasetParams.tsx +++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDatasetParams.tsx @@ -12,7 +12,6 @@ import SearchParamsTip from '@/components/core/dataset/SearchParamsTip'; import { useContextSelector } from 'use-context-selector'; import { WorkflowContext } from '@/pageComponents/app/detail/WorkflowComponents/context'; import { getWebLLMModel } from '@/web/common/system/utils'; -import { defaultDatasetMaxTokens } from '@fastgpt/global/core/app/constants'; import { type AppDatasetSearchParamsType } from '@fastgpt/global/core/app/type'; const SelectDatasetParam = ({ inputs = [], nodeId }: RenderInputProps) => { @@ -36,19 +35,19 @@ const SelectDatasetParam = ({ inputs = [], nodeId }: RenderInputProps) => { }); const tokenLimit = useMemo(() => { - let maxTokens = defaultDatasetMaxTokens; + let maxTokens = 0; nodeList.forEach((item) => { if ([FlowNodeTypeEnum.chatNode, FlowNodeTypeEnum.tools].includes(item.flowNodeType)) { const model = item.inputs.find((item) => item.key === NodeInputKeyEnum.aiModel)?.value || ''; - const quoteMaxToken = getWebLLMModel(model)?.quoteMaxToken || defaultDatasetMaxTokens; + const quoteMaxToken = getWebLLMModel(model)?.quoteMaxToken ?? 0; maxTokens = Math.max(maxTokens, quoteMaxToken); } }); - return maxTokens; + return maxTokens ? maxTokens : undefined; }, [nodeList]); const { isOpen, onOpen, onClose } = useDisclosure();