@memori.ai/memori-react 7.5.0 → 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.
- package/CHANGELOG.md +52 -0
- package/README.md +10 -2
- package/dist/components/Avatar/Avatar.d.ts +2 -0
- package/dist/components/Avatar/Avatar.js +11 -6
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +20 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +107 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controls.d.ts +26 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controls.js +59 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controls.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +30 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +148 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +15 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +77 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/loader.d.ts +5 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/loader.js +12 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/loader.js.map +1 -0
- package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.d.ts +2 -1
- package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.js +3 -2
- package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/index.d.ts +6 -1
- package/dist/components/Avatar/AvatarView/index.js +15 -83
- package/dist/components/Avatar/AvatarView/index.js.map +1 -1
- package/dist/components/Avatar/AvatarView/utils/useEyeBlink.d.ts +16 -2
- package/dist/components/Avatar/AvatarView/utils/useEyeBlink.js +62 -38
- package/dist/components/Avatar/AvatarView/utils/useEyeBlink.js.map +1 -1
- package/dist/components/Avatar/AvatarView/utils/useMouthAnimation.d.ts +16 -0
- package/dist/components/Avatar/AvatarView/utils/useMouthAnimation.js +59 -0
- package/dist/components/Avatar/AvatarView/utils/useMouthAnimation.js.map +1 -0
- package/dist/components/Avatar/AvatarView/utils/useSmile.js +1 -1
- package/dist/components/Avatar/AvatarView/utils/useSmile.js.map +1 -1
- package/dist/components/ChatBubble/ChatBubble.js +2 -3
- package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.d.ts +1 -1
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js +24 -3
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.d.ts +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +25 -3
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/StartPanel/StartPanel.js +1 -1
- package/dist/components/StartPanel/StartPanel.js.map +1 -1
- package/dist/components/layouts/HiddenChat.d.ts +4 -0
- package/dist/components/layouts/HiddenChat.js +51 -0
- package/dist/components/layouts/HiddenChat.js.map +1 -0
- package/dist/components/layouts/ZoomedFullBody.d.ts +4 -0
- package/dist/components/layouts/ZoomedFullBody.js +8 -0
- package/dist/components/layouts/ZoomedFullBody.js.map +1 -0
- package/dist/components/layouts/hidden-chat.css +184 -0
- package/dist/context/visemeContext.d.ts +27 -0
- package/dist/context/visemeContext.js +221 -0
- package/dist/context/visemeContext.js.map +1 -0
- package/dist/helpers/utils.d.ts +7 -0
- package/dist/helpers/utils.js +51 -1
- package/dist/helpers/utils.js.map +1 -1
- package/dist/index.js +20 -16
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -0
- package/esm/components/Avatar/Avatar.d.ts +2 -0
- package/esm/components/Avatar/Avatar.js +11 -6
- package/esm/components/Avatar/Avatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +20 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +102 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.d.ts +26 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.js +56 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +30 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +145 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +15 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +73 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.d.ts +5 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.js +9 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/loader.js.map +1 -0
- package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.d.ts +2 -1
- package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.js +3 -2
- package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/index.d.ts +6 -1
- package/esm/components/Avatar/AvatarView/index.js +16 -84
- package/esm/components/Avatar/AvatarView/index.js.map +1 -1
- package/esm/components/Avatar/AvatarView/utils/useEyeBlink.d.ts +16 -2
- package/esm/components/Avatar/AvatarView/utils/useEyeBlink.js +61 -38
- package/esm/components/Avatar/AvatarView/utils/useEyeBlink.js.map +1 -1
- package/esm/components/Avatar/AvatarView/utils/useMouthAnimation.d.ts +16 -0
- package/esm/components/Avatar/AvatarView/utils/useMouthAnimation.js +55 -0
- package/esm/components/Avatar/AvatarView/utils/useMouthAnimation.js.map +1 -0
- package/esm/components/Avatar/AvatarView/utils/useSmile.js +1 -1
- package/esm/components/Avatar/AvatarView/utils/useSmile.js.map +1 -1
- package/esm/components/ChatBubble/ChatBubble.js +2 -3
- package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.d.ts +1 -1
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js +24 -3
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.d.ts +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +26 -4
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/StartPanel/StartPanel.js +1 -1
- package/esm/components/StartPanel/StartPanel.js.map +1 -1
- package/esm/components/layouts/HiddenChat.d.ts +4 -0
- package/esm/components/layouts/HiddenChat.js +48 -0
- package/esm/components/layouts/HiddenChat.js.map +1 -0
- package/esm/components/layouts/ZoomedFullBody.d.ts +4 -0
- package/esm/components/layouts/ZoomedFullBody.js +5 -0
- package/esm/components/layouts/ZoomedFullBody.js.map +1 -0
- package/esm/components/layouts/hidden-chat.css +184 -0
- package/esm/context/visemeContext.d.ts +27 -0
- package/esm/context/visemeContext.js +216 -0
- package/esm/context/visemeContext.js.map +1 -0
- package/esm/helpers/utils.d.ts +7 -0
- package/esm/helpers/utils.js +45 -0
- package/esm/helpers/utils.js.map +1 -1
- package/esm/index.js +20 -16
- package/esm/index.js.map +1 -1
- package/esm/styles.css +1 -0
- package/package.json +2 -2
- package/src/components/Avatar/Avatar.test.tsx +28 -20
- package/src/components/Avatar/Avatar.tsx +19 -5
- package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +222 -0
- package/src/components/Avatar/AvatarView/{components → AvatarComponent/components}/controls.tsx +16 -10
- package/src/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.tsx +234 -0
- package/src/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.tsx +123 -0
- package/src/components/Avatar/AvatarView/{components → AvatarComponent/components}/loader.tsx +1 -1
- package/src/components/Avatar/AvatarView/AvatarView.stories.tsx +47 -8
- package/src/components/Avatar/AvatarView/index.tsx +47 -174
- package/src/components/Avatar/AvatarView/utils/useEyeBlink.ts +89 -48
- package/src/components/Avatar/AvatarView/utils/useMouthAnimation.ts +93 -0
- package/src/components/Avatar/AvatarView/utils/useSmile.ts +1 -1
- package/src/components/ChatBubble/ChatBubble.tsx +3 -4
- package/src/components/CompletionProviderStatus/CompletionProviderStatus.tsx +33 -3
- package/src/components/CompletionProviderStatus/__snapshots__/CompletionProviderStatus.test.tsx.snap +18 -0
- package/src/components/MemoriWidget/MemoriWidget.tsx +60 -5
- package/src/components/StartPanel/StartPanel.tsx +1 -1
- package/src/components/layouts/Chat.test.tsx +7 -5
- package/src/components/layouts/FullPage.test.tsx +11 -8
- package/src/components/layouts/HiddenChat.test.tsx +37 -0
- package/src/components/layouts/HiddenChat.tsx +108 -0
- package/src/components/layouts/Totem.test.tsx +6 -4
- package/src/components/layouts/WebsiteAssistant.test.tsx +7 -5
- package/src/components/layouts/ZoomedFullBody.test.tsx +37 -0
- package/src/components/layouts/ZoomedFullBody.tsx +55 -0
- package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +210 -0
- package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +444 -0
- package/src/components/layouts/hidden-chat.css +184 -0
- package/src/components/layouts/layouts.stories.tsx +135 -19
- package/src/context/visemeContext.tsx +328 -0
- package/src/helpers/utils.test.ts +18 -0
- package/src/helpers/utils.ts +73 -0
- package/src/index.stories.tsx +40 -17
- package/src/index.tsx +82 -78
- package/src/styles.css +1 -0
- package/src/components/Avatar/AvatarView/components/fullbodyAvatar.tsx +0 -120
- package/src/components/Avatar/AvatarView/components/halfbodyAvatar.tsx +0 -69
- package/src/components/Avatar/AvatarView/utils/useMouthSpeaking.ts +0 -87
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
stripEmojis,
|
|
4
4
|
stripMarkdown,
|
|
5
5
|
stripOutputTags,
|
|
6
|
+
escapeHTML,
|
|
6
7
|
} from './utils';
|
|
7
8
|
|
|
8
9
|
describe('Utils/difference', () => {
|
|
@@ -139,3 +140,20 @@ describe('utils/stripOutputTags', () => {
|
|
|
139
140
|
expect(result).toEqual('test\n');
|
|
140
141
|
});
|
|
141
142
|
});
|
|
143
|
+
|
|
144
|
+
describe('utils/parsing combined', () => {
|
|
145
|
+
it('should remove output tag from real message', () => {
|
|
146
|
+
const result = escapeHTML(
|
|
147
|
+
stripMarkdown(
|
|
148
|
+
stripEmojis(
|
|
149
|
+
stripOutputTags(`Beh... grazie, davvero. Non so cosa dire, sono lusingata. Ma... mi scusi se glielo chiedo, è sicuro che non ci sia stato un errore? Di solito ricevo più critiche che complimenti per il mio lavoro. So di impegnarmi molto, faccio spesso straordinari e salto persino la pausa pranzo per finire le pratiche. Però mi rendo conto che a volte ci sono imprecisioni e ritardi nelle consegne... Forse c'è qualcosa che non sto capendo?
|
|
150
|
+
|
|
151
|
+
<output class="memori-emotion">["timore"]</output>`)
|
|
152
|
+
)
|
|
153
|
+
)
|
|
154
|
+
);
|
|
155
|
+
expect(result).toEqual(
|
|
156
|
+
`Beh... grazie, davvero. Non so cosa dire, sono lusingata. Ma... mi scusi se glielo chiedo, è sicuro che non ci sia stato un errore? Di solito ricevo più critiche che complimenti per il mio lavoro. So di impegnarmi molto, faccio spesso straordinari e salto persino la pausa pranzo per finire le pratiche. Però mi rendo conto che a volte ci sono imprecisioni e ritardi nelle consegne... Forse c'è qualcosa che non sto capendo?`
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
});
|
package/src/helpers/utils.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { useState, useEffect, useRef, useMemo } from 'react';
|
|
2
|
+
import { Material, MeshStandardMaterial, SkinnedMesh } from 'three';
|
|
3
|
+
import * as THREE from 'three';
|
|
2
4
|
|
|
3
5
|
export const hasTouchscreen = (): boolean => {
|
|
4
6
|
let hasTouchScreen = false;
|
|
@@ -148,6 +150,7 @@ export const stripEmojis = (text: string) => {
|
|
|
148
150
|
|
|
149
151
|
export const stripMarkdown = (text: string) => {
|
|
150
152
|
// Remove code blocks
|
|
153
|
+
text = text.replaceAll(/```*?```/g, '');
|
|
151
154
|
text = text.replaceAll(/```[\s\S]*?```/g, '');
|
|
152
155
|
// Remove inline code
|
|
153
156
|
text = text.replaceAll(/`[^`]*`/g, '');
|
|
@@ -192,6 +195,12 @@ export const stripOutputTags = (text: string): string => {
|
|
|
192
195
|
return stripOutputTags(textBefore + textAfter);
|
|
193
196
|
};
|
|
194
197
|
|
|
198
|
+
export const stripHTML = (text: string) => {
|
|
199
|
+
const el = document.createElement('div');
|
|
200
|
+
el.innerHTML = text;
|
|
201
|
+
return el.textContent || '';
|
|
202
|
+
};
|
|
203
|
+
|
|
195
204
|
export const escapeHTML = (text: string) => {
|
|
196
205
|
const el = document.createElement('textarea');
|
|
197
206
|
el.textContent = text;
|
|
@@ -308,3 +317,67 @@ export const installMathJax = () => {
|
|
|
308
317
|
|
|
309
318
|
installMathJaxScript();
|
|
310
319
|
};
|
|
320
|
+
/**
|
|
321
|
+
* Corrects materials by setting some specific properties.
|
|
322
|
+
* This is often necessary when working with imported 3D models.
|
|
323
|
+
*
|
|
324
|
+
* @param materials - An object containing materials to be corrected.
|
|
325
|
+
*/
|
|
326
|
+
export function correctMaterials(materials: { [key: string]: Material }) {
|
|
327
|
+
Object.values(materials).forEach(material => {
|
|
328
|
+
if (material instanceof MeshStandardMaterial) {
|
|
329
|
+
// Improve the material's appearance
|
|
330
|
+
material.roughness = 0.8;
|
|
331
|
+
material.metalness = 0.1;
|
|
332
|
+
|
|
333
|
+
// Enable shadow casting and receiving
|
|
334
|
+
material.shadowSide = 2; // FrontSide and BackSide
|
|
335
|
+
|
|
336
|
+
// Improve texture rendering if the material uses textures
|
|
337
|
+
if (material.map) {
|
|
338
|
+
material.map.anisotropy = 16;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Type guard to check if an object is a SkinnedMesh.
|
|
346
|
+
* This is useful when working with 3D models that may contain different types of meshes.
|
|
347
|
+
*
|
|
348
|
+
* @param object - The object to check.
|
|
349
|
+
* @returns True if the object is a SkinnedMesh, false otherwise.
|
|
350
|
+
*/
|
|
351
|
+
export function isSkinnedMesh(object: any): object is SkinnedMesh {
|
|
352
|
+
return object.isSkinnedMesh === true;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Disposes of a Three.js object and its children recursively.
|
|
357
|
+
* This is important for memory management, especially when removing objects from the scene.
|
|
358
|
+
*
|
|
359
|
+
* @param object - The Three.js object to dispose.
|
|
360
|
+
*/
|
|
361
|
+
export function disposeObject(object: any) {
|
|
362
|
+
if ('geometry' in object && object.geometry instanceof THREE.BufferGeometry) {
|
|
363
|
+
object.geometry.dispose();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if ('material' in object) {
|
|
367
|
+
if (Array.isArray(object.material)) {
|
|
368
|
+
if (Array.isArray(object.material)) {
|
|
369
|
+
object.material.forEach((material: any) => {
|
|
370
|
+
if (material instanceof THREE.Material) {
|
|
371
|
+
material.dispose();
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
} else if (object && object.material instanceof THREE.Material) {
|
|
375
|
+
object.material.dispose();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (object.children) {
|
|
381
|
+
object.children.forEach(disposeObject);
|
|
382
|
+
}
|
|
383
|
+
}
|
package/src/index.stories.tsx
CHANGED
|
@@ -42,7 +42,7 @@ Localhost.args = {
|
|
|
42
42
|
ownerUserName: 'nicola',
|
|
43
43
|
memoriID: '1a9c75e8-57aa-4ce3-8ea5-256185fa79a7',
|
|
44
44
|
ownerUserID: '04a8cff9-13d6-4367-9cb2-72b9af9ee494',
|
|
45
|
-
tenantID: '
|
|
45
|
+
tenantID: 'www.aisuru.com',
|
|
46
46
|
apiURL: 'http://localhost:7778',
|
|
47
47
|
baseURL: 'http://localhost:3000',
|
|
48
48
|
uiLang: 'EN',
|
|
@@ -58,7 +58,7 @@ LocalhostBoE.args = {
|
|
|
58
58
|
ownerUserName: 'nicola',
|
|
59
59
|
memoriID: '2b094cd6-77b8-4e09-a807-0039b84c988e',
|
|
60
60
|
ownerUserID: '04a8cff9-13d6-4367-9cb2-72b9af9ee494',
|
|
61
|
-
tenantID: '
|
|
61
|
+
tenantID: 'www.aisuru.com',
|
|
62
62
|
apiURL: 'http://localhost:7778',
|
|
63
63
|
baseURL: 'http://localhost:3000',
|
|
64
64
|
uiLang: 'EN',
|
|
@@ -82,24 +82,50 @@ Staging.args = {
|
|
|
82
82
|
layout: 'FULLPAGE',
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
export const
|
|
86
|
-
|
|
87
|
-
memoriName: '
|
|
85
|
+
export const Giovanna = Template.bind({});
|
|
86
|
+
Giovanna.args = {
|
|
87
|
+
memoriName: 'Giovanna',
|
|
88
|
+
ownerUserName: 'memoridev',
|
|
89
|
+
memoriID: '3b308d07-0ff8-4f18-b885-fad501164c43',
|
|
90
|
+
ownerUserID: '13ab0379-a51d-4a83-8389-4f4b95e15567',
|
|
91
|
+
tenantID: 'www.aisuru.com',
|
|
92
|
+
engineURL: 'https://engine.memori.ai',
|
|
93
|
+
apiURL: 'https://backend.memori.ai',
|
|
94
|
+
baseURL: 'https://www.aisuru.com',
|
|
95
|
+
uiLang: 'IT',
|
|
96
|
+
spokenLang: 'IT',
|
|
97
|
+
layout: 'ZOOMED_FULL_BODY',
|
|
98
|
+
showInstruct: 'false',
|
|
99
|
+
showSettings: 'true',
|
|
100
|
+
showClear: 'false',
|
|
101
|
+
showAIicon: 'true',
|
|
102
|
+
showWhyThisAnswer: 'true',
|
|
103
|
+
showTypingText: 'false',
|
|
104
|
+
showOnlyLastMessages: 'false',
|
|
105
|
+
showTranslationOriginal: 'false',
|
|
106
|
+
showCopyButton: 'false',
|
|
107
|
+
showShare: 'true',
|
|
108
|
+
showLogin: 'false',
|
|
109
|
+
enableAudio: 'true',
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const GiovannaProva = Template.bind({});
|
|
113
|
+
GiovannaProva.args = {
|
|
114
|
+
memoriName: 'GiovannaProva',
|
|
88
115
|
ownerUserName: 'patini929',
|
|
89
|
-
memoriID: '
|
|
116
|
+
memoriID: 'aee4c0ab-66c0-4a4e-acf5-e7be0a3a8ddf',
|
|
90
117
|
ownerUserID: '1941d326-6986-4fa1-872b-458d09fb654c',
|
|
91
118
|
tenantID: 'www.aisuru.com',
|
|
92
119
|
engineURL: 'https://engine.memori.ai',
|
|
93
120
|
apiURL: 'https://backend.memori.ai',
|
|
94
121
|
baseURL: 'https://www.aisuru.com',
|
|
95
122
|
uiLang: 'IT',
|
|
96
|
-
spokenLang: '
|
|
97
|
-
layout: '
|
|
98
|
-
|
|
123
|
+
spokenLang: 'IT',
|
|
124
|
+
layout: 'ZOOMED_FULL_BODY',
|
|
99
125
|
showInstruct: false,
|
|
100
126
|
showSettings: true,
|
|
101
127
|
showClear: false,
|
|
102
|
-
showAIicon:
|
|
128
|
+
showAIicon: true,
|
|
103
129
|
showWhyThisAnswer: true,
|
|
104
130
|
showTypingText: false,
|
|
105
131
|
showOnlyLastMessages: false,
|
|
@@ -108,7 +134,6 @@ ProductionTotem.args = {
|
|
|
108
134
|
showShare: true,
|
|
109
135
|
showLogin: false,
|
|
110
136
|
enableAudio: true,
|
|
111
|
-
integrationID: '37d368cf-6241-4cc8-a1f3-742786f22431',
|
|
112
137
|
};
|
|
113
138
|
|
|
114
139
|
const TemplateWithBatchButton: Story<Props> = args => (
|
|
@@ -186,13 +211,11 @@ WithCustomUserAvatar.args = {
|
|
|
186
211
|
|
|
187
212
|
export const Test = Template.bind({});
|
|
188
213
|
Test.args = {
|
|
189
|
-
ownerUserName: '
|
|
190
|
-
memoriName: '
|
|
191
|
-
tenantID: '
|
|
192
|
-
apiURL: 'https://backend.memori.ai',
|
|
193
|
-
baseURL: 'https://bcc-iccrea.aclambda.online',
|
|
214
|
+
ownerUserName: 'dpezzettone',
|
|
215
|
+
memoriName: 'Meta Prompt Engineer',
|
|
216
|
+
tenantID: 'www.aisuru.com',
|
|
194
217
|
layout: 'CHAT',
|
|
195
|
-
uiLang: '
|
|
218
|
+
uiLang: 'en',
|
|
196
219
|
showShare: true,
|
|
197
220
|
showSettings: true,
|
|
198
221
|
showLogin: true,
|
package/src/index.tsx
CHANGED
|
@@ -16,7 +16,7 @@ import { installMathJax } from './helpers/utils';
|
|
|
16
16
|
import i18n from './i18n';
|
|
17
17
|
import { useTranslation } from 'react-i18next';
|
|
18
18
|
import I18nWrapper from './I18nWrapper';
|
|
19
|
-
|
|
19
|
+
import { VisemeProvider } from './context/visemeContext';
|
|
20
20
|
export interface Props {
|
|
21
21
|
memoriName?: string | null;
|
|
22
22
|
memoriID?: string | null;
|
|
@@ -223,85 +223,87 @@ const Memori: React.FC<Props> = ({
|
|
|
223
223
|
installMathJax();
|
|
224
224
|
}, []);
|
|
225
225
|
|
|
226
|
-
const renderer = memori ? (
|
|
227
|
-
<MemoriWidget
|
|
228
|
-
layout={layout}
|
|
229
|
-
customLayout={customLayout}
|
|
230
|
-
height={height}
|
|
231
|
-
baseUrl={
|
|
232
|
-
baseURL ||
|
|
233
|
-
(tenantID.startsWith('https://') ? tenantID : `https://${tenantID}`)
|
|
234
|
-
}
|
|
235
|
-
apiUrl={apiURL}
|
|
236
|
-
memori={{
|
|
237
|
-
...memori,
|
|
238
|
-
secretToken,
|
|
239
|
-
}}
|
|
240
|
-
ownerUserName={ownerUserName ?? memori.ownerUserName}
|
|
241
|
-
ownerUserID={ownerUserID ?? memori.ownerUserID}
|
|
242
|
-
tenantID={tenantID}
|
|
243
|
-
memoriLang={spokenLang ?? memori.culture?.split('-')?.[0]}
|
|
244
|
-
multilingual={multilingual}
|
|
245
|
-
tenant={tenant}
|
|
246
|
-
secret={secretToken}
|
|
247
|
-
sessionID={sessionID}
|
|
248
|
-
showShare={showShare}
|
|
249
|
-
showCopyButton={showCopyButton}
|
|
250
|
-
showTranslationOriginal={showTranslationOriginal}
|
|
251
|
-
showSettings={showSettings}
|
|
252
|
-
showInstruct={showInstruct}
|
|
253
|
-
showTypingText={showTypingText}
|
|
254
|
-
showClear={showClear}
|
|
255
|
-
showOnlyLastMessages={showOnlyLastMessages}
|
|
256
|
-
showInputs={showInputs}
|
|
257
|
-
showDates={showDates}
|
|
258
|
-
showContextPerLine={showContextPerLine}
|
|
259
|
-
showLogin={showLogin ?? memori?.enableDeepThought}
|
|
260
|
-
integration={memori?.integrations?.find(i =>
|
|
261
|
-
integrationID
|
|
262
|
-
? i.integrationID === integrationID
|
|
263
|
-
: !!i.publish && i.type === 'LANDING_EXPERIENCE'
|
|
264
|
-
)}
|
|
265
|
-
initialContextVars={context}
|
|
266
|
-
initialQuestion={initialQuestion}
|
|
267
|
-
authToken={authToken}
|
|
268
|
-
AZURE_COGNITIVE_SERVICES_TTS_KEY={
|
|
269
|
-
speechKey || AZURE_COGNITIVE_SERVICES_TTS_KEY
|
|
270
|
-
}
|
|
271
|
-
enableAudio={enableAudio}
|
|
272
|
-
defaultSpeakerActive={defaultSpeakerActive}
|
|
273
|
-
disableTextEnteredEvents={disableTextEnteredEvents}
|
|
274
|
-
onStateChange={onStateChange}
|
|
275
|
-
additionalInfo={additionalInfo}
|
|
276
|
-
customMediaRenderer={customMediaRenderer}
|
|
277
|
-
additionalSettings={additionalSettings}
|
|
278
|
-
userAvatar={userAvatar}
|
|
279
|
-
{...(tag && pin ? { personification: { tag, pin } } : {})}
|
|
280
|
-
/>
|
|
281
|
-
) : (
|
|
282
|
-
<div
|
|
283
|
-
style={{
|
|
284
|
-
display: 'flex',
|
|
285
|
-
alignItems: 'center',
|
|
286
|
-
justifyContent: 'center',
|
|
287
|
-
}}
|
|
288
|
-
>
|
|
289
|
-
<p
|
|
290
|
-
style={{
|
|
291
|
-
textAlign: 'center',
|
|
292
|
-
margin: '2rem auto',
|
|
293
|
-
textTransform: 'capitalize',
|
|
294
|
-
}}
|
|
295
|
-
>
|
|
296
|
-
{t('loading') || 'Loading'}...
|
|
297
|
-
</p>
|
|
298
|
-
</div>
|
|
299
|
-
);
|
|
300
|
-
|
|
301
226
|
return (
|
|
302
227
|
<I18nWrapper>
|
|
303
|
-
<
|
|
304
|
-
|
|
228
|
+
<VisemeProvider>
|
|
229
|
+
<Toaster position="top-center" reverseOrder={true} />
|
|
230
|
+
{memori ? (
|
|
231
|
+
<MemoriWidget
|
|
232
|
+
layout={layout}
|
|
233
|
+
customLayout={customLayout}
|
|
234
|
+
height={height}
|
|
235
|
+
baseUrl={
|
|
236
|
+
baseURL ||
|
|
237
|
+
(tenantID.startsWith('https://')
|
|
238
|
+
? tenantID
|
|
239
|
+
: `https://${tenantID}`)
|
|
240
|
+
}
|
|
241
|
+
apiUrl={apiURL}
|
|
242
|
+
memori={{
|
|
243
|
+
...memori,
|
|
244
|
+
secretToken,
|
|
245
|
+
}}
|
|
246
|
+
ownerUserName={ownerUserName ?? memori.ownerUserName}
|
|
247
|
+
ownerUserID={ownerUserID ?? memori.ownerUserID}
|
|
248
|
+
tenantID={tenantID}
|
|
249
|
+
memoriLang={spokenLang ?? memori.culture?.split('-')?.[0]}
|
|
250
|
+
multilingual={multilingual}
|
|
251
|
+
tenant={tenant}
|
|
252
|
+
secret={secretToken}
|
|
253
|
+
sessionID={sessionID}
|
|
254
|
+
showShare={showShare}
|
|
255
|
+
showCopyButton={showCopyButton}
|
|
256
|
+
showTranslationOriginal={showTranslationOriginal}
|
|
257
|
+
showSettings={showSettings}
|
|
258
|
+
showInstruct={showInstruct}
|
|
259
|
+
showTypingText={showTypingText}
|
|
260
|
+
showClear={showClear}
|
|
261
|
+
showOnlyLastMessages={showOnlyLastMessages}
|
|
262
|
+
showInputs={showInputs}
|
|
263
|
+
showDates={showDates}
|
|
264
|
+
showContextPerLine={showContextPerLine}
|
|
265
|
+
showLogin={showLogin ?? memori?.enableDeepThought}
|
|
266
|
+
integration={memori?.integrations?.find(i =>
|
|
267
|
+
integrationID
|
|
268
|
+
? i.integrationID === integrationID
|
|
269
|
+
: !!i.publish && i.type === 'LANDING_EXPERIENCE'
|
|
270
|
+
)}
|
|
271
|
+
initialContextVars={context}
|
|
272
|
+
initialQuestion={initialQuestion}
|
|
273
|
+
authToken={authToken}
|
|
274
|
+
AZURE_COGNITIVE_SERVICES_TTS_KEY={
|
|
275
|
+
speechKey || AZURE_COGNITIVE_SERVICES_TTS_KEY
|
|
276
|
+
}
|
|
277
|
+
enableAudio={enableAudio}
|
|
278
|
+
defaultSpeakerActive={defaultSpeakerActive}
|
|
279
|
+
disableTextEnteredEvents={disableTextEnteredEvents}
|
|
280
|
+
onStateChange={onStateChange}
|
|
281
|
+
additionalInfo={additionalInfo}
|
|
282
|
+
customMediaRenderer={customMediaRenderer}
|
|
283
|
+
additionalSettings={additionalSettings}
|
|
284
|
+
userAvatar={userAvatar}
|
|
285
|
+
{...(tag && pin ? { personification: { tag, pin } } : {})}
|
|
286
|
+
/>
|
|
287
|
+
) : (
|
|
288
|
+
<div
|
|
289
|
+
style={{
|
|
290
|
+
display: 'flex',
|
|
291
|
+
alignItems: 'center',
|
|
292
|
+
justifyContent: 'center',
|
|
293
|
+
}}
|
|
294
|
+
>
|
|
295
|
+
<p
|
|
296
|
+
style={{
|
|
297
|
+
textAlign: 'center',
|
|
298
|
+
margin: '2rem auto',
|
|
299
|
+
textTransform: 'capitalize',
|
|
300
|
+
}}
|
|
301
|
+
>
|
|
302
|
+
{t('loading') || 'Loading'}...
|
|
303
|
+
</p>
|
|
304
|
+
</div>
|
|
305
|
+
)}
|
|
306
|
+
</VisemeProvider>
|
|
305
307
|
</I18nWrapper>
|
|
306
308
|
);
|
|
307
309
|
};
|
|
@@ -321,6 +323,8 @@ Memori.propTypes = {
|
|
|
321
323
|
'TOTEM',
|
|
322
324
|
'WEBSITE_ASSISTANT',
|
|
323
325
|
'CHAT',
|
|
326
|
+
'HIDDEN_CHAT',
|
|
327
|
+
'ZOOMED_FULL_BODY',
|
|
324
328
|
]),
|
|
325
329
|
customLayout: PropTypes.any,
|
|
326
330
|
showShare: PropTypes.bool,
|
package/src/styles.css
CHANGED
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
|
|
49
49
|
@import url('https://fonts.bunny.net/css?family=lexend-deca:200,400,700');
|
|
50
50
|
|
|
51
|
+
@import url('./components/layouts/hidden-chat.css');
|
|
51
52
|
@import url('./components/layouts/totem.css');
|
|
52
53
|
@import url('./components/layouts/website-assistant.css');
|
|
53
54
|
@import url('./components/layouts/chat.css');
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
Vector3,
|
|
4
|
-
Euler,
|
|
5
|
-
AnimationMixer,
|
|
6
|
-
AnimationAction,
|
|
7
|
-
AnimationClip,
|
|
8
|
-
} from 'three';
|
|
9
|
-
import { useAnimations, useGLTF } from '@react-three/drei';
|
|
10
|
-
import { useGraph, dispose, useFrame } from '@react-three/fiber';
|
|
11
|
-
import { correctMaterials, isSkinnedMesh } from '../utils/utils';
|
|
12
|
-
import useEyeBlink from '../utils/useEyeBlink';
|
|
13
|
-
import useMouthSpeaking from '../utils/useMouthSpeaking';
|
|
14
|
-
import useHeadMovement from '../utils/useHeadMovement';
|
|
15
|
-
import useSmile from '../utils/useSmile';
|
|
16
|
-
|
|
17
|
-
export interface FullbodyAvatarProps {
|
|
18
|
-
url: string;
|
|
19
|
-
sex: 'MALE' | 'FEMALE';
|
|
20
|
-
onLoaded?: () => void;
|
|
21
|
-
currentBaseAction: {
|
|
22
|
-
action: string;
|
|
23
|
-
weight: number;
|
|
24
|
-
};
|
|
25
|
-
additiveActions: {
|
|
26
|
-
[key: string]: {
|
|
27
|
-
weight: number;
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
timeScale: number;
|
|
31
|
-
loading?: boolean;
|
|
32
|
-
speaking?: boolean;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const AVATAR_POSITION = new Vector3(0, -1, 0);
|
|
36
|
-
const AVATAR_ROTATION = new Euler(0.175, 0, 0);
|
|
37
|
-
const ANIMATION_URLS = {
|
|
38
|
-
MALE: 'https://assets.memori.ai/api/v2/asset/5de7456f-0cd8-4e29-95a7-0cd0045a5325.glb',
|
|
39
|
-
FEMALE:
|
|
40
|
-
'https://assets.memori.ai/api/v2/asset/84487a2b-377c-4565-800a-51459d580ec8.glb',
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export default function FullbodyAvatar({
|
|
44
|
-
url,
|
|
45
|
-
sex,
|
|
46
|
-
onLoaded,
|
|
47
|
-
currentBaseAction,
|
|
48
|
-
additiveActions,
|
|
49
|
-
timeScale
|
|
50
|
-
}: FullbodyAvatarProps) {
|
|
51
|
-
const { scene } = useGLTF(url);
|
|
52
|
-
const { animations } = useGLTF(ANIMATION_URLS[sex]);
|
|
53
|
-
const { nodes, materials } = useGraph(scene);
|
|
54
|
-
const { actions } = useAnimations(animations, scene);
|
|
55
|
-
const [mixer] = useState(() => new AnimationMixer(scene));
|
|
56
|
-
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
correctMaterials(materials);
|
|
59
|
-
onLoaded?.();
|
|
60
|
-
|
|
61
|
-
return () => {
|
|
62
|
-
Object.values(materials).forEach(dispose);
|
|
63
|
-
Object.values(nodes).filter(isSkinnedMesh).forEach(dispose);
|
|
64
|
-
};
|
|
65
|
-
}, [materials, nodes, url, onLoaded]);
|
|
66
|
-
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (!actions || !currentBaseAction.action) return;
|
|
69
|
-
|
|
70
|
-
const newAction = actions[currentBaseAction.action];
|
|
71
|
-
|
|
72
|
-
if (!newAction) {
|
|
73
|
-
console.warn(
|
|
74
|
-
`Animation "${currentBaseAction.action}" not found in actions.`
|
|
75
|
-
);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const fadeOutDuration = 0.8;
|
|
80
|
-
const fadeInDuration = 0.8;
|
|
81
|
-
|
|
82
|
-
newAction.timeScale = timeScale;
|
|
83
|
-
newAction.reset().fadeIn(fadeInDuration).play();
|
|
84
|
-
|
|
85
|
-
return () => {
|
|
86
|
-
newAction.fadeOut(fadeOutDuration);
|
|
87
|
-
};
|
|
88
|
-
}, [currentBaseAction, timeScale]);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// useEffect(() => {
|
|
94
|
-
// if (speaking && actions['Talk 1'] && actions['Talk 2']) {
|
|
95
|
-
// const talk1 = actions['Talk 1'].getClip();
|
|
96
|
-
// const talk2 = actions['Talk 2'].getClip();
|
|
97
|
-
// const talk = new AnimationClip(
|
|
98
|
-
// 'Talk',
|
|
99
|
-
// talk1.duration + talk2.duration,
|
|
100
|
-
// );
|
|
101
|
-
// mixer.clipAction(talk, scene).play();
|
|
102
|
-
// }
|
|
103
|
-
// }, [speaking]);
|
|
104
|
-
|
|
105
|
-
// Additive actions
|
|
106
|
-
useEyeBlink(additiveActions.blink.weight > 0, nodes);
|
|
107
|
-
useMouthSpeaking(additiveActions.speak.weight > 0, nodes);
|
|
108
|
-
useHeadMovement(additiveActions.headMovement.weight > 0, nodes);
|
|
109
|
-
useSmile(additiveActions.smile.weight > 0, nodes);
|
|
110
|
-
|
|
111
|
-
useFrame((_, delta) => {
|
|
112
|
-
mixer.update(delta * 0.001);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
return (
|
|
116
|
-
<group position={AVATAR_POSITION} rotation={AVATAR_ROTATION}>
|
|
117
|
-
<primitive object={scene} />
|
|
118
|
-
</group>
|
|
119
|
-
);
|
|
120
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useMemo } from 'react';
|
|
2
|
-
import { Object3D, Vector3 } from 'three';
|
|
3
|
-
import { useGLTF } from '@react-three/drei';
|
|
4
|
-
import useEyeBlink from '../utils/useEyeBlink';
|
|
5
|
-
import useHeadMovement from '../utils/useHeadMovement';
|
|
6
|
-
import useMouthSpeaking from '../utils/useMouthSpeaking';
|
|
7
|
-
import { dispose, useGraph } from '@react-three/fiber';
|
|
8
|
-
import { correctMaterials, hideHands, isSkinnedMesh } from '../utils/utils';
|
|
9
|
-
|
|
10
|
-
interface HalfBodyAvatarProps {
|
|
11
|
-
url: string;
|
|
12
|
-
eyeBlink?: boolean;
|
|
13
|
-
headMovement?: boolean;
|
|
14
|
-
speaking?: boolean;
|
|
15
|
-
onLoaded?: () => void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const AVATAR_POSITION = new Vector3(0, -0.6, 0);
|
|
19
|
-
|
|
20
|
-
export default function HalfBodyAvatar({
|
|
21
|
-
url,
|
|
22
|
-
eyeBlink,
|
|
23
|
-
headMovement,
|
|
24
|
-
speaking,
|
|
25
|
-
onLoaded,
|
|
26
|
-
}: HalfBodyAvatarProps) {
|
|
27
|
-
const { scene } = useGLTF(url);
|
|
28
|
-
const { nodes, materials } = useGraph(scene);
|
|
29
|
-
|
|
30
|
-
useEyeBlink(eyeBlink, nodes);
|
|
31
|
-
useHeadMovement(headMovement, nodes);
|
|
32
|
-
useMouthSpeaking(!!speaking, nodes);
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
const setupAvatar = () => {
|
|
36
|
-
hideHands(nodes);
|
|
37
|
-
correctMaterials(materials);
|
|
38
|
-
onLoaded?.();
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
setupAvatar();
|
|
42
|
-
|
|
43
|
-
return () => {
|
|
44
|
-
const disposeObjects = () => {
|
|
45
|
-
Object.values(materials).forEach(dispose);
|
|
46
|
-
Object.values(nodes).filter(isSkinnedMesh).forEach(dispose);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
disposeObjects();
|
|
50
|
-
};
|
|
51
|
-
}, [materials, nodes, url, onLoaded]);
|
|
52
|
-
|
|
53
|
-
const skinnedMeshes = useMemo(
|
|
54
|
-
() => Object.values(nodes).filter(isSkinnedMesh),
|
|
55
|
-
[nodes]
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<group position={AVATAR_POSITION}>
|
|
60
|
-
{nodes.Hips && <primitive key="armature" object={nodes.Hips} />}
|
|
61
|
-
{skinnedMeshes.map(
|
|
62
|
-
(node: Object3D) =>
|
|
63
|
-
node && (
|
|
64
|
-
<primitive key={node.name} object={node} receiveShadow castShadow />
|
|
65
|
-
)
|
|
66
|
-
)}
|
|
67
|
-
</group>
|
|
68
|
-
);
|
|
69
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { Nodes } from './utils';
|
|
2
|
-
import { SkinnedMesh } from 'three';
|
|
3
|
-
import { useEffect, useRef, useCallback } from 'react';
|
|
4
|
-
import { useFrame } from '@react-three/fiber';
|
|
5
|
-
|
|
6
|
-
interface MouthState {
|
|
7
|
-
moveTime: number;
|
|
8
|
-
mesh: SkinnedMesh | null;
|
|
9
|
-
morphIndices: {
|
|
10
|
-
open: number;
|
|
11
|
-
smile: number;
|
|
12
|
-
funner: number;
|
|
13
|
-
pucker: number;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const MOUTH_MOVE_DURATION = 2;
|
|
18
|
-
const MOUTH_MOVE_INTERVAL_MIN = 100;
|
|
19
|
-
const MOUTH_MOVE_INTERVAL_MAX = 500;
|
|
20
|
-
|
|
21
|
-
export default function useMouthSpeaking(speaking: boolean | undefined, nodes: Nodes) {
|
|
22
|
-
const mouthStateRef = useRef<MouthState>({
|
|
23
|
-
moveTime: 999,
|
|
24
|
-
mesh: null,
|
|
25
|
-
morphIndices: { open: 0, smile: 0, funner: 0, pucker: 0 },
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const setNextMouthMove = useCallback(() => {
|
|
29
|
-
mouthStateRef.current.moveTime = 0;
|
|
30
|
-
const nextMoveDelay = Math.random() * (MOUTH_MOVE_INTERVAL_MAX - MOUTH_MOVE_INTERVAL_MIN) + MOUTH_MOVE_INTERVAL_MIN;
|
|
31
|
-
setTimeout(setNextMouthMove, nextMoveDelay);
|
|
32
|
-
}, []);
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
if (!speaking) return;
|
|
36
|
-
|
|
37
|
-
const mouthMesh = (nodes.Wolf3D_Head || nodes.Wolf3D_Avatar || nodes.Wolf3D_Avatar001) as SkinnedMesh;
|
|
38
|
-
mouthStateRef.current.mesh = mouthMesh;
|
|
39
|
-
|
|
40
|
-
if (mouthMesh?.morphTargetDictionary && mouthMesh?.morphTargetInfluences) {
|
|
41
|
-
mouthStateRef.current.morphIndices = {
|
|
42
|
-
open: mouthMesh.morphTargetDictionary.mouthOpen,
|
|
43
|
-
smile: mouthMesh.morphTargetDictionary.mouthSmile,
|
|
44
|
-
funner: mouthMesh.morphTargetDictionary.mouthFunner,
|
|
45
|
-
pucker: mouthMesh.morphTargetDictionary.mouthPucker,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const initialMoveDelay = setTimeout(setNextMouthMove, 200);
|
|
50
|
-
|
|
51
|
-
return () => {
|
|
52
|
-
clearTimeout(initialMoveDelay);
|
|
53
|
-
};
|
|
54
|
-
}, [nodes, speaking, setNextMouthMove]);
|
|
55
|
-
|
|
56
|
-
useFrame((_, delta) => {
|
|
57
|
-
const { moveTime, mesh, morphIndices } = mouthStateRef.current;
|
|
58
|
-
|
|
59
|
-
if (!speaking || !mesh?.morphTargetInfluences) {
|
|
60
|
-
resetMouthShape(mesh, morphIndices);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (moveTime < MOUTH_MOVE_DURATION) {
|
|
65
|
-
const value = Math.abs(Math.sin((moveTime * Math.PI) / 2));
|
|
66
|
-
mouthStateRef.current.moveTime += delta * 10;
|
|
67
|
-
updateMouthShape(mesh, morphIndices, value);
|
|
68
|
-
} else {
|
|
69
|
-
resetMouthShape(mesh, morphIndices);
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function updateMouthShape(mesh: SkinnedMesh, morphIndices: MouthState['morphIndices'], value: number) {
|
|
75
|
-
mesh.morphTargetInfluences![morphIndices.open] = value / 3;
|
|
76
|
-
mesh.morphTargetInfluences![morphIndices.smile] = value / 10;
|
|
77
|
-
mesh.morphTargetInfluences![morphIndices.funner] = value / 7;
|
|
78
|
-
mesh.morphTargetInfluences![morphIndices.pucker] = value / 5;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function resetMouthShape(mesh: SkinnedMesh | null, morphIndices: MouthState['morphIndices']) {
|
|
82
|
-
if (!mesh?.morphTargetInfluences) return;
|
|
83
|
-
mesh.morphTargetInfluences[morphIndices.open] = 0;
|
|
84
|
-
mesh.morphTargetInfluences[morphIndices.smile] = 0;
|
|
85
|
-
mesh.morphTargetInfluences[morphIndices.funner] = 0;
|
|
86
|
-
mesh.morphTargetInfluences[morphIndices.pucker] = 0;
|
|
87
|
-
}
|