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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yt-chat-components",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
4
4
  "main": "build/static/js/bundle.min.js",
5
5
  "module": "build/static/js/bundle.min.js",
6
6
  "types": "build/static/js/index.d.ts",
@@ -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, DatePicker, Button, Spin, Skeleton} from 'antd';
10
- import React, {useState, useRef} from '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 { ThoughtChain } from '@ant-design/x';
22
- import type { ThoughtChainProps, ThoughtChainItem } from '@ant-design/x';
23
- import { CheckCircleOutlined, MoreOutlined, InfoCircleOutlined, LoadingOutlined, EllipsisOutlined } from '@ant-design/icons';
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.echart, 300);
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: <Markdown
302
- key={id}
303
- className={'markdown-body prose flex flex-col word-break-break-word'}
304
- remarkPlugins={[remarkGfm]}
305
- rehypePlugins={[rehypeMathjax]}
306
- components={CustomRender}
307
- >
308
- {message}
309
- </Markdown>,
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 == 'form') {
281
- // 这里添加到延时队列,直接处理可能会把form渲染到token上面
282
- delayMessageList.push(data)
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
- // 这个时候还没有信息的id,所以 content_id 给特殊值
292
- content_id = "WAIT"
293
- addMessageItem("", "WAIT", name, status)
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){
@@ -1,12 +1,13 @@
1
1
  export enum MessageType {
2
2
  text,
3
- form,
3
+ form, // 目前只用于渲染loading
4
4
  echart // 目前只用于渲染loading
5
5
  }
6
6
 
7
7
  export type MessageItem = {
8
8
  id:string,
9
9
  name: string;
10
+ thinkMessage: string;
10
11
  message: string;
11
12
  rawInfo?: any;
12
13
  type?: MessageType,