* fix: chat variable sync

* feat: chat save variable config

* fix: target handle hidden

* adapt v1 chat init

* adapt v1 chat init

* adapt v1 chat init

* adapt v1 chat init
This commit is contained in:
Archer
2024-05-08 19:49:17 +08:00
committed by GitHub
parent 7b75a99ba2
commit 3c6e5a6e00
20 changed files with 332 additions and 259 deletions

View File

@@ -12,7 +12,7 @@ import { ChatSiteItemType } from '@fastgpt/global/core/chat/type';
type useChatStoreType = OutLinkChatAuthProps & {
welcomeText: string;
variableModules: VariableItemType[];
variableNodes: VariableItemType[];
questionGuide: boolean;
ttsConfig: AppTTSConfigType;
whisperConfig: AppWhisperConfigType;
@@ -41,7 +41,7 @@ type useChatStoreType = OutLinkChatAuthProps & {
};
const StateContext = createContext<useChatStoreType>({
welcomeText: '',
variableModules: [],
variableNodes: [],
questionGuide: false,
ttsConfig: {
type: 'none',
@@ -110,7 +110,7 @@ const Provider = ({
}: ChatProviderProps) => {
const [chatHistories, setChatHistories] = useState<ChatSiteItemType[]>([]);
const { welcomeText, variableModules, questionGuide, ttsConfig, whisperConfig } = useMemo(
const { welcomeText, variableNodes, questionGuide, ttsConfig, whisperConfig } = useMemo(
() => splitGuideModule(userGuideModule),
[userGuideModule]
);
@@ -150,7 +150,7 @@ const Provider = ({
teamId,
teamToken,
welcomeText,
variableModules,
variableNodes,
questionGuide,
ttsConfig,
whisperConfig,

View File

@@ -1,5 +1,5 @@
import { VariableItemType } from '@fastgpt/global/core/app/type.d';
import React, { useEffect, useState } from 'react';
import React from 'react';
import { UseFormReturn } from 'react-hook-form';
import { useTranslation } from 'next-i18next';
import { Box, Button, Card, Input, Textarea } from '@chakra-ui/react';
@@ -12,34 +12,19 @@ import { ChatBoxInputFormType } from '../type.d';
const VariableInput = ({
appAvatar,
variableModules,
variableIsFinish,
variableNodes,
chatForm,
onSubmitVariables
}: {
appAvatar?: string;
variableModules: VariableItemType[];
variableIsFinish: boolean;
variableNodes: VariableItemType[];
onSubmitVariables: (e: Record<string, any>) => void;
chatForm: UseFormReturn<ChatBoxInputFormType>;
}) => {
const { t } = useTranslation();
const { register, unregister, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
const { register, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
const variables = watch('variables');
useEffect(() => {
// 重新注册所有字段
variableModules.forEach((item) => {
register(`variables.${item.key}`, { required: item.required });
});
return () => {
// 组件卸载时注销所有字段
variableModules.forEach((item) => {
unregister(`variables.${item.key}`);
});
};
}, [register, unregister, variableModules]);
const chatStarted = watch('chatStarted');
return (
<Box py={3}>
@@ -55,7 +40,7 @@ const VariableInput = ({
bg={'white'}
boxShadow={'0 0 8px rgba(0,0,0,0.15)'}
>
{variableModules.map((item) => (
{variableNodes.map((item) => (
<Box key={item.id} mb={4}>
<Box as={'label'} display={'inline-block'} position={'relative'} mb={1}>
{item.label}
@@ -73,7 +58,6 @@ const VariableInput = ({
</Box>
{item.type === VariableInputEnum.input && (
<Input
isDisabled={variableIsFinish}
bg={'myWhite.400'}
{...register(`variables.${item.key}`, {
required: item.required
@@ -82,7 +66,6 @@ const VariableInput = ({
)}
{item.type === VariableInputEnum.textarea && (
<Textarea
isDisabled={variableIsFinish}
bg={'myWhite.400'}
{...register(`variables.${item.key}`, {
required: item.required
@@ -94,7 +77,6 @@ const VariableInput = ({
{item.type === VariableInputEnum.select && (
<MySelect
width={'100%'}
isDisabled={variableIsFinish}
list={(item.enums || []).map((item) => ({
label: item.value,
value: item.value
@@ -110,7 +92,7 @@ const VariableInput = ({
)}
</Box>
))}
{!variableIsFinish && (
{!chatStarted && (
<Button
leftIcon={<MyIcon name={'core/chat/chatFill'} w={'16px'} />}
size={'sm'}

View File

@@ -58,6 +58,8 @@ import ChatProvider, { useChatProviderStore } from './Provider';
import ChatItem from './components/ChatItem';
import dynamic from 'next/dynamic';
import { useCreation, useUpdateEffect } from 'ahooks';
const ResponseTags = dynamic(() => import('./ResponseTags'));
const FeedbackModal = dynamic(() => import('./FeedbackModal'));
const ReadFeedbackModal = dynamic(() => import('./ReadFeedbackModal'));
@@ -147,7 +149,7 @@ const ChatBox = (
const {
welcomeText,
variableModules,
variableNodes,
questionGuide,
startSegmentedAudio,
finishSegmentedAudio,
@@ -171,24 +173,10 @@ const ChatBox = (
const chatStarted = watch('chatStarted');
/* variable */
const variables = watch('variables');
const filterVariableModules = useMemo(
() => variableModules.filter((item) => item.type !== VariableInputEnum.custom),
[variableModules]
const filterVariableNodes = useCreation(
() => variableNodes.filter((item) => item.type !== VariableInputEnum.custom),
[variableNodes]
);
const variableIsFinish = (() => {
if (!filterVariableModules || filterVariableModules.length === 0 || chatHistories.length > 0)
return true;
for (let i = 0; i < filterVariableModules.length; i++) {
const item = filterVariableModules[i];
if (item.required && !variables[item.key]) {
return false;
}
}
return chatStarted;
})();
// 滚动到底部
const scrollToBottom = (behavior: 'smooth' | 'auto' = 'smooth') => {
@@ -379,174 +367,185 @@ const ChatBox = (
autoTTSResponse?: boolean;
history?: ChatSiteItemType[];
}) => {
handleSubmit(async ({ variables }) => {
if (!onStartChat) return;
if (isChatting) {
toast({
title: '正在聊天中...请等待结束',
status: 'warning'
});
return;
}
abortRequest();
text = text.trim();
if (!text && files.length === 0) {
toast({
title: '内容为空',
status: 'warning'
});
return;
}
const responseChatId = getNanoid(24);
questionGuideController.current?.abort('stop');
// set auto audio playing
if (autoTTSResponse) {
await startSegmentedAudio();
setAudioPlayingChatId(responseChatId);
}
const newChatList: ChatSiteItemType[] = [
...history,
{
dataId: getNanoid(24),
obj: ChatRoleEnum.Human,
value: [
...files.map((file) => ({
type: ChatItemValueTypeEnum.file,
file: {
type: file.type,
name: file.name,
url: file.url || ''
}
})),
...(text
? [
{
type: ChatItemValueTypeEnum.text,
text: {
content: text
}
}
]
: [])
] as UserChatItemValueItemType[],
status: 'finish'
},
{
dataId: responseChatId,
obj: ChatRoleEnum.AI,
value: [
{
type: ChatItemValueTypeEnum.text,
text: {
content: ''
}
}
],
status: 'loading'
}
];
// 插入内容
setChatHistories(newChatList);
// 清空输入内容
resetInputVal({});
setQuestionGuide([]);
setTimeout(() => {
scrollToBottom();
}, 100);
try {
// create abort obj
const abortSignal = new AbortController();
chatController.current = abortSignal;
const messages = chats2GPTMessages({ messages: newChatList, reserveId: true });
const {
responseData,
responseText,
newVariables,
isNewChat = false
} = await onStartChat({
chatList: newChatList,
messages,
controller: abortSignal,
generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }),
variables
});
newVariables && setValue('variables', newVariables);
isNewChatReplace.current = isNewChat;
// set finish status
setChatHistories((state) =>
state.map((item, index) => {
if (index !== state.length - 1) return item;
return {
...item,
status: 'finish',
responseData
};
})
);
setTimeout(() => {
createQuestionGuide({
history: newChatList.map((item, i) =>
i === newChatList.length - 1
? {
...item,
value: [
{
type: ChatItemValueTypeEnum.text,
text: {
content: responseText
}
}
]
}
: item
)
handleSubmit(
async ({ variables }) => {
if (!onStartChat) return;
if (isChatting) {
toast({
title: '正在聊天中...请等待结束',
status: 'warning'
});
generatingScroll();
isPc && TextareaDom.current?.focus();
}, 100);
// tts audio
autoTTSResponse && splitText2Audio(responseText, true);
} catch (err: any) {
toast({
title: t(getErrText(err, 'core.chat.error.Chat error')),
status: 'error',
duration: 5000,
isClosable: true
});
if (!err?.responseText) {
resetInputVal({ text, files });
setChatHistories(newChatList.slice(0, newChatList.length - 2));
return;
}
// set finish status
setChatHistories((state) =>
state.map((item, index) => {
if (index !== state.length - 1) return item;
return {
...item,
status: 'finish'
};
})
);
}
abortRequest();
autoTTSResponse && finishSegmentedAudio();
})();
text = text.trim();
if (!text && files.length === 0) {
toast({
title: '内容为空',
status: 'warning'
});
return;
}
// delete invalid variables 只保留在 variableNodes 中的变量
const requestVariables: Record<string, any> = {};
variableNodes?.forEach((item) => {
requestVariables[item.key] = variables[item.key] || '';
});
const responseChatId = getNanoid(24);
questionGuideController.current?.abort('stop');
// set auto audio playing
if (autoTTSResponse) {
await startSegmentedAudio();
setAudioPlayingChatId(responseChatId);
}
const newChatList: ChatSiteItemType[] = [
...history,
{
dataId: getNanoid(24),
obj: ChatRoleEnum.Human,
value: [
...files.map((file) => ({
type: ChatItemValueTypeEnum.file,
file: {
type: file.type,
name: file.name,
url: file.url || ''
}
})),
...(text
? [
{
type: ChatItemValueTypeEnum.text,
text: {
content: text
}
}
]
: [])
] as UserChatItemValueItemType[],
status: 'finish'
},
{
dataId: responseChatId,
obj: ChatRoleEnum.AI,
value: [
{
type: ChatItemValueTypeEnum.text,
text: {
content: ''
}
}
],
status: 'loading'
}
];
// 插入内容
setChatHistories(newChatList);
// 清空输入内容
resetInputVal({});
setQuestionGuide([]);
setTimeout(() => {
scrollToBottom();
}, 100);
try {
// create abort obj
const abortSignal = new AbortController();
chatController.current = abortSignal;
const messages = chats2GPTMessages({ messages: newChatList, reserveId: true });
const {
responseData,
responseText,
newVariables,
isNewChat = false
} = await onStartChat({
chatList: newChatList,
messages,
controller: abortSignal,
generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }),
variables: requestVariables
});
newVariables && setValue('variables', newVariables);
isNewChatReplace.current = isNewChat;
// set finish status
setChatHistories((state) =>
state.map((item, index) => {
if (index !== state.length - 1) return item;
return {
...item,
status: 'finish',
responseData
};
})
);
setTimeout(() => {
createQuestionGuide({
history: newChatList.map((item, i) =>
i === newChatList.length - 1
? {
...item,
value: [
{
type: ChatItemValueTypeEnum.text,
text: {
content: responseText
}
}
]
}
: item
)
});
generatingScroll();
isPc && TextareaDom.current?.focus();
}, 100);
// tts audio
autoTTSResponse && splitText2Audio(responseText, true);
} catch (err: any) {
toast({
title: t(getErrText(err, 'core.chat.error.Chat error')),
status: 'error',
duration: 5000,
isClosable: true
});
if (!err?.responseText) {
resetInputVal({ text, files });
setChatHistories(newChatList.slice(0, newChatList.length - 2));
}
// set finish status
setChatHistories((state) =>
state.map((item, index) => {
if (index !== state.length - 1) return item;
return {
...item,
status: 'finish'
};
})
);
}
autoTTSResponse && finishSegmentedAudio();
},
(err) => {
console.log(err?.variables);
}
)();
},
[
abortRequest,
@@ -566,7 +565,8 @@ const ChatBox = (
splitText2Audio,
startSegmentedAudio,
t,
toast
toast,
variableNodes
]
);
@@ -630,7 +630,7 @@ const ChatBox = (
});
};
},
[onDelMessage]
[onDelMessage, setChatHistories]
);
// admin mark
const onMark = useCallback(
@@ -796,7 +796,19 @@ const ChatBox = (
}
};
},
[appId, chatId]
[appId, chatId, setChatHistories]
);
const resetVariables = useCallback(
(e: Record<string, any> = {}) => {
const value: Record<string, any> = { ...e };
filterVariableNodes?.forEach((item) => {
value[item.key] = e[item.key] || '';
});
setValue('variables', value);
},
[filterVariableNodes, setValue]
);
const showEmpty = useMemo(
@@ -804,13 +816,13 @@ const ChatBox = (
feConfigs?.show_emptyChat &&
showEmptyIntro &&
chatHistories.length === 0 &&
!filterVariableModules?.length &&
!filterVariableNodes?.length &&
!welcomeText,
[
chatHistories.length,
feConfigs?.show_emptyChat,
showEmptyIntro,
filterVariableModules?.length,
filterVariableNodes?.length,
welcomeText
]
);
@@ -869,14 +881,7 @@ const ChatBox = (
// output data
useImperativeHandle(ref, () => ({
getChatHistories: () => chatHistories,
resetVariables(e) {
const defaultVal: Record<string, any> = {};
filterVariableModules?.forEach((item) => {
defaultVal[item.key] = '';
});
setValue('variables', e || defaultVal);
},
resetVariables,
resetHistory(e) {
abortRequest();
setValue('chatStarted', e.length > 0);
@@ -891,7 +896,7 @@ const ChatBox = (
}));
return (
<Flex flexDirection={'column'} h={'100%'}>
<Flex flexDirection={'column'} h={'100%'} position={'relative'}>
<Script src="/js/html2pdf.bundle.min.js" strategy="lazyOnload"></Script>
{/* chat box container */}
<Box ref={ChatBoxRef} flex={'1 0 0'} h={0} w={'100%'} overflow={'overlay'} px={[4, 0]} pb={3}>
@@ -899,11 +904,10 @@ const ChatBox = (
{showEmpty && <Empty />}
{!!welcomeText && <WelcomeBox appAvatar={appAvatar} welcomeText={welcomeText} />}
{/* variable input */}
{!!filterVariableModules?.length && (
{!!filterVariableNodes?.length && (
<VariableInput
appAvatar={appAvatar}
variableModules={filterVariableModules}
variableIsFinish={variableIsFinish}
variableNodes={filterVariableNodes}
chatForm={chatForm}
onSubmitVariables={(data) => {
setValue('chatStarted', true);
@@ -995,7 +999,7 @@ const ChatBox = (
</Box>
</Box>
{/* message input */}
{onStartChat && variableIsFinish && active && (
{onStartChat && (chatStarted || filterVariableNodes.length === 0) && active && (
<MessageInput
onSendMessage={sendPrompt}
onStop={() => chatController.current?.abort('stop')}

View File

@@ -34,11 +34,13 @@ export type ChatTestComponentRef = {
const ChatTest = (
{
app,
isOpen,
nodes = [],
edges = [],
onClose
}: {
app: AppSchema;
isOpen: boolean;
nodes?: StoreNodeItemType[];
edges?: StoreEdgeItemType[];
onClose: () => void;
@@ -48,7 +50,6 @@ const ChatTest = (
const { t } = useTranslation();
const ChatBoxRef = useRef<ComponentRef>(null);
const { userInfo } = useUserStore();
const isOpen = useMemo(() => nodes && nodes.length > 0, [nodes]);
const startChat = useCallback(
async ({ chatList, controller, generatingMessage, variables }: StartChatFnProps) => {

View File

@@ -28,7 +28,7 @@ export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
edges.some((edge) => edge.targetHandle === getHandleId(nodeId, 'target', 'top')));
const Render = useMemo(() => {
return (
return hidden ? null : (
<MyTooltip label={t('core.workflow.tool.Handle')} shouldWrapChildren={false}>
<Handle
style={{
@@ -49,7 +49,7 @@ export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
border={'4px solid #8774EE'}
transform={'translate(0,-30%) rotate(45deg)'}
pointerEvents={'none'}
visibility={hidden ? 'hidden' : 'visible'}
visibility={'visible'}
/>
</Handle>
</MyTooltip>

View File

@@ -200,14 +200,19 @@ const MyTargetHandle = React.memo(function MyTargetHandle({
) {
return false;
}
if (connectingEdge?.handleId && !connectingEdge.handleId?.includes('source')) return false;
// Same source node
if (connectedEdges.some((item) => item.target === nodeId && item.targetHandle !== handleId))
// From same source node
if (
connectedEdges.some(
(item) => item.source === connectingEdge?.nodeId && item.target === nodeId
)
)
return false;
return true;
}, [connectedEdges, connectingEdge?.handleId, edges, handleId, node, nodeId]);
}, [connectedEdges, connectingEdge?.handleId, connectingEdge?.nodeId, edges, node, nodeId]);
const RenderHandle = useMemo(() => {
return (

View File

@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { authApp } from '@fastgpt/service/support/permission/auth/app';
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import type { InitChatProps, InitChatResponse } from '@/global/core/chat/api.d';
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
@@ -62,7 +62,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
variables: chat?.variables || {},
history,
app: {
userGuideModule: getGuideModule(nodes),
userGuideModule: replaceAppChatConfig({
node: getGuideModule(nodes),
variableList: chat?.variableList,
welcomeText: chat?.welcomeText
}),
chatModels: getChatModelNameListByModules(nodes),
name: app.name,
avatar: app.avatar,

View File

@@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { getChatItems } from '@fastgpt/service/core/chat/controller';
@@ -72,7 +72,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
variables: chat?.variables || {},
history,
app: {
userGuideModule: getGuideModule(nodes),
userGuideModule: replaceAppChatConfig({
node: getGuideModule(nodes),
variableList: chat?.variableList,
welcomeText: chat?.welcomeText
}),
chatModels: getChatModelNameListByModules(nodes),
name: app.name,
avatar: app.avatar,

View File

@@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@fastgpt/service/common/response';
import { connectToDatabase } from '@/service/mongo';
import { getGuideModule } from '@fastgpt/global/core/workflow/utils';
import { getGuideModule, replaceAppChatConfig } from '@fastgpt/global/core/workflow/utils';
import { getChatModelNameListByModules } from '@/service/core/app/workflow';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import type { InitChatResponse, InitTeamChatProps } from '@/global/core/chat/api.d';
@@ -73,7 +73,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
variables: chat?.variables || {},
history,
app: {
userGuideModule: getGuideModule(nodes),
userGuideModule: replaceAppChatConfig({
node: getGuideModule(nodes),
variableList: chat?.variableList,
welcomeText: chat?.welcomeText
}),
chatModels: getChatModelNameListByModules(nodes),
name: app.name,
avatar: app.avatar,

View File

@@ -246,6 +246,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
appId: app._id,
teamId,
tmbId: tmbId,
nodes,
variables: newVariables,
isUpdateUseTime: isOwnerUse && source === ChatSourceEnum.online, // owner update use time
shareId,

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useMemo, useRef, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Box, Flex, IconButton, useTheme, useDisclosure, Button } from '@chakra-ui/react';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
import { AppSchema } from '@fastgpt/global/core/app/type.d';
@@ -25,7 +25,7 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { formatTime2HM } from '@fastgpt/global/common/string/time';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext, getWorkflowStore } from '@/components/core/workflow/context';
import { useInterval } from 'ahooks';
import { useInterval, useUpdateEffect } from 'ahooks';
const ImportSettings = dynamic(() => import('@/components/core/workflow/Flow/ImportSettings'));
const PublishHistories = dynamic(
@@ -341,6 +341,11 @@ const Header = (props: Props) => {
nodes: StoreNodeItemType[];
edges: StoreEdgeItemType[];
}>();
const { isOpen: isOpenTest, onOpen: onOpenTest, onClose: onCloseTest } = useDisclosure();
useUpdateEffect(() => {
onOpenTest();
}, [workflowTestData]);
return (
<>
@@ -351,9 +356,10 @@ const Header = (props: Props) => {
/>
<ChatTest
ref={ChatTestRef}
isOpen={isOpenTest}
{...workflowTestData}
app={app}
onClose={() => setWorkflowTestData(undefined)}
onClose={onCloseTest}
/>
</>
);

View File

@@ -99,6 +99,7 @@ const EditForm = ({
const selectLLMModel = watch('aiSettings.model');
const datasetSearchSetting = watch('dataset');
const variables = watch('userGuide.variables');
const formatVariables = useMemo(
() => formatEditorVariablePickerIcon([...getSystemVariables(t), ...variables]),
[t, variables]

View File

@@ -12,6 +12,7 @@ import ChatTest from './ChatTest';
import AppCard from './AppCard';
import EditForm from './EditForm';
import { AppSimpleEditFormType } from '@fastgpt/global/core/app/type';
import { v1Workflow2V2 } from '@/web/core/workflow/adapt';
const SimpleEdit = ({ appId }: { appId: string }) => {
const { isPc } = useSystemStore();
@@ -28,6 +29,14 @@ const SimpleEdit = ({ appId }: { appId: string }) => {
// show selected dataset
useMount(() => {
loadAllDatasets();
if (appDetail.version !== 'v2') {
editForm.reset(
appWorkflow2Form({
nodes: v1Workflow2V2((appDetail.modules || []) as any)?.nodes
})
);
}
});
return (

View File

@@ -1,8 +1,4 @@
import type {
AIChatItemType,
ChatItemType,
UserChatItemType
} from '@fastgpt/global/core/chat/type.d';
import type { AIChatItemType, UserChatItemType } from '@fastgpt/global/core/chat/type.d';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
@@ -10,12 +6,15 @@ import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { addLog } from '@fastgpt/service/common/system/log';
import { getChatTitleFromChatMessage } from '@fastgpt/global/core/chat/utils';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type';
import { getGuideModule, splitGuideModule } from '@fastgpt/global/core/workflow/utils';
type Props = {
chatId: string;
appId: string;
teamId: string;
tmbId: string;
nodes: StoreNodeItemType[];
variables?: Record<string, any>;
isUpdateUseTime: boolean;
source: `${ChatSourceEnum}`;
@@ -30,6 +29,7 @@ export async function saveChat({
appId,
teamId,
tmbId,
nodes,
variables,
isUpdateUseTime,
source,
@@ -72,6 +72,8 @@ export async function saveChat({
chat.variables = variables || {};
await chat.save({ session });
} else {
const { welcomeText, variableNodes } = splitGuideModule(getGuideModule(nodes));
await MongoChat.create(
[
{
@@ -79,6 +81,8 @@ export async function saveChat({
teamId,
tmbId,
appId,
variableList: variableNodes,
welcomeText,
variables,
title,
source,

View File

@@ -288,7 +288,7 @@ export const getWorkflowGlobalVariables = (
t: TFunction
): EditorVariablePickerType[] => {
const globalVariables = formatEditorVariablePickerIcon(
splitGuideModule(getGuideModule(nodes))?.variableModules || []
splitGuideModule(getGuideModule(nodes))?.variableNodes || []
).map((item) => ({
...item,
valueType: WorkflowIOValueTypeEnum.any