yt-chat-components 0.9.9 → 1.0.0
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/.idea/sonarlint/issuestore/index.pb +1 -5
- package/package.json +2 -3
- package/public/index.html +28 -1
- package/src/YtChatView/chatWidget/chatWindow/chatMessage/index.tsx +305 -52
- package/src/YtChatView/chatWidget/chatWindow/controllers/index.ts +6 -3
- package/src/YtChatView/chatWidget/chatWindow/index.tsx +244 -127
- package/src/YtChatView/chatWidget/chatWindow/types/chatWidget/index.ts +13 -0
- package/src/YtChatView/chatWidget/index.tsx +85 -1
- package/src/YtChatView/mobileChat/index.jsx +848 -0
- package/src/YtChatView/mobileChat/index.module.css +254 -0
- package/src/YtChatView/previewDialog/index.jsx +1 -1
- package/src/assets/aicenter/icon_agents.png +0 -0
- package/src/assets/aicenter/icon_history.png +0 -0
- package/src/assets/aicenter/icon_history_add.png +0 -0
- package/src/assets/aicenter/icon_history_headerbg.png +0 -0
- package/src/assets/aicenter/icon_history_upload.png +0 -0
- package/src/index.tsx +2 -1
- package/.idea/sonarlint/issuestore/2/e/2e9f70bf32b414323ca1647e2b6f26e1533ee2fc +0 -0
- package/.idea/sonarlint/issuestore/5/a/5ab44fe33ca96299f51ad4778a73e425b92bf439 +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import { extractMessageFromOutput } from './utils';
|
|
3
3
|
import React, { useEffect, useRef, useState } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import {ChatMessageType, embedAppExtend, InputValueType, MessageType} from './types/chatWidget';
|
|
5
5
|
import ChatMessage from './chatMessage';
|
|
6
6
|
import { fetchUploadFile, getChatHistory, sendMessage } from './controllers';
|
|
7
7
|
import ChatMessagePlaceholder from './chatPlaceholder/index.tsx';
|
|
@@ -30,6 +30,7 @@ import btn_answer from '../../../assets/aicenter/btn_answer.png';
|
|
|
30
30
|
|
|
31
31
|
let mediaRecorder = null; // 语音对象,用于录音
|
|
32
32
|
let recognition = null; // 语音识别对象
|
|
33
|
+
const delayMessageList = []
|
|
33
34
|
|
|
34
35
|
export default function ChatWindow({
|
|
35
36
|
tags,
|
|
@@ -70,9 +71,12 @@ export default function ChatWindow({
|
|
|
70
71
|
setDropDownList = () => {},
|
|
71
72
|
dropDownList = [],
|
|
72
73
|
baseConfig = {},
|
|
74
|
+
isShowVoiceButton = true,
|
|
73
75
|
isShowUploadButton,
|
|
74
76
|
dropManUrl = '',
|
|
75
|
-
modalWidth
|
|
77
|
+
modalWidth,
|
|
78
|
+
isMobile = false,
|
|
79
|
+
isShowChatHeader = true,
|
|
76
80
|
}: {
|
|
77
81
|
tags: [];
|
|
78
82
|
getHistoryList: Function;
|
|
@@ -110,9 +114,12 @@ export default function ChatWindow({
|
|
|
110
114
|
sessionId: string;
|
|
111
115
|
additional_headers?: { [key: string]: string };
|
|
112
116
|
baseConfig: object;
|
|
117
|
+
isShowVoiceButton: boolean;
|
|
113
118
|
isShowUploadButton: boolean;
|
|
114
119
|
dropManUrl: string;
|
|
115
120
|
modalWidth: number;
|
|
121
|
+
isMobile: boolean;
|
|
122
|
+
isShowChatHeader: boolean;
|
|
116
123
|
}) {
|
|
117
124
|
const [value, setValue] = useState<string>('');
|
|
118
125
|
const ref = useRef<HTMLDivElement>(null);
|
|
@@ -135,6 +142,7 @@ export default function ChatWindow({
|
|
|
135
142
|
const {isTitleSideIcon, logoWidth, agentUrl} = baseConfig;
|
|
136
143
|
const inputContainerRef = useRef(null);
|
|
137
144
|
const [inputContainerHeight,setInputContainerHeight] = useState('50px')
|
|
145
|
+
const contentRef = useRef(nowAIContent);
|
|
138
146
|
|
|
139
147
|
let voiceChunks = []; // 临时存储录制的语音片段
|
|
140
148
|
// 滚动事件处理,选择文件时,文件内容超出显示框时,显示左右箭头
|
|
@@ -153,18 +161,61 @@ export default function ChatWindow({
|
|
|
153
161
|
}
|
|
154
162
|
};
|
|
155
163
|
|
|
164
|
+
// 处理延时队列,因为后端返回的是 token token form token token.....会导致form渲染在token前面,所以用这个方式
|
|
165
|
+
// 当处理token的时候,form的信息放到这里,然后使用 delayMessageTimer 处理这个延时队列
|
|
166
|
+
// 处理逻辑是:收到 token 的时候,重置timer,由于timer一直被重置所以不会处理 delayMessageList,直到 1.5内没有新 token 才会处理延时队列
|
|
167
|
+
const handleDelayMessage = () => {
|
|
168
|
+
if (delayMessageList.length > 0) {
|
|
169
|
+
const message = delayMessageList.shift();
|
|
170
|
+
addMessage(message);
|
|
171
|
+
handleDelayMessage();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const delayMessageTimer = (whenTimerExistsDoNothing: boolean = false) => {
|
|
176
|
+
if(window.delayMessageTimer)
|
|
177
|
+
if(whenTimerExistsDoNothing){
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
clearTimeout(window.delayMessageTimer);
|
|
181
|
+
window.delayMessageTimer = null
|
|
182
|
+
if(!window.delayMessageTimer){
|
|
183
|
+
window.delayMessageTimer = setTimeout(handleDelayMessage, 1500);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
156
187
|
// 流式输出消息,实时显示(token为流式输出内容,end为结束输出,整体输出一次)
|
|
157
188
|
const handleMessageContent = (event, data) => {
|
|
189
|
+
// console.error("event, data",event, data)
|
|
158
190
|
if (event == 'add_message' && data['sender'] == 'Machine') {
|
|
159
191
|
getHistoryList();
|
|
160
|
-
}
|
|
161
|
-
|
|
192
|
+
}
|
|
193
|
+
else if (event == 'token') {
|
|
194
|
+
setNowAIContent((prevState) => {
|
|
195
|
+
const newValue = prevState + data['chunk'];
|
|
196
|
+
contentRef.current = newValue
|
|
197
|
+
return newValue
|
|
198
|
+
});
|
|
162
199
|
if (lastMessage.current) lastMessage.current.scrollIntoView({ behavior: 'smooth' });
|
|
163
|
-
|
|
200
|
+
|
|
201
|
+
// 处理延时队列
|
|
202
|
+
delayMessageTimer();
|
|
203
|
+
}
|
|
204
|
+
else if (event == 'form') {
|
|
205
|
+
// 这里添加到延时队列,直接处理可能会把form渲染到token上面
|
|
206
|
+
delayMessageList.push({
|
|
207
|
+
message: "",
|
|
208
|
+
isSend: false,
|
|
209
|
+
rawInfo: data,
|
|
210
|
+
type: MessageType.form
|
|
211
|
+
})
|
|
212
|
+
delayMessageTimer(true)
|
|
213
|
+
}
|
|
214
|
+
else if (event == 'end') {
|
|
164
215
|
const res = {
|
|
165
216
|
data: data['result'],
|
|
166
217
|
};
|
|
167
|
-
if (
|
|
218
|
+
if (false&&
|
|
168
219
|
res.data &&
|
|
169
220
|
res.data.outputs &&
|
|
170
221
|
Object.keys(res.data.outputs).length > 0 &&
|
|
@@ -217,6 +268,15 @@ export default function ChatWindow({
|
|
|
217
268
|
});
|
|
218
269
|
}
|
|
219
270
|
}
|
|
271
|
+
const output = {
|
|
272
|
+
message:contentRef.current,
|
|
273
|
+
type:'text'
|
|
274
|
+
};
|
|
275
|
+
addMessage({
|
|
276
|
+
message: extractMessageFromOutput(output),
|
|
277
|
+
isSend: false,
|
|
278
|
+
rawInfo: output.message,
|
|
279
|
+
});
|
|
220
280
|
setSendingMessage(false);
|
|
221
281
|
}
|
|
222
282
|
};
|
|
@@ -276,7 +336,7 @@ export default function ChatWindow({
|
|
|
276
336
|
};
|
|
277
337
|
|
|
278
338
|
// 点击send发送按钮,进行消息提交发送逻辑;userMessage为传入的文本消息,优先级比input中value高
|
|
279
|
-
|
|
339
|
+
const handleSendMessage = (userMessage, callback = () => {}, input_value_type: string = InputValueType.text)=> {
|
|
280
340
|
let message = '';
|
|
281
341
|
if (value && value.trim() !== '') {
|
|
282
342
|
message = value;
|
|
@@ -288,13 +348,16 @@ export default function ChatWindow({
|
|
|
288
348
|
}
|
|
289
349
|
|
|
290
350
|
if (message && message.trim() !== '') {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
351
|
+
if(input_value_type === InputValueType.text){
|
|
352
|
+
addMessage({
|
|
353
|
+
message: message,
|
|
354
|
+
isSend: true,
|
|
355
|
+
rawInfo: { files: fileList.map((fileItem) => fileItem.fileUrl) },
|
|
356
|
+
});
|
|
357
|
+
setValue('');
|
|
358
|
+
setSendingMessage(true);
|
|
359
|
+
}
|
|
360
|
+
|
|
298
361
|
let userInfoClone = userInfo;
|
|
299
362
|
if(isEmpty(userInfoClone.code)) {
|
|
300
363
|
userInfoClone.code = sessionId;
|
|
@@ -322,6 +385,7 @@ export default function ChatWindow({
|
|
|
322
385
|
setFileList([]);
|
|
323
386
|
handleScroll();
|
|
324
387
|
sendMessage(
|
|
388
|
+
input_value_type,
|
|
325
389
|
embedAppExtend,
|
|
326
390
|
isStream,
|
|
327
391
|
handleMessageContent,
|
|
@@ -635,110 +699,158 @@ export default function ChatWindow({
|
|
|
635
699
|
return 'cl-drop-horizontal'
|
|
636
700
|
}
|
|
637
701
|
|
|
702
|
+
const renderTipsInfo = () => {
|
|
703
|
+
if (isMobile && !isEmpty(dropDownList)){
|
|
704
|
+
return (
|
|
705
|
+
<div className={'cl-tips-wrapper'}>
|
|
706
|
+
<img className="drop-man-img" src={dropManUrl}/>
|
|
707
|
+
<div className="drop-down-title"><strong>Hi,</strong><br/><strong>欢迎使用{window_title}!</strong><br/><div style={{fontSize:'14px'}}>您可以这样问我:</div></div>
|
|
708
|
+
<div className={'cl-drop-down-mobile'}>
|
|
709
|
+
<div className="drop-down-list-mobile">
|
|
710
|
+
{dropDownList.map(({backgroundImg, title}) => (
|
|
711
|
+
<div
|
|
712
|
+
className="drop-down-item-card-mobile"
|
|
713
|
+
key={title}
|
|
714
|
+
onClick={() => {
|
|
715
|
+
setDropDownList(undefined);
|
|
716
|
+
handleSendMessage(title);
|
|
717
|
+
}}>
|
|
718
|
+
<Typography.Paragraph
|
|
719
|
+
className="drop-down-item-title-mobile"
|
|
720
|
+
ellipsis={{
|
|
721
|
+
rows: 2,
|
|
722
|
+
tooltip: `“${title}”`,
|
|
723
|
+
}}>{'“' + title + '”'}
|
|
724
|
+
</Typography.Paragraph>
|
|
725
|
+
<img className="drop-down-item-bottom-img-mobile" src={backgroundImg}/>
|
|
726
|
+
{/*</div>*/}
|
|
727
|
+
</div>
|
|
728
|
+
))}
|
|
729
|
+
</div>
|
|
730
|
+
</div>
|
|
731
|
+
</div>
|
|
732
|
+
)
|
|
733
|
+
}
|
|
734
|
+
if (!isEmpty(dropDownList)){
|
|
735
|
+
if (isEmpty(dropManUrl)){
|
|
736
|
+
return (
|
|
737
|
+
<div className='cl-drop-down'>
|
|
738
|
+
<div className="drop-down-title">Hi,ssss欢迎使用{window_title},您可以这样问我:</div>
|
|
739
|
+
<div className="drop-down-list">
|
|
740
|
+
{dropDownList.map(({backgroundImg, title}) => (
|
|
741
|
+
<div className="drop-down-item-card" key={title}>
|
|
742
|
+
<Typography.Paragraph
|
|
743
|
+
className="drop-down-item-title"
|
|
744
|
+
ellipsis={{
|
|
745
|
+
rows: 2,
|
|
746
|
+
tooltip: `“${title}”`,
|
|
747
|
+
}}>{'“' + title + '”'}
|
|
748
|
+
</Typography.Paragraph>
|
|
749
|
+
<div className="drop-down-item-bottom">
|
|
750
|
+
<div
|
|
751
|
+
className="drop-down-item-bottom-button"
|
|
752
|
+
onClick={() => {
|
|
753
|
+
setDropDownList(undefined);
|
|
754
|
+
handleSendMessage(title);
|
|
755
|
+
}}
|
|
756
|
+
>
|
|
757
|
+
<img src={btn_answer}/>
|
|
758
|
+
{/*<RightOutlined style={{ height: '0.8rem', width: '0.4rem' }} />*/}
|
|
759
|
+
</div>
|
|
760
|
+
<img className="drop-down-item-bottom-img" src={backgroundImg}/>
|
|
761
|
+
</div>
|
|
762
|
+
</div>
|
|
763
|
+
))}
|
|
764
|
+
</div>
|
|
765
|
+
</div>
|
|
766
|
+
)
|
|
767
|
+
} else {
|
|
768
|
+
return (
|
|
769
|
+
<div className={judgeDropClass()}>
|
|
770
|
+
<img className="drop-man-img" src={dropManUrl}/>
|
|
771
|
+
<div className='cl-drop-down'>
|
|
772
|
+
<div className="drop-down-title">Hi,欢迎使用{window_title},您可以这样问我:</div>
|
|
773
|
+
<div className="drop-down-list">
|
|
774
|
+
{dropDownList.map(({backgroundImg, title}) => (
|
|
775
|
+
<div
|
|
776
|
+
className="drop-down-item-card"
|
|
777
|
+
key={title}
|
|
778
|
+
onClick={() => {
|
|
779
|
+
setDropDownList(undefined);
|
|
780
|
+
handleSendMessage(title);
|
|
781
|
+
}}>
|
|
782
|
+
<Typography.Paragraph
|
|
783
|
+
className="drop-down-item-title"
|
|
784
|
+
ellipsis={{
|
|
785
|
+
rows: 2,
|
|
786
|
+
tooltip: `“${title}”`,
|
|
787
|
+
}}>{'“' + title + '”'}
|
|
788
|
+
</Typography.Paragraph>
|
|
789
|
+
<div className="drop-down-item-bottom">
|
|
790
|
+
<div
|
|
791
|
+
className="drop-down-item-bottom-button"
|
|
792
|
+
onClick={() => {
|
|
793
|
+
setDropDownList(undefined);
|
|
794
|
+
handleSendMessage(title);
|
|
795
|
+
}}
|
|
796
|
+
>
|
|
797
|
+
<img src={btn_answer}/>
|
|
798
|
+
{/*<RightOutlined style={{ height: '0.8rem', width: '0.4rem' }} />*/}
|
|
799
|
+
</div>
|
|
800
|
+
<img className="drop-down-item-bottom-img" src={backgroundImg}/>
|
|
801
|
+
</div>
|
|
802
|
+
</div>
|
|
803
|
+
))}
|
|
804
|
+
</div>
|
|
805
|
+
</div>
|
|
806
|
+
</div>
|
|
807
|
+
)
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return <></>
|
|
811
|
+
}
|
|
638
812
|
|
|
639
813
|
return (
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
<div className="header-title">
|
|
814
|
+
<div
|
|
815
|
+
style={{...chat_window_style, width: width, height: "100%"}}
|
|
816
|
+
ref={ref}
|
|
817
|
+
className="cl-window"
|
|
818
|
+
>
|
|
819
|
+
<div className="cl-middle-container">
|
|
820
|
+
<div className="cl-header" style={isMobile ? {position: 'absolute', top: 20, left: 0, paddingLeft: '1.6rem', paddingRight: '1.6rem'} : {}}>
|
|
648
821
|
{
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
822
|
+
isShowChatHeader && (
|
|
823
|
+
<div className="header-title">
|
|
824
|
+
{
|
|
825
|
+
isTitleSideIcon ?
|
|
826
|
+
<img className="p_logoImg" style={{width: logoWidth, height: 'auto', marginRight: 10}}
|
|
827
|
+
src={agentUrl}/> :
|
|
828
|
+
<span className="diamond"/>
|
|
829
|
+
}
|
|
830
|
+
{window_title}
|
|
831
|
+
</div>
|
|
832
|
+
)
|
|
652
833
|
}
|
|
653
|
-
|
|
834
|
+
<div className="cl-header-subtitle"/>
|
|
835
|
+
{renderTipsInfo()}
|
|
654
836
|
</div>
|
|
655
|
-
<div
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
className="drop-down-item-bottom-button"
|
|
673
|
-
onClick={() => {
|
|
674
|
-
setDropDownList(undefined);
|
|
675
|
-
handleClick(title);
|
|
676
|
-
}}
|
|
677
|
-
>
|
|
678
|
-
<img src={btn_answer}/>
|
|
679
|
-
{/*<RightOutlined style={{ height: '0.8rem', width: '0.4rem' }} />*/}
|
|
680
|
-
</div>
|
|
681
|
-
<img className="drop-down-item-bottom-img" src={backgroundImg}/>
|
|
682
|
-
</div>
|
|
683
|
-
</div>
|
|
684
|
-
))}
|
|
685
|
-
</div>
|
|
686
|
-
</div>
|
|
687
|
-
:
|
|
688
|
-
<div className={judgeDropClass()}>
|
|
689
|
-
<img className="drop-man-img" src={dropManUrl}/>
|
|
690
|
-
<div className="cl-drop-down">
|
|
691
|
-
<div className="drop-down-title">Hi,欢迎使用{window_title},您可以这样问我:</div>
|
|
692
|
-
<div className="drop-down-list">
|
|
693
|
-
{dropDownList.map(({backgroundImg, title}) => (
|
|
694
|
-
<div
|
|
695
|
-
className="drop-down-item-card"
|
|
696
|
-
key={title}
|
|
697
|
-
onClick={() => {
|
|
698
|
-
setDropDownList(undefined);
|
|
699
|
-
handleClick(title);
|
|
700
|
-
}}>
|
|
701
|
-
<Typography.Paragraph
|
|
702
|
-
className="drop-down-item-title"
|
|
703
|
-
ellipsis={{
|
|
704
|
-
rows: 2,
|
|
705
|
-
tooltip: `“${title}”`,
|
|
706
|
-
}}>{'“' + title + '”'}
|
|
707
|
-
</Typography.Paragraph>
|
|
708
|
-
<div className="drop-down-item-bottom">
|
|
709
|
-
<div
|
|
710
|
-
className="drop-down-item-bottom-button"
|
|
711
|
-
onClick={() => {
|
|
712
|
-
setDropDownList(undefined);
|
|
713
|
-
handleClick(title);
|
|
714
|
-
}}
|
|
715
|
-
>
|
|
716
|
-
<img src={btn_answer}/>
|
|
717
|
-
{/*<RightOutlined style={{ height: '0.8rem', width: '0.4rem' }} />*/}
|
|
718
|
-
</div>
|
|
719
|
-
<img className="drop-down-item-bottom-img" src={backgroundImg}/>
|
|
720
|
-
</div>
|
|
721
|
-
</div>
|
|
722
|
-
))}
|
|
723
|
-
</div>
|
|
724
|
-
</div>
|
|
725
|
-
</div>
|
|
726
|
-
)}
|
|
727
|
-
</div>
|
|
728
|
-
<div
|
|
729
|
-
className="cl-messages_container"
|
|
730
|
-
// style={{ maxWidth: '100%', minHeight:'300px', height:'700px', paddingBottom: '56px' }}
|
|
731
|
-
>
|
|
732
|
-
{messages.map((message, index) => (
|
|
733
|
-
<ChatMessage
|
|
734
|
-
bot_message_style={bot_message_style}
|
|
735
|
-
user_message_style={user_message_style}
|
|
736
|
-
error_message_style={error_message_style}
|
|
737
|
-
key={index}
|
|
738
|
-
host_url={hostUrl}
|
|
739
|
-
message={message}
|
|
740
|
-
isSend={message.isSend}
|
|
741
|
-
error={message.error}
|
|
837
|
+
<div
|
|
838
|
+
className="cl-messages_container"
|
|
839
|
+
// style={{ maxWidth: '100%', minHeight:'300px', height:'700px', paddingBottom: '56px' }}
|
|
840
|
+
>
|
|
841
|
+
{messages.map((message, index) => (
|
|
842
|
+
<ChatMessage
|
|
843
|
+
bot_message_style={bot_message_style}
|
|
844
|
+
user_message_style={user_message_style}
|
|
845
|
+
error_message_style={error_message_style}
|
|
846
|
+
key={index}
|
|
847
|
+
host_url={hostUrl}
|
|
848
|
+
message={message}
|
|
849
|
+
isSend={message.isSend}
|
|
850
|
+
error={message.error}
|
|
851
|
+
type={message.type}
|
|
852
|
+
rawInfo={message.rawInfo}
|
|
853
|
+
handleSendMessage={handleSendMessage}
|
|
742
854
|
/>
|
|
743
855
|
))}
|
|
744
856
|
{sendingMessage && (nowAIContent?
|
|
@@ -750,6 +862,7 @@ export default function ChatWindow({
|
|
|
750
862
|
host_url={hostUrl}
|
|
751
863
|
message={{ message: nowAIContent}}
|
|
752
864
|
isSend={false}
|
|
865
|
+
handleSendMessage={handleSendMessage}
|
|
753
866
|
/>:<ChatMessagePlaceholder bot_message_style={bot_message_style} />
|
|
754
867
|
)}
|
|
755
868
|
<div ref={lastMessage}></div>
|
|
@@ -759,6 +872,7 @@ export default function ChatWindow({
|
|
|
759
872
|
style={{
|
|
760
873
|
// bottom: fileList.length > 0 ? '130px' : '80px',
|
|
761
874
|
display: tagList?.length > 0 ? '' : 'none',
|
|
875
|
+
zIndex: tagList?.length > 0 ? '2' : '-1',
|
|
762
876
|
}}
|
|
763
877
|
>
|
|
764
878
|
{tagList.map((item, index) => (
|
|
@@ -766,7 +880,7 @@ export default function ChatWindow({
|
|
|
766
880
|
key={index}
|
|
767
881
|
className="w_tagItemBox"
|
|
768
882
|
onClick={() => {
|
|
769
|
-
|
|
883
|
+
handleSendMessage(item?.name);
|
|
770
884
|
setFileList([]);
|
|
771
885
|
}}
|
|
772
886
|
>
|
|
@@ -857,7 +971,7 @@ export default function ChatWindow({
|
|
|
857
971
|
value={value}
|
|
858
972
|
onChange={(e) => setValue(e.target.value)}
|
|
859
973
|
onKeyDown={(e) => {
|
|
860
|
-
if (e.key === 'Enter' && !e.shiftKey)
|
|
974
|
+
if (e.key === 'Enter' && !e.shiftKey) handleSendMessage();
|
|
861
975
|
}}
|
|
862
976
|
disabled={sendingMessage}
|
|
863
977
|
placeholder={
|
|
@@ -869,15 +983,18 @@ export default function ChatWindow({
|
|
|
869
983
|
ref={inputRef}
|
|
870
984
|
className="cl-input-element"
|
|
871
985
|
/>
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
986
|
+
{
|
|
987
|
+
isShowVoiceButton &&
|
|
988
|
+
<Tooltip title={recordState ? "点击结束录音" : "点击开始录音"}>
|
|
989
|
+
<div
|
|
990
|
+
className="w_send_voice_box"
|
|
991
|
+
style={sendingMessage ? { cursor: 'not-allowed' } : {}}
|
|
992
|
+
onClick={startRecord}
|
|
993
|
+
>
|
|
994
|
+
<img src={recordState ? soundWavePng : luyinPng} style={{ width: 23 }} className={recordState ? "w_recordIng" : ''}></img>
|
|
995
|
+
</div>
|
|
996
|
+
</Tooltip>
|
|
997
|
+
}
|
|
881
998
|
{/*<Tooltip title="支持PDF / Word / Excel / Markdown / txt / mobi / rpub">*/}
|
|
882
999
|
{
|
|
883
1000
|
isShowUploadButton &&
|
|
@@ -908,13 +1025,13 @@ export default function ChatWindow({
|
|
|
908
1025
|
abortControllerRef.current.abort('disconnect');
|
|
909
1026
|
abortControllerRef.current = new AbortController();
|
|
910
1027
|
}else{
|
|
911
|
-
|
|
1028
|
+
handleSendMessage()
|
|
912
1029
|
}
|
|
913
1030
|
}}
|
|
914
1031
|
>
|
|
915
1032
|
|
|
916
|
-
|
|
917
|
-
|
|
1033
|
+
<img src={sendingMessage ? stopmessagePng : sendmessagePng} style={{width: 55}}/>
|
|
1034
|
+
</button>
|
|
918
1035
|
</Tooltip>
|
|
919
1036
|
</div>
|
|
920
1037
|
</div>
|
|
@@ -11,8 +11,21 @@ export type ChatMessageType = {
|
|
|
11
11
|
user_message_style?: React.CSSProperties;
|
|
12
12
|
error_message_style?: React.CSSProperties;
|
|
13
13
|
rawInfo?: any;
|
|
14
|
+
type?: MessageType,
|
|
15
|
+
handleSendMessage?: (message: string, callback?: Function) => void;
|
|
14
16
|
};
|
|
15
17
|
|
|
18
|
+
export enum MessageType {
|
|
19
|
+
text,
|
|
20
|
+
form,
|
|
21
|
+
echart
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const InputValueType = {
|
|
25
|
+
text: "text",
|
|
26
|
+
form : "form",
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
export type ChatMessagePlaceholderType = {
|
|
17
30
|
bot_message_style?: React.CSSProperties;
|
|
18
31
|
};
|
|
@@ -37,9 +37,12 @@ export default function ChatWidget({
|
|
|
37
37
|
setDropDownList,
|
|
38
38
|
dropDownList,
|
|
39
39
|
baseConfig,
|
|
40
|
+
isShowVoiceButton,
|
|
40
41
|
isShowUploadButton,
|
|
41
42
|
dropManUrl,
|
|
42
|
-
modalWidth
|
|
43
|
+
modalWidth,
|
|
44
|
+
isMobile = false,
|
|
45
|
+
isShowChatHeader = true,
|
|
43
46
|
}: {
|
|
44
47
|
tags: [];
|
|
45
48
|
getHistoryList: Function;
|
|
@@ -73,9 +76,12 @@ export default function ChatWidget({
|
|
|
73
76
|
session_id?: string;
|
|
74
77
|
start_open?: boolean;
|
|
75
78
|
baseConfig:object;
|
|
79
|
+
isShowVoiceButton:boolean;
|
|
76
80
|
isShowUploadButton:boolean;
|
|
77
81
|
dropManUrl: string;
|
|
78
82
|
modalWidth: number;
|
|
83
|
+
isMobile: boolean;
|
|
84
|
+
isShowChatHeader: boolean;
|
|
79
85
|
}) {
|
|
80
86
|
const [open, setOpen] = useState(start_open);
|
|
81
87
|
const [messages, setMessages] = useState<ChatMessageType[]>([]);
|
|
@@ -476,6 +482,81 @@ video {
|
|
|
476
482
|
border-radius: 3px;
|
|
477
483
|
}
|
|
478
484
|
|
|
485
|
+
.cl-tips-wrapper {
|
|
486
|
+
width:100%;
|
|
487
|
+
display:flex;
|
|
488
|
+
margin-top:0.81rem;
|
|
489
|
+
flex-direction: row;
|
|
490
|
+
position: relative;
|
|
491
|
+
padding-bottom: 100px;
|
|
492
|
+
z-index: 1;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.cl-tips-wrapper .drop-man-img {
|
|
496
|
+
width: 35%;
|
|
497
|
+
}
|
|
498
|
+
.cl-tips-wrapper .drop-down-title {
|
|
499
|
+
margin-top: 45px;
|
|
500
|
+
font-family: PingFangSC, PingFang SC;
|
|
501
|
+
font-weight: 500;
|
|
502
|
+
font-size: 18px;
|
|
503
|
+
color: #333333;
|
|
504
|
+
line-height: 28px;
|
|
505
|
+
text-align: left;
|
|
506
|
+
font-style: normal;
|
|
507
|
+
> div {
|
|
508
|
+
margin-top: 15px;
|
|
509
|
+
font-size: 12px;
|
|
510
|
+
color: # 999;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.cl-tips-wrapper .cl-drop-down-mobile {
|
|
515
|
+
position: absolute;
|
|
516
|
+
width:100%;
|
|
517
|
+
top: 120px;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.cl-tips-wrapper .drop-down-list-mobile {
|
|
521
|
+
display: flex;
|
|
522
|
+
flex-direction: column;
|
|
523
|
+
margin-top: 2rem;
|
|
524
|
+
width:100%;
|
|
525
|
+
align-items: end;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.drop-down-item-card-mobile {
|
|
529
|
+
width: 85%;
|
|
530
|
+
height: 3.4rem;
|
|
531
|
+
padding: 0 0.6rem 0;
|
|
532
|
+
border-radius:20px;
|
|
533
|
+
border-top-left-radius: 0;
|
|
534
|
+
background: url("https://trans-from-yuntu-resourse.oss-cn-beijing.aliyuncs.com/smartSchool/appCreator/ai/drop-down-item-card-bg.png");
|
|
535
|
+
background-size: cover;
|
|
536
|
+
background-position: center;
|
|
537
|
+
background-repeat: no-repeat;
|
|
538
|
+
margin-bottom: 20px;
|
|
539
|
+
|
|
540
|
+
display:flex;
|
|
541
|
+
align-items: center;
|
|
542
|
+
}
|
|
543
|
+
.drop-down-item-title-mobile {
|
|
544
|
+
font-family: PingFangSC, PingFang SC;
|
|
545
|
+
font-weight: 400;
|
|
546
|
+
font-size: 13px;
|
|
547
|
+
color: #000000;
|
|
548
|
+
line-height: 17px;
|
|
549
|
+
text-align: left;
|
|
550
|
+
font-style: normal;
|
|
551
|
+
width: 100%;
|
|
552
|
+
margin-bottom:0 !important;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.drop-down-item-bottom-img-mobile{
|
|
556
|
+
width:3.5rem;
|
|
557
|
+
height:2.5rem;
|
|
558
|
+
}
|
|
559
|
+
|
|
479
560
|
.cl-drop-man{
|
|
480
561
|
width:100%;
|
|
481
562
|
display:flex;
|
|
@@ -2493,9 +2574,12 @@ input::-ms-input-placeholder { /* Microsoft Edge */
|
|
|
2493
2574
|
setDropDownList={setDropDownList}
|
|
2494
2575
|
dropDownList={dropDownList}
|
|
2495
2576
|
baseConfig={baseConfig}
|
|
2577
|
+
isShowVoiceButton={isShowVoiceButton}
|
|
2496
2578
|
isShowUploadButton={isShowUploadButton}
|
|
2497
2579
|
dropManUrl={dropManUrl}
|
|
2498
2580
|
modalWidth={modalWidth}
|
|
2581
|
+
isMobile={isMobile}
|
|
2582
|
+
isShowChatHeader={isShowChatHeader}
|
|
2499
2583
|
/>
|
|
2500
2584
|
</div>
|
|
2501
2585
|
);
|