yt-chat-components 1.2.9 → 1.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yt-chat-components",
3
- "version": "1.2.9",
3
+ "version": "1.3.1",
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,7 +6,7 @@ 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 {Button, Collapse, DatePicker, Form, Image, Input, message as messageTip, Select, Skeleton} from 'antd';
9
+ import {Button, Collapse, DatePicker, Form, Image, Input, message as messageTip, Select, Skeleton, Avatar} from 'antd';
10
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';
@@ -30,6 +30,20 @@ const isEmpty = (o) => {
30
30
  return !o || (typeof o === 'object' && Object.keys(o).length === 0) || (typeof o === 'string' && o.trim().length === 0);
31
31
  }
32
32
 
33
+ // 使用 for 循环生成头像图片数组
34
+ const avatarImages = [];
35
+ for (let i = 1; i <= 68; i++) {
36
+ avatarImages.push(`https://ai-file.yuntu.cn/yt-ai/system/${i}.png`);
37
+ }
38
+
39
+ // 根据name生成固定的颜色索引
40
+ const getAvatarByName = (name: string) => {
41
+ const total = name.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
42
+ const index = total % avatarImages.length;
43
+ const img = avatarImages[index];
44
+ return <Avatar shape="square" src={img} style={{marginRight: 8}}/>
45
+ };
46
+
33
47
  export default function ChatMessage({
34
48
  receivingMessage,
35
49
  setReceivingMessage,
@@ -302,18 +316,22 @@ export default function ChatMessage({
302
316
 
303
317
  const renderBotTextMessage = () => {
304
318
  const items = messageItemList.map((item, index) => {
305
- const {id, thinkMessage, message, type, name, toolCallInfo, rawInfo} = item;
319
+ const {id, thinkMessage, message, loadingMessage, type, name, toolCallInfo, rawInfo} = item;
320
+ const isLatest = index == messageItemList.length - 1;
306
321
  let status = 'success'
307
322
  // 只有在接收信息的时候有 pending 状态
308
323
  if (receivingMessage && isLatest){
309
324
  // 最后的信息才为 pending
310
- if(messageItemList.length - 1 == index){
325
+ if(isLatest){
311
326
  status = 'pending'
312
327
  }
313
328
  }
314
329
 
315
330
  const resultItem: ThoughtChainItem = {
316
- title: name,
331
+ title: <div style={{display:"flex", flexDirection: 'row', alignItems: 'center'}}>
332
+ {getAvatarByName(name)}
333
+ <span>{name}</span>
334
+ </div>,
317
335
  description: toolCallInfo,
318
336
  icon: getStatusIcon(status),
319
337
  status: status,
@@ -325,7 +343,7 @@ export default function ChatMessage({
325
343
  size="small"
326
344
  defaultActiveKey={'1'}
327
345
  expandIconPosition={'end'}
328
- items={[{key: '1', label: renderThinkTitle(isEmpty(message)), children: <Markdown
346
+ items={[{key: '1', label: renderThinkTitle(isEmpty(message) && isLatest), children: <Markdown
329
347
  className={'think markdown-body prose flex flex-col word-break-break-word'}
330
348
  remarkPlugins={[remarkGfm]}
331
349
  rehypePlugins={[rehypeMathjax]}
@@ -334,6 +352,7 @@ export default function ChatMessage({
334
352
  </Markdown>}]}
335
353
  />
336
354
  }
355
+ {/* 有 thinkMessage 的时候没有占位符,否则赞为符输出*/}
337
356
  {
338
357
  message ? <Markdown
339
358
  key={id}
@@ -343,7 +362,7 @@ export default function ChatMessage({
343
362
  components={CustomRender}
344
363
  >
345
364
  {message}
346
- </Markdown> : thinkMessage ? "" : <ChatMessagePlaceholderInThought aiStatus={"正在处理数据"} />
365
+ </Markdown> : thinkMessage ? "" : <ChatMessagePlaceholderInThought aiStatus={loadingMessage ? loadingMessage : "正在处理数据"} />
347
366
  }
348
367
  </div>,
349
368
  footer: <div key={id} className="msg_operateBox">
@@ -353,7 +372,7 @@ export default function ChatMessage({
353
372
  };
354
373
  return resultItem
355
374
  });
356
- return <ThoughtChain items={items} />
375
+ return <ThoughtChain items={items} size={'small'} />
357
376
  }
358
377
 
359
378
  const renderBotFormMessage = (form_config) => {
@@ -163,7 +163,7 @@ const extractAndParseJSON = (buffer, handleMessageContent) => {
163
163
  handleMessageContent(parsedJson['event'], parsedJson['data']);
164
164
  parsedData.push(parsedJson); // 添加到解析结果中
165
165
  } catch (error) {
166
- console.warn('无法解析 JSON 数据:', error);
166
+ console.warn('无法解析 JSON 数据:', error, jsonString);
167
167
  }
168
168
 
169
169
  // 更新剩余缓冲区的起始位置
@@ -150,6 +150,7 @@ export default function ChatWindow({
150
150
  const [inputContainerHeight, setInputContainerHeight] = useState('50px')
151
151
  let content_id: string = null
152
152
  let content_ns: string = null
153
+ let event_latest: string = null
153
154
  const nowAIContentListRef = useRef(nowAIContentList)
154
155
 
155
156
  let voiceChunks = []; // 临时存储录制的语音片段
@@ -176,7 +177,7 @@ export default function ChatWindow({
176
177
  if (delayMessageList.length > 0) {
177
178
  const data = delayMessageList.shift();
178
179
  const {r_id, form_config} = data;
179
- updateMessageItem("\n```form\n" + JSON.stringify(form_config) + "\n```\n")
180
+ updateMessageItem({chunk:"\n```form\n" + JSON.stringify(form_config) + "\n```\n"})
180
181
 
181
182
  // ?????? done
182
183
  // addMessage({
@@ -193,8 +194,8 @@ export default function ChatWindow({
193
194
  }
194
195
  }
195
196
 
196
- const addMessageItem = (chunk, id, name, status = null, isThinkChunk = false) => {
197
- // console.log("--- addMessageItem", chunk, status)
197
+ const addMessageItem = ({chunk, id, name, status = null, isThinkChunk = false, loadingMessage = null}) => {
198
+ // console.log("--- addMessageItem", chunk, status, loadingMessage)
198
199
  setNowAIContentList((prevState) => {
199
200
  const content = {}
200
201
  if(isThinkChunk){
@@ -210,6 +211,7 @@ export default function ChatWindow({
210
211
  name,
211
212
  type: MessageType.text,
212
213
  toolCallInfo: status,
214
+ loadingMessage,
213
215
  ...content
214
216
  }
215
217
  nowAIContentListRef.current = [...prevState, messageItem]
@@ -217,8 +219,12 @@ export default function ChatWindow({
217
219
  })
218
220
  }
219
221
 
220
- const updateMessageItem = (chunk, status = null, isThinkChunk = false) => {
221
- // console.log("--- updateMessageItem", chunk, status)
222
+ const updateMessageItem = ({chunk, status = null, isThinkChunk = false, loadingMessage = null}) => {
223
+ // console.log("--- updateMessageItem", chunk, status, loadingMessage)
224
+ // chunk 和 status 都为空,则不更新
225
+ if(isEmpty(chunk) && isEmpty(status)){
226
+ return
227
+ }
222
228
  setNowAIContentList((prevState) => {
223
229
  const latestMessageItem = prevState[prevState.length - 1]
224
230
  const content = {}
@@ -235,6 +241,7 @@ export default function ChatWindow({
235
241
  name: latestMessageItem.name,
236
242
  type: latestMessageItem.type,
237
243
  toolCallInfo: status,
244
+ loadingMessage,
238
245
  ...content
239
246
  }
240
247
 
@@ -248,13 +255,13 @@ export default function ChatWindow({
248
255
 
249
256
  // 流式输出消息,实时显示(token为流式输出内容,end为结束输出,整体输出一次)
250
257
  const handleMessageContent = (event, data) => {
251
- // console.log("--- event, data",event, data)
258
+ // console.log(`--- event = ${event}, content_ns = ${content_ns}, content_id = ${content_id}, data = `, data)
252
259
 
253
260
  if (event == 'add_message' && data['sender'] == 'Machine') {
254
261
  getHistoryList();
255
262
  }
256
- else if (event == 'token') {
257
- let { chunk, id, r_id, ns, name } = data
263
+ else if (event == 'token' || event == 't_full_token') {
264
+ let { chunk, id, r_id, ns, name, loading_message } = data
258
265
  if (chunk.includes('```') && !chunk.startsWith('\n')) {
259
266
  // 确保 ``` 前有换行
260
267
  chunk = '\n' + chunk;
@@ -266,14 +273,16 @@ export default function ChatWindow({
266
273
  // 如果刚才在调用工具,则追加信息
267
274
  if (content_id === 'WAIT'){
268
275
  content_id = id
269
- updateMessageItem(chunk)
276
+ updateMessageItem({chunk, loadingMessage: loading_message || ''})
270
277
  }
271
278
  // 新建信息
272
279
  else{
273
280
  content_id = id
274
- addMessageItem(chunk, id, name)
281
+ addMessageItem({chunk, id, name, loadingMessage: loading_message || ''})
275
282
  }
276
- }else {
283
+ }
284
+ // 输出主体没有变化
285
+ else {
277
286
  // 如果 content_id === WAIT 表示 token 发出来之前 agent在调用工具
278
287
  // 但是调用工具的时候已经创建了信息,所以这里更新一下 content_id。这样就可以追加信息
279
288
  if(content_id === 'WAIT'){
@@ -283,9 +292,15 @@ export default function ChatWindow({
283
292
  // id切换表示一句话说完了, 新增信息
284
293
  if (content_id !== id){
285
294
  content_id = id
286
- addMessageItem(chunk, id, name)
295
+
296
+ // 如果 event_latest 是 token,此刻变成了 t_full_token,表示之前都在输出占位符,所以更新信息
297
+ if (event_latest === 'token' && event === 't_full_token'){
298
+ updateMessageItem({chunk, loadingMessage: loading_message || ''})
299
+ } else {
300
+ addMessageItem({chunk, id, name, loadingMessage:loading_message})
301
+ }
287
302
  }else{
288
- updateMessageItem(chunk)
303
+ updateMessageItem({chunk, loadingMessage: loading_message || ''})
289
304
  }
290
305
  }
291
306
 
@@ -294,16 +309,16 @@ export default function ChatWindow({
294
309
  }
295
310
  }
296
311
  else if (event == 't_token') {
297
- let { chunk, id, r_id, ns, name } = data
312
+ let { chunk, id, r_id, ns, name, loading_message } = data
298
313
 
299
314
  // ns切换表示切换了智能体
300
315
  if (content_ns !== ns){
301
316
  content_ns = ns
302
317
  // 新建信息
303
318
  content_id = id
304
- addMessageItem(chunk, id, name, null, true)
319
+ addMessageItem({chunk, id, name, status:null, isThinkChunk:true, loadingMessage: loading_message || ''})
305
320
  }else {
306
- updateMessageItem(chunk, null, true)
321
+ updateMessageItem({chunk, status:null, isThinkChunk:true, loadingMessage: loading_message || ''})
307
322
  }
308
323
 
309
324
  if (lastMessage.current) {
@@ -312,23 +327,23 @@ export default function ChatWindow({
312
327
  }
313
328
  else if (event == 'status') {
314
329
  // 更新状态
315
- const {r_id, id, ns, name, status} = data
330
+ const {r_id, id, ns, name, status, loading_message} = data
316
331
 
317
332
  // ns变化表示切换了智能体,表示智能体一上来就调用工具
318
333
  if (content_ns !== ns){
319
334
  content_ns = ns
320
335
  // 表示智能体连续调用工具
321
336
  if (content_id === 'WAIT') {
322
- updateMessageItem("", status)
337
+ updateMessageItem({chunk:"", status, loadingMessage: loading_message || ''})
323
338
  }else{
324
339
  // 这个时候还没有信息的id,所以 content_id 给特殊值
325
340
  content_id = "WAIT"
326
- addMessageItem("", "WAIT", name, status)
341
+ addMessageItem({chunk:"", id: "WAIT", name, status})
327
342
  }
328
343
  }
329
344
  // 当前智能体在调用工具
330
345
  else{
331
- updateMessageItem("", status)
346
+ updateMessageItem({chunk:"", status, loadingMessage: loading_message || ''})
332
347
  }
333
348
 
334
349
  setAiStatus(data.status)
@@ -410,6 +425,8 @@ export default function ChatWindow({
410
425
  content_ns = null
411
426
  content_id = null
412
427
  }
428
+
429
+ event_latest = event
413
430
  };
414
431
 
415
432
  const sendMessageNoStream = (res) => {
@@ -821,7 +838,7 @@ export default function ChatWindow({
821
838
  */
822
839
  useEffect(() => {
823
840
  if (lastMessage.current) lastMessage.current.scrollIntoView({ behavior: 'smooth' });
824
- }, [messages]);
841
+ }, [nowAIContentList]);
825
842
 
826
843
  /* Refocus the User input whenever a new response is returned from the LLM */
827
844
 
@@ -848,7 +865,7 @@ export default function ChatWindow({
848
865
  let current_r_id: string = null
849
866
  let current_sender: string = null
850
867
  chatHistory.forEach((data) => {
851
- const {sender, sender_name, text, id, category, r_id, error} = data;
868
+ const {sender, sender_name, text, id, category, r_id, error, reasoning_content} = data;
852
869
  // r_id 不一样表示切换了对话轮次,则新增一个 ChatMessageType
853
870
  if(current_r_id != r_id){
854
871
  current_r_id = r_id
@@ -879,6 +896,7 @@ export default function ChatWindow({
879
896
  id: id,
880
897
  name: sender_name,
881
898
  message: text,
899
+ thinkMessage: reasoning_content,
882
900
  // rawInfo: data,
883
901
  type: MessageType.text,
884
902
  });
@@ -9,6 +9,7 @@ export type MessageItem = {
9
9
  name: string;
10
10
  thinkMessage: string;
11
11
  message: string;
12
+ loadingMessage?: string;
12
13
  rawInfo?: any;
13
14
  type?: MessageType,
14
15
  toolCallInfo?: string
@@ -2459,5 +2459,20 @@ export const yt_style = `
2459
2459
  background: #1552FF;
2460
2460
  border-radius: 8px;
2461
2461
  }
2462
- `
2463
2462
 
2463
+ .ant-thought-chain-item-title{
2464
+ max-height: 32px !important;
2465
+ height: 32px !important;
2466
+ }
2467
+
2468
+ .ant-thought-chain-item-icon{
2469
+ margin-top: 6px !important;
2470
+ }
2471
+
2472
+ .ant-thought-chain-item-header::before {
2473
+ top: 6px !important;
2474
+ }
2475
+ .ant-thought-chain-item-content::before {
2476
+ height: 55px !important;
2477
+ }
2478
+ `