@memori.ai/memori-react 7.5.1 → 7.6.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.
Files changed (218) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +10 -2
  3. package/dist/components/Avatar/Avatar.d.ts +2 -0
  4. package/dist/components/Avatar/Avatar.js +11 -6
  5. package/dist/components/Avatar/Avatar.js.map +1 -1
  6. package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +20 -0
  7. package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +107 -0
  8. package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -0
  9. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controls.d.ts +26 -0
  10. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controls.js +59 -0
  11. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controls.js.map +1 -0
  12. package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +30 -0
  13. package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +148 -0
  14. package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -0
  15. package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +15 -0
  16. package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +77 -0
  17. package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -0
  18. package/dist/components/Avatar/AvatarView/AvatarComponent/components/loader.d.ts +5 -0
  19. package/dist/components/Avatar/AvatarView/AvatarComponent/components/loader.js +12 -0
  20. package/dist/components/Avatar/AvatarView/AvatarComponent/components/loader.js.map +1 -0
  21. package/dist/components/Avatar/AvatarView/components/avatar.d.ts +9 -0
  22. package/dist/components/Avatar/AvatarView/components/avatar.js +39 -0
  23. package/dist/components/Avatar/AvatarView/components/avatar.js.map +1 -0
  24. package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.d.ts +2 -1
  25. package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.js +8 -9
  26. package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.js.map +1 -1
  27. package/dist/components/Avatar/AvatarView/index.d.ts +6 -1
  28. package/dist/components/Avatar/AvatarView/index.js +14 -84
  29. package/dist/components/Avatar/AvatarView/index.js.map +1 -1
  30. package/dist/components/Avatar/AvatarView/utils/useEyeBlink.d.ts +16 -2
  31. package/dist/components/Avatar/AvatarView/utils/useEyeBlink.js +62 -38
  32. package/dist/components/Avatar/AvatarView/utils/useEyeBlink.js.map +1 -1
  33. package/dist/components/Avatar/AvatarView/utils/useMouthAnimation.d.ts +16 -0
  34. package/dist/components/Avatar/AvatarView/utils/useMouthAnimation.js +59 -0
  35. package/dist/components/Avatar/AvatarView/utils/useMouthAnimation.js.map +1 -0
  36. package/dist/components/Avatar/AvatarView/utils/useMouthSpeaking.js +1 -1
  37. package/dist/components/Avatar/AvatarView/utils/useMouthSpeaking.js.map +1 -1
  38. package/dist/components/Avatar/AvatarView/utils/useSmile.js +1 -1
  39. package/dist/components/Avatar/AvatarView/utils/useSmile.js.map +1 -1
  40. package/dist/components/Avatar/AvatarView/utils/useViseme.d.ts +18 -0
  41. package/dist/components/Avatar/AvatarView/utils/useViseme.js +141 -0
  42. package/dist/components/Avatar/AvatarView/utils/useViseme.js.map +1 -0
  43. package/dist/components/Avatar/AvatarView/utils/visemeContext.d.ts +24 -0
  44. package/dist/components/Avatar/AvatarView/utils/visemeContext.js +157 -0
  45. package/dist/components/Avatar/AvatarView/utils/visemeContext.js.map +1 -0
  46. package/dist/components/ChatBubble/ChatBubble.js +2 -3
  47. package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
  48. package/dist/components/CompletionProviderStatus/CompletionProviderStatus.d.ts +1 -1
  49. package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js +24 -3
  50. package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
  51. package/dist/components/MemoriWidget/MemoriWidget.d.ts +1 -1
  52. package/dist/components/MemoriWidget/MemoriWidget.js +25 -3
  53. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  54. package/dist/components/MemoriWidget/enhanceSSML/enhanceSSML.d.ts +4 -0
  55. package/dist/components/MemoriWidget/enhanceSSML/enhanceSSML.js +157 -0
  56. package/dist/components/MemoriWidget/enhanceSSML/enhanceSSML.js.map +1 -0
  57. package/dist/components/StartPanel/StartPanel.js +1 -1
  58. package/dist/components/StartPanel/StartPanel.js.map +1 -1
  59. package/dist/components/layouts/HiddenChat.d.ts +4 -0
  60. package/dist/components/layouts/HiddenChat.js +50 -0
  61. package/dist/components/layouts/HiddenChat.js.map +1 -0
  62. package/dist/components/layouts/ZoomedFullBody.d.ts +4 -0
  63. package/dist/components/layouts/ZoomedFullBody.js +8 -0
  64. package/dist/components/layouts/ZoomedFullBody.js.map +1 -0
  65. package/dist/components/layouts/ZoomedHalfBody.d.ts +4 -0
  66. package/dist/components/layouts/ZoomedHalfBody.js +8 -0
  67. package/dist/components/layouts/ZoomedHalfBody.js.map +1 -0
  68. package/dist/components/layouts/hidden-chat.css +184 -0
  69. package/dist/components/layouts/zoomed-half-body.css +3 -0
  70. package/dist/context/visemeContext.d.ts +27 -0
  71. package/dist/context/visemeContext.js +221 -0
  72. package/dist/context/visemeContext.js.map +1 -0
  73. package/dist/helpers/utils.d.ts +7 -0
  74. package/dist/helpers/utils.js +51 -1
  75. package/dist/helpers/utils.js.map +1 -1
  76. package/dist/index.js +20 -16
  77. package/dist/index.js.map +1 -1
  78. package/dist/styles.css +1 -0
  79. package/esm/components/Avatar/Avatar.d.ts +2 -0
  80. package/esm/components/Avatar/Avatar.js +11 -6
  81. package/esm/components/Avatar/Avatar.js.map +1 -1
  82. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +20 -0
  83. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +102 -0
  84. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -0
  85. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.d.ts +26 -0
  86. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.js +56 -0
  87. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.js.map +1 -0
  88. package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +30 -0
  89. package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +145 -0
  90. package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -0
  91. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +15 -0
  92. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +73 -0
  93. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -0
  94. package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.d.ts +5 -0
  95. package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.js +9 -0
  96. package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.js.map +1 -0
  97. package/esm/components/Avatar/AvatarView/components/avatar.d.ts +9 -0
  98. package/esm/components/Avatar/AvatarView/components/avatar.js +35 -0
  99. package/esm/components/Avatar/AvatarView/components/avatar.js.map +1 -0
  100. package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.d.ts +2 -1
  101. package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.js +8 -9
  102. package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.js.map +1 -1
  103. package/esm/components/Avatar/AvatarView/index.d.ts +6 -1
  104. package/esm/components/Avatar/AvatarView/index.js +15 -85
  105. package/esm/components/Avatar/AvatarView/index.js.map +1 -1
  106. package/esm/components/Avatar/AvatarView/utils/useEyeBlink.d.ts +16 -2
  107. package/esm/components/Avatar/AvatarView/utils/useEyeBlink.js +61 -38
  108. package/esm/components/Avatar/AvatarView/utils/useEyeBlink.js.map +1 -1
  109. package/esm/components/Avatar/AvatarView/utils/useMouthAnimation.d.ts +16 -0
  110. package/esm/components/Avatar/AvatarView/utils/useMouthAnimation.js +55 -0
  111. package/esm/components/Avatar/AvatarView/utils/useMouthAnimation.js.map +1 -0
  112. package/esm/components/Avatar/AvatarView/utils/useMouthSpeaking.js +1 -1
  113. package/esm/components/Avatar/AvatarView/utils/useMouthSpeaking.js.map +1 -1
  114. package/esm/components/Avatar/AvatarView/utils/useSmile.js +1 -1
  115. package/esm/components/Avatar/AvatarView/utils/useSmile.js.map +1 -1
  116. package/esm/components/Avatar/AvatarView/utils/useViseme.d.ts +18 -0
  117. package/esm/components/Avatar/AvatarView/utils/useViseme.js +137 -0
  118. package/esm/components/Avatar/AvatarView/utils/useViseme.js.map +1 -0
  119. package/esm/components/Avatar/AvatarView/utils/visemeContext.d.ts +24 -0
  120. package/esm/components/Avatar/AvatarView/utils/visemeContext.js +152 -0
  121. package/esm/components/Avatar/AvatarView/utils/visemeContext.js.map +1 -0
  122. package/esm/components/ChatBubble/ChatBubble.js +2 -3
  123. package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
  124. package/esm/components/CompletionProviderStatus/CompletionProviderStatus.d.ts +1 -1
  125. package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js +24 -3
  126. package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
  127. package/esm/components/MemoriWidget/MemoriWidget.d.ts +1 -1
  128. package/esm/components/MemoriWidget/MemoriWidget.js +26 -4
  129. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  130. package/esm/components/MemoriWidget/enhanceSSML/enhanceSSML.d.ts +4 -0
  131. package/esm/components/MemoriWidget/enhanceSSML/enhanceSSML.js +152 -0
  132. package/esm/components/MemoriWidget/enhanceSSML/enhanceSSML.js.map +1 -0
  133. package/esm/components/StartPanel/StartPanel.js +1 -1
  134. package/esm/components/StartPanel/StartPanel.js.map +1 -1
  135. package/esm/components/layouts/HiddenChat.d.ts +4 -0
  136. package/esm/components/layouts/HiddenChat.js +47 -0
  137. package/esm/components/layouts/HiddenChat.js.map +1 -0
  138. package/esm/components/layouts/ZoomedFullBody.d.ts +4 -0
  139. package/esm/components/layouts/ZoomedFullBody.js +5 -0
  140. package/esm/components/layouts/ZoomedFullBody.js.map +1 -0
  141. package/esm/components/layouts/ZoomedHalfBody.d.ts +4 -0
  142. package/esm/components/layouts/ZoomedHalfBody.js +5 -0
  143. package/esm/components/layouts/ZoomedHalfBody.js.map +1 -0
  144. package/esm/components/layouts/hidden-chat.css +184 -0
  145. package/esm/components/layouts/zoomed-half-body.css +3 -0
  146. package/esm/context/visemeContext.d.ts +27 -0
  147. package/esm/context/visemeContext.js +216 -0
  148. package/esm/context/visemeContext.js.map +1 -0
  149. package/esm/helpers/utils.d.ts +7 -0
  150. package/esm/helpers/utils.js +45 -0
  151. package/esm/helpers/utils.js.map +1 -1
  152. package/esm/index.js +20 -16
  153. package/esm/index.js.map +1 -1
  154. package/esm/styles.css +1 -0
  155. package/package.json +2 -2
  156. package/src/components/Avatar/Avatar.test.tsx +28 -20
  157. package/src/components/Avatar/Avatar.tsx +19 -5
  158. package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +222 -0
  159. package/src/components/Avatar/AvatarView/{components → AvatarComponent/components}/controls.tsx +16 -10
  160. package/src/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.tsx +234 -0
  161. package/src/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.tsx +123 -0
  162. package/src/components/Avatar/AvatarView/{components → AvatarComponent/components}/loader.tsx +1 -1
  163. package/src/components/Avatar/AvatarView/AvatarView.stories.tsx +47 -8
  164. package/src/components/Avatar/AvatarView/index.tsx +35 -167
  165. package/src/components/Avatar/AvatarView/utils/useEyeBlink.ts +89 -48
  166. package/src/components/Avatar/AvatarView/utils/useMouthAnimation.ts +93 -0
  167. package/src/components/Avatar/AvatarView/utils/useSmile.ts +1 -1
  168. package/src/components/ChatBubble/ChatBubble.tsx +3 -4
  169. package/src/components/CompletionProviderStatus/CompletionProviderStatus.tsx +33 -3
  170. package/src/components/CompletionProviderStatus/__snapshots__/CompletionProviderStatus.test.tsx.snap +18 -0
  171. package/src/components/MemoriWidget/MemoriWidget.tsx +60 -5
  172. package/src/components/StartPanel/StartPanel.tsx +1 -1
  173. package/src/components/layouts/Chat.test.tsx +7 -5
  174. package/src/components/layouts/FullPage.test.tsx +11 -8
  175. package/src/components/layouts/HiddenChat.test.tsx +37 -0
  176. package/src/components/layouts/HiddenChat.tsx +107 -0
  177. package/src/components/layouts/Totem.test.tsx +6 -4
  178. package/src/components/layouts/WebsiteAssistant.test.tsx +7 -5
  179. package/src/components/layouts/ZoomedFullBody.test.tsx +37 -0
  180. package/src/components/layouts/ZoomedFullBody.tsx +55 -0
  181. package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +210 -0
  182. package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +444 -0
  183. package/src/components/layouts/hidden-chat.css +184 -0
  184. package/src/components/layouts/layouts.stories.tsx +135 -19
  185. package/src/context/visemeContext.tsx +328 -0
  186. package/src/helpers/utils.ts +73 -0
  187. package/src/index.stories.tsx +40 -17
  188. package/src/index.tsx +82 -78
  189. package/src/styles.css +1 -0
  190. package/dist/components/AttachmentMediaModal/AttachmentMediaModal.d.ts +0 -14
  191. package/dist/components/AttachmentMediaModal/AttachmentMediaModal.js +0 -66
  192. package/dist/components/AttachmentMediaModal/AttachmentMediaModal.js.map +0 -1
  193. package/dist/components/ImageUpload/ImageUpload.css +0 -168
  194. package/dist/components/ImageUpload/ImageUpload.d.ts +0 -28
  195. package/dist/components/ImageUpload/ImageUpload.js +0 -163
  196. package/dist/components/ImageUpload/ImageUpload.js.map +0 -1
  197. package/dist/components/layouts/Default.d.ts +0 -17
  198. package/dist/components/layouts/Default.js +0 -8
  199. package/dist/components/layouts/Default.js.map +0 -1
  200. package/dist/components/ui/Message.d.ts +0 -17
  201. package/dist/components/ui/Message.js +0 -13
  202. package/dist/components/ui/Message.js.map +0 -1
  203. package/esm/components/AttachmentMediaModal/AttachmentMediaModal.d.ts +0 -14
  204. package/esm/components/AttachmentMediaModal/AttachmentMediaModal.js +0 -63
  205. package/esm/components/AttachmentMediaModal/AttachmentMediaModal.js.map +0 -1
  206. package/esm/components/ImageUpload/ImageUpload.css +0 -168
  207. package/esm/components/ImageUpload/ImageUpload.d.ts +0 -28
  208. package/esm/components/ImageUpload/ImageUpload.js +0 -160
  209. package/esm/components/ImageUpload/ImageUpload.js.map +0 -1
  210. package/esm/components/layouts/Default.d.ts +0 -17
  211. package/esm/components/layouts/Default.js +0 -5
  212. package/esm/components/layouts/Default.js.map +0 -1
  213. package/esm/components/ui/Message.d.ts +0 -17
  214. package/esm/components/ui/Message.js +0 -10
  215. package/esm/components/ui/Message.js.map +0 -1
  216. package/src/components/Avatar/AvatarView/components/fullbodyAvatar.tsx +0 -120
  217. package/src/components/Avatar/AvatarView/components/halfbodyAvatar.tsx +0 -69
  218. package/src/components/Avatar/AvatarView/utils/useMouthSpeaking.ts +0 -87
