Ai histories (#1376)

* perf: workflow node ui

* i18n

* rename controller

* fix: zindex

* fix: leave page callback

* revert button
This commit is contained in:
Archer
2024-05-07 13:32:01 +08:00
committed by GitHub
parent eef609a063
commit 9e192c6d11
13 changed files with 116 additions and 111 deletions

View File

@@ -6,10 +6,10 @@
"i18n-ally.localesPaths": [
"projects/app/i18n",
],
"i18n-ally.enabledParsers": ["json"],
"i18n-ally.enabledParsers": ["json", "yaml", "js", "ts"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.keepFulfilled": true,
"i18n-ally.keepFulfilled": false,
"i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译其他语言文件的变量和内容
"i18n-ally.displayLanguage": "zh", // 显示语言
"i18n-ally.displayLanguage": "zh" // 显示语言
}

View File

@@ -1,6 +1,6 @@
import { FlowNodeTemplateTypeEnum, WorkflowIOValueTypeEnum } from '../../constants';
import { getHandleConfig } from '../utils';
import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
import { VariableItemType } from '../../../app/type';
import { FlowNodeTemplateType } from '../../type';
@@ -25,6 +25,7 @@ export const getGlobalVariableNode = ({
id: item.key,
key: item.key,
valueType: WorkflowIOValueTypeEnum.string,
type: FlowNodeOutputTypeEnum.static,
label: item.label
}))
};

View File

