yt-chat-components 1.1.7 → 1.1.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.
Files changed (26) hide show
  1. package/build/asset-manifest.json +19 -0
  2. package/build/index.html +1 -0
  3. package/build/static/css/main.8ee59d98.css +2 -0
  4. package/build/static/css/main.8ee59d98.css.map +1 -0
  5. package/build/static/js/main.ae39ed55.js +3 -0
  6. package/build/static/js/main.ae39ed55.js.LICENSE.txt +181 -0
  7. package/build/static/js/main.ae39ed55.js.map +1 -0
  8. package/build/static/media/aiavatar.74bafa995cce4c01b804.png +0 -0
  9. package/build/static/media/history-list-empty.1eb65b1550aef4e8c8a4.png +0 -0
  10. package/build/static/media/icon_history_headerbg.50747e81d01257f55346.png +0 -0
  11. package/build/static/media/moreAi.285e66289f838072060c.png +0 -0
  12. package/build/static/media/moreBg.9fc998472925cecd89f2.png +0 -0
  13. package/build/static/media/phone.19bc6f0d2e9eae4863ae.png +0 -0
  14. package/package.json +3 -3
  15. package/public/index.html +2 -2
  16. package/src/YtChatView/chatWidget/chatWindow/callInterface/index.module.css +51 -0
  17. package/src/YtChatView/chatWidget/chatWindow/callInterface/index.tsx +553 -0
  18. package/src/YtChatView/chatWidget/chatWindow/callInterface/style.ts +45 -0
  19. package/src/YtChatView/chatWidget/chatWindow/chatMessage/index.tsx +3 -0
  20. package/src/YtChatView/chatWidget/chatWindow/index.tsx +101 -24
  21. package/src/YtChatView/chatWidget/index.tsx +3 -0
  22. package/src/YtChatView/previewDialog/index.jsx +2 -1
  23. package/src/assets/aicenter/ai_call_thinking.png +0 -0
  24. package/src/assets/aicenter/ai_call_working.gif +0 -0
  25. package/src/assets/aicenter/phone.png +0 -0
  26. package/dist/build/static/js/bundle.min.js +0 -1
@@ -0,0 +1,45 @@
1
+ export const callStyle = `
2
+ .call-interface {
3
+ width: 100%;
4
+ height: 100%;
5
+ display: flex;
6
+ flex-direction: column;
7
+ justify-content: space-between;
8
+ }
9
+
10
+ .call-header {
11
+ padding-top: 100px;
12
+ display: flex;
13
+ flex-direction: column;
14
+ align-items: center;
15
+ }
16
+
17
+ .contact-info {
18
+ display: flex;
19
+ flex-direction: column;
20
+ align-items: center;
21
+ }
22
+
23
+ .contact-info h2 {
24
+ margin-top: 20px;
25
+ margin-bottom: 5px;
26
+ font-size: 24px;
27
+ color: #333;
28
+ }
29
+
30
+ .call-status {
31
+ color: #666;
32
+ font-size: 16px;
33
+ }
34
+
35
+ .call-controls {
36
+ padding-bottom: 100px;
37
+ display: flex;
38
+ justify-content: center;
39
+ }
40
+
41
+ .hangup-icon {
42
+ font-size: 24px;
43
+ color: white;
44
+ }
45
+ `
@@ -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) {
@@ -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,6 +131,7 @@ export default function ChatWindow({
127
131
  }) {
128
132
  const ref = useRef<HTMLDivElement>(null);
129
133
  const lastMessage = useRef<HTMLDivElement>(null);
134
+ const [showCallInterface, setShowCallInterface] = useState(false); // 添加通话界面状态
130
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 */
@@ -447,8 +452,19 @@ export default function ChatWindow({
447
452
  });
448
453
  setDropDownList(undefined);
449
454
  }
455
+ inputRef.current.value=''
450
456
  }
451
457
 
458
+ // 处理打电话按钮点击
459
+ const handleCallButtonClick = () => {
460
+ setShowCallInterface(true);
461
+ };
462
+
463
+ // 处理挂断电话
464
+ const handleHangup = () => {
465
+ setShowCallInterface(false);
466
+ };
467
+
452
468
  /**
453
469
  * 获取文件类型
454
470
  * @param file File 对象
@@ -613,37 +629,70 @@ export default function ChatWindow({
613
629
  /**
614
630
  * 语音实时识别
615
631
  */
