diff --git a/.github/imgs/intro1.png b/.github/imgs/intro1.png index 048841628bfc..78c3031ebda7 100644 Binary files a/.github/imgs/intro1.png and b/.github/imgs/intro1.png differ diff --git a/.github/imgs/intro2.png b/.github/imgs/intro2.png index ae723b63c4c2..7846424a4b54 100644 Binary files a/.github/imgs/intro2.png and b/.github/imgs/intro2.png differ diff --git a/.github/imgs/intro3.png b/.github/imgs/intro3.png index 9e89f946cbe7..22184c6b5c66 100644 Binary files a/.github/imgs/intro3.png and b/.github/imgs/intro3.png differ diff --git a/.github/imgs/intro4.png b/.github/imgs/intro4.png index e4bac94fc829..be1fc9528758 100644 Binary files a/.github/imgs/intro4.png and b/.github/imgs/intro4.png differ diff --git a/docSite/content/zh-cn/docs/development/upgrading/4810.md b/docSite/content/zh-cn/docs/development/upgrading/4810.md index f676b5924908..e32975893fb0 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/4810.md +++ b/docSite/content/zh-cn/docs/development/upgrading/4810.md @@ -24,6 +24,9 @@ weight: 816 3. 新增 - 用户选择节点(Debug 模式暂未支持) 4. 商业版新增 - 飞书机器人接入 5. 商业版新增 - 公众号接入接入 -6. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。 -7. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。 -8. 修复 - 选择 Milvus 部署时,无法导出知识库。 +6. 优化 - 知识库集合禁用,目录禁用会递归修改其下所有 children 的禁用状态。 +7. 修复 - Prompt 模式调用工具,stream=false 模式下,会携带 0: 开头标记。 +8. 修复 - 对话日志鉴权问题:仅为 APP 管理员的用户,无法查看对话日志详情。 +9. 修复 - 选择 Milvus 部署时,无法导出知识库。 +10. 修复 - 创建 APP 副本,无法复制系统配置。 +11. 修复 - 图片识别模式下,自动解析图片链接正则不够严谨问题。 diff --git a/docSite/content/zh-cn/docs/use-cases/feishu.md b/docSite/content/zh-cn/docs/use-cases/feishu.md index c8f1ab4d036c..775adf5c83c3 100644 --- a/docSite/content/zh-cn/docs/use-cases/feishu.md +++ b/docSite/content/zh-cn/docs/use-cases/feishu.md @@ -1,11 +1,12 @@ --- -title: "教程 - 接入飞书机器人" -description: "FastGPT 接入飞书机器人" +title: "接入飞书机器人教程" +description: "FastGPT 接入飞书机器人教程" icon: "chat" draft: false toc: true weight: 507 --- + ## 1. 申请飞书应用 开一个免费的测试企业更方便进行调试。 diff --git a/packages/global/core/workflow/constants.ts b/packages/global/core/workflow/constants.ts index 6b8085541d79..e343d4d93de1 100644 --- a/packages/global/core/workflow/constants.ts +++ b/packages/global/core/workflow/constants.ts @@ -1,3 +1,5 @@ +import { i18nT } from '../../../web/i18n/utils'; + export enum FlowNodeTemplateTypeEnum { systemInput = 'systemInput', ai = 'ai', @@ -181,23 +183,23 @@ export enum VariableInputEnum { export const variableMap = { [VariableInputEnum.input]: { icon: 'core/app/variable/input', - title: 'core.module.variable.input type', + title: i18nT('common:core.module.variable.input type'), desc: '' }, [VariableInputEnum.textarea]: { icon: 'core/app/variable/textarea', - title: 'core.module.variable.textarea type', - desc: '允许用户最多输入4000字的对话框。' + title: i18nT('common:core.module.variable.textarea type'), + desc: i18nT('app:variable.textarea_type_desc') }, [VariableInputEnum.select]: { icon: 'core/app/variable/select', - title: 'core.module.variable.select type', + title: i18nT('common:core.module.variable.select type'), desc: '' }, [VariableInputEnum.custom]: { icon: 'core/app/variable/external', - title: 'core.module.variable.Custom type', - desc: '可以定义一个无需用户填写的全局变量。\n该变量的值可以来自于 API 接口,分享链接的 Query 或通过【变量更新】模块进行赋值。' + title: i18nT('common:core.module.variable.Custom type'), + desc: i18nT('app:variable.select type_desc') } }; diff --git a/packages/service/core/chat/utils.ts b/packages/service/core/chat/utils.ts index 8795b545e5b4..a01999781462 100644 --- a/packages/service/core/chat/utils.ts +++ b/packages/service/core/chat/utils.ts @@ -118,7 +118,8 @@ export const loadRequestMessages = async ({ } // 正则表达式匹配图片URL - const imageRegex = /(https?:\/\/.*\.(?:png|jpe?g|gif|webp|bmp|tiff?|svg|ico|heic|avif))/i; + const imageRegex = + /(https?:\/\/[^\s/$.?#].[^\s]*\.(?:png|jpe?g|gif|webp|bmp|tiff?|svg|ico|heic|avif))/i; const result: { type: 'text' | 'image'; value: string }[] = []; let lastIndex = 0; diff --git a/packages/service/core/workflow/dispatch/tools/http468.ts b/packages/service/core/workflow/dispatch/tools/http468.ts index b0fafbd74620..216034b97db6 100644 --- a/packages/service/core/workflow/dispatch/tools/http468.ts +++ b/packages/service/core/workflow/dispatch/tools/http468.ts @@ -110,10 +110,15 @@ export const dispatchHttp468Request = async (props: HttpRequestProps): Promise { if (!httpJsonBody) return {}; try { + // Replace all variables in the string body httpJsonBody = replaceVariable(httpJsonBody, allVariables); + + // Text body, return directly if (headers['Content-Type']?.includes('text/plain')) { return httpJsonBody?.replaceAll(UNDEFINED_SIGN, 'null'); } + + // Json body, parse and return const jsonParse = JSON.parse(httpJsonBody); const removeSignJson = removeUndefinedSign(jsonParse); return removeSignJson; diff --git a/packages/web/components/common/MyModal/index.tsx b/packages/web/components/common/MyModal/index.tsx index 35625f7e05f1..9c9988ef0b60 100644 --- a/packages/web/components/common/MyModal/index.tsx +++ b/packages/web/components/common/MyModal/index.tsx @@ -35,7 +35,7 @@ const MyModal = ({ closeOnOverlayClick = true, ...props }: MyModalProps) => { - const isPc = useSystem(); + const { isPc } = useSystem(); return ( + + + diff --git a/projects/app/public/imgs/app/variable.svg b/projects/app/public/imgs/app/variable.svg index c8a3551bb304..12f14bcfd685 100644 --- a/projects/app/public/imgs/app/variable.svg +++ b/projects/app/public/imgs/app/variable.svg @@ -1,175 +1,156 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - + + + + + - - - - + + + + + - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - + + - - - - - - - + + + + + + + - + - + - + - - + + - + - + - - + + - + - + - + - + - + - + - + - - - - - + + - - + + - - + + - - + + - - + + diff --git a/projects/app/public/imgs/app/welcome.svg b/projects/app/public/imgs/app/welcome.svg index 8a9ddad7c78c..3784857e7fbd 100644 --- a/projects/app/public/imgs/app/welcome.svg +++ b/projects/app/public/imgs/app/welcome.svg @@ -1,137 +1,118 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + - - + + - - - - - - - + + + + + + + - + - + - + - - + + - - - - - + + + + + - + - + - - + + - - - - - + + + + + - + - + - + - + - + - + - + - - - - - + + - - + + diff --git a/projects/app/src/components/common/MyRadio/index.tsx b/projects/app/src/components/common/MyRadio/index.tsx index 9cf8a6d01882..b7cb53e3a20b 100644 --- a/projects/app/src/components/common/MyRadio/index.tsx +++ b/projects/app/src/components/common/MyRadio/index.tsx @@ -1,8 +1,8 @@ import React from 'react'; -import { Box, Flex, useTheme, Grid, type GridProps, theme, Image, Radio } from '@chakra-ui/react'; -import MyIcon from '@fastgpt/web/components/common/Icon'; +import { Box, Flex, useTheme, Grid, type GridProps, Radio } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; import { useToast } from '@fastgpt/web/hooks/useToast'; +import Avatar from '@fastgpt/web/components/common/Avatar'; // @ts-ignore interface Props extends GridProps { @@ -53,7 +53,8 @@ const MyRadio = ({ {...(value === item.value ? { borderColor: 'primary.400', - bg: 'primary.50' + bg: 'primary.50', + color: 'primary.600' } : { bg: 'myWhite.300', @@ -74,11 +75,7 @@ const MyRadio = ({ > {!!item.icon && ( <> - {item.icon.startsWith('/') ? ( - - ) : ( - - )} + )} diff --git a/projects/app/src/components/core/ai/AISettingModal/index.tsx b/projects/app/src/components/core/ai/AISettingModal/index.tsx index 3487086a3a7f..73a134f068a9 100644 --- a/projects/app/src/components/core/ai/AISettingModal/index.tsx +++ b/projects/app/src/components/core/ai/AISettingModal/index.tsx @@ -136,7 +136,7 @@ const AIChatSettingsModal = ({ {t('common:core.ai.Support tool')} - + {selectedModel?.toolChoice || selectedModel?.functionCall ? t('common:common.support') : t('common:common.not_support')} diff --git a/projects/app/src/components/core/app/Tip.tsx b/projects/app/src/components/core/app/Tip.tsx index 3222e8fa0ed2..6cc95fc402c8 100644 --- a/projects/app/src/components/core/app/Tip.tsx +++ b/projects/app/src/components/core/app/Tip.tsx @@ -50,7 +50,7 @@ const ChatFunctionTip = ({ type }: { type: `${FnTypeEnum}` }) => { imgUrl: '/imgs/app/welcome.svg' }, [FnTypeEnum.file]: { - icon: '/imgs/app/welcome-icon.svg', + icon: '/imgs/app/fileinput.svg', title: t('app:file_upload'), desc: t('app:file_upload_tip'), imgUrl: '/imgs/app/fileUploadPlaceholder.png' diff --git a/projects/app/src/components/support/wallet/StandardPlanContentList.tsx b/projects/app/src/components/support/wallet/StandardPlanContentList.tsx index 314e7b5cb35e..7484da242a38 100644 --- a/projects/app/src/components/support/wallet/StandardPlanContentList.tsx +++ b/projects/app/src/components/support/wallet/StandardPlanContentList.tsx @@ -112,13 +112,13 @@ const StandardPlanContentList = ({ {!!planContent.permissionReRank && ( - {t('chat:rearrangement')} + {t('support.wallet.subscription.rerank')} )} {!!planContent.permissionWebsiteSync && ( - {t('chat:web_site_sync')} + {t('support.wallet.subscription.web_site_sync')} )} diff --git a/projects/app/src/pages/api/core/app/copy.ts b/projects/app/src/pages/api/core/app/copy.ts index d7e5e699b1d6..2f7e51d541fc 100644 --- a/projects/app/src/pages/api/core/app/copy.ts +++ b/projects/app/src/pages/api/core/app/copy.ts @@ -39,6 +39,7 @@ async function handler( type: app.type, modules: app.modules, edges: app.edges, + chatConfig: app.chatConfig, teamId: app.teamId, tmbId, pluginData: app.pluginData diff --git a/projects/app/src/pages/api/core/dataset/collection/update.ts b/projects/app/src/pages/api/core/dataset/collection/update.ts index bf9e40472bf2..d8327f7cdca5 100644 --- a/projects/app/src/pages/api/core/dataset/collection/update.ts +++ b/projects/app/src/pages/api/core/dataset/collection/update.ts @@ -5,6 +5,10 @@ import { NextAPI } from '@/service/middleware/entry'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; import { CommonErrEnum } from '@fastgpt/global/common/error/code/common'; import { ApiRequestProps } from '@fastgpt/service/type/next'; +import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constants'; +import { ClientSession } from '@fastgpt/service/common/mongo'; +import { CollectionWithDatasetType } from '@fastgpt/global/core/dataset/type'; +import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun'; export type UpdateDatasetCollectionParams = { id: string; @@ -14,6 +18,52 @@ export type UpdateDatasetCollectionParams = { forbid?: boolean; }; +// Set folder collection children forbid status +const updateFolderChildrenForbid = async ({ + collection, + forbid, + session +}: { + collection: CollectionWithDatasetType; + forbid: boolean; + session: ClientSession; +}) => { + // 从 collection 作为 parent 进行递归查找,找到它所有 forbid 与它相同的 child + const find = async (parentId: string): Promise => { + const children = await MongoDatasetCollection.find( + { + teamId: collection.teamId, + datasetId: collection.datasetId, + parentId + }, + '_id', + { session } + ); + + const idList = children.map((item) => String(item._id)); + + const IdChildren = (await Promise.all(idList.map(find))).flat(); + + return [...idList, ...IdChildren]; + }; + + const allChildrenIdList = await find(collection._id); + + await MongoDatasetCollection.updateMany( + { + _id: { $in: allChildrenIdList } + }, + { + $set: { + forbid + } + }, + { + session + } + ); +}; + async function handler(req: ApiRequestProps) { const { id, parentId, name, tags, forbid } = req.body; @@ -22,7 +72,7 @@ async function handler(req: ApiRequestProps) { } // 凭证校验 - await authDatasetCollection({ + const { collection } = await authDatasetCollection({ req, authToken: true, authApiKey: true, @@ -30,15 +80,32 @@ async function handler(req: ApiRequestProps) { per: WritePermissionVal }); - const updateFields: Record = { - ...(parentId !== undefined && { parentId: parentId || null }), - ...(name && { name, updateTime: getCollectionUpdateTime({ name }) }), - ...(tags && { tags }), - ...(forbid !== undefined && { forbid }) - }; + await mongoSessionRun(async (session) => { + await MongoDatasetCollection.updateOne( + { + _id: id + }, + { + $set: { + ...(parentId !== undefined && { parentId: parentId || null }), + ...(name && { name, updateTime: getCollectionUpdateTime({ name }) }), + ...(tags && { tags }), + ...(forbid !== undefined && { forbid }) + } + }, + { + session + } + ); - await MongoDatasetCollection.findByIdAndUpdate(id, { - $set: updateFields + // Folder update forbid + if (collection.type === DatasetCollectionTypeEnum.folder && forbid !== undefined) { + await updateFolderChildrenForbid({ + collection, + forbid, + session + }); + } }); } diff --git a/projects/app/src/pages/app/detail/components/Publish/FeiShu/FeiShuEditModal.tsx b/projects/app/src/pages/app/detail/components/Publish/FeiShu/FeiShuEditModal.tsx index cb94018ac0d5..cf8bf3773b89 100644 --- a/projects/app/src/pages/app/detail/components/Publish/FeiShu/FeiShuEditModal.tsx +++ b/projects/app/src/pages/app/detail/components/Publish/FeiShu/FeiShuEditModal.tsx @@ -76,7 +76,7 @@ const FeiShuEditModal = ({ {t('publish:feishu_api')} {feConfigs?.docUrl && ( - {t('publish:official_account.api')} + {t('publish:official_account.params')} {feConfigs?.docUrl && ( inputs.find((input) => input.key === NodeInputKeyEnum.aiChatMaxToken)?.value ?? 2048, temperature: inputs.find((input) => input.key === NodeInputKeyEnum.aiChatTemperature)?.value ?? 1, - isResponseAnswerText: - inputs.find((input) => input.key === NodeInputKeyEnum.aiChatIsResponseText)?.value ?? true, + isResponseAnswerText: inputs.find( + (input) => input.key === NodeInputKeyEnum.aiChatIsResponseText + )?.value, aiChatVision: inputs.find((input) => input.key === NodeInputKeyEnum.aiChatVision)?.value ?? true }), diff --git a/projects/app/src/pages/dataset/detail/index.tsx b/projects/app/src/pages/dataset/detail/index.tsx index c710742ef221..70c3c39d694f 100644 --- a/projects/app/src/pages/dataset/detail/index.tsx +++ b/projects/app/src/pages/dataset/detail/index.tsx @@ -95,6 +95,10 @@ export async function getServerSideProps(context: any) { const datasetId = context?.query?.datasetId; return { - props: { currentTab, datasetId, ...(await serviceSideProps(context, ['dataset', 'file'])) } + props: { + currentTab, + datasetId, + ...(await serviceSideProps(context, ['dataset', 'file', 'user'])) + } }; }