@memori.ai/memori-react 7.5.1 → 7.6.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.
Files changed (156) hide show
  1. package/CHANGELOG.md +44 -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/fullbodyAvatar.d.ts +2 -1
  22. package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.js +3 -2
  23. package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.js.map +1 -1
  24. package/dist/components/Avatar/AvatarView/index.d.ts +6 -1
  25. package/dist/components/Avatar/AvatarView/index.js +14 -84
  26. package/dist/components/Avatar/AvatarView/index.js.map +1 -1
  27. package/dist/components/Avatar/AvatarView/utils/useEyeBlink.d.ts +16 -2
  28. package/dist/components/Avatar/AvatarView/utils/useEyeBlink.js +62 -38
  29. package/dist/components/Avatar/AvatarView/utils/useEyeBlink.js.map +1 -1
  30. package/dist/components/Avatar/AvatarView/utils/useMouthAnimation.d.ts +16 -0
  31. package/dist/components/Avatar/AvatarView/utils/useMouthAnimation.js +59 -0
  32. package/dist/components/Avatar/AvatarView/utils/useMouthAnimation.js.map +1 -0
  33. package/dist/components/Avatar/AvatarView/utils/useSmile.js +1 -1
  34. package/dist/components/Avatar/AvatarView/utils/useSmile.js.map +1 -1
  35. package/dist/components/ChatBubble/ChatBubble.js +2 -3
  36. package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
  37. package/dist/components/CompletionProviderStatus/CompletionProviderStatus.d.ts +1 -1
  38. package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js +24 -3
  39. package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
  40. package/dist/components/MemoriWidget/MemoriWidget.d.ts +1 -1
  41. package/dist/components/MemoriWidget/MemoriWidget.js +25 -3
  42. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  43. package/dist/components/StartPanel/StartPanel.js +1 -1
  44. package/dist/components/StartPanel/StartPanel.js.map +1 -1
  45. package/dist/components/layouts/HiddenChat.d.ts +4 -0
  46. package/dist/components/layouts/HiddenChat.js +51 -0
  47. package/dist/components/layouts/HiddenChat.js.map +1 -0
  48. package/dist/components/layouts/ZoomedFullBody.d.ts +4 -0
  49. package/dist/components/layouts/ZoomedFullBody.js +8 -0
  50. package/dist/components/layouts/ZoomedFullBody.js.map +1 -0
  51. package/dist/components/layouts/hidden-chat.css +184 -0
  52. package/dist/context/visemeContext.d.ts +27 -0
  53. package/dist/context/visemeContext.js +221 -0
  54. package/dist/context/visemeContext.js.map +1 -0
  55. package/dist/helpers/utils.d.ts +7 -0
  56. package/dist/helpers/utils.js +51 -1
  57. package/dist/helpers/utils.js.map +1 -1
  58. package/dist/index.js +20 -16
  59. package/dist/index.js.map +1 -1
  60. package/dist/styles.css +1 -0
  61. package/esm/components/Avatar/Avatar.d.ts +2 -0
  62. package/esm/components/Avatar/Avatar.js +11 -6
  63. package/esm/components/Avatar/Avatar.js.map +1 -1
  64. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +20 -0
  65. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +102 -0
  66. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -0
  67. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.d.ts +26 -0
  68. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.js +56 -0
  69. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.js.map +1 -0
  70. package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +30 -0
  71. package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +145 -0
  72. package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -0
  73. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +15 -0
  74. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +73 -0
  75. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -0
  76. package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.d.ts +5 -0
  77. package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.js +9 -0
  78. package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.js.map +1 -0
  79. package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.d.ts +2 -1
  80. package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.js +3 -2
  81. package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.js.map +1 -1
  82. package/esm/components/Avatar/AvatarView/index.d.ts +6 -1
  83. package/esm/components/Avatar/AvatarView/index.js +15 -85
  84. package/esm/components/Avatar/AvatarView/index.js.map +1 -1
  85. package/esm/components/Avatar/AvatarView/utils/useEyeBlink.d.ts +16 -2
  86. package/esm/components/Avatar/AvatarView/utils/useEyeBlink.js +61 -38
  87. package/esm/components/Avatar/AvatarView/utils/useEyeBlink.js.map +1 -1
  88. package/esm/components/Avatar/AvatarView/utils/useMouthAnimation.d.ts +16 -0
  89. package/esm/components/Avatar/AvatarView/utils/useMouthAnimation.js +55 -0
  90. package/esm/components/Avatar/AvatarView/utils/useMouthAnimation.js.map +1 -0
  91. package/esm/components/Avatar/AvatarView/utils/useSmile.js +1 -1
  92. package/esm/components/Avatar/AvatarView/utils/useSmile.js.map +1 -1
  93. package/esm/components/ChatBubble/ChatBubble.js +2 -3
  94. package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
  95. package/esm/components/CompletionProviderStatus/CompletionProviderStatus.d.ts +1 -1
  96. package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js +24 -3
  97. package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
  98. package/esm/components/MemoriWidget/MemoriWidget.d.ts +1 -1
  99. package/esm/components/MemoriWidget/MemoriWidget.js +26 -4
  100. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  101. package/esm/components/StartPanel/StartPanel.js +1 -1
  102. package/esm/components/StartPanel/StartPanel.js.map +1 -1
  103. package/esm/components/layouts/HiddenChat.d.ts +4 -0
  104. package/esm/components/layouts/HiddenChat.js +48 -0
  105. package/esm/components/layouts/HiddenChat.js.map +1 -0
  106. package/esm/components/layouts/ZoomedFullBody.d.ts +4 -0
  107. package/esm/components/layouts/ZoomedFullBody.js +5 -0
  108. package/esm/components/layouts/ZoomedFullBody.js.map +1 -0
  109. package/esm/components/layouts/hidden-chat.css +184 -0
  110. package/esm/context/visemeContext.d.ts +27 -0
  111. package/esm/context/visemeContext.js +216 -0
  112. package/esm/context/visemeContext.js.map +1 -0
  113. package/esm/helpers/utils.d.ts +7 -0
  114. package/esm/helpers/utils.js +45 -0
  115. package/esm/helpers/utils.js.map +1 -1
  116. package/esm/index.js +20 -16
  117. package/esm/index.js.map +1 -1
  118. package/esm/styles.css +1 -0
  119. package/package.json +2 -2
  120. package/src/components/Avatar/Avatar.test.tsx +28 -20
  121. package/src/components/Avatar/Avatar.tsx +19 -5
  122. package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +222 -0
  123. package/src/components/Avatar/AvatarView/{components → AvatarComponent/components}/controls.tsx +16 -10
  124. package/src/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.tsx +234 -0
  125. package/src/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.tsx +123 -0
  126. package/src/components/Avatar/AvatarView/{components → AvatarComponent/components}/loader.tsx +1 -1
  127. package/src/components/Avatar/AvatarView/AvatarView.stories.tsx +47 -8
  128. package/src/components/Avatar/AvatarView/index.tsx +35 -167
  129. package/src/components/Avatar/AvatarView/utils/useEyeBlink.ts +89 -48
  130. package/src/components/Avatar/AvatarView/utils/useMouthAnimation.ts +93 -0
  131. package/src/components/Avatar/AvatarView/utils/useSmile.ts +1 -1
  132. package/src/components/ChatBubble/ChatBubble.tsx +3 -4
  133. package/src/components/CompletionProviderStatus/CompletionProviderStatus.tsx +33 -3
  134. package/src/components/CompletionProviderStatus/__snapshots__/CompletionProviderStatus.test.tsx.snap +18 -0
  135. package/src/components/MemoriWidget/MemoriWidget.tsx +60 -5
  136. package/src/components/StartPanel/StartPanel.tsx +1 -1
  137. package/src/components/layouts/Chat.test.tsx +7 -5
  138. package/src/components/layouts/FullPage.test.tsx +11 -8
  139. package/src/components/layouts/HiddenChat.test.tsx +37 -0
  140. package/src/components/layouts/HiddenChat.tsx +108 -0
  141. package/src/components/layouts/Totem.test.tsx +6 -4
  142. package/src/components/layouts/WebsiteAssistant.test.tsx +7 -5
  143. package/src/components/layouts/ZoomedFullBody.test.tsx +37 -0
  144. package/src/components/layouts/ZoomedFullBody.tsx +55 -0
  145. package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +210 -0
  146. package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +444 -0
  147. package/src/components/layouts/hidden-chat.css +184 -0
  148. package/src/components/layouts/layouts.stories.tsx +135 -19
  149. package/src/context/visemeContext.tsx +328 -0
  150. package/src/helpers/utils.ts +73 -0
  151. package/src/index.stories.tsx +40 -17
  152. package/src/index.tsx +82 -78
  153. package/src/styles.css +1 -0
  154. package/src/components/Avatar/AvatarView/components/fullbodyAvatar.tsx +0 -120
  155. package/src/components/Avatar/AvatarView/components/halfbodyAvatar.tsx +0 -69
  156. package/src/components/Avatar/AvatarView/utils/useMouthSpeaking.ts +0 -87
