mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
fix: fixed the issue that the prompt word for registering an account is not in English and fixed the issue where the last message would keep loading if the backend reported an error during chat and fixed the issue where the next button would float above the file list on the file upload page (#133)
* feat: fixed the issue where the next button would float above the file list on the file upload page. * feat: fixed the issue where the last message would keep loading if the backend reported an error during chat. * fix: fixed the issue that the prompt word for registering an account is not in English
This commit is contained in:
@ -8,6 +8,7 @@
|
|||||||
}
|
}
|
||||||
.footer {
|
.footer {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
padding-top: 16px;
|
||||||
.nextButton {
|
.nextButton {
|
||||||
background-color: @purple;
|
background-color: @purple;
|
||||||
}
|
}
|
||||||
@ -17,8 +18,9 @@
|
|||||||
padding-top: 60px;
|
padding-top: 60px;
|
||||||
}
|
}
|
||||||
.uploader {
|
.uploader {
|
||||||
display: block;
|
:global(.ant-upload) {
|
||||||
height: 200px;
|
height: 126px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.hiddenUploader {
|
.hiddenUploader {
|
||||||
:global(.ant-upload-drag) {
|
:global(.ant-upload-drag) {
|
||||||
@ -29,6 +31,17 @@
|
|||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
}
|
}
|
||||||
|
.uploaderButton {
|
||||||
|
padding: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.uploaderIcon {
|
||||||
|
svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
.deleteIcon {
|
.deleteIcon {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { ReactComponent as SelectFilesEndIcon } from '@/assets/svg/select-files-end.svg';
|
import { ReactComponent as SelectFilesEndIcon } from '@/assets/svg/select-files-end.svg';
|
||||||
import { ReactComponent as SelectFilesStartIcon } from '@/assets/svg/select-files-start.svg';
|
import { ReactComponent as SelectFilesStartIcon } from '@/assets/svg/select-files-start.svg';
|
||||||
|
import { KnowledgeRouteKey } from '@/constants/knowledge';
|
||||||
import {
|
import {
|
||||||
useDeleteDocumentById,
|
useDeleteDocumentById,
|
||||||
useFetchKnowledgeDetail,
|
useFetchKnowledgeDetail,
|
||||||
@ -10,14 +11,14 @@ import {
|
|||||||
useFetchTenantInfo,
|
useFetchTenantInfo,
|
||||||
useSelectParserList,
|
useSelectParserList,
|
||||||
} from '@/hooks/userSettingHook';
|
} from '@/hooks/userSettingHook';
|
||||||
|
|
||||||
import uploadService from '@/services/uploadService';
|
import uploadService from '@/services/uploadService';
|
||||||
|
import { isFileUploadDone } from '@/utils/documentUtils';
|
||||||
import {
|
import {
|
||||||
ArrowLeftOutlined,
|
ArrowLeftOutlined,
|
||||||
|
CloudUploadOutlined,
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
FileDoneOutlined,
|
FileDoneOutlined,
|
||||||
InboxOutlined,
|
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@ -43,8 +44,6 @@ import {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { Link, useDispatch, useNavigate } from 'umi';
|
import { Link, useDispatch, useNavigate } from 'umi';
|
||||||
|
|
||||||
import { KnowledgeRouteKey } from '@/constants/knowledge';
|
|
||||||
import { isFileUploadDone } from '@/utils/documentUtils';
|
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
const { Dragger } = Upload;
|
const { Dragger } = Upload;
|
||||||
@ -290,9 +289,9 @@ const KnowledgeUploadFile = () => {
|
|||||||
[styles.hiddenUploader]: !isUpload,
|
[styles.hiddenUploader]: !isUpload,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<p className="ant-upload-drag-icon">
|
<Button className={styles.uploaderButton}>
|
||||||
<InboxOutlined />
|
<CloudUploadOutlined className={styles.uploaderIcon} />
|
||||||
</p>
|
</Button>
|
||||||
<p className="ant-upload-text">
|
<p className="ant-upload-text">
|
||||||
Click or drag file to this area to upload
|
Click or drag file to this area to upload
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -27,7 +27,7 @@ const ChunkTitle = ({ item }: { item: ITestingChunk }) => {
|
|||||||
{similarityList.map((x) => (
|
{similarityList.map((x) => (
|
||||||
<Space key={x.field}>
|
<Space key={x.field}>
|
||||||
<span className={styles.similarityCircle}>
|
<span className={styles.similarityCircle}>
|
||||||
{((item[x.field] as number) * 100).toFixed(2)}%
|
{((item[x.field] as number) * 100).toFixed(2)}
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.similarityText}>{x.label}</span>
|
<span className={styles.similarityText}>{x.label}</span>
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import NewDocumentLink from '@/components/new-document-link';
|
|||||||
import DocumentPreviewer from '@/components/pdf-previewer';
|
import DocumentPreviewer from '@/components/pdf-previewer';
|
||||||
import { MessageType } from '@/constants/chat';
|
import { MessageType } from '@/constants/chat';
|
||||||
import { useSelectFileThumbnails } from '@/hooks/knowledgeHook';
|
import { useSelectFileThumbnails } from '@/hooks/knowledgeHook';
|
||||||
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
|
||||||
import { useSelectUserInfo } from '@/hooks/userSettingHook';
|
import { useSelectUserInfo } from '@/hooks/userSettingHook';
|
||||||
import { IReference, Message } from '@/interfaces/database/chat';
|
import { IReference, Message } from '@/interfaces/database/chat';
|
||||||
import { IChunk } from '@/interfaces/database/knowledge';
|
import { IChunk } from '@/interfaces/database/knowledge';
|
||||||
@ -21,7 +20,7 @@ import {
|
|||||||
Space,
|
Space,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { ChangeEventHandler, useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import Markdown from 'react-markdown';
|
import Markdown from 'react-markdown';
|
||||||
import reactStringReplace from 'react-string-replace';
|
import reactStringReplace from 'react-string-replace';
|
||||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||||
@ -243,35 +242,19 @@ const MessageItem = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ChatContainer = () => {
|
const ChatContainer = () => {
|
||||||
const [value, setValue] = useState('');
|
|
||||||
const {
|
const {
|
||||||
ref,
|
ref,
|
||||||
currentConversation: conversation,
|
currentConversation: conversation,
|
||||||
addNewestConversation,
|
addNewestConversation,
|
||||||
|
removeLatestMessage,
|
||||||
} = useFetchConversationOnMount();
|
} = useFetchConversationOnMount();
|
||||||
const { sendMessage } = useSendMessage();
|
const { handleInputChange, handlePressEnter, value, loading } =
|
||||||
|
useSendMessage(conversation, addNewestConversation, removeLatestMessage);
|
||||||
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||||
useClickDrawer();
|
useClickDrawer();
|
||||||
|
|
||||||
const loading = useOneNamespaceEffectsLoading('chatModel', [
|
|
||||||
'completeConversation',
|
|
||||||
]);
|
|
||||||
useGetFileIcon();
|
useGetFileIcon();
|
||||||
|
|
||||||
const handlePressEnter = () => {
|
|
||||||
if (!loading) {
|
|
||||||
setValue('');
|
|
||||||
addNewestConversation(value);
|
|
||||||
sendMessage(value.trim());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInputChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
|
||||||
const value = e.target.value;
|
|
||||||
const nextValue = value.replaceAll('\\n', '\n').replaceAll('\\t', '\t');
|
|
||||||
setValue(nextValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Flex flex={1} className={styles.chatContainer} vertical>
|
<Flex flex={1} className={styles.chatContainer} vertical>
|
||||||
|
|||||||
@ -7,7 +7,14 @@ import { IConversation, IDialog } from '@/interfaces/database/chat';
|
|||||||
import { IChunk } from '@/interfaces/database/knowledge';
|
import { IChunk } from '@/interfaces/database/knowledge';
|
||||||
import { getFileExtension } from '@/utils';
|
import { getFileExtension } from '@/utils';
|
||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import {
|
||||||
|
ChangeEventHandler,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import { useDispatch, useSearchParams, useSelector } from 'umi';
|
import { useDispatch, useSearchParams, useSelector } from 'umi';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { ChatSearchParams } from './constants';
|
import { ChatSearchParams } from './constants';
|
||||||
@ -432,6 +439,16 @@ export const useSelectCurrentConversation = () => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const removeLatestMessage = useCallback(() => {
|
||||||
|
setCurrentConversation((pre) => {
|
||||||
|
const nextMessages = pre.message.slice(0, -2);
|
||||||
|
return {
|
||||||
|
...pre,
|
||||||
|
message: nextMessages,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const addPrologue = useCallback(() => {
|
const addPrologue = useCallback(() => {
|
||||||
if (dialogId !== '' && conversationId === '') {
|
if (dialogId !== '' && conversationId === '') {
|
||||||
const prologue = dialog.prompt_config?.prologue;
|
const prologue = dialog.prompt_config?.prologue;
|
||||||
@ -459,7 +476,7 @@ export const useSelectCurrentConversation = () => {
|
|||||||
setCurrentConversation(conversation);
|
setCurrentConversation(conversation);
|
||||||
}, [conversation]);
|
}, [conversation]);
|
||||||
|
|
||||||
return { currentConversation, addNewestConversation };
|
return { currentConversation, addNewestConversation, removeLatestMessage };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useFetchConversation = () => {
|
export const useFetchConversation = () => {
|
||||||
@ -501,7 +518,7 @@ export const useScrollToBottom = (currentConversation: IClientConversation) => {
|
|||||||
export const useFetchConversationOnMount = () => {
|
export const useFetchConversationOnMount = () => {
|
||||||
const { conversationId } = useGetChatSearchParams();
|
const { conversationId } = useGetChatSearchParams();
|
||||||
const fetchConversation = useFetchConversation();
|
const fetchConversation = useFetchConversation();
|
||||||
const { currentConversation, addNewestConversation } =
|
const { currentConversation, addNewestConversation, removeLatestMessage } =
|
||||||
useSelectCurrentConversation();
|
useSelectCurrentConversation();
|
||||||
const ref = useScrollToBottom(currentConversation);
|
const ref = useScrollToBottom(currentConversation);
|
||||||
|
|
||||||
@ -515,16 +532,45 @@ export const useFetchConversationOnMount = () => {
|
|||||||
fetchConversationOnMount();
|
fetchConversationOnMount();
|
||||||
}, [fetchConversationOnMount]);
|
}, [fetchConversationOnMount]);
|
||||||
|
|
||||||
return { currentConversation, addNewestConversation, ref };
|
return {
|
||||||
|
currentConversation,
|
||||||
|
addNewestConversation,
|
||||||
|
ref,
|
||||||
|
removeLatestMessage,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSendMessage = () => {
|
export const useHandleMessageInputChange = () => {
|
||||||
|
const [value, setValue] = useState('');
|
||||||
|
|
||||||
|
const handleInputChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
const nextValue = value.replaceAll('\\n', '\n').replaceAll('\\t', '\t');
|
||||||
|
setValue(nextValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleInputChange,
|
||||||
|
value,
|
||||||
|
setValue,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSendMessage = (
|
||||||
|
conversation: IClientConversation,
|
||||||
|
addNewestConversation: (message: string) => void,
|
||||||
|
removeLatestMessage: () => void,
|
||||||
|
) => {
|
||||||
|
const loading = useOneNamespaceEffectsLoading('chatModel', [
|
||||||
|
'completeConversation',
|
||||||
|
]);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { setConversation } = useSetConversation();
|
const { setConversation } = useSetConversation();
|
||||||
const { conversationId } = useGetChatSearchParams();
|
const { conversationId } = useGetChatSearchParams();
|
||||||
const conversation: IClientConversation = useSelector(
|
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
|
||||||
(state: any) => state.chatModel.currentConversation,
|
// const conversation: IClientConversation = useSelector(
|
||||||
);
|
// (state: any) => state.chatModel.currentConversation,
|
||||||
|
// );
|
||||||
const fetchConversation = useFetchConversation();
|
const fetchConversation = useFetchConversation();
|
||||||
|
|
||||||
const { handleClickConversation } = useClickConversationCard();
|
const { handleClickConversation } = useClickConversationCard();
|
||||||
@ -549,10 +595,15 @@ export const useSendMessage = () => {
|
|||||||
|
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
if (id) {
|
if (id) {
|
||||||
|
// new conversation
|
||||||
handleClickConversation(id);
|
handleClickConversation(id);
|
||||||
} else {
|
} else {
|
||||||
fetchConversation(conversationId);
|
fetchConversation(conversationId);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// cancel loading
|
||||||
|
setValue(message);
|
||||||
|
removeLatestMessage();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@ -561,6 +612,8 @@ export const useSendMessage = () => {
|
|||||||
conversationId,
|
conversationId,
|
||||||
fetchConversation,
|
fetchConversation,
|
||||||
handleClickConversation,
|
handleClickConversation,
|
||||||
|
removeLatestMessage,
|
||||||
|
setValue,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -579,7 +632,20 @@ export const useSendMessage = () => {
|
|||||||
[conversationId, setConversation, sendMessage],
|
[conversationId, setConversation, sendMessage],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { sendMessage: handleSendMessage };
|
const handlePressEnter = () => {
|
||||||
|
if (!loading) {
|
||||||
|
setValue('');
|
||||||
|
addNewestConversation(value);
|
||||||
|
handleSendMessage(value.trim());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
handlePressEnter,
|
||||||
|
handleInputChange,
|
||||||
|
value,
|
||||||
|
loading,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetFileIcon = () => {
|
export const useGetFileIcon = () => {
|
||||||
|
|||||||
@ -115,7 +115,11 @@ const Login = () => {
|
|||||||
label="Password"
|
label="Password"
|
||||||
rules={[{ required: true, message: 'Please input value' }]}
|
rules={[{ required: true, message: 'Please input value' }]}
|
||||||
>
|
>
|
||||||
<Input.Password size="large" placeholder="Please input value" />
|
<Input.Password
|
||||||
|
size="large"
|
||||||
|
placeholder="Please input value"
|
||||||
|
onPressEnter={onCheck}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{title === 'login' && (
|
{title === 'login' && (
|
||||||
<Form.Item name="remember" valuePropName="checked">
|
<Form.Item name="remember" valuePropName="checked">
|
||||||
|
|||||||
@ -51,7 +51,7 @@ const model: DvaModel<LoginModelState> = {
|
|||||||
console.log();
|
console.log();
|
||||||
const { retcode } = data;
|
const { retcode } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
message.success('注册成功!');
|
message.success('Registered!');
|
||||||
}
|
}
|
||||||
return retcode;
|
return retcode;
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user