4.8.11 perf (#2768)

* perf: watch local

* perf: dataset list ui

* perf: Check workflow invalid edges in saved

* remove log

* perf: Forbid touch scale

* perf: rename dataset process

* feat: support child app unstream mode

* feat: Dispatch child app will record detail

* feat: Save childApp run log

* fix: share page init error

* perf: chatId reset
This commit is contained in:
Archer
2024-09-23 10:17:49 +08:00
committed by GitHub
parent 4245ea4998
commit 3ab934771f
38 changed files with 252 additions and 143 deletions

View File

@@ -20,7 +20,7 @@
"charsPointsPrice": 0, // n积分/1k token商业版
"censor": false, // 是否开启敏感校验(商业版)
"vision": true, // 是否支持图片输入
"datasetProcess": true, // 是否设置为知识库处理模型QA务必保证至少有一个为true否则知识库会报错
"datasetProcess": true, // 是否设置为文本理解模型QA务必保证至少有一个为true否则知识库会报错
"usedInClassify": true, // 是否用于问题分类务必保证至少有一个为true
"usedInExtractFields": true, // 是否用于内容提取务必保证至少有一个为true
"usedInToolCall": true, // 是否用于工具调用务必保证至少有一个为true
@@ -44,7 +44,7 @@
"charsPointsPrice": 0,
"censor": false,
"vision": true,
"datasetProcess": false,
"datasetProcess": true,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,
@@ -68,7 +68,7 @@
"charsPointsPrice": 0,
"censor": false,
"vision": false,
"datasetProcess": false,
"datasetProcess": true,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,
@@ -97,7 +97,7 @@
"charsPointsPrice": 0,
"censor": false,
"vision": false,
"datasetProcess": false,
"datasetProcess": true,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,

View File

@@ -56,6 +56,7 @@ const Layout = ({ children }: { children: JSX.Element }) => {
[router.pathname, router.query]
);
// System hook
const { data, refetch: refetchUnRead } = useQuery(['getUnreadCount'], getUnreadCount, {
enabled: !!userInfo && !!feConfigs.isPlus,
refetchInterval: 10000

View File

@@ -11,11 +11,25 @@ import { useInitApp } from '@/web/context/useInitApp';
import { useTranslation } from 'next-i18next';
import '@/web/styles/reset.scss';
import NextHead from '@/components/common/NextHead';
import { useEffect } from 'react';
function App({ Component, pageProps }: AppProps) {
const { feConfigs, scripts, title } = useInitApp();
const { t } = useTranslation();
// Forbid touch scale
useEffect(() => {
document.addEventListener(
'wheel',
function (e) {
if (e.ctrlKey && Math.abs(e.deltaY) !== 0) {
e.preventDefault();
}
},
{ passive: false }
);
}, []);
return (
<>
<NextHead

View File

@@ -3,7 +3,7 @@
*/
import type { NextApiResponse } from 'next';
import {
getPluginPreviewNode,
getChildAppPreviewNode,
splitCombinePluginId
} from '@fastgpt/service/core/app/plugin/controller';
import { FlowNodeTemplateType } from '@fastgpt/global/core/workflow/type/node.d';
@@ -27,7 +27,7 @@ async function handler(
await authApp({ req, authToken: true, appId, per: ReadPermissionVal });
}
return getPluginPreviewNode({ id: appId });
return getChildAppPreviewNode({ id: appId });
}
export default NextAPI(handler);

View File

@@ -116,8 +116,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const workflowResponseWrite = getWorkflowResponseWrite({
res,
detail: true,
streamResponse: true,
id: getNanoid(24)
streamResponse: true
});
/* start process */

View File

@@ -240,7 +240,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
res,
detail,
streamResponse: stream,
id: chatId || getNanoid(24)
id: chatId
});
/* start flow controller */

View File

@@ -262,7 +262,8 @@ const Header = () => {
await onClickSave({});
toast({
status: 'success',
title: t('app:saved_success')
title: t('app:saved_success'),
position: 'top-right'
});
onClose();
setIsSave(false);
@@ -332,7 +333,8 @@ const Header = () => {
onBack();
toast({
status: 'success',
title: t('app:saved_success')
title: t('app:saved_success'),
position: 'top-right'
});
}}
>

View File

@@ -85,7 +85,8 @@ const Header = ({
});
toast({
status: 'success',
title: t('app:publish_success')
title: t('app:publish_success'),
position: 'top-right'
});
},
[onSaveApp, t, toast]

View File

@@ -264,7 +264,8 @@ const Header = () => {
await onClickSave({});
toast({
status: 'success',
title: t('app:saved_success')
title: t('app:saved_success'),
position: 'top-right'
});
onClose();
setIsSave(false);
@@ -334,7 +335,8 @@ const Header = () => {
onBack();
toast({
status: 'success',
title: t('app:saved_success')
title: t('app:saved_success'),
position: 'top-right'
});
}}
>

View File

@@ -67,7 +67,8 @@ const SaveAndPublishModal = ({
await onClickSave({ ...data, isPublish: true });
toast({
status: 'success',
title: t('app:publish_success')
title: t('app:publish_success'),
position: 'top-right'
});
onClose();
})}

