fix: new message appears in wrong chat window. #1289 (#1571)

### What problem does this PR solve?
fix: new message appears in wrong chat window. #1289

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
balibabu 2024-07-17 17:08:24 +08:00 committed by GitHub
parent 4df75ca84e
commit 06fd35d420
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 639 additions and 627 deletions

View File

@ -214,7 +214,7 @@ export const useSendMessageWithSse = (
[url], [url],
); );
return { send, answer, done }; return { send, answer, done, setDone };
}; };
//#region chat hooks //#region chat hooks

View File

@ -8,7 +8,7 @@ import { useCallback, useMemo } from 'react';
import { useLocation } from 'umi'; import { useLocation } from 'umi';
import Toolbar from '../right-toolbar'; import Toolbar from '../right-toolbar';
import { useFetchAppConf } from '@/hooks/logicHooks'; import { useFetchAppConf } from '@/hooks/logic-hooks';
import { MessageOutlined } from '@ant-design/icons'; import { MessageOutlined } from '@ant-design/icons';
import styles from './index.less'; import styles from './index.less';

View File

@ -6,7 +6,7 @@ import React from 'react';
import User from '../user'; import User from '../user';
import { LanguageList } from '@/constants/common'; import { LanguageList } from '@/constants/common';
import { useChangeLanguage } from '@/hooks/logicHooks'; import { useChangeLanguage } from '@/hooks/logic-hooks';
import { useSelector } from 'umi'; import { useSelector } from 'umi';
import styled from './index.less'; import styled from './index.less';

View File

