yt-chat-components 1.2.2 → 1.2.4

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 (42) hide show
  1. package/.idea/sonarlint/issuestore/7/0/7030d0b2f71b999ff89a343de08c414af32fc93a +0 -0
  2. package/.idea/sonarlint/issuestore/8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d +0 -0
  3. package/.idea/sonarlint/issuestore/9/c/9cfff9a6d27bd6c255aa751213163c7901fb8ce7 +0 -0
  4. package/.idea/sonarlint/issuestore/index.pb +7 -0
  5. package/build/asset-manifest.json +20 -0
  6. package/build/index.html +1 -0
  7. package/build/static/css/main.8ee59d98.css +2 -0
  8. package/build/static/css/main.8ee59d98.css.map +1 -0
  9. package/build/static/js/main.371ede49.js +3 -0
  10. package/build/static/js/main.371ede49.js.LICENSE.txt +181 -0
  11. package/build/static/js/main.371ede49.js.map +1 -0
  12. package/build/static/media/ai_call_working.a63afffab31dc8264d05.gif +0 -0
  13. package/build/static/media/aiavatar.74bafa995cce4c01b804.png +0 -0
  14. package/build/static/media/history-list-empty.1eb65b1550aef4e8c8a4.png +0 -0
  15. package/build/static/media/icon_history_headerbg.50747e81d01257f55346.png +0 -0
  16. package/build/static/media/moreAi.285e66289f838072060c.png +0 -0
  17. package/build/static/media/moreBg.9fc998472925cecd89f2.png +0 -0
  18. package/build/static/media/phone.19bc6f0d2e9eae4863ae.png +0 -0
  19. package/package.json +80 -78
  20. package/public/index.html +108 -108
  21. package/src/YtChatView/chatWidget/chatWindow/callInterface/index.module.css +50 -50
  22. package/src/YtChatView/chatWidget/chatWindow/callInterface/index.tsx +549 -549
  23. package/src/YtChatView/chatWidget/chatWindow/callInterface/style.ts +44 -44
  24. package/src/YtChatView/chatWidget/chatWindow/chatMessage/index.tsx +501 -501
  25. package/src/YtChatView/chatWidget/chatWindow/chatPlaceholder/index.tsx +23 -23
  26. package/src/YtChatView/chatWidget/chatWindow/controllers/index.ts +249 -249
  27. package/src/YtChatView/chatWidget/chatWindow/index.module.css +196 -196
  28. package/src/YtChatView/chatWidget/chatWindow/index.tsx +1182 -1186
  29. package/src/YtChatView/chatWidget/chatWindow/types/chatWidget/index.ts +50 -50
  30. package/src/YtChatView/chatWidget/index.tsx +2598 -2596
  31. package/src/YtChatView/logoBtn/index.css +3 -3
  32. package/src/YtChatView/logoBtn/index.jsx +103 -103
  33. package/src/YtChatView/logoSplitBtn/index.css +3 -3
  34. package/src/YtChatView/logoSplitBtn/index.jsx +105 -105
  35. package/src/YtChatView/mobileChat/index.jsx +945 -945
  36. package/src/YtChatView/mobileChat/index.module.css +253 -253
  37. package/src/YtChatView/previewDialog/index.jsx +601 -601
  38. package/src/YtChatView/previewDialog/index.module.css +253 -253
  39. package/src/chatWidget/chatWindow/index.tsx +426 -426
  40. package/src/chatWidget/index.tsx +2195 -2195
  41. package/src/index.tsx +11 -127
  42. package/webpack.config.js +50 -50