@@ -0,0 +1,184 @@
1
+ .sidebar-container {
2
+ position: fixed;
3
+ z-index: 1000;
4
+ top: 0;
5
+ right: 0;
6
+ height: 100%;
7
+ }
8
+
9
+ .sidebar-toggle {
10
+ display: none;
11
+ }
12
+
13
+ .sidebar-toggle-label {
14
+ position: absolute;
15
+ top: 50%;
16
+ right: 0;
17
+ display: flex;
18
+ width: auto;
19
+ height: 80px;
20
+ align-items: center;
21
+ justify-content: center;
22
+ padding: 10px 5px;
23
+ background-color: var(--memori-primary);
24
+ color: white;
25
+ cursor: pointer;
26
+ font-size: 18px;
27
+ font-weight: bold;
28
+ text-orientation: mixed;
29
+ transform: translateY(-50%);
30
+ transition: all 0.3s ease-in-out;
31
+ writing-mode: vertical-rl;
32
+ }
33
+
34
+ .open-label {
35
+ border-radius: 5px 0 0 5px;
36
+ }
37
+
38
+ .close-label {
39
+ right: 350px;
40
+ border-radius: 0 5px 5px 0;
41
+ opacity: 0;
42
+ pointer-events: none;
43
+ transform: rotate(180deg);
44
+ }
45
+
46
+ .sidebar {
47
+ position: fixed;
48
+ z-index: 1000;
49
+ top: 0;
50
+ right: -350px;
51
+ width: 350px;
52
+ height: 100%;
53
+ background-color: white;
54
+ box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
55
+ transition: right 0.3s ease-in-out;
56
+ }
57
+
58
+ .sidebar-content h2 {
59
+ margin-bottom: 20px;
60
+ color: var(--memori-primary);
61
+ font-size: 24px;
62
+ font-weight: bold;
63
+ }
64
+
65
+ .sidebar-content ul {
66
+ padding: 0;
67
+ list-style-type: none;
68
+ }
69
+
70
+ .sidebar-content li {
71
+ margin-bottom: 10px;
72
+ }
73
+
74
+ .sidebar-content a {
75
+ display: flex;
76
+ align-items: center;
77
+ color: #4b5563;
78
+ text-decoration: none;
79
+ transition: color 0.2s ease-in-out;
80
+ }
81
+
82
+ .sidebar-content a:hover {
83
+ color: var(--memori-primary);
84
+ }
85
+
86
+ .sidebar-content svg {
87
+ width: 20px;
88
+ height: 20px;
89
+ margin-right: 10px;
90
+ }
91
+
92
+ .sidebar-toggle:checked ~ .sidebar-container .sidebar {
93
+ right: 0;
94
+ }
95
+
96
+ .sidebar-toggle:checked ~ .sidebar-container .open-label {
97
+ opacity: 0;
98
+ pointer-events: none;
99
+ transform: translateY(-50%) translateX(350px);
100
+ }
101
+
102
+ .loading {
103
+ display: flex;
104
+ height: 100%;
105
+ align-items: center;
106
+ justify-content: center;
107
+ }
108
+
109
+
110
+ .sidebar-content {
111
+ position: absolute;
112
+ top: -10px;
113
+ width: 100%;
114
+ padding: 20px;
115
+ }
116
+
117
+ .sidebar-toggle:checked ~ .sidebar-container .close-label {
118
+ opacity: 1;
119
+ pointer-events: auto;
120
+ }
121
+
122
+ .memori-hidden-chat-layout--controls {
123
+ display: flex;
124
+ height: 90%;
125
+ padding: 10px;
126
+ margin-top: 50px;
127
+ }
128
+
129
+ .memori-hidden-chat-layout-header--layout {
130
+ display: flex;
131
+ width: 100%;
132
+ align-items: center;
133
+ justify-content: flex-end;
134
+ padding: 10px;
135
+ margin: 0;
136
+ background-color: white;
137
+ color: white;
138
+ }
139
+
140
+ .memori-hidden-chat-layout-header--layout > button, .memori-hidden-chat-layout-header--layout > div > button {
141
+ display: flex;
142
+ width: 38px;
143
+ height: 38px;
144
+ align-items: center;
145
+ justify-content: center;
146
+ border-radius: 50%;
147
+ aspect-ratio: 1;
148
+ background-color: var(--memori-primary);
149
+ cursor: pointer;
150
+ transition: background-color 0.3s ease-in-out;
151
+ }
152
+
153
+ .memori-button--icon > svg {
154
+ margin: 0;
155
+ }
156
+
157
+ .icon,.icon-close {
158
+ width: 25px;
159
+ height: 25px;
160
+ }
161
+
162
+ .icon-close{
163
+ fill: white;
164
+ }
165
+
166
+
167
+ @media (max-width: 768px) {
168
+ .sidebar-container {
169
+ display: none;
170
+ }
171
+
172
+ .sidebar {
173
+ right: -100%;
174
+ width: 100%;
175
+ }
176
+
177
+ .sidebar-toggle:checked ~ .sidebar-container .open-label {
178
+ transform: translateY(-50%) translateX(100%);
179
+ }
180
+
181
+ .close-label {
182
+ right: 100%;
183
+ }
184
+ }
@@ -4,6 +4,7 @@ import { memori, tenant, integration } from '../../mocks/data';
4
4
  import Memori, { LayoutProps, Props } from '../MemoriWidget/MemoriWidget';