@@ -27,7 +27,7 @@ export const ToolModule: FlowNodeTemplateType = {
sourceHandle: getHandleConfig(true, true, false, true),
targetHandle: getHandleConfig(true, true, false, true),
avatar: '/imgs/workflow/tool.svg',
name: '工具调用实验',
name: '工具调用(实验)',
intro: '通过AI模型自动选择一个或多个功能块进行调用也可以对插件进行调用。',
showStatus: true,
inputs: [

View File

@@ -47,7 +47,7 @@ export const filterToolNodeIdByEdges = ({
export const getHistories = (history?: ChatItemType[] | number, histories: ChatItemType[] = []) => {
if (!history) return [];
if (typeof history === 'number') return histories.slice(-history);
if (typeof history === 'number') return histories.slice(-(history * 2));
if (Array.isArray(history)) return history;
return [];

View File

@@ -8,7 +8,7 @@ export const useBeforeunload = (props?: { callback?: () => any; tip?: string })
useEffect(() => {
const listen =
process.env.NODE_ENV !== 'production'
process.env.NODE_ENV === 'production'
? (e: any) => {
e.preventDefault();
e.returnValue = tip;

View File

@@ -92,9 +92,9 @@ export const useEditTextarea = ({
closeBtnText?: string;
}) => (
<MyModal isOpen={isOpen} onClose={onClose} iconSrc={iconSrc} title={title} maxW={'500px'}>
<ModalBody>
<ModalBody pt={tip ? '3 !important' : '5 !important'}>
{!!tip && (
<Box mb={2} color={'myGray.500'} fontSize={'sm'}>
<Box mb={3} color={'myGray.500'} fontSize={'sm'}>
{tip}
</Box>
)}

View File

@@ -1,13 +1,11 @@
{
"App": "App",
"Create New": "Create New",
"Export": "Export",
"Folder": "Folder",
"Move": "Move",
"Name": "Name",
"Rename": "Rename",
"Running": "Running",
"Select value is empty": "Selected value is empty",
"UnKnow": "Unknown",
"Warning": "Warning",
"app": {
@@ -646,7 +644,8 @@
"success": "Sync started"
}
},
"training": {}
"training": {
}
},
"data": {
"Auxiliary Data": "Auxiliary Data",
@@ -1167,7 +1166,7 @@
},
"publish": {
"OnRevert version": "Click back to that version",
"OnRevert version confirm": "Are you sure to roll back the version?",
"OnRevert version confirm": "Sure you want to roll back to this version? The configuration for the version in editing is saved for you and a new release is created for the rollback version.",
"histories": "Publiish histories"
},
"tool": {
@@ -1204,7 +1203,6 @@
"Select Dataset": "Select this knowledge base",
"Select Dataset Tips": "Only knowledge bases of the same index model can be selected",
"Select Folder": "Enter folder",
"System Data Queue": "Queue Length",
"Training Name": "Data Training",
"Upload Time": "Upload Time",
"collections": {

View File

@@ -1,13 +1,11 @@
{
"App": "应用",
"Create New": "",
"Export": "导出",
"Folder": "文件夹",
"Move": "移动",
"Name": "名称",
"Rename": "重命名",
"Running": "运行中",
"Select value is empty": "选择的内容为空",
"UnKnow": "未知",
"Warning": "提示",
"app": {
@@ -646,7 +644,8 @@
"success": "开始同步"
}
},
"training": {}
"training": {
}
},
"data": {
"Auxiliary Data": "辅助数据",
@@ -1167,7 +1166,7 @@
},
"publish": {
"OnRevert version": "点击回退到该版本",
"OnRevert version confirm": "确认回退该版本?",
"OnRevert version confirm": "确认回退该版本?会为您保存编辑中版本的配置,并为回退版本创建一个新的发布版本。",
"histories": "发布记录"
},
"tool": {
@@ -1204,7 +1203,6 @@
"Select Dataset": "选择该知识库",
"Select Dataset Tips": "仅能选择同一个索引模型的知识库",
"Select Folder": "进入文件夹",
"System Data Queue": "排队长度",
"Training Name": "数据训练",
"Upload Time": "上传时间",
"collections": {

View File

@@ -99,7 +99,7 @@ const ChatTest = (
return (
<>
<Flex
zIndex={3}
zIndex={101}
flexDirection={'column'}
position={'absolute'}
top={5}

View File

@@ -90,7 +90,7 @@ const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
</Box>
<Box flex={'1 0 0'} />
<Button
variant={'transparentBase'}
variant={'whitePrimary'}
leftIcon={<SmallAddIcon />}
iconSpacing={1}
size={'sm'}

View File

@@ -38,6 +38,8 @@ type Props = FlowNodeItemType & {
const NodeCard = (props: Props) => {
const { t } = useTranslation();
const { toast } = useToast();
const {
children,
avatar = LOGO_ICON,
@@ -59,6 +61,13 @@ const NodeCard = (props: Props) => {
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
const setHoverNodeId = useContextSelector(WorkflowContext, (v) => v.setHoverNodeId);
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
// custom title edit
const { onOpenModal: onOpenCustomTitleModal, EditModal: EditTitleModal } = useEditTitle({
title: t('common.Custom Title'),
placeholder: t('app.module.Custom Title Tip') || ''
});
const showToolHandle = useMemo(
() => isTool && !!nodeList.find((item) => item?.flowNodeType === FlowNodeTypeEnum.tools),
@@ -81,13 +90,42 @@ const NodeCard = (props: Props) => {
<Box ml={3} fontSize={'lg'} fontWeight={'medium'}>
{t(name)}
</Box>
{!menuForbid?.rename && (
<MyIcon
className="controller-rename"
display={'none'}
name={'edit'}
w={'14px'}
cursor={'pointer'}
ml={1}
color={'myGray.500'}
_hover={{ color: 'primary.600' }}
onClick={() => {
onOpenCustomTitleModal({
defaultVal: name,
onSuccess: (e) => {
if (!e) {
return toast({
title: t('app.modules.Title is required'),
status: 'warning'
});
}
onChangeNode({
nodeId,
type: 'attr',
key: 'name',
value: e
});
}
});
}}
/>
)}
</Flex>
<MenuRender
name={name}
nodeId={nodeId}
pluginId={pluginId}
flowNodeType={flowNodeType}
inputs={inputs}
menuForbid={menuForbid}
/>
<NodeIntro nodeId={nodeId} intro={intro} />
@@ -101,11 +139,13 @@ const NodeCard = (props: Props) => {
avatar,
t,
name,
menuForbid,
pluginId,
flowNodeType,
inputs,
menuForbid,
intro
intro,
onOpenCustomTitleModal,
onChangeNode,
toast
]);
return (
@@ -123,6 +163,9 @@ const NodeCard = (props: Props) => {
},
'& .controller-debug': {
display: 'block'
},
'& .controller-rename': {
display: 'block'
}
}}
onMouseEnter={() => setHoverNodeId(nodeId)}
@@ -140,6 +183,8 @@ const NodeCard = (props: Props) => {
{children}
<ConnectionSourceHandle nodeId={nodeId} />
<ConnectionTargetHandle nodeId={nodeId} />
<EditTitleModal maxLength={20} />
</Box>
);
};
@@ -147,18 +192,14 @@ const NodeCard = (props: Props) => {
export default React.memo(NodeCard);
const MenuRender = React.memo(function MenuRender({
name,
nodeId,
pluginId,
flowNodeType,
inputs,
menuForbid
}: {
name: string;
nodeId: string;
pluginId?: string;
flowNodeType: Props['flowNodeType'];
inputs: Props['inputs'];
menuForbid?: Props['menuForbid'];
}) {
const { t } = useTranslation();
@@ -169,11 +210,7 @@ const MenuRender = React.memo(function MenuRender({
const { openConfirm: onOpenConfirmSync, ConfirmModal: ConfirmSyncModal } = useConfirm({
content: t('module.Confirm Sync Plugin')
});
// custom title edit
const { onOpenModal: onOpenCustomTitleModal, EditModal: EditTitleModal } = useEditTitle({
title: t('common.Custom Title'),
placeholder: t('app.module.Custom Title Tip') || ''
});
const { openConfirm: onOpenConfirmDeleteNode, ConfirmModal: ConfirmDeleteModal } = useConfirm({
content: t('core.module.Confirm Delete Node'),
type: 'delete'
@@ -182,7 +219,6 @@ const MenuRender = React.memo(function MenuRender({
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
const onResetNode = useContextSelector(WorkflowContext, (v) => v.onResetNode);
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const onCopyNode = useCallback(
(nodeId: string) => {
@@ -236,6 +272,16 @@ const MenuRender = React.memo(function MenuRender({
onClick: () => openDebugNode({ entryNodeId: nodeId })
}
]),
...(menuForbid?.copy
? []
: [
{
icon: 'copy',
label: t('common.Copy'),
variant: 'whiteBase',
onClick: () => onCopyNode(nodeId)
}
]),
...(flowNodeType === FlowNodeTypeEnum.pluginModule
? [
{
@@ -264,43 +310,7 @@ const MenuRender = React.memo(function MenuRender({
}
]
: []),
...(menuForbid?.rename
? []
: [
{
icon: 'edit',
label: t('common.Rename'),
variant: 'whiteBase',
onClick: () =>
onOpenCustomTitleModal({
defaultVal: name,
onSuccess: (e) => {
if (!e) {
return toast({
title: t('app.modules.Title is required'),
status: 'warning'
});
}
onChangeNode({
nodeId,
type: 'attr',
key: 'name',
value: e
});
}
})
}
]),
...(menuForbid?.copy
? []
: [
{
icon: 'copy',
label: t('common.Copy'),
variant: 'whiteBase',
onClick: () => onCopyNode(nodeId)
}
]),
...(menuForbid?.delete
? []
: [
@@ -342,7 +352,6 @@ const MenuRender = React.memo(function MenuRender({
</Box>
))}
</Box>
<EditTitleModal maxLength={20} />
<ConfirmSyncModal />
<ConfirmDeleteModal />
<DebugInputModal />
@@ -352,20 +361,15 @@ const MenuRender = React.memo(function MenuRender({
ConfirmDeleteModal,
ConfirmSyncModal,
DebugInputModal,
EditTitleModal,
flowNodeType,
menuForbid?.copy,
menuForbid?.debug,
menuForbid?.delete,
menuForbid?.rename,
name,
nodeId,
onChangeNode,
onCopyNode,
onDelNode,
onOpenConfirmDeleteNode,
onOpenConfirmSync,
onOpenCustomTitleModal,
onResetNode,
openDebugNode,
pluginId,
@@ -388,7 +392,7 @@ const NodeIntro = React.memo(function NodeIntro({
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const moduleIsTool = useMemo(() => {
const NodeIsTool = useMemo(() => {
const { isTool } = splitToolInputs([], nodeId);
return isTool;
}, [nodeId, splitToolInputs]);
@@ -407,7 +411,7 @@ const NodeIntro = React.memo(function NodeIntro({
<Box fontSize={'xs'} color={'myGray.600'} flex={'1 0 0'}>
{t(intro)}
</Box>
{moduleIsTool && (
{NodeIsTool && (
<Button
size={'xs'}
variant={'whiteBase'}
@@ -432,7 +436,7 @@ const NodeIntro = React.memo(function NodeIntro({
<EditIntroModal maxLength={500} />
</>
);
}, [EditIntroModal, intro, moduleIsTool, nodeId, onChangeNode, onOpenIntroModal, t]);
}, [EditIntroModal, intro, NodeIsTool, nodeId, onChangeNode, onOpenIntroModal, t]);
return Render;
});

View File

@@ -413,7 +413,7 @@ const WorkflowContextProvider = ({
});
/* If the module is connected by a tool, the tool input and the normal input are separated */
const splitToolInputs = useMemoizedFn((inputs: FlowNodeInputItemType[], nodeId: string) => {
const splitToolInputs = (inputs: FlowNodeInputItemType[], nodeId: string) => {
const isTool = !!edges.find(
(edge) => edge.targetHandle === NodeOutputKeyEnum.selectedTools && edge.target === nodeId
);
@@ -426,7 +426,7 @@ const WorkflowContextProvider = ({
return !item.toolDescription;
})
};
});
};
const initData = useMemoizedFn(
async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {

View File

@@ -232,39 +232,43 @@ const RenderHeaderContainer = React.memo(function RenderHeaderContainer({
<Box flex={1} />
<MyMenu
Button={
{!isShowVersionHistories && (
<>
<MyMenu
Button={
<IconButton
mr={[2, 4]}
icon={<MyIcon name={'more'} w={'14px'} p={2} />}
aria-label={''}
size={'sm'}
variant={'whitePrimary'}
/>
}
menuList={[
{
label: t('app.Import Configs'),
icon: 'common/importLight',
onClick: onOpenImport
},
{
label: t('app.Export Configs'),
icon: 'export',
onClick: onExportWorkflow
}
]}
/>
<IconButton
mr={[2, 4]}
icon={<MyIcon name={'more'} w={'14px'} p={2} />}
icon={<MyIcon name={'history'} w={'18px'} />}
aria-label={''}
size={'sm'}
w={'30px'}
variant={'whitePrimary'}
onClick={() => setIsShowVersionHistories(true)}
/>
}
menuList={[
{
label: t('app.Import Configs'),
icon: 'common/importLight',
onClick: onOpenImport
},
{
label: t('app.Export Configs'),
icon: 'export',
onClick: onExportWorkflow
}
]}
/>
<IconButton
mr={[2, 4]}
icon={<MyIcon name={'history'} w={'18px'} />}
aria-label={''}
size={'sm'}
w={'30px'}
variant={'whitePrimary'}
onClick={() => setIsShowVersionHistories(true)}
/>
</>
)}
<Button
size={'sm'}