@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.
- package/CHANGELOG.md +14 -0
- package/dist/components/ChatBubble/ChatBubble.js +31 -31
- package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.d.ts +15 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +238 -225
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/StartPanel/StartPanel.js +6 -1
- package/dist/components/StartPanel/StartPanel.js.map +1 -1
- package/esm/components/ChatBubble/ChatBubble.js +31 -31
- package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.d.ts +15 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +238 -225
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/StartPanel/StartPanel.js +6 -1
- package/esm/components/StartPanel/StartPanel.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ChatBubble/ChatBubble.tsx +1 -1
- package/src/components/ChatBubble/__snapshots__/ChatBubble.test.tsx.snap +0 -3
- package/src/components/MemoriWidget/MemoriWidget.tsx +335 -289
- package/src/components/StartPanel/StartPanel.tsx +8 -3
|
@@ -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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
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;
|