@memori.ai/memori-react 2.9.2 → 2.10.1
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 +26 -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 +16 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +242 -226
- 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/dist/helpers/utils.d.ts +1 -0
- package/dist/helpers/utils.js +5 -1
- package/dist/helpers/utils.js.map +1 -1
- package/dist/helpers/utils.test.js +12 -0
- package/dist/helpers/utils.test.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 +16 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +243 -227
- 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/esm/helpers/utils.d.ts +1 -0
- package/esm/helpers/utils.js +3 -0
- package/esm/helpers/utils.js.map +1 -1
- package/esm/helpers/utils.test.js +13 -1
- package/esm/helpers/utils.test.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 +353 -292
- package/src/components/StartPanel/StartPanel.tsx +8 -3
- package/src/helpers/utils.test.ts +15 -1
- package/src/helpers/utils.ts +4 -0
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
GamificationLevel,
|
|
14
14
|
Tenant,
|
|
15
15
|
Asset,
|
|
16
|
+
MemoriSession,
|
|
16
17
|
} from '@memori.ai/memori-api-client/src/types';
|
|
17
18
|
import {
|
|
18
19
|
SpeakerAudioDestination,
|
|
@@ -59,7 +60,11 @@ import ChatLayout from '../layouts/Chat';
|
|
|
59
60
|
// Helpers / Utils
|
|
60
61
|
import { getTranslation } from '../../helpers/translations';
|
|
61
62
|
import { setLocalConfig, getLocalConfig } from '../../helpers/configuration';
|
|
62
|
-
import {
|
|
63
|
+
import {
|
|
64
|
+
hasTouchscreen,
|
|
65
|
+
stripDuplicates,
|
|
66
|
+
stripEmojis,
|
|
67
|
+
} from '../../helpers/utils';
|
|
63
68
|
import { anonTag } from '../../helpers/constants';
|
|
64
69
|
import { getErrori18nKey } from '../../helpers/error';
|
|
65
70
|
import { getGamificationLevel } from '../../helpers/statistics';
|
|
@@ -89,55 +94,55 @@ const getMemoriState = (integrationId?: string): object | null => {
|
|
|
89
94
|
return dialogState;
|
|
90
95
|
};
|
|
91
96
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
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 }));
|
|
97
|
+
type MemoriTextEnteredEvent = CustomEvent<{
|
|
98
|
+
text: string;
|
|
99
|
+
waitForPrevious?: boolean;
|
|
100
|
+
hidden?: boolean;
|
|
101
|
+
}>;
|
|
102
|
+
|
|
103
|
+
const typeMessage = (
|
|
104
|
+
message: string,
|
|
105
|
+
waitForPrevious = true,
|
|
106
|
+
hidden = false
|
|
107
|
+
) => {
|
|
108
|
+
const e: MemoriTextEnteredEvent = new CustomEvent('MemoriTextEntered', {
|
|
109
|
+
detail: {
|
|
110
|
+
text: message,
|
|
111
|
+
waitForPrevious,
|
|
112
|
+
hidden,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
121
115
|
|
|
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);
|
|
116
|
+
document.dispatchEvent(e);
|
|
131
117
|
};
|
|
118
|
+
const typeMessageHidden = (message: string, waitForPrevious = true) =>
|
|
119
|
+
typeMessage(message, waitForPrevious, true);
|
|
132
120
|
|
|
121
|
+
interface CustomEventMap {
|
|
122
|
+
MemoriTextEntered: MemoriTextEnteredEvent;
|
|
123
|
+
}
|
|
133
124
|
declare global {
|
|
125
|
+
interface Document {
|
|
126
|
+
addEventListener<K extends keyof CustomEventMap>(
|
|
127
|
+
type: K,
|
|
128
|
+
listener: (this: Document, ev: CustomEventMap[K]) => void
|
|
129
|
+
): void;
|
|
130
|
+
removeEventListener<K extends keyof CustomEventMap>(
|
|
131
|
+
type: K,
|
|
132
|
+
listener: (this: Document, ev: CustomEventMap[K]) => void
|
|
133
|
+
): void;
|
|
134
|
+
dispatchEvent<K extends keyof CustomEventMap>(ev: CustomEventMap[K]): void;
|
|
135
|
+
}
|
|
136
|
+
|
|
134
137
|
interface Window {
|
|
135
138
|
getMemoriState: typeof getMemoriState;
|
|
136
139
|
typeMessage: typeof typeMessage;
|
|
140
|
+
typeMessageHidden: typeof typeMessageHidden;
|
|
137
141
|
}
|
|
138
142
|
}
|
|
139
143
|
window.getMemoriState = getMemoriState;
|
|
140
144
|
window.typeMessage = typeMessage;
|
|
145
|
+
window.typeMessageHidden = typeMessageHidden;
|
|
141
146
|
|
|
142
147
|
// Global variables
|
|
143
148
|
let recognizer: SpeechRecognizer | null;
|
|
@@ -148,6 +153,7 @@ let audioContext: IAudioContext;
|
|
|
148
153
|
|
|
149
154
|
let memoriPassword: string | undefined;
|
|
150
155
|
let speakerMuted: boolean = false;
|
|
156
|
+
let memoriSpeaking: boolean = false;
|
|
151
157
|
|
|
152
158
|
export interface LayoutProps {
|
|
153
159
|
Header?: typeof Header;
|
|
@@ -305,6 +311,7 @@ const MemoriWidget = ({
|
|
|
305
311
|
const [hideEmissions, setHideEmissions] = useState(false);
|
|
306
312
|
useEffect(() => {
|
|
307
313
|
setIsPlayingAudio(!!speechSynthesizer);
|
|
314
|
+
memoriSpeaking = !!speechSynthesizer;
|
|
308
315
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
309
316
|
}, [speechSynthesizer]);
|
|
310
317
|
|
|
@@ -376,258 +383,6 @@ const MemoriWidget = ({
|
|
|
376
383
|
applyPosition(venue);
|
|
377
384
|
};
|
|
378
385
|
|
|
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
386
|
/**
|
|
632
387
|
* Sessione
|
|
633
388
|
*/
|
|
@@ -940,6 +695,264 @@ const MemoriWidget = ({
|
|
|
940
695
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
941
696
|
}, []);
|
|
942
697
|
|
|
698
|
+
/**
|
|
699
|
+
* History e gestione invio messaggi
|
|
700
|
+
*/
|
|
701
|
+
const [userMessage, setUserMessage] = useState<string>('');
|
|
702
|
+
const onChangeUserMessage = (value: string) => {
|
|
703
|
+
if (!value || value === '\n' || value.trim() === '') {
|
|
704
|
+
setUserMessage('');
|
|
705
|
+
resetInteractionTimeout();
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
setUserMessage(value);
|
|
709
|
+
clearInteractionTimeout();
|
|
710
|
+
};
|
|
711
|
+
const [listening, setListening] = useState(false);
|
|
712
|
+
const [history, setHistory] = useState<Message[]>([]);
|
|
713
|
+
const pushMessage = (message: Message) => {
|
|
714
|
+
setHistory(history => [...history, { ...message }]);
|
|
715
|
+
};
|
|
716
|
+
const sendMessage = useCallback(
|
|
717
|
+
async (
|
|
718
|
+
text: string,
|
|
719
|
+
media?: Medium[],
|
|
720
|
+
newSessionId?: string,
|
|
721
|
+
translate: boolean = true,
|
|
722
|
+
translatedText?: string,
|
|
723
|
+
hidden: boolean = false
|
|
724
|
+
) => {
|
|
725
|
+
const sessionID = newSessionId || sessionId;
|
|
726
|
+
if (!sessionID || !text?.length) return;
|
|
727
|
+
|
|
728
|
+
if (!hidden)
|
|
729
|
+
pushMessage({
|
|
730
|
+
text: text,
|
|
731
|
+
translatedText,
|
|
732
|
+
fromUser: true,
|
|
733
|
+
media: media ?? [],
|
|
734
|
+
initial: !!newSessionId,
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
setMemoriTyping(true);
|
|
738
|
+
|
|
739
|
+
const language = memori.culture?.split('-')?.[0] ?? i18n.language ?? 'IT';
|
|
740
|
+
let msg = text;
|
|
741
|
+
|
|
742
|
+
if (
|
|
743
|
+
translate &&
|
|
744
|
+
!instruct &&
|
|
745
|
+
isMultilanguageEnabled &&
|
|
746
|
+
userLang.toUpperCase() !== language.toUpperCase()
|
|
747
|
+
) {
|
|
748
|
+
const translation = await getTranslation(
|
|
749
|
+
text,
|
|
750
|
+
language,
|
|
751
|
+
userLang,
|
|
752
|
+
baseUrl
|
|
753
|
+
);
|
|
754
|
+
msg = translation.text;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
const { currentState, ...response } = await postTextEnteredEvent({
|
|
758
|
+
sessionId: sessionID,
|
|
759
|
+
text: msg,
|
|
760
|
+
});
|
|
761
|
+
if (response.resultCode === 0 && currentState) {
|
|
762
|
+
const emission = currentState.emission ?? currentDialogState?.emission;
|
|
763
|
+
if (currentState.state === 'X4' && memori.giverTag) {
|
|
764
|
+
const { currentState, ...resp } = await postTagChangedEvent(
|
|
765
|
+
sessionID,
|
|
766
|
+
memori.giverTag
|
|
767
|
+
);
|
|
768
|
+
|
|
769
|
+
if (resp.resultCode === 0) {
|
|
770
|
+
setCurrentDialogState(currentState);
|
|
771
|
+
|
|
772
|
+
if (currentState.emission) {
|
|
773
|
+
pushMessage({
|
|
774
|
+
text: currentState.emission,
|
|
775
|
+
media: currentState.media,
|
|
776
|
+
fromUser: false,
|
|
777
|
+
});
|
|
778
|
+
speak(currentState.emission);
|
|
779
|
+
}
|
|
780
|
+
} else {
|
|
781
|
+
console.error(response, resp);
|
|
782
|
+
message.error(t(getErrori18nKey(resp.resultCode)));
|
|
783
|
+
}
|
|
784
|
+
} else if (currentState.state === 'X2d' && memori.giverTag) {
|
|
785
|
+
const { currentState, ...resp } = await postTextEnteredEvent({
|
|
786
|
+
sessionId: sessionID,
|
|
787
|
+
text: Math.random().toString().substring(2, 8),
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
if (resp.resultCode === 0) {
|
|
791
|
+
const { currentState, ...resp } = await postTagChangedEvent(
|
|
792
|
+
sessionID,
|
|
793
|
+
memori.giverTag
|
|
794
|
+
);
|
|
795
|
+
|
|
796
|
+
if (resp.resultCode === 0) {
|
|
797
|
+
setCurrentDialogState(currentState);
|
|
798
|
+
|
|
799
|
+
if (currentState.emission) {
|
|
800
|
+
pushMessage({
|
|
801
|
+
text: currentState.emission,
|
|
802
|
+
media: currentState.media,
|
|
803
|
+
fromUser: false,
|
|
804
|
+
});
|
|
805
|
+
speak(currentState.emission);
|
|
806
|
+
}
|
|
807
|
+
} else {
|
|
808
|
+
console.error(response, resp);
|
|
809
|
+
message.error(t(getErrori18nKey(resp.resultCode)));
|
|
810
|
+
}
|
|
811
|
+
} else {
|
|
812
|
+
console.error(response, resp);
|
|
813
|
+
message.error(t(getErrori18nKey(resp.resultCode)));
|
|
814
|
+
}
|
|
815
|
+
} else if (
|
|
816
|
+
userLang.toLowerCase() !== language.toLowerCase() &&
|
|
817
|
+
emission &&
|
|
818
|
+
!instruct &&
|
|
819
|
+
isMultilanguageEnabled
|
|
820
|
+
) {
|
|
821
|
+
translateDialogState(currentState, userLang).then(ts => {
|
|
822
|
+
if (ts.emission) {
|
|
823
|
+
speak(ts.emission);
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
} else {
|
|
827
|
+
setCurrentDialogState({
|
|
828
|
+
...currentState,
|
|
829
|
+
emission,
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
if (emission) {
|
|
833
|
+
pushMessage({
|
|
834
|
+
text: emission,
|
|
835
|
+
media: currentState.media,
|
|
836
|
+
fromUser: false,
|
|
837
|
+
generatedByAI: !!currentState.completion,
|
|
838
|
+
});
|
|
839
|
+
speak(emission);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
} else if (response.resultCode === 404) {
|
|
843
|
+
// remove last sent message, will set it as initial
|
|
844
|
+
setHistory(h => [...h.slice(0, h.length - 1)]);
|
|
845
|
+
|
|
846
|
+
// post session timeout -> Z0/A0 -> restart session and re-send msg
|
|
847
|
+
reopenSession(
|
|
848
|
+
false,
|
|
849
|
+
memoriPwd || memori.secretToken,
|
|
850
|
+
memoriTokens,
|
|
851
|
+
instruct && memori.giverTag ? memori.giverTag : undefined,
|
|
852
|
+
instruct && memori.giverPIN ? memori.giverPIN : undefined,
|
|
853
|
+
initialContextVars,
|
|
854
|
+
initialQuestion
|
|
855
|
+
).then(state => {
|
|
856
|
+
console.info('session timeout');
|
|
857
|
+
if (state?.sessionID) {
|
|
858
|
+
setTimeout(() => {
|
|
859
|
+
sendMessage(text, media, state?.sessionID);
|
|
860
|
+
}, 500);
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
setMemoriTyping(false);
|
|
866
|
+
},
|
|
867
|
+
[sessionId]
|
|
868
|
+
);
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Traduzioni istantanee
|
|
872
|
+
*/
|
|
873
|
+
const translateDialogState = async (state: DialogState, userLang: string) => {
|
|
874
|
+
const language = memori.culture?.split('-')?.[0] ?? i18n.language ?? 'IT';
|
|
875
|
+
const emission = state.emission ?? currentDialogState?.emission;
|
|
876
|
+
|
|
877
|
+
let translatedState = { ...state };
|
|
878
|
+
let translatedMsg = null;
|
|
879
|
+
|
|
880
|
+
if (
|
|
881
|
+
!emission ||
|
|
882
|
+
instruct ||
|
|
883
|
+
language.toUpperCase() === userLang.toUpperCase() ||
|
|
884
|
+
!isMultilanguageEnabled
|
|
885
|
+
) {
|
|
886
|
+
translatedState = { ...state, emission };
|
|
887
|
+
if (emission) {
|
|
888
|
+
translatedMsg = {
|
|
889
|
+
text: emission,
|
|
890
|
+
media: state.media,
|
|
891
|
+
fromUser: false,
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
} else {
|
|
895
|
+
const t = await getTranslation(emission, userLang, language, baseUrl);
|
|
896
|
+
if (state.hints && state.hints.length > 0) {
|
|
897
|
+
const translatedHints = await Promise.all(
|
|
898
|
+
(state.hints ?? []).map(async hint => {
|
|
899
|
+
const tHint = await getTranslation(
|
|
900
|
+
hint,
|
|
901
|
+
userLang,
|
|
902
|
+
language,
|
|
903
|
+
baseUrl
|
|
904
|
+
);
|
|
905
|
+
return {
|
|
906
|
+
text: tHint?.text ?? hint,
|
|
907
|
+
originalText: hint,
|
|
908
|
+
} as TranslatedHint;
|
|
909
|
+
})
|
|
910
|
+
);
|
|
911
|
+
translatedState = {
|
|
912
|
+
...state,
|
|
913
|
+
emission: t.text,
|
|
914
|
+
translatedHints,
|
|
915
|
+
};
|
|
916
|
+
} else {
|
|
917
|
+
translatedState = {
|
|
918
|
+
...state,
|
|
919
|
+
emission: t.text,
|
|
920
|
+
hints:
|
|
921
|
+
state.hints ??
|
|
922
|
+
(state.state === 'G1' ? currentDialogState?.hints : []),
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
if (t.text.length > 0)
|
|
927
|
+
translatedMsg = {
|
|
928
|
+
text: t.text,
|
|
929
|
+
media: state.media,
|
|
930
|
+
fromUser: false,
|
|
931
|
+
generatedByAI: !!state.completion,
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
setCurrentDialogState(translatedState);
|
|
936
|
+
if (translatedMsg) {
|
|
937
|
+
pushMessage(translatedMsg);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
return translatedState;
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Age verification
|
|
945
|
+
*/
|
|
946
|
+
const minAge = memori.ageRestriction
|
|
947
|
+
? memori.ageRestriction
|
|
948
|
+
: memori.nsfw
|
|
949
|
+
? 18
|
|
950
|
+
: memori.enableCompletions
|
|
951
|
+
? 14
|
|
952
|
+
: 0;
|
|
953
|
+
const [birthDate, setBirthDate] = useState<string | undefined>();
|
|
954
|
+
const [showAgeVerification, setShowAgeVerification] = useState(false);
|
|
955
|
+
|
|
943
956
|
/**
|
|
944
957
|
* Timeout conversazione
|
|
945
958
|
*/
|
|
@@ -1302,6 +1315,8 @@ const MemoriWidget = ({
|
|
|
1302
1315
|
if (preview) return;
|
|
1303
1316
|
|
|
1304
1317
|
if (muteSpeaker || speakerMuted) {
|
|
1318
|
+
memoriSpeaking = false;
|
|
1319
|
+
|
|
1305
1320
|
// trigger start continuous listening if set, see MemoriChat
|
|
1306
1321
|
if (continuousSpeech) {
|
|
1307
1322
|
setListeningTimeout();
|
|
@@ -1337,6 +1352,7 @@ const MemoriWidget = ({
|
|
|
1337
1352
|
|
|
1338
1353
|
if (isPlayingAudio) {
|
|
1339
1354
|
try {
|
|
1355
|
+
memoriSpeaking = false;
|
|
1340
1356
|
if (speechSynthesizer) {
|
|
1341
1357
|
speechSynthesizer.close();
|
|
1342
1358
|
speechSynthesizer = null;
|
|
@@ -1389,9 +1405,11 @@ const MemoriWidget = ({
|
|
|
1389
1405
|
const source = audioContext.createBufferSource();
|
|
1390
1406
|
source.addEventListener('ended', () => {
|
|
1391
1407
|
setIsPlayingAudio(false);
|
|
1408
|
+
memoriSpeaking = false;
|
|
1392
1409
|
});
|
|
1393
1410
|
audioDestination.onAudioEnd = () => {
|
|
1394
1411
|
setIsPlayingAudio(false);
|
|
1412
|
+
memoriSpeaking = false;
|
|
1395
1413
|
source.disconnect();
|
|
1396
1414
|
|
|
1397
1415
|
// trigger start continuous listening if set
|
|
@@ -1403,12 +1421,13 @@ const MemoriWidget = ({
|
|
|
1403
1421
|
`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" xml:lang="${getCultureCodeByLanguage(
|
|
1404
1422
|
userLang
|
|
1405
1423
|
)}"><voice name="${getTTSVoice(userLang)}"><s>${replaceTextWithPhonemes(
|
|
1406
|
-
escapeHTML(text),
|
|
1424
|
+
escapeHTML(stripEmojis(text)),
|
|
1407
1425
|
userLang.toLowerCase()
|
|
1408
1426
|
)}</s></voice></speak>`,
|
|
1409
1427
|
result => {
|
|
1410
1428
|
if (result) {
|
|
1411
1429
|
setIsPlayingAudio(true);
|
|
1430
|
+
memoriSpeaking = true;
|
|
1412
1431
|
|
|
1413
1432
|
try {
|
|
1414
1433
|
// if (audioContext.destination.context.state === 'running') {
|
|
@@ -1430,6 +1449,7 @@ const MemoriWidget = ({
|
|
|
1430
1449
|
) {
|
|
1431
1450
|
source.disconnect();
|
|
1432
1451
|
setIsPlayingAudio(false);
|
|
1452
|
+
memoriSpeaking = false;
|
|
1433
1453
|
} else if ((audioContext.state as string) === 'interrupted') {
|
|
1434
1454
|
audioContext.resume();
|
|
1435
1455
|
}
|
|
@@ -1445,6 +1465,7 @@ const MemoriWidget = ({
|
|
|
1445
1465
|
console.error('speak error: ', e);
|
|
1446
1466
|
window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
|
|
1447
1467
|
setIsPlayingAudio(false);
|
|
1468
|
+
memoriSpeaking = false;
|
|
1448
1469
|
|
|
1449
1470
|
if (speechSynthesizer) {
|
|
1450
1471
|
speechSynthesizer.close();
|
|
@@ -1454,12 +1475,14 @@ const MemoriWidget = ({
|
|
|
1454
1475
|
} else {
|
|
1455
1476
|
audioContext.resume();
|
|
1456
1477
|
setIsPlayingAudio(false);
|
|
1478
|
+
memoriSpeaking = false;
|
|
1457
1479
|
}
|
|
1458
1480
|
},
|
|
1459
1481
|
error => {
|
|
1460
1482
|
console.error('speak:', error);
|
|
1461
1483
|
window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
|
|
1462
1484
|
setIsPlayingAudio(false);
|
|
1485
|
+
memoriSpeaking = false;
|
|
1463
1486
|
}
|
|
1464
1487
|
);
|
|
1465
1488
|
|
|
@@ -1467,6 +1490,7 @@ const MemoriWidget = ({
|
|
|
1467
1490
|
};
|
|
1468
1491
|
const stopAudio = () => {
|
|
1469
1492
|
setIsPlayingAudio(false);
|
|
1493
|
+
memoriSpeaking = false;
|
|
1470
1494
|
try {
|
|
1471
1495
|
if (speechSynthesizer) {
|
|
1472
1496
|
speechSynthesizer.close();
|
|
@@ -1925,6 +1949,43 @@ const MemoriWidget = ({
|
|
|
1925
1949
|
sendMessage(text, undefined, undefined, false, translatedText);
|
|
1926
1950
|
};
|
|
1927
1951
|
|
|
1952
|
+
// listen to events from browser
|
|
1953
|
+
// to use in integrations or snippets
|
|
1954
|
+
const memoriTextEnteredHandler = useCallback(
|
|
1955
|
+
(e: MemoriTextEnteredEvent) => {
|
|
1956
|
+
const { text, waitForPrevious, hidden } = e.detail;
|
|
1957
|
+
|
|
1958
|
+
const sessionID =
|
|
1959
|
+
sessionId || (window.getMemoriState() as MemoriSession)?.sessionID;
|
|
1960
|
+
|
|
1961
|
+
if (text) {
|
|
1962
|
+
// wait to finish reading previous emission
|
|
1963
|
+
if (
|
|
1964
|
+
waitForPrevious &&
|
|
1965
|
+
!speakerMuted &&
|
|
1966
|
+
(memoriSpeaking || memoriTyping)
|
|
1967
|
+
) {
|
|
1968
|
+
setTimeout(() => {
|
|
1969
|
+
memoriTextEnteredHandler(e);
|
|
1970
|
+
}, 1000);
|
|
1971
|
+
} else {
|
|
1972
|
+
sendMessage(text, undefined, sessionID, undefined, undefined, hidden);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
},
|
|
1976
|
+
[sessionId, isPlayingAudio, memoriTyping]
|
|
1977
|
+
);
|
|
1978
|
+
useEffect(() => {
|
|
1979
|
+
document.addEventListener('MemoriTextEntered', memoriTextEnteredHandler);
|
|
1980
|
+
|
|
1981
|
+
return () => {
|
|
1982
|
+
document.removeEventListener(
|
|
1983
|
+
'MemoriTextEntered',
|
|
1984
|
+
memoriTextEnteredHandler
|
|
1985
|
+
);
|
|
1986
|
+
};
|
|
1987
|
+
}, []);
|
|
1988
|
+
|
|
1928
1989
|
const onClickStart = useCallback(
|
|
1929
1990
|
async (session?: { dialogState: DialogState; sessionID: string }) => {
|
|
1930
1991
|
const sessionID = session?.sessionID || sessionId;
|