@lobehub/chat 0.118.5 → 0.118.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/next.config.mjs +0 -1
  3. package/package.json +1 -1
  4. package/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx +1 -1
  5. package/src/features/Conversation/{ChatList/Actions → Actions}/Assistant.tsx +3 -1
  6. package/src/features/Conversation/{ChatList/Actions → Actions}/Error.tsx +3 -1
  7. package/src/features/Conversation/{ChatList/Actions → Actions}/Fallback.tsx +4 -1
  8. package/src/features/Conversation/{ChatList/Actions → Actions}/Function.tsx +4 -1
  9. package/src/features/Conversation/{ChatList/Actions → Actions}/User.tsx +3 -1
  10. package/src/features/Conversation/{ChatList/Actions → Actions}/index.ts +1 -2
  11. package/src/features/Conversation/{ChatList/Error → Error}/InvalidAccess.tsx +2 -1
  12. package/src/features/Conversation/{ChatList/Error → Error}/OpenAPIKey.tsx +1 -1
  13. package/src/features/Conversation/{ChatList/Error → Error}/OpenAiBizError.tsx +2 -1
  14. package/src/features/Conversation/{ChatList/Error → Error}/Plugin/PluginError.tsx +3 -1
  15. package/src/features/Conversation/{ChatList/Error → Error}/Plugin/PluginSettings.tsx +2 -1
  16. package/src/features/Conversation/{ChatList/Error → Error}/index.tsx +1 -1
  17. package/src/features/Conversation/{ChatList/Extras → Extras}/Translate.tsx +1 -1
  18. package/src/features/Conversation/{ChatList/Extras → Extras}/index.ts +1 -2
  19. package/src/features/Conversation/{ChatList/Messages → Messages}/Default.tsx +1 -1
  20. package/src/features/Conversation/{ChatList/Messages → Messages}/User.tsx +1 -1
  21. package/src/features/Conversation/{ChatList/Messages → Messages}/index.ts +5 -5
  22. package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/Loading.tsx +10 -11
  23. package/src/features/Conversation/components/ChatList/ActionsBar.tsx +27 -0
  24. package/src/features/Conversation/components/ChatList/HistoryDivider.tsx +23 -0
  25. package/src/features/Conversation/components/ChatList/Item.tsx +236 -0
  26. package/src/features/Conversation/components/ChatList/index.tsx +88 -0
  27. package/src/features/Conversation/components/ChatList/style.ts +10 -0
  28. package/src/features/Conversation/{ChatList → container}/index.tsx +6 -7
  29. package/src/features/Conversation/hooks/useChatListActionsBar.tsx +43 -0
  30. package/src/features/Conversation/index.tsx +3 -3
  31. package/src/store/middleware/createHyperStorage/index.test.ts +341 -0
  32. package/src/store/middleware/createHyperStorage/indexedDB.test.ts +64 -0
  33. package/src/store/middleware/createHyperStorage/urlStorage.test.ts +84 -0
  34. package/src/store/middleware/createHyperStorage/urlStorage.ts +25 -8
  35. /package/src/features/Conversation/{ChatList/Actions → Actions}/customAction.ts +0 -0
  36. /package/src/features/Conversation/{ChatList/Error → Error}/ApiKeyForm.tsx +0 -0
  37. /package/src/features/Conversation/{ChatList/Error → Error}/ErrorActionContainer.tsx +0 -0
  38. /package/src/features/Conversation/{ChatList/Error → Error}/style.tsx +0 -0
  39. /package/src/features/Conversation/{ChatList/Extras → Extras}/Assistant.test.tsx +0 -0
  40. /package/src/features/Conversation/{ChatList/Extras → Extras}/Assistant.tsx +0 -0
  41. /package/src/features/Conversation/{ChatList/Extras → Extras}/ExtraContainer.tsx +0 -0
  42. /package/src/features/Conversation/{ChatList/Extras → Extras}/TTS/FilePlayer.tsx +0 -0
  43. /package/src/features/Conversation/{ChatList/Extras → Extras}/TTS/InitPlayer.tsx +0 -0
  44. /package/src/features/Conversation/{ChatList/Extras → Extras}/TTS/Player.tsx +0 -0
  45. /package/src/features/Conversation/{ChatList/Extras → Extras}/TTS/index.tsx +0 -0
  46. /package/src/features/Conversation/{ChatList/Extras → Extras}/User.tsx +0 -0
  47. /package/src/features/Conversation/{ChatList/Extras → Extras}/type.ts +0 -0
  48. /package/src/features/Conversation/{ChatList/Messages → Messages}/Assistant.tsx +0 -0
  49. /package/src/features/Conversation/{ChatList/Messages → Messages}/Function.tsx +0 -0
  50. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Inspector/PluginResultJSON.tsx +0 -0
  51. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Inspector/Settings.tsx +0 -0
  52. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Inspector/index.tsx +0 -0
  53. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Inspector/style.ts +0 -0
  54. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/BuiltinType/index.test.tsx +0 -0
  55. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/BuiltinType/index.tsx +0 -0
  56. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/DefaultType/IFrameRender/index.tsx +0 -0
  57. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/DefaultType/SystemJsRender/index.tsx +0 -0
  58. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/DefaultType/SystemJsRender/utils.ts +0 -0
  59. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/DefaultType/index.tsx +0 -0
  60. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/MarkdownType/index.tsx +0 -0
  61. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/StandaloneType/Iframe.tsx +0 -0
  62. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/StandaloneType/index.tsx +0 -0
  63. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/index.tsx +0 -0
  64. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/useParseContent.ts +0 -0
  65. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/iframeOnReady.test.ts +0 -0
  66. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/iframeOnReady.ts +0 -0
  67. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/listenToPlugin.test.ts +0 -0
  68. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/listenToPlugin.ts +0 -0
  69. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/pluginSettings.test.ts +0 -0
  70. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/pluginSettings.ts +0 -0
  71. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/pluginState.test.ts +0 -0
  72. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/pluginState.ts +0 -0
  73. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/postMessage.test.ts +0 -0
  74. /package/src/features/Conversation/{ChatList/Plugins → Plugins}/Render/utils/postMessage.ts +0 -0
  75. /package/src/features/Conversation/{ChatList/Loading.tsx → components/BubblesLoading.tsx} +0 -0
  76. /package/src/features/Conversation/{ChatList → components}/OTPInput.tsx +0 -0
  77. /package/src/features/Conversation/{ScrollAnchor → components/ScrollAnchor}/index.tsx +0 -0
  78. /package/src/features/Conversation/{ScrollAnchor → components/ScrollAnchor}/useAtBottom.ts +0 -0
  79. /package/src/features/Conversation/{ChatList → components}/SkeletonList.tsx +0 -0
  80. /package/src/features/Conversation/{useInitConversation.ts → hooks/useInitConversation.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.118.6](https://github.com/lobehub/lobe-chat/compare/v0.118.5...v0.118.6)
6
+
7
+ <sup>Released on **2024-01-03**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Migration the ChatList into Conversation.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Migration the ChatList into Conversation, closes [#916](https://github.com/lobehub/lobe-chat/issues/916) ([6ee3795](https://github.com/lobehub/lobe-chat/commit/6ee3795))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ### [Version 0.118.5](https://github.com/lobehub/lobe-chat/compare/v0.118.4...v0.118.5)
6
31
 
7
32
  <sup>Released on **2024-01-02**</sup>
package/next.config.mjs CHANGED
@@ -20,7 +20,6 @@ const withPWA = nextPWA({
20
20
  const nextConfig = {
21
21
  compress: isProd,
22
22
  experimental: {
23
- forceSwcTransforms: true,
24
23
  optimizePackageImports: [
25
24
  'modern-screenshot',
26
25
  'emoji-mart',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.118.5",
3
+ "version": "0.118.6",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
7
  import pkg from '@/../package.json';
8
- import ChatList from '@/features/Conversation/ChatList';
8
+ import ChatList from '@/features/Conversation/container';
9
9
  import { useSessionStore } from '@/store/session';
10
10
  import { agentSelectors, sessionSelectors } from '@/store/session/selectors';
11
11
 
@@ -1,6 +1,8 @@
1
- import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
 
4
+ import { RenderAction } from '../components/ChatList';
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
4
6
  import { ErrorActionsBar } from './Error';
5
7
  import { useCustomActions } from './customAction';
6
8
 
@@ -1,7 +1,9 @@
1
- import { ActionIconGroup, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { ActionsBarProps } from '@lobehub/ui/es/ChatList/ActionsBar';
3
3
  import { memo } from 'react';
4
4
 
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
6
+
5
7
  export const ErrorActionsBar = memo<ActionsBarProps>(({ text, onActionClick }) => {
6
8
  const { regenerate, del } = useChatListActionsBar(text);
7
9
 
@@ -1,6 +1,9 @@
1
- import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
 
4
+ import { RenderAction } from '../components/ChatList';
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
6
+
4
7
  export const DefaultActionsBar: RenderAction = memo(({ text, onActionClick }) => {
5
8
  const { del } = useChatListActionsBar(text);
6
9
  return (
@@ -1,6 +1,9 @@
1
- import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
 
4
+ import { RenderAction } from '../components/ChatList';
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
6
+
4
7
  export const FunctionActionsBar: RenderAction = memo(({ text, onActionClick }) => {
5
8
  const { regenerate, divider, del } = useChatListActionsBar(text);
6
9
  return (
@@ -1,6 +1,8 @@
1
- import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui';
1
+ import { ActionIconGroup } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
 
4
+ import { RenderAction } from '../components/ChatList';
5
+ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
4
6
  import { useCustomActions } from './customAction';
5
7
 
6
8
  export const UserActionsBar: RenderAction = memo(({ text, onActionClick }) => {
@@ -1,7 +1,6 @@
1
- import { ChatListProps } from '@lobehub/ui';
2
-
3
1
  import { useChatStore } from '@/store/chat';
4
2
 
3
+ import { ChatListProps } from '../components/ChatList';
5
4
  import { AssistantActionsBar } from './Assistant';
6
5
  import { DefaultActionsBar } from './Fallback';
7
6
  import { FunctionActionsBar } from './Function';
@@ -1,4 +1,4 @@
1
- import { Icon, RenderErrorMessage } from '@lobehub/ui';
1
+ import { Icon } from '@lobehub/ui';
2
2
  import { Button, Input, Segmented } from 'antd';
3
3
  import { KeySquare, SquareAsterisk } from 'lucide-react';
4
4
  import { memo, useState } from 'react';
@@ -8,6 +8,7 @@ import { Flexbox } from 'react-layout-kit';
8
8
  import { useChatStore } from '@/store/chat';
9
9
  import { useGlobalStore } from '@/store/global';
10
10
 
11
+ import { RenderErrorMessage } from '../components/ChatList';
11
12
  import APIKeyForm from './ApiKeyForm';
12
13
  import { ErrorActionContainer, FormAction } from './style';
13
14
 
@@ -1,6 +1,6 @@
1
- import { RenderErrorMessage } from '@lobehub/ui';
2
1
  import { memo } from 'react';
3
2
 
3
+ import { RenderErrorMessage } from '../components/ChatList';
4
4
  import APIKeyForm from './ApiKeyForm';
5
5
  import { ErrorActionContainer } from './style';
6
6
 
@@ -1,7 +1,8 @@
1
- import { Highlighter, RenderErrorMessage } from '@lobehub/ui';
1
+ import { Highlighter } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
  import { Flexbox } from 'react-layout-kit';
4
4
 
5
+ import { RenderErrorMessage } from '../components/ChatList';
5
6
  import OpenAPIKey from './OpenAPIKey';
6
7
 
7
8
  interface OpenAIError {
@@ -1,7 +1,9 @@
1
- import { Highlighter, RenderErrorMessage } from '@lobehub/ui';
1
+ import { Highlighter } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
  import { Flexbox } from 'react-layout-kit';
4
4
 
5
+ import { RenderErrorMessage } from '../../components/ChatList';
6
+
5
7
  interface OpenAIError {
6
8
  code: 'invalid_api_key' | string;
7
9
  message: string;
@@ -1,4 +1,4 @@
1
- import { Avatar, RenderErrorMessage } from '@lobehub/ui';
1
+ import { Avatar } from '@lobehub/ui';
2
2
  import { Button, Divider } from 'antd';
3
3
  import { useTheme } from 'antd-style';
4
4
  import isEqual from 'fast-deep-equal';
@@ -11,6 +11,7 @@ import { useChatStore } from '@/store/chat';
11
11
  import { pluginHelpers, useToolStore } from '@/store/tool';
12
12
  import { pluginSelectors } from '@/store/tool/selectors';
13
13
 
14
+ import { RenderErrorMessage } from '../../components/ChatList';
14
15
  import { ErrorActionContainer, useStyles } from '../style';
15
16
 
16
17
  const PluginSettings: RenderErrorMessage['Render'] = memo(({ id, plugin }) => {
@@ -1,8 +1,8 @@
1
1
  import { PluginErrorType } from '@lobehub/chat-plugin-sdk';
2
- import { ChatListProps } from '@lobehub/ui';
3
2
 
4
3
  import { ChatErrorType } from '@/types/fetch';
5
4
 
5
+ import { ChatListProps } from '../components/ChatList';
6
6
  import InvalidAccess from './InvalidAccess';
7
7
  import OpenAPIKey from './OpenAPIKey';
8
8
  import OpenAiBizError from './OpenAiBizError';
@@ -10,7 +10,7 @@ import { Flexbox } from 'react-layout-kit';
10
10
  import { useChatStore } from '@/store/chat';
11
11
  import { ChatTranslate } from '@/types/message';
12
12
 
13
- import BubblesLoading from '../Loading';
13
+ import BubblesLoading from '../components/BubblesLoading';
14
14
 
15
15
  const useStyles = createStyles(({ stylish }) => ({
16
16
  markdown: stylish.markdownInChat,
@@ -1,5 +1,4 @@
1
- import { ChatListProps, RenderMessageExtra } from '@lobehub/ui';
2
-
1
+ import { ChatListProps, RenderMessageExtra } from '../components/ChatList';
3
2
  import { AssistantMessageExtra } from './Assistant';
4
3
  import { UserMessageExtra } from './User';
5
4
 
@@ -3,7 +3,7 @@ import { ReactNode, memo } from 'react';
3
3
  import { LOADING_FLAT } from '@/const/message';
4
4
  import { ChatMessage } from '@/types/message';
5
5
 
6
- import BubblesLoading from '../Loading';
6
+ import BubblesLoading from '../components/BubblesLoading';
7
7
 
8
8
  export const DefaultMessage = memo<
9
9
  ChatMessage & {
@@ -5,7 +5,7 @@ import FileList from '@/components/FileList';
5
5
  import { LOADING_FLAT } from '@/const/message';
6
6
  import { ChatMessage } from '@/types/message';
7
7
 
8
- import BubblesLoading from '../Loading';
8
+ import BubblesLoading from '../components/BubblesLoading';
9
9
 
10
10
  export const UserMessage = memo<
11
11
  ChatMessage & {
@@ -1,4 +1,3 @@
1
- import { ChatListProps } from '@lobehub/ui';
2
1
  import { useResponsive } from 'antd-style';
3
2
  import { useRouter } from 'next/navigation';
4
3
 
@@ -7,16 +6,17 @@ import { useSessionStore } from '@/store/session';
7
6
  import { sessionSelectors } from '@/store/session/selectors';
8
7
  import { pathString } from '@/utils/url';
9
8
 
9
+ import { ChatListProps } from '../components/ChatList';
10
10
  import { AssistantMessage } from './Assistant';
11
11
  import { DefaultMessage } from './Default';
12
12
  import { FunctionMessage } from './Function';
13
13
  import { UserMessage } from './User';
14
14
 
15
15
  export const renderMessages: ChatListProps['renderMessages'] = {
16
- assistant: AssistantMessage as any,
17
- default: DefaultMessage as any,
18
- function: FunctionMessage as any,
19
- user: UserMessage as any,
16
+ assistant: AssistantMessage,
17
+ default: DefaultMessage,
18
+ function: FunctionMessage,
19
+ user: UserMessage,
20
20
  };
21
21
 
22
22
  export const useAvatarsClick = (): ChatListProps['onAvatarsClick'] => {
@@ -1,11 +1,10 @@
1
- import {createStyles} from 'antd-style';
2
- import {useTranslation} from 'react-i18next';
3
- import {Flexbox} from 'react-layout-kit';
4
- import {memo} from "react";
5
-
1
+ import { createStyles } from 'antd-style';
2
+ import { memo } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { Flexbox } from 'react-layout-kit';
6
5
 
7
6
  const useStyles = createStyles(
8
- ({css, token}) => css`
7
+ ({ css, token }) => css`
9
8
  position: relative;
10
9
 
11
10
  overflow: hidden;
@@ -46,16 +45,16 @@ const useStyles = createStyles(
46
45
  }
47
46
  `,
48
47
  );
49
- const Loading = memo(() => {
50
- const {t} = useTranslation('plugin');
51
- const {styles} = useStyles();
48
+ const Loading = memo(() => {
49
+ const { t } = useTranslation('plugin');
50
+ const { styles } = useStyles();
52
51
 
53
52
  return (
54
53
  <Flexbox align={'center'} gap={8} padding={16}>
55
- <span className={styles}/>
54
+ <span className={styles} />
56
55
  {t('loading.content')}
57
56
  </Flexbox>
58
57
  );
59
58
  });
60
59
 
61
- export default Loading
60
+ export default Loading;
@@ -0,0 +1,27 @@
1
+ import { ActionIconGroup, type ActionIconGroupProps } from '@lobehub/ui';
2
+ import { memo } from 'react';
3
+
4
+ import { useChatListActionsBar } from '../../hooks/useChatListActionsBar';
5
+
6
+ export interface ActionsBarProps extends ActionIconGroupProps {
7
+ text?: {
8
+ copy?: string;
9
+ delete?: string;
10
+ edit?: string;
11
+ regenerate?: string;
12
+ };
13
+ }
14
+
15
+ const ActionsBar = memo<ActionsBarProps>(({ text, ...rest }) => {
16
+ const { regenerate, edit, copy, divider, del } = useChatListActionsBar(text);
17
+ return (
18
+ <ActionIconGroup
19
+ dropdownMenu={[edit, copy, regenerate, divider, del]}
20
+ items={[regenerate, edit]}
21
+ type="ghost"
22
+ {...rest}
23
+ />
24
+ );
25
+ });
26
+
27
+ export default ActionsBar;
@@ -0,0 +1,23 @@
1
+ import { Icon, Tag } from '@lobehub/ui';
2
+ import { Divider } from 'antd';
3
+ import { Timer } from 'lucide-react';
4
+ import { memo } from 'react';
5
+
6
+ interface HistoryDividerProps {
7
+ enable?: boolean;
8
+ text?: string;
9
+ }
10
+
11
+ const HistoryDivider = memo<HistoryDividerProps>(({ enable, text }) => {
12
+ if (!enable) return null;
13
+
14
+ return (
15
+ <div style={{ padding: '0 20px' }}>
16
+ <Divider>
17
+ <Tag icon={<Icon icon={Timer} />}>{text || 'History Message'}</Tag>
18
+ </Divider>
19
+ </div>
20
+ );
21
+ });
22
+
23
+ export default HistoryDivider;
@@ -0,0 +1,236 @@
1
+ import { type AlertProps, ChatItem, type ChatItemProps } from '@lobehub/ui';
2
+ import { ActionEvent, copyToClipboard } from '@lobehub/ui';
3
+ import { App } from 'antd';
4
+ import { FC, ReactNode, memo, useCallback, useMemo, useState } from 'react';
5
+
6
+ import { LLMRoleType } from '@/types/llm';
7
+ import { ChatMessage } from '@/types/message';
8
+
9
+ import ActionsBar, { type ActionsBarProps } from './ActionsBar';
10
+
11
+ export type OnMessageChange = (id: string, content: string) => void;
12
+ export type OnActionsClick = (action: ActionEvent, message: ChatMessage) => void;
13
+ export type OnAvatatsClick = (role: RenderRole) => ChatItemProps['onAvatarClick'];
14
+ export type RenderRole = LLMRoleType | 'default' | string;
15
+ export type RenderItem = FC<{ key: string } & ChatMessage & ListItemProps>;
16
+ export type RenderMessage = FC<ChatMessage & { editableContent: ReactNode }>;
17
+ export type RenderMessageExtra = FC<ChatMessage>;
18
+ export interface RenderErrorMessage {
19
+ Render?: FC<ChatMessage>;
20
+ config?: AlertProps;
21
+ }
22
+ export type RenderAction = FC<ActionsBarProps & ChatMessage>;
23
+
24
+ export interface ListItemProps {
25
+ groupNav?: ChatItemProps['avatarAddon'];
26
+ loading?: boolean;
27
+ /**
28
+ * @description 点击操作按钮的回调函数
29
+ */
30
+ onActionsClick?: OnActionsClick;
31
+ onAvatarsClick?: OnAvatatsClick;
32
+ /**
33
+ * @description 消息变化的回调函数
34
+ */
35
+ onMessageChange?: OnMessageChange;
36
+ renderActions?: {
37
+ [actionKey: string]: RenderAction;
38
+ };
39
+ /**
40
+ * @description 渲染错误消息的函数
41
+ */
42
+ renderErrorMessages?: {
43
+ [errorType: 'default' | string]: RenderErrorMessage;
44
+ };
45
+ renderItems?: {
46
+ [role: RenderRole]: RenderItem;
47
+ };
48
+ /**
49
+ * @description 渲染消息的函数
50
+ */
51
+ renderMessages?: {
52
+ [role: RenderRole]: RenderMessage;
53
+ };
54
+ /**
55
+ * @description 渲染消息额外内容的函数
56
+ */
57
+ renderMessagesExtra?: {
58
+ [role: RenderRole]: RenderMessageExtra;
59
+ };
60
+ /**
61
+ * @description 是否显示聊天项的名称
62
+ * @default false
63
+ */
64
+ showTitle?: boolean;
65
+ /**
66
+ * @description 文本内容
67
+ */
68
+ text?: ChatItemProps['text'] &
69
+ ActionsBarProps['text'] & {
70
+ copySuccess?: string;
71
+ history?: string;
72
+ } & {
73
+ [key: string]: string;
74
+ };
75
+ /**
76
+ * @description 聊天列表的类型
77
+ * @default 'chat'
78
+ */
79
+ type?: 'docs' | 'chat';
80
+ }
81
+
82
+ export type ChatListItemProps = ChatMessage & ListItemProps;
83
+
84
+ const Item = memo<ChatListItemProps>((props) => {
85
+ const {
86
+ renderMessagesExtra,
87
+ showTitle,
88
+ onActionsClick,
89
+ onAvatarsClick,
90
+ onMessageChange,
91
+ type,
92
+ text,
93
+ renderMessages,
94
+ renderErrorMessages,
95
+ renderActions,
96
+ loading,
97
+ groupNav,
98
+ renderItems,
99
+ ...item
100
+ } = props;
101
+
102
+ const [editing, setEditing] = useState(false);
103
+
104
+ const { message } = App.useApp();
105
+
106
+ const RenderItem = useMemo(() => {
107
+ if (!renderItems || !item?.role) return;
108
+ let renderFunction;
109
+ if (renderItems?.[item.role]) renderFunction = renderItems[item.role];
110
+ if (!renderFunction && renderItems?.['default']) renderFunction = renderItems['default'];
111
+ if (!renderFunction) return;
112
+ return renderFunction;
113
+ }, [renderItems?.[item.role]]);
114
+
115
+ const RenderMessage = useCallback(
116
+ ({ editableContent, data }: { data: ChatMessage; editableContent: ReactNode }) => {
117
+ if (!renderMessages || !item?.role) return;
118
+ let RenderFunction;
119
+ if (renderMessages?.[item.role]) RenderFunction = renderMessages[item.role];
120
+ if (!RenderFunction && renderMessages?.['default'])
121
+ RenderFunction = renderMessages['default'];
122
+ if (!RenderFunction) return;
123
+ return <RenderFunction {...data} editableContent={editableContent} />;
124
+ },
125
+ [renderMessages?.[item.role]],
126
+ );
127
+
128
+ const MessageExtra = useCallback(
129
+ ({ data }: { data: ChatMessage }) => {
130
+ if (!renderMessagesExtra || !item?.role) return;
131
+ let RenderFunction;
132
+ if (renderMessagesExtra?.[item.role]) RenderFunction = renderMessagesExtra[item.role];
133
+ if (renderMessagesExtra?.['default']) RenderFunction = renderMessagesExtra['default'];
134
+ if (!RenderFunction) return;
135
+ return <RenderFunction {...data} />;
136
+ },
137
+ [renderMessagesExtra?.[item.role]],
138
+ );
139
+
140
+ const ErrorMessage = useCallback(
141
+ ({ data }: { data: ChatMessage }) => {
142
+ if (!renderErrorMessages || !item?.error?.type) return;
143
+ let RenderFunction;
144
+ if (renderErrorMessages?.[item.error.type])
145
+ RenderFunction = renderErrorMessages[item.error.type].Render;
146
+ if (!RenderFunction && renderErrorMessages?.['default'])
147
+ RenderFunction = renderErrorMessages['default'].Render;
148
+ if (!RenderFunction) return;
149
+ return <RenderFunction {...data} />;
150
+ },
151
+ [renderErrorMessages?.[item?.error?.type]],
152
+ );
153
+
154
+ const Actions = useCallback(
155
+ ({ data }: { data: ChatMessage }) => {
156
+ if (!renderActions || !item?.role) return;
157
+ let RenderFunction;
158
+ if (renderActions?.[item.role]) RenderFunction = renderActions[item.role];
159
+ if (renderActions?.['default']) RenderFunction = renderActions['default'];
160
+ if (!RenderFunction) RenderFunction = ActionsBar;
161
+
162
+ const handleActionClick: ListItemProps['onActionsClick'] = async (action, data) => {
163
+ switch (action.key) {
164
+ case 'copy': {
165
+ await copyToClipboard(data.content);
166
+ message.success(text?.copySuccess || 'Copy Success');
167
+ break;
168
+ }
169
+ case 'edit': {
170
+ setEditing(true);
171
+ }
172
+ }
173
+
174
+ onActionsClick?.(action, data);
175
+ };
176
+
177
+ return (
178
+ <RenderFunction
179
+ {...data}
180
+ onActionClick={(actionKey) => handleActionClick?.(actionKey, data)}
181
+ text={text}
182
+ />
183
+ );
184
+ },
185
+ [renderActions?.[item.role], text, onActionsClick],
186
+ );
187
+
188
+ const error = useMemo(() => {
189
+ if (!item.error) return;
190
+ const message = item.error?.message;
191
+ let alertConfig = {};
192
+ if (item.error.type && renderErrorMessages?.[item.error.type]) {
193
+ alertConfig = renderErrorMessages[item.error.type]?.config as AlertProps;
194
+ }
195
+ return {
196
+ message,
197
+ ...alertConfig,
198
+ };
199
+ }, [renderErrorMessages, item.error]);
200
+
201
+ if (RenderItem) return <RenderItem key={item.id} {...props} />;
202
+
203
+ return (
204
+ <ChatItem
205
+ actions={<Actions data={item} />}
206
+ avatar={item.meta}
207
+ avatarAddon={groupNav}
208
+ editing={editing}
209
+ error={error}
210
+ errorMessage={<ErrorMessage data={item} />}
211
+ loading={loading}
212
+ message={item.content}
213
+ messageExtra={<MessageExtra data={item} />}
214
+ onAvatarClick={onAvatarsClick?.(item.role)}
215
+ onChange={(value) => onMessageChange?.(item.id, value)}
216
+ onDoubleClick={(e) => {
217
+ if (item.id === 'default' || item.error) return;
218
+ if (item.role && ['assistant', 'user'].includes(item.role) && e.altKey) {
219
+ setEditing(true);
220
+ }
221
+ }}
222
+ onEditingChange={setEditing}
223
+ placement={type === 'chat' ? (item.role === 'user' ? 'right' : 'left') : 'left'}
224
+ primary={item.role === 'user'}
225
+ renderMessage={(editableContent) => (
226
+ <RenderMessage data={item} editableContent={editableContent} />
227
+ )}
228
+ showTitle={showTitle}
229
+ text={text}
230
+ time={item.updateAt || item.createAt}
231
+ type={type === 'chat' ? 'block' : 'pure'}
232
+ />
233
+ );
234
+ });
235
+
236
+ export default Item;