yt-chat-components 0.9.9-c → 0.9.9-d

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": "0.9.9c",
3
+ "version": "0.9.9d",
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",
@@ -31,8 +31,7 @@
31
31
  "typescript": "^4.9.5",
32
32
  "uglifyjs-webpack-plugin": "^2.2.0",
33
33
  "uuid": "^10.0.0",
34
- "web-vitals": "^2.1.4",
35
- "yt-chat-components": "^0.2.0"
34
+ "web-vitals": "^2.1.4"
36
35
  },
37
36
  "scripts": {
38
37
  "start": "react-scripts start",
@@ -1,12 +1,12 @@
1
1
  // @ts-nocheck
2
2
  import Markdown from 'react-markdown';
3
- import { ChatMessageType } from '../types/chatWidget';
3
+ import {ChatMessageType, InputValueType, MessageType} from '../types/chatWidget';
4
4
  import remarkGfm from 'remark-gfm';
5
5
  import rehypeMathjax from 'rehype-mathjax';
6
6
  // import './index.module.css';
7
7
  import upFilePng from '../../../../assets/aicenter/upfile.png';
8
- import { Image, message as messageTip } from 'antd';
9
- import React, {useState} from 'react';
8
+ import {Form, Image, Input, message as messageTip, Select, DatePicker, Button} from 'antd';
9
+ import React, {useState, useRef} from 'react';
10
10
  import typePdfPng from '../../../../assets/aicenter/type-pdf.png';
11
11
  import typeWordPng from '../../../../assets/aicenter/type-word.png';
12
12
  import typeExcelPng from '../../../../assets/aicenter/type-excel.png';
@@ -22,6 +22,8 @@ let speechSynth = window.speechSynthesis;
22
22
  let utterance = null;
23
23
 
24
24
  export default function ChatMessage({
25
+ type = MessageType.text,
26
+ rawInfo,
25
27
  message,
26
28
  isSend,
27
29
  error,
@@ -29,6 +31,7 @@ export default function ChatMessage({
29
31
  user_message_style,
30
32
  bot_message_style,
31
33
  error_message_style,
34
+ handleSendMessage
32
35
  }: ChatMessageType) {
33
36
  const parseFileName = (
34
37
  text: string,
@@ -62,6 +65,10 @@ export default function ChatMessage({
62
65
  };
63
66
 
64
67
  const [isPlay, setIsPlay] = useState(false) // 是否正在播放文字
68
+ const [isSubmittingForm, setIsSubmittingForm] = useState(false) // 正在提交form
69
+ const [isShowFormBtns, setIsShowFormBtns] = useState(true) // 正在提交form
70
+ const formRef = useRef(null);
71
+
65
72
  /**
66
73
  * 根据文件URL获取文件类型
67
74
  * @param url
@@ -130,9 +137,9 @@ export default function ChatMessage({
130
137
  messageTip.error("消息框没有文字")
131
138
  }
132
139
  }
133
- return (
134
- <div className={'cl-chat-message ' + (isSend ? ' cl-justify-end' : ' cl-justify-start')}>
135
- {isSend ? (
140
+
141
+ const renderUserMessage = () => {
142
+ return (
136
143
  <div className="msg_userMessageBox">
137
144
  <div style={user_message_style} className="cl-user_message">
138
145
  {message.message}
@@ -140,62 +147,70 @@ export default function ChatMessage({
140
147
  <div className="msg_messageImgBox">
141
148
  {message.rawInfo?.files.map((item, index) => {
142
149
  return (
143
- <div key={item} className="msg_fileBox">
144
- {parseFileName(item).isImg && (
145
- <Image
146
- height={40}
147
- width={40}
148
- className="msg_messageImg"
149
- src={`${host_url}/api/v1/files/images/${item}`}
150
- alt={item}
151
- preview={{
152
- mask: <span className="custom-mask"></span>,
153
- }}
154
- />
155
- )}
156
- {getFileTypeByUrl(item) == 'pdf' && (
157
- <img style={{ width: 40, height: 40 }} src={typePdfPng} />
158
- )}
159
- {getFileTypeByUrl(item) == 'excel' && (
160
- <img style={{ width: 40, height: 40 }} src={typeExcelPng} />
161
- )}
162
- {getFileTypeByUrl(item) == 'markdown' && (
163
- <img style={{ width: 40, height: 40 }} src={typeMarkdownPng} />
164
- )}
165
- {getFileTypeByUrl(item) == 'txt' && (
166
- <img style={{ width: 40, height: 40 }} src={typeTextPng} />
167
- )}
168
- {getFileTypeByUrl(item) == 'word' && (
169
- <img style={{ width: 40, height: 40 }} src={typeWordPng} />
170
- )}
171
- {getFileTypeByUrl(item) == 'mobi' && (
172
- <img style={{ width: 40, height: 40 }} src={typeMobiPng} />
173
- )}
174
- {getFileTypeByUrl(item) == 'rpub' && (
175
- <img style={{ width: 40, height: 40 }} src={typeRPubPng} />
176
- )}
177
- {getFileTypeByUrl(item) == 'file' && (
178
- <img style={{ width: 40, height: 40 }} src={upFilePng} />
179
- )}
180
- <div className="msg_fileInfoBox">
181
- <div className="msg_fileInfoFileName">{parseFileName(item).fileName}</div>
150
+ <div key={item} className="msg_fileBox">
151
+ {parseFileName(item).isImg && (
152
+ <Image
153
+ height={40}
154
+ width={40}
155
+ className="msg_messageImg"
156
+ src={`${host_url}/api/v1/files/images/${item}`}
157
+ alt={item}
158
+ preview={{
159
+ mask: <span className="custom-mask"></span>,
160
+ }}
161
+ />
162
+ )}
163
+ {getFileTypeByUrl(item) == 'pdf' && (
164
+ <img style={{ width: 40, height: 40 }} src={typePdfPng} />
165
+ )}
166
+ {getFileTypeByUrl(item) == 'excel' && (
167
+ <img style={{ width: 40, height: 40 }} src={typeExcelPng} />
168
+ )}
169
+ {getFileTypeByUrl(item) == 'markdown' && (
170
+ <img style={{ width: 40, height: 40 }} src={typeMarkdownPng} />
171
+ )}
172
+ {getFileTypeByUrl(item) == 'txt' && (
173
+ <img style={{ width: 40, height: 40 }} src={typeTextPng} />
174
+ )}
175
+ {getFileTypeByUrl(item) == 'word' && (
176
+ <img style={{ width: 40, height: 40 }} src={typeWordPng} />
177
+ )}
178
+ {getFileTypeByUrl(item) == 'mobi' && (
179
+ <img style={{ width: 40, height: 40 }} src={typeMobiPng} />
180
+ )}
181
+ {getFileTypeByUrl(item) == 'rpub' && (
182
+ <img style={{ width: 40, height: 40 }} src={typeRPubPng} />
183
+ )}
184
+ {getFileTypeByUrl(item) == 'file' && (
185
+ <img style={{ width: 40, height: 40 }} src={upFilePng} />
186
+ )}
187
+ <div className="msg_fileInfoBox">
188
+ <div className="msg_fileInfoFileName">{parseFileName(item).fileName}</div>
189
+ </div>
182
190
  </div>
183
- </div>
184
191
  );
185
192
  })}
186
193
  </div>
187
194
  </div>
188
- ) : error ? (
195
+ )
196
+ }
197
+
198
+ const renderErrorMessage = () => {
199
+ return (
189
200
  <div style={error_message_style} className={'cl-error_message'}>
190
201
  {message.message}
191
202
  </div>
192
- ) : (
203
+ )
204
+ }
205
+
206
+ const renderBotTextMessage = () => {
207
+ return (
193
208
  <div>
194
209
  <div style={bot_message_style} className={'cl-bot_message'}>
195
210
  <Markdown
196
- className={'markdown-body prose flex flex-col word-break-break-word'}
197
- remarkPlugins={[remarkGfm]}
198
- rehypePlugins={[rehypeMathjax]}
211
+ className={'markdown-body prose flex flex-col word-break-break-word'}
212
+ remarkPlugins={[remarkGfm]}
213
+ rehypePlugins={[rehypeMathjax]}
199
214
  >
200
215
  {message.message}
201
216
  </Markdown>
@@ -205,7 +220,245 @@ export default function ChatMessage({
205
220
  <img src={copyPng} onClick={()=>copyText(message.message)} />
206
221
  </div>
207
222
  </div>
208
- )}
223
+ )
224
+ }
225
+
226
+ const renderBotEchartMessage = () => {
227
+ return (
228
+ <div>
229
+ echart
230
+ </div>
231
+ )
232
+ }
233
+
234
+ const renderBotFormMessage = () => {
235
+ const { form_config } = rawInfo;
236
+
237
+ // 处理表单提交
238
+ const handleSubmit = (values) => {
239
+ console.log('表单提交数据:', values);
240
+ if (handleSendMessage) {
241
+ setIsSubmittingForm(true);
242
+ // TODO 提交的数据需要多一些
243
+ handleSendMessage(JSON.stringify(values), () => {
244
+ messageTip.success('表单提交成功');
245
+ setIsSubmittingForm(false);
246
+ setIsShowFormBtns(false);
247
+ }, InputValueType.form);
248
+ }
249
+ };
250
+
251
+ // 处理表单取消
252
+ const handleCancel = () => {
253
+ if (formRef.current) {
254
+ formRef.current.resetFields();
255
+ }
256
+ if (handleSendMessage) {
257
+ setIsSubmittingForm(true);
258
+ handleSendMessage('', () => {
259
+ messageTip.success('取消成功');
260
+ setIsSubmittingForm(false);
261
+ setIsShowFormBtns(false);
262
+ }, InputValueType.form);
263
+ }
264
+ };
265
+
266
+ return (
267
+ <div className="form-container">
268
+ <div className="form-title">{form_config?.name || '表单'}</div>
269
+ <Form
270
+ ref={formRef}
271
+ layout="vertical"
272
+ onFinish={handleSubmit}
273
+ className="dynamic-form"
274
+ >
275
+ {form_config?.config?.map((item, index) => {
276
+ const { key, name, type, options } = item;
277
+ // 根据不同的表单项类型渲染不同的组件
278
+ switch (type) {
279
+ case 'text':
280
+ return (
281
+ <Form.Item
282
+ key={index}
283
+ label={name}
284
+ name={key}
285
+ rules={[{ required: true, message: `请输入${name}` }]}
286
+ >
287
+ <Input placeholder={`请输入${name}`} />
288
+ </Form.Item>
289
+ );
290
+ case 'date':
291
+ return (
292
+ <Form.Item
293
+ key={index}
294
+ label={name}
295
+ name={key}
296
+ rules={[{ required: true, message: `请选择${name}` }]}
297
+ >
298
+ <DatePicker style={{ width: '100%' }} placeholder={`请选择${name}`} />
299
+ </Form.Item>
300
+ );
301
+ case 'select':
302
+ return (
303
+ <Form.Item
304
+ key={index}
305
+ label={name}
306
+ name={key}
307
+ rules={[{ required: true, message: `请选择${name}` }]}
308
+ >
309
+ <Select
310
+ placeholder={`请选择${name}`}
311
+ style={{ width: '100%' }}
312
+ >
313
+ {options?.map((option, optIndex) => (
314
+ <Select.Option key={optIndex} value={option}>
315
+ {option}
316
+ </Select.Option>
317
+ ))}
318
+ </Select>
319
+ </Form.Item>
320
+ );
321
+ default:
322
+ return (
323
+ <Form.Item
324
+ key={index}
325
+ label={name}
326
+ name={name}
327
+ >
328
+ <Input placeholder={`请输入${name}`} />
329
+ </Form.Item>
330
+ );
331
+ }
332
+ })}
333
+
334
+ {
335
+ isShowFormBtns && (
336
+ <div className="form-buttons">
337
+ <Form.Item>
338
+ <div style={{ display: 'flex', justifyContent: 'flex-end', gap: '12px' }}>
339
+ <Button
340
+ loading={isSubmittingForm}
341
+ onClick={handleCancel}
342
+ >
343
+ 取消
344
+ </Button>
345
+ <Button
346
+ loading={isSubmittingForm}
347
+ type="primary"
348
+ htmlType="submit"
349
+ style={{ backgroundColor: '#8064f6' }}
350
+ >
351
+ 提交
352
+ </Button>
353
+ </div>
354
+ </Form.Item>
355
+ </div>
356
+ )
357
+ }
358
+ </Form>
359
+
360
+ <style jsx>{`
361
+ .form-container {
362
+ width: 100%;
363
+ padding: 16px;
364
+ border-radius: 8px;
365
+ background-color:rgb(244, 244, 244);
366
+ }
367
+
368
+ .form-title {
369
+ font-size: 18px;
370
+ font-weight: bold;
371
+ margin-bottom: 16px;
372
+ color: #333;
373
+ }
374
+
375
+ .dynamic-form {
376
+ width: 100%;
377
+ }
378
+
379
+ .form-select {
380
+ width: 100%;
381
+ height: 32px;
382
+ border: 1px solid #d9d9d9;
383
+ border-radius: 4px;
384
+ padding: 4px 11px;
385
+ }
386
+
387
+ .form-buttons {
388
+ display: flex;
389
+ justify-content: flex-end;
390
+ margin-top: 20px;
391
+ gap: 12px;
392
+ }
393
+
394
+ .cancel-button {
395
+ padding: 6px 16px;
396
+ background-color: #f0f0f0;
397
+ border: 1px solid #d9d9d9;
398
+ border-radius: 4px;
399
+ cursor: pointer;
400
+ }
401
+
402
+ .submit-button {
403
+ padding: 6px 16px;
404
+ background-color: #8064f6;
405
+ color: white;
406
+ border: none;
407
+ border-radius: 4px;
408
+ cursor: pointer;
409
+ }
410
+
411
+ /* 移动端适配 */
412
+ @media (max-width: 768px) {
413
+ .form-container {
414
+ padding: 12px;
415
+ }
416
+
417
+ .form-buttons {
418
+ flex-direction: column;
419
+ gap: 8px;
420
+ }
421
+
422
+ .cancel-button,
423
+ .submit-button {
424
+ width: 100%;
425
+ padding: 8px 0;
426
+ }
427
+ }
428
+ `}</style>
429
+ </div>
430
+ );
431
+ };
432
+
433
+ const renderBotMessage = () => {
434
+ switch (type) {
435
+ case MessageType.echart:
436
+ return renderBotEchartMessage()
437
+ case MessageType.form:
438
+ return renderBotFormMessage()
439
+ case MessageType.text:
440
+ default:
441
+ return renderBotTextMessage()
442
+ }
443
+ }
444
+
445
+ const render = () => {
446
+ if (isSend){
447
+ return renderUserMessage()
448
+ }else {
449
+ if (error){
450
+ return renderErrorMessage()
451
+ }else{
452
+ return renderBotMessage()
453
+ }
454
+ }
455
+ }
456
+
457
+ return (
458
+ <div className={'cl-chat-message ' + (isSend ? ' cl-justify-end' : ' cl-justify-start')}>
459
+ {
460
+ render()
461
+ }
209
462
  </div>
210
463
  );
211
464
  }
@@ -1,11 +1,13 @@
1
1
  // @ts-nocheck
2
2
  import axios from "axios";
3
+ import {InputValueType} from "../types/chatWidget";
3
4
 
4
5
 
5
6
  /**
6
7
  * 发送消息
7
- * @param embed_app_extend 扩展参数
8
- * @param isStream 是否启用流式传输
8
+ * @param input_value_type
9
+ * @param isStream
10
+ * @param embed_app_extend 扩展参数 * @param isStream 是否启用流式传输
9
11
  * @param handleMessageContent 处理消息内容的回调函数
10
12
  * @param signal 用于主动关闭请求流
11
13
  * @param baseUrl 接口地址
@@ -20,6 +22,7 @@ import axios from "axios";
20
22
  * @param additional_headers
21
23
  */
22
24
  export async function sendMessage(
25
+ input_value_type: string = InputValueType.text,
23
26
  embed_app_extend: object,
24
27
  isStream: boolean,
25
28
  handleMessageContent: Function,
@@ -38,7 +41,7 @@ export async function sendMessage(
38
41
  },
39
42
  ) {
40
43
  let data: any;
41
- data = {input_type, input_value: message, output_type};
44
+ data = {input_value_type, input_type, input_value: message, output_type};
42
45
  if (tweaks) {
43
46
  data['tweaks'] = tweaks;
44
47
  }
@@ -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 { ChatMessageType, embedAppExtend } from './types/chatWidget';
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,6 +71,7 @@ export default function ChatWindow({
70
71
  setDropDownList = () => {},
71
72
  dropDownList = [],
72
73
  baseConfig = {},
74
+ isShowVoiceButton = true,
73
75
  isShowUploadButton,
74
76
  dropManUrl = '',
75
77
  modalWidth,
@@ -112,6 +114,7 @@ export default function ChatWindow({
112
114
  sessionId: string;
113
115
  additional_headers?: { [key: string]: string };
114
116
  baseConfig: object;
117
+ isShowVoiceButton: boolean;
115
118
  isShowUploadButton: boolean;
116
119
  dropManUrl: string;
117
120
  modalWidth: number;
@@ -158,19 +161,57 @@ export default function ChatWindow({
158
161
  }
159
162
  };
160
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
+
161
187
  // 流式输出消息,实时显示(token为流式输出内容,end为结束输出,整体输出一次)
162
188
  const handleMessageContent = (event, data) => {
163
189
  // console.error("event, data",event, data)
164
190
  if (event == 'add_message' && data['sender'] == 'Machine') {
165
191
  getHistoryList();
166
- } else if (event == 'token') {
192
+ }
193
+ else if (event == 'token') {
167
194
  setNowAIContent((prevState) => {
168
195
  const newValue = prevState + data['chunk'];
169
196
  contentRef.current = newValue
170
197
  return newValue
171
198
  });
172
199
  if (lastMessage.current) lastMessage.current.scrollIntoView({ behavior: 'smooth' });
173
- } else if (event == 'end') {
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') {
174
215
  const res = {
175
216
  data: data['result'],
176
217
  };
@@ -295,7 +336,7 @@ export default function ChatWindow({
295
336
  };
296
337
 
297
338
  // 点击send发送按钮,进行消息提交发送逻辑;userMessage为传入的文本消息,优先级比input中value高
298
- function handleClick(userMessage, callback = () => {}) {
339
+ const handleSendMessage = (userMessage, callback = () => {}, input_value_type: string = InputValueType.text)=> {
299
340
  let message = '';
300
341
  if (value && value.trim() !== '') {
301
342
  message = value;
@@ -307,13 +348,16 @@ export default function ChatWindow({
307
348
  }
308
349
 
309
350
  if (message && message.trim() !== '') {
310
- addMessage({
311
- message: message,
312
- isSend: true,
313
- rawInfo: { files: fileList.map((fileItem) => fileItem.fileUrl) },
314
- });
315
- setSendingMessage(true);
316
- setValue('');
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
+
317
361
  let userInfoClone = userInfo;
318
362
  if(isEmpty(userInfoClone.code)) {
319
363
  userInfoClone.code = sessionId;
@@ -341,6 +385,7 @@ export default function ChatWindow({
341
385
  setFileList([]);
342
386
  handleScroll();
343
387
  sendMessage(
388
+ input_value_type,
344
389
  embedAppExtend,
345
390
  isStream,
346
391
  handleMessageContent,
@@ -659,7 +704,7 @@ export default function ChatWindow({
659
704
  return (
660
705
  <div className={'cl-tips-wrapper'}>
661
706
  <img className="drop-man-img" src={dropManUrl}/>
662
- <div className="drop-down-title"><strong>Hi,</strong><br/><strong>欢迎使用{window_title}!</strong><br/><div>您可以这样问我:</div></div>
707
+ <div className="drop-down-title"><strong>Hi,</strong><br/><strong>欢迎使用{window_title}!</strong><br/><div style={{fontSize:'14px'}}>您可以这样问我:</div></div>
663
708
  <div className={'cl-drop-down-mobile'}>
664
709
  <div className="drop-down-list-mobile">
665
710
  {dropDownList.map(({backgroundImg, title}) => (
@@ -668,7 +713,7 @@ export default function ChatWindow({
668
713
  key={title}
669
714
  onClick={() => {
670
715
  setDropDownList(undefined);
671
- handleClick(title);
716
+ handleSendMessage(title);
672
717
  }}>
673
718
  <Typography.Paragraph
674
719
  className="drop-down-item-title-mobile"
@@ -706,7 +751,7 @@ export default function ChatWindow({
706
751
  className="drop-down-item-bottom-button"
707
752
  onClick={() => {
708
753
  setDropDownList(undefined);
709
- handleClick(title);
754
+ handleSendMessage(title);
710
755
  }}
711
756
  >
712
757
  <img src={btn_answer}/>
@@ -732,7 +777,7 @@ export default function ChatWindow({
732
777
  key={title}
733
778
  onClick={() => {
734
779
  setDropDownList(undefined);
735
- handleClick(title);
780
+ handleSendMessage(title);
736
781
  }}>
737
782
  <Typography.Paragraph
738
783
  className="drop-down-item-title"
@@ -746,7 +791,7 @@ export default function ChatWindow({
746
791
  className="drop-down-item-bottom-button"
747
792
  onClick={() => {
748
793
  setDropDownList(undefined);
749
- handleClick(title);
794
+ handleSendMessage(title);
750
795
  }}
751
796
  >
752
797
  <img src={btn_answer}/>
@@ -799,10 +844,13 @@ export default function ChatWindow({
799
844
  user_message_style={user_message_style}
800
845
  error_message_style={error_message_style}
801
846
  key={index}
802
- host_url={hostUrl}
803
- message={message}
804
- isSend={message.isSend}
805
- error={message.error}
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}
806
854
  />
807
855
  ))}
808
856
  {sendingMessage && (nowAIContent?
@@ -814,6 +862,7 @@ export default function ChatWindow({
814
862
  host_url={hostUrl}
815
863
  message={{ message: nowAIContent}}
816
864
  isSend={false}
865
+ handleSendMessage={handleSendMessage}
817
866
  />:<ChatMessagePlaceholder bot_message_style={bot_message_style} />
818
867
  )}
819
868
  <div ref={lastMessage}></div>
@@ -831,7 +880,7 @@ export default function ChatWindow({
831
880
  key={index}
832
881
  className="w_tagItemBox"
833
882
  onClick={() => {
834
- handleClick(item?.name);
883
+ handleSendMessage(item?.name);
835
884
  setFileList([]);
836
885
  }}
837
886
  >
@@ -922,7 +971,7 @@ export default function ChatWindow({
922
971
  value={value}
923
972
  onChange={(e) => setValue(e.target.value)}
924
973
  onKeyDown={(e) => {
925
- if (e.key === 'Enter' && !e.shiftKey) handleClick();
974
+ if (e.key === 'Enter' && !e.shiftKey) handleSendMessage();
926
975
  }}
927
976
  disabled={sendingMessage}
928
977
  placeholder={
@@ -934,15 +983,18 @@ export default function ChatWindow({
934
983
  ref={inputRef}
935
984
  className="cl-input-element"
936
985
  />
937
- <Tooltip title={recordState ? "点击结束录音" : "点击开始录音"}>
938
- <div
939
- className="w_send_voice_box"
940
- style={sendingMessage ? { cursor: 'not-allowed' } : {}}
941
- onClick={startRecord}
942
- >
943
- <img src={recordState ? soundWavePng : luyinPng} style={{ width: 23 }} className={recordState ? "w_recordIng" : ''}></img>
944
- </div>
945
- </Tooltip>
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
+ }
946
998
  {/*<Tooltip title="支持PDF / Word / Excel / Markdown / txt / mobi / rpub">*/}
947
999
  {
948
1000
  isShowUploadButton &&
@@ -973,13 +1025,13 @@ export default function ChatWindow({
973
1025
  abortControllerRef.current.abort('disconnect');
974
1026
  abortControllerRef.current = new AbortController();
975
1027
  }else{
976
- handleClick()
1028
+ handleSendMessage()
977
1029
  }
978
1030
  }}
979
1031
  >
980
1032
 
981
- <img src={sendingMessage ? stopmessagePng : sendmessagePng} style={{width: 55}}/>
982
- </button>
1033
+ <img src={sendingMessage ? stopmessagePng : sendmessagePng} style={{width: 55}}/>
1034
+ </button>
983
1035
  </Tooltip>
984
1036
  </div>
985
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,6 +37,7 @@ export default function ChatWidget({
37
37
  setDropDownList,
38
38
  dropDownList,
39
39
  baseConfig,
40
+ isShowVoiceButton,
40
41
  isShowUploadButton,
41
42
  dropManUrl,
42
43
  modalWidth,
@@ -75,6 +76,7 @@ export default function ChatWidget({
75
76
  session_id?: string;
76
77
  start_open?: boolean;
77
78
  baseConfig:object;
79
+ isShowVoiceButton:boolean;
78
80
  isShowUploadButton:boolean;
79
81
  dropManUrl: string;
80
82
  modalWidth: number;
@@ -497,14 +499,14 @@ video {
497
499
  margin-top: 45px;
498
500
  font-family: PingFangSC, PingFang SC;
499
501
  font-weight: 500;
500
- font-size: 22px;
502
+ font-size: 18px;
501
503
  color: #333333;
502
504
  line-height: 28px;
503
505
  text-align: left;
504
506
  font-style: normal;
505
507
  > div {
506
508
  margin-top: 15px;
507
- font-size: 14px;
509
+ font-size: 12px;
508
510
  color: # 999;
509
511
  }
510
512
  }
@@ -2572,6 +2574,7 @@ input::-ms-input-placeholder { /* Microsoft Edge */
2572
2574
  setDropDownList={setDropDownList}
2573
2575
  dropDownList={dropDownList}
2574
2576
  baseConfig={baseConfig}
2577
+ isShowVoiceButton={isShowVoiceButton}
2575
2578
  isShowUploadButton={isShowUploadButton}
2576
2579
  dropManUrl={dropManUrl}
2577
2580
  modalWidth={modalWidth}
@@ -487,6 +487,7 @@ export class MobileChatPage extends React.Component {
487
487
  logoFontSize = '26px',
488
488
  isTitleSideIcon = false,// 是否将左侧历史顶部icon移到中间顶部左侧蓝点位置
489
489
  modalIndex,
490
+ isShowVoiceButton,
490
491
  isShowUploadButton,
491
492
  dropManUrl,
492
493
  modalWidth,
@@ -528,7 +529,7 @@ export class MobileChatPage extends React.Component {
528
529
  onClose={() => this.setState({drawerVisible: false})}
529
530
  open={this.state.drawerVisible}
530
531
  >
531
- <div className="drawer-history-header" style={{padding: '54px 14px 14px 14px', background: 'linear-gradient( 71deg, #E1E9FF 0%, #FFFFFF 100%)', position: "relative"}}>
532
+ <div className="drawer-history-header" style={{marginTop:0, padding: '54px 14px 14px 14px', background: 'linear-gradient( 71deg, #E1E9FF 0%, #FFFFFF 100%)', position: "relative"}}>
532
533
  <img src={icon_history_headerbg} style={{position: 'absolute', right: 0, bottom: 0, width: '40%', zIndex:0}}/>
533
534
  <div className="drawer-history-header-title" style={{display: 'flex', flexDirection: 'row', alignItems: 'center'}}>
534
535
  <img style={{width: 35}} src={agentUrl}/>
@@ -674,6 +675,7 @@ export class MobileChatPage extends React.Component {
674
675
  setDropDownList={(list) => this.setState({dropDownList: list})}
675
676
  dropDownList={this.state.dropDownList}
676
677
  baseConfig={{isTitleSideIcon, logoWidth, agentUrl}}
678
+ isShowVoiceButton={isShowVoiceButton}
677
679
  isShowUploadButton={isShowUploadButton}
678
680
  dropManUrl={character || dropManUrl}
679
681
  modalWidth={modalWidth}
@@ -765,6 +767,7 @@ export class MobileChatPage extends React.Component {
765
767
  background: '#fff',
766
768
  borderRadius: 22,
767
769
  opacity: 0.7,
770
+ width:'100%',
768
771
  height: '45vw',
769
772
  boxSizing: 'border-box',
770
773
  padding: '18px',
@@ -784,10 +787,10 @@ export class MobileChatPage extends React.Component {
784
787
  <img
785
788
  src={item.icon}
786
789
  alt={item.name}
787
- style={{width: '60px', height: '60px'}}
790
+ style={{width: '40px', height: '40px'}}
788
791
  />
789
- <div style={{marginTop: '12px', color: '#333333', fontWeight: "bold", fontSize: '16px'}}>{item.name}</div>
790
- <div style={{marginTop: '8px', color: '#333333', fontSize: '12px'}}>{item.content}</div>
792
+ <div style={{marginTop: '12px', color: '#333333', fontWeight: "bold", fontSize: '14px', textAlign: "left"}}>{item.name}</div>
793
+ <div style={{marginTop: '8px', color: '#333333', fontSize: '10px', textAlign: "left"}}>{item.content}</div>
791
794
  </div>
792
795
  ))}
793
796
  </div>
@@ -453,7 +453,7 @@ export class ToolDialog extends React.Component {
453
453
  {
454
454
  isShowSideLeft && <div className="p_toolLeft">
455
455
  <div className="p_toolLogo">
456
- <img className="p_logoImg" style={{ width: logoWidth }} src={agentUrl}/>
456
+ <img className="p_logoImg" style={{ width: logoWidth, borderRadius: 15 }} src={agentUrl}/>
457
457
  <div className="p_logoText" style={{ fontSize: logoFontSize }}>{agentName}</div>
458
458
  </div>
459
459
  <div className="p_historyDialog">