View File

@@ -89,6 +89,7 @@ const InputLabel = ({ nodeId, input }: Props) => {
required,
selectedTypeIndex,
t,
valueDesc,
valueType
]);

View File

@@ -344,7 +344,7 @@ const WorkflowContextProvider = ({
const [workflowControlMode, setWorkflowControlMode] = useLocalStorageState<'drag' | 'select'>(
'workflow-control-mode',
{
defaultValue: 'select',
defaultValue: 'drag',
listenStorageChange: true
}
);
@@ -782,10 +782,12 @@ const WorkflowContextProvider = ({
/* snapshots */
const [past, setPast] = useLocalStorageState<SnapshotsType[]>(`${appId}-past`, {
defaultValue: []
defaultValue: [],
listenStorageChange: true
}) as [SnapshotsType[], (value: SetStateAction<SnapshotsType[]>) => void];
const [future, setFuture] = useLocalStorageState<SnapshotsType[]>(`${appId}-future`, {
defaultValue: []
defaultValue: [],
listenStorageChange: true
}) as [SnapshotsType[], (value: SetStateAction<SnapshotsType[]>) => void];
const resetSnapshot = useMemoizedFn((state: SnapshotsType) => {

View File

@@ -25,10 +25,17 @@ export const uiWorkflow2StoreWorkflow = ({
version: item.data.version,
inputs: item.data.inputs,
outputs: item.data.outputs,
pluginId: item.data.pluginId,
parentNodeId: item.data.parentNodeId
pluginId: item.data.pluginId
}));
// get all handle
const reactFlowViewport = document.querySelector('.react-flow__viewport');
// Gets the value of data-handleid on all elements below it whose data-handleid is not empty
const handleList =
reactFlowViewport?.querySelectorAll('[data-handleid]:not([data-handleid=""])') || [];
const handleIdList = Array.from(handleList).map(
(item) => item.getAttribute('data-handleid') || ''
);
const formatEdges: StoreEdgeItemType[] = edges
.map((item) => ({
source: item.source,
@@ -36,7 +43,15 @@ export const uiWorkflow2StoreWorkflow = ({
sourceHandle: item.sourceHandle || '',
targetHandle: item.targetHandle || ''
}))
.filter((item) => item.sourceHandle && item.targetHandle);
.filter((item) => item.sourceHandle && item.targetHandle)
.filter(
// Filter out edges that do not have both sourceHandle and targetHandle
(item) => {
// Not in react flow page
if (!reactFlowViewport) return true;
return handleIdList.includes(item.sourceHandle) && handleIdList.includes(item.targetHandle);
}
);
return {
nodes: formatNodes,

View File

@@ -113,7 +113,7 @@ const Chat = ({
if (e?.code === 501) {
router.replace('/app/list');
} else if (chatId) {
onChangeChatId('');
onChangeChatId();
}
},
onFinally() {

View File

@@ -2,12 +2,13 @@ import React, { useCallback, useMemo, useRef, useState } from 'react';
import { useRouter } from 'next/router';
import { Box, Flex, Drawer, DrawerOverlay, DrawerContent } from '@chakra-ui/react';
import { streamFetch } from '@/web/common/api/fetch';
import { useShareChatStore } from '@/web/core/chat/storeShareChat';
import SideBar from '@/components/SideBar';
import { GPTMessages2Chats } from '@fastgpt/global/core/chat/adapt';
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
const nanoid = customAlphabet(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ1234567890_',
24
);
import ChatBox from '@/components/core/chat/ChatContainer/ChatBox';
import type { StartChatFnProps } from '@/components/core/chat/ChatContainer/type';
@@ -16,7 +17,7 @@ import ChatHeader from './components/ChatHeader';
import ChatHistorySlider from './components/ChatHistorySlider';
import { serviceSideProps } from '@/web/common/utils/i18n';
import { useTranslation } from 'next-i18next';
import { delChatRecordById, getChatHistories, getInitOutLinkChatInfo } from '@/web/core/chat/api';
import { delChatRecordById, getInitOutLinkChatInfo } from '@/web/core/chat/api';
import { getChatTitleFromChatMessage } from '@fastgpt/global/core/chat/utils';
import { ChatStatusEnum } from '@fastgpt/global/core/chat/constants';
import { MongoOutLink } from '@fastgpt/service/support/outLink/schema';
@@ -36,6 +37,7 @@ import { getNanoid } from '@fastgpt/global/common/string/tools';
import dynamic from 'next/dynamic';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { useShareChatStore } from '@/web/core/chat/storeShareChat';
const CustomPluginRunBox = dynamic(() => import('./components/CustomPluginRunBox'));
type Props = {
@@ -46,7 +48,14 @@ type Props = {
authToken: string;
};
const OutLink = ({ appName, appIntro, appAvatar }: Props) => {
const OutLink = ({
outLinkUid,
appName,
appIntro,
appAvatar
}: Props & {
outLinkUid: string;
}) => {
const { t } = useTranslation();
const router = useRouter();
const {
@@ -69,14 +78,9 @@ const OutLink = ({ appName, appIntro, appAvatar }: Props) => {
const [isEmbed, setIdEmbed] = useState(true);
const [chatData, setChatData] = useState<InitChatResponse>(defaultChatData);
const appId = chatData.appId;
const { localUId } = useShareChatStore();
const outLinkUid: string = authToken || localUId;
const {
onUpdateHistoryTitle,
loadHistories,
onUpdateHistory,
onClearHistories,
onDelHistory,
@@ -212,7 +216,7 @@ const OutLink = ({ appName, appIntro, appAvatar }: Props) => {
onError(e: any) {
console.log(e);
if (chatId) {
onChangeChatId('');
onChangeChatId();
}
},
onFinally() {
@@ -352,16 +356,21 @@ const OutLink = ({ appName, appIntro, appAvatar }: Props) => {
const Render = (props: Props) => {
const { shareId, authToken } = props;
const { localUId } = useShareChatStore();
const outLinkUid: string = authToken || localUId;
const { localUId, setLocalUId } = useShareChatStore();
const contextParams = useMemo(() => {
return { shareId, outLinkUid };
}, [shareId, outLinkUid]);
if (!localUId) {
const localId = `shareChat-${Date.now()}-${nanoid()}`;
setLocalUId(localId);
return { shareId, outLinkUid: authToken || localId };
}
return { shareId, outLinkUid: authToken || localUId };
}, []);
return (
<ChatContextProvider params={contextParams}>
<OutLink {...props} />;
<OutLink {...props} outLinkUid={contextParams.outLinkUid} />;
</ChatContextProvider>
);
};

View File

@@ -166,7 +166,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
status: 'error'
});
if (chatId) {
onChangeChatId('');
onChangeChatId();
}
},
onFinally() {

View File

@@ -287,9 +287,9 @@ function List() {
<HStack>
{isPc && (
<HStack spacing={1} className="time">
<MyIcon name={'history'} w={'0.85rem'} color={'myGray.400'} />
<Avatar src={dataset.vectorModel.avatar} w={'0.85rem'} />
<Box color={'myGray.500'} fontSize={'mini'}>
{formatTimeToChatTime(dataset.updateTime)}
{dataset.vectorModel.name}
</Box>
</HStack>
)}

View File

@@ -195,7 +195,7 @@ const ChatContextProvider = ({
setHistories([]);
},
onFinally() {
onChangeChatId('');
onChangeChatId();
}
}
);

View File

@@ -1,22 +1,22 @@
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import type { ChatHistoryItemType } from '@fastgpt/global/core/chat/type.d';
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet(
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWSYZ1234567890_',
24
);
type State = {
localUId: string;
setLocalUId: (id: string) => void;
};
export const useShareChatStore = create<State>()(
devtools(
persist(
immer((set, get) => ({
localUId: `shareChat-${Date.now()}-${nanoid()}`
localUId: '',
setLocalUId(id) {
set((state) => {
state.localUId = id;
});
}
})),
{
name: 'shareChatStore'

View File

@@ -90,7 +90,7 @@ export const useUserStore = create<State>()(
if (!useSystemStore.getState()?.feConfigs?.isPlus) return [];
const randomRefresh = Math.random() > 0.7;
if (!randomRefresh && !init && get().teamMembers.length)
if (!randomRefresh && !init && get().teamMembers?.length)
return Promise.resolve(get().teamMembers);
const res = await getTeamMembers();