diff --git a/web/src/assets/svg/paper-clip.svg b/web/src/assets/svg/paper-clip.svg new file mode 100644 index 000000000..d3fdc540b --- /dev/null +++ b/web/src/assets/svg/paper-clip.svg @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/web/src/components/api-service/chat-overview-modal/index.tsx b/web/src/components/api-service/chat-overview-modal/index.tsx index e14a53c01..44d271721 100644 --- a/web/src/components/api-service/chat-overview-modal/index.tsx +++ b/web/src/components/api-service/chat-overview-modal/index.tsx @@ -50,13 +50,8 @@ const ChatOverviewModal = ({ hideModal: hideApiKeyModal, showModal: showApiKeyModal, } = useSetModalState(); - const { - embedVisible, - hideEmbedModal, - showEmbedModal, - embedToken, - errorContextHolder, - } = useShowEmbedModal(id, idKey); + const { embedVisible, hideEmbedModal, showEmbedModal, embedToken } = + useShowEmbedModal(id, idKey); const { pickerValue, setPickerValue } = useFetchNextStats(); @@ -64,7 +59,7 @@ const ChatOverviewModal = ({ return current && current > dayjs().endOf('day'); }; - const { handlePreview, contextHolder } = usePreviewChat(id, idKey); + const { handlePreview } = usePreviewChat(id, idKey); return ( <> @@ -138,8 +133,6 @@ const ChatOverviewModal = ({ visible={embedVisible} hideModal={hideEmbedModal} > - {contextHolder} - {errorContextHolder} ); diff --git a/web/src/components/api-service/hooks.ts b/web/src/components/api-service/hooks.ts index d93eab2db..2435f99f0 100644 --- a/web/src/components/api-service/hooks.ts +++ b/web/src/components/api-service/hooks.ts @@ -63,13 +63,12 @@ export const useSelectChartStatsList = (): ChartStatsType => { }; export const useShowTokenEmptyError = () => { - const [messageApi, contextHolder] = message.useMessage(); const { t } = useTranslate('chat'); const showTokenEmptyError = useCallback(() => { - messageApi.error(t('tokenError')); - }, [messageApi, t]); - return { showTokenEmptyError, contextHolder }; + message.error(t('tokenError')); + }, [t]); + return { showTokenEmptyError }; }; const getUrlWithToken = (token: string) => { @@ -78,7 +77,7 @@ const getUrlWithToken = (token: string) => { }; const useFetchTokenListBeforeOtherStep = (dialogId: string, idKey: string) => { - const { showTokenEmptyError, contextHolder } = useShowTokenEmptyError(); + const { showTokenEmptyError } = useShowTokenEmptyError(); const { data: tokenList, refetch } = useFetchTokenList({ [idKey]: dialogId }); @@ -98,7 +97,6 @@ const useFetchTokenListBeforeOtherStep = (dialogId: string, idKey: string) => { return { token, - contextHolder, handleOperate, }; }; @@ -110,8 +108,10 @@ export const useShowEmbedModal = (dialogId: string, idKey: string) => { showModal: showEmbedModal, } = useSetModalState(); - const { handleOperate, token, contextHolder } = - useFetchTokenListBeforeOtherStep(dialogId, idKey); + const { handleOperate, token } = useFetchTokenListBeforeOtherStep( + dialogId, + idKey, + ); const handleShowEmbedModal = useCallback(async () => { const succeed = await handleOperate(); @@ -125,15 +125,11 @@ export const useShowEmbedModal = (dialogId: string, idKey: string) => { hideEmbedModal, embedVisible, embedToken: token, - errorContextHolder: contextHolder, }; }; export const usePreviewChat = (dialogId: string, idKey: string) => { - const { handleOperate, contextHolder } = useFetchTokenListBeforeOtherStep( - dialogId, - idKey, - ); + const { handleOperate } = useFetchTokenListBeforeOtherStep(dialogId, idKey); const open = useCallback((t: string) => { window.open(getUrlWithToken(t), '_blank'); @@ -148,6 +144,5 @@ export const usePreviewChat = (dialogId: string, idKey: string) => { return { handlePreview, - contextHolder, }; }; diff --git a/web/src/components/message-input/index.less b/web/src/components/message-input/index.less index 5b203d69e..c4648dfca 100644 --- a/web/src/components/message-input/index.less +++ b/web/src/components/message-input/index.less @@ -1,11 +1,23 @@ .messageInputWrapper { margin-right: 20px; + background-color: #f5f5f8; + border-radius: 8px; + :global(.ant-input-affix-wrapper) { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + } .documentCard { :global(.ant-card-body) { padding: 10px; position: relative; } } + .listWrapper { + padding: 0 10px; + } + .inputWrapper { + border-radius: 8px; + } .deleteIcon { position: absolute; right: -4px; diff --git a/web/src/components/message-input/index.tsx b/web/src/components/message-input/index.tsx index 2b86c50fa..61a762c47 100644 --- a/web/src/components/message-input/index.tsx +++ b/web/src/components/message-input/index.tsx @@ -1,14 +1,13 @@ import { Authorization } from '@/constants/authorization'; import { useTranslate } from '@/hooks/common-hooks'; -import { useRemoveNextDocument } from '@/hooks/document-hooks'; +import { + useFetchDocumentInfosByIds, + useRemoveNextDocument, +} from '@/hooks/document-hooks'; import { getAuthorization } from '@/utils/authorization-util'; import { getExtension } from '@/utils/document-util'; -import { - CloseCircleOutlined, - LoadingOutlined, - PlusOutlined, - UploadOutlined, -} from '@ant-design/icons'; +import { formatBytes } from '@/utils/file-util'; +import { CloseCircleOutlined, LoadingOutlined } from '@ant-design/icons'; import type { GetProp, UploadFile } from 'antd'; import { Button, @@ -22,10 +21,11 @@ import { Upload, UploadProps, } from 'antd'; +import classNames from 'classnames'; import get from 'lodash/get'; -import { ChangeEventHandler, useCallback, useState } from 'react'; +import { ChangeEventHandler, useCallback, useEffect, useState } from 'react'; import FileIcon from '../file-icon'; - +import SvgIcon from '../svg-icon'; import styles from './index.less'; type FileType = Parameters>[0]; @@ -33,6 +33,14 @@ const { Text } = Typography; const getFileId = (file: UploadFile) => get(file, 'response.data.0'); +const getFileIds = (fileList: UploadFile[]) => { + const ids = fileList.reduce((pre, cur) => { + return pre.concat(get(cur, 'response.data', [])); + }, []); + + return ids; +}; + interface IProps { disabled: boolean; value: string; @@ -41,6 +49,7 @@ interface IProps { onPressEnter(documentIds: string[]): void; onInputChange: ChangeEventHandler; conversationId: string; + uploadUrl?: string; } const getBase64 = (file: FileType): Promise => @@ -59,9 +68,11 @@ const MessageInput = ({ sendLoading, onInputChange, conversationId, + uploadUrl = '/v1/document/upload_and_parse', }: IProps) => { const { t } = useTranslate('chat'); const { removeDocument } = useRemoveNextDocument(); + const { data: documentInfos, setDocumentIds } = useFetchDocumentInfosByIds(); const [fileList, setFileList] = useState([]); @@ -78,9 +89,7 @@ const MessageInput = ({ const handlePressEnter = useCallback(async () => { if (isUploadingFile) return; - const ids = fileList.reduce((pre, cur) => { - return pre.concat(get(cur, 'response.data', [])); - }, []); + const ids = getFileIds(fileList); onPressEnter(ids); setFileList([]); @@ -99,13 +108,18 @@ const MessageInput = ({ [removeDocument], ); - const uploadButton = ( - + const getDocumentInfoById = useCallback( + (id: string) => { + return documentInfos.find((x) => x.id === id); + }, + [documentInfos], ); + useEffect(() => { + const ids = getFileIds(fileList); + setDocumentIds(ids); + }, [fileList, setDocumentIds]); + return ( - - - + {conversationId && ( + + + + )} - } + disabled={false} + sendDisabled={sendDisabled} + conversationId={conversationId} + onInputChange={handleInputChange} onPressEnter={handlePressEnter} - onChange={handleInputChange} - /> + sendLoading={sendLoading} + uploadUrl="/v1/api/document/upload_and_parse" + > ); diff --git a/web/src/utils/file-util.ts b/web/src/utils/file-util.ts index 3ec01f3ff..8a61217bf 100644 --- a/web/src/utils/file-util.ts +++ b/web/src/utils/file-util.ts @@ -85,3 +85,16 @@ export const downloadFile = ({ downloadElement.click(); document.body.removeChild(downloadElement); }; + +const Units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + +export const formatBytes = (x: string | number) => { + let l = 0, + n = (typeof x === 'string' ? parseInt(x, 10) : x) || 0; + + while (n >= 1024 && ++l) { + n = n / 1024; + } + + return n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + Units[l]; +};