@clikvn/agent-widget-embedded 0.0.4-dev → 0.0.5-dev

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 (46) hide show
  1. package/dist/components/Chat/AudioPlayer.d.ts +6 -0
  2. package/dist/components/Chat/AudioPlayer.d.ts.map +1 -0
  3. package/dist/components/Chat/Chat.d.ts.map +1 -1
  4. package/dist/components/Chat/Icons.d.ts +5 -2
  5. package/dist/components/Chat/Icons.d.ts.map +1 -1
  6. package/dist/components/Chat/Message.d.ts +1 -0
  7. package/dist/components/Chat/Message.d.ts.map +1 -1
  8. package/dist/components/Chat/MultimodalInput.d.ts +2 -0
  9. package/dist/components/Chat/MultimodalInput.d.ts.map +1 -1
  10. package/dist/features/AgentWidget/index.d.ts +2 -0
  11. package/dist/features/AgentWidget/index.d.ts.map +1 -1
  12. package/dist/hooks/useAudioRecording.d.ts +2 -6
  13. package/dist/hooks/useAudioRecording.d.ts.map +1 -1
  14. package/dist/hooks/useChat.d.ts +2 -0
  15. package/dist/hooks/useChat.d.ts.map +1 -1
  16. package/dist/hooks/useChatData.d.ts +2 -0
  17. package/dist/hooks/useChatData.d.ts.map +1 -1
  18. package/dist/hooks/useConfiguration.d.ts +1 -6
  19. package/dist/hooks/useConfiguration.d.ts.map +1 -1
  20. package/dist/index.html +11 -2
  21. package/dist/register.d.ts +5 -3
  22. package/dist/register.d.ts.map +1 -1
  23. package/dist/types/common.type.d.ts +5 -0
  24. package/dist/types/common.type.d.ts.map +1 -1
  25. package/dist/types/flowise.type.d.ts +2 -0
  26. package/dist/types/flowise.type.d.ts.map +1 -1
  27. package/dist/web.d.ts +1 -12
  28. package/dist/web.d.ts.map +1 -1
  29. package/dist/web.js +1 -1
  30. package/dist/window.d.ts +3 -15
  31. package/dist/window.d.ts.map +1 -1
  32. package/package.json +1 -1
  33. package/src/components/Chat/AudioPlayer.tsx +43 -0
  34. package/src/components/Chat/Chat.tsx +5 -0
  35. package/src/components/Chat/Icons.tsx +32 -2
  36. package/src/components/Chat/Message.tsx +6 -0
  37. package/src/components/Chat/MultimodalInput.tsx +56 -54
  38. package/src/features/AgentWidget/index.tsx +5 -2
  39. package/src/hooks/useAudioRecording.ts +4 -8
  40. package/src/hooks/useChat.ts +12 -2
  41. package/src/hooks/useChatData.tsx +3 -0
  42. package/src/hooks/useConfiguration.tsx +1 -6
  43. package/src/register.tsx +5 -2
  44. package/src/types/common.type.ts +6 -0
  45. package/src/types/flowise.type.ts +2 -0
  46. package/src/window.ts +2 -15
