* feat: fixed the issue where ChatConfigurationModal displays old data when creating a new dialog * feat: Add Skeleton to MessageItem before the backend returns a messagetags/v0.1.0
| @@ -18,7 +18,7 @@ export default defineConfig({ | |||
| dva: {}, | |||
| lessLoader: { | |||
| modifyVars: { | |||
| hack: `true; @import "~@/less/variable.less";`, | |||
| hack: `true; @import "~@/less/index.less";`, | |||
| }, | |||
| }, | |||
| proxy: { | |||
| @@ -1,5 +1,4 @@ | |||
| import { ReactComponent as StarIon } from '@/assets/svg/chat-star.svg'; | |||
| import { ReactComponent as FileIcon } from '@/assets/svg/file-management.svg'; | |||
| import { ReactComponent as KnowledgeBaseIcon } from '@/assets/svg/knowledge-base.svg'; | |||
| import { ReactComponent as Logo } from '@/assets/svg/logo.svg'; | |||
| import { Layout, Radio, Space, theme } from 'antd'; | |||
| @@ -23,7 +22,7 @@ const RagHeader = () => { | |||
| () => [ | |||
| { path: '/knowledge', name: 'Knowledge Base', icon: KnowledgeBaseIcon }, | |||
| { path: '/chat', name: 'Chat', icon: StarIon }, | |||
| { path: '/file', name: 'File Management', icon: FileIcon }, | |||
| // { path: '/file', name: 'File Management', icon: FileIcon }, | |||
| ], | |||
| [], | |||
| ); | |||
| @@ -0,0 +1,2 @@ | |||
| @import './variable.less'; | |||
| @import './mixins.less'; | |||
| @@ -0,0 +1,31 @@ | |||
| .chunkText() { | |||
| em { | |||
| color: red; | |||
| font-style: normal; | |||
| } | |||
| table { | |||
| width: 100%; | |||
| } | |||
| caption { | |||
| color: @blurBackground; | |||
| font-size: 20px; | |||
| height: 50px; | |||
| line-height: 50px; | |||
| font-weight: 600; | |||
| margin-bottom: 10px; | |||
| } | |||
| th { | |||
| color: #fff; | |||
| background-color: @blurBackground; | |||
| } | |||
| td:hover { | |||
| background: @blurBackgroundHover; | |||
| } | |||
| tr:nth-child(even) { | |||
| background-color: #f2f2f2; | |||
| } | |||
| } | |||
| @@ -9,35 +9,7 @@ | |||
| .content { | |||
| flex: 1; | |||
| em { | |||
| color: red; | |||
| font-style: normal; | |||
| } | |||
| table { | |||
| width: 100%; | |||
| } | |||
| caption { | |||
| color: @blurBackground; | |||
| font-size: 20px; | |||
| height: 50px; | |||
| line-height: 50px; | |||
| font-weight: 600; | |||
| margin-bottom: 10px; | |||
| } | |||
| th { | |||
| color: #fff; | |||
| background-color: @blurBackground; | |||
| } | |||
| td:hover { | |||
| background: @blurBackgroundHover; | |||
| } | |||
| tr:nth-child(even) { | |||
| background-color: #f2f2f2; | |||
| } | |||
| .chunkText; | |||
| } | |||
| .cardSelected { | |||
| @@ -121,14 +121,16 @@ const ChatConfigurationModal = ({ visible, hideModal, id }: IProps) => { | |||
| ); | |||
| useEffect(() => { | |||
| const icon = currentDialog.icon; | |||
| let fileList: UploadFile[] = []; | |||
| if (icon) { | |||
| fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }]; | |||
| if (visible) { | |||
| const icon = currentDialog.icon; | |||
| let fileList: UploadFile[] = []; | |||
| if (icon) { | |||
| fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }]; | |||
| } | |||
| form.setFieldsValue({ ...currentDialog, icon: fileList }); | |||
| } | |||
| form.setFieldsValue({ ...currentDialog, icon: fileList }); | |||
| }, [currentDialog, form]); | |||
| }, [currentDialog, form, visible]); | |||
| return ( | |||
| <Modal | |||
| @@ -28,6 +28,9 @@ | |||
| padding: 0 14px; | |||
| background-color: rgba(249, 250, 251, 1); | |||
| } | |||
| .messageEmpty { | |||
| width: 300px; | |||
| } | |||
| .referenceIcon { | |||
| padding: 0 6px; | |||
| } | |||
| @@ -52,3 +55,6 @@ | |||
| .referenceImagePreview { | |||
| width: 600px; | |||
| } | |||
| .chunkContentText { | |||
| .chunkText; | |||
| } | |||
| @@ -11,6 +11,7 @@ import { | |||
| Input, | |||
| List, | |||
| Popover, | |||
| Skeleton, | |||
| Space, | |||
| } from 'antd'; | |||
| import classNames from 'classnames'; | |||
| @@ -100,7 +101,12 @@ const MessageItem = ({ | |||
| ></Image> | |||
| </Popover> | |||
| <Space direction={'vertical'}> | |||
| <div>{chunkItem?.content_with_weight}</div> | |||
| <div | |||
| dangerouslySetInnerHTML={{ | |||
| __html: chunkItem?.content_with_weight, | |||
| }} | |||
| className={styles.chunkContentText} | |||
| ></div> | |||
| {documentId && ( | |||
| <Flex gap={'middle'}> | |||
| <img src={fileThumbnails[documentId]} alt="" /> | |||
| @@ -171,17 +177,24 @@ const MessageItem = ({ | |||
| <Flex vertical gap={8} flex={1}> | |||
| <b>{isAssistant ? '' : userInfo.nickname}</b> | |||
| <div className={styles.messageText}> | |||
| <Markdown | |||
| rehypePlugins={[rehypeWrapReference]} | |||
| components={ | |||
| { | |||
| 'custom-typography': ({ children }: { children: string }) => | |||
| renderReference(children), | |||
| } as any | |||
| } | |||
| > | |||
| {item.content} | |||
| </Markdown> | |||
| {item.content ? ( | |||
| <Markdown | |||
| rehypePlugins={[rehypeWrapReference]} | |||
| components={ | |||
| { | |||
| 'custom-typography': ({ | |||
| children, | |||
| }: { | |||
| children: string; | |||
| }) => renderReference(children), | |||
| } as any | |||
| } | |||
| > | |||
| {item.content} | |||
| </Markdown> | |||
| ) : ( | |||
| <Skeleton active className={styles.messageEmpty} /> | |||
| )} | |||
| </div> | |||
| {isAssistant && referenceDocumentList.length > 0 && ( | |||
| <List | |||
| @@ -78,12 +78,10 @@ export const useSetCurrentDialog = () => { | |||
| const setCurrentDialog = useCallback( | |||
| (dialogId: string) => { | |||
| if (dialogId) { | |||
| dispatch({ | |||
| type: 'chatModel/setCurrentDialog', | |||
| payload: { id: dialogId }, | |||
| }); | |||
| } | |||
| dispatch({ | |||
| type: 'chatModel/setCurrentDialog', | |||
| payload: { id: dialogId }, | |||
| }); | |||
| }, | |||
| [dispatch], | |||
| ); | |||
| @@ -427,6 +425,12 @@ export const useSelectCurrentConversation = () => { | |||
| content: message, | |||
| id: uuid(), | |||
| } as IMessage, | |||
| { | |||
| role: MessageType.Assistant, | |||
| content: '', | |||
| id: uuid(), | |||
| reference: [], | |||
| } as IMessage, | |||
| ], | |||
| }; | |||
| }); | |||
| @@ -525,12 +529,13 @@ export const useSendMessage = () => { | |||
| const conversation: IClientConversation = useSelector( | |||
| (state: any) => state.chatModel.currentConversation, | |||
| ); | |||
| const fetchConversation = useFetchConversation(); | |||
| const { handleClickConversation } = useClickConversationCard(); | |||
| const sendMessage = useCallback( | |||
| (message: string, id?: string) => { | |||
| dispatch({ | |||
| async (message: string, id?: string) => { | |||
| const retcode = await dispatch<any>({ | |||
| type: 'chatModel/completeConversation', | |||
| payload: { | |||
| conversation_id: id ?? conversationId, | |||
| @@ -545,8 +550,22 @@ export const useSendMessage = () => { | |||
| ], | |||
| }, | |||
| }); | |||
| if (retcode === 0) { | |||
| if (id) { | |||
| handleClickConversation(id); | |||
| } else { | |||
| fetchConversation(conversationId); | |||
| } | |||
| } | |||
| }, | |||
| [dispatch, conversation?.message, conversationId], | |||
| [ | |||
| dispatch, | |||
| conversation?.message, | |||
| conversationId, | |||
| fetchConversation, | |||
| handleClickConversation, | |||
| ], | |||
| ); | |||
| const handleSendMessage = useCallback( | |||
| @@ -557,12 +576,11 @@ export const useSendMessage = () => { | |||
| const data = await setConversation(message); | |||
| if (data.retcode === 0) { | |||
| const id = data.data.id; | |||
| handleClickConversation(id); | |||
| sendMessage(message, id); | |||
| } | |||
| } | |||
| }, | |||
| [conversationId, handleClickConversation, setConversation, sendMessage], | |||
| [conversationId, setConversation, sendMessage], | |||
| ); | |||
| return { sendMessage: handleSendMessage }; | |||
| @@ -38,6 +38,7 @@ | |||
| .chatTitleContent { | |||
| padding: 5px 10px; | |||
| overflow: auto; | |||
| } | |||
| .chatTitleCard { | |||
| @@ -76,9 +76,9 @@ const Chat = () => { | |||
| (info: any) => { | |||
| info?.domEvent?.preventDefault(); | |||
| info?.domEvent?.stopPropagation(); | |||
| if (dialogId) { | |||
| setCurrentDialog(dialogId); | |||
| } | |||
| // if (dialogId) { | |||
| setCurrentDialog(dialogId ?? ''); | |||
| // } | |||
| showModal(); | |||
| }; | |||
| @@ -140,14 +140,15 @@ const model: DvaModel<ChatModelState> = { | |||
| }, | |||
| *completeConversation({ payload }, { call, put }) { | |||
| const { data } = yield call(chatService.completeConversation, payload); | |||
| if (data.retcode === 0) { | |||
| yield put({ | |||
| type: 'getConversation', | |||
| payload: { | |||
| conversation_id: payload.conversation_id, | |||
| }, | |||
| }); | |||
| } | |||
| // if (data.retcode === 0) { | |||
| // yield put({ | |||
| // type: 'getConversation', | |||
| // payload: { | |||
| // conversation_id: payload.conversation_id, | |||
| // }, | |||
| // }); | |||
| // } | |||
| return data.retcode; | |||
| }, | |||
| *removeConversation({ payload }, { call, put }) { | |||
| const { data } = yield call(chatService.removeConversation, { | |||