@lobehub/lobehub 2.0.0-next.44 → 2.0.0-next.46
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 +50 -0
- package/changelog/v1.json +18 -0
- package/package.json +1 -1
- package/packages/model-runtime/src/providers/azureai/index.ts +34 -2
- package/packages/utils/src/server/__tests__/response.test.ts +79 -0
- package/packages/utils/src/server/index.ts +1 -0
- package/packages/utils/src/server/response.ts +110 -0
- package/src/app/(backend)/webapi/stt/openai/route.ts +0 -2
- package/src/app/(backend)/webapi/tts/edge/route.ts +8 -2
- package/src/app/(backend)/webapi/tts/microsoft/route.ts +8 -2
- package/src/app/(backend)/webapi/tts/openai/route.ts +15 -3
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/ChatItem/Thread.tsx +1 -1
- package/src/app/[variants]/(main)/chat/components/conversation/features/ChatList/ChatItem/index.tsx +9 -16
- package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +3 -5
- package/src/features/Conversation/Messages/Assistant/Extra/index.test.tsx +3 -3
- package/src/features/Conversation/Messages/Assistant/Extra/index.tsx +8 -5
- package/src/features/Conversation/Messages/Assistant/index.tsx +29 -15
- package/src/features/Conversation/Messages/Group/Actions/WithContentId.tsx +3 -5
- package/src/features/Conversation/Messages/Group/index.tsx +12 -20
- package/src/features/Conversation/Messages/Supervisor/index.tsx +14 -5
- package/src/features/Conversation/Messages/User/index.tsx +14 -8
- package/src/features/Conversation/Messages/index.tsx +16 -26
- package/src/features/Conversation/components/Extras/Usage/UsageDetail/index.tsx +7 -6
- package/src/features/Conversation/components/Extras/Usage/UsageDetail/tokens.ts +2 -5
- package/src/features/Conversation/components/Extras/Usage/index.tsx +13 -6
- package/src/server/modules/ContentChunk/index.test.ts +372 -0
- package/src/server/utils/createSpeechResponse.ts +55 -0
- package/src/app/(backend)/webapi/chat/azureai/route.test.ts +0 -25
- package/src/app/(backend)/webapi/chat/azureai/route.ts +0 -6
|
@@ -29,28 +29,20 @@ import EditState from './EditState';
|
|
|
29
29
|
|
|
30
30
|
const MOBILE_AVATAR_SIZE = 32;
|
|
31
31
|
|
|
32
|
-
interface GroupMessageProps
|
|
32
|
+
interface GroupMessageProps {
|
|
33
33
|
disableEditing?: boolean;
|
|
34
|
+
id: string;
|
|
34
35
|
index: number;
|
|
35
|
-
showTitle?: boolean;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const GroupMessage = memo<GroupMessageProps>((
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
index,
|
|
45
|
-
createdAt,
|
|
46
|
-
meta,
|
|
47
|
-
children,
|
|
48
|
-
performance,
|
|
49
|
-
model,
|
|
50
|
-
provider,
|
|
51
|
-
} = props;
|
|
38
|
+
const GroupMessage = memo<GroupMessageProps>(({ id, index, disableEditing }) => {
|
|
39
|
+
const item = useChatStore(
|
|
40
|
+
displayMessageSelectors.getDisplayMessageById(id),
|
|
41
|
+
isEqual,
|
|
42
|
+
) as UIChatMessage;
|
|
43
|
+
const { usage, createdAt, meta, children, performance, model, provider } = item;
|
|
52
44
|
const avatar = meta;
|
|
53
|
-
|
|
45
|
+
|
|
54
46
|
const { mobile } = useResponsive();
|
|
55
47
|
const placement = 'left';
|
|
56
48
|
const type = useAgentStore(agentChatConfigSelectors.displayMode);
|
|
@@ -60,7 +52,7 @@ const GroupMessage = memo<GroupMessageProps>((props) => {
|
|
|
60
52
|
editing: false,
|
|
61
53
|
placement,
|
|
62
54
|
primary: false,
|
|
63
|
-
showTitle,
|
|
55
|
+
showTitle: true,
|
|
64
56
|
time: createdAt,
|
|
65
57
|
title: avatar.title,
|
|
66
58
|
variant,
|
|
@@ -129,14 +121,14 @@ const GroupMessage = memo<GroupMessageProps>((props) => {
|
|
|
129
121
|
)}
|
|
130
122
|
|
|
131
123
|
{model && (
|
|
132
|
-
<Usage
|
|
124
|
+
<Usage model={model} performance={performance} provider={provider!} usage={usage} />
|
|
133
125
|
)}
|
|
134
126
|
{!disableEditing && (
|
|
135
127
|
<Flexbox align={'flex-start'} className={styles.actions} role="menubar">
|
|
136
128
|
<GroupActionsBar
|
|
137
129
|
contentBlock={lastAssistantMsg}
|
|
138
130
|
contentId={contentId}
|
|
139
|
-
data={
|
|
131
|
+
data={item}
|
|
140
132
|
id={id}
|
|
141
133
|
index={index}
|
|
142
134
|
/>
|
|
@@ -4,6 +4,7 @@ import { UIChatMessage } from '@lobechat/types';
|
|
|
4
4
|
import { ModelIcon } from '@lobehub/icons';
|
|
5
5
|
import { Button, Text } from '@lobehub/ui';
|
|
6
6
|
import { createStyles, useTheme } from 'antd-style';
|
|
7
|
+
import isEqual from 'fast-deep-equal';
|
|
7
8
|
import { LucideRefreshCw } from 'lucide-react';
|
|
8
9
|
import { memo, useCallback } from 'react';
|
|
9
10
|
import { useTranslation } from 'react-i18next';
|
|
@@ -12,6 +13,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
12
13
|
import { DEFAULT_SUPERVISOR_AVATAR } from '@/const/meta';
|
|
13
14
|
import { ChatItem } from '@/features/ChatItem';
|
|
14
15
|
import { useChatStore } from '@/store/chat';
|
|
16
|
+
import { displayMessageSelectors } from '@/store/chat/slices/message/selectors';
|
|
15
17
|
import { ChatErrorType } from '@/types/fetch';
|
|
16
18
|
|
|
17
19
|
import TodoList, { TodoData } from './TodoList';
|
|
@@ -54,13 +56,20 @@ const parseMarkdownTodos = (content: string): TodoData => {
|
|
|
54
56
|
};
|
|
55
57
|
};
|
|
56
58
|
|
|
57
|
-
interface SupervisorMessageProps
|
|
59
|
+
interface SupervisorMessageProps {
|
|
58
60
|
disableEditing?: boolean;
|
|
61
|
+
id: string;
|
|
59
62
|
index: number;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
const SupervisorMessage = memo<SupervisorMessageProps>((
|
|
63
|
-
const
|
|
65
|
+
const SupervisorMessage = memo<SupervisorMessageProps>(({ id }) => {
|
|
66
|
+
const item = useChatStore(
|
|
67
|
+
displayMessageSelectors.getDisplayMessageById(id),
|
|
68
|
+
isEqual,
|
|
69
|
+
) as UIChatMessage;
|
|
70
|
+
|
|
71
|
+
const { content, error, groupId, role, updatedAt, createdAt } = item;
|
|
72
|
+
|
|
64
73
|
const { t } = useTranslation('chat');
|
|
65
74
|
const theme = useTheme();
|
|
66
75
|
const { styles } = useStyles();
|
|
@@ -128,8 +137,8 @@ const SupervisorMessage = memo<SupervisorMessageProps>((props) => {
|
|
|
128
137
|
|
|
129
138
|
// Render todo message with dedicated component
|
|
130
139
|
if (isTodoMessage && todoData) {
|
|
131
|
-
const model =
|
|
132
|
-
const provider =
|
|
140
|
+
const model = item.extra?.model;
|
|
141
|
+
const provider = item.extra?.provider;
|
|
133
142
|
const hasModelInfo = model || provider;
|
|
134
143
|
|
|
135
144
|
return (
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { UIChatMessage } from '@lobechat/types';
|
|
2
2
|
import { Tag } from '@lobehub/ui';
|
|
3
3
|
import { useResponsive } from 'antd-style';
|
|
4
|
+
import isEqual from 'fast-deep-equal';
|
|
4
5
|
import { ReactNode, memo, useCallback, useMemo } from 'react';
|
|
5
6
|
import { useTranslation } from 'react-i18next';
|
|
6
7
|
import { Flexbox } from 'react-layout-kit';
|
|
@@ -15,7 +16,7 @@ import { useUserAvatar } from '@/hooks/useUserAvatar';
|
|
|
15
16
|
import { useAgentStore } from '@/store/agent';
|
|
16
17
|
import { agentChatConfigSelectors } from '@/store/agent/selectors';
|
|
17
18
|
import { useChatStore } from '@/store/chat';
|
|
18
|
-
import { messageStateSelectors } from '@/store/chat/selectors';
|
|
19
|
+
import { displayMessageSelectors, messageStateSelectors } from '@/store/chat/selectors';
|
|
19
20
|
import { useSessionStore } from '@/store/session';
|
|
20
21
|
import { sessionSelectors } from '@/store/session/selectors';
|
|
21
22
|
import { useUserStore } from '@/store/user';
|
|
@@ -28,8 +29,9 @@ import { UserMessageExtra } from './Extra';
|
|
|
28
29
|
import { MarkdownRender as UserMarkdownRender } from './MarkdownRender';
|
|
29
30
|
import { UserMessageContent } from './MessageContent';
|
|
30
31
|
|
|
31
|
-
interface UserMessageProps
|
|
32
|
+
interface UserMessageProps {
|
|
32
33
|
disableEditing?: boolean;
|
|
34
|
+
id: string;
|
|
33
35
|
index: number;
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -43,9 +45,13 @@ const remarkPlugins = markdownElements
|
|
|
43
45
|
.map((element) => element.remarkPlugin)
|
|
44
46
|
.filter(Boolean);
|
|
45
47
|
|
|
46
|
-
const UserMessage = memo<UserMessageProps>((
|
|
47
|
-
const
|
|
48
|
-
|
|
48
|
+
const UserMessage = memo<UserMessageProps>(({ id, disableEditing, index }) => {
|
|
49
|
+
const item = useChatStore(
|
|
50
|
+
displayMessageSelectors.getDisplayMessageById(id),
|
|
51
|
+
isEqual,
|
|
52
|
+
) as UIChatMessage;
|
|
53
|
+
|
|
54
|
+
const { ragQuery, content, createdAt, error, role, extra, targetId } = item;
|
|
49
55
|
|
|
50
56
|
const { t } = useTranslation('chat');
|
|
51
57
|
const { mobile } = useResponsive();
|
|
@@ -97,9 +103,9 @@ const UserMessage = memo<UserMessageProps>((props) => {
|
|
|
97
103
|
|
|
98
104
|
const renderMessage = useCallback(
|
|
99
105
|
(editableContent: ReactNode) => (
|
|
100
|
-
<UserMessageContent {...
|
|
106
|
+
<UserMessageContent {...item} editableContent={editableContent} />
|
|
101
107
|
),
|
|
102
|
-
[
|
|
108
|
+
[item],
|
|
103
109
|
);
|
|
104
110
|
|
|
105
111
|
const components = useMemo(
|
|
@@ -178,7 +184,7 @@ const UserMessage = memo<UserMessageProps>((props) => {
|
|
|
178
184
|
</Flexbox>
|
|
179
185
|
|
|
180
186
|
<Flexbox direction={'horizontal-reverse'}>
|
|
181
|
-
<Actions data={
|
|
187
|
+
<Actions data={item} disableEditing={disableEditing} id={id} index={index} />
|
|
182
188
|
</Flexbox>
|
|
183
189
|
</Flexbox>
|
|
184
190
|
);
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
removeVirtuosoVisibleItem,
|
|
11
11
|
upsertVirtuosoVisibleItem,
|
|
12
12
|
} from '@/features/Conversation/components/VirtualizedList/VirtuosoContext';
|
|
13
|
-
import { useChatStore } from '@/store/chat';
|
|
13
|
+
import { getChatStoreState, useChatStore } from '@/store/chat';
|
|
14
14
|
import { displayMessageSelectors, messageStateSelectors } from '@/store/chat/selectors';
|
|
15
15
|
|
|
16
16
|
import History from '../components/History';
|
|
@@ -56,9 +56,10 @@ const Item = memo<ChatListItemProps>(
|
|
|
56
56
|
const { styles, cx } = useStyles();
|
|
57
57
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
58
58
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
const [isMessageLoading, role] = useChatStore((s) => [
|
|
60
|
+
messageStateSelectors.isMessageLoading(id)(s),
|
|
61
|
+
displayMessageSelectors.getDisplayMessageById(id)(s)?.role,
|
|
62
|
+
]);
|
|
62
63
|
|
|
63
64
|
// ======================= Performance Optimization ======================= //
|
|
64
65
|
// these useMemo/useCallback are all for the performance optimization
|
|
@@ -104,6 +105,8 @@ const Item = memo<ChatListItemProps>(
|
|
|
104
105
|
}, [index]);
|
|
105
106
|
|
|
106
107
|
const onContextMenu = useCallback(async () => {
|
|
108
|
+
const item = displayMessageSelectors.getDisplayMessageById(id)(getChatStoreState());
|
|
109
|
+
|
|
107
110
|
if (isDesktop && item) {
|
|
108
111
|
const { electronSystemService } = await import('@/services/electron/system');
|
|
109
112
|
|
|
@@ -114,45 +117,31 @@ const Item = memo<ChatListItemProps>(
|
|
|
114
117
|
role: item.role,
|
|
115
118
|
});
|
|
116
119
|
}
|
|
117
|
-
}, [id
|
|
120
|
+
}, [id]);
|
|
118
121
|
|
|
119
122
|
const renderContent = useMemo(() => {
|
|
120
|
-
switch (
|
|
123
|
+
switch (role) {
|
|
121
124
|
case 'user': {
|
|
122
|
-
return <UserMessage {
|
|
125
|
+
return <UserMessage disableEditing={disableEditing} id={id} index={index} />;
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
case 'assistant': {
|
|
126
|
-
return
|
|
127
|
-
<AssistantMessage
|
|
128
|
-
{...item}
|
|
129
|
-
disableEditing={disableEditing}
|
|
130
|
-
index={index}
|
|
131
|
-
showTitle={item.groupId ? true : false}
|
|
132
|
-
/>
|
|
133
|
-
);
|
|
129
|
+
return <AssistantMessage disableEditing={disableEditing} id={id} index={index} />;
|
|
134
130
|
}
|
|
135
131
|
|
|
136
132
|
case 'assistantGroup': {
|
|
137
|
-
return
|
|
138
|
-
<GroupMessage
|
|
139
|
-
{...item}
|
|
140
|
-
disableEditing={disableEditing}
|
|
141
|
-
index={index}
|
|
142
|
-
showTitle={item.groupId ? true : false}
|
|
143
|
-
/>
|
|
144
|
-
);
|
|
133
|
+
return <GroupMessage disableEditing={disableEditing} id={id} index={index} />;
|
|
145
134
|
}
|
|
146
135
|
|
|
147
136
|
case 'supervisor': {
|
|
148
|
-
return <SupervisorMessage {
|
|
137
|
+
return <SupervisorMessage disableEditing={disableEditing} id={id} index={index} />;
|
|
149
138
|
}
|
|
150
139
|
}
|
|
151
140
|
|
|
152
141
|
return null;
|
|
153
|
-
}, [
|
|
142
|
+
}, [role, disableEditing, id, index]);
|
|
154
143
|
|
|
155
|
-
if (!
|
|
144
|
+
if (!role) return;
|
|
156
145
|
|
|
157
146
|
return (
|
|
158
147
|
<InPortalThreadContext.Provider value={inPortalThread}>
|
|
@@ -169,6 +158,7 @@ const Item = memo<ChatListItemProps>(
|
|
|
169
158
|
</InPortalThreadContext.Provider>
|
|
170
159
|
);
|
|
171
160
|
},
|
|
161
|
+
isEqual,
|
|
172
162
|
);
|
|
173
163
|
|
|
174
164
|
Item.displayName = 'ChatItem';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ModelPerformance, ModelUsage } from '@lobechat/types';
|
|
2
2
|
import { Icon } from '@lobehub/ui';
|
|
3
3
|
import { Divider, Popover } from 'antd';
|
|
4
4
|
import { useTheme } from 'antd-style';
|
|
@@ -20,12 +20,13 @@ import TokenProgress, { TokenProgressItem } from './TokenProgress';
|
|
|
20
20
|
import { getDetailsToken } from './tokens';
|
|
21
21
|
|
|
22
22
|
interface TokenDetailProps {
|
|
23
|
-
meta: MessageMetadata;
|
|
24
23
|
model: string;
|
|
24
|
+
performance?: ModelPerformance;
|
|
25
25
|
provider: string;
|
|
26
|
+
usage: ModelUsage;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
const TokenDetail = memo<TokenDetailProps>(({
|
|
29
|
+
const TokenDetail = memo<TokenDetailProps>(({ usage, performance, model, provider }) => {
|
|
29
30
|
const { t } = useTranslation('chat');
|
|
30
31
|
const theme = useTheme();
|
|
31
32
|
const isMobile = useIsMobile();
|
|
@@ -37,7 +38,7 @@ const TokenDetail = memo<TokenDetailProps>(({ meta, model, provider }) => {
|
|
|
37
38
|
const modelCard = useAiInfraStore(aiModelSelectors.getModelCard(model, provider));
|
|
38
39
|
const isShowCredit = useGlobalStore(systemStatusSelectors.isShowCredit) && !!modelCard?.pricing;
|
|
39
40
|
|
|
40
|
-
const detailTokens = getDetailsToken(
|
|
41
|
+
const detailTokens = getDetailsToken(usage, modelCard);
|
|
41
42
|
const inputDetails = [
|
|
42
43
|
!!detailTokens.inputAudio && {
|
|
43
44
|
color: theme.cyan9,
|
|
@@ -130,8 +131,8 @@ const TokenDetail = memo<TokenDetailProps>(({ meta, model, provider }) => {
|
|
|
130
131
|
2,
|
|
131
132
|
);
|
|
132
133
|
|
|
133
|
-
const tps =
|
|
134
|
-
const ttft =
|
|
134
|
+
const tps = performance?.tps ? formatNumber(performance.tps, 2) : undefined;
|
|
135
|
+
const ttft = performance?.ttft ? formatNumber(performance.ttft / 1000, 2) : undefined;
|
|
135
136
|
|
|
136
137
|
return (
|
|
137
138
|
<Popover
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ModelUsage } from '@lobechat/types';
|
|
2
2
|
import { LobeDefaultAiModelListItem } from 'model-bank';
|
|
3
3
|
|
|
4
4
|
import { getAudioInputUnitRate, getAudioOutputUnitRate } from '@/utils/pricing';
|
|
@@ -11,10 +11,7 @@ const calcCredit = (token: number, pricing?: number) => {
|
|
|
11
11
|
return parseInt((token * pricing).toFixed(0));
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export const getDetailsToken = (
|
|
15
|
-
usage: ModelTokensUsage,
|
|
16
|
-
modelCard?: LobeDefaultAiModelListItem,
|
|
17
|
-
) => {
|
|
14
|
+
export const getDetailsToken = (usage: ModelUsage, modelCard?: LobeDefaultAiModelListItem) => {
|
|
18
15
|
const inputTextTokens = usage.inputTextTokens || (usage as any).inputTokens || 0;
|
|
19
16
|
const totalInputTokens = usage.totalInputTokens || (usage as any).inputTokens || 0;
|
|
20
17
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ModelPerformance, ModelUsage } from '@lobechat/types';
|
|
2
2
|
import { ModelIcon } from '@lobehub/icons';
|
|
3
3
|
import { createStyles } from 'antd-style';
|
|
4
|
+
import isEqual from 'fast-deep-equal';
|
|
4
5
|
import { memo } from 'react';
|
|
5
6
|
import { Center, Flexbox } from 'react-layout-kit';
|
|
6
7
|
|
|
@@ -14,12 +15,13 @@ export const useStyles = createStyles(({ token, css, cx }) => ({
|
|
|
14
15
|
}));
|
|
15
16
|
|
|
16
17
|
interface UsageProps {
|
|
17
|
-
metadata: MessageMetadata;
|
|
18
18
|
model: string;
|
|
19
|
+
performance?: ModelPerformance;
|
|
19
20
|
provider: string;
|
|
21
|
+
usage?: ModelUsage;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
const Usage = memo<UsageProps>(({ model,
|
|
24
|
+
const Usage = memo<UsageProps>(({ model, usage, performance, provider }) => {
|
|
23
25
|
const { styles } = useStyles();
|
|
24
26
|
|
|
25
27
|
return (
|
|
@@ -35,11 +37,16 @@ const Usage = memo<UsageProps>(({ model, metadata, provider }) => {
|
|
|
35
37
|
{model}
|
|
36
38
|
</Center>
|
|
37
39
|
|
|
38
|
-
{!!
|
|
39
|
-
<TokenDetail
|
|
40
|
+
{!!usage?.totalTokens && (
|
|
41
|
+
<TokenDetail
|
|
42
|
+
model={model as string}
|
|
43
|
+
performance={performance}
|
|
44
|
+
provider={provider}
|
|
45
|
+
usage={usage}
|
|
46
|
+
/>
|
|
40
47
|
)}
|
|
41
48
|
</Flexbox>
|
|
42
49
|
);
|
|
43
|
-
});
|
|
50
|
+
}, isEqual);
|
|
44
51
|
|
|
45
52
|
export default Usage;
|