mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-13 23:45:56 +08:00
### What problem does this PR solve? feat: add OperateDropdown feat: send debug message #918 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
59efba3d87
commit
706985c188
3
web/src/components/operate-dropdown/index.less
Normal file
3
web/src/components/operate-dropdown/index.less
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.delete {
|
||||||
|
height: 24px;
|
||||||
|
}
|
61
web/src/components/operate-dropdown/index.tsx
Normal file
61
web/src/components/operate-dropdown/index.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { ReactComponent as MoreIcon } from '@/assets/svg/more.svg';
|
||||||
|
import { useShowDeleteConfirm } from '@/hooks/commonHooks';
|
||||||
|
import { DeleteOutlined } from '@ant-design/icons';
|
||||||
|
import { Dropdown, MenuProps, Space } from 'antd';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './index.less';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
deleteItem: () => Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const OperateDropdown = ({
|
||||||
|
deleteItem,
|
||||||
|
children,
|
||||||
|
}: React.PropsWithChildren<IProps>) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const showDeleteConfirm = useShowDeleteConfirm();
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
showDeleteConfirm({ onOk: deleteItem });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDropdownMenuClick: MenuProps['onClick'] = ({ domEvent, key }) => {
|
||||||
|
domEvent.preventDefault();
|
||||||
|
domEvent.stopPropagation();
|
||||||
|
if (key === '1') {
|
||||||
|
handleDelete();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const items: MenuProps['items'] = [
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
label: (
|
||||||
|
<Space>
|
||||||
|
{t('common.delete')}
|
||||||
|
<DeleteOutlined />
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
menu={{
|
||||||
|
items,
|
||||||
|
onClick: handleDropdownMenuClick,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children || (
|
||||||
|
<span className={styles.delete}>
|
||||||
|
<MoreIcon />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OperateDropdown;
|
@ -64,7 +64,7 @@ export const useSetFlow = () => {
|
|||||||
);
|
);
|
||||||
queryClient.invalidateQueries({ queryKey: ['fetchFlowList'] });
|
queryClient.invalidateQueries({ queryKey: ['fetchFlowList'] });
|
||||||
}
|
}
|
||||||
return data?.retcode;
|
return data;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -206,14 +206,14 @@ export const useSendMessageWithSse = (
|
|||||||
|
|
||||||
//#region chat hooks
|
//#region chat hooks
|
||||||
|
|
||||||
export const useScrollToBottom = (id?: string) => {
|
export const useScrollToBottom = (messages?: unknown) => {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const scrollToBottom = useCallback(() => {
|
const scrollToBottom = useCallback(() => {
|
||||||
if (id) {
|
if (messages) {
|
||||||
ref.current?.scrollIntoView({ behavior: 'instant' });
|
ref.current?.scrollIntoView({ behavior: 'instant' });
|
||||||
}
|
}
|
||||||
}, [id]);
|
}, [messages]); // If the message changes, scroll to the bottom
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Edge, Node } from 'reactflow';
|
import { Edge, Node } from 'reactflow';
|
||||||
|
import { IReference, Message } from './chat';
|
||||||
|
|
||||||
export type DSLComponents = Record<string, IOperator>;
|
export type DSLComponents = Record<string, IOperator>;
|
||||||
|
|
||||||
@ -8,6 +9,8 @@ export interface DSL {
|
|||||||
path?: string[];
|
path?: string[];
|
||||||
answer?: any[];
|
answer?: any[];
|
||||||
graph?: IGraph;
|
graph?: IGraph;
|
||||||
|
messages: Message[];
|
||||||
|
reference: IReference[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOperator {
|
export interface IOperator {
|
||||||
@ -32,13 +35,7 @@ export interface IFlow {
|
|||||||
create_date: string;
|
create_date: string;
|
||||||
create_time: number;
|
create_time: number;
|
||||||
description: null;
|
description: null;
|
||||||
dsl: {
|
dsl: DSL;
|
||||||
answer: any[];
|
|
||||||
components: DSLComponents;
|
|
||||||
graph: IGraph;
|
|
||||||
history: any[];
|
|
||||||
path: string[];
|
|
||||||
};
|
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
update_date: string;
|
update_date: string;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { MessageType } from '@/constants/chat';
|
import { MessageType } from '@/constants/chat';
|
||||||
import { IConversation, IReference } from '@/interfaces/database/chat';
|
import { IConversation, IReference } from '@/interfaces/database/chat';
|
||||||
import { EmptyConversationId } from './constants';
|
import { EmptyConversationId } from './constants';
|
||||||
import { IClientConversation, IMessage } from './interface';
|
import { IMessage } from './interface';
|
||||||
|
|
||||||
export const isConversationIdExist = (conversationId: string) => {
|
export const isConversationIdExist = (conversationId: string) => {
|
||||||
return conversationId !== EmptyConversationId && conversationId !== '';
|
return conversationId !== EmptyConversationId && conversationId !== '';
|
||||||
@ -25,7 +25,7 @@ export const getDocumentIdsFromConversionReference = (data: IConversation) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const buildMessageItemReference = (
|
export const buildMessageItemReference = (
|
||||||
conversation: IClientConversation,
|
conversation: { message: IMessage[]; reference: IReference[] },
|
||||||
message: IMessage,
|
message: IMessage,
|
||||||
) => {
|
) => {
|
||||||
const assistantMessages = conversation.message
|
const assistantMessages = conversation.message
|
||||||
|
@ -2,43 +2,34 @@ import MessageItem from '@/components/message-item';
|
|||||||
import DocumentPreviewer from '@/components/pdf-previewer';
|
import DocumentPreviewer from '@/components/pdf-previewer';
|
||||||
import { MessageType } from '@/constants/chat';
|
import { MessageType } from '@/constants/chat';
|
||||||
import { useTranslate } from '@/hooks/commonHooks';
|
import { useTranslate } from '@/hooks/commonHooks';
|
||||||
import {
|
import { useClickDrawer, useGetFileIcon } from '@/pages/chat/hooks';
|
||||||
useClickDrawer,
|
|
||||||
useFetchConversationOnMount,
|
|
||||||
useGetFileIcon,
|
|
||||||
useGetSendButtonDisabled,
|
|
||||||
useSelectConversationLoading,
|
|
||||||
useSendMessage,
|
|
||||||
} from '@/pages/chat/hooks';
|
|
||||||
import { buildMessageItemReference } from '@/pages/chat/utils';
|
import { buildMessageItemReference } from '@/pages/chat/utils';
|
||||||
import { Button, Drawer, Flex, Input, Spin } from 'antd';
|
import { Button, Drawer, Flex, Input, Spin } from 'antd';
|
||||||
|
|
||||||
|
import { useSelectCurrentMessages, useSendMessage } from './hooks';
|
||||||
|
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
const FlowChatBox = () => {
|
const FlowChatBox = () => {
|
||||||
const {
|
const {
|
||||||
ref,
|
ref,
|
||||||
currentConversation: conversation,
|
currentMessages,
|
||||||
addNewestConversation,
|
reference,
|
||||||
removeLatestMessage,
|
|
||||||
addNewestAnswer,
|
addNewestAnswer,
|
||||||
} = useFetchConversationOnMount();
|
addNewestQuestion,
|
||||||
|
removeLatestMessage,
|
||||||
|
loading,
|
||||||
|
} = useSelectCurrentMessages();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleInputChange,
|
handleInputChange,
|
||||||
handlePressEnter,
|
handlePressEnter,
|
||||||
value,
|
value,
|
||||||
loading: sendLoading,
|
loading: sendLoading,
|
||||||
} = useSendMessage(
|
} = useSendMessage(addNewestQuestion, removeLatestMessage, addNewestAnswer);
|
||||||
conversation,
|
|
||||||
addNewestConversation,
|
|
||||||
removeLatestMessage,
|
|
||||||
addNewestAnswer,
|
|
||||||
);
|
|
||||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||||
useClickDrawer();
|
useClickDrawer();
|
||||||
const disabled = useGetSendButtonDisabled();
|
|
||||||
useGetFileIcon();
|
useGetFileIcon();
|
||||||
const loading = useSelectConversationLoading();
|
|
||||||
const { t } = useTranslate('chat');
|
const { t } = useTranslate('chat');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -47,17 +38,20 @@ const FlowChatBox = () => {
|
|||||||
<Flex flex={1} vertical className={styles.messageContainer}>
|
<Flex flex={1} vertical className={styles.messageContainer}>
|
||||||
<div>
|
<div>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
{conversation?.message?.map((message, i) => {
|
{currentMessages?.map((message, i) => {
|
||||||
return (
|
return (
|
||||||
<MessageItem
|
<MessageItem
|
||||||
loading={
|
loading={
|
||||||
message.role === MessageType.Assistant &&
|
message.role === MessageType.Assistant &&
|
||||||
sendLoading &&
|
sendLoading &&
|
||||||
conversation?.message.length - 1 === i
|
currentMessages.length - 1 === i
|
||||||
}
|
}
|
||||||
key={message.id}
|
key={message.id}
|
||||||
item={message}
|
item={message}
|
||||||
reference={buildMessageItemReference(conversation, message)}
|
reference={buildMessageItemReference(
|
||||||
|
{ message: currentMessages, reference },
|
||||||
|
message,
|
||||||
|
)}
|
||||||
clickDocumentButton={clickDocumentButton}
|
clickDocumentButton={clickDocumentButton}
|
||||||
></MessageItem>
|
></MessageItem>
|
||||||
);
|
);
|
||||||
@ -70,13 +64,11 @@ const FlowChatBox = () => {
|
|||||||
size="large"
|
size="large"
|
||||||
placeholder={t('sendPlaceholder')}
|
placeholder={t('sendPlaceholder')}
|
||||||
value={value}
|
value={value}
|
||||||
disabled={disabled}
|
|
||||||
suffix={
|
suffix={
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={handlePressEnter}
|
onClick={handlePressEnter}
|
||||||
loading={sendLoading}
|
loading={sendLoading}
|
||||||
disabled={disabled}
|
|
||||||
>
|
>
|
||||||
{t('send')}
|
{t('send')}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
import { IModalProps } from '@/interfaces/common';
|
||||||
|
import { Drawer } from 'antd';
|
||||||
|
import FlowChatBox from './box';
|
||||||
|
|
||||||
|
const ChatDrawer = ({ visible, hideModal }: IModalProps<any>) => {
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
title="Debug"
|
||||||
|
placement="right"
|
||||||
|
onClose={hideModal}
|
||||||
|
open={visible}
|
||||||
|
getContainer={false}
|
||||||
|
width={470}
|
||||||
|
zIndex={10000}
|
||||||
|
>
|
||||||
|
<FlowChatBox></FlowChatBox>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChatDrawer;
|
@ -2,27 +2,25 @@ import { MessageType } from '@/constants/chat';
|
|||||||
import { useFetchFlow } from '@/hooks/flow-hooks';
|
import { useFetchFlow } from '@/hooks/flow-hooks';
|
||||||
import {
|
import {
|
||||||
useHandleMessageInputChange,
|
useHandleMessageInputChange,
|
||||||
// useScrollToBottom,
|
useScrollToBottom,
|
||||||
useSendMessageWithSse,
|
useSendMessageWithSse,
|
||||||
} from '@/hooks/logicHooks';
|
} from '@/hooks/logicHooks';
|
||||||
import { IAnswer } from '@/interfaces/database/chat';
|
import { IAnswer } from '@/interfaces/database/chat';
|
||||||
import { IMessage } from '@/pages/chat/interface';
|
import { IMessage } from '@/pages/chat/interface';
|
||||||
import omit from 'lodash/omit';
|
import api from '@/utils/api';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useParams } from 'umi';
|
import { useParams } from 'umi';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { Operator } from '../constant';
|
|
||||||
import useGraphStore from '../store';
|
|
||||||
|
|
||||||
export const useSelectCurrentConversation = () => {
|
export const useSelectCurrentMessages = () => {
|
||||||
const { id: id } = useParams();
|
const { id: id } = useParams();
|
||||||
const findNodeByName = useGraphStore((state) => state.findNodeByName);
|
|
||||||
const [currentMessages, setCurrentMessages] = useState<IMessage[]>([]);
|
const [currentMessages, setCurrentMessages] = useState<IMessage[]>([]);
|
||||||
|
|
||||||
const { data: flowDetail } = useFetchFlow();
|
const { data: flowDetail, loading } = useFetchFlow();
|
||||||
const messages = flowDetail.dsl.history;
|
const messages = flowDetail.dsl.messages;
|
||||||
|
const reference = flowDetail.dsl.reference;
|
||||||
|
|
||||||
const prologue = findNodeByName(Operator.Begin)?.data?.form?.prologue;
|
const ref = useScrollToBottom(currentMessages);
|
||||||
|
|
||||||
const addNewestQuestion = useCallback(
|
const addNewestQuestion = useCallback(
|
||||||
(message: string, answer: string = '') => {
|
(message: string, answer: string = '') => {
|
||||||
@ -45,10 +43,9 @@ export const useSelectCurrentConversation = () => {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const addNewestAnswer = useCallback(
|
const addNewestAnswer = useCallback((answer: IAnswer) => {
|
||||||
(answer: IAnswer) => {
|
|
||||||
setCurrentMessages((pre) => {
|
setCurrentMessages((pre) => {
|
||||||
const latestMessage = currentMessages?.at(-1);
|
const latestMessage = pre?.at(-1);
|
||||||
|
|
||||||
if (latestMessage) {
|
if (latestMessage) {
|
||||||
return [
|
return [
|
||||||
@ -62,104 +59,55 @@ export const useSelectCurrentConversation = () => {
|
|||||||
}
|
}
|
||||||
return pre;
|
return pre;
|
||||||
});
|
});
|
||||||
},
|
}, []);
|
||||||
[currentMessages],
|
|
||||||
);
|
|
||||||
|
|
||||||
const removeLatestMessage = useCallback(() => {
|
const removeLatestMessage = useCallback(() => {
|
||||||
setCurrentMessages((pre) => {
|
setCurrentMessages((pre) => {
|
||||||
const nextMessages = pre?.slice(0, -2) ?? [];
|
const nextMessages = pre?.slice(0, -2) ?? [];
|
||||||
|
return nextMessages;
|
||||||
return [...pre, ...nextMessages];
|
return [...pre, ...nextMessages];
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const addPrologue = useCallback(() => {
|
|
||||||
if (id === '') {
|
|
||||||
const nextMessage = {
|
|
||||||
role: MessageType.Assistant,
|
|
||||||
content: prologue,
|
|
||||||
id: uuid(),
|
|
||||||
} as IMessage;
|
|
||||||
|
|
||||||
setCurrentMessages({
|
|
||||||
id: '',
|
|
||||||
reference: [],
|
|
||||||
message: [nextMessage],
|
|
||||||
} as any);
|
|
||||||
}
|
|
||||||
}, [id, prologue]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
addPrologue();
|
|
||||||
}, [addPrologue]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id) {
|
if (id) {
|
||||||
setCurrentMessages(messages);
|
const nextMessages = messages.map((x) => ({ ...x, id: uuid() }));
|
||||||
|
setCurrentMessages(nextMessages);
|
||||||
}
|
}
|
||||||
}, [messages, id]);
|
}, [messages, id]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentConversation: currentMessages,
|
currentMessages,
|
||||||
|
reference,
|
||||||
addNewestQuestion,
|
addNewestQuestion,
|
||||||
removeLatestMessage,
|
removeLatestMessage,
|
||||||
addNewestAnswer,
|
addNewestAnswer,
|
||||||
|
ref,
|
||||||
|
loading,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// export const useFetchConversationOnMount = () => {
|
|
||||||
// const { conversationId } = useGetChatSearchParams();
|
|
||||||
// const fetchConversation = useFetchConversation();
|
|
||||||
// const {
|
|
||||||
// currentConversation,
|
|
||||||
// addNewestQuestion,
|
|
||||||
// removeLatestMessage,
|
|
||||||
// addNewestAnswer,
|
|
||||||
// } = useSelectCurrentConversation();
|
|
||||||
// const ref = useScrollToBottom(currentConversation);
|
|
||||||
|
|
||||||
// const fetchConversationOnMount = useCallback(() => {
|
|
||||||
// if (isConversationIdExist(conversationId)) {
|
|
||||||
// fetchConversation(conversationId);
|
|
||||||
// }
|
|
||||||
// }, [fetchConversation, conversationId]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// fetchConversationOnMount();
|
|
||||||
// }, [fetchConversationOnMount]);
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// currentConversation,
|
|
||||||
// addNewestQuestion,
|
|
||||||
// ref,
|
|
||||||
// removeLatestMessage,
|
|
||||||
// addNewestAnswer,
|
|
||||||
// };
|
|
||||||
// };
|
|
||||||
|
|
||||||
export const useSendMessage = (
|
export const useSendMessage = (
|
||||||
conversation: any,
|
|
||||||
addNewestQuestion: (message: string, answer?: string) => void,
|
addNewestQuestion: (message: string, answer?: string) => void,
|
||||||
removeLatestMessage: () => void,
|
removeLatestMessage: () => void,
|
||||||
addNewestAnswer: (answer: IAnswer) => void,
|
addNewestAnswer: (answer: IAnswer) => void,
|
||||||
) => {
|
) => {
|
||||||
const { id: conversationId } = useParams();
|
const { id: flowId } = useParams();
|
||||||
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
||||||
|
const { data: flowDetail } = useFetchFlow();
|
||||||
|
const messages = flowDetail.dsl.messages;
|
||||||
|
|
||||||
const { send, answer, done } = useSendMessageWithSse();
|
const { send, answer, done } = useSendMessageWithSse(api.runCanvas);
|
||||||
|
|
||||||
const sendMessage = useCallback(
|
const sendMessage = useCallback(
|
||||||
async (message: string, id?: string) => {
|
async (message: string, id?: string) => {
|
||||||
const res: Response | undefined = await send({
|
const params: Record<string, unknown> = {
|
||||||
conversation_id: id ?? conversationId,
|
id: flowId,
|
||||||
messages: [
|
};
|
||||||
...(conversation?.message ?? []).map((x: IMessage) => omit(x, 'id')),
|
if (message) {
|
||||||
{
|
params.message = message;
|
||||||
role: MessageType.User,
|
}
|
||||||
content: message,
|
const res: Response | undefined = await send(params);
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res?.status !== 200) {
|
if (res?.status !== 200) {
|
||||||
// cancel loading
|
// cancel loading
|
||||||
@ -167,13 +115,7 @@ export const useSendMessage = (
|
|||||||
removeLatestMessage();
|
removeLatestMessage();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[flowId, removeLatestMessage, setValue, send],
|
||||||
conversation?.message,
|
|
||||||
conversationId,
|
|
||||||
removeLatestMessage,
|
|
||||||
setValue,
|
|
||||||
send,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSendMessage = useCallback(
|
const handleSendMessage = useCallback(
|
||||||
@ -189,6 +131,13 @@ export const useSendMessage = (
|
|||||||
}
|
}
|
||||||
}, [answer, addNewestAnswer]);
|
}, [answer, addNewestAnswer]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// fetch prologue
|
||||||
|
if (messages.length === 0) {
|
||||||
|
sendMessage('');
|
||||||
|
}
|
||||||
|
}, [sendMessage, messages]);
|
||||||
|
|
||||||
const handlePressEnter = useCallback(() => {
|
const handlePressEnter = useCallback(() => {
|
||||||
if (done) {
|
if (done) {
|
||||||
setValue('');
|
setValue('');
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
.chatContainer {
|
.chatContainer {
|
||||||
padding: 0 0 24px 24px;
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
.messageContainer {
|
.messageContainer {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding-right: 24px;
|
padding-right: 24px;
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
.flowHeader {
|
.flowHeader {
|
||||||
padding: 20px;
|
padding: 0 20px;
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,51 @@
|
|||||||
import { Button, Flex } from 'antd';
|
import { Button, Flex, Space } from 'antd';
|
||||||
|
|
||||||
|
import { useSetModalState } from '@/hooks/commonHooks';
|
||||||
|
import { useFetchFlow } from '@/hooks/flow-hooks';
|
||||||
|
import { ArrowLeftOutlined } from '@ant-design/icons';
|
||||||
|
import { Link } from 'umi';
|
||||||
|
import ChatDrawer from '../chat/drawer';
|
||||||
import { useRunGraph, useSaveGraph } from '../hooks';
|
import { useRunGraph, useSaveGraph } from '../hooks';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
const FlowHeader = () => {
|
const FlowHeader = () => {
|
||||||
const { saveGraph } = useSaveGraph();
|
const { saveGraph } = useSaveGraph();
|
||||||
const { runGraph } = useRunGraph();
|
const { runGraph } = useRunGraph();
|
||||||
|
const {
|
||||||
|
visible: chatDrawerVisible,
|
||||||
|
hideModal: hideChatDrawer,
|
||||||
|
showModal: showChatDrawer,
|
||||||
|
} = useSetModalState();
|
||||||
|
const { data } = useFetchFlow();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<Flex
|
<Flex
|
||||||
align="center"
|
align="center"
|
||||||
justify="end"
|
justify={'space-between'}
|
||||||
gap={'large'}
|
gap={'large'}
|
||||||
className={styles.flowHeader}
|
className={styles.flowHeader}
|
||||||
>
|
>
|
||||||
<Button onClick={runGraph}>
|
<Space size={'large'}>
|
||||||
|
<Link to={`/flow`}>
|
||||||
|
<ArrowLeftOutlined />
|
||||||
|
</Link>
|
||||||
|
<h3>{data.title}</h3>
|
||||||
|
</Space>
|
||||||
|
<Space size={'large'}>
|
||||||
|
<Button onClick={showChatDrawer}>
|
||||||
<b>Debug</b>
|
<b>Debug</b>
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="primary" onClick={saveGraph}>
|
<Button type="primary" onClick={saveGraph}>
|
||||||
<b>Save</b>
|
<b>Save</b>
|
||||||
</Button>
|
</Button>
|
||||||
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<ChatDrawer
|
||||||
|
visible={chatDrawerVisible}
|
||||||
|
hideModal={hideChatDrawer}
|
||||||
|
></ChatDrawer>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ const useSetGraphInfo = () => {
|
|||||||
const { setEdges, setNodes } = useGraphStore((state) => state);
|
const { setEdges, setNodes } = useGraphStore((state) => state);
|
||||||
const setGraphInfo = useCallback(
|
const setGraphInfo = useCallback(
|
||||||
({ nodes = [], edges = [] }: IGraph) => {
|
({ nodes = [], edges = [] }: IGraph) => {
|
||||||
if (nodes.length && edges.length) {
|
if (nodes.length || edges.length) {
|
||||||
setNodes(nodes);
|
setNodes(nodes);
|
||||||
setEdges(edges);
|
setEdges(edges);
|
||||||
}
|
}
|
||||||
@ -202,7 +202,7 @@ export const useFetchDataOnMount = () => {
|
|||||||
const setGraphInfo = useSetGraphInfo();
|
const setGraphInfo = useSetGraphInfo();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setGraphInfo(data?.dsl?.graph ?? {});
|
setGraphInfo(data?.dsl?.graph ?? ({} as IGraph));
|
||||||
}, [setGraphInfo, data?.dsl?.graph]);
|
}, [setGraphInfo, data?.dsl?.graph]);
|
||||||
|
|
||||||
useWatchGraphChange();
|
useWatchGraphChange();
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
import { ReactComponent as MoreIcon } from '@/assets/svg/more.svg';
|
|
||||||
import { useShowDeleteConfirm } from '@/hooks/commonHooks';
|
|
||||||
import { formatDate } from '@/utils/date';
|
import { formatDate } from '@/utils/date';
|
||||||
import {
|
import { CalendarOutlined, UserOutlined } from '@ant-design/icons';
|
||||||
CalendarOutlined,
|
import { Avatar, Card } from 'antd';
|
||||||
DeleteOutlined,
|
|
||||||
UserOutlined,
|
|
||||||
} from '@ant-design/icons';
|
|
||||||
import { Avatar, Card, Dropdown, MenuProps, Space } from 'antd';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useNavigate } from 'umi';
|
import { useNavigate } from 'umi';
|
||||||
|
|
||||||
|
import OperateDropdown from '@/components/operate-dropdown';
|
||||||
import { useDeleteFlow } from '@/hooks/flow-hooks';
|
import { useDeleteFlow } from '@/hooks/flow-hooks';
|
||||||
import { IFlow } from '@/interfaces/database/flow';
|
import { IFlow } from '@/interfaces/database/flow';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
@ -20,37 +15,11 @@ interface IProps {
|
|||||||
|
|
||||||
const FlowCard = ({ item }: IProps) => {
|
const FlowCard = ({ item }: IProps) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const showDeleteConfirm = useShowDeleteConfirm();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { deleteFlow } = useDeleteFlow();
|
const { deleteFlow } = useDeleteFlow();
|
||||||
|
|
||||||
const removeKnowledge = () => {
|
const removeFlow = useCallback(() => {
|
||||||
return deleteFlow([item.id]);
|
return deleteFlow([item.id]);
|
||||||
};
|
}, [deleteFlow, item]);
|
||||||
|
|
||||||
const handleDelete = () => {
|
|
||||||
showDeleteConfirm({ onOk: removeKnowledge });
|
|
||||||
};
|
|
||||||
|
|
||||||
const items: MenuProps['items'] = [
|
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
label: (
|
|
||||||
<Space>
|
|
||||||
{t('common.delete')}
|
|
||||||
<DeleteOutlined />
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const handleDropdownMenuClick: MenuProps['onClick'] = ({ domEvent, key }) => {
|
|
||||||
domEvent.preventDefault();
|
|
||||||
domEvent.stopPropagation();
|
|
||||||
if (key === '1') {
|
|
||||||
handleDelete();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCardClick = () => {
|
const handleCardClick = () => {
|
||||||
navigate(`/flow/${item.id}`);
|
navigate(`/flow/${item.id}`);
|
||||||
@ -61,16 +30,7 @@ const FlowCard = ({ item }: IProps) => {
|
|||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<Avatar size={34} icon={<UserOutlined />} src={item.avatar} />
|
<Avatar size={34} icon={<UserOutlined />} src={item.avatar} />
|
||||||
<Dropdown
|
<OperateDropdown deleteItem={removeFlow}></OperateDropdown>
|
||||||
menu={{
|
|
||||||
items,
|
|
||||||
onClick: handleDropdownMenuClick,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className={styles.delete}>
|
|
||||||
<MoreIcon />
|
|
||||||
</span>
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.titleWrapper}>
|
<div className={styles.titleWrapper}>
|
||||||
<span className={styles.title}>{item.title}</span>
|
<span className={styles.title}>{item.title}</span>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useSetModalState } from '@/hooks/commonHooks';
|
import { useSetModalState } from '@/hooks/commonHooks';
|
||||||
import { useFetchFlowList, useSetFlow } from '@/hooks/flow-hooks';
|
import { useFetchFlowList, useSetFlow } from '@/hooks/flow-hooks';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
import { useNavigate } from 'umi';
|
||||||
import { dsl } from '../mock';
|
import { dsl } from '../mock';
|
||||||
|
|
||||||
export const useFetchDataOnMount = () => {
|
export const useFetchDataOnMount = () => {
|
||||||
@ -17,16 +18,18 @@ export const useSaveFlow = () => {
|
|||||||
showModal: showFileRenameModal,
|
showModal: showFileRenameModal,
|
||||||
} = useSetModalState();
|
} = useSetModalState();
|
||||||
const { loading, setFlow } = useSetFlow();
|
const { loading, setFlow } = useSetFlow();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const onFlowOk = useCallback(
|
const onFlowOk = useCallback(
|
||||||
async (title: string) => {
|
async (title: string) => {
|
||||||
const ret = await setFlow({ title, dsl });
|
const ret = await setFlow({ title, dsl });
|
||||||
|
|
||||||
if (ret === 0) {
|
if (ret?.retcode === 0) {
|
||||||
hideFlowSettingModal();
|
hideFlowSettingModal();
|
||||||
|
navigate(`/flow/${ret.data.id}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setFlow, hideFlowSettingModal],
|
[setFlow, hideFlowSettingModal, navigate],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleShowFlowSettingModal = useCallback(
|
const handleShowFlowSettingModal = useCallback(
|
||||||
|
@ -49,83 +49,83 @@ export const dsl = {
|
|||||||
sourcePosition: 'left',
|
sourcePosition: 'left',
|
||||||
targetPosition: 'right',
|
targetPosition: 'right',
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
id: 'Answer:China',
|
// id: 'Answer:China',
|
||||||
type: 'textUpdater',
|
// type: 'textUpdater',
|
||||||
position: {
|
// position: {
|
||||||
x: 150,
|
// x: 150,
|
||||||
y: 200,
|
// y: 200,
|
||||||
},
|
// },
|
||||||
data: {
|
// data: {
|
||||||
label: 'Answer',
|
// label: 'Answer',
|
||||||
},
|
// },
|
||||||
sourcePosition: 'left',
|
// sourcePosition: 'left',
|
||||||
targetPosition: 'right',
|
// targetPosition: 'right',
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: 'Retrieval:China',
|
// id: 'Retrieval:China',
|
||||||
type: 'textUpdater',
|
// type: 'textUpdater',
|
||||||
position: {
|
// position: {
|
||||||
x: 250,
|
// x: 250,
|
||||||
y: 200,
|
// y: 200,
|
||||||
},
|
// },
|
||||||
data: {
|
// data: {
|
||||||
label: 'Retrieval',
|
// label: 'Retrieval',
|
||||||
},
|
// },
|
||||||
sourcePosition: 'left',
|
// sourcePosition: 'left',
|
||||||
targetPosition: 'right',
|
// targetPosition: 'right',
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: 'Generate:China',
|
// id: 'Generate:China',
|
||||||
type: 'textUpdater',
|
// type: 'textUpdater',
|
||||||
position: {
|
// position: {
|
||||||
x: 100,
|
// x: 100,
|
||||||
y: 100,
|
// y: 100,
|
||||||
},
|
// },
|
||||||
data: {
|
// data: {
|
||||||
label: 'Generate',
|
// label: 'Generate',
|
||||||
},
|
// },
|
||||||
sourcePosition: 'left',
|
// sourcePosition: 'left',
|
||||||
targetPosition: 'right',
|
// targetPosition: 'right',
|
||||||
},
|
// },
|
||||||
],
|
],
|
||||||
edges: [
|
edges: [
|
||||||
{
|
// {
|
||||||
id: '7facb53d-65c9-43b3-ac55-339c445d3891',
|
// id: '7facb53d-65c9-43b3-ac55-339c445d3891',
|
||||||
label: '',
|
// label: '',
|
||||||
source: 'begin',
|
// source: 'begin',
|
||||||
target: 'Answer:China',
|
// target: 'Answer:China',
|
||||||
markerEnd: {
|
// markerEnd: {
|
||||||
type: 'arrow',
|
// type: 'arrow',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: '7ac83631-502d-410f-a6e7-bec6866a5e99',
|
// id: '7ac83631-502d-410f-a6e7-bec6866a5e99',
|
||||||
label: '',
|
// label: '',
|
||||||
source: 'Generate:China',
|
// source: 'Generate:China',
|
||||||
target: 'Answer:China',
|
// target: 'Answer:China',
|
||||||
markerEnd: {
|
// markerEnd: {
|
||||||
type: 'arrow',
|
// type: 'arrow',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: '0aaab297-5779-43ed-9281-2c4d3741566f',
|
// id: '0aaab297-5779-43ed-9281-2c4d3741566f',
|
||||||
label: '',
|
// label: '',
|
||||||
source: 'Answer:China',
|
// source: 'Answer:China',
|
||||||
target: 'Retrieval:China',
|
// target: 'Retrieval:China',
|
||||||
markerEnd: {
|
// markerEnd: {
|
||||||
type: 'arrow',
|
// type: 'arrow',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
id: '3477f9f3-0a7d-400e-af96-a11ea7673183',
|
// id: '3477f9f3-0a7d-400e-af96-a11ea7673183',
|
||||||
label: '',
|
// label: '',
|
||||||
source: 'Retrieval:China',
|
// source: 'Retrieval:China',
|
||||||
target: 'Generate:China',
|
// target: 'Generate:China',
|
||||||
markerEnd: {
|
// markerEnd: {
|
||||||
type: 'arrow',
|
// type: 'arrow',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@ -137,43 +137,45 @@ export const dsl = {
|
|||||||
downstream: ['Answer:China'], // other edge target is downstream, edge source is current node id
|
downstream: ['Answer:China'], // other edge target is downstream, edge source is current node id
|
||||||
upstream: [], // edge source is upstream, edge target is current node id
|
upstream: [], // edge source is upstream, edge target is current node id
|
||||||
},
|
},
|
||||||
'Answer:China': {
|
// 'Answer:China': {
|
||||||
obj: {
|
// obj: {
|
||||||
component_name: 'Answer',
|
// component_name: 'Answer',
|
||||||
params: {},
|
// params: {},
|
||||||
},
|
// },
|
||||||
downstream: ['Retrieval:China'],
|
// downstream: ['Retrieval:China'],
|
||||||
upstream: ['begin', 'Generate:China'],
|
// upstream: ['begin', 'Generate:China'],
|
||||||
},
|
// },
|
||||||
'Retrieval:China': {
|
// 'Retrieval:China': {
|
||||||
obj: {
|
// obj: {
|
||||||
component_name: 'Retrieval',
|
// component_name: 'Retrieval',
|
||||||
params: {
|
// params: {
|
||||||
similarity_threshold: 0.2,
|
// similarity_threshold: 0.2,
|
||||||
keywords_similarity_weight: 0.3,
|
// keywords_similarity_weight: 0.3,
|
||||||
top_n: 6,
|
// top_n: 6,
|
||||||
top_k: 1024,
|
// top_k: 1024,
|
||||||
rerank_id: 'BAAI/bge-reranker-v2-m3',
|
// rerank_id: 'BAAI/bge-reranker-v2-m3',
|
||||||
kb_ids: ['568aa82603b611efa9d9fa163e197198'],
|
// kb_ids: ['568aa82603b611efa9d9fa163e197198'],
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
downstream: ['Generate:China'],
|
// downstream: ['Generate:China'],
|
||||||
upstream: ['Answer:China'],
|
// upstream: ['Answer:China'],
|
||||||
},
|
// },
|
||||||
'Generate:China': {
|
// 'Generate:China': {
|
||||||
obj: {
|
// obj: {
|
||||||
component_name: 'Generate',
|
// component_name: 'Generate',
|
||||||
params: {
|
// params: {
|
||||||
llm_id: 'deepseek-chat',
|
// llm_id: 'deepseek-chat',
|
||||||
prompt:
|
// prompt:
|
||||||
'You are an intelligent assistant. Please summarize the content of the knowledge base to answer the question. Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, your answer must include the sentence "The answer you are looking for is not found in the knowledge base!" Answers need to consider chat history.\n Here is the knowledge base:\n {input}\n The above is the knowledge base.',
|
// 'You are an intelligent assistant. Please summarize the content of the knowledge base to answer the question. Please list the data in the knowledge base and answer in detail. When all knowledge base content is irrelevant to the question, your answer must include the sentence "The answer you are looking for is not found in the knowledge base!" Answers need to consider chat history.\n Here is the knowledge base:\n {input}\n The above is the knowledge base.',
|
||||||
temperature: 0.2,
|
// temperature: 0.2,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
downstream: ['Answer:China'],
|
// downstream: ['Answer:China'],
|
||||||
upstream: ['Retrieval:China'],
|
// upstream: ['Retrieval:China'],
|
||||||
},
|
// },
|
||||||
},
|
},
|
||||||
|
messages: [],
|
||||||
|
reference: [],
|
||||||
history: [],
|
history: [],
|
||||||
path: [],
|
path: [],
|
||||||
answer: [],
|
answer: [],
|
||||||
|
@ -147,11 +147,6 @@ export const buildDslComponentsByGraph = (
|
|||||||
components[id] = {
|
components[id] = {
|
||||||
obj: {
|
obj: {
|
||||||
component_name: operatorName,
|
component_name: operatorName,
|
||||||
// params:
|
|
||||||
// removeUselessDataInTheOperator(
|
|
||||||
// operatorName,
|
|
||||||
// x.data.form as Record<string, unknown>,
|
|
||||||
// ) ?? {},
|
|
||||||
params:
|
params:
|
||||||
buildOperatorParams(operatorName)(
|
buildOperatorParams(operatorName)(
|
||||||
x.data.form as Record<string, unknown>,
|
x.data.form as Record<string, unknown>,
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import { ReactComponent as MoreIcon } from '@/assets/svg/more.svg';
|
|
||||||
import { KnowledgeRouteKey } from '@/constants/knowledge';
|
import { KnowledgeRouteKey } from '@/constants/knowledge';
|
||||||
import { useShowDeleteConfirm } from '@/hooks/commonHooks';
|
|
||||||
import { IKnowledge } from '@/interfaces/database/knowledge';
|
import { IKnowledge } from '@/interfaces/database/knowledge';
|
||||||
import { formatDate } from '@/utils/date';
|
import { formatDate } from '@/utils/date';
|
||||||
import {
|
import {
|
||||||
CalendarOutlined,
|
CalendarOutlined,
|
||||||
DeleteOutlined,
|
|
||||||
FileTextOutlined,
|
FileTextOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Avatar, Card, Dropdown, MenuProps, Space } from 'antd';
|
import { Avatar, Card, Space } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useDispatch, useNavigate } from 'umi';
|
import { useDispatch, useNavigate } from 'umi';
|
||||||
|
|
||||||
|
import OperateDropdown from '@/components/operate-dropdown';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
@ -22,10 +20,9 @@ interface IProps {
|
|||||||
const KnowledgeCard = ({ item }: IProps) => {
|
const KnowledgeCard = ({ item }: IProps) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const showDeleteConfirm = useShowDeleteConfirm();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const removeKnowledge = () => {
|
const removeKnowledge = async () => {
|
||||||
return dispatch({
|
return dispatch({
|
||||||
type: 'knowledgeModel/rmKb',
|
type: 'knowledgeModel/rmKb',
|
||||||
payload: {
|
payload: {
|
||||||
@ -34,30 +31,6 @@ const KnowledgeCard = ({ item }: IProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = () => {
|
|
||||||
showDeleteConfirm({ onOk: removeKnowledge });
|
|
||||||
};
|
|
||||||
|
|
||||||
const items: MenuProps['items'] = [
|
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
label: (
|
|
||||||
<Space>
|
|
||||||
{t('common.delete')}
|
|
||||||
<DeleteOutlined />
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const handleDropdownMenuClick: MenuProps['onClick'] = ({ domEvent, key }) => {
|
|
||||||
domEvent.preventDefault();
|
|
||||||
domEvent.stopPropagation();
|
|
||||||
if (key === '1') {
|
|
||||||
handleDelete();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCardClick = () => {
|
const handleCardClick = () => {
|
||||||
navigate(`/knowledge/${KnowledgeRouteKey.Dataset}?id=${item.id}`, {
|
navigate(`/knowledge/${KnowledgeRouteKey.Dataset}?id=${item.id}`, {
|
||||||
state: { from: 'list' },
|
state: { from: 'list' },
|
||||||
@ -69,16 +42,7 @@ const KnowledgeCard = ({ item }: IProps) => {
|
|||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<Avatar size={34} icon={<UserOutlined />} src={item.avatar} />
|
<Avatar size={34} icon={<UserOutlined />} src={item.avatar} />
|
||||||
<Dropdown
|
<OperateDropdown deleteItem={removeKnowledge}></OperateDropdown>
|
||||||
menu={{
|
|
||||||
items,
|
|
||||||
onClick: handleDropdownMenuClick,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className={styles.delete}>
|
|
||||||
<MoreIcon />
|
|
||||||
</span>
|
|
||||||
</Dropdown>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.titleWrapper}>
|
<div className={styles.titleWrapper}>
|
||||||
<span className={styles.title}>{item.name}</span>
|
<span className={styles.title}>{item.name}</span>
|
||||||
|
@ -89,5 +89,5 @@ export default {
|
|||||||
removeCanvas: `${api_host}/canvas/rm`,
|
removeCanvas: `${api_host}/canvas/rm`,
|
||||||
setCanvas: `${api_host}/canvas/set`,
|
setCanvas: `${api_host}/canvas/set`,
|
||||||
resetCanvas: `${api_host}/canvas/reset`,
|
resetCanvas: `${api_host}/canvas/reset`,
|
||||||
runCanvas: `${api_host}/canvas/run`,
|
runCanvas: `${api_host}/canvas/completion`,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user