package/dist/window.d.ts CHANGED
@@ -1,17 +1,5 @@
1
- import { EVENT_TYPE } from './models';
2
- type VoiceAgentWidget = {
3
- apiHost: string;
4
- agentId: string;
5
- overrideConfig?: {
6
- chatId?: string | undefined;
7
- overrideConfig?: Record<string, any>;
8
- } & Record<string, unknown>;
9
- theme?: {
10
- avatar?: string;
11
- } & Record<string, unknown>;
12
- listeners?: Record<EVENT_TYPE, (props: any) => void>;
13
- };
14
- export declare const initWidget: (props: VoiceAgentWidget & {
1
+ import { AgentWidgetType } from './register';
2
+ export declare const initWidget: (props: AgentWidgetType & {
15
3
  id?: string;
16
4
  }) => void;
17
5
  export declare const destroy: () => void;
@@ -20,7 +8,7 @@ type AgentWidget = {
20
8
  destroy: typeof destroy;
21
9
  };
22
10
  export declare const parseAgentVoice: () => {
23
- initWidget: (props: VoiceAgentWidget & {
11
+ initWidget: (props: AgentWidgetType & {
24
12
  id?: string;
25
13
  }) => void;
26
14
  destroy: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../src/window.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAItC,KAAK,gBAAgB,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE;QACf,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACtC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC,CAAC;CACtD,CAAC;AACF,eAAO,MAAM,UAAU,UAAW,gBAAgB,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,SAYnE,CAAC;AAEF,eAAO,MAAM,OAAO,YAEnB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,OAAO,EAAE,OAAO,OAAO,CAAC;CACzB,CAAC;AAQF,eAAO,MAAM,eAAe;wBA7BM,gBAAgB,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE;;CAgClE,CAAC;AAEH,eAAO,MAAM,wBAAwB,UAAW,WAAW,SAG1D,CAAC"}
1
+ {"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../src/window.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAyB,MAAM,YAAY,CAAC;AAIpE,eAAO,MAAM,UAAU,UAAW,eAAe,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,SAYlE,CAAC;AAEF,eAAO,MAAM,OAAO,YAEnB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,OAAO,EAAE,OAAO,OAAO,CAAC;CACzB,CAAC;AAQF,eAAO,MAAM,eAAe;wBA7BM,eAAe,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE;;CAgCjE,CAAC;AAEH,eAAO,MAAM,wBAAwB,UAAW,WAAW,SAG1D,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@clikvn/agent-widget-embedded",
3
3
  "description": "This is agent widget",
4
- "version": "0.0.4-dev",
4
+ "version": "0.0.5-dev",
5
5
  "author": "Clik JSC",
6
6
  "license": "ISC",
7
7
  "type": "module",
@@ -0,0 +1,43 @@
1
+ import React, { useRef, useState } from 'react';
2
+ import { PlayIcon, StopIcon1 } from './Icons';
3
+
4
+ const AudioPlayer = ({
5
+ src,
6
+ autoplay = false,
7
+ }: {
8
+ src: string;
9
+ autoplay?: boolean;
10
+ }) => {
11
+ const audioRef = useRef<any>(null);
12
+ const [isPlaying, setIsPlaying] = useState(false);
13
+
14
+ const handlePlayPause = (e: any) => {
15
+ e.preventDefault();
16
+ if (isPlaying) {
17
+ audioRef.current.pause();
18
+ } else {
19
+ audioRef.current.play();
20
+ }
21
+ setIsPlaying(!isPlaying);
22
+ };
23
+
24
+ return (
25
+ <>
26
+ <button
27
+ className="rounded-full cursor-pointer h-fit w-[24px]"
28
+ onClick={handlePlayPause}
29
+ >
30
+ {isPlaying ? <StopIcon1 /> : <PlayIcon />}
31
+ </button>
32
+ <audio
33
+ ref={audioRef}
34
+ className="hidden"
35
+ src={src}
36
+ autoPlay={autoplay}
37
+ onEnded={() => setIsPlaying(false)}
38
+ ></audio>
39
+ </>
40
+ );
41
+ };
42
+
43
+ export default AudioPlayer;
@@ -25,6 +25,8 @@ export const Chat: FC<PropsType> = ({ id, agentId, initialMessages = [] }) => {
25
25
  chatId,
26
26
  append,
27
27
  bot,
28
+ enableTTS,
29
+ setEnableTTS,
28
30
  } = useChat({ id, initialMessages, agentId });
29
31
  const { apiHost } = useConfiguration();
30
32
  const [messagesContainerRef, messagesEndRef] =
@@ -47,6 +49,7 @@ export const Chat: FC<PropsType> = ({ id, agentId, initialMessages = [] }) => {
47
49
  chatId={id}
48
50
  message={message}
49
51
  isLoading={isLoading && (messages || []).length - 1 === index}
52
+ enableTTS={enableTTS}
50
53
  />
51
54
  ))}
52
55
 
@@ -76,6 +79,8 @@ export const Chat: FC<PropsType> = ({ id, agentId, initialMessages = [] }) => {
76
79
  setAttachments={setAttachments}
77
80
  bot={bot}
78
81
  apiHost={apiHost}
82
+ setEnableTTS={setEnableTTS}
83
+ enableTTS={enableTTS}
79
84
  />
80
85
  </form>
81
86
  </div>
@@ -477,7 +477,13 @@ export const MoreIcon = ({ size = 16 }: { size?: number }) => {
477
477
  );
478
478
  };
479
479
 
480
- export const TrashIcon = ({ size = 16, color }: { size?: number, color?: string }) => {
480
+ export const TrashIcon = ({
481
+ size = 16,
482
+ color,
483
+ }: {
484
+ size?: number;
485
+ color?: string;
486
+ }) => {
481
487
  return (
482
488
  <svg
483
489
  height={size}
@@ -882,7 +888,13 @@ export const MicrophoneIcon = ({ size = 16 }: { size?: number }) => {
882
888
  );
883
889
  };
884
890
 
885
- export const CircleDotIcon = ({ size = 16, color = 'red' }: { size?: number, color?: string }) => (
891
+ export const CircleDotIcon = ({
892
+ size = 16,
893
+ color = 'red',
894
+ }: {
895
+ size?: number;
896
+ color?: string;
897
+ }) => (
886
898
  <svg
887
899
  xmlns="http://www.w3.org/2000/svg"
888
900
  height={size}
@@ -898,3 +910,21 @@ export const CircleDotIcon = ({ size = 16, color = 'red' }: { size?: number, col
898
910
  <circle cx="12" cy="12" r="1" />
899
911
  </svg>
900
912
  );
913
+
914
+ export const PlayIcon = () => (
915
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
916
+ <path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zM188.3 147.1c7.6-4.2 16.8-4.1 24.3 .5l144 88c7.1 4.4 11.5 12.1 11.5 20.5s-4.4 16.1-11.5 20.5l-144 88c-7.4 4.5-16.7 4.7-24.3 .5s-12.3-12.2-12.3-20.9l0-176c0-8.7 4.7-16.7 12.3-20.9z" />
917
+ </svg>
918
+ );
919
+
920
+ export const StopIcon1 = () => (
921
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
922
+ <path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm192-96l128 0c17.7 0 32 14.3 32 32l0 128c0 17.7-14.3 32-32 32l-128 0c-17.7 0-32-14.3-32-32l0-128c0-17.7 14.3-32 32-32z" />
923
+ </svg>
924
+ );
925
+
926
+ export const VolumeIcon = () => (
927
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512">
928
+ <path d="M533.6 32.5C598.5 85.2 640 165.8 640 256s-41.5 170.7-106.4 223.5c-10.3 8.4-25.4 6.8-33.8-3.5s-6.8-25.4 3.5-33.8C557.5 398.2 592 331.2 592 256s-34.5-142.2-88.7-186.3c-10.3-8.4-11.8-23.5-3.5-33.8s23.5-11.8 33.8-3.5zM473.1 107c43.2 35.2 70.9 88.9 70.9 149s-27.7 113.8-70.9 149c-10.3 8.4-25.4 6.8-33.8-3.5s-6.8-25.4 3.5-33.8C475.3 341.3 496 301.1 496 256s-20.7-85.3-53.2-111.8c-10.3-8.4-11.8-23.5-3.5-33.8s23.5-11.8 33.8-3.5zm-60.5 74.5C434.1 199.1 448 225.9 448 256s-13.9 56.9-35.4 74.5c-10.3 8.4-25.4 6.8-33.8-3.5s-6.8-25.4 3.5-33.8C393.1 284.4 400 271 400 256s-6.9-28.4-17.7-37.3c-10.3-8.4-11.8-23.5-3.5-33.8s23.5-11.8 33.8-3.5zM301.1 34.8C312.6 40 320 51.4 320 64l0 384c0 12.6-7.4 24-18.9 29.2s-25 3.1-34.4-5.3L131.8 352 64 352c-35.3 0-64-28.7-64-64l0-64c0-35.3 28.7-64 64-64l67.8 0L266.7 40.1c9.4-8.4 22.9-10.4 34.4-5.3z" />
929
+ </svg>
930
+ );
@@ -10,12 +10,14 @@ import {
10
10
  ToolUsage,
11
11
  } from '../../types/flowise.type';
12
12
  import { cn } from '../../utils/commonUtils';
13
+ import AudioPlayer from './AudioPlayer';
13
14
 
14
15
  type PropsType = {
15
16
  chatId?: string;
16
17
  message: ChatMessageType;
17
18
  isLoading: boolean;
18
19
  bot: BotType | null;
20
+ enableTTS?: boolean;
19
21
  };
20
22
 
21
23
  const getRole = (role?: MessageRoleType) => {
@@ -31,6 +33,7 @@ export const PreviewMessage: FC<PropsType> = ({
31
33
  message,
32
34
  isLoading,
33
35
  bot,
36
+ enableTTS,
34
37
  }) => {
35
38
  const parseOutput = (outputData: any) => {
36
39
  try {
@@ -136,6 +139,9 @@ export const PreviewMessage: FC<PropsType> = ({
136
139
  </Markdown>
137
140
  </div>
138
141
  )}
142
+ {message?.ttsUrl && (
143
+ <AudioPlayer src={message.ttsUrl} autoplay={!!enableTTS} />
144
+ )}
139
145
  </div>
140
146
  </div>
141
147
  </motion.div>
@@ -12,17 +12,16 @@ import {
12
12
  cn,
13
13
  generateExtendedFileName,
14
14
  generateUUID,
15
- sleep,
16
15
  } from '../../utils/commonUtils';
17
16
  import { PreviewAttachment } from './PreviewAttachment';
18
17
  import {
19
18
  ArrowUpIcon,
20
19
  CircleDotIcon,
21
20
  MicrophoneIcon,
22
- PaperclipIcon,
23
21
  PlusIcon,
24
22
  StopIcon,
25
23
  TrashIcon,
24
+ VolumeIcon,
26
25
  } from './Icons';
27
26
  import { ChatMessageType, IFileUpload } from '../../types/flowise.type';
28
27
  import { BotType } from '../../types/bot.type';
@@ -31,29 +30,7 @@ import { createAttachments } from '../../services/chat.service';
31
30
  import { Button } from './ui/Button';
32
31
  import { Textarea } from './ui/Textarea';
33
32
  import { useAudioRecording } from '../../hooks/useAudioRecording';
34
-
35
- const suggestedActions = [
36
- {
37
- title: 'What is the weather',
38
- label: 'in Ha Noi?',
39
- action: 'What is the weather in Ha Noi?',
40
- },
41
- {
42
- title: 'Create a travel plan for an traveling',
43
- label: 'to Ha Noi',
44
- action: 'Create a travel plan for an traveling to Ha Noi',
45
- },
46
- {
47
- title: 'Top of tourist attractions',
48
- label: 'in Ha Noi',
49
- action: 'Top of tourist attractions in Ha Noi',
50
- },
51
- {
52
- title: 'List of museums',
53
- label: 'in Ha Noi',
54
- action: 'List of museums in Ha Noi',
55
- },
56
- ];
33
+ import { useChatData } from '../../hooks/useChatData';
57
34
 
58
35
  type PropsType = {
59
36
  input: string;
@@ -73,6 +50,8 @@ type PropsType = {
73
50
  setAttachments?: (func: (files: IFileUpload[]) => IFileUpload[]) => void;
74
51
  bot: BotType | null;
75
52
  apiHost: string;
53
+ setEnableTTS: (value: boolean) => void;
54
+ enableTTS: boolean;
76
55
  };
77
56
 
78
57
  export const MultimodalInput: FC<PropsType> = ({
@@ -90,7 +69,10 @@ export const MultimodalInput: FC<PropsType> = ({
90
69
  setAttachments,
91
70
  bot,
92
71
  apiHost,
72
+ setEnableTTS,
73
+ enableTTS,
93
74
  }) => {
75
+ const { suggestedActions = [] } = useChatData();
94
76
  const {
95
77
  isRecording,
96
78
  setIsRecording,
@@ -98,17 +80,7 @@ export const MultimodalInput: FC<PropsType> = ({
98
80
  onRecordingStopped,
99
81
  elapsedTime,
100
82
  isLoadingRecording,
101
- } = useAudioRecording({
102
- addRecordingToPreviews: async (blob: Blob) => {
103
- try {
104
- const audioFile = await toAudioBase64(blob);
105
- handleSubmit(undefined, [audioFile]);
106
- setIsRecording(false);
107
- } catch (error) {
108
- console.error('Error uploading files!', error);
109
- }
110
- },
111
- });
83
+ } = useAudioRecording();
112
84
  const textareaRef = useRef<HTMLTextAreaElement | null>(null);
113
85
  const { width } = useWindowSize();
114
86
  useEffect(() => {
@@ -289,6 +261,27 @@ export const MultimodalInput: FC<PropsType> = ({
289
261
  [setAttachments, checkUploadFile]
290
262
  );
291
263
 
264
+ const handleSubmitRecording = useCallback(
265
+ async (blob: Blob) => {
266
+ try {
267
+ const audioFile = await toAudioBase64(blob);
268
+ handleSubmit(undefined, [audioFile]);
269
+ setIsRecording(false);
270
+ } catch (error) {
271
+ console.error('Error uploading files!', error);
272
+ }
273
+ },
274
+ [handleSubmit, setIsRecording]
275
+ );
276
+
277
+ const handleSend = useCallback(async () => {
278
+ if (isRecording) {
279
+ onRecordingStopped(handleSubmitRecording);
280
+ } else {
281
+ submitForm();
282
+ }
283
+ }, [submitForm, onRecordingStopped, handleSubmitRecording]);
284
+
292
285
  return (
293
286
  <div className="relative w-full flex flex-col gap-4">
294
287
  {messages.length === 0 && (
@@ -371,7 +364,6 @@ export const MultimodalInput: FC<PropsType> = ({
371
364
  onKeyDown={(event) => {
372
365
  if (event.key === 'Enter' && !event.shiftKey) {
373
366
  event.preventDefault();
374
-
375
367
  if (isLoading) {
376
368
  console.error(
377
369
  'Please wait for the model to finish its response!'
@@ -379,7 +371,7 @@ export const MultimodalInput: FC<PropsType> = ({
379
371
  } else if (uploadQueue.length) {
380
372
  console.error('Please wait for file is uploading!');
381
373
  } else {
382
- submitForm();
374
+ handleSend();
383
375
  }
384
376
  }
385
377
  }}
@@ -401,11 +393,7 @@ export const MultimodalInput: FC<PropsType> = ({
401
393
  className="rounded-full p-1.5 h-fit absolute bottom-2 right-2 m-0.5 border dark:border-zinc-600"
402
394
  onClick={(event) => {
403
395
  event.preventDefault();
404
- if (isRecording) {
405
- onRecordingStopped();
406
- } else {
407
- submitForm();
408
- }
396
+ handleSend();
409
397
  }}
410
398
  disabled={
411
399
  !isRecording && (input.length === 0 || !!uploadQueue.length)
@@ -440,18 +428,32 @@ export const MultimodalInput: FC<PropsType> = ({
440
428
  </Button>
441
429
  </>
442
430
  ) : (
443
- <Button
444
- className="rounded-full p-1.5 h-fit absolute bottom-2 right-11 m-0.5 dark:border-zinc-700"
445
- onClick={(event) => {
446
- event.preventDefault();
447
- setIsRecording(true);
448
- }}
449
- variant="outline"
450
- disabled={isLoading}
451
- >
452
- <MicrophoneIcon size={14} />
453
- </Button>
431
+ <>
432
+ <Button
433
+ className="rounded-full p-1.5 h-fit absolute bottom-2 right-11 m-0.5 dark:border-zinc-700"
434
+ onClick={(event) => {
435
+ event.preventDefault();
436
+ setIsRecording(true);
437
+ }}
438
+ variant="outline"
439
+ disabled={isLoading}
440
+ >
441
+ <MicrophoneIcon size={14} />
442
+ </Button>
443
+ <Button
444
+ className={`rounded-full p-1.5 h-fit absolute bottom-2 right-[80px] m-0.5 dark:border-zinc-700 ${enableTTS ? 'text-white hover:bg-primary/90 bg-primary' : ''}`}
445
+ onClick={(event) => {
446
+ event.preventDefault();
447
+ setEnableTTS(!enableTTS);
448
+ }}
449
+ variant="outline"
450
+ disabled={isLoading}
451
+ >
452
+ <VolumeIcon />
453
+ </Button>
454
+ </>
454
455
  )}
456
+
455
457
  <Button
456
458
  className="rounded-full p-1.5 h-fit absolute bottom-2 left-2 m-0.5 dark:border-zinc-700"
457
459
  onClick={(event) => {
@@ -5,6 +5,7 @@ import Agent from '../../components/Agent';
5
5
  import { ChatDataProvider } from '../../hooks/useChatData';
6
6
  import styles from '../../assets/tailwindcss.css';
7
7
  import commonStyles from '../../assets/common.css';
8
+ import { SuggestionType } from '../../types/common.type';
8
9
 
9
10
  export type AgentWidgetType = {
10
11
  apiHost: string;
@@ -12,6 +13,7 @@ export type AgentWidgetType = {
12
13
  overrideConfig?: {
13
14
  chatId?: string | undefined;
14
15
  overrideConfig?: Record<string, unknown>;
16
+ suggestedActions?: SuggestionType[];
15
17
  } & Record<string, unknown>;
16
18
  theme?: {
17
19
  avatar?: string;
@@ -27,14 +29,15 @@ const AgentWidget: FC<AgentWidgetType> = (props: AgentWidgetType) => {
27
29
  config={{
28
30
  apiHost: props.apiHost,
29
31
  agentId: props.agentId,
30
- listeners: props.listeners,
31
- overrideConfig: props.overrideConfig,
32
+ overrideConfig: props.overrideConfig?.overrideConfig,
32
33
  theme: props.theme,
33
34
  }}
34
35
  >
35
36
  <ChatDataProvider
36
37
  data={{
37
38
  chatId: props.overrideConfig?.chatId,
39
+ suggestedActions: props.overrideConfig?.suggestedActions,
40
+ listeners: props.listeners,
38
41
  }}
39
42
  >
40
43
  <Agent />
@@ -5,12 +5,7 @@ import {
5
5
  stopAudioRecording,
6
6
  } from '../utils/audioRecording';
7
7
 
8
- type Props = {
9
- addRecordingToPreviews: (blob: Blob) => void;
10
- };
11
-
12
- export const useAudioRecording = (props: Props) => {
13
- const { addRecordingToPreviews } = props;
8
+ export const useAudioRecording = () => {
14
9
  const [elapsedTime, setElapsedTime] = useState('00:00');
15
10
  const [recordingNotSupported, setRecordingNotSupported] = useState(false);
16
11
  const [isLoadingRecording, setIsLoadingRecording] = useState(false);
@@ -23,6 +18,7 @@ export const useAudioRecording = (props: Props) => {
23
18
  }, [isRecording]);
24
19
  const onRecordingStarted = () => {
25
20
  setIsRecording(true);
21
+ setIsLoadingRecording(false);
26
22
  startAudioRecording(
27
23
  setIsRecording,
28
24
  setRecordingNotSupported,
@@ -36,9 +32,9 @@ export const useAudioRecording = (props: Props) => {
36
32
  setRecordingNotSupported(false);
37
33
  };
38
34
 
39
- const onRecordingStopped = () => {
35
+ const onRecordingStopped = (onStop: null | ((blob: Blob) => void)) => {
40
36
  setIsLoadingRecording(true);
41
- stopAudioRecording(addRecordingToPreviews);
37
+ stopAudioRecording(onStop);
42
38
  };
43
39
 
44
40
  return {
@@ -33,6 +33,8 @@ type ReturnType = {
33
33
  chatId: string;
34
34
  append: (message: ChatMessageType) => Promise<void>;
35
35
  bot: BotType | null;
36
+ enableTTS: boolean;
37
+ setEnableTTS: (value: boolean) => void;
36
38
  };
37
39
 
38
40
  export const useChat = (props: PropsType): ReturnType => {
@@ -43,6 +45,7 @@ export const useChat = (props: PropsType): ReturnType => {
43
45
  const chatIdRef = useRef<string>(idKey);
44
46
  const [chatId, setChatId] = useState(idKey);
45
47
  const [bot, setBot] = useState<BotType | null>(null);
48
+ const [enableTTS, setEnableTTS] = useState(false);
46
49
 
47
50
  const updateChatId = (uuid: string) => {
48
51
  chatIdRef.current = uuid;
@@ -91,6 +94,9 @@ export const useChat = (props: PropsType): ReturnType => {
91
94
  lastMsg.content = newMessage.metaData.question;
92
95
  }
93
96
  mutateMessages([...msgs, { ...newMessage }]);
97
+ } else if (chunk.event == 'audio') {
98
+ newMessage.ttsUrl = chunk.data as string;
99
+ mutateMessages([...msgs, { ...newMessage }]);
94
100
  }
95
101
  };
96
102
 
@@ -170,7 +176,8 @@ export const useChat = (props: PropsType): ReturnType => {
170
176
  chatId: chatIdRef.current,
171
177
  question: message.content,
172
178
  chatflowId: bot?.id,
173
- overrideConfig: overrideConfig?.overrideConfig,
179
+ overrideConfig: overrideConfig,
180
+ tts: enableTTS,
174
181
  });
175
182
  setInput('');
176
183
  };
@@ -213,7 +220,8 @@ export const useChat = (props: PropsType): ReturnType => {
213
220
  question: input || '',
214
221
  uploads: files || [],
215
222
  chatflowId: bot?.id,
216
- overrideConfig: overrideConfig?.overrideConfig,
223
+ overrideConfig: overrideConfig,
224
+ tts: enableTTS,
217
225
  });
218
226
  setInput('');
219
227
  },
@@ -231,5 +239,7 @@ export const useChat = (props: PropsType): ReturnType => {
231
239
  chatId,
232
240
  append,
233
241
  bot,
242
+ enableTTS,
243
+ setEnableTTS,
234
244
  };
235
245
  };
@@ -4,11 +4,13 @@ import { getChatMessage } from '../services/chat.service';
4
4
  import { ChatMessageType } from '../types/flowise.type';
5
5
  import { generateUUID } from '../utils/commonUtils';
6
6
  import { useConfiguration } from './useConfiguration';
7
+ import { SuggestionType } from '../types/common.type';
7
8
 
8
9
  type ChatData = {
9
10
  chatId?: string | undefined;
10
11
  listeners?: Record<EVENT_TYPE, (props: any) => void>;
11
12
  initialMessages?: ChatMessageType[];
13
+ suggestedActions?: SuggestionType[];
12
14
  };
13
15
 
14
16
  const ChatDataContext = createContext<ChatData | undefined>(undefined);
@@ -21,6 +23,7 @@ export const ChatDataProvider = ({
21
23
  data: ChatData;
22
24
  }) => {
23
25
  const [chatData, setChatData] = useState<ChatData>({
26
+ ...data,
24
27
  chatId: data.chatId || generateUUID(),
25
28
  });
26
29
 
@@ -1,17 +1,12 @@
1
1
  import React, { createContext, useEffect, useState } from 'react';
2
- import { EVENT_TYPE } from '../models';
3
2
 
4
3
  type ConfigurationData = {
5
4
  apiHost: string;
6
5
  agentId: string;
7
- overrideConfig?: {
8
- chatId?: string | undefined;
9
- overrideConfig?: Record<string, any>;
10
- } & Record<string, unknown>;
6
+ overrideConfig?: Record<string, any>;
11
7
  theme?: {
12
8
  avatar?: string;
13
9
  } & Record<string, unknown>;
14
- listeners?: Record<EVENT_TYPE, (props: any) => void>;
15
10
  };
16
11
 
17
12
  const ConfigurationContext = createContext<ConfigurationData | undefined>(
package/src/register.tsx CHANGED
@@ -2,13 +2,15 @@ import { agentWidgetElementName } from './constants';
2
2
  import * as ReactDom from 'react-dom';
3
3
  import AgentWidget from './features/AgentWidget';
4
4
  import { EVENT_TYPE } from './models';
5
+ import { SuggestionType } from './types/common.type';
5
6
 
6
- type AgentType = {
7
+ export type AgentWidgetType = {
7
8
  apiHost: string;
8
9
  agentId: string;
9
10
  overrideConfig?: {
10
11
  chatId?: string | undefined;
11
12
  overrideConfig?: Record<string, unknown>;
13
+ suggestedActions?: SuggestionType[];
12
14
  } & Record<string, unknown>;
13
15
  theme?: {
14
16
  avatar?: string;
@@ -22,6 +24,7 @@ export class AgentWidgetComponent extends HTMLElement {
22
24
  overrideConfig?: {
23
25
  chatId?: string | undefined;
24
26
  overrideConfig?: Record<string, unknown>;
27
+ suggestedActions?: SuggestionType[];
25
28
  } & Record<string, unknown>;
26
29
  theme?: {
27
30
  avatar?: string;
@@ -32,7 +35,7 @@ export class AgentWidgetComponent extends HTMLElement {
32
35
  this.updateAttributes = this.updateAttributes.bind(this);
33
36
  }
34
37
 
35
- updateAttributes(attributes: AgentType) {
38
+ updateAttributes(attributes: AgentWidgetType) {
36
39
  this.apiHost = attributes.apiHost;
37
40
  this.agentId = attributes.agentId;
38
41
  this.overrideConfig = attributes.overrideConfig;
@@ -9,3 +9,9 @@ export interface CommonChatType {
9
9
  type: 'PRIVATE' | 'ANONYMOUS';
10
10
  bot: BotType;
11
11
  }
12
+
13
+ export interface SuggestionType {
14
+ title?: string;
15
+ label?: string;
16
+ action?: string;
17
+ }
@@ -11,6 +11,7 @@ export interface PredictionData {
11
11
  leadEmail?: string;
12
12
  action?: IAction;
13
13
  language?: string;
14
+ tts?: boolean;
14
15
  }
15
16
 
16
17
  export interface ChatMessageType {
@@ -32,6 +33,7 @@ export interface ChatMessageType {
32
33
  fileAnnotations?: FileAnnotation[];
33
34
  agentReasoning?: AgentReasoning[];
34
35
  metaData?: ChatMessageMetadataType;
36
+ ttsUrl?: string;
35
37
  }
36
38
 
37
39
  export interface ChatMessageMetadataType {
package/src/window.ts CHANGED
@@ -1,22 +1,9 @@
1
1
  import { agentWidgetElementName } from './constants';
2
- import { registerWebComponents } from './register';
3
- import { EVENT_TYPE } from './models';
2
+ import { AgentWidgetType, registerWebComponents } from './register';
4
3
 
5
4
  let elementUsed: Element | undefined;
6
5
 
7
- type VoiceAgentWidget = {
8
- apiHost: string;
9
- agentId: string;
10
- overrideConfig?: {
11
- chatId?: string | undefined;
12
- overrideConfig?: Record<string, any>;
13
- } & Record<string, unknown>;
14
- theme?: {
15
- avatar?: string;
16
- } & Record<string, unknown>;
17
- listeners?: Record<EVENT_TYPE, (props: any) => void>;
18
- };
19
- export const initWidget = (props: VoiceAgentWidget & { id?: string }) => {
6
+ export const initWidget = (props: AgentWidgetType & { id?: string }) => {
20
7
  destroy();
21
8
  const element: any = props.id
22
9
  ? document.getElementById(props.id)