@ -15,7 +15,7 @@ import {
import { import {
useChangeDocumentParser, useChangeDocumentParser,
useSetSelectedRecord, useSetSelectedRecord,
} from '@/hooks/logicHooks'; } from '@/hooks/logic-hooks';
import { useFetchTenantInfo } from '@/hooks/userSettingHook'; import { useFetchTenantInfo } from '@/hooks/userSettingHook';
import { IKnowledgeFile } from '@/interfaces/database/knowledge'; import { IKnowledgeFile } from '@/interfaces/database/knowledge';
import { getExtension, isFileUploadDone } from '@/utils/documentUtils'; import { getExtension, isFileUploadDone } from '@/utils/documentUtils';

View File

@ -1,233 +1,234 @@
import ChunkMethodModal from '@/components/chunk-method-modal'; import ChunkMethodModal from '@/components/chunk-method-modal';
import SvgIcon from '@/components/svg-icon'; import SvgIcon from '@/components/svg-icon';
import { import {
useSelectDocumentList, useSelectDocumentList,
useSetDocumentStatus, useSetDocumentStatus,
} from '@/hooks/documentHooks'; } from '@/hooks/documentHooks';
import { useSetSelectedRecord } from '@/hooks/logicHooks'; import { useSetSelectedRecord } from '@/hooks/logic-hooks';
import { useSelectParserList } from '@/hooks/userSettingHook'; import { useSelectParserList } from '@/hooks/userSettingHook';
import { IKnowledgeFile } from '@/interfaces/database/knowledge'; import { IKnowledgeFile } from '@/interfaces/database/knowledge';
import { getExtension } from '@/utils/documentUtils'; import { getExtension } from '@/utils/documentUtils';
import { Divider, Flex, Switch, Table, Typography } from 'antd'; import { Divider, Flex, Switch, Table, Typography } from 'antd';
import type { ColumnsType } from 'antd/es/table'; import type { ColumnsType } from 'antd/es/table';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import CreateFileModal from './create-file-modal'; import CreateFileModal from './create-file-modal';
import WebCrawlModal from './web-crawl-modal'; import DocumentToolbar from './document-toolbar';
import DocumentToolbar from './document-toolbar'; import {
import { useChangeDocumentParser,
useChangeDocumentParser, useCreateEmptyDocument,
useCreateEmptyDocument, useFetchDocumentListOnMount,
useFetchDocumentListOnMount, useGetPagination,
useGetPagination, useGetRowSelection,
useGetRowSelection, useHandleUploadDocument,
useHandleUploadDocument, useHandleWebCrawl, useHandleWebCrawl,
useNavigateToOtherPage, useNavigateToOtherPage,
useRenameDocument, useRenameDocument,
} from './hooks'; } from './hooks';
import ParsingActionCell from './parsing-action-cell'; import ParsingActionCell from './parsing-action-cell';
import ParsingStatusCell from './parsing-status-cell'; import ParsingStatusCell from './parsing-status-cell';
import RenameModal from './rename-modal'; import RenameModal from './rename-modal';
import WebCrawlModal from './web-crawl-modal';
import FileUploadModal from '@/components/file-upload-modal';
import { formatDate } from '@/utils/date'; import FileUploadModal from '@/components/file-upload-modal';
import styles from './index.less'; import { formatDate } from '@/utils/date';
import styles from './index.less';
const { Text } = Typography;
const { Text } = Typography;
const KnowledgeFile = () => {
const data = useSelectDocumentList(); const KnowledgeFile = () => {
const { fetchDocumentList } = useFetchDocumentListOnMount(); const data = useSelectDocumentList();
const parserList = useSelectParserList(); const { fetchDocumentList } = useFetchDocumentListOnMount();
const { pagination } = useGetPagination(fetchDocumentList); const parserList = useSelectParserList();
const onChangeStatus = useSetDocumentStatus(); const { pagination } = useGetPagination(fetchDocumentList);
const { toChunk } = useNavigateToOtherPage(); const onChangeStatus = useSetDocumentStatus();
const { currentRecord, setRecord } = useSetSelectedRecord(); const { toChunk } = useNavigateToOtherPage();
const { const { currentRecord, setRecord } = useSetSelectedRecord();
renameLoading, const {
onRenameOk, renameLoading,
renameVisible, onRenameOk,
hideRenameModal, renameVisible,
showRenameModal, hideRenameModal,
} = useRenameDocument(currentRecord.id); showRenameModal,
const { } = useRenameDocument(currentRecord.id);
createLoading, const {
onCreateOk, createLoading,
createVisible, onCreateOk,
hideCreateModal, createVisible,
showCreateModal, hideCreateModal,
} = useCreateEmptyDocument(); showCreateModal,
const { } = useCreateEmptyDocument();
changeParserLoading, const {
onChangeParserOk, changeParserLoading,
changeParserVisible, onChangeParserOk,
hideChangeParserModal, changeParserVisible,
showChangeParserModal, hideChangeParserModal,
} = useChangeDocumentParser(currentRecord.id); showChangeParserModal,
const { } = useChangeDocumentParser(currentRecord.id);
documentUploadVisible, const {
hideDocumentUploadModal, documentUploadVisible,
showDocumentUploadModal, hideDocumentUploadModal,
onDocumentUploadOk, showDocumentUploadModal,
documentUploadLoading, onDocumentUploadOk,
} = useHandleUploadDocument(); documentUploadLoading,
const { } = useHandleUploadDocument();
webCrawlUploadVisible, const {
hideWebCrawlUploadModal, webCrawlUploadVisible,
showWebCrawlUploadModal, hideWebCrawlUploadModal,
onWebCrawlUploadOk, showWebCrawlUploadModal,
webCrawlUploadLoading, onWebCrawlUploadOk,
} = useHandleWebCrawl(); webCrawlUploadLoading,
const { t } = useTranslation('translation', { } = useHandleWebCrawl();
keyPrefix: 'knowledgeDetails', const { t } = useTranslation('translation', {
}); keyPrefix: 'knowledgeDetails',
});
const rowSelection = useGetRowSelection();
const rowSelection = useGetRowSelection();
const columns: ColumnsType<IKnowledgeFile> = [
{ const columns: ColumnsType<IKnowledgeFile> = [
title: t('name'), {
dataIndex: 'name', title: t('name'),
key: 'name', dataIndex: 'name',
fixed: 'left', key: 'name',
render: (text: any, { id, thumbnail, name }) => ( fixed: 'left',
<div className={styles.toChunks} onClick={() => toChunk(id)}> render: (text: any, { id, thumbnail, name }) => (
<Flex gap={10} align="center"> <div className={styles.toChunks} onClick={() => toChunk(id)}>
{thumbnail ? ( <Flex gap={10} align="center">
<img className={styles.img} src={thumbnail} alt="" /> {thumbnail ? (
) : ( <img className={styles.img} src={thumbnail} alt="" />
<SvgIcon ) : (
name={`file-icon/${getExtension(name)}`} <SvgIcon
width={24} name={`file-icon/${getExtension(name)}`}
></SvgIcon> width={24}
)} ></SvgIcon>
<Text ellipsis={{ tooltip: text }} className={styles.nameText}> )}
{text} <Text ellipsis={{ tooltip: text }} className={styles.nameText}>
</Text> {text}
</Flex> </Text>
</div> </Flex>
), </div>
}, ),
{ },
title: t('chunkNumber'), {
dataIndex: 'chunk_num', title: t('chunkNumber'),
key: 'chunk_num', dataIndex: 'chunk_num',
}, key: 'chunk_num',
{ },
title: t('uploadDate'), {
dataIndex: 'create_time', title: t('uploadDate'),
key: 'create_time', dataIndex: 'create_time',
render(value) { key: 'create_time',
return formatDate(value); render(value) {
}, return formatDate(value);
}, },
{ },
title: t('chunkMethod'), {
dataIndex: 'parser_id', title: t('chunkMethod'),
key: 'parser_id', dataIndex: 'parser_id',
render: (text) => { key: 'parser_id',
return parserList.find((x) => x.value === text)?.label; render: (text) => {
}, return parserList.find((x) => x.value === text)?.label;
}, },
{ },
title: t('enabled'), {
key: 'status', title: t('enabled'),
dataIndex: 'status', key: 'status',
render: (_, { status, id }) => ( dataIndex: 'status',
<> render: (_, { status, id }) => (
<Switch <>
checked={status === '1'} <Switch
onChange={(e) => { checked={status === '1'}
onChangeStatus(e, id); onChange={(e) => {
}} onChangeStatus(e, id);
/> }}
</> />
), </>
}, ),
{ },
title: t('parsingStatus'), {
dataIndex: 'run', title: t('parsingStatus'),
key: 'run', dataIndex: 'run',
render: (text, record) => { key: 'run',
return <ParsingStatusCell record={record}></ParsingStatusCell>; render: (text, record) => {
}, return <ParsingStatusCell record={record}></ParsingStatusCell>;
}, },
{ },
title: t('action'), {
key: 'action', title: t('action'),
render: (_, record) => ( key: 'action',
<ParsingActionCell render: (_, record) => (
setCurrentRecord={setRecord} <ParsingActionCell
showRenameModal={showRenameModal} setCurrentRecord={setRecord}
showChangeParserModal={showChangeParserModal} showRenameModal={showRenameModal}
record={record} showChangeParserModal={showChangeParserModal}
></ParsingActionCell> record={record}
), ></ParsingActionCell>
}, ),
]; },
];
const finalColumns = columns.map((x) => ({
...x, const finalColumns = columns.map((x) => ({
className: `${styles.column}`, ...x,
})); className: `${styles.column}`,
}));
return (
<div className={styles.datasetWrapper}> return (
<h3>{t('dataset')}</h3> <div className={styles.datasetWrapper}>
<p>{t('datasetDescription')}</p> <h3>{t('dataset')}</h3>
<Divider></Divider> <p>{t('datasetDescription')}</p>
<DocumentToolbar <Divider></Divider>
selectedRowKeys={rowSelection.selectedRowKeys as string[]} <DocumentToolbar
showCreateModal={showCreateModal} selectedRowKeys={rowSelection.selectedRowKeys as string[]}
showWebCrawlModal={showWebCrawlUploadModal} showCreateModal={showCreateModal}
showDocumentUploadModal={showDocumentUploadModal} showWebCrawlModal={showWebCrawlUploadModal}
></DocumentToolbar> showDocumentUploadModal={showDocumentUploadModal}
<Table ></DocumentToolbar>
rowKey="id" <Table
columns={finalColumns} rowKey="id"
dataSource={data} columns={finalColumns}
// loading={loading} dataSource={data}
pagination={pagination} // loading={loading}
rowSelection={rowSelection} pagination={pagination}
className={styles.documentTable} rowSelection={rowSelection}
scroll={{ scrollToFirstRowOnChange: true, x: 1300 }} className={styles.documentTable}
/> scroll={{ scrollToFirstRowOnChange: true, x: 1300 }}
<CreateFileModal />
visible={createVisible} <CreateFileModal
hideModal={hideCreateModal} visible={createVisible}
loading={createLoading} hideModal={hideCreateModal}
onOk={onCreateOk} loading={createLoading}
/> onOk={onCreateOk}
<ChunkMethodModal />
documentId={currentRecord.id} <ChunkMethodModal
parserId={currentRecord.parser_id} documentId={currentRecord.id}
parserConfig={currentRecord.parser_config} parserId={currentRecord.parser_id}
documentExtension={getExtension(currentRecord.name)} parserConfig={currentRecord.parser_config}
onOk={onChangeParserOk} documentExtension={getExtension(currentRecord.name)}
visible={changeParserVisible} onOk={onChangeParserOk}
hideModal={hideChangeParserModal} visible={changeParserVisible}
loading={changeParserLoading} hideModal={hideChangeParserModal}
/> loading={changeParserLoading}
<RenameModal />
visible={renameVisible} <RenameModal
onOk={onRenameOk} visible={renameVisible}
loading={renameLoading} onOk={onRenameOk}
hideModal={hideRenameModal} loading={renameLoading}
initialName={currentRecord.name} hideModal={hideRenameModal}
></RenameModal> initialName={currentRecord.name}
<FileUploadModal ></RenameModal>
visible={documentUploadVisible} <FileUploadModal
hideModal={hideDocumentUploadModal} visible={documentUploadVisible}
loading={documentUploadLoading} hideModal={hideDocumentUploadModal}
onOk={onDocumentUploadOk} loading={documentUploadLoading}
></FileUploadModal> onOk={onDocumentUploadOk}
<WebCrawlModal ></FileUploadModal>
visible={webCrawlUploadVisible} <WebCrawlModal
hideModal={hideWebCrawlUploadModal} visible={webCrawlUploadVisible}
loading={webCrawlUploadLoading} hideModal={hideWebCrawlUploadModal}
onOk={onWebCrawlUploadOk} loading={webCrawlUploadLoading}
></WebCrawlModal> onOk={onWebCrawlUploadOk}
</div> ></WebCrawlModal>
); </div>
}; );
};
export default KnowledgeFile;
export default KnowledgeFile;

View File

@ -15,7 +15,10 @@ import ModelSetting from './model-setting';
import PromptEngine from './prompt-engine'; import PromptEngine from './prompt-engine';
import { useTranslate } from '@/hooks/commonHooks'; import { useTranslate } from '@/hooks/commonHooks';
import { useFetchLlmModelOnVisible, useFetchModelId } from '@/hooks/logicHooks'; import {
useFetchLlmModelOnVisible,
useFetchModelId,
} from '@/hooks/logic-hooks';
import { getBase64FromUploadFileList } from '@/utils/fileUtil'; import { getBase64FromUploadFileList } from '@/utils/fileUtil';
import { removeUselessFieldsFromValues } from '@/utils/form'; import { removeUselessFieldsFromValues } from '@/utils/form';
import styles from './index.less'; import styles from './index.less';

View File

@ -23,7 +23,7 @@ import {
useShowDeleteConfirm, useShowDeleteConfirm,
useTranslate, useTranslate,
} from '@/hooks/commonHooks'; } from '@/hooks/commonHooks';
import { useSendMessageWithSse } from '@/hooks/logicHooks'; import { useSendMessageWithSse } from '@/hooks/logic-hooks';
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
import { import {
IAnswer, IAnswer,
@ -552,7 +552,7 @@ export const useSendMessage = (
const { handleInputChange, value, setValue } = useHandleMessageInputChange(); const { handleInputChange, value, setValue } = useHandleMessageInputChange();
const { handleClickConversation } = useClickConversationCard(); const { handleClickConversation } = useClickConversationCard();
const { send, answer, done } = useSendMessageWithSse(); const { send, answer, done, setDone } = useSendMessageWithSse();
const sendMessage = useCallback( const sendMessage = useCallback(
async (message: string, id?: string) => { async (message: string, id?: string) => {
@ -609,11 +609,19 @@ export const useSendMessage = (
); );
useEffect(() => { useEffect(() => {
// #1289
if (answer.answer && answer?.conversationId === conversationId) { if (answer.answer && answer?.conversationId === conversationId) {
addNewestAnswer(answer); addNewestAnswer(answer);
} }
}, [answer, addNewestAnswer, conversationId]); }, [answer, addNewestAnswer, conversationId]);
useEffect(() => {
// #1289 switch to another conversion window when the last conversion answer doesn't finish.
if (conversationId) {
setDone(true);
}
}, [setDone, conversationId]);
const handlePressEnter = useCallback(() => { const handlePressEnter = useCallback(() => {
if (trim(value) === '') return; if (trim(value) === '') return;

View File

@ -1,381 +1,381 @@
import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg'; import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg';
import RenameModal from '@/components/rename-modal'; import RenameModal from '@/components/rename-modal';
import { import {
CloudOutlined, CloudOutlined,
DeleteOutlined, DeleteOutlined,
EditOutlined, EditOutlined,
PlusOutlined, PlusOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { import {
Avatar, Avatar,
Button, Button,
Card, Card,
Divider, Divider,
Dropdown, Dropdown,
Flex, Flex,
MenuProps, MenuProps,
Space, Space,
Spin, Spin,
Tag, Tag,
Typography, Typography,
} from 'antd'; } from 'antd';
import { MenuItemProps } from 'antd/lib/menu/MenuItem'; import { MenuItemProps } from 'antd/lib/menu/MenuItem';
import classNames from 'classnames'; import classNames from 'classnames';
import { useCallback } from 'react'; import { useCallback } from 'react';
import ChatConfigurationModal from './chat-configuration-modal'; import ChatConfigurationModal from './chat-configuration-modal';
import ChatContainer from './chat-container'; import ChatContainer from './chat-container';
import { import {
useClickConversationCard, useClickConversationCard,
useClickDialogCard, useClickDialogCard,
useDeleteConversation, useDeleteConversation,
useDeleteDialog, useDeleteDialog,
useEditDialog, useEditDialog,
useFetchConversationListOnMount, useFetchConversationListOnMount,
useFetchDialogOnMount, useFetchDialogOnMount,
useGetChatSearchParams, useGetChatSearchParams,
useHandleItemHover, useHandleItemHover,
useRenameConversation, useRenameConversation,
useSelectConversationListLoading, useSelectConversationListLoading,
useSelectDerivedConversationList, useSelectDerivedConversationList,
useSelectDialogListLoading, useSelectDialogListLoading,
useSelectFirstDialogOnMount, useSelectFirstDialogOnMount,
} from './hooks'; } from './hooks';
import { useSetModalState, useTranslate } from '@/hooks/commonHooks'; import { useSetModalState, useTranslate } from '@/hooks/commonHooks';
import { useSetSelectedRecord } from '@/hooks/logicHooks'; import { useSetSelectedRecord } from '@/hooks/logic-hooks';
import { IDialog } from '@/interfaces/database/chat'; import { IDialog } from '@/interfaces/database/chat';
import ChatOverviewModal from './chat-overview-modal'; import ChatOverviewModal from './chat-overview-modal';
import styles from './index.less'; import styles from './index.less';
const { Text } = Typography; const { Text } = Typography;
const Chat = () => { const Chat = () => {
const dialogList = useSelectFirstDialogOnMount(); const dialogList = useSelectFirstDialogOnMount();
const { onRemoveDialog } = useDeleteDialog(); const { onRemoveDialog } = useDeleteDialog();
const { onRemoveConversation } = useDeleteConversation(); const { onRemoveConversation } = useDeleteConversation();
const { handleClickDialog } = useClickDialogCard(); const { handleClickDialog } = useClickDialogCard();
const { handleClickConversation } = useClickConversationCard(); const { handleClickConversation } = useClickConversationCard();
const { dialogId, conversationId } = useGetChatSearchParams(); const { dialogId, conversationId } = useGetChatSearchParams();
const { list: conversationList, addTemporaryConversation } = const { list: conversationList, addTemporaryConversation } =
useSelectDerivedConversationList(); useSelectDerivedConversationList();
const { activated, handleItemEnter, handleItemLeave } = useHandleItemHover(); const { activated, handleItemEnter, handleItemLeave } = useHandleItemHover();
const { const {
activated: conversationActivated, activated: conversationActivated,
handleItemEnter: handleConversationItemEnter, handleItemEnter: handleConversationItemEnter,
handleItemLeave: handleConversationItemLeave, handleItemLeave: handleConversationItemLeave,
} = useHandleItemHover(); } = useHandleItemHover();
const { const {
conversationRenameLoading, conversationRenameLoading,
initialConversationName, initialConversationName,
onConversationRenameOk, onConversationRenameOk,
conversationRenameVisible, conversationRenameVisible,
hideConversationRenameModal, hideConversationRenameModal,
showConversationRenameModal, showConversationRenameModal,
} = useRenameConversation(); } = useRenameConversation();
const { const {
dialogSettingLoading, dialogSettingLoading,
initialDialog, initialDialog,
onDialogEditOk, onDialogEditOk,
dialogEditVisible, dialogEditVisible,
clearDialog, clearDialog,
hideDialogEditModal, hideDialogEditModal,
showDialogEditModal, showDialogEditModal,
} = useEditDialog(); } = useEditDialog();
const dialogLoading = useSelectDialogListLoading(); const dialogLoading = useSelectDialogListLoading();
const conversationLoading = useSelectConversationListLoading(); const conversationLoading = useSelectConversationListLoading();
const { t } = useTranslate('chat'); const { t } = useTranslate('chat');
const { const {
visible: overviewVisible, visible: overviewVisible,
hideModal: hideOverviewModal, hideModal: hideOverviewModal,
showModal: showOverviewModal, showModal: showOverviewModal,
} = useSetModalState(); } = useSetModalState();
const { currentRecord, setRecord } = useSetSelectedRecord<IDialog>(); const { currentRecord, setRecord } = useSetSelectedRecord<IDialog>();
useFetchDialogOnMount(dialogId, true); useFetchDialogOnMount(dialogId, true);
const handleAppCardEnter = (id: string) => () => { const handleAppCardEnter = (id: string) => () => {
handleItemEnter(id); handleItemEnter(id);
}; };
const handleConversationCardEnter = (id: string) => () => { const handleConversationCardEnter = (id: string) => () => {
handleConversationItemEnter(id); handleConversationItemEnter(id);
}; };
const handleShowChatConfigurationModal = const handleShowChatConfigurationModal =
(dialogId?: string): any => (dialogId?: string): any =>
(info: any) => { (info: any) => {
info?.domEvent?.preventDefault(); info?.domEvent?.preventDefault();
info?.domEvent?.stopPropagation(); info?.domEvent?.stopPropagation();
showDialogEditModal(dialogId); showDialogEditModal(dialogId);
}; };
const handleRemoveDialog = const handleRemoveDialog =
(dialogId: string): MenuItemProps['onClick'] => (dialogId: string): MenuItemProps['onClick'] =>
({ domEvent }) => { ({ domEvent }) => {
domEvent.preventDefault(); domEvent.preventDefault();
domEvent.stopPropagation(); domEvent.stopPropagation();
onRemoveDialog([dialogId]); onRemoveDialog([dialogId]);
}; };
const handleShowOverviewModal = const handleShowOverviewModal =
(dialog: IDialog): any => (dialog: IDialog): any =>
(info: any) => { (info: any) => {
info?.domEvent?.preventDefault(); info?.domEvent?.preventDefault();
info?.domEvent?.stopPropagation(); info?.domEvent?.stopPropagation();
setRecord(dialog); setRecord(dialog);
showOverviewModal(); showOverviewModal();
}; };
const handleRemoveConversation = const handleRemoveConversation =
(conversationId: string): MenuItemProps['onClick'] => (conversationId: string): MenuItemProps['onClick'] =>
({ domEvent }) => { ({ domEvent }) => {
domEvent.preventDefault(); domEvent.preventDefault();
domEvent.stopPropagation(); domEvent.stopPropagation();
onRemoveConversation([conversationId]); onRemoveConversation([conversationId]);
}; };
const handleShowConversationRenameModal = const handleShowConversationRenameModal =
(conversationId: string): MenuItemProps['onClick'] => (conversationId: string): MenuItemProps['onClick'] =>
({ domEvent }) => { ({ domEvent }) => {
domEvent.preventDefault(); domEvent.preventDefault();
domEvent.stopPropagation(); domEvent.stopPropagation();
showConversationRenameModal(conversationId); showConversationRenameModal(conversationId);
}; };
const handleDialogCardClick = (dialogId: string) => () => { const handleDialogCardClick = (dialogId: string) => () => {
handleClickDialog(dialogId); handleClickDialog(dialogId);
}; };
const handleConversationCardClick = (dialogId: string) => () => { const handleConversationCardClick = (dialogId: string) => () => {
handleClickConversation(dialogId); handleClickConversation(dialogId);
}; };
const handleCreateTemporaryConversation = useCallback(() => { const handleCreateTemporaryConversation = useCallback(() => {
addTemporaryConversation(); addTemporaryConversation();
}, [addTemporaryConversation]); }, [addTemporaryConversation]);
const items: MenuProps['items'] = [ const items: MenuProps['items'] = [
{ {
key: '1', key: '1',
onClick: handleCreateTemporaryConversation, onClick: handleCreateTemporaryConversation,
label: ( label: (
<Space> <Space>
<PlusOutlined /> <PlusOutlined />
{t('newChat')} {t('newChat')}
</Space> </Space>
), ),
}, },
]; ];
const buildAppItems = (dialog: IDialog) => { const buildAppItems = (dialog: IDialog) => {
const dialogId = dialog.id; const dialogId = dialog.id;
const appItems: MenuProps['items'] = [ const appItems: MenuProps['items'] = [
{ {
key: '1', key: '1',
onClick: handleShowChatConfigurationModal(dialogId), onClick: handleShowChatConfigurationModal(dialogId),
label: ( label: (
<Space> <Space>
<EditOutlined /> <EditOutlined />
{t('edit', { keyPrefix: 'common' })} {t('edit', { keyPrefix: 'common' })}
</Space> </Space>
), ),
}, },
{ type: 'divider' }, { type: 'divider' },
{ {
key: '2', key: '2',
onClick: handleRemoveDialog(dialogId), onClick: handleRemoveDialog(dialogId),
label: ( label: (
<Space> <Space>
<DeleteOutlined /> <DeleteOutlined />
{t('delete', { keyPrefix: 'common' })} {t('delete', { keyPrefix: 'common' })}
</Space> </Space>
), ),
}, },
{ type: 'divider' }, { type: 'divider' },
{ {
key: '3', key: '3',
onClick: handleShowOverviewModal(dialog), onClick: handleShowOverviewModal(dialog),
label: ( label: (
<Space> <Space>
<CloudOutlined /> <CloudOutlined />
{t('overview')} {t('overview')}
</Space> </Space>
), ),
}, },
]; ];
return appItems; return appItems;
}; };
const buildConversationItems = (conversationId: string) => { const buildConversationItems = (conversationId: string) => {
const appItems: MenuProps['items'] = [ const appItems: MenuProps['items'] = [
{ {
key: '1', key: '1',
onClick: handleShowConversationRenameModal(conversationId), onClick: handleShowConversationRenameModal(conversationId),
label: ( label: (
<Space> <Space>
<EditOutlined /> <EditOutlined />
{t('rename', { keyPrefix: 'common' })} {t('rename', { keyPrefix: 'common' })}
</Space> </Space>
), ),
}, },
{ type: 'divider' }, { type: 'divider' },
{ {
key: '2', key: '2',
onClick: handleRemoveConversation(conversationId), onClick: handleRemoveConversation(conversationId),
label: ( label: (
<Space> <Space>
<DeleteOutlined /> <DeleteOutlined />
{t('delete', { keyPrefix: 'common' })} {t('delete', { keyPrefix: 'common' })}
</Space> </Space>
), ),
}, },
]; ];
return appItems; return appItems;
}; };
useFetchConversationListOnMount(); useFetchConversationListOnMount();
return ( return (
<Flex className={styles.chatWrapper}> <Flex className={styles.chatWrapper}>
<Flex className={styles.chatAppWrapper}> <Flex className={styles.chatAppWrapper}>
<Flex flex={1} vertical> <Flex flex={1} vertical>
<Button type="primary" onClick={handleShowChatConfigurationModal()}> <Button type="primary" onClick={handleShowChatConfigurationModal()}>
{t('createAssistant')} {t('createAssistant')}
</Button> </Button>
<Divider></Divider> <Divider></Divider>
<Flex className={styles.chatAppContent} vertical gap={10}> <Flex className={styles.chatAppContent} vertical gap={10}>
<Spin spinning={dialogLoading} wrapperClassName={styles.chatSpin}> <Spin spinning={dialogLoading} wrapperClassName={styles.chatSpin}>
{dialogList.map((x) => ( {dialogList.map((x) => (
<Card <Card
key={x.id} key={x.id}
hoverable hoverable
className={classNames(styles.chatAppCard, { className={classNames(styles.chatAppCard, {
[styles.chatAppCardSelected]: dialogId === x.id, [styles.chatAppCardSelected]: dialogId === x.id,
})} })}
onMouseEnter={handleAppCardEnter(x.id)} onMouseEnter={handleAppCardEnter(x.id)}
onMouseLeave={handleItemLeave} onMouseLeave={handleItemLeave}
onClick={handleDialogCardClick(x.id)} onClick={handleDialogCardClick(x.id)}
> >
<Flex justify="space-between" align="center"> <Flex justify="space-between" align="center">
<Space size={15}> <Space size={15}>
<Avatar src={x.icon} shape={'square'} /> <Avatar src={x.icon} shape={'square'} />
<section> <section>
<b> <b>
<Text <Text
ellipsis={{ tooltip: x.name }} ellipsis={{ tooltip: x.name }}
style={{ width: 130 }} style={{ width: 130 }}
> >
{x.name} {x.name}
</Text> </Text>
</b> </b>
<div>{x.description}</div> <div>{x.description}</div>
</section> </section>
</Space> </Space>
{activated === x.id && ( {activated === x.id && (
<section> <section>
<Dropdown menu={{ items: buildAppItems(x) }}> <Dropdown menu={{ items: buildAppItems(x) }}>
<ChatAppCube <ChatAppCube
className={styles.cubeIcon} className={styles.cubeIcon}
></ChatAppCube> ></ChatAppCube>
</Dropdown> </Dropdown>
</section> </section>
)} )}
</Flex> </Flex>
</Card> </Card>
))} ))}
</Spin> </Spin>
</Flex> </Flex>
</Flex> </Flex>
</Flex> </Flex>
<Divider type={'vertical'} className={styles.divider}></Divider> <Divider type={'vertical'} className={styles.divider}></Divider>
<Flex className={styles.chatTitleWrapper}> <Flex className={styles.chatTitleWrapper}>
<Flex flex={1} vertical> <Flex flex={1} vertical>
<Flex <Flex
justify={'space-between'} justify={'space-between'}
align="center" align="center"
className={styles.chatTitle} className={styles.chatTitle}
> >
<Space> <Space>
<b>{t('chat')}</b> <b>{t('chat')}</b>
<Tag>{conversationList.length}</Tag> <Tag>{conversationList.length}</Tag>
</Space> </Space>
<Dropdown menu={{ items }}> <Dropdown menu={{ items }}>
{/* <FormOutlined /> */} {/* <FormOutlined /> */}
<PlusOutlined /> <PlusOutlined />
</Dropdown> </Dropdown>
</Flex> </Flex>
<Divider></Divider> <Divider></Divider>
<Flex vertical gap={10} className={styles.chatTitleContent}> <Flex vertical gap={10} className={styles.chatTitleContent}>
<Spin <Spin
spinning={conversationLoading} spinning={conversationLoading}
wrapperClassName={styles.chatSpin} wrapperClassName={styles.chatSpin}
> >
{conversationList.map((x) => ( {conversationList.map((x) => (
<Card <Card
key={x.id} key={x.id}
hoverable hoverable
onClick={handleConversationCardClick(x.id)} onClick={handleConversationCardClick(x.id)}
onMouseEnter={handleConversationCardEnter(x.id)} onMouseEnter={handleConversationCardEnter(x.id)}
onMouseLeave={handleConversationItemLeave} onMouseLeave={handleConversationItemLeave}
className={classNames(styles.chatTitleCard, { className={classNames(styles.chatTitleCard, {
[styles.chatTitleCardSelected]: x.id === conversationId, [styles.chatTitleCardSelected]: x.id === conversationId,
})} })}
> >
<Flex justify="space-between" align="center"> <Flex justify="space-between" align="center">
<div> <div>
<Text <Text
ellipsis={{ tooltip: x.name }} ellipsis={{ tooltip: x.name }}
style={{ width: 150 }} style={{ width: 150 }}
> >
{x.name} {x.name}
</Text> </Text>
</div> </div>
{conversationActivated === x.id && x.id !== '' && ( {conversationActivated === x.id && x.id !== '' && (
<section> <section>
<Dropdown <Dropdown
menu={{ items: buildConversationItems(x.id) }} menu={{ items: buildConversationItems(x.id) }}
> >
<ChatAppCube <ChatAppCube
className={styles.cubeIcon} className={styles.cubeIcon}
></ChatAppCube> ></ChatAppCube>
</Dropdown> </Dropdown>
</section> </section>
)} )}
</Flex> </Flex>
</Card> </Card>
))} ))}
</Spin> </Spin>
</Flex> </Flex>
</Flex> </Flex>
</Flex> </Flex>
<Divider type={'vertical'} className={styles.divider}></Divider> <Divider type={'vertical'} className={styles.divider}></Divider>
<ChatContainer></ChatContainer> <ChatContainer></ChatContainer>
<ChatConfigurationModal <ChatConfigurationModal
visible={dialogEditVisible} visible={dialogEditVisible}
initialDialog={initialDialog} initialDialog={initialDialog}
showModal={showDialogEditModal} showModal={showDialogEditModal}
hideModal={hideDialogEditModal} hideModal={hideDialogEditModal}
loading={dialogSettingLoading} loading={dialogSettingLoading}
onOk={onDialogEditOk} onOk={onDialogEditOk}
clearDialog={clearDialog} clearDialog={clearDialog}
></ChatConfigurationModal> ></ChatConfigurationModal>
<RenameModal <RenameModal
visible={conversationRenameVisible} visible={conversationRenameVisible}
hideModal={hideConversationRenameModal} hideModal={hideConversationRenameModal}
onOk={onConversationRenameOk} onOk={onConversationRenameOk}
initialName={initialConversationName} initialName={initialConversationName}
loading={conversationRenameLoading} loading={conversationRenameLoading}
></RenameModal> ></RenameModal>
<ChatOverviewModal <ChatOverviewModal
visible={overviewVisible} visible={overviewVisible}
hideModal={hideOverviewModal} hideModal={hideOverviewModal}
dialog={currentRecord} dialog={currentRecord}
></ChatOverviewModal> ></ChatOverviewModal>
</Flex> </Flex>
); );
}; };
export default Chat; export default Chat;

View File

@ -3,7 +3,7 @@ import {
useCreateSharedConversation, useCreateSharedConversation,
useFetchSharedConversation, useFetchSharedConversation,
} from '@/hooks/chatHooks'; } from '@/hooks/chatHooks';
import { useSendMessageWithSse } from '@/hooks/logicHooks'; import { useSendMessageWithSse } from '@/hooks/logic-hooks';
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
import { IAnswer } from '@/interfaces/database/chat'; import { IAnswer } from '@/interfaces/database/chat';
import api from '@/utils/api'; import api from '@/utils/api';

View File

@ -10,7 +10,7 @@ import {
useSelectParentFolderList, useSelectParentFolderList,
useUploadFile, useUploadFile,
} from '@/hooks/fileManagerHooks'; } from '@/hooks/fileManagerHooks';
import { useGetPagination, useSetPagination } from '@/hooks/logicHooks'; import { useGetPagination, useSetPagination } from '@/hooks/logic-hooks';
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
import { IFile } from '@/interfaces/database/file-manager'; import { IFile } from '@/interfaces/database/file-manager';
import { PaginationProps } from 'antd'; import { PaginationProps } from 'antd';

View File

@ -4,7 +4,7 @@ import {
useHandleMessageInputChange, useHandleMessageInputChange,
useScrollToBottom, useScrollToBottom,
useSendMessageWithSse, useSendMessageWithSse,
} from '@/hooks/logicHooks'; } from '@/hooks/logic-hooks';
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 api from '@/utils/api'; import api from '@/utils/api';

View File

@ -18,7 +18,7 @@ import {
ModelVariableType, ModelVariableType,
settledModelVariableMap, settledModelVariableMap,
} from '@/constants/knowledge'; } from '@/constants/knowledge';
import { useFetchModelId, useSendMessageWithSse } from '@/hooks/logicHooks'; import { useFetchModelId, useSendMessageWithSse } from '@/hooks/logic-hooks';
import { Variable } from '@/interfaces/database/chat'; import { Variable } from '@/interfaces/database/chat';
import api from '@/utils/api'; import api from '@/utils/api';
import { useDebounceEffect } from 'ahooks'; import { useDebounceEffect } from 'ahooks';

View File

@ -1,7 +1,7 @@
import { IModalManagerChildrenProps } from '@/components/modal-manager'; import { IModalManagerChildrenProps } from '@/components/modal-manager';
import { useTranslate } from '@/hooks/commonHooks'; import { useTranslate } from '@/hooks/commonHooks';
import { useFetchFlowTemplates } from '@/hooks/flow-hooks'; import { useFetchFlowTemplates } from '@/hooks/flow-hooks';
import { useSelectItem } from '@/hooks/logicHooks'; import { useSelectItem } from '@/hooks/logic-hooks';
import { Card, Flex, Form, Input, Modal, Space, Typography } from 'antd'; import { Card, Flex, Form, Input, Modal, Space, Typography } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { useEffect } from 'react'; import { useEffect } from 'react';

View File

@ -32,7 +32,7 @@ import {
import { LanguageList } from '@/constants/common'; import { LanguageList } from '@/constants/common';
import { useTranslate } from '@/hooks/commonHooks'; import { useTranslate } from '@/hooks/commonHooks';
import { useChangeLanguage } from '@/hooks/logicHooks'; import { useChangeLanguage } from '@/hooks/logic-hooks';
import parentStyles from '../index.less'; import parentStyles from '../index.less';
import styles from './index.less'; import styles from './index.less';