@memori.ai/memori-react 2.9.2 → 2.10.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.
@@ -65,6 +65,7 @@ import { getErrori18nKey } from '../../helpers/error';
65
65
  import { getGamificationLevel } from '../../helpers/statistics';
66
66
  import AgeVerificationModal from '../AgeVerificationModal/AgeVerificationModal';
67
67
  import SettingsDrawer from '../SettingsDrawer/SettingsDrawer';
68
+ import { MemoriSession } from '@memori.ai/memori-api-client/dist/types';
68
69
 
69
70
  // Widget utilities and helpers
70
71
  const getMemoriState = (integrationId?: string): object | null => {
@@ -89,55 +90,48 @@ const getMemoriState = (integrationId?: string): object | null => {
89
90
  return dialogState;
90
91
  };
91
92
 
92
- function setNativeValue(element: Element, value: string) {
93
- const valueSetter = Object?.getOwnPropertyDescriptor?.(element, 'value')?.set;
94
- const prototype = Object.getPrototypeOf(element);
95
- const prototypeValueSetter = Object?.getOwnPropertyDescriptor?.(
96
- prototype,
97
- 'value'
98
- )?.set;
99
-
100
- if (
101
- prototypeValueSetter &&
102
- valueSetter &&
103
- valueSetter !== prototypeValueSetter
104
- ) {
105
- prototypeValueSetter.call(element, value);
106
- } else if (valueSetter) {
107
- valueSetter.call(element, value);
108
- }
109
- }
93
+ type MemoriTextEnteredEvent = CustomEvent<{
94
+ text: string;
95
+ hidden?: boolean;
96
+ }>;
110
97
 
111
- const typeMessage = (message: string) => {
112
- let textarea =
113
- document.querySelector('fieldset#chat-fieldset textarea') ||
114
- document
115
- .querySelector('memori-client')
116
- ?.shadowRoot?.querySelector('fieldset#chat-fieldset textarea');
117
- if (!textarea) return;
118
-
119
- setNativeValue(textarea, message);
120
- textarea.dispatchEvent(new Event('input', { bubbles: true }));
98
+ const typeMessage = (message: string, hidden = false) => {
99
+ const e: MemoriTextEnteredEvent = new CustomEvent('MemoriTextEntered', {
100
+ detail: {
101
+ text: message,
102
+ hidden,
103
+ },
104
+ });
121
105
 
122
- setTimeout(() => {
123
- let sendButton =
124
- document.querySelector('button.memori-chat-inputs--send') ||
125
- document
126
- .querySelector('memori-client')
127
- ?.shadowRoot?.querySelector('button.memori-chat-inputs--send');
128
- if (!sendButton) return;
129
- (sendButton as HTMLButtonElement).click();
130
- }, 100);
106
+ document.dispatchEvent(e);
131
107
  };
108
+ const typeMessageHidden = (message: string) => typeMessage(message, true);
132
109
 
110
+ interface CustomEventMap {
111
+ MemoriTextEntered: MemoriTextEnteredEvent;
112
+ }
133
113
  declare global {
114
+ interface Document {
115
+ addEventListener<K extends keyof CustomEventMap>(
116
+ type: K,
117
+ listener: (this: Document, ev: CustomEventMap[K]) => void
118
+ ): void;
119
+ removeEventListener<K extends keyof CustomEventMap>(
120
+ type: K,
121
+ listener: (this: Document, ev: CustomEventMap[K]) => void
122
+ ): void;
123
+ dispatchEvent<K extends keyof CustomEventMap>(ev: CustomEventMap[K]): void;
124
+ }
125
+
134
126
  interface Window {
135
127
  getMemoriState: typeof getMemoriState;
136
128
  typeMessage: typeof typeMessage;
129
+ typeMessageHidden: typeof typeMessageHidden;
137
130
  }
138
131
  }
139
132
  window.getMemoriState = getMemoriState;
140
133
  window.typeMessage = typeMessage;
134
+ window.typeMessageHidden = typeMessageHidden;
141
135
 
142
136
  // Global variables
143
137
  let recognizer: SpeechRecognizer | null;
@@ -148,6 +142,7 @@ let audioContext: IAudioContext;
148
142
 
149
143
  let memoriPassword: string | undefined;
150
144
  let speakerMuted: boolean = false;
145
+ let memoriSpeaking: boolean = false;
151
146
 
152
147
  export interface LayoutProps {
153
148
  Header?: typeof Header;
@@ -305,6 +300,7 @@ const MemoriWidget = ({
305
300
  const [hideEmissions, setHideEmissions] = useState(false);
306
301
  useEffect(() => {
307
302
  setIsPlayingAudio(!!speechSynthesizer);
303
+ memoriSpeaking = !!speechSynthesizer;
308
304
  // eslint-disable-next-line react-hooks/exhaustive-deps
309
305
  }, [speechSynthesizer]);
310
306
 
@@ -376,258 +372,6 @@ const MemoriWidget = ({
376
372
  applyPosition(venue);
377
373
  };
378
374
 
379
- /**
380
- * History e gestione invio messaggi
381
- */
382
- const [userMessage, setUserMessage] = useState<string>('');
383
- const onChangeUserMessage = (value: string) => {
384
- if (!value || value === '\n' || value.trim() === '') {
385
- setUserMessage('');
386
- resetInteractionTimeout();
387
- return;
388
- }
389
- setUserMessage(value);
390
- clearInteractionTimeout();
391
- };
392
- const [listening, setListening] = useState(false);
393
- const [history, setHistory] = useState<Message[]>([]);
394
- const pushMessage = (message: Message) => {
395
- setHistory(history => [...history, { ...message }]);
396
- };
397
- const sendMessage = async (
398
- text: string,
399
- media?: Medium[],
400
- newSessionId?: string,
401
- translate: boolean = true,
402
- translatedText?: string
403
- ) => {
404
- if (!sessionId || !text?.length) return;
405
-
406
- pushMessage({
407
- text: text,
408
- translatedText,
409
- fromUser: true,
410
- media: media ?? [],
411
- initial: !!newSessionId,
412
- });
413
-
414
- setMemoriTyping(true);
415
-
416
- const language = memori.culture?.split('-')?.[0] ?? i18n.language ?? 'IT';
417
- let msg = text;
418
-
419
- if (
420
- translate &&
421
- !instruct &&
422
- isMultilanguageEnabled &&
423
- userLang.toUpperCase() !== language.toUpperCase()
424
- ) {
425
- const translation = await getTranslation(
426
- text,
427
- language,
428
- userLang,
429
- baseUrl
430
- );
431
- msg = translation.text;
432
- }
433
-
434
- const { currentState, ...response } = await postTextEnteredEvent({
435
- sessionId: newSessionId ?? sessionId,
436
- text: msg,
437
- });
438
- if (response.resultCode === 0 && currentState) {
439
- const emission = currentState.emission ?? currentDialogState?.emission;
440
- if (currentState.state === 'X4' && memori.giverTag) {
441
- const { currentState, ...resp } = await postTagChangedEvent(
442
- sessionId,
443
- memori.giverTag
444
- );
445
-
446
- if (resp.resultCode === 0) {
447
- setCurrentDialogState(currentState);
448
-
449
- if (currentState.emission) {
450
- pushMessage({
451
- text: currentState.emission,
452
- media: currentState.media,
453
- fromUser: false,
454
- });
455
- speak(currentState.emission);
456
- }
457
- } else {
458
- console.error(response, resp);
459
- message.error(t(getErrori18nKey(resp.resultCode)));
460
- }
461
- } else if (currentState.state === 'X2d' && memori.giverTag) {
462
- const { currentState, ...resp } = await postTextEnteredEvent({
463
- sessionId: newSessionId ?? sessionId,
464
- text: Math.random().toString().substring(2, 8),
465
- });
466
-
467
- if (resp.resultCode === 0) {
468
- const { currentState, ...resp } = await postTagChangedEvent(
469
- sessionId,
470
- memori.giverTag
471
- );
472
-
473
- if (resp.resultCode === 0) {
474
- setCurrentDialogState(currentState);
475
-
476
- if (currentState.emission) {
477
- pushMessage({
478
- text: currentState.emission,
479
- media: currentState.media,
480
- fromUser: false,
481
- });
482
- speak(currentState.emission);
483
- }
484
- } else {
485
- console.error(response, resp);
486
- message.error(t(getErrori18nKey(resp.resultCode)));
487
- }
488
- } else {
489
- console.error(response, resp);
490
- message.error(t(getErrori18nKey(resp.resultCode)));
491
- }
492
- } else if (
493
- userLang.toLowerCase() !== language.toLowerCase() &&
494
- emission &&
495
- !instruct &&
496
- isMultilanguageEnabled
497
- ) {
498
- translateDialogState(currentState, userLang).then(ts => {
499
- if (ts.emission) {
500
- speak(ts.emission);
501
- }
502
- });
503
- } else {
504
- setCurrentDialogState({
505
- ...currentState,
506
- emission,
507
- });
508
-
509
- if (emission) {
510
- pushMessage({
511
- text: emission,
512
- media: currentState.media,
513
- fromUser: false,
514
- generatedByAI: !!currentState.completion,
515
- });
516
- speak(emission);
517
- }
518
- }
519
- } else if (response.resultCode === 404) {
520
- // remove last sent message, will set it as initial
521
- setHistory(h => [...h.slice(0, h.length - 1)]);
522
-
523
- // post session timeout -> Z0/A0 -> restart session and re-send msg
524
- reopenSession(
525
- false,
526
- memoriPwd || memori.secretToken,
527
- memoriTokens,
528
- instruct && memori.giverTag ? memori.giverTag : undefined,
529
- instruct && memori.giverPIN ? memori.giverPIN : undefined,
530
- initialContextVars,
531
- initialQuestion
532
- ).then(state => {
533
- console.info('session timeout');
534
- if (state?.sessionID) {
535
- setTimeout(() => {
536
- sendMessage(text, media, state?.sessionID);
537
- }, 500);
538
- }
539
- });
540
- }
541
-
542
- setMemoriTyping(false);
543
- };
544
-
545
- /**
546
- * Traduzioni istantanee
547
- */
548
- const translateDialogState = async (state: DialogState, userLang: string) => {
549
- const language = memori.culture?.split('-')?.[0] ?? i18n.language ?? 'IT';
550
- const emission = state.emission ?? currentDialogState?.emission;
551
-
552
- let translatedState = { ...state };
553
- let translatedMsg = null;
554
-
555
- if (
556
- !emission ||
557
- instruct ||
558
- language.toUpperCase() === userLang.toUpperCase() ||
559
- !isMultilanguageEnabled
560
- ) {
561
- translatedState = { ...state, emission };
562
- if (emission) {
563
- translatedMsg = {
564
- text: emission,
565
- media: state.media,
566
- fromUser: false,
567
- };
568
- }
569
- } else {
570
- const t = await getTranslation(emission, userLang, language, baseUrl);
571
- if (state.hints && state.hints.length > 0) {
572
- const translatedHints = await Promise.all(
573
- (state.hints ?? []).map(async hint => {
574
- const tHint = await getTranslation(
575
- hint,
576
- userLang,
577
- language,
578
- baseUrl
579
- );
580
- return {
581
- text: tHint?.text ?? hint,
582
- originalText: hint,
583
- } as TranslatedHint;
584
- })
585
- );
586
- translatedState = {
587
- ...state,
588
- emission: t.text,
589
- translatedHints,
590
- };
591
- } else {
592
- translatedState = {
593
- ...state,
594
- emission: t.text,
595
- hints:
596
- state.hints ??
597
- (state.state === 'G1' ? currentDialogState?.hints : []),
598
- };
599
- }
600
-
601
- if (t.text.length > 0)
602
- translatedMsg = {
603
- text: t.text,
604
- media: state.media,
605
- fromUser: false,
606
- generatedByAI: !!state.completion,
607
- };
608
- }
609
-
610
- setCurrentDialogState(translatedState);
611
- if (translatedMsg) {
612
- pushMessage(translatedMsg);
613
- }
614
-
615
- return translatedState;
616
- };
617
-
618
- /**
619
- * Age verification
620
- */
621
- const minAge = memori.ageRestriction
622
- ? memori.ageRestriction
623
- : memori.nsfw
624
- ? 18
625
- : memori.enableCompletions
626
- ? 14
627
- : 0;
628
- const [birthDate, setBirthDate] = useState<string | undefined>();
629
- const [showAgeVerification, setShowAgeVerification] = useState(false);
630
-
631
375
  /**
632
376
  * Sessione
633
377
  */
@@ -940,6 +684,264 @@ const MemoriWidget = ({
940
684
  // eslint-disable-next-line react-hooks/exhaustive-deps
941
685
  }, []);
942
686
 
687
+ /**
688
+ * History e gestione invio messaggi
689
+ */
690
+ const [userMessage, setUserMessage] = useState<string>('');
691
+ const onChangeUserMessage = (value: string) => {
692
+ if (!value || value === '\n' || value.trim() === '') {
693
+ setUserMessage('');
694
+ resetInteractionTimeout();
695
+ return;
696
+ }
697
+ setUserMessage(value);
698
+ clearInteractionTimeout();
699
+ };
700
+ const [listening, setListening] = useState(false);
701
+ const [history, setHistory] = useState<Message[]>([]);
702
+ const pushMessage = (message: Message) => {
703
+ setHistory(history => [...history, { ...message }]);
704
+ };
705
+ const sendMessage = useCallback(
706
+ async (
707
+ text: string,
708
+ media?: Medium[],
709
+ newSessionId?: string,
710
+ translate: boolean = true,
711
+ translatedText?: string,
712
+ hidden: boolean = false
713
+ ) => {
714
+ const sessionID = newSessionId || sessionId;
715
+ if (!sessionID || !text?.length) return;
716
+
717
+ if (!hidden)
718
+ pushMessage({
719
+ text: text,
720
+ translatedText,
721
+ fromUser: true,
722
+ media: media ?? [],
723
+ initial: !!newSessionId,
724
+ });
725
+
726
+ setMemoriTyping(true);
727
+
728
+ const language = memori.culture?.split('-')?.[0] ?? i18n.language ?? 'IT';
729
+ let msg = text;
730
+
731
+ if (
732
+ translate &&
733
+ !instruct &&
734
+ isMultilanguageEnabled &&
735
+ userLang.toUpperCase() !== language.toUpperCase()
736
+ ) {
737
+ const translation = await getTranslation(
738
+ text,
739
+ language,
740
+ userLang,
741
+ baseUrl
742
+ );
743
+ msg = translation.text;
744
+ }
745
+
746
+ const { currentState, ...response } = await postTextEnteredEvent({
747
+ sessionId: sessionID,
748
+ text: msg,
749
+ });
750
+ if (response.resultCode === 0 && currentState) {
751
+ const emission = currentState.emission ?? currentDialogState?.emission;
752
+ if (currentState.state === 'X4' && memori.giverTag) {
753
+ const { currentState, ...resp } = await postTagChangedEvent(
754
+ sessionID,
755
+ memori.giverTag
756
+ );
757
+
758
+ if (resp.resultCode === 0) {
759
+ setCurrentDialogState(currentState);
760
+
761
+ if (currentState.emission) {
762
+ pushMessage({
763
+ text: currentState.emission,
764
+ media: currentState.media,
765
+ fromUser: false,
766
+ });
767
+ speak(currentState.emission);
768
+ }
769
+ } else {
770
+ console.error(response, resp);
771
+ message.error(t(getErrori18nKey(resp.resultCode)));
772
+ }
773
+ } else if (currentState.state === 'X2d' && memori.giverTag) {
774
+ const { currentState, ...resp } = await postTextEnteredEvent({
775
+ sessionId: sessionID,
776
+ text: Math.random().toString().substring(2, 8),
777
+ });
778
+
779
+ if (resp.resultCode === 0) {
780
+ const { currentState, ...resp } = await postTagChangedEvent(
781
+ sessionID,
782
+ memori.giverTag
783
+ );
784
+
785
+ if (resp.resultCode === 0) {
786
+ setCurrentDialogState(currentState);
787
+
788
+ if (currentState.emission) {
789
+ pushMessage({
790
+ text: currentState.emission,
791
+ media: currentState.media,
792
+ fromUser: false,
793
+ });
794
+ speak(currentState.emission);
795
+ }
796
+ } else {
797
+ console.error(response, resp);
798
+ message.error(t(getErrori18nKey(resp.resultCode)));
799
+ }
800
+ } else {
801
+ console.error(response, resp);
802
+ message.error(t(getErrori18nKey(resp.resultCode)));
803
+ }
804
+ } else if (
805
+ userLang.toLowerCase() !== language.toLowerCase() &&
806
+ emission &&
807
+ !instruct &&
808
+ isMultilanguageEnabled
809
+ ) {
810
+ translateDialogState(currentState, userLang).then(ts => {
811
+ if (ts.emission) {
812
+ speak(ts.emission);
813
+ }
814
+ });
815
+ } else {
816
+ setCurrentDialogState({
817
+ ...currentState,
818
+ emission,
819
+ });
820
+
821
+ if (emission) {
822
+ pushMessage({
823
+ text: emission,
824
+ media: currentState.media,
825
+ fromUser: false,
826
+ generatedByAI: !!currentState.completion,
827
+ });
828
+ speak(emission);
829
+ }
830
+ }
831
+ } else if (response.resultCode === 404) {
832
+ // remove last sent message, will set it as initial
833
+ setHistory(h => [...h.slice(0, h.length - 1)]);
834
+
835
+ // post session timeout -> Z0/A0 -> restart session and re-send msg
836
+ reopenSession(
837
+ false,
838
+ memoriPwd || memori.secretToken,
839
+ memoriTokens,
840
+ instruct && memori.giverTag ? memori.giverTag : undefined,
841
+ instruct && memori.giverPIN ? memori.giverPIN : undefined,
842
+ initialContextVars,
843
+ initialQuestion
844
+ ).then(state => {
845
+ console.info('session timeout');
846
+ if (state?.sessionID) {
847
+ setTimeout(() => {
848
+ sendMessage(text, media, state?.sessionID);
849
+ }, 500);
850
+ }
851
+ });
852
+ }
853
+
854
+ setMemoriTyping(false);
855
+ },
856
+ [sessionId]
857
+ );
858
+
859
+ /**
860
+ * Traduzioni istantanee
861
+ */
862
+ const translateDialogState = async (state: DialogState, userLang: string) => {
863
+ const language = memori.culture?.split('-')?.[0] ?? i18n.language ?? 'IT';
864
+ const emission = state.emission ?? currentDialogState?.emission;
865
+
866
+ let translatedState = { ...state };
867
+ let translatedMsg = null;
868
+
869
+ if (
870
+ !emission ||
871
+ instruct ||
872
+ language.toUpperCase() === userLang.toUpperCase() ||
873
+ !isMultilanguageEnabled
874
+ ) {
875
+ translatedState = { ...state, emission };
876
+ if (emission) {
877
+ translatedMsg = {
878
+ text: emission,
879
+ media: state.media,
880
+ fromUser: false,
881
+ };
882
+ }
883
+ } else {
884
+ const t = await getTranslation(emission, userLang, language, baseUrl);
885
+ if (state.hints && state.hints.length > 0) {
886
+ const translatedHints = await Promise.all(
887
+ (state.hints ?? []).map(async hint => {
888
+ const tHint = await getTranslation(
889
+ hint,
890
+ userLang,
891
+ language,
892
+ baseUrl
893
+ );
894
+ return {
895
+ text: tHint?.text ?? hint,
896
+ originalText: hint,
897
+ } as TranslatedHint;
898
+ })
899
+ );
900
+ translatedState = {
901
+ ...state,
902
+ emission: t.text,
903
+ translatedHints,
904
+ };
905
+ } else {
906
+ translatedState = {
907
+ ...state,
908
+ emission: t.text,
909
+ hints:
910
+ state.hints ??
911
+ (state.state === 'G1' ? currentDialogState?.hints : []),
912
+ };
913
+ }
914
+
915
+ if (t.text.length > 0)
916
+ translatedMsg = {
917
+ text: t.text,
918
+ media: state.media,
919
+ fromUser: false,
920
+ generatedByAI: !!state.completion,
921
+ };
922
+ }
923
+
924
+ setCurrentDialogState(translatedState);
925
+ if (translatedMsg) {
926
+ pushMessage(translatedMsg);
927
+ }
928
+
929
+ return translatedState;
930
+ };
931
+
932
+ /**
933
+ * Age verification
934
+ */
935
+ const minAge = memori.ageRestriction
936
+ ? memori.ageRestriction
937
+ : memori.nsfw
938
+ ? 18
939
+ : memori.enableCompletions
940
+ ? 14
941
+ : 0;
942
+ const [birthDate, setBirthDate] = useState<string | undefined>();
943
+ const [showAgeVerification, setShowAgeVerification] = useState(false);
944
+
943
945
  /**
944
946
  * Timeout conversazione
945
947
  */
@@ -1302,6 +1304,8 @@ const MemoriWidget = ({
1302
1304
  if (preview) return;
1303
1305
 
1304
1306
  if (muteSpeaker || speakerMuted) {
1307
+ memoriSpeaking = false;
1308
+
1305
1309
  // trigger start continuous listening if set, see MemoriChat
1306
1310
  if (continuousSpeech) {
1307
1311
  setListeningTimeout();
@@ -1337,6 +1341,7 @@ const MemoriWidget = ({
1337
1341
 
1338
1342
  if (isPlayingAudio) {
1339
1343
  try {
1344
+ memoriSpeaking = false;
1340
1345
  if (speechSynthesizer) {
1341
1346
  speechSynthesizer.close();
1342
1347
  speechSynthesizer = null;
@@ -1389,9 +1394,11 @@ const MemoriWidget = ({
1389
1394
  const source = audioContext.createBufferSource();
1390
1395
  source.addEventListener('ended', () => {
1391
1396
  setIsPlayingAudio(false);
1397
+ memoriSpeaking = false;
1392
1398
  });
1393
1399
  audioDestination.onAudioEnd = () => {
1394
1400
  setIsPlayingAudio(false);
1401
+ memoriSpeaking = false;
1395
1402
  source.disconnect();
1396
1403
 
1397
1404
  // trigger start continuous listening if set
@@ -1409,6 +1416,7 @@ const MemoriWidget = ({
1409
1416
  result => {
1410
1417
  if (result) {
1411
1418
  setIsPlayingAudio(true);
1419
+ memoriSpeaking = true;
1412
1420
 
1413
1421
  try {
1414
1422
  // if (audioContext.destination.context.state === 'running') {
@@ -1430,6 +1438,7 @@ const MemoriWidget = ({
1430
1438
  ) {
1431
1439
  source.disconnect();
1432
1440
  setIsPlayingAudio(false);
1441
+ memoriSpeaking = false;
1433
1442
  } else if ((audioContext.state as string) === 'interrupted') {
1434
1443
  audioContext.resume();
1435
1444
  }
@@ -1445,6 +1454,7 @@ const MemoriWidget = ({
1445
1454
  console.error('speak error: ', e);
1446
1455
  window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
1447
1456
  setIsPlayingAudio(false);
1457
+ memoriSpeaking = false;
1448
1458
 
1449
1459
  if (speechSynthesizer) {
1450
1460
  speechSynthesizer.close();
@@ -1454,12 +1464,14 @@ const MemoriWidget = ({
1454
1464
  } else {
1455
1465
  audioContext.resume();
1456
1466
  setIsPlayingAudio(false);
1467
+ memoriSpeaking = false;
1457
1468
  }
1458
1469
  },
1459
1470
  error => {
1460
1471
  console.error('speak:', error);
1461
1472
  window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
1462
1473
  setIsPlayingAudio(false);
1474
+ memoriSpeaking = false;
1463
1475
  }
1464
1476
  );
1465
1477
 
@@ -1467,6 +1479,7 @@ const MemoriWidget = ({
1467
1479
  };
1468
1480
  const stopAudio = () => {
1469
1481
  setIsPlayingAudio(false);
1482
+ memoriSpeaking = false;
1470
1483
  try {
1471
1484
  if (speechSynthesizer) {
1472
1485
  speechSynthesizer.close();
@@ -1925,6 +1938,39 @@ const MemoriWidget = ({
1925
1938
  sendMessage(text, undefined, undefined, false, translatedText);
1926
1939
  };
1927
1940
 
1941
+ // listen to events from browser
1942
+ // to use in integrations or snippets
1943
+ const memoriTextEnteredHandler = useCallback(
1944
+ (e: MemoriTextEnteredEvent) => {
1945
+ const { text, hidden } = e.detail;
1946
+
1947
+ const sessionID =
1948
+ sessionId || (window.getMemoriState() as MemoriSession)?.sessionID;
1949
+
1950
+ if (text) {
1951
+ // wait to finish reading previous emission
1952
+ if (!speakerMuted && (memoriSpeaking || memoriTyping)) {
1953
+ setTimeout(() => {
1954
+ memoriTextEnteredHandler(e);
1955
+ }, 1000);
1956
+ } else {
1957
+ sendMessage(text, undefined, sessionID, undefined, undefined, hidden);
1958
+ }
1959
+ }
1960
+ },
1961
+ [sessionId, isPlayingAudio, memoriTyping]
1962
+ );
1963
+ useEffect(() => {
1964
+ document.addEventListener('MemoriTextEntered', memoriTextEnteredHandler);
1965
+
1966
+ return () => {
1967
+ document.removeEventListener(
1968
+ 'MemoriTextEntered',
1969
+ memoriTextEnteredHandler
1970
+ );
1971
+ };
1972
+ }, []);
1973
+
1928
1974
  const onClickStart = useCallback(
1929
1975
  async (session?: { dialogState: DialogState; sessionID: string }) => {
1930
1976
  const sessionID = session?.sessionID || sessionId;