From d38e92aac82bba4c052a3440384789230aa5b7b1 Mon Sep 17 00:00:00 2001
From: balibabu <cike8899@users.noreply.github.com>
Date: Tue, 19 Mar 2024 19:21:35 +0800
Subject: [PATCH] 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
---
 .../knowledge-upload-file/index.less          | 17 +++-
 .../knowledge-upload-file/index.tsx           | 13 ++-
 .../testing-result/index.tsx                  |  2 +-
 web/src/pages/chat/chat-container/index.tsx   | 25 +-----
 web/src/pages/chat/hooks.ts                   | 84 +++++++++++++++++--
 web/src/pages/login/index.tsx                 |  6 +-
 web/src/pages/login/model.ts                  |  2 +-
 7 files changed, 107 insertions(+), 42 deletions(-)

diff --git a/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.less b/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.less
index 3514272..b3d17f1 100644
--- a/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.less
+++ b/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.less
@@ -8,6 +8,7 @@
   }
   .footer {
     text-align: right;
+    padding-top: 16px;
     .nextButton {
       background-color: @purple;
     }
@@ -17,8 +18,9 @@
     padding-top: 60px;
   }
   .uploader {
-    display: block;
-    height: 200px;
+    :global(.ant-upload) {
+      height: 126px;
+    }
   }
   .hiddenUploader {
     :global(.ant-upload-drag) {
@@ -29,6 +31,17 @@
     font-size: 40px;
     align-items: end;
   }
+  .uploaderButton {
+    padding: 10px;
+    vertical-align: middle;
+    height: 40px;
+  }
+  .uploaderIcon {
+    svg {
+      width: 20px;
+      height: 20px;
+    }
+  }
   .deleteIcon {
     font-size: 20px;
   }
diff --git a/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.tsx b/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.tsx
index 27d2486..b3e5a7a 100644
--- a/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.tsx
+++ b/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.tsx
@@ -1,5 +1,6 @@
 import { ReactComponent as SelectFilesEndIcon } from '@/assets/svg/select-files-end.svg';
 import { ReactComponent as SelectFilesStartIcon } from '@/assets/svg/select-files-start.svg';
+import { KnowledgeRouteKey } from '@/constants/knowledge';
 import {
   useDeleteDocumentById,
   useFetchKnowledgeDetail,
@@ -10,14 +11,14 @@ import {
   useFetchTenantInfo,
   useSelectParserList,
 } from '@/hooks/userSettingHook';
-
 import uploadService from '@/services/uploadService';
+import { isFileUploadDone } from '@/utils/documentUtils';
 import {
   ArrowLeftOutlined,
+  CloudUploadOutlined,
   DeleteOutlined,
   EditOutlined,
   FileDoneOutlined,
-  InboxOutlined,
 } from '@ant-design/icons';
 import {
   Button,
@@ -43,8 +44,6 @@ import {
 } from 'react';
 import { Link, useDispatch, useNavigate } from 'umi';
 
-import { KnowledgeRouteKey } from '@/constants/knowledge';
-import { isFileUploadDone } from '@/utils/documentUtils';
 import styles from './index.less';
 
 const { Dragger } = Upload;
@@ -290,9 +289,9 @@ const KnowledgeUploadFile = () => {
             [styles.hiddenUploader]: !isUpload,
           })}
         >
-          <p className="ant-upload-drag-icon">
-            <InboxOutlined />
-          </p>
+          <Button className={styles.uploaderButton}>
+            <CloudUploadOutlined className={styles.uploaderIcon} />
+          </Button>
           <p className="ant-upload-text">
             Click or drag file to this area to upload
           </p>
diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx
index 86ef8e8..9277418 100644
--- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx
+++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx
@@ -27,7 +27,7 @@ const ChunkTitle = ({ item }: { item: ITestingChunk }) => {
       {similarityList.map((x) => (
         <Space key={x.field}>
           <span className={styles.similarityCircle}>
-            {((item[x.field] as number) * 100).toFixed(2)}%
+            {((item[x.field] as number) * 100).toFixed(2)}
           </span>
           <span className={styles.similarityText}>{x.label}</span>
         </Space>
diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx
index b0a3ca8..e7cd63e 100644
--- a/web/src/pages/chat/chat-container/index.tsx
+++ b/web/src/pages/chat/chat-container/index.tsx
@@ -4,7 +4,6 @@ import NewDocumentLink from '@/components/new-document-link';
 import DocumentPreviewer from '@/components/pdf-previewer';
 import { MessageType } from '@/constants/chat';
 import { useSelectFileThumbnails } from '@/hooks/knowledgeHook';
-import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
 import { useSelectUserInfo } from '@/hooks/userSettingHook';
 import { IReference, Message } from '@/interfaces/database/chat';
 import { IChunk } from '@/interfaces/database/knowledge';
@@ -21,7 +20,7 @@ import {
   Space,
 } from 'antd';
 import classNames from 'classnames';
-import { ChangeEventHandler, useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo } from 'react';
 import Markdown from 'react-markdown';
 import reactStringReplace from 'react-string-replace';
 import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
@@ -243,35 +242,19 @@ const MessageItem = ({
 };
 
 const ChatContainer = () => {
-  const [value, setValue] = useState('');
   const {
     ref,
     currentConversation: conversation,
     addNewestConversation,
+    removeLatestMessage,
   } = useFetchConversationOnMount();
-  const { sendMessage } = useSendMessage();
+  const { handleInputChange, handlePressEnter, value, loading } =
+    useSendMessage(conversation, addNewestConversation, removeLatestMessage);
   const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
     useClickDrawer();
 
-  const loading = useOneNamespaceEffectsLoading('chatModel', [
-    'completeConversation',
-  ]);
   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 (
     <>
       <Flex flex={1} className={styles.chatContainer} vertical>
diff --git a/web/src/pages/chat/hooks.ts b/web/src/pages/chat/hooks.ts
index b3e83bc..877c91a 100644
--- a/web/src/pages/chat/hooks.ts
+++ b/web/src/pages/chat/hooks.ts
@@ -7,7 +7,14 @@ import { IConversation, IDialog } from '@/interfaces/database/chat';
 import { IChunk } from '@/interfaces/database/knowledge';
 import { getFileExtension } from '@/utils';
 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 { v4 as uuid } from 'uuid';
 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(() => {
     if (dialogId !== '' && conversationId === '') {
       const prologue = dialog.prompt_config?.prologue;
@@ -459,7 +476,7 @@ export const useSelectCurrentConversation = () => {
     setCurrentConversation(conversation);
   }, [conversation]);
 
-  return { currentConversation, addNewestConversation };
+  return { currentConversation, addNewestConversation, removeLatestMessage };
 };
 
 export const useFetchConversation = () => {
@@ -501,7 +518,7 @@ export const useScrollToBottom = (currentConversation: IClientConversation) => {
 export const useFetchConversationOnMount = () => {
   const { conversationId } = useGetChatSearchParams();
   const fetchConversation = useFetchConversation();
-  const { currentConversation, addNewestConversation } =
+  const { currentConversation, addNewestConversation, removeLatestMessage } =
     useSelectCurrentConversation();
   const ref = useScrollToBottom(currentConversation);
 
@@ -515,16 +532,45 @@ export const useFetchConversationOnMount = () => {
     fetchConversationOnMount();
   }, [fetchConversationOnMount]);
 
-  return { currentConversation, addNewestConversation, ref };
+  return {
+    currentConversation,
+    addNewestConversation,
+    ref,
+    removeLatestMessage,
+  };
+};
+
+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 = () => {
+export const useSendMessage = (
+  conversation: IClientConversation,
+  addNewestConversation: (message: string) => void,
+  removeLatestMessage: () => void,
+) => {
+  const loading = useOneNamespaceEffectsLoading('chatModel', [
+    'completeConversation',
+  ]);
   const dispatch = useDispatch();
   const { setConversation } = useSetConversation();
   const { conversationId } = useGetChatSearchParams();
-  const conversation: IClientConversation = useSelector(
-    (state: any) => state.chatModel.currentConversation,
-  );
+  const { handleInputChange, value, setValue } = useHandleMessageInputChange();
+  // const conversation: IClientConversation = useSelector(
+  //   (state: any) => state.chatModel.currentConversation,
+  // );
   const fetchConversation = useFetchConversation();
 
   const { handleClickConversation } = useClickConversationCard();
@@ -549,10 +595,15 @@ export const useSendMessage = () => {
 
       if (retcode === 0) {
         if (id) {
+          // new conversation
           handleClickConversation(id);
         } else {
           fetchConversation(conversationId);
         }
+      } else {
+        // cancel loading
+        setValue(message);
+        removeLatestMessage();
       }
     },
     [
@@ -561,6 +612,8 @@ export const useSendMessage = () => {
       conversationId,
       fetchConversation,
       handleClickConversation,
+      removeLatestMessage,
+      setValue,
     ],
   );
 
@@ -579,7 +632,20 @@ export const useSendMessage = () => {
     [conversationId, setConversation, sendMessage],
   );
 
-  return { sendMessage: handleSendMessage };
+  const handlePressEnter = () => {
+    if (!loading) {
+      setValue('');
+      addNewestConversation(value);
+      handleSendMessage(value.trim());
+    }
+  };
+
+  return {
+    handlePressEnter,
+    handleInputChange,
+    value,
+    loading,
+  };
 };
 
 export const useGetFileIcon = () => {
diff --git a/web/src/pages/login/index.tsx b/web/src/pages/login/index.tsx
index 6050822..cb6aa41 100644
--- a/web/src/pages/login/index.tsx
+++ b/web/src/pages/login/index.tsx
@@ -115,7 +115,11 @@ const Login = () => {
               label="Password"
               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>
             {title === 'login' && (
               <Form.Item name="remember" valuePropName="checked">
diff --git a/web/src/pages/login/model.ts b/web/src/pages/login/model.ts
index 8faf077..eaa92fb 100644
--- a/web/src/pages/login/model.ts
+++ b/web/src/pages/login/model.ts
@@ -51,7 +51,7 @@ const model: DvaModel<LoginModelState> = {
       console.log();
       const { retcode } = data;
       if (retcode === 0) {
-        message.success('注册成功!');
+        message.success('Registered!');
       }
       return retcode;
     },
-- 
GitLab