yt-chat-components 1.2.8 → 1.2.9
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/package.json +1 -1
- package/src/YtChatView/chatWidget/chatWindow/chatMessage/index.tsx +56 -17
- package/src/YtChatView/chatWidget/chatWindow/chatPlaceholder/index.tsx +19 -0
- package/src/YtChatView/chatWidget/chatWindow/index.tsx +52 -14
- package/src/YtChatView/chatWidget/chatWindow/types/chatWidget/index.ts +2 -1
- package/src/YtChatView/chatWidget/index.tsx +1 -2437
- package/src/YtChatView/chatWidget/style.js +2463 -0
package/package.json
CHANGED
|
@@ -6,8 +6,8 @@ import remarkGfm from 'remark-gfm';
|
|
|
6
6
|
import rehypeMathjax from 'rehype-mathjax';
|
|
7
7
|
// import './index.module.css';
|
|
8
8
|
import upFilePng from '../../../../assets/aicenter/upfile.png';
|
|
9
|
-
import {Form, Image, Input, message as messageTip, Select,
|
|
10
|
-
import React, {
|
|
9
|
+
import {Button, Collapse, DatePicker, Form, Image, Input, message as messageTip, Select, Skeleton} from 'antd';
|
|
10
|
+
import React, {useRef, useState} from 'react';
|
|
11
11
|
import typePdfPng from '../../../../assets/aicenter/type-pdf.png';
|
|
12
12
|
import typeWordPng from '../../../../assets/aicenter/type-word.png';
|
|
13
13
|
import typeExcelPng from '../../../../assets/aicenter/type-excel.png';
|
|
@@ -18,13 +18,18 @@ import typeRPubPng from '../../../../assets/aicenter/type-rpub.png';
|
|
|
18
18
|
import playPng from '../../../../assets/aicenter/play.png';
|
|
19
19
|
import playRunGif from '../../../../assets/aicenter/play-run.gif';
|
|
20
20
|
import copyPng from '../../../../assets/aicenter/copy.png';
|
|
21
|
-
import {
|
|
22
|
-
import
|
|
23
|
-
import {
|
|
21
|
+
import type {ThoughtChainItem} from '@ant-design/x';
|
|
22
|
+
import {ThoughtChain} from '@ant-design/x';
|
|
23
|
+
import {CheckCircleOutlined, EllipsisOutlined, InfoCircleOutlined, ClockCircleOutlined} from '@ant-design/icons';
|
|
24
|
+
import ChatMessagePlaceholder, {ChatMessagePlaceholderInThought} from "../chatPlaceholder";
|
|
24
25
|
|
|
25
26
|
let speechSynth = window.speechSynthesis;
|
|
26
27
|
let utterance = null;
|
|
27
28
|
|
|
29
|
+
const isEmpty = (o) => {
|
|
30
|
+
return !o || (typeof o === 'object' && Object.keys(o).length === 0) || (typeof o === 'string' && o.trim().length === 0);
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
export default function ChatMessage({
|
|
29
34
|
receivingMessage,
|
|
30
35
|
setReceivingMessage,
|
|
@@ -219,7 +224,7 @@ export default function ChatMessage({
|
|
|
219
224
|
>
|
|
220
225
|
{
|
|
221
226
|
// 其他类型暂不处理
|
|
222
|
-
type == MessageType.echart && (
|
|
227
|
+
(type == MessageType.echart || type == MessageType.form) && (
|
|
223
228
|
<Skeleton.Image active={true} style={{width: '100%', height: '100%'}}/>
|
|
224
229
|
)
|
|
225
230
|
}
|
|
@@ -261,7 +266,7 @@ export default function ChatMessage({
|
|
|
261
266
|
// 渲染 form 组件
|
|
262
267
|
return renderBotFormMessage(form_config);
|
|
263
268
|
} catch (error) {
|
|
264
|
-
return renderLoading(MessageType.
|
|
269
|
+
return renderLoading(MessageType.form, 300);
|
|
265
270
|
}
|
|
266
271
|
}
|
|
267
272
|
// 默认渲染其他代码块
|
|
@@ -281,9 +286,23 @@ export default function ChatMessage({
|
|
|
281
286
|
}
|
|
282
287
|
}
|
|
283
288
|
|
|
289
|
+
const renderThinkTitle = (isThinking) => {
|
|
290
|
+
return <div style={{display: 'flex', alignItems: 'center', color: '#989898', fontSize: 14}}>
|
|
291
|
+
{
|
|
292
|
+
isThinking ? [
|
|
293
|
+
<ClockCircleOutlined style={{color: '#82b6dd'}}/>,
|
|
294
|
+
<span style={{marginLeft: 8}}>正在深度思考</span>
|
|
295
|
+
] : [
|
|
296
|
+
<CheckCircleOutlined style={{color: '#8add82'}} />,
|
|
297
|
+
<span style={{marginLeft: 8}}>已完成深度思考</span>
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
</div>
|
|
301
|
+
}
|
|
302
|
+
|
|
284
303
|
const renderBotTextMessage = () => {
|
|
285
304
|
const items = messageItemList.map((item, index) => {
|
|
286
|
-
const {id, message, type, name, toolCallInfo, rawInfo} = item;
|
|
305
|
+
const {id, thinkMessage, message, type, name, toolCallInfo, rawInfo} = item;
|
|
287
306
|
let status = 'success'
|
|
288
307
|
// 只有在接收信息的时候有 pending 状态
|
|
289
308
|
if (receivingMessage && isLatest){
|
|
@@ -298,15 +317,35 @@ export default function ChatMessage({
|
|
|
298
317
|
description: toolCallInfo,
|
|
299
318
|
icon: getStatusIcon(status),
|
|
300
319
|
status: status,
|
|
301
|
-
content: <
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
320
|
+
content: <div style={{display:"flex", flexDirection: 'column'}}>
|
|
321
|
+
{
|
|
322
|
+
thinkMessage && <Collapse
|
|
323
|
+
bordered={false}
|
|
324
|
+
style={{marginBottom: 15, color: '#989898'}}
|
|
325
|
+
size="small"
|
|
326
|
+
defaultActiveKey={'1'}
|
|
327
|
+
expandIconPosition={'end'}
|
|
328
|
+
items={[{key: '1', label: renderThinkTitle(isEmpty(message)), children: <Markdown
|
|
329
|
+
className={'think markdown-body prose flex flex-col word-break-break-word'}
|
|
330
|
+
remarkPlugins={[remarkGfm]}
|
|
331
|
+
rehypePlugins={[rehypeMathjax]}
|
|
332
|
+
>
|
|
333
|
+
{thinkMessage}
|
|
334
|
+
</Markdown>}]}
|
|
335
|
+
/>
|
|
336
|
+
}
|
|
337
|
+
{
|
|
338
|
+
message ? <Markdown
|
|
339
|
+
key={id}
|
|
340
|
+
className={'markdown-body prose flex flex-col word-break-break-word'}
|
|
341
|
+
remarkPlugins={[remarkGfm]}
|
|
342
|
+
rehypePlugins={[rehypeMathjax]}
|
|
343
|
+
components={CustomRender}
|
|
344
|
+
>
|
|
345
|
+
{message}
|
|
346
|
+
</Markdown> : thinkMessage ? "" : <ChatMessagePlaceholderInThought aiStatus={"正在处理数据"} />
|
|
347
|
+
}
|
|
348
|
+
</div>,
|
|
310
349
|
footer: <div key={id} className="msg_operateBox">
|
|
311
350
|
<img src={isPlay ? playRunGif : playPng} onClick={() => playVoice(message)} />
|
|
312
351
|
<img src={copyPng} onClick={() => copyText(message)} />
|
|
@@ -21,3 +21,22 @@ export default function ChatMessagePlaceholder({
|
|
|
21
21
|
</div>
|
|
22
22
|
);
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
export function ChatMessagePlaceholderInThought({
|
|
26
|
+
aiStatus
|
|
27
|
+
}: ChatMessagePlaceholderType) {
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
className="cl-chat-message-in-thought cl-justify-start"
|
|
31
|
+
>
|
|
32
|
+
<div className={"cl-bot_message-in-thought"}>
|
|
33
|
+
<div className="cl-animate-pulse">
|
|
34
|
+
<div className="plh_textBox">
|
|
35
|
+
<div className="plh_text">{aiStatus ? aiStatus : "深度思考中"}</div>
|
|
36
|
+
<MoreHorizontal />
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -193,32 +193,49 @@ export default function ChatWindow({
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
const addMessageItem = (chunk, id, name, status = null) => {
|
|
197
|
-
console.log("--- addMessageItem", chunk, status)
|
|
196
|
+
const addMessageItem = (chunk, id, name, status = null, isThinkChunk = false) => {
|
|
197
|
+
// console.log("--- addMessageItem", chunk, status)
|
|
198
198
|
setNowAIContentList((prevState) => {
|
|
199
|
+
const content = {}
|
|
200
|
+
if(isThinkChunk){
|
|
201
|
+
content["thinkMessage"] = chunk
|
|
202
|
+
content["message"] = ""
|
|
203
|
+
}else {
|
|
204
|
+
content["thinkMessage"] = ""
|
|
205
|
+
content["message"] = chunk
|
|
206
|
+
}
|
|
207
|
+
|
|
199
208
|
const messageItem : MessageItem = {
|
|
200
209
|
id,
|
|
201
210
|
name,
|
|
202
|
-
message: chunk,
|
|
203
211
|
type: MessageType.text,
|
|
204
212
|
toolCallInfo: status,
|
|
213
|
+
...content
|
|
205
214
|
}
|
|
206
215
|
nowAIContentListRef.current = [...prevState, messageItem]
|
|
207
216
|
return [...prevState, messageItem]
|
|
208
217
|
})
|
|
209
218
|
}
|
|
210
219
|
|
|
211
|
-
const updateMessageItem = (chunk, status = null) => {
|
|
212
|
-
console.log("--- updateMessageItem", chunk, status)
|
|
220
|
+
const updateMessageItem = (chunk, status = null, isThinkChunk = false) => {
|
|
221
|
+
// console.log("--- updateMessageItem", chunk, status)
|
|
213
222
|
setNowAIContentList((prevState) => {
|
|
214
223
|
const latestMessageItem = prevState[prevState.length - 1]
|
|
224
|
+
const content = {}
|
|
225
|
+
if(isThinkChunk){
|
|
226
|
+
content["thinkMessage"] = latestMessageItem.thinkMessage + chunk
|
|
227
|
+
content["message"] = latestMessageItem.message
|
|
228
|
+
}else {
|
|
229
|
+
content["thinkMessage"] = latestMessageItem.thinkMessage
|
|
230
|
+
content["message"] = latestMessageItem.message + chunk
|
|
231
|
+
}
|
|
215
232
|
|
|
216
233
|
const newMessageItem: MessageItem = {
|
|
217
234
|
id: latestMessageItem.id === 'WAIT' ? content_id : latestMessageItem.id,
|
|
218
235
|
name: latestMessageItem.name,
|
|
219
|
-
message: latestMessageItem.message + chunk,
|
|
220
236
|
type: latestMessageItem.type,
|
|
221
237
|
toolCallInfo: status,
|
|
238
|
+
...content
|
|
222
239
|
}
|
|
223
240
|
|
|
224
241
|
const newState = [...prevState]
|
|
@@ -228,7 +245,6 @@ export default function ChatWindow({
|
|
|
228
245
|
return newState
|
|
229
246
|
})
|
|
230
247
|
}
|
|
231
|
-
|
|
232
248
|
|
|
233
249
|
// 流式输出消息,实时显示(token为流式输出内容,end为结束输出,整体输出一次)
|
|
234
250
|
const handleMessageContent = (event, data) => {
|
|
@@ -277,9 +293,22 @@ export default function ChatWindow({
|
|
|
277
293
|
lastMessage.current.scrollIntoView({ behavior: 'smooth' });
|
|
278
294
|
}
|
|
279
295
|
}
|
|
280
|
-
else if (event == '
|
|
281
|
-
|
|
282
|
-
|
|
296
|
+
else if (event == 't_token') {
|
|
297
|
+
let { chunk, id, r_id, ns, name } = data
|
|
298
|
+
|
|
299
|
+
// ns切换表示切换了智能体
|
|
300
|
+
if (content_ns !== ns){
|
|
301
|
+
content_ns = ns
|
|
302
|
+
// 新建信息
|
|
303
|
+
content_id = id
|
|
304
|
+
addMessageItem(chunk, id, name, null, true)
|
|
305
|
+
}else {
|
|
306
|
+
updateMessageItem(chunk, null, true)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (lastMessage.current) {
|
|
310
|
+
lastMessage.current.scrollIntoView({ behavior: 'smooth' });
|
|
311
|
+
}
|
|
283
312
|
}
|
|
284
313
|
else if (event == 'status') {
|
|
285
314
|
// 更新状态
|
|
@@ -288,9 +317,14 @@ export default function ChatWindow({
|
|
|
288
317
|
// ns变化表示切换了智能体,表示智能体一上来就调用工具
|
|
289
318
|
if (content_ns !== ns){
|
|
290
319
|
content_ns = ns
|
|
291
|
-
//
|
|
292
|
-
content_id
|
|
293
|
-
|
|
320
|
+
// 表示智能体连续调用工具
|
|
321
|
+
if (content_id === 'WAIT') {
|
|
322
|
+
updateMessageItem("", status)
|
|
323
|
+
}else{
|
|
324
|
+
// 这个时候还没有信息的id,所以 content_id 给特殊值
|
|
325
|
+
content_id = "WAIT"
|
|
326
|
+
addMessageItem("", "WAIT", name, status)
|
|
327
|
+
}
|
|
294
328
|
}
|
|
295
329
|
// 当前智能体在调用工具
|
|
296
330
|
else{
|
|
@@ -299,6 +333,10 @@ export default function ChatWindow({
|
|
|
299
333
|
|
|
300
334
|
setAiStatus(data.status)
|
|
301
335
|
}
|
|
336
|
+
else if (event == 'form') {
|
|
337
|
+
// 这里添加到延时队列,直接处理可能会把form渲染到token上面
|
|
338
|
+
delayMessageList.push(data)
|
|
339
|
+
}
|
|
302
340
|
else if (event == 'end') {
|
|
303
341
|
// const res = {
|
|
304
342
|
// data: data['result'],
|
|
@@ -999,7 +1037,7 @@ export default function ChatWindow({
|
|
|
999
1037
|
if(messages.length > 0){
|
|
1000
1038
|
const { messageItemList } = messages[messages.length - 1]
|
|
1001
1039
|
const latestMessageItem = messageItemList[messageItemList.length - 1]
|
|
1002
|
-
isRender = !latestMessageItem.message.includes("```form")
|
|
1040
|
+
isRender = !(latestMessageItem.message || "").includes("```form")
|
|
1003
1041
|
}
|
|
1004
1042
|
|
|
1005
1043
|
if(!isRender){
|