yt-chat-components 1.1.6 → 1.1.8

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.
@@ -234,7 +234,10 @@ export default function ChatMessage({
234
234
  if (className && className.includes('language-echart')) {
235
235
  try {
236
236
  // 解析代码块内容为 JSON 配置
237
+ // console.log(" --- 1", children.toString().trim())
237
238
  const chartOptions = JSON.parse(children.toString().trim());
239
+ // console.log(" --- 2", chartOptions)
240
+
238
241
  // 渲染 ECharts 组件
239
242
  return <EChartsReact option={chartOptions} style={{minWidth: 500, width: '100%', height: 300, backgroundColor: '#fff' }} />;
240
243
  } catch (error) {
@@ -1,23 +1,23 @@
1
- // @ts-nocheck
2
- import { MoreHorizontal } from "lucide-react";
3
- import { ChatMessagePlaceholderType } from "../types/chatWidget";
4
- // import './index.module.css'
5
-
6
- export default function ChatMessagePlaceholder({
7
- bot_message_style,
8
- }: ChatMessagePlaceholderType) {
9
- return (
10
- <div
11
- className="cl-chat-message cl-justify-start"
12
- >
13
- <div style={bot_message_style} className={"cl-bot_message"}>
14
- <div className="cl-animate-pulse">
15
- <div className="plh_textBox">
16
- <div className="plh_text">深度思考中</div>
17
- <MoreHorizontal />
18
- </div>
19
- </div>
20
- </div>
21
- </div>
22
- );
23
- }
1
+ // @ts-nocheck
2
+ import { MoreHorizontal } from "lucide-react";
3
+ import { ChatMessagePlaceholderType } from "../types/chatWidget";
4
+ // import './index.module.css'
5
+
6
+ export default function ChatMessagePlaceholder({
7
+ bot_message_style, aiStatus
8
+ }: ChatMessagePlaceholderType) {
9
+ return (
10
+ <div
11
+ className="cl-chat-message cl-justify-start"
12
+ >
13
+ <div style={bot_message_style} className={"cl-bot_message"}>
14
+ <div className="cl-animate-pulse">
15
+ <div className="plh_textBox">
16
+ <div className="plh_text">{aiStatus ? aiStatus : "深度思考中"}</div>
17
+ <MoreHorizontal />
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ );
23
+ }
@@ -22,6 +22,8 @@ import typeMobiPng from '../../../assets/aicenter/type-mobi.png';
22
22
  import typeRPubPng from '../../../assets/aicenter/type-rpub.png';
23
23
  import soundWavePng from '../../../assets/aicenter/sound-wave.gif';
24
24
  import luyinPng from '../../../assets/aicenter/luyin.png';
25
+ import phonePng from '../../../assets/aicenter/phone.png';
26
+ import CallInterface from './callInterface/index.tsx';
25
27
  import { RightOutlined } from '@ant-design/icons';
26
28
  import { Image, message as messageTip, Tooltip, Typography } from 'antd';
27
29
  import { isEmpty, isFunction } from 'lodash';
@@ -37,6 +39,7 @@ const setValue = (value) => {
37
39
  };
38
40
 
39
41
  export default function ChatWindow({
42
+ is_enable_call,
40
43
  tags,
41
44
  getHistoryList,
42
45
  userInfo,
@@ -82,6 +85,7 @@ export default function ChatWindow({
82
85
  isMobile = false,
83
86
  isShowChatHeader = true,
84
87
  }: {
88
+ is_enable_call:boolean;
85
89
  tags: [];
86
90
  getHistoryList: Function;
87
91
  userInfo: object;
@@ -127,7 +131,8 @@ export default function ChatWindow({
127
131
  }) {
128
132
  const ref = useRef<HTMLDivElement>(null);
129
133
  const lastMessage = useRef<HTMLDivElement>(null);
130
- const [windowPosition, setWindowPosition] = useState({ left: '0', top: '0' });
134
+ const [showCallInterface, setShowCallInterface] = useState(false); // 添加通话界面状态
135
+ const [aiStatus, setAiStatus] = useState(null);
131
136
  const inputRef = useRef<HTMLInputElement>(null); /* User input Ref */
132
137
  /* Initial listener for loss of focus that refocuses User input after a small delay */
133
138
  const [nowAIContent, setNowAIContent] = useState<string>('');
@@ -170,7 +175,7 @@ export default function ChatWindow({
170
175
  const handleDelayMessage = () => {
171
176
  if (delayMessageList.length > 0) {
172
177
  const message = delayMessageList.shift();
173
- console.log("-- add = delay")
178
+ // console.log("-- add = delay")
174
179
  addMessage(message);
175
180
  handleDelayMessage();
176
181
  }
@@ -220,6 +225,11 @@ export default function ChatWindow({
220
225
  })
221
226
  delayMessageTimer()
222
227
  }
228
+ else if (event == 'status') {
229
+ // 更新状态
230
+ console.log("-- status = ", data)
231
+ setAiStatus(data.status)
232
+ }
223
233
  else if (event == 'end') {
224
234
  const res = {
225
235
  data: data['result'],
@@ -291,6 +301,7 @@ export default function ChatWindow({
291
301
  contentRef.current = null
292
302
  }
293
303
  setSendingMessage(false);
304
+ setAiStatus(null)
294
305
  }
295
306
  };
296
307
 
@@ -443,6 +454,16 @@ export default function ChatWindow({
443
454
  }
444
455
  }
445
456
 
457
+ // 处理打电话按钮点击
458
+ const handleCallButtonClick = () => {
459
+ setShowCallInterface(true);
460
+ };
461
+
462
+ // 处理挂断电话
463
+ const handleHangup = () => {
464
+ setShowCallInterface(false);
465
+ };
466
+
446
467
  /**
447
468
  * 获取文件类型
448
469
  * @param file File 对象
@@ -607,37 +628,70 @@ export default function ChatWindow({
607
628
  /**
608
629
  * 语音实时识别
609
630
  */
610
- const startRecord = ()=>{
611
- if (!('webkitSpeechRecognition' in window)) {
612
- alert('您的浏览器不支持语音识别功能')
631
+ const startRecord = () => {
632
+ // 检查是否支持语音识别API(更通用的检测方式)
633
+ if (!('SpeechRecognition' in window || 'webkitSpeechRecognition' in window)) {
634
+ messageTip.error('您的浏览器不支持语音识别功能,请使用Chrome或Edge浏览器');
613
635
  return;
614
636
  }
615
- if(recordState){
637
+
638
+ // 检查是否在HTTPS环境
639
+ if (window.location.protocol !== 'https:' && window.location.hostname !== 'localhost') {
640
+ messageTip.error('语音识别功能需要在HTTPS环境下使用');
641
+ return;
642
+ }
643
+
644
+ if (recordState) {
616
645
  recognition.stop();
617
646
  setRecordState(false);
618
- }else{
619
- recognition = new webkitSpeechRecognition();
647
+ } else {
648
+ // 使用标准API或webkit前缀版本
649
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
650
+ recognition = new SpeechRecognition();
620
651
  recognition.continuous = true;
621
652
  recognition.interimResults = true;
622
653
  recognition.lang = 'zh-CN';
623
-
654
+
624
655
  recognition.onresult = (event) => {
625
656
  const transcript = Array.from(event.results)
626
657
  .map(result => result[0].transcript)
627
658
  .join('');
628
- setValue(transcript)
659
+ setValue(transcript);
660
+
661
+ // 如果使用的是textarea,还需要更新DOM元素的值
662
+ if (inputRef.current) {
663
+ inputRef.current.value = transcript;
664
+ }
629
665
  };
630
-
666
+
631
667
  recognition.onerror = (event) => {
632
- if(event.error === 'not-allowed'){
633
- messageTip.error("录音权限被拒绝,请允许录音权限后重试")
668
+ if (event.error === 'not-allowed') {
669
+ messageTip.error("录音权限被拒绝,请允许录音权限后重试");
670
+ } else if (event.error === 'no-speech') {
671
+ messageTip.info("未检测到语音,请说话或检查麦克风");
672
+ } else {
673
+ messageTip.error(`语音识别错误: ${event.error}`);
634
674
  }
635
675
  console.error('语音识别错误:', event);
676
+ setRecordState(false);
636
677
  };
637
- recognition.start()
638
- setRecordState(true);
678
+
679
+ recognition.onend = () => {
680
+ // 如果不是手动停止的,则可能是出错或自动结束
681
+ if (recordState) {
682
+ setRecordState(false);
683
+ }
684
+ };
685
+
686
+ try {
687
+ recognition.start();
688
+ setRecordState(true);
689
+ } catch (error) {
690
+ messageTip.error("启动语音识别失败,请检查浏览器设置");
691
+ console.error("启动语音识别失败:", error);
692
+ }
639
693
  }
640
- }
694
+ };
641
695
 
642
696
  /**
643
697
  * 输出消息时,滚动到底部
@@ -748,7 +802,7 @@ export default function ChatWindow({
748
802
  if (isEmpty(dropManUrl)){
749
803
  return (
750
804
  <div className='cl-drop-down'>
751
- <div className="drop-down-title">Hi,ssss欢迎使用{window_title},您可以这样问我:</div>
805
+ <div className="drop-down-title">Hi,欢迎使用{window_title},您可以这样问我:</div>
752
806
  <div className="drop-down-list">
753
807
  {dropDownList.map(({backgroundImg, title}) => (
754
808
  <div className="drop-down-item-card" key={title}>
@@ -862,6 +916,9 @@ export default function ChatWindow({
862
916
  key={index}
863
917
  className="w_tagItemBox"
864
918
  onClick={() => {
919
+ if (sendingMessage){
920
+ return
921
+ }
865
922
  handleSendMessage(item?.name);
866
923
  setFileList([]);
867
924
  }}
@@ -986,7 +1043,18 @@ export default function ChatWindow({
986
1043
  </div>
987
1044
  </Tooltip>
988
1045
  }
989
- {/*<Tooltip title="支持PDF / Word / Excel / Markdown / txt / mobi / rpub">*/}
1046
+ {
1047
+ is_enable_call &&
1048
+ <Tooltip title="语音通话">
1049
+ <div
1050
+ className="w_send_voice_box"
1051
+ style={sendingMessage ? { cursor: 'not-allowed' } : {}}
1052
+ onClick={handleCallButtonClick}
1053
+ >
1054
+ <img src={phonePng} style={{ width: 23 }}></img>
1055
+ </div>
1056
+ </Tooltip>
1057
+ }
990
1058
  {
991
1059
  isShowUploadButton &&
992
1060
  <Tooltip title="支持图片格式">
@@ -1029,11 +1097,25 @@ export default function ChatWindow({
1029
1097
  )
1030
1098
  }
1031
1099
  return (
1032
- <div
1033
- style={{...chat_window_style, width: width, height: "100%"}}
1034
- ref={ref}
1035
- className="cl-window"
1036
- >
1100
+ <div
1101
+ style={{...chat_window_style, width: width, height: "100%"}}
1102
+ ref={ref}
1103
+ className="cl-window"
1104
+ >
1105
+
1106
+ {/* 添加通话界面 */}
1107
+ {is_enable_call && showCallInterface ?
1108
+ <CallInterface
1109
+ onHangup={handleHangup}
1110
+ contactName={window_title}
1111
+ contactAvatar={agentUrl}
1112
+ api_key={api_key}
1113
+ flowId={flowId}
1114
+ sessionId={sessionId}
1115
+ hostUrl={hostUrl}
1116
+ onMessage={addMessage}
1117
+ />
1118
+ :
1037
1119
  <div className="cl-middle-container">
1038
1120
  <div className="cl-header" style={isMobile ? {position: 'absolute', top: 20, left: 0, paddingLeft: '1.6rem', paddingRight: '1.6rem'} : {}}>
1039
1121
  {
@@ -1042,7 +1124,7 @@ export default function ChatWindow({
1042
1124
  {
1043
1125
  isTitleSideIcon ?
1044
1126
  <img className="p_logoImg" style={{width: logoWidth, height: 'auto', marginRight: 10}}
1045
- src={agentUrl}/> :
1127
+ src={agentUrl}/> :
1046
1128
  <span className="diamond"/>
1047
1129
  }
1048
1130
  {window_title}
@@ -1085,7 +1167,7 @@ export default function ChatWindow({
1085
1167
  message={{ message: nowAIContent}}
1086
1168
  isSend={false}
1087
1169
  handleSendMessage={handleSendMessage}
1088
- /> : <ChatMessagePlaceholder bot_message_style={bot_message_style} />
1170
+ /> : <ChatMessagePlaceholder bot_message_style={bot_message_style} aiStatus={aiStatus} />
1089
1171
  )
1090
1172
  }
1091
1173
  <div ref={lastMessage}></div>
@@ -1093,7 +1175,8 @@ export default function ChatWindow({
1093
1175
  {
1094
1176
  renderInputArea()
1095
1177
  }
1096
- </div>
1178
+ </div>
1179
+ }
1097
1180
  </div>
1098
1181
  );
1099
1182
  }
@@ -4,6 +4,7 @@ import ChatWindow from './chatWindow';
4
4
  import { ChatMessageType } from './chatWindow/types/chatWidget';
5
5
 
6
6
  export default function ChatWidget({
7
+ is_enable_call,
7
8
  tags,
8
9
  getHistoryList,
9
10
  userInfo,
@@ -44,6 +45,7 @@ export default function ChatWidget({
44
45
  isMobile = false,
45
46
  isShowChatHeader = true,
46
47
  }: {
48
+ is_enable_call:boolean,
47
49
  tags: [];
48
50
  getHistoryList: Function;
49
51
  userInfo: object;
@@ -2543,6 +2545,7 @@ input::-ms-input-placeholder { /* Microsoft Edge */
2543
2545
  <div style={{ position: 'relative',height:'100%' }}>
2544
2546
  <style dangerouslySetInnerHTML={{ __html: styles + markdownBody + yt_style }}></style>
2545
2547
  <ChatWindow
2548
+ is_enable_call={is_enable_call}
2546
2549
  tags={tags}
2547
2550
  getHistoryList={getHistoryList}
2548
2551
  userInfo={userInfo}
@@ -502,6 +502,7 @@ export class ToolDialog extends React.Component {
502
502
  window_title={currentFlow?.name || title}
503
503
  flow_id={currentFlow?.id || flowId}
504
504
  tags={currentFlow?.keywords || tags}
505
+ is_enable_call={currentFlow?.is_enable_call || false}
505
506
  host_url={hostUrl}
506
507
  api_key={api_key}
507
508
  session_id={this.state.sessionId}
Binary file