@alicloud/appflow-chat 0.0.1-beta.1
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/README-ZH.md +188 -0
- package/README.md +190 -0
- package/dist/appflow-chat.cjs.js +1903 -0
- package/dist/appflow-chat.esm.js +36965 -0
- package/dist/types/index.d.ts +862 -0
- package/package.json +87 -0
- package/src/components/DocReferences.tsx +64 -0
- package/src/components/HumanVerify/CustomParamsRenderer/ArrayField.tsx +394 -0
- package/src/components/HumanVerify/CustomParamsRenderer/FieldRenderer.tsx +202 -0
- package/src/components/HumanVerify/CustomParamsRenderer/ObjectField.tsx +126 -0
- package/src/components/HumanVerify/CustomParamsRenderer/index.tsx +166 -0
- package/src/components/HumanVerify/CustomParamsRenderer/types.ts +203 -0
- package/src/components/HumanVerify/HistoryCard.tsx +156 -0
- package/src/components/HumanVerify/HumanVerify.tsx +184 -0
- package/src/components/HumanVerify/index.ts +11 -0
- package/src/components/MarkdownRenderer.tsx +195 -0
- package/src/components/MessageBubble.tsx +400 -0
- package/src/components/RichMessageBubble.tsx +283 -0
- package/src/components/WebSearchPanel.tsx +68 -0
- package/src/context/RichBubble.tsx +21 -0
- package/src/core/BubbleContent.tsx +75 -0
- package/src/core/RichBubbleContent.tsx +324 -0
- package/src/core/SourceContent.tsx +285 -0
- package/src/core/WebSearchContent.tsx +219 -0
- package/src/core/index.ts +16 -0
- package/src/hooks/usePreSignUpload.ts +36 -0
- package/src/index.ts +80 -0
- package/src/markdown/components/Chart.tsx +120 -0
- package/src/markdown/components/Error.tsx +39 -0
- package/src/markdown/components/FileDisplay.tsx +246 -0
- package/src/markdown/components/Loading.tsx +41 -0
- package/src/markdown/components/SyntaxHighlight.tsx +182 -0
- package/src/markdown/index.tsx +250 -0
- package/src/markdown/styled.ts +234 -0
- package/src/markdown/utils/dataProcessor.ts +89 -0
- package/src/services/ChatService.ts +926 -0
- package/src/utils/fetchEventSource.ts +65 -0
- package/src/utils/loadEcharts.ts +32 -0
- package/src/utils/loadPrism.ts +156 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SourceContent - 参考资料核心展示组件
|
|
3
|
+
*
|
|
4
|
+
* 支持的内容类型:
|
|
5
|
+
* - rag: 知识库参考资料
|
|
6
|
+
* - web_search: 网页搜索结果
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React, { useMemo } from 'react';
|
|
10
|
+
import styled from 'styled-components';
|
|
11
|
+
import { Image } from 'antd';
|
|
12
|
+
import { SearchOutlined } from '@ant-design/icons';
|
|
13
|
+
import { flatten, uniq } from 'lodash-es';
|
|
14
|
+
|
|
15
|
+
// 参考资料项类型
|
|
16
|
+
export interface SourceItem {
|
|
17
|
+
/** 标题 */
|
|
18
|
+
title?: string;
|
|
19
|
+
Title?: string;
|
|
20
|
+
/** 内容文本 */
|
|
21
|
+
text?: string;
|
|
22
|
+
Text?: string;
|
|
23
|
+
/** 索引序号 */
|
|
24
|
+
index?: string;
|
|
25
|
+
Index?: string;
|
|
26
|
+
/** 类型:rag-知识库, web_search-网页搜索 */
|
|
27
|
+
type?: 'rag' | 'web_search' | string;
|
|
28
|
+
Type?: string;
|
|
29
|
+
/** 图片列表 */
|
|
30
|
+
images?: string[];
|
|
31
|
+
Images?: string[];
|
|
32
|
+
/** 链接URL(网页搜索结果) */
|
|
33
|
+
url?: string;
|
|
34
|
+
Url?: string;
|
|
35
|
+
/** 文档ID */
|
|
36
|
+
doc_id?: string;
|
|
37
|
+
doc_name?: string;
|
|
38
|
+
index_id?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface SourceContentProps {
|
|
42
|
+
/** 参考资料列表 */
|
|
43
|
+
items: SourceItem[];
|
|
44
|
+
/** 渲染状态 */
|
|
45
|
+
status?: 'Running' | 'Success' | 'Error' | string;
|
|
46
|
+
/** 是否使用大写字段名(PageConfig模式) */
|
|
47
|
+
isPageConfig?: boolean;
|
|
48
|
+
/** 点击参考资料回调 */
|
|
49
|
+
onItemClick?: (item: SourceItem) => void;
|
|
50
|
+
/** 点击网页搜索结果回调 */
|
|
51
|
+
onWebSearchClick?: (items: SourceItem[]) => void;
|
|
52
|
+
/** 自定义类名 */
|
|
53
|
+
className?: string;
|
|
54
|
+
/** 自定义样式 */
|
|
55
|
+
style?: React.CSSProperties;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 样式组件
|
|
59
|
+
const StyledSource = styled.div`
|
|
60
|
+
margin-top: 16px;
|
|
61
|
+
border-top: 1px solid #e8e8e8;
|
|
62
|
+
padding-top: 16px;
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
const StyledAnswerSource = styled.div`
|
|
66
|
+
display: flex;
|
|
67
|
+
gap: 8px;
|
|
68
|
+
margin-bottom: 8px;
|
|
69
|
+
align-items: baseline;
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const StyledSourceItem = styled.div`
|
|
73
|
+
margin-bottom: 8px;
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
width: 100%;
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
const StyledSourceItemSpace = styled.div`
|
|
79
|
+
display: flex;
|
|
80
|
+
gap: 8px;
|
|
81
|
+
align-items: center;
|
|
82
|
+
justify-content: flex-start;
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
const StyledItemOrder = styled.div`
|
|
86
|
+
align-items: center;
|
|
87
|
+
border: 0.5px solid #2c2c73;
|
|
88
|
+
border-radius: 2px;
|
|
89
|
+
display: flex;
|
|
90
|
+
font-size: 10px;
|
|
91
|
+
height: 12px;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
line-height: 1;
|
|
94
|
+
min-width: 14px;
|
|
95
|
+
white-space: nowrap;
|
|
96
|
+
`;
|
|
97
|
+
|
|
98
|
+
const StyledItemTitle = styled.div`
|
|
99
|
+
border: 0.5px solid #9296a9;
|
|
100
|
+
border-radius: 4px;
|
|
101
|
+
color: #707279;
|
|
102
|
+
font-size: 12px;
|
|
103
|
+
height: 28px;
|
|
104
|
+
line-height: 28px;
|
|
105
|
+
margin: 0;
|
|
106
|
+
padding: 0 8px;
|
|
107
|
+
width: auto;
|
|
108
|
+
overflow: hidden;
|
|
109
|
+
text-overflow: ellipsis;
|
|
110
|
+
white-space: nowrap;
|
|
111
|
+
`;
|
|
112
|
+
|
|
113
|
+
const StyledWrapSpace = styled.div`
|
|
114
|
+
display: flex;
|
|
115
|
+
flex-wrap: wrap;
|
|
116
|
+
gap: 8px;
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
const StyledImageBox = styled.div`
|
|
120
|
+
border: 1px solid #e8e8e8;
|
|
121
|
+
border-radius: 4px;
|
|
122
|
+
padding: 4px;
|
|
123
|
+
`;
|
|
124
|
+
|
|
125
|
+
const StyledWebSearchSource = styled.div`
|
|
126
|
+
display: flex;
|
|
127
|
+
gap: 8px;
|
|
128
|
+
margin-bottom: 8px;
|
|
129
|
+
align-items: center;
|
|
130
|
+
background: rgb(230, 232, 236);
|
|
131
|
+
border-radius: 10px;
|
|
132
|
+
width: fit-content;
|
|
133
|
+
padding: 7px 14px;
|
|
134
|
+
font-size: 12px;
|
|
135
|
+
cursor: pointer;
|
|
136
|
+
|
|
137
|
+
&:hover {
|
|
138
|
+
background: rgb(220, 222, 226);
|
|
139
|
+
}
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
const StyledLabel = styled.div`
|
|
143
|
+
color: #707279;
|
|
144
|
+
font-size: 12px;
|
|
145
|
+
min-width: 60px;
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
// 单个参考资料项组件
|
|
149
|
+
interface SourceItemComponentProps {
|
|
150
|
+
item: SourceItem;
|
|
151
|
+
isPageConfig?: boolean;
|
|
152
|
+
onClick: (item: SourceItem) => void;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const SourceItemComponent: React.FC<SourceItemComponentProps> = ({
|
|
156
|
+
item,
|
|
157
|
+
isPageConfig,
|
|
158
|
+
onClick
|
|
159
|
+
}) => {
|
|
160
|
+
const index = isPageConfig ? item.Index : item.index;
|
|
161
|
+
const title = isPageConfig ? item.Title : item.title;
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<StyledSourceItem onClick={() => onClick(item)}>
|
|
165
|
+
<StyledSourceItemSpace>
|
|
166
|
+
{index && <StyledItemOrder>{index}</StyledItemOrder>}
|
|
167
|
+
{title && <StyledItemTitle>{title}</StyledItemTitle>}
|
|
168
|
+
</StyledSourceItemSpace>
|
|
169
|
+
</StyledSourceItem>
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* SourceContent - 参考资料核心展示组件
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```tsx
|
|
178
|
+
* <SourceContent
|
|
179
|
+
* items={[
|
|
180
|
+
* { title: '参考文档1', text: '内容...', index: '1', type: 'rag' },
|
|
181
|
+
* { title: '搜索结果1', url: 'https://...', type: 'web_search' }
|
|
182
|
+
* ]}
|
|
183
|
+
* status="Success"
|
|
184
|
+
* onItemClick={(item) => console.log('点击了', item)}
|
|
185
|
+
* onWebSearchClick={(items) => console.log('网页搜索', items)}
|
|
186
|
+
* />
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export const SourceContent: React.FC<SourceContentProps> = ({
|
|
190
|
+
items,
|
|
191
|
+
status = 'Success',
|
|
192
|
+
isPageConfig = false,
|
|
193
|
+
onItemClick,
|
|
194
|
+
onWebSearchClick,
|
|
195
|
+
className,
|
|
196
|
+
style,
|
|
197
|
+
}) => {
|
|
198
|
+
// 提取唯一图片
|
|
199
|
+
const uniqueImages = useMemo(() => {
|
|
200
|
+
let images;
|
|
201
|
+
if (isPageConfig) {
|
|
202
|
+
images = items?.filter(item => item.Images)?.map(item => item.Images);
|
|
203
|
+
} else {
|
|
204
|
+
images = items?.filter(item => item.images)?.map(item => item.images);
|
|
205
|
+
}
|
|
206
|
+
return uniq(flatten(images));
|
|
207
|
+
}, [items, isPageConfig]);
|
|
208
|
+
|
|
209
|
+
// RAG类型的参考资料
|
|
210
|
+
const ragArray = useMemo(() => {
|
|
211
|
+
if (isPageConfig) {
|
|
212
|
+
return items?.filter(item => item.Type === 'rag') || [];
|
|
213
|
+
} else {
|
|
214
|
+
return items?.filter(item => item.type === 'rag') || [];
|
|
215
|
+
}
|
|
216
|
+
}, [items, isPageConfig]);
|
|
217
|
+
|
|
218
|
+
// 网页搜索结果
|
|
219
|
+
const webSearchArray = useMemo(() => {
|
|
220
|
+
if (isPageConfig) {
|
|
221
|
+
return items?.filter(item => item.Type === 'web_search') || [];
|
|
222
|
+
} else {
|
|
223
|
+
return items?.filter(item => item.type === 'web_search') || [];
|
|
224
|
+
}
|
|
225
|
+
}, [items, isPageConfig]);
|
|
226
|
+
|
|
227
|
+
// 点击处理
|
|
228
|
+
const handleItemClick = (item: SourceItem) => {
|
|
229
|
+
onItemClick?.(item);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const handleWebSearchClick = () => {
|
|
233
|
+
onWebSearchClick?.(webSearchArray);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// 只在成功状态下显示
|
|
237
|
+
if (status !== 'Success') {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<StyledSource className={className} style={style}>
|
|
243
|
+
{/* 网页搜索结果 */}
|
|
244
|
+
{webSearchArray.length > 0 && (
|
|
245
|
+
<StyledWebSearchSource onClick={handleWebSearchClick}>
|
|
246
|
+
<SearchOutlined />
|
|
247
|
+
<div>已搜索到{webSearchArray.length}个网页</div>
|
|
248
|
+
</StyledWebSearchSource>
|
|
249
|
+
)}
|
|
250
|
+
|
|
251
|
+
{/* RAG参考资料 */}
|
|
252
|
+
{ragArray.length > 0 && (
|
|
253
|
+
<StyledAnswerSource>
|
|
254
|
+
<StyledLabel>回答来源:</StyledLabel>
|
|
255
|
+
<div style={{ width: 'calc(100% - 70px)' }}>
|
|
256
|
+
{ragArray.map((item, index) => (
|
|
257
|
+
<SourceItemComponent
|
|
258
|
+
key={index}
|
|
259
|
+
item={item}
|
|
260
|
+
isPageConfig={isPageConfig}
|
|
261
|
+
onClick={handleItemClick}
|
|
262
|
+
/>
|
|
263
|
+
))}
|
|
264
|
+
</div>
|
|
265
|
+
</StyledAnswerSource>
|
|
266
|
+
)}
|
|
267
|
+
|
|
268
|
+
{/* 图片来源 */}
|
|
269
|
+
{uniqueImages.length > 0 && (
|
|
270
|
+
<StyledAnswerSource>
|
|
271
|
+
<StyledLabel>图片来源:</StyledLabel>
|
|
272
|
+
<StyledWrapSpace>
|
|
273
|
+
{uniqueImages.map((image, index) => (
|
|
274
|
+
<StyledImageBox key={index}>
|
|
275
|
+
<Image src={image} width={50} height={50} />
|
|
276
|
+
</StyledImageBox>
|
|
277
|
+
))}
|
|
278
|
+
</StyledWrapSpace>
|
|
279
|
+
</StyledAnswerSource>
|
|
280
|
+
)}
|
|
281
|
+
</StyledSource>
|
|
282
|
+
);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export default SourceContent;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSearchContent - 网页搜索结果核心展示组件
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import styled from 'styled-components';
|
|
7
|
+
import { Drawer, List, Typography } from 'antd';
|
|
8
|
+
import { CloseOutlined } from '@ant-design/icons';
|
|
9
|
+
|
|
10
|
+
const { Title } = Typography;
|
|
11
|
+
|
|
12
|
+
// 网页搜索结果项类型
|
|
13
|
+
export interface WebSearchItem {
|
|
14
|
+
/** 标题 */
|
|
15
|
+
title?: string;
|
|
16
|
+
Title?: string;
|
|
17
|
+
/** 内容摘要 */
|
|
18
|
+
text?: string;
|
|
19
|
+
Text?: string;
|
|
20
|
+
/** 链接URL */
|
|
21
|
+
url?: string;
|
|
22
|
+
Url?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface WebSearchContentProps {
|
|
26
|
+
/** 搜索结果列表 */
|
|
27
|
+
items?: WebSearchItem[];
|
|
28
|
+
/** 是否显示 */
|
|
29
|
+
open?: boolean;
|
|
30
|
+
/** 关闭回调 */
|
|
31
|
+
onClose?: () => void;
|
|
32
|
+
/** 是否使用大写字段名(PageConfig模式) */
|
|
33
|
+
isPageConfig?: boolean;
|
|
34
|
+
/** 面板宽度 */
|
|
35
|
+
width?: number | string;
|
|
36
|
+
/** 挂载容器 */
|
|
37
|
+
getContainer?: () => HTMLElement;
|
|
38
|
+
/** 自定义类名 */
|
|
39
|
+
className?: string;
|
|
40
|
+
/** 自定义样式 */
|
|
41
|
+
style?: React.CSSProperties;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 样式组件
|
|
45
|
+
const StyledContainer = styled.div<{ $isMobile: boolean }>`
|
|
46
|
+
height: 100%;
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
50
|
+
${props => props.$isMobile && `
|
|
51
|
+
padding: 16px;
|
|
52
|
+
`}
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const StyledContent = styled.div`
|
|
56
|
+
flex: 1;
|
|
57
|
+
overflow-y: auto;
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
const StyledHeader = styled.div`
|
|
61
|
+
display: flex;
|
|
62
|
+
justify-content: space-between;
|
|
63
|
+
align-items: baseline;
|
|
64
|
+
padding-bottom: 16px;
|
|
65
|
+
border-bottom: 1px solid #f0f0f0;
|
|
66
|
+
margin-bottom: 16px;
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
const StyledCloseButton = styled.div`
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
padding: 4px 8px;
|
|
72
|
+
border-radius: 4px;
|
|
73
|
+
color: #666;
|
|
74
|
+
font-size: 14px;
|
|
75
|
+
|
|
76
|
+
&:hover {
|
|
77
|
+
background: #f5f5f5;
|
|
78
|
+
color: #333;
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
const StyledMeta = styled.div`
|
|
83
|
+
display: flex;
|
|
84
|
+
align-items: flex-start;
|
|
85
|
+
gap: 8px;
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
const StyledMetaIndex = styled.span`
|
|
89
|
+
font-weight: 600;
|
|
90
|
+
color: #333;
|
|
91
|
+
min-width: 20px;
|
|
92
|
+
`;
|
|
93
|
+
|
|
94
|
+
const StyledMetaTitle = styled.div`
|
|
95
|
+
color: #1890ff;
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
flex: 1;
|
|
98
|
+
|
|
99
|
+
&:hover {
|
|
100
|
+
text-decoration: underline;
|
|
101
|
+
}
|
|
102
|
+
`;
|
|
103
|
+
|
|
104
|
+
const StyledMetaText = styled.div`
|
|
105
|
+
color: #666;
|
|
106
|
+
font-size: 13px;
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
margin-top: 4px;
|
|
109
|
+
|
|
110
|
+
&:hover {
|
|
111
|
+
color: #333;
|
|
112
|
+
}
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* WebSearchContent - 网页搜索结果核心展示组件
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```tsx
|
|
120
|
+
* <WebSearchContent
|
|
121
|
+
* items={[
|
|
122
|
+
* { title: '搜索结果1', text: '内容摘要...', url: 'https://...' }
|
|
123
|
+
* ]}
|
|
124
|
+
* open={true}
|
|
125
|
+
* onClose={() => setOpen(false)}
|
|
126
|
+
* />
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export const WebSearchContent: React.FC<WebSearchContentProps> = ({
|
|
130
|
+
items = [],
|
|
131
|
+
open = false,
|
|
132
|
+
onClose,
|
|
133
|
+
isPageConfig = false,
|
|
134
|
+
width = 400,
|
|
135
|
+
getContainer,
|
|
136
|
+
className,
|
|
137
|
+
style,
|
|
138
|
+
}) => {
|
|
139
|
+
// 判断是否移动端
|
|
140
|
+
const isMobile = typeof window !== 'undefined' && window.innerWidth <= 500;
|
|
141
|
+
const panelWidth = isMobile ? '100%' : width;
|
|
142
|
+
|
|
143
|
+
// 打开链接
|
|
144
|
+
const handleOpenUrl = (item: WebSearchItem) => {
|
|
145
|
+
const url = isPageConfig ? item.Url : item.url;
|
|
146
|
+
if (url) {
|
|
147
|
+
window.open(url, '_blank');
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// 关闭处理
|
|
152
|
+
const handleClose = () => {
|
|
153
|
+
onClose?.();
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<Drawer
|
|
158
|
+
className={className}
|
|
159
|
+
style={style}
|
|
160
|
+
placement="right"
|
|
161
|
+
open={open}
|
|
162
|
+
mask={false}
|
|
163
|
+
width={panelWidth}
|
|
164
|
+
destroyOnClose
|
|
165
|
+
closable={false}
|
|
166
|
+
bodyStyle={{
|
|
167
|
+
boxShadow: 'none',
|
|
168
|
+
outline: 'none',
|
|
169
|
+
padding: '16px',
|
|
170
|
+
}}
|
|
171
|
+
getContainer={getContainer}
|
|
172
|
+
onClose={handleClose}
|
|
173
|
+
>
|
|
174
|
+
<StyledContainer $isMobile={isMobile}>
|
|
175
|
+
<StyledContent>
|
|
176
|
+
<StyledHeader>
|
|
177
|
+
<Title level={5} style={{ margin: 0 }}>搜索结果</Title>
|
|
178
|
+
<StyledCloseButton onClick={handleClose}>
|
|
179
|
+
<CloseOutlined />
|
|
180
|
+
</StyledCloseButton>
|
|
181
|
+
</StyledHeader>
|
|
182
|
+
|
|
183
|
+
<List
|
|
184
|
+
itemLayout="horizontal"
|
|
185
|
+
dataSource={items}
|
|
186
|
+
renderItem={(item, index) => {
|
|
187
|
+
const title = isPageConfig ? item.Title : item.title;
|
|
188
|
+
const text = isPageConfig ? item.Text : item.text;
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<List.Item>
|
|
192
|
+
<List.Item.Meta
|
|
193
|
+
title={
|
|
194
|
+
<StyledMeta>
|
|
195
|
+
<StyledMetaIndex>{index + 1}.</StyledMetaIndex>
|
|
196
|
+
<StyledMetaTitle
|
|
197
|
+
onClick={() => handleOpenUrl(item)}
|
|
198
|
+
dangerouslySetInnerHTML={{ __html: title || '' }}
|
|
199
|
+
/>
|
|
200
|
+
</StyledMeta>
|
|
201
|
+
}
|
|
202
|
+
description={
|
|
203
|
+
<StyledMetaText
|
|
204
|
+
onClick={() => handleOpenUrl(item)}
|
|
205
|
+
dangerouslySetInnerHTML={{ __html: text || '' }}
|
|
206
|
+
/>
|
|
207
|
+
}
|
|
208
|
+
/>
|
|
209
|
+
</List.Item>
|
|
210
|
+
);
|
|
211
|
+
}}
|
|
212
|
+
/>
|
|
213
|
+
</StyledContent>
|
|
214
|
+
</StyledContainer>
|
|
215
|
+
</Drawer>
|
|
216
|
+
);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
export default WebSearchContent;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core 组件导出
|
|
3
|
+
* 这些是纯展示组件,不包含业务逻辑
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { BubbleContent } from './BubbleContent';
|
|
7
|
+
export type { BubbleContentProps } from './BubbleContent';
|
|
8
|
+
|
|
9
|
+
export { RichBubbleContent } from './RichBubbleContent';
|
|
10
|
+
export type { RichBubbleContentProps } from './RichBubbleContent';
|
|
11
|
+
|
|
12
|
+
export { SourceContent } from './SourceContent';
|
|
13
|
+
export type { SourceContentProps, SourceItem } from './SourceContent';
|
|
14
|
+
|
|
15
|
+
export { WebSearchContent } from './WebSearchContent';
|
|
16
|
+
export type { WebSearchContentProps, WebSearchItem } from './WebSearchContent';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
export interface FetchUploadResponseData {
|
|
4
|
+
/** 文件全路径链接 */
|
|
5
|
+
url?: string;
|
|
6
|
+
/** 文件 oss key */
|
|
7
|
+
key?: string;
|
|
8
|
+
/** oss bucket name */
|
|
9
|
+
bucketName?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 上传数据到指定bucket
|
|
14
|
+
* @param file 文件
|
|
15
|
+
* @param signedUrl 预签名URL
|
|
16
|
+
* @returns
|
|
17
|
+
*/
|
|
18
|
+
export const fetchUploadApi = (
|
|
19
|
+
file: Blob,
|
|
20
|
+
signedUrl: string,
|
|
21
|
+
): Promise<FetchUploadResponseData> => {
|
|
22
|
+
return new Promise<FetchUploadResponseData>((resolve, reject) => {
|
|
23
|
+
// 发送 PUT 请求上传文件
|
|
24
|
+
axios.put(signedUrl, file, {
|
|
25
|
+
headers: {
|
|
26
|
+
'Content-Type': 'application/octet-stream',
|
|
27
|
+
'x-oss-object-acl': 'private',
|
|
28
|
+
},
|
|
29
|
+
}).then(() => {
|
|
30
|
+
// 文件上传成功 请求体为空 暂定判断 ok
|
|
31
|
+
resolve({});
|
|
32
|
+
}).catch(error => reject(error));
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default fetchUploadApi;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Appflow Chat - NPM 包入口文件
|
|
3
|
+
*
|
|
4
|
+
* 使用方式:
|
|
5
|
+
* import { chatService, MarkdownRenderer, BubbleContent } from '@ali/appflow-chat';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ==================== 服务导出 ====================
|
|
9
|
+
export { chatService } from './services/ChatService';
|
|
10
|
+
export { default as ChatService } from './services/ChatService';
|
|
11
|
+
|
|
12
|
+
// ==================== 服务类型导出 ====================
|
|
13
|
+
export type {
|
|
14
|
+
SetupConfig,
|
|
15
|
+
ChatConfig,
|
|
16
|
+
ModelInfo,
|
|
17
|
+
ModelCapabilities,
|
|
18
|
+
ChatMessage,
|
|
19
|
+
ChatStreamCallbacks,
|
|
20
|
+
ChatStream,
|
|
21
|
+
HistoryMessage,
|
|
22
|
+
ChatSession,
|
|
23
|
+
} from './services/ChatService';
|
|
24
|
+
|
|
25
|
+
// ==================== UI 组件导出(简化接口,包含默认交互) ====================
|
|
26
|
+
export { MarkdownRenderer } from './components/MarkdownRenderer';
|
|
27
|
+
export { MessageBubble } from './components/MessageBubble';
|
|
28
|
+
export { RichMessageBubble } from './components/RichMessageBubble';
|
|
29
|
+
export { DocReferences } from './components/DocReferences';
|
|
30
|
+
export { WebSearchPanel } from './components/WebSearchPanel';
|
|
31
|
+
|
|
32
|
+
// ==================== UI 组件类型导出 ====================
|
|
33
|
+
export type { MarkdownRendererProps } from './components/MarkdownRenderer';
|
|
34
|
+
export type {
|
|
35
|
+
MessageBubbleProps,
|
|
36
|
+
HumanVerifySubmitData,
|
|
37
|
+
HumanVerifyData,
|
|
38
|
+
HistoryCardData
|
|
39
|
+
} from './components/MessageBubble';
|
|
40
|
+
export type { RichMessageBubbleProps } from './components/RichMessageBubble';
|
|
41
|
+
export type { DocReferencesProps, DocReferenceItem } from './components/DocReferences';
|
|
42
|
+
export type { WebSearchPanelProps, WebSearchItem } from './components/WebSearchPanel';
|
|
43
|
+
|
|
44
|
+
// ==================== Core 组件导出(纯展示组件,供高级定制) ====================
|
|
45
|
+
export { BubbleContent } from './core/BubbleContent';
|
|
46
|
+
export { RichBubbleContent } from './core/RichBubbleContent';
|
|
47
|
+
export { SourceContent } from './core/SourceContent';
|
|
48
|
+
export { WebSearchContent } from './core/WebSearchContent';
|
|
49
|
+
|
|
50
|
+
// ==================== Core 组件类型导出 ====================
|
|
51
|
+
export type { BubbleContentProps } from './core/BubbleContent';
|
|
52
|
+
export type { RichBubbleContentProps } from './core/RichBubbleContent';
|
|
53
|
+
export type { SourceContentProps, SourceItem } from './core/SourceContent';
|
|
54
|
+
export type { WebSearchContentProps } from './core/WebSearchContent';
|
|
55
|
+
|
|
56
|
+
// ==================== Context 导出 ====================
|
|
57
|
+
export { useRichBubbleContext, RichBubbleProvider } from './context/RichBubble';
|
|
58
|
+
export type { RichBubbleContextValue } from './context/RichBubble';
|
|
59
|
+
|
|
60
|
+
// ==================== Markdown 组件导出 ====================
|
|
61
|
+
export { MarkdownView } from './markdown';
|
|
62
|
+
export type { MarkdownViewProps } from './markdown';
|
|
63
|
+
|
|
64
|
+
// ==================== HumanVerify 组件导出 ====================
|
|
65
|
+
export { HumanVerify } from './components/HumanVerify';
|
|
66
|
+
export { HistoryCard, convertSchemaToUpperCase } from './components/HumanVerify';
|
|
67
|
+
export { CustomParamsRenderer, useCustomParamsRenderer, validateCustomParams } from './components/HumanVerify';
|
|
68
|
+
|
|
69
|
+
// ==================== HumanVerify 组件类型导出 ====================
|
|
70
|
+
export type { HumanVerifyProps } from './components/HumanVerify';
|
|
71
|
+
export type { HistoryCardProps } from './components/HumanVerify';
|
|
72
|
+
export type {
|
|
73
|
+
CustomParamSchema,
|
|
74
|
+
CustomParamsRendererProps,
|
|
75
|
+
ValidationResult,
|
|
76
|
+
ValidationError,
|
|
77
|
+
} from './components/HumanVerify';
|
|
78
|
+
|
|
79
|
+
// ==================== 工具函数导出 ====================
|
|
80
|
+
export { loadEchartsScript } from './utils/loadEcharts';
|