@lobehub/chat 1.51.1 → 1.51.3
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 +66 -0
- package/Dockerfile +1 -1
- package/Dockerfile.database +1 -1
- package/changelog/v1.json +21 -0
- package/docs/usage/providers/wenxin.mdx +16 -13
- package/docs/usage/providers/wenxin.zh-CN.mdx +11 -8
- package/next.config.ts +6 -0
- package/package.json +1 -2
- package/src/app/(main)/settings/llm/ProviderList/providers.tsx +2 -4
- package/src/config/aiModels/ai360.ts +22 -2
- package/src/config/aiModels/fireworksai.ts +3 -0
- package/src/config/aiModels/giteeai.ts +60 -0
- package/src/config/aiModels/github.ts +7 -0
- package/src/config/aiModels/google.ts +2 -0
- package/src/config/aiModels/groq.ts +12 -0
- package/src/config/aiModels/huggingface.ts +6 -0
- package/src/config/aiModels/internlm.ts +19 -2
- package/src/config/aiModels/ollama.ts +1 -0
- package/src/config/aiModels/openai.ts +10 -0
- package/src/config/aiModels/perplexity.ts +3 -0
- package/src/config/aiModels/qwen.ts +2 -0
- package/src/config/aiModels/siliconcloud.ts +4 -0
- package/src/config/aiModels/togetherai.ts +64 -1
- package/src/config/aiModels/wenxin.ts +125 -19
- package/src/config/aiModels/zhipu.ts +3 -0
- package/src/config/llm.ts +3 -5
- package/src/config/modelProviders/wenxin.ts +100 -23
- package/src/const/auth.ts +0 -3
- package/src/features/Conversation/Error/APIKeyForm/index.tsx +0 -3
- package/src/features/Conversation/components/ChatItem/utils.test.ts +284 -0
- package/src/features/Conversation/components/ChatItem/utils.ts +39 -8
- package/src/features/Conversation/components/MarkdownElements/LobeArtifact/rehypePlugin.test.ts +125 -0
- package/src/features/DevPanel/CacheViewer/DataTable/index.tsx +33 -0
- package/src/features/DevPanel/CacheViewer/cacheProvider.tsx +64 -0
- package/src/features/DevPanel/CacheViewer/getCacheEntries.ts +52 -0
- package/src/features/DevPanel/CacheViewer/index.tsx +25 -0
- package/src/features/DevPanel/CacheViewer/schema.ts +49 -0
- package/src/features/DevPanel/FeatureFlagViewer/Form.tsx +93 -0
- package/src/features/DevPanel/FeatureFlagViewer/index.tsx +11 -0
- package/src/features/DevPanel/MetadataViewer/Ld.tsx +25 -0
- package/src/features/DevPanel/MetadataViewer/MetaData.tsx +30 -0
- package/src/features/DevPanel/MetadataViewer/Og.tsx +75 -0
- package/src/features/DevPanel/MetadataViewer/index.tsx +80 -0
- package/src/features/DevPanel/MetadataViewer/useHead.ts +16 -0
- package/src/features/DevPanel/PostgresViewer/DataTable/index.tsx +39 -49
- package/src/features/DevPanel/PostgresViewer/{TableColumns.tsx → SchemaSidebar/Columns.tsx} +6 -4
- package/src/features/DevPanel/PostgresViewer/{Schema.tsx → SchemaSidebar/index.tsx} +49 -55
- package/src/features/DevPanel/PostgresViewer/index.tsx +4 -2
- package/src/features/DevPanel/features/FloatPanel.tsx +218 -0
- package/src/features/DevPanel/features/Header.tsx +50 -0
- package/src/features/DevPanel/features/Table/TableCell.tsx +73 -0
- package/src/features/DevPanel/features/Table/TooltipContent.tsx +39 -0
- package/src/features/DevPanel/{PostgresViewer/DataTable/Table.tsx → features/Table/index.tsx} +12 -14
- package/src/features/DevPanel/index.tsx +29 -5
- package/src/libs/agent-runtime/AgentRuntime.test.ts +0 -1
- package/src/libs/agent-runtime/AgentRuntime.ts +7 -0
- package/src/libs/agent-runtime/wenxin/index.ts +10 -107
- package/src/locales/default/modelProvider.ts +0 -20
- package/src/server/modules/AgentRuntime/index.test.ts +0 -21
- package/src/services/_auth.ts +0 -14
- package/src/store/chat/slices/portal/selectors.test.ts +169 -3
- package/src/store/chat/slices/portal/selectors.ts +6 -1
- package/src/store/user/slices/modelList/selectors/keyVaults.ts +0 -2
- package/src/types/aiProvider.ts +0 -1
- package/src/types/user/settings/keyVaults.ts +1 -6
- package/src/app/(backend)/webapi/chat/wenxin/route.test.ts +0 -27
- package/src/app/(backend)/webapi/chat/wenxin/route.ts +0 -30
- package/src/app/(main)/settings/llm/ProviderList/Wenxin/index.tsx +0 -44
- package/src/app/(main)/settings/provider/(detail)/wenxin/page.tsx +0 -61
- package/src/features/Conversation/Error/APIKeyForm/Wenxin.tsx +0 -49
- package/src/features/DevPanel/FloatPanel.tsx +0 -136
- package/src/features/DevPanel/PostgresViewer/DataTable/TableCell.tsx +0 -34
- package/src/libs/agent-runtime/utils/streams/wenxin.test.ts +0 -153
- package/src/libs/agent-runtime/utils/streams/wenxin.ts +0 -38
- package/src/libs/agent-runtime/wenxin/type.ts +0 -84
@@ -0,0 +1,218 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { ActionIcon, FluentEmoji, Icon, SideNav } from '@lobehub/ui';
|
4
|
+
import { Dropdown, FloatButton } from 'antd';
|
5
|
+
import { createStyles } from 'antd-style';
|
6
|
+
import { BugIcon, BugOff, XIcon } from 'lucide-react';
|
7
|
+
import { ReactNode, memo, useEffect, useState } from 'react';
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
9
|
+
import { Rnd } from 'react-rnd';
|
10
|
+
|
11
|
+
import { BRANDING_NAME } from '@/const/branding';
|
12
|
+
|
13
|
+
// 定义样式
|
14
|
+
const useStyles = createStyles(({ token, css, prefixCls }) => {
|
15
|
+
return {
|
16
|
+
collapsed: css`
|
17
|
+
pointer-events: none;
|
18
|
+
transform: scale(0.8);
|
19
|
+
opacity: 0;
|
20
|
+
`,
|
21
|
+
expanded: css`
|
22
|
+
pointer-events: auto;
|
23
|
+
transform: scale(1);
|
24
|
+
opacity: 1;
|
25
|
+
`,
|
26
|
+
floatButton: css`
|
27
|
+
inset-block-end: 16px;
|
28
|
+
inset-inline-end: 16px;
|
29
|
+
|
30
|
+
width: 36px;
|
31
|
+
height: 36px;
|
32
|
+
border: 1px solid ${token.colorBorderSecondary};
|
33
|
+
|
34
|
+
font-size: 20px;
|
35
|
+
.${prefixCls}-float-btn-body {
|
36
|
+
background: ${token.colorBgLayout};
|
37
|
+
|
38
|
+
&:hover {
|
39
|
+
width: auto;
|
40
|
+
background: ${token.colorBgElevated};
|
41
|
+
}
|
42
|
+
}
|
43
|
+
`,
|
44
|
+
header: css`
|
45
|
+
cursor: move;
|
46
|
+
user-select: none;
|
47
|
+
|
48
|
+
padding-block: 8px;
|
49
|
+
padding-inline: 16px;
|
50
|
+
border-block-end: 1px solid ${token.colorBorderSecondary};
|
51
|
+
|
52
|
+
color: ${token.colorText};
|
53
|
+
|
54
|
+
background: ${token.colorFillAlter};
|
55
|
+
`,
|
56
|
+
panel: css`
|
57
|
+
position: fixed;
|
58
|
+
z-index: 1000;
|
59
|
+
|
60
|
+
overflow: hidden;
|
61
|
+
display: flex;
|
62
|
+
|
63
|
+
border: 1px solid ${token.colorBorderSecondary};
|
64
|
+
border-radius: 12px;
|
65
|
+
|
66
|
+
background: ${token.colorBgContainer};
|
67
|
+
box-shadow: ${token.boxShadow};
|
68
|
+
|
69
|
+
transition: opacity ${token.motionDurationMid} ${token.motionEaseInOut};
|
70
|
+
`,
|
71
|
+
};
|
72
|
+
});
|
73
|
+
|
74
|
+
const minWidth = 800;
|
75
|
+
const minHeight = 600;
|
76
|
+
|
77
|
+
interface CollapsibleFloatPanelProps {
|
78
|
+
items: { children: ReactNode; icon: ReactNode; key: string }[];
|
79
|
+
}
|
80
|
+
|
81
|
+
const CollapsibleFloatPanel = memo<CollapsibleFloatPanelProps>(({ items }) => {
|
82
|
+
const { styles, theme } = useStyles();
|
83
|
+
const [tab, setTab] = useState<string>(items[0].key);
|
84
|
+
const [isHide, setIsHide] = useState(false);
|
85
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
86
|
+
const [position, setPosition] = useState({ x: 100, y: 100 });
|
87
|
+
const [size, setSize] = useState({ height: minHeight, width: minWidth });
|
88
|
+
|
89
|
+
useEffect(() => {
|
90
|
+
try {
|
91
|
+
const localStoragePosition = localStorage.getItem('debug-panel-position');
|
92
|
+
if (localStoragePosition && JSON.parse(localStoragePosition)) {
|
93
|
+
setPosition(JSON.parse(localStoragePosition));
|
94
|
+
}
|
95
|
+
} catch {
|
96
|
+
/* empty */
|
97
|
+
}
|
98
|
+
|
99
|
+
try {
|
100
|
+
const localStorageSize = localStorage.getItem('debug-panel-size');
|
101
|
+
if (localStorageSize && JSON.parse(localStorageSize)) {
|
102
|
+
setSize(JSON.parse(localStorageSize));
|
103
|
+
}
|
104
|
+
} catch {
|
105
|
+
/* empty */
|
106
|
+
}
|
107
|
+
}, []);
|
108
|
+
|
109
|
+
return (
|
110
|
+
<>
|
111
|
+
{!isHide && (
|
112
|
+
<Dropdown
|
113
|
+
menu={{
|
114
|
+
items: [
|
115
|
+
{
|
116
|
+
icon: (
|
117
|
+
<Icon color={theme.colorTextSecondary} icon={BugOff} size={{ fontSize: 16 }} />
|
118
|
+
),
|
119
|
+
key: 'hide',
|
120
|
+
label: 'Hide Toolbar',
|
121
|
+
onClick: () => setIsHide(true),
|
122
|
+
},
|
123
|
+
],
|
124
|
+
}}
|
125
|
+
trigger={['hover']}
|
126
|
+
>
|
127
|
+
<FloatButton
|
128
|
+
className={styles.floatButton}
|
129
|
+
icon={<Icon icon={isExpanded ? BugOff : BugIcon} />}
|
130
|
+
onClick={() => setIsExpanded(!isExpanded)}
|
131
|
+
/>
|
132
|
+
</Dropdown>
|
133
|
+
)}
|
134
|
+
{isExpanded && (
|
135
|
+
<Rnd
|
136
|
+
bounds="window"
|
137
|
+
className={`${styles.panel} ${isExpanded ? styles.expanded : styles.collapsed}`}
|
138
|
+
dragHandleClassName="panel-drag-handle"
|
139
|
+
minHeight={minHeight}
|
140
|
+
minWidth={minWidth}
|
141
|
+
onDragStop={(e, d) => {
|
142
|
+
setPosition({ x: d.x, y: d.y });
|
143
|
+
}}
|
144
|
+
onResizeStop={(e, direction, ref, delta, position) => {
|
145
|
+
setSize({
|
146
|
+
height: Number(ref.style.height),
|
147
|
+
width: Number(ref.style.width),
|
148
|
+
});
|
149
|
+
setPosition(position);
|
150
|
+
}}
|
151
|
+
position={position}
|
152
|
+
size={size}
|
153
|
+
>
|
154
|
+
<Flexbox
|
155
|
+
height={'100%'}
|
156
|
+
horizontal
|
157
|
+
style={{ overflow: 'hidden', position: 'relative' }}
|
158
|
+
width={'100%'}
|
159
|
+
>
|
160
|
+
<SideNav
|
161
|
+
avatar={<FluentEmoji emoji={'🧰'} size={24} />}
|
162
|
+
bottomActions={[]}
|
163
|
+
style={{
|
164
|
+
paddingBlock: 12,
|
165
|
+
width: 48,
|
166
|
+
}}
|
167
|
+
topActions={items.map((item) => (
|
168
|
+
<ActionIcon
|
169
|
+
active={tab === item.key}
|
170
|
+
key={item.key}
|
171
|
+
onClick={() => setTab(item.key)}
|
172
|
+
placement={'right'}
|
173
|
+
title={item.key}
|
174
|
+
>
|
175
|
+
{item.icon}
|
176
|
+
</ActionIcon>
|
177
|
+
))}
|
178
|
+
/>
|
179
|
+
<Flexbox
|
180
|
+
height={'100%'}
|
181
|
+
style={{ overflow: 'hidden', position: 'relative' }}
|
182
|
+
width={'100%'}
|
183
|
+
>
|
184
|
+
<Flexbox
|
185
|
+
align={'center'}
|
186
|
+
className={`panel-drag-handle ${styles.header}`}
|
187
|
+
horizontal
|
188
|
+
justify={'space-between'}
|
189
|
+
>
|
190
|
+
<Flexbox align={'baseline'} gap={6} horizontal>
|
191
|
+
<b>{BRANDING_NAME} Dev Tools</b>
|
192
|
+
<span style={{ color: theme.colorTextDescription }}>/</span>
|
193
|
+
<span style={{ color: theme.colorTextDescription }}>{tab}</span>
|
194
|
+
</Flexbox>
|
195
|
+
<ActionIcon icon={XIcon} onClick={() => setIsExpanded(false)} />
|
196
|
+
</Flexbox>
|
197
|
+
{items.map((item) => (
|
198
|
+
<Flexbox
|
199
|
+
flex={1}
|
200
|
+
height={'100%'}
|
201
|
+
key={item.key}
|
202
|
+
style={{
|
203
|
+
display: tab === item.key ? 'flex' : 'none',
|
204
|
+
overflow: 'hidden',
|
205
|
+
}}
|
206
|
+
>
|
207
|
+
{item.children}
|
208
|
+
</Flexbox>
|
209
|
+
))}
|
210
|
+
</Flexbox>
|
211
|
+
</Flexbox>
|
212
|
+
</Rnd>
|
213
|
+
)}
|
214
|
+
</>
|
215
|
+
);
|
216
|
+
});
|
217
|
+
|
218
|
+
export default CollapsibleFloatPanel;
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { ActionIcon, type ActionIconProps } from '@lobehub/ui';
|
2
|
+
import { createStyles } from 'antd-style';
|
3
|
+
import React, { ReactNode } from 'react';
|
4
|
+
import { Flexbox, FlexboxProps } from 'react-layout-kit';
|
5
|
+
|
6
|
+
const useStyles = createStyles(({ token, css }) => ({
|
7
|
+
header: css`
|
8
|
+
border-block-end: 1px solid ${token.colorBorderSecondary};
|
9
|
+
`,
|
10
|
+
title: css`
|
11
|
+
font-weight: 550;
|
12
|
+
`,
|
13
|
+
}));
|
14
|
+
|
15
|
+
interface HeaderProps extends Omit<FlexboxProps, 'title' | 'children'> {
|
16
|
+
actions?: ActionIconProps[];
|
17
|
+
extra?: ReactNode;
|
18
|
+
title?: ReactNode;
|
19
|
+
}
|
20
|
+
|
21
|
+
const Header = ({ title, actions = [], extra, ...rest }: HeaderProps) => {
|
22
|
+
const { styles } = useStyles();
|
23
|
+
|
24
|
+
return (
|
25
|
+
<Flexbox
|
26
|
+
align={'center'}
|
27
|
+
className={styles.header}
|
28
|
+
flex={'none'}
|
29
|
+
height={46}
|
30
|
+
horizontal
|
31
|
+
justify={'space-between'}
|
32
|
+
paddingInline={16}
|
33
|
+
{...rest}
|
34
|
+
>
|
35
|
+
<div className={styles.title}>{title}</div>
|
36
|
+
<Flexbox align={'center'} gap={4} horizontal>
|
37
|
+
{extra}
|
38
|
+
{actions.map((action, index) => (
|
39
|
+
<ActionIcon
|
40
|
+
{...action}
|
41
|
+
key={action.title || index}
|
42
|
+
size={{ blockSize: 28, fontSize: 16 }}
|
43
|
+
/>
|
44
|
+
))}
|
45
|
+
</Flexbox>
|
46
|
+
</Flexbox>
|
47
|
+
);
|
48
|
+
};
|
49
|
+
|
50
|
+
export default Header;
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import { Typography } from 'antd';
|
2
|
+
import { createStyles } from 'antd-style';
|
3
|
+
import dayjs from 'dayjs';
|
4
|
+
import { get, isDate } from 'lodash-es';
|
5
|
+
import React, { useMemo } from 'react';
|
6
|
+
|
7
|
+
import TooltipContent from './TooltipContent';
|
8
|
+
|
9
|
+
const { Text } = Typography;
|
10
|
+
|
11
|
+
const useStyles = createStyles(({ token, css }) => ({
|
12
|
+
cell: css`
|
13
|
+
font-family: ${token.fontFamilyCode};
|
14
|
+
font-size: ${token.fontSizeSM}px;
|
15
|
+
`,
|
16
|
+
tooltip: css`
|
17
|
+
border: 1px solid ${token.colorBorder};
|
18
|
+
|
19
|
+
font-family: ${token.fontFamilyCode};
|
20
|
+
font-size: ${token.fontSizeSM}px;
|
21
|
+
color: ${token.colorText} !important;
|
22
|
+
word-break: break-all;
|
23
|
+
|
24
|
+
background: ${token.colorBgElevated} !important;
|
25
|
+
`,
|
26
|
+
}));
|
27
|
+
|
28
|
+
interface TableCellProps {
|
29
|
+
column: string;
|
30
|
+
dataItem: any;
|
31
|
+
rowIndex: number;
|
32
|
+
}
|
33
|
+
|
34
|
+
const TableCell = ({ dataItem, column, rowIndex }: TableCellProps) => {
|
35
|
+
const { styles } = useStyles();
|
36
|
+
const data = get(dataItem, column);
|
37
|
+
const content = useMemo(() => {
|
38
|
+
if (isDate(data)) return dayjs(data).format('YYYY-MM-DD HH:mm:ss');
|
39
|
+
|
40
|
+
switch (typeof data) {
|
41
|
+
case 'object': {
|
42
|
+
return JSON.stringify(data);
|
43
|
+
}
|
44
|
+
|
45
|
+
case 'boolean': {
|
46
|
+
return data ? 'True' : 'False';
|
47
|
+
}
|
48
|
+
|
49
|
+
default: {
|
50
|
+
return data;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}, [data]);
|
54
|
+
|
55
|
+
return (
|
56
|
+
<td key={column} onDoubleClick={() => console.log('Edit cell:', rowIndex, column)}>
|
57
|
+
<Text
|
58
|
+
className={styles.cell}
|
59
|
+
ellipsis={{
|
60
|
+
tooltip: {
|
61
|
+
arrow: false,
|
62
|
+
classNames: { body: styles.tooltip },
|
63
|
+
title: <TooltipContent>{content}</TooltipContent>,
|
64
|
+
},
|
65
|
+
}}
|
66
|
+
>
|
67
|
+
{content}
|
68
|
+
</Text>
|
69
|
+
</td>
|
70
|
+
);
|
71
|
+
};
|
72
|
+
|
73
|
+
export default TableCell;
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { Highlighter } from '@lobehub/ui';
|
2
|
+
import Link from 'next/link';
|
3
|
+
import { ReactNode, memo } from 'react';
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
5
|
+
|
6
|
+
const TooltipContent = memo<{ children: ReactNode }>(({ children }) => {
|
7
|
+
if (typeof children !== 'string') return children;
|
8
|
+
|
9
|
+
if (children.startsWith('data:image')) {
|
10
|
+
return <img src={children} style={{ height: 'auto', maxWidth: '100%' }} />;
|
11
|
+
}
|
12
|
+
|
13
|
+
if (children.startsWith('http'))
|
14
|
+
return (
|
15
|
+
<Link href={children} target={'_blank'}>
|
16
|
+
{children}
|
17
|
+
</Link>
|
18
|
+
);
|
19
|
+
|
20
|
+
const code = children.trim().trimEnd();
|
21
|
+
|
22
|
+
if ((code.startsWith('{') && code.endsWith('}')) || (code.startsWith('[') && code.endsWith(']')))
|
23
|
+
return (
|
24
|
+
<Highlighter
|
25
|
+
language={'json'}
|
26
|
+
style={{
|
27
|
+
maxHeight: 400,
|
28
|
+
overflow: 'auto',
|
29
|
+
}}
|
30
|
+
type={'pure'}
|
31
|
+
>
|
32
|
+
{JSON.stringify(JSON.parse(code), null, 2)}
|
33
|
+
</Highlighter>
|
34
|
+
);
|
35
|
+
|
36
|
+
return <Flexbox>{children}</Flexbox>;
|
37
|
+
});
|
38
|
+
|
39
|
+
export default TooltipContent;
|
package/src/features/DevPanel/{PostgresViewer/DataTable/Table.tsx → features/Table/index.tsx}
RENAMED
@@ -1,9 +1,10 @@
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
1
2
|
import { createStyles } from 'antd-style';
|
3
|
+
import { Loader2Icon } from 'lucide-react';
|
2
4
|
import React from 'react';
|
3
5
|
import { Center } from 'react-layout-kit';
|
4
6
|
import { TableVirtuoso } from 'react-virtuoso';
|
5
7
|
|
6
|
-
import { usePgTable, useTableColumns } from '../usePgTable';
|
7
8
|
import TableCell from './TableCell';
|
8
9
|
|
9
10
|
const useStyles = createStyles(({ token, css }) => ({
|
@@ -88,24 +89,21 @@ const useStyles = createStyles(({ token, css }) => ({
|
|
88
89
|
}));
|
89
90
|
|
90
91
|
interface TableProps {
|
91
|
-
|
92
|
+
columns: string[];
|
93
|
+
dataSource: any[];
|
94
|
+
loading?: boolean;
|
92
95
|
}
|
93
96
|
|
94
|
-
const Table = ({
|
97
|
+
const Table = ({ columns, dataSource, loading }: TableProps) => {
|
95
98
|
const { styles } = useStyles();
|
96
99
|
|
97
|
-
|
100
|
+
if (loading)
|
101
|
+
return (
|
102
|
+
<Center height={'100%'}>
|
103
|
+
<Icon icon={Loader2Icon} spin />
|
104
|
+
</Center>
|
105
|
+
);
|
98
106
|
|
99
|
-
const tableData = usePgTable(tableName);
|
100
|
-
|
101
|
-
const columns = tableColumns.data?.map((t) => t.name) || [];
|
102
|
-
const isLoading = tableColumns.isLoading || tableData.isLoading;
|
103
|
-
|
104
|
-
if (!tableName) return <Center height={'80%'}>Select a table to view data</Center>;
|
105
|
-
|
106
|
-
if (isLoading) return <Center height={'80%'}>Loading...</Center>;
|
107
|
-
|
108
|
-
const dataSource = tableData.data?.data || [];
|
109
107
|
const header = (
|
110
108
|
<tr>
|
111
109
|
{columns.map((column) => (
|
@@ -1,12 +1,36 @@
|
|
1
|
-
|
1
|
+
import { BookText, DatabaseIcon, FlagIcon, GlobeLockIcon } from 'lucide-react';
|
2
2
|
|
3
|
-
import
|
3
|
+
import CacheViewer from './CacheViewer';
|
4
|
+
import FeatureFlagViewer from './FeatureFlagViewer';
|
5
|
+
import MetadataViewer from './MetadataViewer';
|
4
6
|
import PostgresViewer from './PostgresViewer';
|
7
|
+
import FloatPanel from './features/FloatPanel';
|
5
8
|
|
6
9
|
const DevPanel = () => (
|
7
|
-
<FloatPanel
|
8
|
-
|
9
|
-
|
10
|
+
<FloatPanel
|
11
|
+
items={[
|
12
|
+
{
|
13
|
+
children: <PostgresViewer />,
|
14
|
+
icon: <DatabaseIcon size={16} />,
|
15
|
+
key: 'Postgres Viewer',
|
16
|
+
},
|
17
|
+
{
|
18
|
+
children: <MetadataViewer />,
|
19
|
+
icon: <BookText size={16} />,
|
20
|
+
key: 'SEO Metadata',
|
21
|
+
},
|
22
|
+
{
|
23
|
+
children: <CacheViewer />,
|
24
|
+
icon: <GlobeLockIcon size={16} />,
|
25
|
+
key: 'NextJS Caches',
|
26
|
+
},
|
27
|
+
{
|
28
|
+
children: <FeatureFlagViewer />,
|
29
|
+
icon: <FlagIcon size={16} />,
|
30
|
+
key: 'Feature Flags',
|
31
|
+
},
|
32
|
+
]}
|
33
|
+
/>
|
10
34
|
);
|
11
35
|
|
12
36
|
export default DevPanel;
|
@@ -26,7 +26,6 @@ import {
|
|
26
26
|
ModelProvider,
|
27
27
|
} from '@/libs/agent-runtime';
|
28
28
|
import { LobeStepfunAI } from '@/libs/agent-runtime/stepfun';
|
29
|
-
import LobeWenxinAI from '@/libs/agent-runtime/wenxin';
|
30
29
|
import { createTraceOptions } from '@/server/modules/AgentRuntime';
|
31
30
|
|
32
31
|
import { AgentChatOptions } from './AgentRuntime';
|
@@ -47,6 +47,7 @@ import {
|
|
47
47
|
TextToSpeechPayload,
|
48
48
|
} from './types';
|
49
49
|
import { LobeUpstageAI } from './upstage';
|
50
|
+
import { LobeWenxinAI } from './wenxin';
|
50
51
|
import { LobeXAI } from './xai';
|
51
52
|
import { LobeZeroOneAI } from './zeroone';
|
52
53
|
import { LobeZhipuAI } from './zhipu';
|
@@ -167,6 +168,7 @@ class AgentRuntime {
|
|
167
168
|
taichu: Partial<ClientOptions>;
|
168
169
|
togetherai: Partial<ClientOptions>;
|
169
170
|
upstage: Partial<ClientOptions>;
|
171
|
+
wenxin: Partial<ClientOptions>;
|
170
172
|
xai: Partial<ClientOptions>;
|
171
173
|
zeroone: Partial<ClientOptions>;
|
172
174
|
zhipu: Partial<ClientOptions>;
|
@@ -370,6 +372,11 @@ class AgentRuntime {
|
|
370
372
|
runtimeModel = new LobeDoubaoAI(params.doubao);
|
371
373
|
break;
|
372
374
|
}
|
375
|
+
|
376
|
+
case ModelProvider.Wenxin: {
|
377
|
+
runtimeModel = new LobeWenxinAI(params.wenxin);
|
378
|
+
break;
|
379
|
+
}
|
373
380
|
}
|
374
381
|
return new AgentRuntime(runtimeModel);
|
375
382
|
}
|
@@ -1,107 +1,10 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
import { debugStream } from '../utils/debugStream';
|
12
|
-
import { StreamingResponse } from '../utils/response';
|
13
|
-
import { convertIterableToStream } from '../utils/streams';
|
14
|
-
import { WenxinStream } from '../utils/streams/wenxin';
|
15
|
-
import { ChatResp } from './type';
|
16
|
-
|
17
|
-
interface ChatErrorCode {
|
18
|
-
error_code: number;
|
19
|
-
error_msg: string;
|
20
|
-
}
|
21
|
-
|
22
|
-
export interface LobeWenxinAIParams {
|
23
|
-
accessKey?: string;
|
24
|
-
baseURL?: string;
|
25
|
-
secretKey?: string;
|
26
|
-
}
|
27
|
-
|
28
|
-
export class LobeWenxinAI implements LobeRuntimeAI {
|
29
|
-
private client: any;
|
30
|
-
baseURL?: string;
|
31
|
-
|
32
|
-
constructor({ accessKey, baseURL, secretKey }: LobeWenxinAIParams = {}) {
|
33
|
-
if (!accessKey || !secretKey)
|
34
|
-
throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidProviderAPIKey);
|
35
|
-
|
36
|
-
this.client = new ChatCompletion({
|
37
|
-
QIANFAN_ACCESS_KEY: accessKey,
|
38
|
-
QIANFAN_SECRET_KEY: secretKey,
|
39
|
-
});
|
40
|
-
this.baseURL = baseURL;
|
41
|
-
}
|
42
|
-
|
43
|
-
async chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions) {
|
44
|
-
try {
|
45
|
-
const result = await this.client.chat(
|
46
|
-
{ messages: payload.messages as any, stream: true, user_id: options?.user },
|
47
|
-
payload.model,
|
48
|
-
);
|
49
|
-
|
50
|
-
const wenxinStream = convertIterableToStream(result as AsyncIterable<ChatResp>);
|
51
|
-
|
52
|
-
const [prod, useForDebug] = wenxinStream.tee();
|
53
|
-
|
54
|
-
if (process.env.DEBUG_WENXIN_CHAT_COMPLETION === '1') {
|
55
|
-
debugStream(useForDebug).catch();
|
56
|
-
}
|
57
|
-
|
58
|
-
const stream = WenxinStream(prod, options?.callback);
|
59
|
-
|
60
|
-
// Respond with the stream
|
61
|
-
return StreamingResponse(stream, { headers: options?.headers });
|
62
|
-
} catch (e) {
|
63
|
-
const err = e as Error;
|
64
|
-
|
65
|
-
const error: ChatErrorCode | undefined = safeParseJSON(err.message);
|
66
|
-
|
67
|
-
if (!error) {
|
68
|
-
throw AgentRuntimeError.createError(AgentRuntimeErrorType.AgentRuntimeError, {
|
69
|
-
message: err.message,
|
70
|
-
name: err.name,
|
71
|
-
});
|
72
|
-
}
|
73
|
-
|
74
|
-
// 文心一言错误码
|
75
|
-
// https://cloud.baidu.com/doc/WENXINWORKSHOP/s/tlmyncueh
|
76
|
-
switch (error.error_code) {
|
77
|
-
// Invalid API key or access key
|
78
|
-
case 100:
|
79
|
-
case 13:
|
80
|
-
case 14: {
|
81
|
-
throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidProviderAPIKey, error);
|
82
|
-
}
|
83
|
-
|
84
|
-
// quota limit
|
85
|
-
case 4:
|
86
|
-
case 17:
|
87
|
-
case 18:
|
88
|
-
case 19:
|
89
|
-
case 336_501:
|
90
|
-
case 336_502:
|
91
|
-
case 336_503:
|
92
|
-
case 336_504:
|
93
|
-
case 336_505:
|
94
|
-
case 336_507: {
|
95
|
-
throw AgentRuntimeError.createError(AgentRuntimeErrorType.QuotaLimitReached, {
|
96
|
-
errorCode: error.error_code,
|
97
|
-
message: `${error.error_msg} | you can visit https://cloud.baidu.com/doc/WENXINWORKSHOP/s/tlmyncueh for more information about the error code`,
|
98
|
-
});
|
99
|
-
}
|
100
|
-
}
|
101
|
-
|
102
|
-
throw AgentRuntimeError.createError(AgentRuntimeErrorType.ProviderBizError, error);
|
103
|
-
}
|
104
|
-
}
|
105
|
-
}
|
106
|
-
|
107
|
-
export default LobeWenxinAI;
|
1
|
+
import { ModelProvider } from '../types';
|
2
|
+
import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
|
3
|
+
|
4
|
+
export const LobeWenxinAI = LobeOpenAICompatibleFactory({
|
5
|
+
baseURL: 'https://qianfan.baidubce.com/v2',
|
6
|
+
debug: {
|
7
|
+
chatCompletion: () => process.env.DEBUG_WENXIN_CHAT_COMPLETION === '1',
|
8
|
+
},
|
9
|
+
provider: ModelProvider.Wenxin,
|
10
|
+
});
|
@@ -296,26 +296,6 @@ export default {
|
|
296
296
|
tooltip: '更新服务商基础配置',
|
297
297
|
updateSuccess: '更新成功',
|
298
298
|
},
|
299
|
-
wenxin: {
|
300
|
-
accessKey: {
|
301
|
-
desc: '填入百度千帆平台的 Access Key',
|
302
|
-
placeholder: 'Qianfan Access Key',
|
303
|
-
title: 'Access Key',
|
304
|
-
},
|
305
|
-
checker: {
|
306
|
-
desc: '测试 AccessKey / SecretAccess 是否填写正确',
|
307
|
-
},
|
308
|
-
secretKey: {
|
309
|
-
desc: '填入百度千帆平台 Secret Key',
|
310
|
-
placeholder: 'Qianfan Secret Key',
|
311
|
-
title: 'Secret Key',
|
312
|
-
},
|
313
|
-
unlock: {
|
314
|
-
customRegion: '自定义服务区域',
|
315
|
-
description: '输入你的 AccessKey / SecretKey 即可开始会话。应用不会记录你的鉴权配置',
|
316
|
-
title: '使用自定义文心一言鉴权信息',
|
317
|
-
},
|
318
|
-
},
|
319
299
|
zeroone: {
|
320
300
|
title: '01.AI 零一万物',
|
321
301
|
},
|