@@ -73,10 +73,14 @@ import {
73
73
  escapeHTML,
74
74
  stripMarkdown,
75
75
  stripOutputTags,
76
+ stripHTML,
76
77
  } from '../../helpers/utils';
77
78
  import { anonTag, uiLanguages } from '../../helpers/constants';
78
79
  import { getErrori18nKey } from '../../helpers/error';
79
80
  import { getCredits } from '../../helpers/credits';
81
+ import HiddenChatLayout from '../layouts/HiddenChat';
82
+ import ZoomedFullBodyLayout from '../layouts/ZoomedFullBody';
83
+ import { useViseme } from '../../context/visemeContext';
80
84
 
81
85
  // Widget utilities and helpers
82
86
  const getMemoriState = (integrationId?: string): object | null => {
@@ -333,7 +337,14 @@ export interface Props {
333
337
  memoriLang?: string;
334
338
  multilingual?: boolean;
335
339
  integration?: Integration;
336
- layout?: 'DEFAULT' | 'FULLPAGE' | 'TOTEM' | 'CHAT' | 'WEBSITE_ASSISTANT';
340
+ layout?:
341
+ | 'DEFAULT'
342
+ | 'FULLPAGE'
343
+ | 'TOTEM'
344
+ | 'CHAT'
345
+ | 'WEBSITE_ASSISTANT'
346
+ | 'HIDDEN_CHAT'
347
+ | 'ZOOMED_FULL_BODY';
337
348
  customLayout?: React.FC<LayoutProps>;
338
349
  showShare?: boolean;
339
350
  showCopyButton?: boolean;
@@ -494,7 +505,11 @@ const MemoriWidget = ({
494
505
  * Sets the language in the i18n instance
495
506
  */
496
507
  useEffect(() => {
497
- if (userLang && uiLanguages.includes(userLang.toLowerCase())) {
508
+ if (
509
+ isMultilanguageEnabled &&
510
+ userLang &&
511
+ uiLanguages.includes(userLang.toLowerCase())
512
+ ) {
498
513
  // @ts-ignore
499
514
  i18n.changeLanguage(userLang.toLowerCase());
500
515
  }
@@ -526,6 +541,15 @@ const MemoriWidget = ({
526
541
  'center'
527
542
  );
528
543
  const [hideEmissions, setHideEmissions] = useState(false);
544
+
545
+ const {
546
+ addVisemeToQueue,
547
+ processVisemeQueue,
548
+ clearVisemes,
549
+ emotion,
550
+ getAzureStyleForEmotion,
551
+ } = useViseme();
552
+
529
553
  useEffect(() => {
530
554
  setIsPlayingAudio(!!speechSynthesizer);
531
555
  memoriSpeaking = !!speechSynthesizer;
@@ -1602,6 +1626,7 @@ const MemoriWidget = ({
1602
1626
  speechConfig.speechSynthesisLanguage = getCultureCodeByLanguage(userLang);
1603
1627
  speechConfig.speechSynthesisVoiceName = getTTSVoice(userLang); // https://docs.microsoft.com/it-it/azure/cognitive-services/speech-service/language-support#text-to-speech
1604
1628
  speechConfig.speechRecognitionLanguage = getCultureCodeByLanguage(userLang);
1629
+ speechConfig.setProperty('speechSynthesis.outputFormat', 'viseme');
1605
1630
 
1606
1631
  if (hasTouchscreen())
1607
1632
  speechConfig.speechSynthesisOutputFormat =
@@ -1936,19 +1961,42 @@ const MemoriWidget = ({
1936
1961
  onEndSpeakStartListen();
1937
1962
  };
1938
1963
 
1964
+ // Clear any existing visemes before starting new speech
1965
+ clearVisemes();
1966
+
1967
+ // Set up the viseme event handler
1968
+ speechSynthesizer.visemeReceived = function (_, e) {
1969
+ addVisemeToQueue({
1970
+ visemeId: e.visemeId,
1971
+ audioOffset: e.audioOffset,
1972
+ });
1973
+ };
1974
+
1975
+ const textToSpeak = escapeHTML(
1976
+ stripMarkdown(stripEmojis(stripHTML(stripOutputTags(text))))
1977
+ );
1978
+
1939
1979
  speechSynthesizer.speakSsmlAsync(
1940
1980
  `<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(
1941
1981
  userLang
1942
- )}"><voice name="${getTTSVoice(userLang)}"><s>${replaceTextWithPhonemes(
1943
- escapeHTML(stripMarkdown(stripEmojis(stripOutputTags(text)))),
1982
+ )}"><voice name="${getTTSVoice(
1983
+ userLang
1984
+ )}"><mstts:express-as style="${getAzureStyleForEmotion(
1985
+ emotion
1986
+ )}"><s>${replaceTextWithPhonemes(
1987
+ textToSpeak,
1944
1988
  userLang.toLowerCase()
1945
- )}</s></voice></speak>`,
1989
+ )}</s></mstts:express-as></voice></speak>`,
1946
1990
  result => {
1947
1991
  if (result) {
1948
1992
  setIsPlayingAudio(true);
1949
1993
  memoriSpeaking = true;
1950
1994
 
1995
+ // Process the viseme data
1996
+ processVisemeQueue();
1997
+
1951
1998
  try {
1999
+ // Decode the audio data
1952
2000
  audioContext.decodeAudioData(result.audioData, function (buffer) {
1953
2001
  source.buffer = buffer;
1954
2002
  source.connect(audioContext.destination);
@@ -1958,6 +2006,7 @@ const MemoriWidget = ({
1958
2006
  }
1959
2007
  });
1960
2008
 
2009
+ // Handle the audio context state changes
1961
2010
  audioContext.onstatechange = () => {
1962
2011
  if (
1963
2012
  audioContext.state === 'suspended' ||
@@ -1980,6 +2029,7 @@ const MemoriWidget = ({
1980
2029
  } catch (e) {
1981
2030
  console.warn('speak error: ', e);
1982
2031
  window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
2032
+ clearVisemes();
1983
2033
  setIsPlayingAudio(false);
1984
2034
  memoriSpeaking = false;
1985
2035
 
@@ -1991,6 +2041,7 @@ const MemoriWidget = ({
1991
2041
  }
1992
2042
  } else {
1993
2043
  audioContext.resume();
2044
+ clearVisemes();
1994
2045
  setIsPlayingAudio(false);
1995
2046
  memoriSpeaking = false;
1996
2047
  emitEndSpeakEvent();
@@ -3134,6 +3185,10 @@ const MemoriWidget = ({
3134
3185
  ? FullPageLayout
3135
3186
  : selectedLayout === 'WEBSITE_ASSISTANT'
3136
3187
  ? WebsiteAssistantLayout
3188
+ : selectedLayout === 'HIDDEN_CHAT'
3189
+ ? HiddenChatLayout
3190
+ : selectedLayout === 'ZOOMED_FULL_BODY'
3191
+ ? ZoomedFullBodyLayout
3137
3192
  : FullPageLayout;
3138
3193
 
3139
3194
  return (
@@ -269,7 +269,7 @@ const StartPanel: React.FC<Props> = ({
269
269
  </Button>
270
270
 
271
271
  <CompletionProviderStatus
272
- provider={memori.completionConfigForQuestionAnswering?.provider}
272
+ provider={memori?.completionConfigForQuestionAnswering?.provider}
273
273
  forceStatus={_TEST_forceProviderStatus}
274
274
  />
275
275
 
@@ -2,7 +2,7 @@ import { render } from '@testing-library/react';
2
2
  import Memori from '../MemoriWidget/MemoriWidget';
3
3
  import { integration, memori, tenant } from '../../mocks/data';
4
4
  import I18nWrapper from '../../I18nWrapper';
5
-
5
+ import { VisemeProvider } from '../../context/visemeContext';
6
6
  Object.defineProperty(window, 'matchMedia', {
7
7
  writable: true,
8
8
  value: jest.fn().mockImplementation(query => ({
@@ -20,15 +20,17 @@ Object.defineProperty(window, 'matchMedia', {
20
20
  it('renders Chat layout unchanged', () => {
21
21
  const { container } = render(
22
22
  <I18nWrapper>
23
- <Memori
24
- showShare={true}
23
+ <VisemeProvider>
24
+ <Memori
25
+ showShare={true}
25
26
  showSettings={true}
26
27
  memori={memori}
27
28
  tenant={tenant}
28
29
  tenantID="aisuru.com"
29
30
  integration={integration}
30
- layout="CHAT"
31
- />
31
+ layout="CHAT"
32
+ />
33
+ </VisemeProvider>
32
34
  </I18nWrapper>
33
35
  );
34
36
  expect(container).toMatchSnapshot();
@@ -2,6 +2,7 @@ import { render } from '@testing-library/react';
2
2
  import Memori from '../MemoriWidget/MemoriWidget';
3
3
  import { integration, memori, tenant } from '../../mocks/data';
4
4
  import I18nWrapper from '../../I18nWrapper';
5
+ import { VisemeProvider } from '../../context/visemeContext';
5
6
 
6
7
  Object.defineProperty(window, 'matchMedia', {
7
8
  writable: true,
@@ -20,15 +21,17 @@ Object.defineProperty(window, 'matchMedia', {
20
21
  it('renders FullPage layout unchanged', () => {
21
22
  const { container } = render(
22
23
  <I18nWrapper>
23
- <Memori
24
- showShare={true}
25
- showSettings={true}
26
- memori={memori}
27
- tenant={tenant}
28
- tenantID="aisuru.com"
29
- integration={integration}
24
+ <VisemeProvider>
25
+ <Memori
26
+ showShare={true}
27
+ showSettings={true}
28
+ memori={memori}
29
+ tenant={tenant}
30
+ tenantID="aisuru.com"
31
+ integration={integration}
30
32
  layout="FULLPAGE"
31
- />
33
+ />
34
+ </VisemeProvider>
32
35
  </I18nWrapper>
33
36
  );
34
37
  expect(container).toMatchSnapshot();
@@ -0,0 +1,37 @@
1
+ import { render } from '@testing-library/react';
2
+ import Memori from '../MemoriWidget/MemoriWidget';
3
+ import { integration, memori, tenant } from '../../mocks/data';
4
+ import I18nWrapper from '../../I18nWrapper';
5
+ import { VisemeProvider } from '../../context/visemeContext';
6
+ Object.defineProperty(window, 'matchMedia', {
7
+ writable: true,
8
+ value: jest.fn().mockImplementation(query => ({
9
+ matches: false,
10
+ media: query,
11
+ onchange: null,
12
+ addListener: jest.fn(), // Deprecated
13
+ removeListener: jest.fn(), // Deprecated
14
+ addEventListener: jest.fn(),
15
+ removeEventListener: jest.fn(),
16
+ dispatchEvent: jest.fn(),
17
+ })),
18
+ });
19
+
20
+ it('renders HIDDEN_CHAT layout unchanged', () => {
21
+ const { container } = render(
22
+ <I18nWrapper>
23
+ <VisemeProvider>
24
+ <Memori
25
+ showShare={true}
26
+ showSettings={true}
27
+ memori={memori}
28
+ tenant={tenant}
29
+ tenantID="aisuru.com"
30
+ integration={integration}
31
+ layout="HIDDEN_CHAT"
32
+ />
33
+ </VisemeProvider>
34
+ </I18nWrapper>
35
+ );
36
+ expect(container).toMatchSnapshot();
37
+ });
@@ -0,0 +1,107 @@
1
+ import React, { useState, useMemo, useEffect } from 'react';
2
+ import Spin from '../ui/Spin';
3
+ import { LayoutProps } from '../MemoriWidget/MemoriWidget';
4
+ import { useTranslation } from 'react-i18next';
5
+ import QuestionHelp from '../icons/QuestionHelp';
6
+ import Close from '../icons/Close';
7
+
8
+ const HiddenChatLayout: React.FC<LayoutProps> = ({
9
+ Header,
10
+ headerProps,
11
+ Chat,
12
+ chatProps,
13
+ startPanelProps,
14
+ sessionId,
15
+ hasUserActivatedSpeak,
16
+ }) => {
17
+ const { t } = useTranslation();
18
+ const [isOpen, setIsOpen] = useState(false);
19
+
20
+ const initChat = () => {
21
+ try {
22
+ window.speechSynthesis.speak(new SpeechSynthesisUtterance(''));
23
+ } catch (e) {
24
+ console.error(e);
25
+ }
26
+ if (startPanelProps && startPanelProps?.initializeTTS)
27
+ startPanelProps?.initializeTTS();
28
+ if (startPanelProps && startPanelProps?.onClickStart)
29
+ startPanelProps?.onClickStart();
30
+ };
31
+
32
+ useEffect(() => {
33
+ const mainDiv = document.body;
34
+ if (mainDiv) {
35
+ if (isOpen) {
36
+ mainDiv.style.width = 'calc(100% - 350px)';
37
+ mainDiv.style.marginRight = '300px';
38
+ mainDiv.style.transition = 'all 0.5s';
39
+ } else {
40
+ mainDiv.style.width = '100%';
41
+ mainDiv.style.marginLeft = '0';
42
+ }
43
+ }
44
+ }, [isOpen]);
45
+
46
+ const handleSidebarToggle = () => {
47
+ setIsOpen(!isOpen);
48
+ initChat();
49
+ };
50
+
51
+ return (
52
+ <>
53
+ <input
54
+ type="checkbox"
55
+ id="memori-sidebar-toggle"
56
+ className="memori-sidebar-toggle"
57
+ checked={isOpen}
58
+ onChange={handleSidebarToggle}
59
+ />
60
+ <div className="memori-sidebar-container">
61
+ <label
62
+ htmlFor="memori-sidebar-toggle"
63
+ className="memori-sidebar-toggle-label memori-open-label"
64
+ >
65
+ <QuestionHelp className="memori-icon" aria-label={t('expand')} />
66
+ </label>
67
+ <aside className="memori-sidebar">
68
+ <label
69
+ htmlFor="memori-sidebar-toggle"
70
+ className="memori-sidebar-toggle-label memori-close-label"
71
+ >
72
+ <span>
73
+ <Close className="memori-icon-close" aria-label={t('collapse')} />
74
+ </span>
75
+ </label>
76
+ <div className="memori-sidebar-content">
77
+ <div className="memori-hidden-chat-layout--header">
78
+ {Header && headerProps && (
79
+ <Header
80
+ position={{
81
+ latitude: 0,
82
+ longitude: 0,
83
+ placeName: '',
84
+ }}
85
+ {...headerProps}
86
+ className="memori-hidden-chat-layout-header--layout"
87
+ />
88
+ )}
89
+ </div>
90
+ </div>
91
+ <div id="extension" />
92
+ <div className="memori-hidden-chat-layout--controls">
93
+ {sessionId && hasUserActivatedSpeak && Chat && chatProps ? (
94
+ <Chat {...chatProps} />
95
+ ) : (
96
+ <div className="memori-loading">
97
+ <Spin />
98
+ </div>
99
+ )}
100
+ </div>
101
+ </aside>
102
+ </div>
103
+ </>
104
+ );
105
+ };
106
+
107
+ export default HiddenChatLayout;
@@ -2,7 +2,7 @@ import { render } from '@testing-library/react';
2
2
  import Memori from '../MemoriWidget/MemoriWidget';
3
3
  import { integration, memori, tenant } from '../../mocks/data';
4
4
  import I18nWrapper from '../../I18nWrapper';
5
-
5
+ import { VisemeProvider } from '../../context/visemeContext';
6
6
  Object.defineProperty(window, 'matchMedia', {
7
7
  writable: true,
8
8
  value: jest.fn().mockImplementation(query => ({
@@ -20,15 +20,17 @@ Object.defineProperty(window, 'matchMedia', {
20
20
  it('renders Totem layout unchanged', () => {
21
21
  const { container } = render(
22
22
  <I18nWrapper>
23
- <Memori
23
+ <VisemeProvider>
24
+ <Memori
24
25
  showShare={true}
25
26
  showSettings={true}
26
27
  memori={memori}
27
28
  tenant={tenant}
28
29
  tenantID="aisuru.com"
29
30
  integration={integration}
30
- layout="TOTEM"
31
- />
31
+ layout="TOTEM"
32
+ />
33
+ </VisemeProvider>
32
34
  </I18nWrapper>
33
35
  );
34
36
  expect(container).toMatchSnapshot();
@@ -2,7 +2,7 @@ import { render } from '@testing-library/react';
2
2
  import Memori from '../MemoriWidget/MemoriWidget';
3
3
  import { integration, memori, tenant } from '../../mocks/data';
4
4
  import I18nWrapper from '../../I18nWrapper';
5
-
5
+ import { VisemeProvider } from '../../context/visemeContext';
6
6
  Object.defineProperty(window, 'matchMedia', {
7
7
  writable: true,
8
8
  value: jest.fn().mockImplementation(query => ({
@@ -20,15 +20,17 @@ Object.defineProperty(window, 'matchMedia', {
20
20
  it('renders WEBSITE_ASSISTANT layout unchanged', () => {
21
21
  const { container } = render(
22
22
  <I18nWrapper>
23
- <Memori
24
- showShare={true}
23
+ <VisemeProvider>
24
+ <Memori
25
+ showShare={true}
25
26
  showSettings={true}
26
27
  memori={memori}
27
28
  tenant={tenant}
28
29
  tenantID="aisuru.com"
29
30
  integration={integration}
30
- layout="WEBSITE_ASSISTANT"
31
- />
31
+ layout="WEBSITE_ASSISTANT"
32
+ />
33
+ </VisemeProvider>
32
34
  </I18nWrapper>
33
35
  );
34
36
  expect(container).toMatchSnapshot();
@@ -0,0 +1,37 @@
1
+ import { render } from '@testing-library/react';
2
+ import Memori from '../MemoriWidget/MemoriWidget';
3
+ import { integration, memori, tenant } from '../../mocks/data';
4
+ import I18nWrapper from '../../I18nWrapper';
5
+ import { VisemeProvider } from '../../context/visemeContext';
6
+ Object.defineProperty(window, 'matchMedia', {
7
+ writable: true,
8
+ value: jest.fn().mockImplementation(query => ({
9
+ matches: false,
10
+ media: query,
11
+ onchange: null,
12
+ addListener: jest.fn(), // Deprecated
13
+ removeListener: jest.fn(), // Deprecated
14
+ addEventListener: jest.fn(),
15
+ removeEventListener: jest.fn(),
16
+ dispatchEvent: jest.fn(),
17
+ })),
18
+ });
19
+
20
+ it('renders ZOOMED_FULL_BODY layout unchanged', () => {
21
+ const { container } = render(
22
+ <I18nWrapper>
23
+ <VisemeProvider>
24
+ <Memori
25
+ showShare={true}
26
+ showSettings={true}
27
+ memori={memori}
28
+ tenant={tenant}
29
+ tenantID="aisuru.com"
30
+ integration={integration}
31
+ layout="ZOOMED_FULL_BODY"
32
+ />
33
+ </VisemeProvider>
34
+ </I18nWrapper>
35
+ );
36
+ expect(container).toMatchSnapshot();
37
+ });
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+ import Spin from '../ui/Spin';
3
+ import { LayoutProps } from '../MemoriWidget/MemoriWidget';
4
+
5
+ const FullPageLayout: React.FC<LayoutProps> = ({
6
+ Header,
7
+ headerProps,
8
+ Avatar,
9
+ avatarProps,
10
+ Chat,
11
+ chatProps,
12
+ StartPanel,
13
+ startPanelProps,
14
+ integrationStyle,
15
+ integrationBackground,
16
+ ChangeMode,
17
+ changeModeProps,
18
+ sessionId,
19
+ hasUserActivatedSpeak,
20
+ showInstruct = false,
21
+ loading = false,
22
+ poweredBy,
23
+ }) => (
24
+ <>
25
+ {integrationStyle}
26
+ {integrationBackground}
27
+
28
+ <Spin spinning={loading}>
29
+ {showInstruct && ChangeMode && changeModeProps && (
30
+ <ChangeMode {...changeModeProps} />
31
+ )}
32
+
33
+ {Header && headerProps && <Header {...headerProps} />}
34
+
35
+ <div className="memori--grid">
36
+ <div className="memori--grid-column memori--grid-column-left">
37
+ {Avatar && avatarProps && <Avatar chatProps={chatProps} isZoomed {...avatarProps} />}
38
+
39
+ <div id="extension" />
40
+ </div>
41
+ <div className="memori--grid-column memori--grid-column-right">
42
+ {sessionId && hasUserActivatedSpeak && Chat && chatProps ? (
43
+ <Chat {...chatProps} />
44
+ ) : startPanelProps ? (
45
+ <StartPanel {...startPanelProps} />
46
+ ) : null}
47
+ </div>
48
+
49
+ {poweredBy}
50
+ </div>
51
+ </Spin>
52
+ </>
53
+ );
54
+
55
+ export default FullPageLayout;