Commit 3c6e5a6e by Archer Committed by GitHub

4.8 test (#1394)

* 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
parent 7b75a99b
......@@ -105,7 +105,7 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
const {
welcomeText,
variableModules,
variableNodes,
questionGuide,
ttsConfig,
whisperConfig,
......@@ -114,7 +114,7 @@ export const appWorkflow2Form = ({ nodes }: { nodes: StoreNodeItemType[] }) => {
defaultAppForm.userGuide = {
welcomeText: welcomeText,
variables: variableModules,
variables: variableNodes,
questionGuide: questionGuide,
tts: ttsConfig,
whisper: whisperConfig,
......
......@@ -10,7 +10,7 @@ import {
import { FlowNodeTypeEnum } from '../workflow/node/constant';
import { NodeOutputKeyEnum } from '../workflow/constants';
import { DispatchNodeResponseKeyEnum } from '../workflow/runtime/constants';
import { AppSchema } from '../app/type';
import { AppSchema, VariableItemType } from '../app/type';
import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
import { DatasetSearchModeEnum } from '../dataset/constants';
import { ChatBoxInputType } from '../../../../projects/app/src/components/ChatBox/type';
......@@ -27,11 +27,13 @@ export type ChatSchema = {
title: string;
customTitle: string;
top: boolean;
variables: Record<string, any>;
source: `${ChatSourceEnum}`;
shareId?: string;
outLinkUid?: string;
content: ChatItemType[];
variableList?: VariableItemType[];
welcomeText?: string;
variables: Record<string, any>;
metadata?: Record<string, any>;
};
......
......@@ -36,13 +36,17 @@ export const checkInputIsReference = (input: FlowNodeInputItemType) => {
/* node */
export const getGuideModule = (modules: StoreNodeItemType[]) =>
modules.find((item) => item.flowNodeType === FlowNodeTypeEnum.systemConfig);
modules.find(
(item) =>
item.flowNodeType === FlowNodeTypeEnum.systemConfig ||
// @ts-ignore (adapt v1)
item.flowType === FlowNodeTypeEnum.systemConfig
);
export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
const welcomeText: string =
guideModules?.inputs?.find((item) => item.key === NodeInputKeyEnum.welcomeText)?.value || '';
const variableModules: VariableItemType[] =
const variableNodes: VariableItemType[] =
guideModules?.inputs.find((item) => item.key === NodeInputKeyEnum.variables)?.value || [];
const questionGuide: boolean =
......@@ -63,13 +67,43 @@ export const splitGuideModule = (guideModules?: StoreNodeItemType) => {
return {
welcomeText,
variableModules,
variableNodes,
questionGuide,
ttsConfig,
whisperConfig,
scheduledTriggerConfig
};
};
export const replaceAppChatConfig = ({
node,
variableList,
welcomeText
}: {
node?: StoreNodeItemType;
variableList?: VariableItemType[];
welcomeText?: string;
}): StoreNodeItemType | undefined => {
if (!node) return;
return {
...node,
inputs: node.inputs.map((input) => {
if (input.key === NodeInputKeyEnum.variables && variableList) {
return {
...input,
value: variableList
};
}
if (input.key === NodeInputKeyEnum.welcomeText && welcomeText) {
return {
...input,
value: welcomeText
};
}
return input;
})
};
};
export const getOrInitModuleInputValue = (input: FlowNodeInputItemType) => {
if (input.value !== undefined || !input.valueType) return input.value;
......
......@@ -41,6 +41,10 @@ export function reRankRecall({
.then((data) => {
addLog.info('ReRank finish:', { time: Date.now() - start });
if (!data?.results || data?.results?.length === 0) {
addLog.error('ReRank error, empty result', data);
}
return data?.results?.map((item) => ({
id: documents[item.index].id,
score: item.relevance_score
......
......@@ -61,7 +61,15 @@ const ChatSchema = new Schema({
outLinkUid: {
type: String
},
variableList: {
type: Array
},
welcomeText: {
type: String
},
variables: {
// variable value
type: Object,
default: {}
},
......
......@@ -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,
......
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'}
......
......@@ -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) => {
......
......@@ -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>
......
......@@ -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 (
......
......@@ -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,
......
......@@ -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,
......
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,
......
......@@ -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,
......
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}
/>
</>
);
......
......@@ -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]
......
......@@ -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 (
......
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,
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment