From 380f98ccc2f78530dfd7d81429cfd2697988c1ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9F=E8=B4=A4?= Date: Sat, 23 Mar 2024 21:12:15 +0800 Subject: [PATCH 01/96] init --- docs/guide/demos/controled-servers-push.tsx | 14 +- docs/guide/demos/doc-mode.tsx | 2 +- ...enderInputArea.tsx => inputAreaRender.tsx} | 0 docs/guide/demos/mocks/fullFeature.ts | 4 +- docs/guide/demos/styles-chatitem.tsx | 10 +- docs/guide/demos/styles-className.tsx | 10 +- docs/guide/demos/styles-darkmode.tsx | 10 +- docs/guide/initial.en-US.md | 21 +- docs/guide/initial.md | 18 +- docs/guide/multimodal.en-US.md | 8 +- docs/guide/multimodal.md | 2 +- docs/guide/servers-push.en-US.md | 2 +- docs/guide/servers-push.md | 2 +- docs/guide/storage.en-US.md | 32 +-- docs/guide/storage.md | 32 +-- package.json | 24 +- src/ActionIcon/index.tsx | 182 --------------- src/ActionIcon/style.ts | 21 -- src/ActionIconGroup/index.tsx | 123 ----------- src/BackBottom/demos/index.tsx | 18 -- src/BackBottom/index.en-US.md | 14 -- src/BackBottom/index.md | 14 -- src/BackBottom/index.tsx | 139 ------------ src/BackBottom/style.ts | 20 -- src/ChatItem/components/Loading.tsx | 27 --- src/ChatList/ActionsBar.tsx | 53 ----- src/ChatList/HistoryDivider.tsx | 37 ---- src/ChatList/ShouldUpdateItem.tsx | 40 ---- src/ChatList/index.tsx | 129 ----------- src/ChatList/style.ts | 9 - src/EditableMessage/demos/index.tsx | 106 --------- src/EditableMessage/index.en-US.md | 14 -- src/EditableMessage/index.md | 14 -- src/EditableMessage/index.tsx | 167 -------------- src/EditableMessageList/demos/data.ts | 43 ---- src/EditableMessageList/demos/index.tsx | 5 - src/EditableMessageList/index.en-US.md | 14 -- src/EditableMessageList/index.md | 14 -- src/EditableMessageList/index.tsx | 106 --------- src/EditableMessageList/messageReducer.ts | 85 ------- src/Emoji/index.tsx | 32 --- src/Emoji/style.ts | 29 --- src/Icon/index.tsx | 92 -------- src/Icon/style.ts | 17 -- src/List/ListItem/index.tsx | 160 -------------- src/List/ListItem/style.ts | 79 ------- src/List/ListItem/time.ts | 15 -- src/List/index.ts | 7 - src/MessageInput/demos/index.tsx | 6 - src/MessageInput/index.en-US.md | 14 -- src/MessageInput/index.md | 14 -- src/MessageInput/index.tsx | 114 ---------- src/MessageInput/style.ts | 13 -- src/MessageModal/demos/index.tsx | 20 -- src/MessageModal/index.en-US.md | 14 -- src/MessageModal/index.md | 14 -- src/MessageModal/index.tsx | 135 ------------ .../__test__/__snapshots__/demo.test.tsx.snap | 2 +- src/ProChat/__test__/index.test.tsx | 6 +- .../components}/ChatList/ChatListItem.tsx | 17 +- .../components/ChatList/Extras/Assistant.tsx | 17 +- .../components/ChatList/Extras/User.tsx | 9 +- .../ChatList/Messages/Assistant.tsx | 2 +- src/ProChat/components/ChatList/OTPInput.tsx | 6 +- .../components/ChatList/SkeletonList.tsx | 7 +- src/ProChat/components/ChatList/index.tsx | 208 ++++++++++-------- .../components/InputArea/ActionBar.tsx | 12 +- src/ProChat/components/InputArea/index.tsx | 23 +- src/ProChat/container/App.tsx | 171 -------------- .../container/OverrideStyle/antdOverride.ts | 64 ------ src/ProChat/container/OverrideStyle/index.ts | 7 - src/ProChat/container/Provider.tsx | 56 ----- src/ProChat/container/StoreUpdater.tsx | 52 ----- src/ProChat/container/index.tsx | 180 +++++++++------ .../{OverrideStyle => style}/global.ts | 0 src/ProChat/container/style/index.ts | 6 + src/ProChat/demos/bigData.tsx | 6 +- src/ProChat/demos/control.tsx | 8 +- src/ProChat/demos/doc-mode.tsx | 2 +- src/ProChat/demos/draggable.tsx | 6 +- src/ProChat/demos/initialChats.tsx | 2 +- src/ProChat/demos/loading.tsx | 11 +- src/ProChat/demos/meta.tsx | 4 +- src/ProChat/demos/toBottomConfig.tsx | 2 +- src/ProChat/demos/use-pro-chat.tsx | 104 --------- src/ProChat/demos/use-ref.tsx | 2 +- src/ProChat/hooks/useProChat.ts | 6 +- src/ProChat/index.en-US.md | 21 +- src/ProChat/index.md | 29 +-- src/ProChat/index.tsx | 1 - src/ProChat/mocks/basic.ts | 2 +- src/ProChat/mocks/fullFeature.ts | 2 +- src/ProChat/mocks/threebody.ts | 4 +- src/ProChat/store/action.ts | 24 +- src/ProChat/store/index.ts | 2 +- src/ProChat/store/initialState.ts | 23 +- src/ProChat/store/selectors/chat.ts | 14 +- src/ProChat/store/selectors/index.ts | 4 +- src/ProChat/store/store.ts | 29 ++- src/TokenTag/demos/index.tsx | 16 -- src/TokenTag/index.en-US.md | 17 -- src/TokenTag/index.md | 17 -- src/TokenTag/index.tsx | 72 ------ src/TokenTag/style.ts | 67 ------ src/components/Avatar/getEmojiByCharacter.ts | 6 - src/components/Avatar/index.tsx | 24 +- src/components/Avatar/style.ts | 7 +- .../ChatItem/components/Actions.tsx | 8 +- .../ChatItem/components/Avatar.tsx | 6 +- .../ChatItem/components/BorderSpacing.tsx | 0 .../ChatItem/components/ErrorContent.tsx | 10 +- .../ChatItem/components/Loading.tsx | 23 ++ .../ChatItem/components/MessageContent.tsx | 41 ++-- .../ChatItem/components/Title.tsx | 14 +- src/{ => components}/ChatItem/demos/Alert.tsx | 0 src/{ => components}/ChatItem/demos/data.tsx | 0 src/{ => components}/ChatItem/demos/index.tsx | 0 src/{ => components}/ChatItem/index.en-US.md | 0 src/{ => components}/ChatItem/index.md | 0 src/{ => components}/ChatItem/index.tsx | 30 ++- src/{ => components}/ChatItem/style.ts | 0 src/{ => components}/ChatItem/type.ts | 0 .../ChatItem/utils/formatTime.ts | 0 src/components/ControlInput.tsx | 95 -------- src/components/CopyButton/index.tsx | 46 ++-- src/components/Form/components/FormGroup.tsx | 37 ++-- src/components/Form/components/FormTitle.tsx | 14 +- src/components/Input/index.tsx | 2 +- src/components/SliderWithInput/index.tsx | 69 ------ src/components/Spotlight/index.tsx | 53 ----- src/components/Spotlight/style.ts | 30 --- src/components/Tag/index.tsx | 45 ---- src/index.ts | 30 +-- tests/demo.tsx | 2 +- 134 files changed, 587 insertions(+), 3707 deletions(-) rename docs/guide/demos/{renderInputArea.tsx => inputAreaRender.tsx} (100%) delete mode 100644 src/ActionIcon/index.tsx delete mode 100644 src/ActionIcon/style.ts delete mode 100644 src/ActionIconGroup/index.tsx delete mode 100644 src/BackBottom/demos/index.tsx delete mode 100644 src/BackBottom/index.en-US.md delete mode 100644 src/BackBottom/index.md delete mode 100644 src/BackBottom/index.tsx delete mode 100644 src/BackBottom/style.ts delete mode 100644 src/ChatItem/components/Loading.tsx delete mode 100644 src/ChatList/ActionsBar.tsx delete mode 100644 src/ChatList/HistoryDivider.tsx delete mode 100644 src/ChatList/ShouldUpdateItem.tsx delete mode 100644 src/ChatList/index.tsx delete mode 100644 src/ChatList/style.ts delete mode 100644 src/EditableMessage/demos/index.tsx delete mode 100644 src/EditableMessage/index.en-US.md delete mode 100644 src/EditableMessage/index.md delete mode 100644 src/EditableMessage/index.tsx delete mode 100644 src/EditableMessageList/demos/data.ts delete mode 100644 src/EditableMessageList/demos/index.tsx delete mode 100644 src/EditableMessageList/index.en-US.md delete mode 100644 src/EditableMessageList/index.md delete mode 100644 src/EditableMessageList/index.tsx delete mode 100644 src/EditableMessageList/messageReducer.ts delete mode 100644 src/Emoji/index.tsx delete mode 100644 src/Emoji/style.ts delete mode 100644 src/Icon/index.tsx delete mode 100644 src/Icon/style.ts delete mode 100644 src/List/ListItem/index.tsx delete mode 100644 src/List/ListItem/style.ts delete mode 100644 src/List/ListItem/time.ts delete mode 100644 src/List/index.ts delete mode 100644 src/MessageInput/demos/index.tsx delete mode 100644 src/MessageInput/index.en-US.md delete mode 100644 src/MessageInput/index.md delete mode 100644 src/MessageInput/index.tsx delete mode 100644 src/MessageInput/style.ts delete mode 100644 src/MessageModal/demos/index.tsx delete mode 100644 src/MessageModal/index.en-US.md delete mode 100644 src/MessageModal/index.md delete mode 100644 src/MessageModal/index.tsx rename src/{ => ProChat/components}/ChatList/ChatListItem.tsx (93%) delete mode 100644 src/ProChat/container/App.tsx delete mode 100644 src/ProChat/container/OverrideStyle/antdOverride.ts delete mode 100644 src/ProChat/container/OverrideStyle/index.ts delete mode 100644 src/ProChat/container/Provider.tsx delete mode 100644 src/ProChat/container/StoreUpdater.tsx rename src/ProChat/container/{OverrideStyle => style}/global.ts (100%) create mode 100644 src/ProChat/container/style/index.ts delete mode 100644 src/ProChat/demos/use-pro-chat.tsx delete mode 100644 src/TokenTag/demos/index.tsx delete mode 100644 src/TokenTag/index.en-US.md delete mode 100644 src/TokenTag/index.md delete mode 100644 src/TokenTag/index.tsx delete mode 100644 src/TokenTag/style.ts delete mode 100644 src/components/Avatar/getEmojiByCharacter.ts rename src/{ => components}/ChatItem/components/Actions.tsx (59%) rename src/{ => components}/ChatItem/components/Avatar.tsx (88%) rename src/{ => components}/ChatItem/components/BorderSpacing.tsx (100%) rename src/{ => components}/ChatItem/components/ErrorContent.tsx (76%) create mode 100644 src/components/ChatItem/components/Loading.tsx rename src/{ => components}/ChatItem/components/MessageContent.tsx (68%) rename src/{ => components}/ChatItem/components/Title.tsx (67%) rename src/{ => components}/ChatItem/demos/Alert.tsx (100%) rename src/{ => components}/ChatItem/demos/data.tsx (100%) rename src/{ => components}/ChatItem/demos/index.tsx (100%) rename src/{ => components}/ChatItem/index.en-US.md (100%) rename src/{ => components}/ChatItem/index.md (100%) rename src/{ => components}/ChatItem/index.tsx (91%) rename src/{ => components}/ChatItem/style.ts (100%) rename src/{ => components}/ChatItem/type.ts (100%) rename src/{ => components}/ChatItem/utils/formatTime.ts (100%) delete mode 100644 src/components/ControlInput.tsx delete mode 100644 src/components/SliderWithInput/index.tsx delete mode 100644 src/components/Spotlight/index.tsx delete mode 100644 src/components/Spotlight/style.ts delete mode 100644 src/components/Tag/index.tsx diff --git a/docs/guide/demos/controled-servers-push.tsx b/docs/guide/demos/controled-servers-push.tsx index 872952c3..8958b613 100644 --- a/docs/guide/demos/controled-servers-push.tsx +++ b/docs/guide/demos/controled-servers-push.tsx @@ -12,13 +12,13 @@ import { MockResponse } from './mocks/streamResponse'; export default () => { const theme = useTheme(); - const [chats, setChats] = useState>[]>( - Object.values(example.initialChats), + const [chatList, setChatList] = useState>[]>( + Object.values(example.initialChatsList), ); useEffect(() => { setTimeout(() => { - setChats([ - ...chats, + setChatList([ + ...chatList, { id: 'VbtDpzsi', content: `当前对话剩余的 token 数量为 100`, @@ -31,9 +31,9 @@ export default () => { return (
{ - setChats(chats); + chatList={chatList} + onChatsChange={(chatList) => { + setChatList(chatList); }} chatItemRenderConfig={{ render: (item, dom, defaultDom) => { diff --git a/docs/guide/demos/doc-mode.tsx b/docs/guide/demos/doc-mode.tsx index c5555a28..0e2e2157 100644 --- a/docs/guide/demos/doc-mode.tsx +++ b/docs/guide/demos/doc-mode.tsx @@ -21,7 +21,7 @@ export default () => { return mockResponse.getResponse(); }} - chats={example.chats} + chatList={example.chatList} config={example.config} />
diff --git a/docs/guide/demos/renderInputArea.tsx b/docs/guide/demos/inputAreaRender.tsx similarity index 100% rename from docs/guide/demos/renderInputArea.tsx rename to docs/guide/demos/inputAreaRender.tsx diff --git a/docs/guide/demos/mocks/fullFeature.ts b/docs/guide/demos/mocks/fullFeature.ts index 314f6f20..00709a72 100644 --- a/docs/guide/demos/mocks/fullFeature.ts +++ b/docs/guide/demos/mocks/fullFeature.ts @@ -1,5 +1,5 @@ export const example = { - initialChats: [ + initialChatsList: [ { content: '你是谁?', createAt: 1697862242452, @@ -22,7 +22,7 @@ export const example = { updateAt: 1697862243540, }, ], - chats: [ + chatList: [ { content: '请展示完整的会话高亮效果?', createAt: 1697862242452, diff --git a/docs/guide/demos/styles-chatitem.tsx b/docs/guide/demos/styles-chatitem.tsx index c5de30ef..dedf023a 100644 --- a/docs/guide/demos/styles-chatitem.tsx +++ b/docs/guide/demos/styles-chatitem.tsx @@ -8,14 +8,16 @@ import { example } from './mocks/fullFeature'; export default () => { const theme = useTheme(); - const [chats, setChats] = useState>[]>(example.initialChats); + const [chatList, setChatList] = useState>[]>( + example.initialChatsList, + ); return (
{ - setChats(chats); + chatList={chatList} + onChatsChange={(chatList) => { + setChatList(chatList); }} chatItemRenderConfig={{ contentRender: (_, defaultContent) => { diff --git a/docs/guide/demos/styles-className.tsx b/docs/guide/demos/styles-className.tsx index 85897edb..f728f5ce 100644 --- a/docs/guide/demos/styles-className.tsx +++ b/docs/guide/demos/styles-className.tsx @@ -8,7 +8,9 @@ import { example } from './mocks/fullFeature'; export default () => { const theme = useTheme(); - const [chats, setChats] = useState>[]>(example.initialChats); + const [chatList, setChatList] = useState>[]>( + example.initialChatsList, + ); const CustomClassName = cx( css(` @@ -21,9 +23,9 @@ export default () => { return (
{ - setChats(chats); + chatList={chatList} + onChatsChange={(chatList) => { + setChatList(chatList); }} chatItemRenderConfig={{ contentRender: (_, defaultContent) => { diff --git a/docs/guide/demos/styles-darkmode.tsx b/docs/guide/demos/styles-darkmode.tsx index 000bbcb9..9ae4fdc2 100644 --- a/docs/guide/demos/styles-darkmode.tsx +++ b/docs/guide/demos/styles-darkmode.tsx @@ -8,7 +8,9 @@ import { useState } from 'react'; import { example } from './mocks/fullFeature'; export default () => { - const [chats, setChats] = useState>[]>(example.initialChats); + const [chatList, setChatList] = useState>[]>( + example.initialChatsList, + ); return ( { >
{ - setChats(chats); + chatList={chatList} + onChatsChange={(chatList) => { + setChatList(chatList); }} request={async (messages) => { const mockedData: string = `这是一段模拟的对话数据。本次会话传入了${messages.length}条消息`; diff --git a/docs/guide/initial.en-US.md b/docs/guide/initial.en-US.md index 2b9d1758..bcff1a51 100644 --- a/docs/guide/initial.en-US.md +++ b/docs/guide/initial.en-US.md @@ -39,7 +39,7 @@ In the above example, we passed in a custom message with a Markdown formatted li ## Initialize data -`initialChats` is a property used to initialize chat data. By setting `initialChats`,We can load the previously saved chat records and display them in the ProChat component. The example code is as follows: +`initialChatsList` is a property used to initialize chat data. By setting `initialChatsList`,We can load the previously saved chat records and display them in the ProChat component. The example code is as follows: ```tsx import { ProChat } from '@ant-design/pro-chat'; @@ -50,13 +50,13 @@ export default () => { const theme = useTheme(); return (
- +
); }; ``` -In the above code, we pass `example.chats` as the initial chat data to the ProChat component. Note that when using this attribute, it is necessary to provide the initial chat data in the correct format. +In the above code, we pass `example.chatList` as the initial chat data to the ProChat component. Note that when using this attribute, it is necessary to provide the initial chat data in the correct format. ## Using a skeleton screen @@ -64,21 +64,20 @@ When the data is not ready yet, the `loading` attribute can be used to display t ```tsx import { ProChat } from '@ant-design/pro-chat'; -import { Button, Divider } from 'antd'; +import { Button, Flex, Divider } from 'antd'; import { useTheme } from 'antd-style'; import { useState } from 'react'; -import { Flexbox } from 'react-layout-kit'; import { example } from './demos/mocks/fullFeature'; export default () => { const [loading, setLoading] = useState(true); const theme = useTheme(); - const [chats, setChats] = useState(example.initialChats); + const [chatList, setChatList] = useState(example.initialChatsList); return ( - - + + - + - - + + ); }; ``` diff --git a/docs/guide/initial.md b/docs/guide/initial.md index a8e2c146..12f3870a 100644 --- a/docs/guide/initial.md +++ b/docs/guide/initial.md @@ -39,7 +39,7 @@ export default () => { ## 初始化数据 -`initialChats` 是用于初始化聊天数据的属性。通过设置 `initialChats`,我们可以加载之前保存的聊天记录,并在 ProChat 组件中展示出来。示例代码如下: +`initialChatsList` 是用于初始化聊天数据的属性。通过设置 `initialChatsList`,我们可以加载之前保存的聊天记录,并在 ProChat 组件中展示出来。示例代码如下: ```tsx import { ProChat } from '@ant-design/pro-chat'; @@ -50,13 +50,13 @@ export default () => { const theme = useTheme(); return (
- +
); }; ``` -上述代码中,我们将 `example.chats` 作为初始聊天数据传递给 ProChat 组件。注意,在使用该属性时需要提供正确格式的初始聊天数据。 +上述代码中,我们将 `example.chatList` 作为初始聊天数据传递给 ProChat 组件。注意,在使用该属性时需要提供正确格式的初始聊天数据。 ## 使用骨架屏 @@ -74,11 +74,11 @@ export default () => { const [loading, setLoading] = useState(true); const theme = useTheme(); - const [chats, setChats] = useState(example.initialChats); + const [chatList, setChatList] = useState(example.initialChatsList); return ( - - + + - + - - + + ); }; ``` diff --git a/docs/guide/multimodal.en-US.md b/docs/guide/multimodal.en-US.md index aa926a84..2cd6b8f7 100644 --- a/docs/guide/multimodal.en-US.md +++ b/docs/guide/multimodal.en-US.md @@ -22,17 +22,17 @@ These design details are not very numerous, and for some models, they may not ne ## Custom input section -We provide an API for renderInputArea to help you support multi-modal situations, as well as integrate and interact with ProChat's data streams +We provide an API for inputAreaRender to help you support multi-modal situations, as well as integrate and interact with ProChat's data streams ```ts - renderInputArea?: ( + inputAreaRender?: ( defaultDom: ReactNode, onMessageSend: (message: string) => void | Promise, onClearAllHistory: () => void, ) => ReactNode; ``` -renderInputArea have three parameters: +inputAreaRender have three parameters: - defaultDom :The default rendering dom, if you want to wrap or add some small content, you can directly combine it on this basis - onMessageSend :The method of sending data, which is essentially the same as ProChat.sendMessage (Hooks), is used to send a data stream to ProChat @@ -42,7 +42,7 @@ Now you can freely combine the current content and various requirements you plan ## A demonstration case of uploading an image - + Let's break down this case in detail diff --git a/docs/guide/multimodal.md b/docs/guide/multimodal.md index 9213d690..8b5629c1 100644 --- a/docs/guide/multimodal.md +++ b/docs/guide/multimodal.md @@ -42,7 +42,7 @@ inputAreaRender 共有三个参数: ## 一个图片上传的演示案例 - + 我们来详细拆解下这个案例 diff --git a/docs/guide/servers-push.en-US.md b/docs/guide/servers-push.en-US.md index 1bc80d1a..022dcb2c 100644 --- a/docs/guide/servers-push.en-US.md +++ b/docs/guide/servers-push.en-US.md @@ -24,7 +24,7 @@ ProChat is very flexible in this situation, and we offer several methods to help ### Controlled mode -In this case, we waited for 3 seconds before actively pushing a notification, and then controlled it through chats and placed it in the last piece of content +In this case, we waited for 3 seconds before actively pushing a notification, and then controlled it through chatList and placed it in the last piece of content > In this case, we also used the render in chatitemRenderConfig to customize a special format of information. For more information about this API, please refer to [Deep Customization Conversation Content](./chatItemRenderConfig.md) diff --git a/docs/guide/servers-push.md b/docs/guide/servers-push.md index a28e29c4..97f506c0 100644 --- a/docs/guide/servers-push.md +++ b/docs/guide/servers-push.md @@ -25,7 +25,7 @@ ProChat 在这种情况下很灵活,我们提供几种方法来帮助你 ### 受控模式 -在这个案例里面,我们等待 3s 后主动推送了一条通知,然后通过 chats 进行受控放到了最后一条内容中 +在这个案例里面,我们等待 3s 后主动推送了一条通知,然后通过 chatList 进行受控放到了最后一条内容中 > 这个案例里面我们还使用了 chatItemRenderConfig 里面的 render 自定义了一条特殊格式的信息,关于这个 api 的更多信息可见[深度自定义对话内容](./chatItemRenderConfig.md) diff --git a/docs/guide/storage.en-US.md b/docs/guide/storage.en-US.md index 56ba2013..11a512f1 100644 --- a/docs/guide/storage.en-US.md +++ b/docs/guide/storage.en-US.md @@ -12,7 +12,7 @@ nav: ## Introduction -When using the ProChat component, you can initialize chat data through the `initialChats` property. This article explains how to use common browser caching strategies for initialization and populate that data into the `initialChats` attribute. +When using the ProChat component, you can initialize chat data through the `initialChatsList` property. This article explains how to use common browser caching strategies for initialization and populate that data into the `initialChatsList` attribute. > In actual business scenarios, data should typically reside on the backend and be distributed by it; however, this document provides examples of logic that only uses the frontend. @@ -24,12 +24,12 @@ localStorage is a persistent storage solution provided by browsers that allows d - During component loading, first check whether there exists cached chat data. - If cached data exists, retrieve it from localStorage -- Fill it into the initialChats property. +- Fill it into the initialChatsList property. - Update new content into the browser cache as needed ### Retrieving Cache Information -Step one involves fetching data from the cache and inserting it into ProChat's `initialChats` +Step one involves fetching data from the cache and inserting it into ProChat's `initialChatsList` > I've simulated some cached data here; in reality, these cached data will persist unless manually cleared by the browser, carrying over whatever content was previously stored. @@ -44,10 +44,10 @@ export default () => { const [cachedChats, setCachedChats] = useState(null); // Simulate adding some data to localStorage initially useEffect(() => { - const cachedData = localStorage.getItem('chats'); + const cachedData = localStorage.getItem('chatList'); if (!cachedData) { localStorage.setItem( - 'chats', + 'chatList', JSON.stringify({ ZGxiX2p4: { content: '昨天的当天是明天的什么?', @@ -71,7 +71,7 @@ export default () => { }, []); useEffect(() => { - const cachedData = localStorage.getItem('chats'); + const cachedData = localStorage.getItem('chatList'); if (cachedData) { setCachedChats(JSON.parse(cachedData)); } @@ -79,7 +79,7 @@ export default () => { return (
- {cachedChats ? : <>} + {cachedChats ? : <>}
); }; @@ -99,7 +99,7 @@ export default () => { const [cachedChats, setCachedChats] = useState(null); useEffect(() => { - const cachedData = localStorage.getItem('chats'); + const cachedData = localStorage.getItem('chatList'); if (cachedData) { setCachedChats(JSON.parse(cachedData)); } @@ -109,12 +109,12 @@ export default () => {
{cachedChats ? ( { + initialChatsList={cachedChats} + onChatsChange={(chatList) => { localStorage.setItem( - 'chats', + 'chatList', JSON.stringify({ - ...chats, + ...chatList, }), ); }} @@ -133,10 +133,10 @@ export default () => { ## Note -### What's the difference between initialChats and chats? +### What's the difference between initialChatsList and chatList? -From a logical perspective, initialChats is used only during initialization; the ProChat component will not update based on changes to initialChats. +From a logical perspective, initialChatsList is used only during initialization; the ProChat component will not update based on changes to initialChatsList. -On the other hand, chats is a controlled API, where any subsequent changes to chats will cause ProChat to update. If you can ensure that chats will trigger updates only once, then you could also use chats for initialization. +On the other hand, chatList is a controlled API, where any subsequent changes to chatList will cause ProChat to update. If you can ensure that chatList will trigger updates only once, then you could also use chatList for initialization. -> That's why if initialChats is empty initially, and later updated through a method like setState, ProChat won't update because initialization has already completed. Therefore, please ensure that the current value of initialChats is non-null when passed to ProChat. +> That's why if initialChatsList is empty initially, and later updated through a method like setState, ProChat won't update because initialization has already completed. Therefore, please ensure that the current value of initialChatsList is non-null when passed to ProChat. diff --git a/docs/guide/storage.md b/docs/guide/storage.md index 72a855b7..faa078ab 100644 --- a/docs/guide/storage.md +++ b/docs/guide/storage.md @@ -12,7 +12,7 @@ nav: ## 介绍 -在使用 ProChat 组件时,可以通过 `initialChats` 属性来初始化聊天数据。本文将介绍如何使用常用的浏览器缓存方案来进行初始化,并填充到 `initialChats` 中。 +在使用 ProChat 组件时,可以通过 `initialChatsList` 属性来初始化聊天数据。本文将介绍如何使用常用的浏览器缓存方案来进行初始化,并填充到 `initialChatsList` 中。 > 当然在真实的业务场景下,其实数据都应该存在后台,然后统一由后台进行派发,这里还是提供一些只使用前端的逻辑。 @@ -24,12 +24,12 @@ localStorage 是一种浏览器提供的持久化存储解决方案,可以将 - 在组件加载时,首先检查是否存在已经缓存的聊天数据。 - 如果存在缓存数据,则从 `localStorage` 中获取该数据。 -- 将获取到的数据填充到 `initialChats` 属性中。 +- 将获取到的数据填充到 `initialChatsList` 属性中。 - 更新新的内容到浏览器缓存中。 ### 拿到缓存信息 -第一步,从缓存中拿到数据并塞入到 ProChat 的 initialChats 中去。 +第一步,从缓存中拿到数据并塞入到 ProChat 的 initialChatsList 中去。 > 我在这里 mock 了缓存数据,真实情况下,这些缓存数据如果不手动清理,浏览器会带上上次你存好的内容。 @@ -44,10 +44,10 @@ export default () => { const [cachedChats, setCachedChats] = useState(null); // 模拟先让 localStorage 有一些数据 useEffect(() => { - const cachedData = localStorage.getItem('chats'); + const cachedData = localStorage.getItem('chatList'); if (!cachedData) { localStorage.setItem( - 'chats', + 'chatList', JSON.stringify({ ZGxiX2p4: { content: '昨天的当天是明天的什么?', @@ -71,7 +71,7 @@ export default () => { }, []); useEffect(() => { - const cachedData = localStorage.getItem('chats'); + const cachedData = localStorage.getItem('chatList'); if (cachedData) { setCachedChats(JSON.parse(cachedData)); } @@ -79,7 +79,7 @@ export default () => { return (
- {cachedChats ? : <>} + {cachedChats ? : <>}
); }; @@ -99,7 +99,7 @@ export default () => { const [cachedChats, setCachedChats] = useState(null); useEffect(() => { - const cachedData = localStorage.getItem('chats'); + const cachedData = localStorage.getItem('chatList'); if (cachedData) { setCachedChats(JSON.parse(cachedData)); } @@ -109,12 +109,12 @@ export default () => {
{cachedChats ? ( { + initialChatsList={cachedChats} + onChatsChange={(chatList) => { localStorage.setItem( - 'chats', + 'chatList', JSON.stringify({ - ...chats, + ...chatList, }), ); }} @@ -133,10 +133,10 @@ export default () => { ## 注意点 -### initialChats 和 chats 有什么不同? +### initialChatsList 和 chatList 有什么不同? -从语言逻辑上说 initialChats 只会作用于初始化的时候,ProChat 并不会随着 initialChats 的变化从而导致更新。 +从语言逻辑上说 initialChatsList 只会作用于初始化的时候,ProChat 并不会随着 initialChatsList 的变化从而导致更新。 -而 chats 是一个受控的 api,所有后续 chats 的变化都会导致 ProChat 进行更新,如果你可以保证 chats 只会触发一次,那么当然你也可以使用 chats 进行初始化。 +而 chatList 是一个受控的 api,所有后续 chatList 的变化都会导致 ProChat 进行更新,如果你可以保证 chatList 只会触发一次,那么当然你也可以使用 chatList 进行初始化。 -> 这也是为什么如果一开始 initialChats 为空,下次通过 SetState 等数据方法进行变化后,ProChat 不会更新的原因,因为初始化已经结束了,所以请保证给到当前的 initialChats 是有值的。 +> 这也是为什么如果一开始 initialChatsList 为空,下次通过 SetState 等数据方法进行变化后,ProChat 不会更新的原因,因为初始化已经结束了,所以请保证给到当前的 initialChatsList 是有值的。 diff --git a/package.json b/package.json index 777ae5bf..c62d7171 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "@ant-design/pro-chat", - "version": "1.12.0", + "version": "2.0.0", "description": "a solution for ai chat", "keywords": [ "ai", "ant-design", + "lui", "chat" ], "homepage": "https://github.com/ant-design/pro-chat", @@ -63,27 +64,15 @@ "@ant-design/icons": "^5.3.0", "@ant-design/pro-editor": "latest", "@babel/runtime": "^7.23.9", - "@emotion/react": "^11.11.4", - "@testing-library/jest-dom": "^6.4.2", "copy-to-clipboard": "^3.3.3", "dayjs": "^1.11.10", - "emoji-regex": "^10.3.0", - "fast-deep-equal": "^3.1.3", - "immer": "^10.0.3", "lodash-es": "^4.17.21", - "lucide-react": "^0.288.0", - "nanoid": "^5.0.6", "polished": "^4.3.1", - "rc-resize-observer": "^1.4.0", - "rc-util": "^5.38.2", - "react-intersection-observer": "^9.8.1", - "react-layout-kit": "^1.7.4", - "react-markdown": "^8.0.7", - "zustand": "^4.5.1", - "zustand-utils": "^1.3.2" + "rc-resize-observer": "^1.4.0" }, "devDependencies": { "@commitlint/cli": "^17.8.1", + "@testing-library/jest-dom": "^6.4.2", "@testing-library/react": "^14.2.1", "@types/chroma-js": "^2.4.4", "@types/glob": "^8.1.0", @@ -128,6 +117,11 @@ "antd-style": "^3", "react": "^18" }, + "optionalDependencies": { + "antd": "^5.14.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" diff --git a/src/ActionIcon/index.tsx b/src/ActionIcon/index.tsx deleted file mode 100644 index 173239de..00000000 --- a/src/ActionIcon/index.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import { Loader2 } from 'lucide-react'; -import { forwardRef, useMemo } from 'react'; - -import Icon, { type IconProps } from '@/Icon'; -import Spotlight from '@/components/Spotlight'; -import { DivProps } from '@/types'; -import { type TooltipProps } from 'antd'; - -import { ActionIcon as ProEditorActionIcon } from '@ant-design/pro-editor'; -import { useStyles } from './style'; - -export type ActionIconSize = - | 'large' - | 'normal' - | 'small' - | 'site' - | { - blockSize?: number; - borderRadius?: number; - fontSize?: number; - strokeWidth?: number; - }; - -const calcSize = (size?: ActionIconSize) => { - let blockSize: number; - let borderRadius: number; - - switch (size) { - case 'large': { - blockSize = 44; - borderRadius = 8; - break; - } - case 'normal': { - blockSize = 36; - borderRadius = 5; - break; - } - case 'small': { - blockSize = 24; - borderRadius = 5; - break; - } - case 'site': { - blockSize = 34; - borderRadius = 5; - break; - } - default: { - blockSize = size?.blockSize || 36; - borderRadius = size?.borderRadius || 5; - break; - } - } - - return { - blockSize, - borderRadius, - }; -}; - -export interface ActionIconProps extends DivProps { - /** - * @description Whether the icon is active or not - * @default false - */ - active?: boolean; - /** - * @description Change arrow's visible state and change whether the arrow is pointed at the center of target. - * @default false - */ - arrow?: boolean; - color?: IconProps['color']; - fill?: IconProps['fill']; - /** - * @description Glass blur style - * @default 'false' - */ - glass?: boolean; - /** - * @description The icon element to be rendered - * @type LucideIcon - */ - icon?: IconProps['icon']; - /** - * @description Set the loading status of ActionIcon - */ - loading?: boolean; - - /** - * @description The position of the tooltip relative to the target - * @enum ["top","left","right","bottom","topLeft","topRight","bottomLeft","bottomRight","leftTop","leftBottom","rightTop","rightBottom"] - * @default "top" - */ - placement?: TooltipProps['placement']; - - /** - * @description Size of the icon - * @default 'normal' - */ - size?: ActionIconSize; - /** - * @description Whether add spotlight background - * @default false - */ - spotlight?: boolean; - /** - * @description The text shown in the tooltip - */ - title?: string; - /** - * @description Mouse enter delay of tooltip - * @default 0.5 - */ - tooltipDelay?: number; -} - -const ActionIcon = forwardRef((props, ref) => { - const { - color, - fill, - className, - active, - icon, - size = 'normal', - style, - glass, - spotlight, - onClick, - children, - loading, - title, - placement, - arrow = false, - tooltipDelay = 0.5, - ...rest - } = props; - - const { styles, cx } = useStyles({ active: Boolean(active), glass: Boolean(glass) }); - - const { blockSize, borderRadius } = useMemo(() => calcSize(size), [size]); - - const content = ( - <> - {icon && ( - - )} - {children} - - ); - - const spin = ; - - const actionIconBlock = ( -
- {spotlight && } - {loading ? spin : content} -
- ); - - return ( - <> - - - ); -}); - -export default ActionIcon; diff --git a/src/ActionIcon/style.ts b/src/ActionIcon/style.ts deleted file mode 100644 index 7dd47e29..00000000 --- a/src/ActionIcon/style.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createStyles } from 'antd-style'; - -export const useStyles = createStyles( - ({ css, stylish, cx }, { glass }: { active: boolean; glass: boolean }) => { - return { - block: cx( - glass && stylish.blur, - css` - cursor: pointer; - - position: relative; - - display: flex; - flex: none; - align-items: center; - justify-content: center; - `, - ), - }; - }, -); diff --git a/src/ActionIconGroup/index.tsx b/src/ActionIconGroup/index.tsx deleted file mode 100644 index 84c9d145..00000000 --- a/src/ActionIconGroup/index.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import ActionIcon, { ActionIconProps } from '@/ActionIcon'; -import Icon from '@/Icon'; -import Spotlight from '@/components/Spotlight'; -import { ActionGroup as ProEditorActionGroup } from '@ant-design/pro-editor'; - -import { DropdownProps } from 'antd'; -import { type LucideIcon } from 'lucide-react'; -import { memo } from 'react'; - -import { DivProps } from '@/types'; - -export interface ActionIconGroupItems { - icon: LucideIcon; - key: string; - label: string; -} - -export interface ActionEvent { - item: ActionIconGroupItems; - key: string; - keyPath: string[]; -} - -export interface ActionIconGroupProps extends Omit { - /** - * @description The direction of the icons - * @default "row" - */ - direction?: 'row' | 'column'; - /** - * @description The menu items for the dropdown - */ - dropdownMenu?: (ActionIconGroupItems | { type: 'divider' })[]; - /** - * @description The items to be rendered - * @default [] - */ - items?: ActionIconGroupItems[]; - onActionClick?: (action: ActionEvent) => void; - /** - * @description The position of the tooltip relative to the target - * @enum ["top","left","right","bottom","topLeft","topRight","bottomLeft","bottomRight","leftTop","leftBottom","rightTop","rightBottom"] - */ - placement?: ActionIconProps['placement']; - /** - * @description Whether to add a spotlight background - * @default true - */ - spotlight?: boolean; - /** - * @description The type of the group - * @default "block" - */ - type?: 'ghost' | 'block' | 'pure'; -} - -const ActionIconGroup = memo( - ({ - type = 'block', - items = [], - placement, - spotlight = false, - direction = 'row', - dropdownMenu = [], - onActionClick, - className, - style, - }) => { - const tooltipsPlacement = placement || (direction === 'column' ? 'right' : 'top'); - - const mergeDropDownList = dropdownMenu?.map((item: any) => { - return { - ...item, - icon: , - onClick: onActionClick - ? (info: ActionEvent) => - onActionClick({ - item, - key: info.key, - keyPath: info.keyPath, - }) - : undefined, - }; - }); - - return ( - { - return ( - <> - {spotlight && } - {items?.length > 0 && - items.map((item) => ( - onActionClick?.({ item, key: item.key, keyPath: [item.key] }) - : undefined - } - placement={tooltipsPlacement} - size="small" - title={item.label} - /> - ))} - - ); - }} - /> - ); - }, -); - -export default ActionIconGroup; diff --git a/src/BackBottom/demos/index.tsx b/src/BackBottom/demos/index.tsx deleted file mode 100644 index 9b6c8520..00000000 --- a/src/BackBottom/demos/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { BackBottom } from '@ant-design/pro-chat'; -import { useRef } from 'react'; - -export default () => { - const ref = useRef(null); - return ( -
-
- {Array.from({ length: 40 }) - .fill('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') - .map((item: any, index) => ( -

{item}

- ))} -
- -
- ); -}; diff --git a/src/BackBottom/index.en-US.md b/src/BackBottom/index.en-US.md deleted file mode 100644 index c65be378..00000000 --- a/src/BackBottom/index.en-US.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -nav: Components -group: Chat -title: BackBottom -order: 10 ---- - -## Default - - - -## APIs - - diff --git a/src/BackBottom/index.md b/src/BackBottom/index.md deleted file mode 100644 index ca7939b6..00000000 --- a/src/BackBottom/index.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -nav: 组件 -group: Chat -title: BackBottom -order: 10 ---- - -## Default - - - -## APIs - - diff --git a/src/BackBottom/index.tsx b/src/BackBottom/index.tsx deleted file mode 100644 index 75465d56..00000000 --- a/src/BackBottom/index.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import { Button, type BackTopProps } from 'antd'; -import { ListEnd } from 'lucide-react'; -import { MouseEventHandler, useEffect, useMemo, useRef, useState, type CSSProperties } from 'react'; - -import Icon from '@/Icon'; -import { useStyles } from './style'; - -export interface BackBottomProps { - className?: string; - /** - * @description - * 点击的回调 - */ - onClick?: BackTopProps['onClick']; - style?: CSSProperties; - target: React.RefObject; - text?: string; - visibilityHeight?: BackTopProps['visibilityHeight']; - /** - * @description 自定义渲染 dom - * @param defaultDom - * @param scrollToBottom - * @param BackBottomConfig - * @returns React.ReactNode - */ - render?: ( - defaultDom: React.ReactNode, - scrollToBottom: MouseEventHandler, - BackBottomConfig: BackBottomProps, - ) => React.ReactNode; - /** - * @description - * 是否一直显示 - */ - alwaysShow?: boolean; -} - -const BackBottom = (props: BackBottomProps) => { - const { - visibilityHeight = 240, - target, - onClick, - style, - className, - text, - render, - alwaysShow = false, - } = props || {}; - const [visible, setVisible] = useState(alwaysShow); - const { styles, cx } = useStyles(visible); - const ref = useRef(null); - - const [isWindowAvailable, setIsWindowAvailable] = useState(false); - - useEffect(() => { - // 检查window对象是否已经可用 - if (typeof window !== 'undefined') { - setIsWindowAvailable(true); - } - }, []); - - const current = useMemo(() => { - if (target.current && target.current.scrollHeight > target.current.clientHeight) { - return target.current; - } - return document.body; - }, [isWindowAvailable]); - - const scrollHeight = current?.scrollHeight || 0; - const clientHeight = current?.clientHeight || 0; - const [scroll, setScroll] = useState({ top: 0, left: 0 }); - - const timeRef = useRef(null); - - useEffect(() => { - if (typeof window === 'undefined') return; - if (typeof current === 'undefined') return; - const scroll = () => { - timeRef.current = window.setTimeout(() => { - if (!alwaysShow) { - setVisible(current?.scrollTop + clientHeight + visibilityHeight < scrollHeight); - } - setScroll({ - top: current?.scrollTop, - left: current?.scrollLeft, - }); - }, 60); - }; - current?.addEventListener?.('scroll', scroll, { - passive: true, - }); - return () => { - if (timeRef.current) { - clearTimeout(timeRef.current); - } - current?.removeEventListener?.('scroll', scroll); - }; - }, [current]); - - useEffect(() => { - if (scroll?.top && !alwaysShow) { - setVisible(scroll?.top + clientHeight + visibilityHeight < scrollHeight); - } - }, [scrollHeight, scroll, visibilityHeight, current]); - - const scrollToBottom: MouseEventHandler = (e) => { - (target as any)?.current?.scrollTo({ behavior: 'smooth', left: 0, top: scrollHeight }); - onClick?.(e); - }; - - /** - * @description - * 为了解决在使用了 ProChatProvider 的情况下,BackBottom 无法正常工作的问题 - */ - useEffect(() => { - setTimeout(() => { - (target as any)?.current?.scrollTo({ behavior: 'smooth', left: 0, top: scrollHeight }); - }, 16); - }, []); - - const defauleDom = ( - - ); - - if (render) return render(defauleDom, scrollToBottom, props); - - return defauleDom; -}; - -export default BackBottom; diff --git a/src/BackBottom/style.ts b/src/BackBottom/style.ts deleted file mode 100644 index f5e24669..00000000 --- a/src/BackBottom/style.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { createStyles } from 'antd-style'; - -export const useStyles = createStyles(({ token, css, stylish, cx }, visible: boolean) => - cx( - stylish.blur, - css` - pointer-events: ${visible ? 'all' : 'none'}; - - transform: translateY(${visible ? 0 : '16px'}); - - padding-inline: 12px !important; - - opacity: ${visible ? 1 : 0}; - background: ${token.colorFillSecondary}; - border-color: ${token.colorFillTertiary} !important; - border-radius: 16px !important; - backdrop-filter: blur(16px); - `, - ), -); diff --git a/src/ChatItem/components/Loading.tsx b/src/ChatItem/components/Loading.tsx deleted file mode 100644 index 7d83517c..00000000 --- a/src/ChatItem/components/Loading.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Loader2 } from 'lucide-react'; -import { memo } from 'react'; -import { Flexbox } from 'react-layout-kit'; - -import { ChatItemProps } from '@/ChatItem'; -import Icon from '@/Icon'; - -import { useStyles } from '../style'; - -export interface LoadingProps { - loading?: ChatItemProps['loading']; - placement?: ChatItemProps['placement']; -} - -const Loading = memo(({ loading, placement }) => { - const { styles } = useStyles({ placement }); - - if (!loading) return null; - - return ( - - - - ); -}); - -export default Loading; diff --git a/src/ChatList/ActionsBar.tsx b/src/ChatList/ActionsBar.tsx deleted file mode 100644 index 8380d4dd..00000000 --- a/src/ChatList/ActionsBar.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { memo } from 'react'; - -import ActionIconGroup, { type ActionIconGroupProps } from '@/ActionIconGroup'; -import { useChatListActionsBar } from '@/hooks/useChatListActionsBar'; - -/** - * ActionsBar组件的属性类型定义 - */ -export interface ActionsBarProps extends ActionIconGroupProps { - /** - * 文本内容 - */ - text?: { - /** - * 复制文本 - */ - copy?: string; - /** - * 删除文本 - */ - delete?: string; - /** - * 编辑文本 - */ - edit?: string; - /** - * 重新生成文本 - */ - regenerate?: string; - }; - /** - * 内容 - */ - content?: React.ReactNode | undefined; -} - -/** - * ActionsBar 组件 - * 用于渲染操作按钮组。 - */ -const ActionsBar = memo(({ text, ...rest }) => { - const { regenerate, edit, copy, divider, del } = useChatListActionsBar(text); - return ( - - ); -}); - -export default ActionsBar; diff --git a/src/ChatList/HistoryDivider.tsx b/src/ChatList/HistoryDivider.tsx deleted file mode 100644 index 497067b4..00000000 --- a/src/ChatList/HistoryDivider.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Divider } from 'antd'; -import { Timer } from 'lucide-react'; -import { memo } from 'react'; - -import Icon from '@/Icon'; -import Tag from '@/components/Tag'; - -/** - * 历史记录分割线组件的属性。 - */ -interface HistoryDividerProps { - /** - * 是否启用分割线。 - */ - enable?: boolean; - /** - * 分割线文本。 - */ - text?: string; -} - -/** - * 历史记录分割线组件。 - */ -const HistoryDivider = memo(({ enable, text }) => { - if (!enable) return null; - - return ( -
- - }>{text || 'History Message'} - -
- ); -}); - -export default HistoryDivider; diff --git a/src/ChatList/ShouldUpdateItem.tsx b/src/ChatList/ShouldUpdateItem.tsx deleted file mode 100644 index 7cc769d9..00000000 --- a/src/ChatList/ShouldUpdateItem.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import isEqual from 'fast-deep-equal'; -import { Component } from 'react'; -/** - * 组件用于判断是否需要更新的辅助类。 - */ -class ShouldUpdateItem extends Component< - { - shouldUpdate?: (prevProps: any, nextProps: any) => boolean; - children: React.ReactNode; - [key: string]: any; - }, - any -> { - /** - * 判断组件是否需要更新。 - * @param nextProps - 下一个属性对象。 - * @returns 如果需要更新则返回 true,否则返回 false。 - */ - shouldComponentUpdate(nextProps: any) { - if (nextProps.shouldUpdate) { - return nextProps.shouldUpdate(this.props, nextProps); - } - try { - return ( - !isEqual(this.props.content, nextProps?.content) || - !isEqual(this.props.loading, nextProps?.loading) || - !isEqual(this.props.chatItemRenderConfig, nextProps?.chatItemRenderConfig) || - !isEqual(this.props.meta, nextProps?.meta) - ); - } catch (error) { - return true; - } - } - - render() { - return this.props.children; - } -} - -export default ShouldUpdateItem; diff --git a/src/ChatList/index.tsx b/src/ChatList/index.tsx deleted file mode 100644 index 39f61c9c..00000000 --- a/src/ChatList/index.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import { Fragment, memo, useContext } from 'react'; - -import type { ChatMessage, DivProps } from '@/types'; - -import { ConfigProvider } from 'antd'; -import ChatItem, { ChatListItemProps, ListItemProps } from './ChatListItem'; -import HistoryDivider from './HistoryDivider'; -import ShouldUpdateItem from './ShouldUpdateItem'; -import { useStyles } from './style'; - -export interface ChatListProps extends DivProps, ListItemProps { - /** - * @description Data of chat messages to be displayed - */ - data: ChatMessage[]; - enableHistoryCount?: boolean; - historyCount?: number; - loadingId?: string; - itemShouldUpdate?: (prevProps: ChatListItemProps, nextProps: ChatListItemProps) => boolean; -} -export type { - OnActionClick, - OnMessageChange, - RenderAction, - RenderErrorMessage, - RenderItem, - RenderMessage, - RenderMessageExtra, -} from './ChatListItem'; - -/** - * ChatList组件用于显示聊天列表。 - * - * @component - * @param {Object} props - 组件属性 - * @param {Function} props.onActionsClick - 点击操作按钮时的回调函数 - * @param {Function} props.renderMessagesExtra - 渲染额外的消息内容的回调函数 - * @param {string} props.className - 自定义类名 - * @param {Array} props.data - 聊天数据数组 - * @param {string} [props.type='chat'] - 聊天类型,默认为'chat' - * @param {string} props.text - 文本内容 - * @param {boolean} props.showTitle - 是否显示标题 - * @param {Function} props.itemShouldUpdate - 判断聊天项是否需要更新的回调函数 - * @param {Function} props.onMessageChange - 消息内容变化时的回调函数 - * @param {Function} props.renderMessages - 渲染消息内容的回调函数 - * @param {Function} props.renderErrorMessages - 渲染错误消息的回调函数 - * @param {string} props.loadingId - 正在加载的聊天项的ID - * @param {Function} props.renderItems - 渲染聊天项的回调函数 - * @param {boolean} props.enableHistoryCount - 是否启用历史记录计数 - * @param {Function} props.renderActions - 渲染操作按钮的回调函数 - * @param {number} [props.historyCount=0] - 历史记录计数 - * @param {Object} props.chatItemRenderConfig - 聊天项渲染配置 - * @returns {JSX.Element} 聊天列表组件 - */ -const ChatList = memo( - ({ - onActionsClick, - renderMessagesExtra, - className, - data, - type = 'chat', - text, - showTitle, - itemShouldUpdate, - onMessageChange, - renderMessages, - renderErrorMessages, - loadingId, - renderItems, - enableHistoryCount, - renderActions, - historyCount = 0, - chatItemRenderConfig, - markdownProps, - ...props - }) => { - const { cx, styles } = useStyles(); - const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); - const prefixClass = getPrefixCls('pro-chat'); - - return ( -
- {data.map((item, index) => { - const itemProps = { - loading: loadingId === item.id, - onActionsClick, - onMessageChange, - renderActions, - renderErrorMessages, - renderItems, - renderMessages, - renderMessagesExtra, - showTitle, - text, - type, - }; - - const historyLength = data.length; - const enableHistoryDivider = - enableHistoryCount && - historyLength > historyCount && - historyCount === historyLength - index + 1; - - return ( - - - - - - - ); - })} -
- ); - }, -); - -export default ChatList; diff --git a/src/ChatList/style.ts b/src/ChatList/style.ts deleted file mode 100644 index e684626a..00000000 --- a/src/ChatList/style.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createStyles } from 'antd-style'; - -export const useStyles = createStyles(({ css }) => { - return { - container: css` - position: relative; - `, - }; -}); diff --git a/src/EditableMessage/demos/index.tsx b/src/EditableMessage/demos/index.tsx deleted file mode 100644 index 61801d6a..00000000 --- a/src/EditableMessage/demos/index.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { EditableMessage } from '@ant-design/pro-chat'; -import { useState } from 'react'; - -export const content = `# This is an H1 -## This is an H2 -### This is an H3 -#### This is an H4 -##### This is an H5 - -The point of reference-style links is not that they’re easier to write. The point is that with reference-style links, your document source is vastly more readable. Compare the above examples: using reference-style links, the paragraph itself is only 81 characters long; with inline-style links, it’s 176 characters; and as raw \`HTML\`, it’s 234 characters. In the raw \`HTML\`, there’s more markup than there is text. - ---- - -> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, -> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. -> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. -> -> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse -> id sem consectetuer libero luctus adipiscing. - ---- - -an example | *an example* | **an example** - ---- - -1. Bird -1. McHale -1. Parish - 1. Bird - 1. McHale - 1. Parish - ---- - -- Red -- Green -- Blue - - Red - - Green - - Blue - ---- - -This is [an example](http://example.com/ "Title") inline link. - - - - -| title | title | title | -| --- | --- | --- | -| content | content | content | - - -\`\`\`bash -$ pnpm install -\`\`\` - - -\`\`\`javascript -import { renderHook } from '@testing-library/react-hooks'; -import { act } from 'react-dom/test-utils'; -import { useDropNodeOnCanvas } from './useDropNodeOnCanvas'; -\`\`\` - ---- - -以下是一段Markdown格式的LaTeX数学公式: - -我是一个行内公式:$E=mc^2$ - -我是一个独立公式: -$$ -\\sum_{i=1}^{n} x_i = x_1 + x_2 + \\ldots + x_n -$$ - -我是一个带有分式的公式: -$$ -\\frac{{n!}}{{k!(n-k)!}} = \\binom{n}{k} -$$ - -我是一个带有上下标的公式: -$$ -x^{2} + y^{2} = r^{2} -$$ - -我是一个带有积分符号的公式: -$$ -\\int_{a}^{b} f(x) \\, dx -$$ -`; - -export default () => { - const [openModal, setOpenModal] = useState(false); - const [editing, setEdit] = useState(false); - - return ( - - ); -}; diff --git a/src/EditableMessage/index.en-US.md b/src/EditableMessage/index.en-US.md deleted file mode 100644 index 0c59d0ec..00000000 --- a/src/EditableMessage/index.en-US.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -nav: Components -group: Message -title: EditableMessage -description: The EditableMessage component is used to display a message that can be edited by the user. It consists of a Markdown component and an optional modal for editing the message. When the user clicks on the message, it enters editing mode and displays an input field for editing the message. ---- - -## Default - - - -## APIs - - diff --git a/src/EditableMessage/index.md b/src/EditableMessage/index.md deleted file mode 100644 index 41d196a0..00000000 --- a/src/EditableMessage/index.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -nav: 组件 -group: Message -title: EditableMessage -description: The EditableMessage component is used to display a message that can be edited by the user. It consists of a Markdown component and an optional modal for editing the message. When the user clicks on the message, it enters editing mode and displays an input field for editing the message. ---- - -## Default - - - -## APIs - - diff --git a/src/EditableMessage/index.tsx b/src/EditableMessage/index.tsx deleted file mode 100644 index 76765afb..00000000 --- a/src/EditableMessage/index.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { useMergedState } from 'rc-util'; -import { CSSProperties, memo } from 'react'; - -import MessageInput, { type MessageInputProps } from '@/MessageInput'; -import MessageModal, { type MessageModalProps } from '@/MessageModal'; -import { Markdown, MarkdownProps } from '@ant-design/pro-editor'; - -export interface EditableMessageProps { - /** - * @title The class name for the Markdown and MessageInput component - */ - classNames?: { - /** - * @title The class name for the MessageInput component - */ - input?: string; - textarea?: string; - }; - editButtonSize?: MessageInputProps['editButtonSize']; - /** - * @title Whether the component is in edit mode or not - * @default false - */ - editing?: boolean; - fullFeaturedCodeBlock?: boolean; - height?: MessageInputProps['height']; - inputType?: MessageInputProps['type']; - model?: { - extra?: MessageModalProps['extra']; - footer?: MessageModalProps['footer']; - }; - /** - * @title Callback function when the value changes - * @param value - The new value - */ - onChange?: (value: string) => void; - /** - * @title Callback function when the editing state changes - * @param editing - Whether the component is in edit mode or not - */ - onEditingChange?: (editing: boolean) => void; - /** - * @title Callback function when the modal open state changes - * @param open - Whether the modal is open or not - */ - onOpenChange?: (open: boolean) => void; - /** - * @title Whether the modal is open or not - * @default false - */ - openModal?: boolean; - placeholder?: string; - /** - * @title Whether to show the edit button when the text value is empty - * @default false - */ - showEditWhenEmpty?: boolean; - styles?: { - /** - * @title The style for the MessageInput component - */ - input?: CSSProperties; - }; - text?: MessageModalProps['text']; - /** - * @title The current text value - */ - value: string; - /** - * @title The props for the Markdown component - */ - markdownProps?: MarkdownProps; -} - -const EditableMessage = memo( - ({ - value, - onChange, - classNames = {}, - onEditingChange, - editing, - openModal, - onOpenChange, - placeholder = 'Type something...', - showEditWhenEmpty = false, - styles, - height, - inputType, - editButtonSize, - text, - model, - markdownProps, - }) => { - const [isEdit, setTyping] = useMergedState(false, { - onChange: onEditingChange, - value: editing, - }); - - const [expand, setExpand] = useMergedState(false, { - onChange: onOpenChange, - value: openModal, - }); - - const isAutoSize = height === 'auto'; - - const input = ( - setTyping(false)} - onConfirm={(text) => { - onChange?.(text); - setTyping(false); - }} - placeholder={placeholder} - style={styles?.input} - text={text} - textareaClassname={classNames?.input} - type={inputType} - /> - ); - - if (!value && showEditWhenEmpty) return input; - - return ( - <> - {!expand && isEdit ? ( - input - ) : ( - - {value || placeholder} - - )} - onChange?.(text)} - onEditingChange={setTyping} - onOpenChange={(e) => { - setExpand(e); - setTyping(false); - }} - markdownProps={markdownProps} - open={expand} - placeholder={placeholder} - text={text} - value={value} - /> - - ); - }, -); - -export default EditableMessage; diff --git a/src/EditableMessageList/demos/data.ts b/src/EditableMessageList/demos/data.ts deleted file mode 100644 index e82b5155..00000000 --- a/src/EditableMessageList/demos/data.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { LLMMessage } from '@ant-design/pro-chat'; - -export const data: LLMMessage[] = [ - { - content: - '| **量化等级** | **最低 GPU 显存**(推理) | **最低 GPU 显存**(高效参数微调) |\n| -------------- | ------------------------- | --------------------------------- |\n| FP16(无量化) | 13 GB | 14 GB |\n| INT8 | 8 GB | 9 GB |\n| INT4 | 6 GB | 7 GB |\n\n请解释 FP16 、INT8、INT4 的意思?', - role: 'user', - }, - { - content: - 'FP16、INT8、INT4 是量化技术中常用的三种精度级别。它们是用来减小模型的计算量和内存占用的一种方式,从而加速推理和高效参数微调的过程。\n\nFP16 表示使用半精度浮点数(16 位)来表示模型参数和激活值,相比于单精度浮点数(32 位)可以减少一半的内存占用和计算量,但是可能会损失一些精度。\n\nINT8 表示使用 8 位整数来表示模型参数和激活值,相比于 FP16 可以进一步减少内存占用和计算量,但是需要进行量化训练和量化后的推理过程。\n\nINT4 表示使用 4 位整数来表示模型参数和激活值,相比于 INT8 可以进一步减少内存占用和计算量,但是需要进行更加复杂的量化训练和量化后的推理过程,且精度降低更明显。', - role: 'assistant', - }, - { - content: - '对比项\t中文LLaMA\t中文Alpaca\n训练方式\t传统CLM (在通用语料上训练)\t指令精调 (在指令数据上训练)\n\nCLM 和指令精调是什么意思?', - role: 'user', - }, - { - content: - 'CLM 是 Continual Language Model 的缩写,指的是基于大规模通用语料库的语言模型。这种模型通常使用 Transformer 结构,通过无监督学习的方式预测下一个词,从而学习语言的统计规律和语义表示。CLM 可以被用于多种自然语言处理任务中,如文本生成、机器翻译、语言理解等。\n\n指令精调(Instruction-based Fine-tuning)是一种在指令数据上进行微调的方法。在这种方法中,模型首先在大规模通用语料上进行训练,然后在特定领域的指令数据上进行微调,以适应该领域的特定需求。指令数据通常是一些特定领域的语料库,比如医学、法律、金融等。指令精调可以提高模型在特定领域的表现,同时保留模型在通用语料上的语言表示能力。', - role: 'assistant', - }, - { - content: 'SOTA是什么意思', - role: 'user', - }, - { - content: - 'SOTA 是 State-Of-The-Art 的缩写,意为“最先进的技术”或“最高水平的技术”。在各个领域,SOTA 指代的是当前最优秀的技术或方法,通常是指在某个任务或问题上取得的最高性能指标。在机器学习、自然语言处理、计算机视觉等领域,SOTA 是一种非常重要的标志,代表着该领域的最高水平和技术进展。SOTA 的不断更新和提升,反映了该领域的技术发展和研究进展。', - role: 'assistant', - }, - { - content: - 'Since the FastChat (Vicuna) repository doesn’t yet support GPTQ-quantized models, I have integrated the GPTQ-for-LLaMa repository into this fork to run a GPTQ-quantized model. Why should we use the GPTQ-quantized version of the Vicuna model? By using the GPTQ-quantized version, we can reduce the VRAM requirement from 28 GB to about 10 GB, which allows us to run the Vicuna-13B model on a single consumer GPU. Another advantage is the ~3x speedup during inference when using the quantized model version. Any disadvantages? Yes, the quantized model is slightly less precise and therefore performs slightly worse than the full precision model. However, it is the quantization of the model that allows many of us to use the model at all. The following figure from the GPTQ paper shows that, especially for larger language models, the qualitative degradation due to the application of quantization is small:\n\n请解释 什么是 GPTQ', - role: 'user', - }, - { - content: - 'GPTQ 是 GPT-Quantized 的缩写,是一种基于量化技术的 GPT 模型。GPTQ 使用定点数(Fixed-Point Number)来表示模型参数和激活值,相比于浮点数可以减小模型的计算量和内存占用,从而提高模型的推理速度和效率。同时,GPTQ 还采用了一些量化技巧和优化策略,如对称量化、非线性量化、动态范围调整等,以保证模型在量化后仍然能够保持较高的精度和性能。\n\n在上述引用中,提到了将 GPTQ 应用于 Vicuna 模型的优点,即可以将 VRAM 要求从 28 GB 减少到约 10 GB,从而可以在单个消费级 GPU 上运行 Vicuna-13B 模型,并且推理速度可以提高约 3 倍。但是,GPTQ 模型的缺点是精度稍低,表现可能略逊于全精度模型。不过,对于大型语言模型而言,应用量化技术带来的质量下降是较小的,因此 GPTQ 可以在一定程度上平衡模型的精度和效率。', - role: 'assistant', - }, -]; diff --git a/src/EditableMessageList/demos/index.tsx b/src/EditableMessageList/demos/index.tsx deleted file mode 100644 index fcd4c126..00000000 --- a/src/EditableMessageList/demos/index.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { EditableMessageList } from '@ant-design/pro-chat'; - -import { data } from './data'; - -export default () => ; diff --git a/src/EditableMessageList/index.en-US.md b/src/EditableMessageList/index.en-US.md deleted file mode 100644 index 88018b7d..00000000 --- a/src/EditableMessageList/index.en-US.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -nav: Components -group: Message -title: EditableMessageList -description: EditableMessageList is a React component that allows users to edit a list of chat messages, including their content and role. It is designed to be used in chatbot building applications. ---- - -## Default - - - -## APIs - - diff --git a/src/EditableMessageList/index.md b/src/EditableMessageList/index.md deleted file mode 100644 index e0706d09..00000000 --- a/src/EditableMessageList/index.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -nav: 组件 -group: Message -title: EditableMessageList -description: EditableMessageList is a React component that allows users to edit a list of chat messages, including their content and role. It is designed to be used in chatbot building applications. ---- - -## Default - - - -## APIs - - diff --git a/src/EditableMessageList/index.tsx b/src/EditableMessageList/index.tsx deleted file mode 100644 index 9b826355..00000000 --- a/src/EditableMessageList/index.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { Button, Select } from 'antd'; -import isEqual from 'fast-deep-equal'; -import { Plus, Trash } from 'lucide-react'; -import { memo, useEffect, useReducer } from 'react'; -import { Flexbox } from 'react-layout-kit'; - -import ActionIcon from '@/ActionIcon'; -import Icon from '@/Icon'; -import { ControlInput } from '@/components/ControlInput'; -import { LLMMessage } from '@/types/llm'; - -import { messagesReducer } from './messageReducer'; - -export interface EditableMessageListProps { - /** - * @description The data sources to be rendered - */ - dataSources: LLMMessage[]; - /** - * @description Whether the component is disabled or not - * @default false - */ - disabled?: boolean; - /** - * @description Callback function triggered when the data sources are changed - * @param chatMessages - the updated data sources - */ - onChange?: (chatMessages: LLMMessage[]) => void; -} - -export const EditableMessageList = memo( - ({ disabled, dataSources, onChange }) => { - const [chatMessages, dispatch] = useReducer(messagesReducer, dataSources); - - useEffect(() => { - if (!isEqual(dataSources, chatMessages)) { - onChange?.(chatMessages); - } - }, [chatMessages]); - - return dataSources ? ( - - {chatMessages.map((item, index) => ( - -