616
- const startRecord = ()=>{
617
- if (!('webkitSpeechRecognition' in window)) {
618
- alert('您的浏览器不支持语音识别功能')
632
+ const startRecord = () => {
633
+ // 检查是否支持语音识别API(更通用的检测方式)
634
+ if (!('SpeechRecognition' in window || 'webkitSpeechRecognition' in window)) {
635
+ messageTip.error('您的浏览器不支持语音识别功能,请使用Chrome或Edge浏览器');
619
636
  return;
620
637
  }
621
- if(recordState){
638
+
639
+ // 检查是否在HTTPS环境
640
+ if (window.location.protocol !== 'https:' && window.location.hostname !== 'localhost') {
641
+ messageTip.error('语音识别功能需要在HTTPS环境下使用');
642
+ return;
643
+ }
644
+
645
+ if (recordState) {
622
646
  recognition.stop();
623
647
  setRecordState(false);
624
- }else{
625
- recognition = new webkitSpeechRecognition();
648
+ } else {
649
+ // 使用标准API或webkit前缀版本
650
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
651
+ recognition = new SpeechRecognition();
626
652
  recognition.continuous = true;
627
653
  recognition.interimResults = true;
628
654
  recognition.lang = 'zh-CN';
629
-
655
+
630
656
  recognition.onresult = (event) => {
631
657
  const transcript = Array.from(event.results)
632
658
  .map(result => result[0].transcript)
633
659
  .join('');
634
- setValue(transcript)
660
+ setValue(transcript);
661
+
662
+ // 如果使用的是textarea,还需要更新DOM元素的值
663
+ if (inputRef.current) {
664
+ inputRef.current.value = transcript;
665
+ }
635
666
  };
636
-
667
+
637
668
  recognition.onerror = (event) => {
638
- if(event.error === 'not-allowed'){
639
- messageTip.error("录音权限被拒绝,请允许录音权限后重试")
669
+ if (event.error === 'not-allowed') {
670
+ messageTip.error("录音权限被拒绝,请允许录音权限后重试");
671
+ } else if (event.error === 'no-speech') {
672
+ messageTip.info("未检测到语音,请说话或检查麦克风");
673
+ } else {
674
+ messageTip.error(`语音识别错误: ${event.error}`);
640
675
  }
641
676
  console.error('语音识别错误:', event);
677
+ setRecordState(false);
678
+ };
679
+
680
+ recognition.onend = () => {
681
+ // 如果不是手动停止的,则可能是出错或自动结束
682
+ if (recordState) {
683
+ setRecordState(false);
684
+ }
642
685
  };
643
- recognition.start()
644
- setRecordState(true);
686
+
687
+ try {
688
+ recognition.start();
689
+ setRecordState(true);
690
+ } catch (error) {
691
+ messageTip.error("启动语音识别失败,请检查浏览器设置");
692
+ console.error("启动语音识别失败:", error);
693
+ }
645
694
  }
646
- }
695
+ };
647
696
 
648
697
  /**
649
698
  * 输出消息时,滚动到底部
@@ -754,7 +803,7 @@ export default function ChatWindow({
754
803
  if (isEmpty(dropManUrl)){
755
804
  return (
756
805
  <div className='cl-drop-down'>
757
- <div className="drop-down-title">Hi,ssss欢迎使用{window_title},您可以这样问我:</div>
806
+ <div className="drop-down-title">Hi,欢迎使用{window_title},您可以这样问我:</div>
758
807
  <div className="drop-down-list">
759
808
  {dropDownList.map(({backgroundImg, title}) => (
760
809
  <div className="drop-down-item-card" key={title}>
@@ -963,7 +1012,7 @@ export default function ChatWindow({
963
1012
  <div className="w_inputBox" style={{height: inputContainerHeight}}>
964
1013
  <textarea
965
1014
  onFocus={()=>setInputContainerHeight('120px')}
966
- onBlur={()=>setInputContainerHeight('50px')}
1015
+ onBlur={() => setTimeout(() => setInputContainerHeight('50px'), 200)}
967
1016
  // value={inputValue}
968
1017
  onChange={(e) => setValue(e.target.value)}
969
1018
  onKeyDown={(e) => {
@@ -995,7 +1044,18 @@ export default function ChatWindow({
995
1044
  </div>
996
1045
  </Tooltip>
997
1046
  }
998
- {/*<Tooltip title="支持PDF / Word / Excel / Markdown / txt / mobi / rpub">*/}
1047
+ {
1048
+ is_enable_call &&
1049
+ <Tooltip title="语音通话">
1050
+ <div
1051
+ className="w_send_voice_box"
1052
+ style={sendingMessage ? { cursor: 'not-allowed' } : {}}
1053
+ onClick={handleCallButtonClick}
1054
+ >
1055
+ <img src={phonePng} style={{ width: 23 }}></img>
1056
+ </div>
1057
+ </Tooltip>
1058
+ }
999
1059
  {
1000
1060
  isShowUploadButton &&
1001
1061
  <Tooltip title="支持图片格式">
@@ -1013,6 +1073,7 @@ export default function ChatWindow({
1013
1073
  style={{ ...(sendingMessage ? { cursor: 'pointer' } : {}), padding: '0 13px', background:'transparent', display:'flex', alignItems:'center', justifyContent:'center' }}
1014
1074
  onClick={() => {
1015
1075
  if(sendingMessage){
1076
+ // 如果正在发送消息,此时点击则为取消发送
1016
1077
  const output = {
1017
1078
  message:nowAIContent,
1018
1079
  type:'text'
@@ -1038,11 +1099,26 @@ export default function ChatWindow({
1038
1099
  )
1039
1100
  }
1040
1101
  return (
1041
- <div
1042
- style={{...chat_window_style, width: width, height: "100%"}}
1043
- ref={ref}
1044
- className="cl-window"
1045
- >
1102
+ <div
1103
+ style={{...chat_window_style, width: width, height: "100%"}}
1104
+ ref={ref}
1105
+ className="cl-window"
1106
+ >
1107
+
1108
+ {/* 添加通话界面 */}
1109
+ {is_enable_call && showCallInterface ?
1110
+ <CallInterface
1111
+ onHangup={handleHangup}
1112
+ contactName={window_title}
1113
+ contactAvatar={agentUrl}
1114
+ api_key={api_key}
1115
+ flowId={flowId}
1116
+ sessionId={sessionId}
1117
+ hostUrl={hostUrl}
1118
+ onMessage={addMessage}
1119
+ userInfo={userInfo}
1120
+ />
1121
+ :
1046
1122
  <div className="cl-middle-container">
1047
1123
  <div className="cl-header" style={isMobile ? {position: 'absolute', top: 20, left: 0, paddingLeft: '1.6rem', paddingRight: '1.6rem'} : {}}>
1048
1124
  {
@@ -1051,7 +1127,7 @@ export default function ChatWindow({
1051
1127
  {
1052
1128
  isTitleSideIcon ?
1053
1129
  <img className="p_logoImg" style={{width: logoWidth, height: 'auto', marginRight: 10}}
1054
- src={agentUrl}/> :
1130
+ src={agentUrl}/> :
1055
1131
  <span className="diamond"/>
1056
1132
  }
1057
1133
  {window_title}
@@ -1102,7 +1178,8 @@ export default function ChatWindow({
1102
1178
  {
1103
1179
  renderInputArea()
1104
1180
  }
1105
- </div>
1181
+ </div>
1182
+ }
1106
1183
  </div>
1107
1184
  );
1108
1185
  }
@@ -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}
@@ -350,7 +350,7 @@ export class ToolDialog extends React.Component {
350
350
 
351
351
  // 获取历史对话列表
352
352
  getHistoryList = (sceneData, isRefreshWords) => {
353
- const { sceneId, appId: flowId, isShowSideLeft } = this.props;
353
+ const { sceneId, appId: flowId, isShowSideLeft = true } = this.props;
354
354
  if(isEmpty(sceneId)){
355
355
  // 单独组件情况
356
356
  if(isRefreshWords){
@@ -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