5
5
  import I18nWrapper from '../../I18nWrapper';
6
6
  import Spin from '../ui/Spin';
7
+ import { VisemeProvider } from '../../context/visemeContext';
7
8
 
8
9
  const meta: Meta = {
9
10
  title: 'General/Layouts',
@@ -62,7 +63,9 @@ export const CustomLayout: React.FC<LayoutProps> = ({
62
63
 
63
64
  const Template: Story<Props> = args => (
64
65
  <I18nWrapper>
65
- <Memori {...args} />
66
+ <VisemeProvider>
67
+ <Memori {...args} />
68
+ </VisemeProvider>
66
69
  </I18nWrapper>
67
70
  );
68
71
  // By passing using the Args format for exported stories, you can control the props for a component for reuse in a test
@@ -197,8 +200,20 @@ ChatOnly.args = {
197
200
  layout: 'CHAT',
198
201
  };
199
202
 
200
- export const Totem = Template.bind({});
201
- Totem.args = {
203
+
204
+ export const Custom = Template.bind({});
205
+ Custom.args = {
206
+ uiLang: 'it',
207
+ showShare: true,
208
+ showSettings: true,
209
+ memori,
210
+ tenant,
211
+ layout: 'FULLPAGE',
212
+ customLayout: CustomLayout,
213
+ };
214
+
215
+ export const WebsiteAssistant = Template.bind({});
216
+ WebsiteAssistant.args = {
202
217
  uiLang: 'it',
203
218
  showShare: true,
204
219
  showSettings: true,
@@ -303,25 +318,16 @@ Totem.args = {
303
318
  }),
304
319
  },
305
320
  tenant,
306
- layout: 'TOTEM',
307
- };
308
-
309
- export const Custom = Template.bind({});
310
- Custom.args = {
311
- uiLang: 'it',
312
- showShare: true,
313
- showSettings: true,
314
- memori,
315
- tenant,
316
- layout: 'FULLPAGE',
317
- customLayout: CustomLayout,
321
+ layout: 'WEBSITE_ASSISTANT',
318
322
  };
319
323
 
320
- export const WebsiteAssistant = Template.bind({});
321
- WebsiteAssistant.args = {
324
+ export const HiddenChat = Template.bind({});
325
+ HiddenChat.args = {
322
326
  uiLang: 'it',
323
327
  showShare: true,
324
328
  showSettings: true,
329
+ // memori,
330
+ // tenant,
325
331
  memori: {
326
332
  memoriID: '6573844d-a7cd-47ef-9e78-840d82020c21',
327
333
  name: 'Nicola',
@@ -422,6 +428,116 @@ WebsiteAssistant.args = {
422
428
  new Date(Date.now()).getTime(),
423
429
  }),
424
430
  },
425
- tenant,
426
- layout: 'WEBSITE_ASSISTANT',
431
+ layout: 'HIDDEN_CHAT',
432
+ };
433
+
434
+
435
+ export const ZoomedFullBody = Template.bind({});
436
+ ZoomedFullBody.args = {
437
+ uiLang: 'it',
438
+ showShare: true,
439
+ showSettings: true,
440
+ showAudio: true,
441
+ enableAudio: true,
442
+ memori: {
443
+ memoriID: '6573844d-a7cd-47ef-9e78-840d82020c21',
444
+ name: 'Nicola',
445
+ password: null,
446
+ recoveryTokens: null,
447
+ newPassword: null,
448
+ ownerUserID: null,
449
+ ownerUserName: 'nzambello',
450
+ ownerTenantName: 'aisuru.com',
451
+ memoriConfigurationID: 'fd10bb42-98d9-4c08-8e02-2b08bd4e4975',
452
+ description:
453
+ 'Sono Nicola Zambello, sviluppatore e attivista per un web etico e sostenibile',
454
+ completionDescription: null,
455
+ engineMemoriID: '9b0a2913-d3d8-4e98-a49d-6e1c99479e1b',
456
+ isOwner: false,
457
+ isGiver: false,
458
+ isReceiver: false,
459
+ giverTag: null,
460
+ giverPIN: null,
461
+ privacyType: 'PUBLIC',
462
+ enableAudio: true,
463
+ secretToken: null,
464
+ minimumNumberOfRecoveryTokens: null,
465
+ totalNumberOfRecoveryTokens: null,
466
+ sentInvitations: [],
467
+ receivedInvitations: [],
468
+ integrations: [
469
+ {
470
+ integrationID: '62de8c99-0ac2-4cbe-bd95-a39ad7dc6b32',
471
+ memoriID: '6573844d-a7cd-47ef-9e78-840d82020c21',
472
+ type: 'LANDING_EXPERIENCE',
473
+ state: 'NEW',
474
+ deviceEmails: null,
475
+ invocationText: null,
476
+ jobID: null,
477
+ customData:
478
+ '{"textColor":"#000000","buttonBgColor":"#007eb6","buttonTextColor":"#ffffff","globalBackground":"https://assets.memori.ai/api/v2/asset/cade3b9c-0437-4342-b2bd-8db9c2a3a20e.png","blurBackground":true,"innerBgColor":"light","multilanguage":true,"avatar":"readyplayerme","avatarURL":"https://assets.memori.ai/api/v2/asset/893c41df-7619-436d-9e86-fe1d406fc933.glb#1681736752156","name":"Pagina pubblica","contextVars":"ANIMALE:CANE","personTag":"☠️","personPIN":"666666","personName":"Pirata","showShare":true,"avatarFullBodyURL":"https://models.readyplayer.me/63b55751f17e295642bf07a2.glb"}',
479
+ resources: [],
480
+ publish: true,
481
+ creationTimestamp: '2022-06-13T14:44:52.833573Z',
482
+ lastChangeTimestamp: '2022-06-13T14:44:52.833573Z',
483
+ },
484
+ ],
485
+ avatarURL:
486
+ 'https://assets.memori.ai/api/v2/asset/3049582f-db5f-452c-913d-e4340d4afd0a.png',
487
+ coverURL:
488
+ 'https://assets.memori.ai/api/v2/asset/e9bb9f6d-8f34-45ab-af9e-6d630d9a51a8.png',
489
+ avatar3DURL:
490
+ 'https://assets.memori.ai/api/v2/asset/3932bf70-e953-4e8a-b63a-f316544c283e.glb',
491
+ avatarOriginal3DURL:
492
+ 'https://assets.memori.ai/api/v2/asset/3932bf70-e953-4e8a-b63a-f316544c283e.glb',
493
+ needsPosition: false,
494
+ voiceType: 'FEMALE',
495
+ culture: 'it-IT',
496
+ categories: [
497
+ 'biografico',
498
+ 'tecnologia',
499
+ 'web',
500
+ 'open-source',
501
+ 'green',
502
+ 'privacy',
503
+ ],
504
+ exposed: true,
505
+ disableR2R3Loop: null,
506
+ disableR4Loop: null,
507
+ disableR5Loop: null,
508
+ enableCompletions: true,
509
+ completionModel: null,
510
+ chainingMemoriID: null,
511
+ chainingBaseURL: null,
512
+ chainingPassword: null,
513
+ contentQualityIndex: 210.8,
514
+ contentQualityIndexTimestamp: '2023-04-17T00:01:32.194744Z',
515
+ publishedInTheMetaverse: true,
516
+ metaverseEnvironment: 'apartment',
517
+ blockedUntil: null,
518
+ creationTimestamp: '2022-06-13T14:21:55.793034Z',
519
+ lastChangeTimestamp: '2023-04-15T08:15:36.403546Z',
520
+ },
521
+ integration: {
522
+ integrationID: '62de8c99-0ac2-4cbe-bd95-a39ad7dc6b32',
523
+ memoriID: '6573844d-a7cd-47ef-9e78-840d82020c21',
524
+ type: 'LANDING_EXPERIENCE',
525
+ state: 'NEW',
526
+ deviceEmails: null,
527
+ invocationText: null,
528
+ jobID: null,
529
+ publish: true,
530
+ creationTimestamp: '2022-06-13T14:44:52.833573Z',
531
+ lastChangeTimestamp: '2022-06-13T14:44:52.833573Z',
532
+ customData: JSON.stringify({
533
+ ...JSON.parse(
534
+ '{"textColor":"#000000","buttonBgColor":"#007eb6","buttonTextColor":"#ffffff","globalBackground":"https://assets.memori.ai/api/v2/asset/cade3b9c-0437-4342-b2bd-8db9c2a3a20e.png","blurBackground":true,"innerBgColor":"light","multilanguage":true,"avatar":"readyplayerme","avatarURL":"https://assets.memori.ai/api/v2/asset/893c41df-7619-436d-9e86-fe1d406fc933.glb#1681736752156","name":"Pagina pubblica","contextVars":"ANIMALE:CANE","personTag":"☠️","personPIN":"666666","personName":"Pirata","showShare":true,"avatarFullBodyURL":"https://models.readyplayer.me/63b55751f17e295642bf07a2.glb"}'
535
+ ),
536
+ avatar: 'readyplayerme-full',
537
+ avatarURL:
538
+ 'https://assets.memori.ai/api/v2/asset/3932bf70-e953-4e8a-b63a-f316544c283e.glb'+
539
+ new Date(Date.now()).getTime(),
540
+ }),
541
+ },
542
+ layout: 'ZOOMED_FULL_BODY',
427
543
  };
@@ -0,0 +1,328 @@
1
+ import React, {
2
+ createContext,
3
+ useContext,
4
+ useState,
5
+ useCallback,
6
+ useRef,
7
+ useEffect,
8
+ } from 'react';
9
+ import { SkinnedMesh } from 'three';
10
+
11
+ type AzureViseme = { visemeId: number; audioOffset: number };
12
+
13
+ type ProcessedViseme = {
14
+ name: string;
15
+ duration: number;
16
+ weight: number;
17
+ startTime: number;
18
+ };
19
+
20
+ interface VisemeContextType {
21
+ setMeshRef: (mesh: SkinnedMesh | null) => void;
22
+ addVisemeToQueue: (viseme: AzureViseme) => void;
23
+ processVisemeQueue: () => ProcessedViseme[];
24
+ clearVisemes: () => void;
25
+ isMeshSet: boolean;
26
+ setEmotion: (emotion: string) => void;
27
+ emotion: string;
28
+ getAzureStyleForEmotion: (emotion: string) => string;
29
+ }
30
+
31
+ const VisemeContext = createContext<VisemeContextType | undefined>(undefined);
32
+
33
+ const VISEME_SMOOTHING = 0.5;
34
+ const DEFAULT_VISEME_DURATION = 0.1;
35
+ const MINIMUM_ELAPSED_TIME = 0.01;
36
+ const VISEME_SPEED_FACTOR = 1.0;
37
+ const AUDIO_PLAYBACK_RATE = 1.0;
38
+ const VISEME_BASE_SPEED = 1.0;
39
+
40
+ const VISEME_MAP: { [key: number]: string } = {
41
+ 0: 'viseme_sil', // silence
42
+ 1: 'viseme_PP', // p, b, m
43
+ 2: 'viseme_FF', // f, v
44
+ 3: 'viseme_TH', // th, dh
45
+ 4: 'viseme_DD', // t, d, n, l
46
+ 5: 'viseme_kk', // k, g, ng
47
+ 6: 'viseme_CH', // tS, dZ, S, Z
48
+ 7: 'viseme_SS', // s, z
49
+ 8: 'viseme_nn', // Not explicitly defined in Azure mapping, keeping for compatibility
50
+ 9: 'viseme_RR', // r
51
+ 10: 'viseme_aa', // A:
52
+ 11: 'viseme_E', // e
53
+ 12: 'viseme_I', // I
54
+ 13: 'viseme_O', // O
55
+ 14: 'viseme_U', // u
56
+ // Mapping the rest based on closest matches or keeping them as in the original mapping
57
+ 15: 'viseme_kk', // g, k (same as 5)
58
+ 16: 'viseme_CH', // ch, j, sh, zh (same as 6)
59
+ 17: 'viseme_SS', // s, z (same as 7)
60
+ 18: 'viseme_TH', // th, dh (same as 3)
61
+ 19: 'viseme_RR', // r (same as 9)
62
+ 20: 'viseme_kk', // w (closest match, could be debated)
63
+ 21: 'viseme_PP', // y (closest match, could be debated)
64
+ };
65
+
66
+ export const VisemeProvider: React.FC<{ children: React.ReactNode }> = ({
67
+ children,
68
+ }) => {
69
+ const [isMeshSet, setIsMeshSet] = useState(false);
70
+ const [emotion, setEmotion] = useState('Neutral');
71
+ const isAnimatingRef = useRef(false);
72
+ const currentVisemesRef = useRef<ProcessedViseme[]>([]);
73
+ const visemeQueueRef = useRef<AzureViseme[]>([]);
74
+ const animationFrameRef = useRef<number | null>(null);
75
+ const startTimeRef = useRef<number | null>(null);
76
+ const currentVisemeWeightRef = useRef<{ [key: string]: number }>({});
77
+ const meshRef = useRef<SkinnedMesh | null>(null);
78
+
79
+ const lerp = (start: number, end: number, alpha: number): number => {
80
+ return start * (1 - alpha) + end * alpha;
81
+ };
82
+
83
+ const easeInOutCubic = (x: number): number => {
84
+ return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
85
+ };
86
+
87
+ const setMeshRef = useCallback(
88
+ (mesh: SkinnedMesh | null) => {
89
+ if (mesh && mesh.morphTargetDictionary && mesh.morphTargetInfluences) {
90
+ meshRef.current = mesh;
91
+ setIsMeshSet(true);
92
+ // console.log('Mesh set successfully:', mesh);
93
+ } else {
94
+ console.error('Invalid mesh provided:', mesh);
95
+ }
96
+ },
97
+ [meshRef]
98
+ );
99
+
100
+ const addVisemeToQueue = useCallback((viseme: AzureViseme) => {
101
+ visemeQueueRef.current.push(viseme);
102
+ // console.log('Viseme added to queue:', viseme);
103
+ }, []);
104
+
105
+ const getCurrentViseme = useCallback((elapsedTime: number) => {
106
+ if (elapsedTime < MINIMUM_ELAPSED_TIME) return null;
107
+
108
+ return currentVisemesRef.current.find((viseme, index) => {
109
+ const nextViseme = currentVisemesRef.current[index + 1];
110
+ return (
111
+ elapsedTime >= viseme.startTime &&
112
+ (!nextViseme || elapsedTime < nextViseme.startTime)
113
+ );
114
+ });
115
+ }, []);
116
+
117
+ const getDynamicSpeedFactor = (visemeDuration: number): number => {
118
+ const baseDuration = 0.1; // Average expected viseme duration
119
+ return (
120
+ VISEME_BASE_SPEED * (baseDuration / visemeDuration) * AUDIO_PLAYBACK_RATE
121
+ );
122
+ };
123
+
124
+ const applyViseme = useCallback(
125
+ (viseme: ProcessedViseme, elapsedTime: number) => {
126
+ if (!meshRef.current) {
127
+ console.error('Mesh not set');
128
+ return;
129
+ }
130
+
131
+ const visemeProgress = Math.min(
132
+ (elapsedTime - viseme.startTime) / viseme.duration,
133
+ 1
134
+ );
135
+
136
+ const dynamicSpeedFactor = getDynamicSpeedFactor(viseme.duration);
137
+ const adjustedProgress = visemeProgress * dynamicSpeedFactor;
138
+
139
+ // Use a cubic easing function for smoother transitions
140
+ const easedProgress = easeInOutCubic(adjustedProgress);
141
+ const targetWeight = Math.sin(easedProgress * Math.PI) * viseme.weight;
142
+
143
+ currentVisemeWeightRef.current[viseme.name] = lerp(
144
+ currentVisemeWeightRef.current[viseme.name] || 0,
145
+ targetWeight,
146
+ VISEME_SMOOTHING
147
+ );
148
+
149
+ const visemeIndex = meshRef.current.morphTargetDictionary?.[viseme.name];
150
+ if (
151
+ typeof visemeIndex === 'number' &&
152
+ meshRef.current.morphTargetInfluences
153
+ ) {
154
+ meshRef.current.morphTargetInfluences[visemeIndex] =
155
+ currentVisemeWeightRef.current[viseme.name];
156
+ // console.log(`Applied viseme: ${viseme.name}, weight: ${currentVisemeWeightRef.current[viseme.name]}`);
157
+ } else {
158
+ console.error(
159
+ `Viseme not found in morph target dictionary: ${viseme.name}`
160
+ );
161
+ }
162
+ },
163
+ []
164
+ );
165
+
166
+ const animate = useCallback(
167
+ (time: number) => {
168
+ if (startTimeRef.current === null) {
169
+ startTimeRef.current = time;
170
+ }
171
+
172
+ const elapsedTime =
173
+ ((time - startTimeRef.current) / 1000) * VISEME_SPEED_FACTOR;
174
+
175
+ const currentViseme = getCurrentViseme(elapsedTime);
176
+
177
+ if (currentViseme) {
178
+ applyViseme(currentViseme, elapsedTime);
179
+ }
180
+
181
+ if (
182
+ currentVisemesRef.current.length > 0 &&
183
+ elapsedTime <
184
+ currentVisemesRef.current[currentVisemesRef.current.length - 1]
185
+ .startTime +
186
+ currentVisemesRef.current[currentVisemesRef.current.length - 1]
187
+ .duration
188
+ ) {
189
+ animationFrameRef.current = requestAnimationFrame(animate);
190
+ } else {
191
+ clearVisemes();
192
+ }
193
+ },
194
+ [getCurrentViseme, applyViseme]
195
+ );
196
+
197
+ const processVisemeQueue = useCallback(() => {
198
+ const azureVisemes = [...visemeQueueRef.current];
199
+ visemeQueueRef.current = [];
200
+
201
+ if (azureVisemes.length === 0) {
202
+ // console.log('No visemes to process');
203
+ return [];
204
+ }
205
+
206
+ const processedVisemes: ProcessedViseme[] = azureVisemes.map(
207
+ (currentViseme, i) => {
208
+ const nextViseme = azureVisemes[i + 1];
209
+ const duration = nextViseme
210
+ ? (nextViseme.audioOffset - currentViseme.audioOffset) / 10000000
211
+ : DEFAULT_VISEME_DURATION;
212
+
213
+ const processedViseme = {
214
+ name: VISEME_MAP[currentViseme.visemeId] || 'viseme_sil',
215
+ duration,
216
+ weight: 1,
217
+ startTime: currentViseme.audioOffset / 10000000,
218
+ };
219
+ //console.log('Processed viseme:', processedViseme);
220
+ return processedViseme;
221
+ }
222
+ );
223
+
224
+ currentVisemesRef.current = processedVisemes;
225
+
226
+ // Start animation immediately if not already animating
227
+ if (!isAnimatingRef.current) {
228
+ isAnimatingRef.current = true;
229
+ startTimeRef.current = performance.now();
230
+ // console.log('Starting animation');
231
+ animationFrameRef.current = requestAnimationFrame(animate);
232
+ } else {
233
+ // If already animating, adjust the start time for the new visemes
234
+ if (startTimeRef.current !== null) {
235
+ const currentTime = performance.now();
236
+ const elapsedTime =
237
+ ((currentTime - startTimeRef.current) / 1000) * VISEME_SPEED_FACTOR;
238
+ startTimeRef.current =
239
+ currentTime - (elapsedTime / VISEME_SPEED_FACTOR) * 1000;
240
+ }
241
+ }
242
+
243
+ return processedVisemes;
244
+ }, [isMeshSet, animate]);
245
+
246
+ const clearVisemes = useCallback(() => {
247
+ currentVisemesRef.current = [];
248
+ visemeQueueRef.current = [];
249
+
250
+ if (animationFrameRef.current !== null) {
251
+ cancelAnimationFrame(animationFrameRef.current);
252
+ animationFrameRef.current = null;
253
+ }
254
+
255
+ if (
256
+ meshRef.current?.morphTargetDictionary &&
257
+ meshRef.current?.morphTargetInfluences
258
+ ) {
259
+ Object.values(meshRef.current.morphTargetDictionary).forEach(index => {
260
+ if (typeof index === 'number') {
261
+ meshRef.current!.morphTargetInfluences![index] = 0;
262
+ }
263
+ });
264
+ }
265
+
266
+ currentVisemeWeightRef.current = {};
267
+ startTimeRef.current = null;
268
+ isAnimatingRef.current = false;
269
+ // console.log('Visemes cleared');
270
+ }, []);
271
+
272
+ // Your existing emotion map
273
+ const emotionMap: Record<string, Record<string, number>> = {
274
+ Gioia: { Gioria: 1 },
275
+ Rabbia: { Rabbia: 1 },
276
+ Sorpresa: { Sorpresa: 1 },
277
+ Tristezza: { Tristezza: 1 },
278
+ Timore: { Timore: 1 },
279
+ };
280
+
281
+ // Mapping from your emotions to Azure styles
282
+ const emotionToAzureStyleMap: Record<string, string> = {
283
+ Gioia: 'cheerful',
284
+ Rabbia: 'angry',
285
+ Sorpresa: 'excited',
286
+ Tristezza: 'sad',
287
+ Timore: 'terrified',
288
+ };
289
+
290
+ // Function to get Azure style from emotion
291
+ function getAzureStyleForEmotion(emotion: string): string {
292
+ return emotionToAzureStyleMap[emotion] || 'neutral';
293
+ }
294
+
295
+
296
+ useEffect(() => {
297
+ return () => {
298
+ if (animationFrameRef.current !== null) {
299
+ cancelAnimationFrame(animationFrameRef.current);
300
+ }
301
+ };
302
+ }, []);
303
+
304
+ const contextValue: VisemeContextType = {
305
+ setMeshRef,
306
+ addVisemeToQueue,
307
+ processVisemeQueue,
308
+ clearVisemes,
309
+ isMeshSet,
310
+ setEmotion,
311
+ emotion,
312
+ getAzureStyleForEmotion,
313
+ };
314
+
315
+ return (
316
+ <VisemeContext.Provider value={contextValue}>
317
+ {children}
318
+ </VisemeContext.Provider>
319
+ );
320
+ };
321
+
322
+ export const useViseme = (): VisemeContextType => {
323
+ const context = useContext(VisemeContext);
324
+ if (context === undefined) {
325
+ throw new Error('useViseme must be used within a VisemeProvider');
326
+ }
327
+ return context;
328
+ };