@@ -1,426 +1,426 @@
1
- // @ts-nocheck
2
- import { Send } from "lucide-react";
3
- import { extractMessageFromOutput, getAnimationOrigin, getChatPosition } from "../utils";
4
- import React, { useEffect, useRef, useState } from "react";
5
- import { ChatMessageType } from "../../types/chatWidget";
6
- import ChatMessage from "./chatMessage";
7
- import {sendMessage, sendMessageStream} from "../../controllers";
8
- import ChatMessagePlaceholder from "../../chatPlaceholder";
9
-
10
- export default function ChatWindow({
11
- api_key,
12
- flowId,
13
- hostUrl,
14
- updateLastMessage,
15
- messages,
16
- output_type,
17
- input_type,
18
- output_component,
19
- bot_message_style,
20
- send_icon_style,
21
- user_message_style,
22
- chat_window_style,
23
- error_message_style,
24
- placeholder_sending,
25
- send_button_style,
26
- online = true,
27
- open,
28
- online_message = "We'll reply as soon as we can",
29
- offline_message = "We're offline now",
30
- window_title = "Chat",
31
- placeholder,
32
- input_style,
33
- input_container_style,
34
- addMessage,
35
- position,
36
- triggerRef,
37
- width = 450,
38
- height = 650,
39
- tweaks,
40
- sessionId,
41
- additional_headers
42
- }: {
43
- api_key?: string;
44
- output_type: string,
45
- input_type: string,
46
- output_component?: string,
47
- bot_message_style?: React.CSSProperties;
48
- send_icon_style?: React.CSSProperties;
49
- user_message_style?: React.CSSProperties;
50
- chat_window_style?: React.CSSProperties;
51
- error_message_style?: React.CSSProperties;
52
- send_button_style?: React.CSSProperties;
53
- online?: boolean;
54
- open: boolean;
55
- online_message?: string;
56
- placeholder_sending?: string;
57
- offline_message?: string;
58
- window_title?: string;
59
- placeholder?: string;
60
- input_style?: React.CSSProperties;
61
- input_container_style?: React.CSSProperties;
62
- tweaks?: { [key: string]: any };
63
- flowId: string;
64
- hostUrl: string;
65
- updateLastMessage: Function;
66
- messages: ChatMessageType[];
67
- addMessage: Function;
68
- position?: string;
69
- triggerRef: React.RefObject<HTMLButtonElement>;
70
- width?: number;
71
- height?: number;
72
- sessionId: React.MutableRefObject<string>;
73
- additional_headers?: { [key: string]: string };
74
-
75
- }) {
76
- const [value, setValue] = useState<string>("");
77
- const ref = useRef<HTMLDivElement>(null);
78
- const lastMessage = useRef<HTMLDivElement>(null);
79
- const [windowPosition, setWindowPosition] = useState({ left: "0", top: "0" });
80
- const abortControllerRef = useRef(new AbortController());
81
- const inputRef = useRef<HTMLInputElement>(null); /* User input Ref */
82
- useEffect(() => {
83
- if (triggerRef)
84
- setWindowPosition(
85
- getChatPosition(
86
- triggerRef.current!.getBoundingClientRect(),
87
- width,
88
- height,
89
- position
90
- )
91
- );
92
- }, [triggerRef, width, height, position]);
93
-
94
- const isStream = true;
95
-
96
- /* Initial listener for loss of focus that refocuses User input after a small delay */
97
-
98
- const [sendingMessage, setSendingMessage] = useState(false);
99
-
100
- // 流式输出消息,实时显示(token为流式输出内容,end为结束输出,整体输出一次)
101
- const handleMessageContent = (event, data) => {
102
- if (event == 'add_message' && data['sender'] == 'Machine') {
103
- getHistoryList();
104
- } else if (event == 'token') {
105
- setNowAIContent((prevState) => prevState + data['chunk']);
106
- if (lastMessage.current) lastMessage.current.scrollIntoView({ behavior: 'smooth' });
107
- } else if (event == 'end') {
108
- const res = {
109
- data: data['result'],
110
- };
111
- if (
112
- res.data &&
113
- res.data.outputs &&
114
- Object.keys(res.data.outputs).length > 0 &&
115
- res.data.outputs[0].outputs &&
116
- res.data.outputs[0].outputs.length > 0
117
- ) {
118
- const flowOutputs: Array<any> = res.data.outputs[0].outputs;
119
- if (output_component && flowOutputs.map((e) => e.component_id).includes(output_component)) {
120
- Object.values(
121
- flowOutputs.find((e) => e.component_id === output_component).outputs,
122
- ).forEach((output: any) => {
123
- addMessage({
124
- message: extractMessageFromOutput(output),
125
- isSend: false,
126
- rawInfo: output.message,
127
- });
128
- });
129
- } else if (flowOutputs.length === 1) {
130
- Object.values(flowOutputs[0].outputs).forEach((output: any) => {
131
- addMessage({
132
- message: extractMessageFromOutput(output),
133
- isSend: false,
134
- rawInfo: output.message,
135
- });
136
- });
137
- } else {
138
- flowOutputs
139
- .sort((a, b) => {
140
- // Get the earliest timestamp from each flowOutput's outputs
141
- const aTimestamp = Math.min(
142
- ...Object.values(a.outputs).map((output: any) =>
143
- Date.parse(output.message?.timestamp),
144
- ),
145
- );
146
- const bTimestamp = Math.min(
147
- ...Object.values(b.outputs).map((output: any) =>
148
- Date.parse(output.message?.timestamp),
149
- ),
150
- );
151
- return aTimestamp - bTimestamp; // Sort descending (newest first)
152
- })
153
- .forEach((flowOutput) => {
154
- Object.values(flowOutput.outputs).forEach((output: any) => {
155
- addMessage({
156
- message: extractMessageFromOutput(output),
157
- isSend: false,
158
- rawInfo: output.message,
159
- });
160
- });
161
- });
162
- }
163
- }
164
- if (res.data && res.data.session_id) {
165
- // sessionId = res.data.session_id;
166
- }
167
- setSendingMessage(false);
168
- }
169
- };
170
-
171
- const sendMessageWrapper =()=>{
172
- sendMessage(hostUrl, flowId, value, input_type, output_type, sessionId, output_component, tweaks, api_key, additional_headers)
173
- .then((res) => {
174
- if (
175
- res.data &&
176
- res.data.outputs &&
177
- Object.keys(res.data.outputs).length > 0 &&
178
- res.data.outputs[0].outputs && res.data.outputs[0].outputs.length > 0
179
- ) {
180
- const flowOutputs: Array<any> = res.data.outputs[0].outputs;
181
- if (output_component &&
182
- flowOutputs.map(e => e.component_id).includes(output_component)) {
183
- Object.values(flowOutputs.find(e => e.component_id === output_component).outputs).forEach((output: any) => {
184
- addMessage({
185
- message: extractMessageFromOutput(output),
186
- isSend: false,
187
- });
188
- })
189
- } else if (
190
- flowOutputs.length === 1
191
- ) {
192
- Object.values(flowOutputs[0].outputs).forEach((output: any) => {
193
- addMessage({
194
- message: extractMessageFromOutput(output),
195
- isSend: false,
196
- });
197
- })
198
- } else {
199
- flowOutputs
200
- .sort((a, b) => {
201
- // Get the earliest timestamp from each flowOutput's outputs
202
- const aTimestamp = Math.min(...Object.values(a.outputs).map((output: any) => Date.parse(output.message?.timestamp)));
203
- const bTimestamp = Math.min(...Object.values(b.outputs).map((output: any) => Date.parse(output.message?.timestamp)));
204
- return aTimestamp - bTimestamp; // Sort descending (newest first)
205
- })
206
- .forEach((flowOutput) => {
207
- Object.values(flowOutput.outputs).forEach((output: any) => {
208
- addMessage({
209
- message: extractMessageFromOutput(output),
210
- isSend: false,
211
- });
212
- });
213
- });
214
- }
215
- }
216
- if (res.data && res.data.session_id) {
217
- sessionId.current = res.data.session_id;
218
- }
219
- setSendingMessage(false);
220
- })
221
- .catch((err) => {
222
- const response = err.response;
223
- if (err.code === "ERR_NETWORK") {
224
- updateLastMessage({
225
- message: "Network error",
226
- isSend: false,
227
- error: true,
228
- });
229
- } else if (
230
- response &&
231
- response.status === 500 &&
232
- response.data &&
233
- response.data.detail
234
- ) {
235
- updateLastMessage({
236
- message: response.data.detail,
237
- isSend: false,
238
- error: true,
239
- });
240
- }
241
- console.error(err);
242
- setSendingMessage(false);
243
- });
244
- }
245
-
246
- const sendMessageStreamWrapper = ()=>{
247
- let embedAppExtend: embedAppExtend = {
248
- operator_id: "2204411202",
249
- upload_file_path_list: [],
250
- http_extend: {
251
- bd:{
252
- code: "2204411202"
253
- },
254
- body: {
255
- code: "2204411202"
256
- }
257
- }
258
- };
259
- sendMessageStream(
260
- embedAppExtend,
261
- false,
262
- handleMessageContent,
263
- abortControllerRef.current.signal,
264
- hostUrl,
265
- flowId,
266
- value,
267
- input_type,
268
- output_type,
269
- sessionId.current,
270
- output_component,
271
- tweaks,
272
- api_key,
273
- additional_headers,
274
- )
275
- .then((res) => {
276
- setSendingMessage(false);
277
- })
278
- .catch((e) => {
279
- console.log('e :>> ', e);
280
- if (e.name !== 'AbortError') {
281
- addMessage({
282
- message: '网络错误',
283
- isSend: false,
284
- });
285
- }
286
- setSendingMessage(false);
287
- })
288
- }
289
- function handleClick() {
290
- if (value && value.trim() !== "") {
291
- addMessage({ message: value, isSend: true });
292
- setSendingMessage(true);
293
- setValue("");
294
- isStream ? sendMessageStreamWrapper() : sendMessageWrapper();
295
- }
296
- }
297
-
298
- useEffect(() => {
299
- if (lastMessage.current)
300
- lastMessage.current.scrollIntoView({ behavior: "smooth" });
301
- }, [messages]);
302
-
303
- /* Refocus the User input whenever a new response is returned from the LLM */
304
-
305
- useEffect(() => {
306
- // after a slight delay
307
- setTimeout(() => {
308
- inputRef.current?.focus();
309
- }, 100);
310
- }, [messages, open]);
311
-
312
- // console.log("---->",{
313
- // api_key,
314
- // flowId,
315
- // hostUrl,
316
- // updateLastMessage,
317
- // messages,
318
- // output_type,
319
- // input_type,
320
- // output_component,
321
- // bot_message_style,
322
- // send_icon_style,
323
- // user_message_style,
324
- // chat_window_style,
325
- // error_message_style,
326
- // placeholder_sending,
327
- // send_button_style,
328
- // online,
329
- // open,
330
- // online_message,
331
- // offline_message,
332
- // window_title,
333
- // placeholder,
334
- // input_style,
335
- // input_container_style,
336
- // addMessage,
337
- // position,
338
- // triggerRef,
339
- // width,
340
- // height,
341
- // tweaks,
342
- // sessionId,
343
- // additional_headers
344
- // })
345
-
346
- return (
347
- <div
348
- className={
349
- "cl-chat-window " +
350
- getAnimationOrigin(position) +
351
- (open ? " cl-scale-100" : " cl-scale-0")
352
- }
353
- style={{ ...windowPosition, zIndex: 9999 }}
354
- >
355
- <div
356
- style={{ ...chat_window_style, width: width, height: height }}
357
- ref={ref}
358
- className="cl-window"
359
- >
360
- <div className="cl-header">
361
- {window_title}
362
- <div className="cl-header-subtitle">
363
- {online ? (
364
- <>
365
- <div className="cl-online-message"></div>
366
- {online_message}
367
- </>
368
- ) : (
369
- <>
370
- <div className="cl-offline-message"></div>
371
- {offline_message}
372
- </>
373
- )}
374
- </div>
375
- </div>
376
- <div className="cl-messages_container">
377
- {messages.map((message, index) => (
378
- <ChatMessage
379
- bot_message_style={bot_message_style}
380
- user_message_style={user_message_style}
381
- error_message_style={error_message_style}
382
- key={index}
383
- message={message.message}
384
- isSend={message.isSend}
385
- error={message.error}
386
- />
387
- ))}
388
- {sendingMessage && (
389
- <ChatMessagePlaceholder bot_message_style={bot_message_style} />
390
- )}
391
- <div ref={lastMessage}></div>
392
- </div>
393
- <div style={input_container_style} className="cl-input_container">
394
- <input
395
- value={value}
396
- onChange={(e) => setValue(e.target.value)}
397
- onKeyDown={(e) => {
398
- if (e.key === "Enter") handleClick();
399
- }}
400
- type="text"
401
- disabled={sendingMessage}
402
- placeholder={sendingMessage ? (placeholder_sending || "Thinking...") : (placeholder || "Type your message...")}
403
- style={input_style}
404
- ref={inputRef}
405
- className="cl-input-element"
406
- />
407
- <button
408
- style={send_button_style}
409
- disabled={sendingMessage}
410
- onClick={handleClick}
411
- >
412
- <Send
413
- style={send_icon_style}
414
- className={
415
- "cl-send-icon " +
416
- (!sendingMessage
417
- ? "cl-notsending-message"
418
- : "cl-sending-message")
419
- }
420
- />
421
- </button>
422
- </div>
423
- </div>
424
- </div>
425
- );
426
- }
1
+ // @ts-nocheck
2
+ import { Send } from "lucide-react";
3
+ import { extractMessageFromOutput, getAnimationOrigin, getChatPosition } from "../utils";
4
+ import React, { useEffect, useRef, useState } from "react";
5
+ import { ChatMessageType } from "../../types/chatWidget";
6
+ import ChatMessage from "./chatMessage";
7
+ import {sendMessage, sendMessageStream} from "../../controllers";
8
+ import ChatMessagePlaceholder from "../../chatPlaceholder";
9
+
10
+ export default function ChatWindow({
11
+ api_key,
12
+ flowId,
13
+ hostUrl,
14
+ updateLastMessage,
15
+ messages,
16
+ output_type,
17
+ input_type,
18
+ output_component,
19
+ bot_message_style,
20
+ send_icon_style,
21
+ user_message_style,
22
+ chat_window_style,
23
+ error_message_style,
24
+ placeholder_sending,
25
+ send_button_style,
26
+ online = true,
27
+ open,
28
+ online_message = "We'll reply as soon as we can",
29
+ offline_message = "We're offline now",
30
+ window_title = "Chat",
31
+ placeholder,
32
+ input_style,
33
+ input_container_style,
34
+ addMessage,
35
+ position,
36
+ triggerRef,
37
+ width = 450,
38
+ height = 650,
39
+ tweaks,
40
+ sessionId,
41
+ additional_headers
42
+ }: {
43
+ api_key?: string;
44
+ output_type: string,
45
+ input_type: string,
46
+ output_component?: string,
47
+ bot_message_style?: React.CSSProperties;
48
+ send_icon_style?: React.CSSProperties;
49
+ user_message_style?: React.CSSProperties;
50
+ chat_window_style?: React.CSSProperties;
51
+ error_message_style?: React.CSSProperties;
52
+ send_button_style?: React.CSSProperties;
53
+ online?: boolean;
54
+ open: boolean;
55
+ online_message?: string;
56
+ placeholder_sending?: string;
57
+ offline_message?: string;
58
+ window_title?: string;
59
+ placeholder?: string;
60
+ input_style?: React.CSSProperties;
61
+ input_container_style?: React.CSSProperties;
62
+ tweaks?: { [key: string]: any };
63
+ flowId: string;
64
+ hostUrl: string;
65
+ updateLastMessage: Function;
66
+ messages: ChatMessageType[];
67
+ addMessage: Function;
68
+ position?: string;
69
+ triggerRef: React.RefObject<HTMLButtonElement>;
70
+ width?: number;
71
+ height?: number;
72
+ sessionId: React.MutableRefObject<string>;
73
+ additional_headers?: { [key: string]: string };
74
+
75
+ }) {
76
+ const [value, setValue] = useState<string>("");
77
+ const ref = useRef<HTMLDivElement>(null);
78
+ const lastMessage = useRef<HTMLDivElement>(null);
79
+ const [windowPosition, setWindowPosition] = useState({ left: "0", top: "0" });
80
+ const abortControllerRef = useRef(new AbortController());
81
+ const inputRef = useRef<HTMLInputElement>(null); /* User input Ref */
82
+ useEffect(() => {
83
+ if (triggerRef)
84
+ setWindowPosition(
85
+ getChatPosition(
86
+ triggerRef.current!.getBoundingClientRect(),
87
+ width,
88
+ height,
89
+ position
90
+ )
91
+ );
92
+ }, [triggerRef, width, height, position]);
93
+
94
+ const isStream = true;
95
+
96
+ /* Initial listener for loss of focus that refocuses User input after a small delay */
97
+
98
+ const [sendingMessage, setSendingMessage] = useState(false);
99
+
100
+ // 流式输出消息,实时显示(token为流式输出内容,end为结束输出,整体输出一次)
101
+ const handleMessageContent = (event, data) => {
102
+ if (event == 'add_message' && data['sender'] == 'Machine') {
103
+ getHistoryList();
104
+ } else if (event == 'token') {
105
+ setNowAIContent((prevState) => prevState + data['chunk']);
106
+ if (lastMessage.current) lastMessage.current.scrollIntoView({ behavior: 'smooth' });
107
+ } else if (event == 'end') {
108
+ const res = {
109
+ data: data['result'],
110
+ };
111
+ if (
112
+ res.data &&
113
+ res.data.outputs &&
114
+ Object.keys(res.data.outputs).length > 0 &&
115
+ res.data.outputs[0].outputs &&
116
+ res.data.outputs[0].outputs.length > 0
117
+ ) {
118
+ const flowOutputs: Array<any> = res.data.outputs[0].outputs;
119
+ if (output_component && flowOutputs.map((e) => e.component_id).includes(output_component)) {
120
+ Object.values(
121
+ flowOutputs.find((e) => e.component_id === output_component).outputs,
122
+ ).forEach((output: any) => {
123
+ addMessage({
124
+ message: extractMessageFromOutput(output),
125
+ isSend: false,
126
+ rawInfo: output.message,
127
+ });
128
+ });
129
+ } else if (flowOutputs.length === 1) {
130
+ Object.values(flowOutputs[0].outputs).forEach((output: any) => {
131
+ addMessage({
132
+ message: extractMessageFromOutput(output),
133
+ isSend: false,
134
+ rawInfo: output.message,
135
+ });
136
+ });
137
+ } else {
138
+ flowOutputs
139
+ .sort((a, b) => {
140
+ // Get the earliest timestamp from each flowOutput's outputs
141
+ const aTimestamp = Math.min(
142
+ ...Object.values(a.outputs).map((output: any) =>
143
+ Date.parse(output.message?.timestamp),
144
+ ),
145
+ );
146
+ const bTimestamp = Math.min(
147
+ ...Object.values(b.outputs).map((output: any) =>
148
+ Date.parse(output.message?.timestamp),
149
+ ),
150
+ );
151
+ return aTimestamp - bTimestamp; // Sort descending (newest first)
152
+ })
153
+ .forEach((flowOutput) => {
154
+ Object.values(flowOutput.outputs).forEach((output: any) => {
155
+ addMessage({
156
+ message: extractMessageFromOutput(output),
157
+ isSend: false,
158
+ rawInfo: output.message,
159
+ });
160
+ });
161
+ });
162
+ }
163
+ }
164
+ if (res.data && res.data.session_id) {
165
+ // sessionId = res.data.session_id;
166
+ }
167
+ setSendingMessage(false);
168
+ }
169
+ };
170
+
171
+ const sendMessageWrapper =()=>{
172
+ sendMessage(hostUrl, flowId, value, input_type, output_type, sessionId, output_component, tweaks, api_key, additional_headers)
173
+ .then((res) => {
174
+ if (
175
+ res.data &&
176
+ res.data.outputs &&
177
+ Object.keys(res.data.outputs).length > 0 &&
178
+ res.data.outputs[0].outputs && res.data.outputs[0].outputs.length > 0
179
+ ) {
180
+ const flowOutputs: Array<any> = res.data.outputs[0].outputs;
181
+ if (output_component &&
182
+ flowOutputs.map(e => e.component_id).includes(output_component)) {
183
+ Object.values(flowOutputs.find(e => e.component_id === output_component).outputs).forEach((output: any) => {
184
+ addMessage({
185
+ message: extractMessageFromOutput(output),
186
+ isSend: false,
187
+ });
188
+ })
189
+ } else if (
190
+ flowOutputs.length === 1
191
+ ) {
192
+ Object.values(flowOutputs[0].outputs).forEach((output: any) => {
193
+ addMessage({
194
+ message: extractMessageFromOutput(output),
195
+ isSend: false,
196
+ });
197
+ })
198
+ } else {
199
+ flowOutputs
200
+ .sort((a, b) => {
201
+ // Get the earliest timestamp from each flowOutput's outputs
202
+ const aTimestamp = Math.min(...Object.values(a.outputs).map((output: any) => Date.parse(output.message?.timestamp)));
203
+ const bTimestamp = Math.min(...Object.values(b.outputs).map((output: any) => Date.parse(output.message?.timestamp)));
204
+ return aTimestamp - bTimestamp; // Sort descending (newest first)
205
+ })
206
+ .forEach((flowOutput) => {
207
+ Object.values(flowOutput.outputs).forEach((output: any) => {
208
+ addMessage({
209
+ message: extractMessageFromOutput(output),
210
+ isSend: false,
211
+ });
212
+ });
213
+ });
214
+ }
215
+ }
216
+ if (res.data && res.data.session_id) {
217
+ sessionId.current = res.data.session_id;
218
+ }
219
+ setSendingMessage(false);
220
+ })
221
+ .catch((err) => {
222
+ const response = err.response;
223
+ if (err.code === "ERR_NETWORK") {
224
+ updateLastMessage({
225
+ message: "Network error",
226
+ isSend: false,
227
+ error: true,
228
+ });
229
+ } else if (
230
+ response &&
231
+ response.status === 500 &&
232
+ response.data &&
233
+ response.data.detail
234
+ ) {
235
+ updateLastMessage({
236
+ message: response.data.detail,
237
+ isSend: false,
238
+ error: true,
239
+ });
240
+ }
241
+ console.error(err);
242
+ setSendingMessage(false);
243
+ });
244
+ }
245
+
246
+ const sendMessageStreamWrapper = ()=>{
247
+ let embedAppExtend: embedAppExtend = {
248
+ operator_id: "2204411202",
249
+ upload_file_path_list: [],
250
+ http_extend: {
251
+ bd:{
252
+ code: "2204411202"
253
+ },
254
+ body: {
255
+ code: "2204411202"
256
+ }
257
+ }
258
+ };
259
+ sendMessageStream(
260
+ embedAppExtend,
261
+ false,
262
+ handleMessageContent,
263
+ abortControllerRef.current.signal,
264
+ hostUrl,
265
+ flowId,
266
+ value,
267
+ input_type,
268
+ output_type,
269
+ sessionId.current,
270
+ output_component,
271
+ tweaks,
272
+ api_key,
273
+ additional_headers,
274
+ )
275
+ .then((res) => {
276
+ setSendingMessage(false);
277
+ })
278
+ .catch((e) => {
279
+ console.log('e :>> ', e);
280
+ if (e.name !== 'AbortError') {
281
+ addMessage({
282
+ message: '网络错误',
283
+ isSend: false,
284
+ });
285
+ }
286
+ setSendingMessage(false);
287
+ })
288
+ }
289
+ function handleClick() {
290
+ if (value && value.trim() !== "") {
291
+ addMessage({ message: value, isSend: true });
292
+ setSendingMessage(true);
293
+ setValue("");
294
+ isStream ? sendMessageStreamWrapper() : sendMessageWrapper();
295
+ }
296
+ }
297
+
298
+ useEffect(() => {
299
+ if (lastMessage.current)
300
+ lastMessage.current.scrollIntoView({ behavior: "smooth" });
301
+ }, [messages]);
302
+
303
+ /* Refocus the User input whenever a new response is returned from the LLM */
304
+
305
+ useEffect(() => {
306
+ // after a slight delay
307
+ setTimeout(() => {
308
+ inputRef.current?.focus();
309
+ }, 100);
310
+ }, [messages, open]);
311
+
312
+ // console.log("---->",{
313
+ // api_key,
314
+ // flowId,
315
+ // hostUrl,
316
+ // updateLastMessage,
317
+ // messages,
318
+ // output_type,
319
+ // input_type,
320
+ // output_component,
321
+ // bot_message_style,
322
+ // send_icon_style,
323
+ // user_message_style,
324
+ // chat_window_style,
325
+ // error_message_style,
326
+ // placeholder_sending,
327
+ // send_button_style,
328
+ // online,
329
+ // open,
330
+ // online_message,
331
+ // offline_message,
332
+ // window_title,
333
+ // placeholder,
334
+ // input_style,
335
+ // input_container_style,
336
+ // addMessage,
337
+ // position,
338
+ // triggerRef,
339
+ // width,
340
+ // height,
341
+ // tweaks,
342
+ // sessionId,
343
+ // additional_headers
344
+ // })
345
+
346
+ return (
347
+ <div
348
+ className={
349
+ "cl-chat-window " +
350
+ getAnimationOrigin(position) +
351
+ (open ? " cl-scale-100" : " cl-scale-0")
352
+ }
353
+ style={{ ...windowPosition, zIndex: 9999 }}
354
+ >
355
+ <div
356
+ style={{ ...chat_window_style, width: width, height: height }}
357
+ ref={ref}
358
+ className="cl-window"
359
+ >
360
+ <div className="cl-header">
361
+ {window_title}
362
+ <div className="cl-header-subtitle">
363
+ {online ? (
364
+ <>
365
+ <div className="cl-online-message"></div>
366
+ {online_message}
367
+ </>
368
+ ) : (
369
+ <>
370
+ <div className="cl-offline-message"></div>
371
+ {offline_message}
372
+ </>
373
+ )}
374
+ </div>
375
+ </div>
376
+ <div className="cl-messages_container">
377
+ {messages.map((message, index) => (
378
+ <ChatMessage
379
+ bot_message_style={bot_message_style}
380
+ user_message_style={user_message_style}
381
+ error_message_style={error_message_style}
382
+ key={index}
383
+ message={message.message}
384
+ isSend={message.isSend}
385
+ error={message.error}
386
+ />
387
+ ))}
388
+ {sendingMessage && (
389
+ <ChatMessagePlaceholder bot_message_style={bot_message_style} />
390
+ )}
391
+ <div ref={lastMessage}></div>
392
+ </div>
393
+ <div style={input_container_style} className="cl-input_container">
394
+ <input
395
+ value={value}
396
+ onChange={(e) => setValue(e.target.value)}
397
+ onKeyDown={(e) => {
398
+ if (e.key === "Enter") handleClick();
399
+ }}
400
+ type="text"
401
+ disabled={sendingMessage}
402
+ placeholder={sendingMessage ? (placeholder_sending || "Thinking...") : (placeholder || "Type your message...")}
403
+ style={input_style}
404
+ ref={inputRef}
405
+ className="cl-input-element"
406
+ />
407
+ <button
408
+ style={send_button_style}
409
+ disabled={sendingMessage}
410
+ onClick={handleClick}
411
+ >
412
+ <Send
413
+ style={send_icon_style}
414
+ className={
415
+ "cl-send-icon " +
416
+ (!sendingMessage
417
+ ? "cl-notsending-message"
418
+ : "cl-sending-message")
419
+ }
420
+ />
421
+ </button>
422
+ </div>
423
+ </div>
424
+ </div>
425
+ );
426
+ }