diff --git a/docSite/content/zh-cn/docs/development/upgrading/4810.md b/docSite/content/zh-cn/docs/development/upgrading/4810.md index a2d9edae4494..34440338661a 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/4810.md +++ b/docSite/content/zh-cn/docs/development/upgrading/4810.md @@ -53,19 +53,27 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4810' \ 4. 新增 - 工作流撤销和重做 5. 新增 - 工作流本次编辑记录,取代自动保存 6. 新增 - 工作流版本支持重命名 -7. 商业版新增 - 飞书机器人接入 -8. 商业版新增 - 公众号接入接入 -9. 商业版新增 - 自助开票申请 -10. 商业版新增 - SSO 定制 -11. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。 -12. 优化 - 节点选择,避免切换 tab 时候,path 加载报错。 -13. 优化 - 最新 React Markdown 组件,支持 Base64 图片。 -14. 优化 - 知识库列表 UI。 -15. 优化 - 支持无网络配置情况下运行。 -16. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。 -17. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。 -18. 修复 - 选择 Milvus 部署时,无法导出知识库。 -19. 修复 - 创建 APP 副本,无法复制系统配置。 -20. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。 -21. 修复 - 内容提取的数据类型与输出数据类型未一致。 -22. 修复 - 工作流运行时间统计错误。 +7. 新增 - 应用调用迁移成单独节点,同时可以传递全局变量和用户的文件。 +8. 商业版新增 - 飞书机器人接入 +9. 商业版新增 - 公众号接入接入 +10. 商业版新增 - 自助开票申请 +11. 商业版新增 - SSO 定制 +12. 优化 - SSE 响应优化。 +13. 优化 - 无 SSL 证书情况下,优化复制。 +14. 优化 - 单选框打开后自动滚动到选中的位置。 +15. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。 +16. 优化 - 节点选择,避免切换 tab 时候,path 加载报错。 +17. 优化 - 最新 React Markdown 组件,支持 Base64 图片。 +18. 优化 - 知识库列表 UI。 +19. 优化 - 支持无网络配置情况下运行。 +20. 优化 - 部分全局变量,增加数据类型约束。 +21. 修复 - 全局变量 key 可能重复。 +22. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。 +23. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。 +24. 修复 - 选择 Milvus 部署时,无法导出知识库。 +25. 修复 - 创建 APP 副本,无法复制系统配置。 +26. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。 +27. 修复 - 内容提取的数据类型与输出数据类型未一致。 +28. 修复 - 工作流运行时间统计错误。 +29. 修复 - stream 模式下,工具调用有可能出现 undefined +30. 修复 - 全局变量在 API 中无法持久化。 diff --git a/packages/global/core/workflow/template/constants.ts b/packages/global/core/workflow/template/constants.ts index a981286ba8a7..e59c801d80b4 100644 --- a/packages/global/core/workflow/template/constants.ts +++ b/packages/global/core/workflow/template/constants.ts @@ -45,8 +45,7 @@ const systemNodes: FlowNodeTemplateType[] = [ LafModule, IfElseNode, VariableUpdateNode, - CodeNode, - RunAppModule + CodeNode ]; /* app flow module templates */ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [ @@ -72,5 +71,6 @@ export const moduleTemplatesFlat: FlowNodeTemplateType[] = [ ), EmptyNode, RunPluginModule, - RunAppPluginModule + RunAppPluginModule, + RunAppModule ]; diff --git a/packages/global/support/wallet/sub/constants.ts b/packages/global/support/wallet/sub/constants.ts index 8f43279c9d3b..9072ae24f383 100644 --- a/packages/global/support/wallet/sub/constants.ts +++ b/packages/global/support/wallet/sub/constants.ts @@ -72,15 +72,3 @@ export const standardSubLevelMap = { weight: 5 } }; - -export enum PackageChangeStatusEnum { - buy = 'buy', - renewal = 'renewal', - upgrade = 'upgrade' -} - -export const packagePayTextMap = { - [PackageChangeStatusEnum.buy]: i18nT('common:pay.package_tip.buy'), - [PackageChangeStatusEnum.renewal]: i18nT('common:pay.package_tip.renewal'), - [PackageChangeStatusEnum.upgrade]: i18nT('common:pay.package_tip.upgrade') -}; diff --git a/packages/service/core/chat/controller.ts b/packages/service/core/chat/controller.ts index 4acfbb6830bd..aef458ce98d0 100644 --- a/packages/service/core/chat/controller.ts +++ b/packages/service/core/chat/controller.ts @@ -5,7 +5,6 @@ import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/c import { delFileByFileIdList, getGFSCollection } from '../../common/file/gridfs/controller'; import { BucketNameEnum } from '@fastgpt/global/common/file/constants'; import { MongoChat } from './chatSchema'; -import { ChatSchema as ChatType } from '@fastgpt/global/core/chat/type.d'; export async function getChatItems({ appId, @@ -37,24 +36,6 @@ export async function getChatItems({ return { histories }; } -export async function getChat({ - appId, - chatId, - field -}: { - appId: string; - chatId?: string; - field: string; -}): Promise<{ chat: ChatType | null }> { - if (!chatId) { - return { chat: null }; - } - - const chat = await MongoChat.findOne({ appId, chatId }, field).lean(); - - return { chat }; -} - /* Temporary adaptation for old conversation records */ export const adaptStringValue = (value: any): ChatItemValueItemType[] => { if (typeof value === 'string') { diff --git a/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts b/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts index f6c9affdef45..92aa035956cc 100644 --- a/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts +++ b/packages/service/core/workflow/dispatch/agent/runTool/promptCall.ts @@ -357,7 +357,7 @@ async function streamResponse({ const responseChoice = part.choices?.[0]?.delta; // console.log(responseChoice, '---==='); - if (responseChoice.content) { + if (responseChoice?.content) { const content = responseChoice?.content || ''; textAnswer += content; diff --git a/packages/web/components/common/MyMenu/index.tsx b/packages/web/components/common/MyMenu/index.tsx index 267e4460890c..357284114935 100644 --- a/packages/web/components/common/MyMenu/index.tsx +++ b/packages/web/components/common/MyMenu/index.tsx @@ -44,7 +44,7 @@ const MyMenu = ({ iconSize = '1rem', Button, menuList, - iconRadius = 'sm', + iconRadius, placement = 'bottom-start' }: Props) => { const typeMapStyle: Record = { diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index 4738fb4b9b40..00447dc5cf66 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -126,6 +126,7 @@ "Confirm to leave the page": "Confirm to leave the page?", "Copy": "Copy", "Copy Successful": "Copy Successful", + "Copy_failed": "Copy failed, please copy manually", "Create Failed": "Create Failed", "Create New": "Create New", "Create Success": "Create Success", @@ -1430,7 +1431,7 @@ "Quote Content Tip": "You can customize the structure of the quote content to better adapt to different scenarios. You can use some variables for template configuration:\n{{q}} - search content, {{a}} - expected content, {{source}} - source, {{sourceId}} - source file name, {{index}} - the nth quote, they are all optional, here are the default values:\n{{default}}", "Quote Prompt Tip": "You can use {{quote}} to insert the quote content template, and use {{question}} to insert the question. Here are the default values:\n{{default}}" }, - "textarea_variable_picker_tip": "Input / to select variables", + "textarea_variable_picker_tip": "Input '/' to select variables", "tool_field": "Tool field parameter configuration", "undefined_var": "An undefined variable is referenced. Is it automatically added?", "unit": { diff --git a/packages/web/i18n/zh/common.json b/packages/web/i18n/zh/common.json index 506a137515e4..54b800351beb 100644 --- a/packages/web/i18n/zh/common.json +++ b/packages/web/i18n/zh/common.json @@ -128,6 +128,7 @@ "Confirm to leave the page": "确认离开该页面?", "Copy": "复制", "Copy Successful": "复制成功", + "Copy_failed": "复制失败,请手动复制", "Create Failed": "创建异常", "Create New": "新建", "Create Success": "创建成功", @@ -637,7 +638,8 @@ "success": "开始同步" } }, - "training": {} + "training": { + } }, "data": { "Auxiliary Data": "辅助数据", @@ -1429,7 +1431,7 @@ "Quote Content Tip": "可以自定义引用内容的结构,以更好的适配不同场景。可以使用一些变量来进行模板配置:\n{{q}} - 检索内容,{{a}} - 预期内容,{{source}} - 来源,{{sourceId}} - 来源文件名,{{index}} - 第 n 个引用,他们都是可选的,下面是默认值:\n{{default}}", "Quote Prompt Tip": "可以用 {{quote}} 来插入引用内容模板,使用 {{question}} 来插入问题。下面是默认值:\n{{default}}" }, - "textarea_variable_picker_tip": "输入 / 可选择变量", + "textarea_variable_picker_tip": "输入\"/\"可选择变量", "tool_field": "工具字段参数配置", "undefined_var": "引用了未定义的变量,是否自动添加?", "unit": { diff --git a/projects/app/src/components/support/apikey/Table.tsx b/projects/app/src/components/support/apikey/Table.tsx index 2f1459ab17a9..c5b56c3a268e 100644 --- a/projects/app/src/components/support/apikey/Table.tsx +++ b/projects/app/src/components/support/apikey/Table.tsx @@ -58,6 +58,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => { const [baseUrl, setBaseUrl] = useState('https://fastgpt.in/api'); const [editData, setEditData] = useState(); const [apiKey, setApiKey] = useState(''); + const { ConfirmModal, openConfirm } = useConfirm({ type: 'delete', content: t('workflow:delete_api') @@ -271,6 +272,7 @@ const ApiKeyTable = ({ tips, appId }: { tips: string; appId?: string }) => { wordBreak={'break-all'} cursor={'pointer'} borderRadius={'md'} + userSelect={'all'} onClick={() => copyData(apiKey)} > {apiKey} diff --git a/projects/app/src/components/support/wallet/QRCodePayModal.tsx b/projects/app/src/components/support/wallet/QRCodePayModal.tsx index af84fd1b5f33..b5a513cd9ff0 100644 --- a/projects/app/src/components/support/wallet/QRCodePayModal.tsx +++ b/projects/app/src/components/support/wallet/QRCodePayModal.tsx @@ -75,7 +75,7 @@ const QRCodePayModal = ({ {tip && ( - + {tip} )} diff --git a/projects/app/src/components/support/wallet/StandardPlanContentList.tsx b/projects/app/src/components/support/wallet/StandardPlanContentList.tsx index ad0bb41ad770..de8c26d86949 100644 --- a/projects/app/src/components/support/wallet/StandardPlanContentList.tsx +++ b/projects/app/src/components/support/wallet/StandardPlanContentList.tsx @@ -43,7 +43,7 @@ const StandardPlanContentList = ({ }, [subPlans?.standard, level, mode]); return planContent ? ( - + diff --git a/projects/app/src/pages/account/components/ApiKeyTable.tsx b/projects/app/src/pages/account/components/ApiKeyTable.tsx index 5b9110a448b2..2ae46b2cfc5d 100644 --- a/projects/app/src/pages/account/components/ApiKeyTable.tsx +++ b/projects/app/src/pages/account/components/ApiKeyTable.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { useTranslation } from 'next-i18next'; import ApiKeyTable from '@/components/support/apikey/Table'; import { useI18n } from '@/web/context/I18n'; import { Box } from '@chakra-ui/react'; diff --git a/projects/app/src/pages/account/components/Info/standardDetailModal.tsx b/projects/app/src/pages/account/components/Info/standardDetailModal.tsx index e8ac1801ed1c..3a7ff3c1503b 100644 --- a/projects/app/src/pages/account/components/Info/standardDetailModal.tsx +++ b/projects/app/src/pages/account/components/Info/standardDetailModal.tsx @@ -16,7 +16,6 @@ import { } from '@chakra-ui/react'; import MyModal from '@fastgpt/web/components/common/MyModal'; import { useTranslation } from 'next-i18next'; -import { useQuery } from '@tanstack/react-query'; import { useLoading } from '@fastgpt/web/hooks/useLoading'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { getTeamPlans } from '@/web/support/user/team/api'; @@ -25,7 +24,6 @@ import { standardSubLevelMap, SubTypeEnum } from '@fastgpt/global/support/wallet/sub/constants'; -import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type'; import { formatTime2YMDHM } from '@fastgpt/global/common/string/time'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; @@ -71,7 +69,7 @@ const StandDetailModal = ({ onClose }: { onClose: () => void }) => { isCentered > - + @@ -100,7 +98,6 @@ const StandDetailModal = ({ onClose }: { onClose: () => void }) => { ? subPlans?.standard?.[currentSubLevel] : undefined; const datasetSize = standardPlan?.maxDatasetSize || currentExtraDatasetSize; - const now = new Date(); return ( diff --git a/projects/app/src/pages/api/v1/chat/completions.ts b/projects/app/src/pages/api/v1/chat/completions.ts index a23e6b79b5d9..3c1a9d410c0c 100644 --- a/projects/app/src/pages/api/v1/chat/completions.ts +++ b/projects/app/src/pages/api/v1/chat/completions.ts @@ -20,7 +20,7 @@ import { textAdaptGptResponse } from '@fastgpt/global/core/workflow/runtime/utils'; import { GPTMessages2Chats, chatValue2RuntimePrompt } from '@fastgpt/global/core/chat/adapt'; -import { getChat, getChatItems } from '@fastgpt/service/core/chat/controller'; +import { getChatItems } from '@fastgpt/service/core/chat/controller'; import { saveChat } from '@fastgpt/service/core/chat/saveChat'; import { responseWrite } from '@fastgpt/service/common/response'; import { pushChatUsage } from '@/service/support/wallet/usage/push'; @@ -216,11 +216,10 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { } return latestHumanChat; })(); - const { text, files } = chatValue2RuntimePrompt(userQuestion.value); // Get and concat history; const limit = getMaxHistoryLimitFromNodes(app.modules); - const [{ histories }, { nodes, edges, chatConfig }, { chat }] = await Promise.all([ + const [{ histories }, { nodes, edges, chatConfig }, chatDetail] = await Promise.all([ getChatItems({ appId: app._id, chatId, @@ -228,32 +227,27 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { field: `dataId obj value nodeOutputs` }), getAppLatestVersion(app._id, app), - getChat({ - appId: app._id, - chatId, - field: 'source variableList variables' - }) + MongoChat.findOne({ appId: app._id, chatId }, 'source variableList variables') ]); - // get chat histories + + // Get chat histories const newHistories = concatHistories(histories, chatMessages); - // get global variables - if (chat && chat.variables) { + // Get store variables(Api variable precedence) + if (chatDetail?.variables) { variables = { - ...chat.variables, + ...chatDetail.variables, ...variables }; } // Get runtimeNodes let runtimeNodes = storeNodes2RuntimeNodes(nodes, getWorkflowEntryNodeIds(nodes, newHistories)); - if (isPlugin) { // Rewrite plugin run params variables variables = removePluginInputVariables(variables, runtimeNodes); runtimeNodes = updatePluginInputByVariables(runtimeNodes, variables); } - runtimeNodes = rewriteNodeOutputByHistories(newHistories, runtimeNodes); const workflowResponseWrite = getWorkflowResponseWrite({ diff --git a/projects/app/src/pages/app/detail/components/Logs/DetailLogsModal.tsx b/projects/app/src/pages/app/detail/components/Logs/DetailLogsModal.tsx index 359809ec4531..8c3848a8f99e 100644 --- a/projects/app/src/pages/app/detail/components/Logs/DetailLogsModal.tsx +++ b/projects/app/src/pages/app/detail/components/Logs/DetailLogsModal.tsx @@ -1,10 +1,8 @@ import React from 'react'; import { Flex, Box, useTheme } from '@chakra-ui/react'; -import MyIcon from '@fastgpt/web/components/common/Icon'; import { useTranslation } from 'next-i18next'; import { HUMAN_ICON } from '@fastgpt/global/common/system/constants'; import { getInitChatInfo } from '@/web/core/chat/api'; -import MyTag from '@fastgpt/web/components/common/Tag/index'; import MyBox from '@fastgpt/web/components/common/MyBox'; import { getNanoid } from '@fastgpt/global/common/string/tools'; import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; @@ -17,6 +15,8 @@ import CloseIcon from '@fastgpt/web/components/common/Icon/close'; import ChatBox from '@/components/core/chat/ChatContainer/ChatBox'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { useQuery } from '@tanstack/react-query'; +import { PcHeader } from '@/pages/chat/components/ChatHeader'; + const PluginRunBox = dynamic(() => import('@/components/core/chat/ChatContainer/PluginRunBox')); const DetailLogsModal = ({ @@ -124,26 +124,7 @@ const DetailLogsModal = ({ > {isPc ? ( <> - - {title} - - {chatRecords.length > 0 && ( - <> - - - - {t('common:core.chat.History Amount', { amount: chatRecords.length })} - - - {!!chatModels && ( - - - {chatModels.join(',')} - - )} - - )} - + ) : ( diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx index deec761dfd02..0b57fee04721 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx @@ -408,7 +408,6 @@ const RenderList = React.memo(function RenderList({ templates.forEach((item) => { const index = copy.findIndex((template) => template.type === item.templateType); if (index === -1) return; - if (item.flowNodeType === FlowNodeTypeEnum.runApp) return; copy[index].list.push(item); }); return copy.filter((item) => item.list.length > 0); diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeWorkflowStart.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeWorkflowStart.tsx index fcbeef48d285..726294eca954 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeWorkflowStart.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeWorkflowStart.tsx @@ -52,7 +52,7 @@ const NodeStart = ({ data, selected }: NodeProps) => { label: item.label }; }); - }, [nodeList, t]); + }, [nodeList, appDetail.chatConfig, t]); return ( - + {title} diff --git a/projects/app/src/pages/price/components/Standard.tsx b/projects/app/src/pages/price/components/Standard.tsx index 8dda48d8e0b5..b6650b15ef15 100644 --- a/projects/app/src/pages/price/components/Standard.tsx +++ b/projects/app/src/pages/price/components/Standard.tsx @@ -2,12 +2,7 @@ import React, { useMemo, useState } from 'react'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { Box, Button, Flex, Grid, HStack } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; -import { - StandardSubLevelEnum, - SubModeEnum, - PackageChangeStatusEnum, - packagePayTextMap -} from '@fastgpt/global/support/wallet/sub/constants'; +import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; @@ -16,8 +11,12 @@ import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRC import { getWxPayQRCode } from '@/web/support/wallet/bill/api'; import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants'; import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList'; -import { useRouter } from 'next/router'; -import { useToast } from '@fastgpt/web/hooks/useToast'; + +export enum PackageChangeStatusEnum { + buy = 'buy', + renewal = 'renewal', + upgrade = 'upgrade' +} const Standard = ({ standardPlan: myStandardPlan, @@ -27,8 +26,13 @@ const Standard = ({ refetchTeamSubPlan: () => void; }) => { const { t } = useTranslation(); - const router = useRouter(); - const { toast } = useToast(); + + const packagePayTextMap = { + [PackageChangeStatusEnum.buy]: t('common:pay.package_tip.buy'), + [PackageChangeStatusEnum.renewal]: t('common:pay.package_tip.renewal'), + [PackageChangeStatusEnum.upgrade]: t('common:pay.package_tip.upgrade') + }; + const [packageChange, setPackageChange] = useState(); const { subPlans, feConfigs } = useSystemStore(); const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month); @@ -177,7 +181,8 @@ const Standard = ({ boxShadow={'0'} cursor={'default'} w={'100%'} - variant={isCurrentPlan ? 'whiteBase' : 'solid'} + isDisabled + variant={'whiteBase'} > {t('common:free')} @@ -265,7 +270,7 @@ const Standard = ({ {!!qrPayData && packageChange && ( - + )} diff --git a/projects/app/src/web/common/hooks/useCopyData.tsx b/projects/app/src/web/common/hooks/useCopyData.tsx index a9b24858d813..3dbcde2d90f3 100644 --- a/projects/app/src/web/common/hooks/useCopyData.tsx +++ b/projects/app/src/web/common/hooks/useCopyData.tsx @@ -2,6 +2,7 @@ import { useTranslation } from 'next-i18next'; import { useToast } from '@fastgpt/web/hooks/useToast'; import { useCallback } from 'react'; import { hasHttps } from '@fastgpt/web/common/system/utils'; +import { isProduction } from '@fastgpt/service/common/system/constants'; /** * copy text data @@ -17,20 +18,31 @@ export const useCopyData = () => { duration = 1000 ) => { try { - if (hasHttps() && navigator.clipboard) { + if (hasHttps() && !isProduction && navigator.clipboard) { await navigator.clipboard.writeText(data); } else { throw new Error(''); } } catch (error) { - console.log(error); + // console.log(error); const textarea = document.createElement('textarea'); textarea.value = data; + textarea.style.position = 'absolute'; + textarea.style.opacity = '0'; document.body.appendChild(textarea); + textarea.select(); - document.execCommand('copy'); - document.body?.removeChild(textarea); + const res = document.execCommand('copy'); + document.body.removeChild(textarea); + + if (!res) { + return toast({ + title: t('common:common.Copy_failed'), + status: 'error', + duration + }); + } } if (title) {