@lobehub/chat 1.135.3 → 1.135.4
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.
- package/CHANGELOG.md +33 -0
- package/changelog/v1.json +9 -0
- package/package.json +2 -2
- package/packages/const/src/index.ts +1 -0
- package/packages/const/src/settings/index.ts +1 -0
- package/packages/model-bank/src/aiModels/aihubmix.ts +25 -0
- package/packages/model-bank/src/aiModels/nvidia.ts +17 -1
- package/packages/model-bank/src/aiModels/openai.ts +80 -1
- package/packages/model-runtime/src/const/models.ts +2 -0
- package/packages/model-runtime/src/providers/openai/index.ts +15 -11
- package/packages/model-runtime/src/providers/openrouter/index.ts +7 -2
- package/packages/model-runtime/src/providers/openrouter/type.ts +4 -2
- package/packages/model-runtime/src/providers/vercelaigateway/index.ts +7 -0
- package/packages/model-runtime/src/utils/modelParse.ts +31 -3
- package/packages/types/src/aiProvider.ts +1 -2
- package/packages/types/src/discover/models.ts +3 -2
- package/packages/types/src/discover/providers.ts +3 -2
- package/packages/types/src/message/chat.ts +13 -0
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/index.tsx +1 -5
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/WelcomeMessage.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/CreateNewModelModal/Form.tsx +1 -2
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelItem.tsx +1 -4
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/SortModelModal/ListItem.tsx +1 -2
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/SortModelModal/index.tsx +1 -1
- package/src/{components → features}/ChatItem/ChatItem.tsx +5 -35
- package/src/{components → features}/ChatItem/components/MessageContent.tsx +27 -7
- package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/Render/index.tsx +1 -1
- package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/getNodeContent.test.ts +1 -1
- package/src/features/Conversation/{Actions → Messages/Assistant/Actions}/Error.tsx +1 -1
- package/src/features/Conversation/{components/ChatItem/ActionsBar.tsx → Messages/Assistant/Actions/index.tsx} +71 -44
- package/src/features/Conversation/Messages/Assistant/Block.tsx +63 -0
- package/src/features/Conversation/{Extras/Assistant.test.tsx → Messages/Assistant/Extra/index.test.tsx} +36 -31
- package/src/features/Conversation/{Extras/Assistant.tsx → Messages/Assistant/Extra/index.tsx} +13 -7
- package/src/features/Conversation/Messages/Assistant/MessageContent.tsx +102 -0
- package/src/features/Conversation/Messages/Assistant/index.tsx +235 -84
- package/src/features/Conversation/Messages/User/Actions.tsx +153 -0
- package/src/features/Conversation/Messages/User/BelowMessage.tsx +7 -2
- package/src/features/Conversation/{Extras/User.tsx → Messages/User/Extra.tsx} +9 -7
- package/src/features/Conversation/Messages/User/MessageContent.tsx +31 -0
- package/src/features/Conversation/Messages/User/index.tsx +127 -24
- package/src/features/Conversation/Messages/index.tsx +152 -0
- package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/ModelCard.tsx +4 -3
- package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/pricing.ts +3 -2
- package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/tokens.test.ts +2 -3
- package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareImage/Preview.tsx +1 -1
- package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/index.tsx +1 -1
- package/src/features/Conversation/components/VirtualizedList/index.tsx +1 -0
- package/src/features/Conversation/hooks/useChatListActionsBar.tsx +29 -1
- package/src/features/Conversation/hooks/useDoubleClickEdit.ts +42 -0
- package/src/features/Conversation/index.ts +1 -1
- package/src/features/Conversation/types/{index.tsx → index.ts} +0 -7
- package/src/features/Portal/Thread/Chat/ChatItem.tsx +0 -7
- package/src/hooks/useUserAvatar.test.ts +129 -0
- package/src/hooks/useUserAvatar.ts +19 -0
- package/src/server/routers/lambda/aiModel.ts +7 -8
- package/src/store/user/slices/settings/selectors/settings.ts +6 -5
- package/src/features/ChatItem/index.tsx +0 -58
- package/src/features/Conversation/Actions/Assistant.tsx +0 -68
- package/src/features/Conversation/Actions/Fallback.tsx +0 -19
- package/src/features/Conversation/Actions/Tool.tsx +0 -33
- package/src/features/Conversation/Actions/User.tsx +0 -39
- package/src/features/Conversation/Actions/customAction.ts +0 -37
- package/src/features/Conversation/Actions/index.ts +0 -14
- package/src/features/Conversation/Extras/index.ts +0 -8
- package/src/features/Conversation/Extras/type.ts +0 -5
- package/src/features/Conversation/Messages/index.ts +0 -45
- package/src/features/Conversation/components/ChatItem/index.tsx +0 -358
- /package/src/{components → features}/ChatItem/components/Actions.tsx +0 -0
- /package/src/{components → features}/ChatItem/components/Avatar.tsx +0 -0
- /package/src/{components → features}/ChatItem/components/BorderSpacing.tsx +0 -0
- /package/src/{components → features}/ChatItem/components/ErrorContent.tsx +0 -0
- /package/src/{components → features}/ChatItem/components/Loading.tsx +0 -0
- /package/src/{components → features}/ChatItem/components/Title.tsx +0 -0
- /package/src/{components → features}/ChatItem/index.ts +0 -0
- /package/src/{components → features}/ChatItem/style.ts +0 -0
- /package/src/{components → features}/ChatItem/type.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/Render/Icon.tsx +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/index.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/rehypePlugin.test.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeArtifact/rehypePlugin.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeThinking/Render.tsx +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LobeThinking/index.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LocalFile/Render/index.tsx +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/LocalFile/index.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/Thinking/Render.tsx +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/Thinking/index.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/index.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/__snapshots__/createRemarkSelfClosingTagPlugin.test.ts.snap +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/createRemarkCustomTagPlugin.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/remarkPlugins/getNodeContent.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/type.ts +0 -0
- /package/src/features/Conversation/{components/MarkdownElements → MarkdownElements}/utils.ts +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/ExtraContainer.tsx +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/TTS/FilePlayer.tsx +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/TTS/InitPlayer.tsx +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/TTS/Player.tsx +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/TTS/index.tsx +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/Translate.tsx +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/TokenProgress.tsx +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/index.tsx +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/Usage/UsageDetail/tokens.ts +0 -0
- /package/src/features/Conversation/{Extras → components/Extras}/Usage/index.tsx +0 -0
- /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareImage/index.tsx +0 -0
- /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareImage/style.ts +0 -0
- /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareImage/type.ts +0 -0
- /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/Preview.tsx +0 -0
- /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/template.test.ts +0 -0
- /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/template.ts +0 -0
- /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/ShareText/type.ts +0 -0
- /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/index.tsx +0 -0
- /package/src/features/Conversation/components/{ChatItem/ShareMessageModal → ShareMessageModal}/style.ts +0 -0
- /package/src/features/Conversation/{components/ChatItem → context}/InPortalThreadContext.ts +0 -0
- /package/src/features/Conversation/{components/ChatItem/utils.test.ts → utils.test.ts} +0 -0
- /package/src/features/Conversation/{components/ChatItem/utils.ts → utils.ts} +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { act, renderHook } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { useElectronStore } from '@/store/electron';
|
|
5
|
+
import { useUserStore } from '@/store/user';
|
|
6
|
+
|
|
7
|
+
import { useUserAvatar } from './useUserAvatar';
|
|
8
|
+
|
|
9
|
+
vi.mock('zustand/traditional');
|
|
10
|
+
|
|
11
|
+
// Mock @lobechat/const
|
|
12
|
+
let mockIsDesktop = false;
|
|
13
|
+
|
|
14
|
+
vi.mock('@lobechat/const', async (importOriginal) => {
|
|
15
|
+
const actual = await importOriginal<typeof import('@lobechat/const')>();
|
|
16
|
+
return {
|
|
17
|
+
...actual,
|
|
18
|
+
get isDesktop() {
|
|
19
|
+
return mockIsDesktop;
|
|
20
|
+
},
|
|
21
|
+
DEFAULT_USER_AVATAR: 'default-avatar.png',
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('useUserAvatar', () => {
|
|
26
|
+
it('should return default avatar when user has no avatar', () => {
|
|
27
|
+
act(() => {
|
|
28
|
+
useUserStore.setState({ user: { avatar: undefined } as any });
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const { result } = renderHook(() => useUserAvatar());
|
|
32
|
+
|
|
33
|
+
expect(result.current).toBe('default-avatar.png');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should return user avatar when available', () => {
|
|
37
|
+
const mockAvatar = 'https://example.com/avatar.png';
|
|
38
|
+
|
|
39
|
+
act(() => {
|
|
40
|
+
useUserStore.setState({ user: { avatar: mockAvatar } as any });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const { result } = renderHook(() => useUserAvatar());
|
|
44
|
+
|
|
45
|
+
expect(result.current).toBe(mockAvatar);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should return original avatar in non-desktop environment', () => {
|
|
49
|
+
mockIsDesktop = false;
|
|
50
|
+
const mockAvatar = '/api/avatar.png';
|
|
51
|
+
|
|
52
|
+
act(() => {
|
|
53
|
+
useUserStore.setState({ user: { avatar: mockAvatar } as any });
|
|
54
|
+
useElectronStore.setState({
|
|
55
|
+
dataSyncConfig: { remoteServerUrl: 'https://server.com', storageMode: 'cloud' },
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const { result } = renderHook(() => useUserAvatar());
|
|
60
|
+
|
|
61
|
+
expect(result.current).toBe(mockAvatar);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should return original avatar when no remote server URL in desktop environment', () => {
|
|
65
|
+
mockIsDesktop = true;
|
|
66
|
+
const mockAvatar = '/api/avatar.png';
|
|
67
|
+
|
|
68
|
+
act(() => {
|
|
69
|
+
useUserStore.setState({ user: { avatar: mockAvatar } as any });
|
|
70
|
+
useElectronStore.setState({
|
|
71
|
+
dataSyncConfig: { remoteServerUrl: undefined, storageMode: 'local' },
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const { result } = renderHook(() => useUserAvatar());
|
|
76
|
+
|
|
77
|
+
expect(result.current).toBe(mockAvatar);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should prepend remote server URL when avatar starts with / in desktop environment', () => {
|
|
81
|
+
mockIsDesktop = true;
|
|
82
|
+
const mockAvatar = '/api/avatar.png';
|
|
83
|
+
const mockServerUrl = 'https://server.com';
|
|
84
|
+
|
|
85
|
+
act(() => {
|
|
86
|
+
useUserStore.setState({ user: { avatar: mockAvatar } as any });
|
|
87
|
+
useElectronStore.setState({
|
|
88
|
+
dataSyncConfig: { remoteServerUrl: mockServerUrl, storageMode: 'cloud' },
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const { result } = renderHook(() => useUserAvatar());
|
|
93
|
+
|
|
94
|
+
expect(result.current).toBe('https://server.com/api/avatar.png');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should not prepend remote server URL when avatar does not start with / in desktop environment', () => {
|
|
98
|
+
mockIsDesktop = true;
|
|
99
|
+
const mockAvatar = 'https://example.com/avatar.png';
|
|
100
|
+
const mockServerUrl = 'https://server.com';
|
|
101
|
+
|
|
102
|
+
act(() => {
|
|
103
|
+
useUserStore.setState({ user: { avatar: mockAvatar } as any });
|
|
104
|
+
useElectronStore.setState({
|
|
105
|
+
dataSyncConfig: { remoteServerUrl: mockServerUrl, storageMode: 'cloud' },
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const { result } = renderHook(() => useUserAvatar());
|
|
110
|
+
|
|
111
|
+
expect(result.current).toBe(mockAvatar);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should handle empty remote server URL in desktop environment', () => {
|
|
115
|
+
mockIsDesktop = true;
|
|
116
|
+
const mockAvatar = '/api/avatar.png';
|
|
117
|
+
|
|
118
|
+
act(() => {
|
|
119
|
+
useUserStore.setState({ user: { avatar: mockAvatar } as any });
|
|
120
|
+
useElectronStore.setState({
|
|
121
|
+
dataSyncConfig: { remoteServerUrl: '', storageMode: 'cloud' },
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const { result } = renderHook(() => useUserAvatar());
|
|
126
|
+
|
|
127
|
+
expect(result.current).toBe(mockAvatar);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DEFAULT_USER_AVATAR, isDesktop } from '@lobechat/const';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
|
|
4
|
+
import { useElectronStore } from '@/store/electron';
|
|
5
|
+
import { electronSyncSelectors } from '@/store/electron/selectors';
|
|
6
|
+
import { useUserStore } from '@/store/user';
|
|
7
|
+
import { userProfileSelectors } from '@/store/user/selectors';
|
|
8
|
+
|
|
9
|
+
export const useUserAvatar = () => {
|
|
10
|
+
const avatar = useUserStore(userProfileSelectors.userAvatar) || DEFAULT_USER_AVATAR;
|
|
11
|
+
const remoteServerUrl = useElectronStore(electronSyncSelectors.remoteServerUrl);
|
|
12
|
+
|
|
13
|
+
return useMemo(() => {
|
|
14
|
+
// only process avatar in desktop environment and when avatar url starts with /
|
|
15
|
+
if (!isDesktop || !remoteServerUrl || !avatar || !avatar.startsWith('/')) return avatar;
|
|
16
|
+
|
|
17
|
+
return remoteServerUrl + avatar;
|
|
18
|
+
}, [avatar, remoteServerUrl]);
|
|
19
|
+
};
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AiModelTypeSchema,
|
|
3
|
+
AiProviderModelListItem,
|
|
4
|
+
CreateAiModelSchema,
|
|
5
|
+
ToggleAiModelEnableSchema,
|
|
6
|
+
UpdateAiModelSchema,
|
|
7
|
+
} from 'model-bank';
|
|
1
8
|
import { z } from 'zod';
|
|
2
9
|
|
|
3
10
|
import { AiModelModel } from '@/database/models/aiModel';
|
|
@@ -9,14 +16,6 @@ import { getServerGlobalConfig } from '@/server/globalConfig';
|
|
|
9
16
|
import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
|
|
10
17
|
import { ProviderConfig } from '@/types/user/settings';
|
|
11
18
|
|
|
12
|
-
import {
|
|
13
|
-
AiModelTypeSchema,
|
|
14
|
-
AiProviderModelListItem,
|
|
15
|
-
CreateAiModelSchema,
|
|
16
|
-
ToggleAiModelEnableSchema,
|
|
17
|
-
UpdateAiModelSchema,
|
|
18
|
-
} from '../../../../packages/model-bank/src/types/aiModel';
|
|
19
|
-
|
|
20
19
|
const aiModelProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
|
21
20
|
const { ctx } = opts;
|
|
22
21
|
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import { DEFAULT_AGENT_META } from '@/const/meta';
|
|
2
1
|
import {
|
|
3
2
|
DEFAULT_AGENT,
|
|
4
3
|
DEFAULT_AGENT_CONFIG,
|
|
4
|
+
DEFAULT_AGENT_META,
|
|
5
5
|
DEFAULT_HOTKEY_CONFIG,
|
|
6
6
|
DEFAULT_SYSTEM_AGENT_CONFIG,
|
|
7
7
|
DEFAULT_TTS_CONFIG,
|
|
8
|
-
} from '
|
|
9
|
-
import type { UserStore } from '@/store/user';
|
|
10
|
-
import { HotkeyId } from '@/types/hotkey';
|
|
8
|
+
} from '@lobechat/const';
|
|
11
9
|
import {
|
|
12
10
|
GlobalLLMProviderKey,
|
|
11
|
+
HotkeyId,
|
|
13
12
|
ProviderConfig,
|
|
14
13
|
UserModelProviderConfig,
|
|
15
14
|
UserSettings,
|
|
16
|
-
} from '
|
|
15
|
+
} from '@lobechat/types';
|
|
16
|
+
|
|
17
|
+
import type { UserStore } from '@/store/user';
|
|
17
18
|
import { merge } from '@/utils/merge';
|
|
18
19
|
|
|
19
20
|
export const currentSettings = (s: UserStore): UserSettings => merge(s.defaultSettings, s.settings);
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import isEqual from 'fast-deep-equal';
|
|
4
|
-
import { memo, useMemo } from 'react';
|
|
5
|
-
|
|
6
|
-
import { ChatItemProps, ChatItem as ChatItemRaw } from '@/components/ChatItem';
|
|
7
|
-
import { isDesktop } from '@/const/version';
|
|
8
|
-
import { useElectronStore } from '@/store/electron';
|
|
9
|
-
import { electronSyncSelectors } from '@/store/electron/selectors';
|
|
10
|
-
import { useUserStore } from '@/store/user';
|
|
11
|
-
import { settingsSelectors } from '@/store/user/selectors';
|
|
12
|
-
|
|
13
|
-
const ChatItem = memo<ChatItemProps>(({ markdownProps = {}, avatar, ...rest }) => {
|
|
14
|
-
const { componentProps, ...restMarkdown } = markdownProps;
|
|
15
|
-
const { general } = useUserStore(settingsSelectors.currentSettings, isEqual);
|
|
16
|
-
|
|
17
|
-
const remoteServerUrl = useElectronStore(electronSyncSelectors.remoteServerUrl);
|
|
18
|
-
const processedAvatar = useMemo(() => {
|
|
19
|
-
// only process avatar in desktop environment and when avatar url starts with /
|
|
20
|
-
if (
|
|
21
|
-
!isDesktop ||
|
|
22
|
-
!remoteServerUrl ||
|
|
23
|
-
!avatar.avatar ||
|
|
24
|
-
typeof avatar.avatar !== 'string' ||
|
|
25
|
-
!avatar.avatar.startsWith('/')
|
|
26
|
-
)
|
|
27
|
-
return avatar;
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
...avatar,
|
|
31
|
-
avatar: remoteServerUrl + avatar.avatar, // prepend the remote server URL
|
|
32
|
-
};
|
|
33
|
-
}, [avatar, remoteServerUrl]);
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<ChatItemRaw
|
|
37
|
-
avatar={processedAvatar}
|
|
38
|
-
fontSize={general.fontSize}
|
|
39
|
-
markdownProps={{
|
|
40
|
-
...restMarkdown,
|
|
41
|
-
componentProps: {
|
|
42
|
-
...componentProps,
|
|
43
|
-
highlight: {
|
|
44
|
-
theme: general.highlighterTheme,
|
|
45
|
-
...componentProps?.highlight,
|
|
46
|
-
},
|
|
47
|
-
mermaid: {
|
|
48
|
-
theme: general.mermaidTheme,
|
|
49
|
-
...componentProps?.mermaid,
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
}}
|
|
53
|
-
{...rest}
|
|
54
|
-
/>
|
|
55
|
-
);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
export default ChatItem;
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { ActionIconGroup } from '@lobehub/ui';
|
|
2
|
-
import type { ActionIconGroupItemType } from '@lobehub/ui';
|
|
3
|
-
import { memo, useContext, useMemo } from 'react';
|
|
4
|
-
|
|
5
|
-
import { useChatStore } from '@/store/chat';
|
|
6
|
-
import { threadSelectors } from '@/store/chat/selectors';
|
|
7
|
-
|
|
8
|
-
import { InPortalThreadContext } from '../components/ChatItem/InPortalThreadContext';
|
|
9
|
-
import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
|
|
10
|
-
import { RenderAction } from '../types';
|
|
11
|
-
import { ErrorActionsBar } from './Error';
|
|
12
|
-
import { useCustomActions } from './customAction';
|
|
13
|
-
|
|
14
|
-
export const AssistantActionsBar: RenderAction = memo(({ onActionClick, error, tools, id }) => {
|
|
15
|
-
const [isThreadMode, hasThread] = useChatStore((s) => [
|
|
16
|
-
!!s.activeThreadId,
|
|
17
|
-
threadSelectors.hasThreadBySourceMsgId(id)(s),
|
|
18
|
-
]);
|
|
19
|
-
|
|
20
|
-
const {
|
|
21
|
-
regenerate,
|
|
22
|
-
edit,
|
|
23
|
-
delAndRegenerate,
|
|
24
|
-
copy,
|
|
25
|
-
divider,
|
|
26
|
-
del,
|
|
27
|
-
branching,
|
|
28
|
-
// export: exportPDF,
|
|
29
|
-
share,
|
|
30
|
-
} = useChatListActionsBar({ hasThread });
|
|
31
|
-
|
|
32
|
-
const { translate, tts } = useCustomActions();
|
|
33
|
-
const hasTools = !!tools;
|
|
34
|
-
|
|
35
|
-
const inPortalThread = useContext(InPortalThreadContext);
|
|
36
|
-
const inThread = isThreadMode || inPortalThread;
|
|
37
|
-
|
|
38
|
-
const items = useMemo(() => {
|
|
39
|
-
if (hasTools) return [delAndRegenerate, copy];
|
|
40
|
-
|
|
41
|
-
return [edit, copy, inThread ? null : branching].filter(Boolean) as ActionIconGroupItemType[];
|
|
42
|
-
}, [inThread, hasTools]);
|
|
43
|
-
|
|
44
|
-
if (error) return <ErrorActionsBar onActionClick={onActionClick} />;
|
|
45
|
-
|
|
46
|
-
return (
|
|
47
|
-
<ActionIconGroup
|
|
48
|
-
items={items}
|
|
49
|
-
menu={{
|
|
50
|
-
items: [
|
|
51
|
-
edit,
|
|
52
|
-
copy,
|
|
53
|
-
divider,
|
|
54
|
-
tts,
|
|
55
|
-
translate,
|
|
56
|
-
divider,
|
|
57
|
-
share,
|
|
58
|
-
// exportPDF,
|
|
59
|
-
divider,
|
|
60
|
-
regenerate,
|
|
61
|
-
delAndRegenerate,
|
|
62
|
-
del,
|
|
63
|
-
],
|
|
64
|
-
}}
|
|
65
|
-
onActionClick={onActionClick}
|
|
66
|
-
/>
|
|
67
|
-
);
|
|
68
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { ActionIconGroup } from '@lobehub/ui';
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
|
|
4
|
-
import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
|
|
5
|
-
import type { RenderAction } from '../types';
|
|
6
|
-
|
|
7
|
-
export const DefaultActionsBar: RenderAction = memo(({ onActionClick }) => {
|
|
8
|
-
const { del } = useChatListActionsBar();
|
|
9
|
-
|
|
10
|
-
return (
|
|
11
|
-
<ActionIconGroup
|
|
12
|
-
items={[]}
|
|
13
|
-
menu={{
|
|
14
|
-
items: [del],
|
|
15
|
-
}}
|
|
16
|
-
onActionClick={onActionClick}
|
|
17
|
-
/>
|
|
18
|
-
);
|
|
19
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { ActionIconGroup } from '@lobehub/ui';
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
|
|
4
|
-
import { useChatStore } from '@/store/chat';
|
|
5
|
-
|
|
6
|
-
import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
|
|
7
|
-
import { RenderAction } from '../types';
|
|
8
|
-
|
|
9
|
-
export const ToolActionsBar: RenderAction = memo(({ id }) => {
|
|
10
|
-
const { regenerate, del } = useChatListActionsBar();
|
|
11
|
-
const [reInvokeToolMessage, deleteToolMessage] = useChatStore((s) => [
|
|
12
|
-
s.reInvokeToolMessage,
|
|
13
|
-
s.deleteToolMessage,
|
|
14
|
-
]);
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<ActionIconGroup
|
|
18
|
-
items={[regenerate, del]}
|
|
19
|
-
onActionClick={async (event) => {
|
|
20
|
-
switch (event.key) {
|
|
21
|
-
case 'regenerate': {
|
|
22
|
-
await reInvokeToolMessage(id);
|
|
23
|
-
break;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
case 'del': {
|
|
27
|
-
await deleteToolMessage(id);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}}
|
|
31
|
-
/>
|
|
32
|
-
);
|
|
33
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { ActionIconGroup } from '@lobehub/ui';
|
|
2
|
-
import { ActionIconGroupItemType } from '@lobehub/ui/es/ActionIconGroup';
|
|
3
|
-
import { memo, useContext, useMemo } from 'react';
|
|
4
|
-
|
|
5
|
-
import { useChatStore } from '@/store/chat';
|
|
6
|
-
import { threadSelectors } from '@/store/chat/slices/thread/selectors';
|
|
7
|
-
|
|
8
|
-
import { InPortalThreadContext } from '../components/ChatItem/InPortalThreadContext';
|
|
9
|
-
import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
|
|
10
|
-
import { RenderAction } from '../types';
|
|
11
|
-
import { useCustomActions } from './customAction';
|
|
12
|
-
|
|
13
|
-
export const UserActionsBar: RenderAction = memo(({ onActionClick, id }) => {
|
|
14
|
-
const [isThreadMode, hasThread] = useChatStore((s) => [
|
|
15
|
-
!!s.activeThreadId,
|
|
16
|
-
threadSelectors.hasThreadBySourceMsgId(id)(s),
|
|
17
|
-
]);
|
|
18
|
-
const { regenerate, edit, copy, divider, del, branching } = useChatListActionsBar({ hasThread });
|
|
19
|
-
const { translate, tts } = useCustomActions();
|
|
20
|
-
|
|
21
|
-
const inPortalThread = useContext(InPortalThreadContext);
|
|
22
|
-
const inThread = isThreadMode || inPortalThread;
|
|
23
|
-
|
|
24
|
-
const items = useMemo(
|
|
25
|
-
() =>
|
|
26
|
-
[regenerate, edit, inThread ? null : branching].filter(Boolean) as ActionIconGroupItemType[],
|
|
27
|
-
[inThread],
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<ActionIconGroup
|
|
32
|
-
items={items}
|
|
33
|
-
menu={{
|
|
34
|
-
items: [edit, copy, divider, tts, translate, divider, regenerate, del],
|
|
35
|
-
}}
|
|
36
|
-
onActionClick={onActionClick}
|
|
37
|
-
/>
|
|
38
|
-
);
|
|
39
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { ActionIconGroupItemType } from '@lobehub/ui';
|
|
2
|
-
import { css, cx } from 'antd-style';
|
|
3
|
-
import { LanguagesIcon, Play } from 'lucide-react';
|
|
4
|
-
import { useMemo } from 'react';
|
|
5
|
-
import { useTranslation } from 'react-i18next';
|
|
6
|
-
|
|
7
|
-
import { localeOptions } from '@/locales/resources';
|
|
8
|
-
|
|
9
|
-
const translateStyle = css`
|
|
10
|
-
.ant-dropdown-menu-sub {
|
|
11
|
-
overflow-y: scroll;
|
|
12
|
-
max-height: 400px;
|
|
13
|
-
}
|
|
14
|
-
`;
|
|
15
|
-
|
|
16
|
-
export const useCustomActions = () => {
|
|
17
|
-
const { t } = useTranslation('chat');
|
|
18
|
-
|
|
19
|
-
const translate = {
|
|
20
|
-
children: localeOptions.map((i) => ({
|
|
21
|
-
key: i.value,
|
|
22
|
-
label: t(`lang.${i.value}`, { ns: 'common' }),
|
|
23
|
-
})),
|
|
24
|
-
icon: LanguagesIcon,
|
|
25
|
-
key: 'translate',
|
|
26
|
-
label: t('translate.action'),
|
|
27
|
-
popupClassName: cx(translateStyle),
|
|
28
|
-
} as ActionIconGroupItemType;
|
|
29
|
-
|
|
30
|
-
const tts = {
|
|
31
|
-
icon: Play,
|
|
32
|
-
key: 'tts',
|
|
33
|
-
label: t('tts.action'),
|
|
34
|
-
} as ActionIconGroupItemType;
|
|
35
|
-
|
|
36
|
-
return useMemo(() => ({ translate, tts }), []);
|
|
37
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { MessageRoleType } from '@/types/message';
|
|
2
|
-
|
|
3
|
-
import { RenderAction } from '../types';
|
|
4
|
-
import { AssistantActionsBar } from './Assistant';
|
|
5
|
-
import { DefaultActionsBar } from './Fallback';
|
|
6
|
-
import { ToolActionsBar } from './Tool';
|
|
7
|
-
import { UserActionsBar } from './User';
|
|
8
|
-
|
|
9
|
-
export const renderActions: Record<MessageRoleType, RenderAction> = {
|
|
10
|
-
assistant: AssistantActionsBar,
|
|
11
|
-
system: DefaultActionsBar,
|
|
12
|
-
tool: ToolActionsBar,
|
|
13
|
-
user: UserActionsBar,
|
|
14
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { RenderMessageExtra } from '../types';
|
|
2
|
-
import { AssistantMessageExtra } from './Assistant';
|
|
3
|
-
import { UserMessageExtra } from './User';
|
|
4
|
-
|
|
5
|
-
export const renderMessagesExtra: Record<string, RenderMessageExtra> = {
|
|
6
|
-
assistant: AssistantMessageExtra,
|
|
7
|
-
user: UserMessageExtra,
|
|
8
|
-
};
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
|
|
3
|
-
import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes';
|
|
4
|
-
import { useGlobalStore } from '@/store/global';
|
|
5
|
-
import { useSessionStore } from '@/store/session';
|
|
6
|
-
import { sessionSelectors } from '@/store/session/selectors';
|
|
7
|
-
|
|
8
|
-
import { MarkdownCustomRender, RenderBelowMessage, RenderMessage } from '../types';
|
|
9
|
-
import { AssistantMessage } from './Assistant';
|
|
10
|
-
import { DefaultBelowMessage, DefaultMessage } from './Default';
|
|
11
|
-
import { UserBelowMessage, UserMarkdownRender, UserMessage } from './User';
|
|
12
|
-
|
|
13
|
-
export const renderMessages: Record<string, RenderMessage> = {
|
|
14
|
-
assistant: AssistantMessage,
|
|
15
|
-
default: DefaultMessage,
|
|
16
|
-
function: DefaultMessage,
|
|
17
|
-
user: UserMessage,
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export const renderBelowMessages: Record<string, RenderBelowMessage> = {
|
|
21
|
-
default: DefaultBelowMessage,
|
|
22
|
-
user: UserBelowMessage,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const markdownCustomRenders: Record<string, MarkdownCustomRender> = {
|
|
26
|
-
user: UserMarkdownRender,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const useAvatarsClick = (role?: string) => {
|
|
30
|
-
const [isInbox] = useSessionStore((s) => [sessionSelectors.isInboxSession(s)]);
|
|
31
|
-
const [toggleSystemRole] = useGlobalStore((s) => [s.toggleSystemRole]);
|
|
32
|
-
const openChatSettings = useOpenChatSettings();
|
|
33
|
-
|
|
34
|
-
return useCallback(() => {
|
|
35
|
-
switch (role) {
|
|
36
|
-
case 'assistant': {
|
|
37
|
-
if (!isInbox) {
|
|
38
|
-
toggleSystemRole(true);
|
|
39
|
-
} else {
|
|
40
|
-
openChatSettings();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}, [isInbox, role]);
|
|
45
|
-
};
|