@memori.ai/memori-react 7.19.2 → 7.21.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 (111) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/components/Avatar/AvatarView/AvatarComponent/Shadow/DynamicShadow.d.ts +3 -2
  3. package/dist/components/Avatar/AvatarView/AvatarComponent/Shadow/DynamicShadow.js +13 -6
  4. package/dist/components/Avatar/AvatarView/AvatarComponent/Shadow/DynamicShadow.js.map +1 -1
  5. package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +14 -18
  6. package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +19 -77
  7. package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
  8. package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.d.ts +17 -2
  9. package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +95 -70
  10. package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
  11. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.d.ts +65 -0
  12. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js +747 -0
  13. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js.map +1 -0
  14. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.d.ts +9 -2
  15. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js +60 -2
  16. package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js.map +1 -1
  17. package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +3 -4
  18. package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +5 -11
  19. package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
  20. package/dist/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +13 -52
  21. package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js +68 -70
  22. package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js.map +1 -1
  23. package/dist/components/Avatar/AvatarView/index.d.ts +1 -1
  24. package/dist/components/Avatar/AvatarView/index.js +2 -2
  25. package/dist/components/Avatar/AvatarView/index.js.map +1 -1
  26. package/dist/components/ChatBubble/ChatBubble.css +9 -0
  27. package/dist/components/ChatBubble/ChatBubble.js +7 -1
  28. package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
  29. package/dist/components/MemoriWidget/MemoriWidget.js +130 -62
  30. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  31. package/dist/components/UploadButton/UploadButton.js +2 -2
  32. package/dist/components/UploadButton/UploadButton.js.map +1 -1
  33. package/dist/components/WhyThisAnswer/WhyThisAnswer.css +43 -0
  34. package/dist/components/WhyThisAnswer/WhyThisAnswer.js +2 -1
  35. package/dist/components/WhyThisAnswer/WhyThisAnswer.js.map +1 -1
  36. package/dist/context/visemeContext.js +0 -39
  37. package/dist/context/visemeContext.js.map +1 -1
  38. package/dist/locales/de.json +1 -0
  39. package/dist/locales/en.json +1 -0
  40. package/dist/locales/es.json +1 -0
  41. package/dist/locales/fr.json +1 -0
  42. package/dist/locales/it.json +1 -0
  43. package/esm/components/Avatar/AvatarView/AvatarComponent/Shadow/DynamicShadow.d.ts +3 -2
  44. package/esm/components/Avatar/AvatarView/AvatarComponent/Shadow/DynamicShadow.js +13 -6
  45. package/esm/components/Avatar/AvatarView/AvatarComponent/Shadow/DynamicShadow.js.map +1 -1
  46. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +14 -18
  47. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +20 -78
  48. package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
  49. package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.d.ts +17 -2
  50. package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +99 -74
  51. package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
  52. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.d.ts +65 -0
  53. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js +743 -0
  54. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.js.map +1 -0
  55. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.d.ts +9 -2
  56. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js +61 -3
  57. package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js.map +1 -1
  58. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +3 -4
  59. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +5 -11
  60. package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
  61. package/esm/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +13 -52
  62. package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js +67 -69
  63. package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js.map +1 -1
  64. package/esm/components/Avatar/AvatarView/index.d.ts +1 -1
  65. package/esm/components/Avatar/AvatarView/index.js +2 -2
  66. package/esm/components/Avatar/AvatarView/index.js.map +1 -1
  67. package/esm/components/ChatBubble/ChatBubble.css +9 -0
  68. package/esm/components/ChatBubble/ChatBubble.js +7 -1
  69. package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
  70. package/esm/components/MemoriWidget/MemoriWidget.js +130 -62
  71. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  72. package/esm/components/UploadButton/UploadButton.js +2 -2
  73. package/esm/components/UploadButton/UploadButton.js.map +1 -1
  74. package/esm/components/WhyThisAnswer/WhyThisAnswer.css +43 -0
  75. package/esm/components/WhyThisAnswer/WhyThisAnswer.js +2 -1
  76. package/esm/components/WhyThisAnswer/WhyThisAnswer.js.map +1 -1
  77. package/esm/context/visemeContext.js +0 -39
  78. package/esm/context/visemeContext.js.map +1 -1
  79. package/esm/locales/de.json +1 -0
  80. package/esm/locales/en.json +1 -0
  81. package/esm/locales/es.json +1 -0
  82. package/esm/locales/fr.json +1 -0
  83. package/esm/locales/it.json +1 -0
  84. package/package.json +2 -2
  85. package/src/components/Avatar/AvatarView/AvatarComponent/Shadow/DynamicShadow.tsx +15 -8
  86. package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +64 -219
  87. package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.tsx +221 -124
  88. package/src/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarAnimator.ts +1250 -0
  89. package/src/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.ts +164 -8
  90. package/src/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.tsx +19 -17
  91. package/src/components/Avatar/AvatarView/AvatarComponent/constants.ts +80 -79
  92. package/src/components/Avatar/AvatarView/index.tsx +1 -7
  93. package/src/components/ChatBubble/ChatBubble.css +9 -0
  94. package/src/components/ChatBubble/ChatBubble.tsx +14 -2
  95. package/src/components/MemoriWidget/MemoriWidget.tsx +168 -76
  96. package/src/components/UploadButton/UploadButton.tsx +4 -4
  97. package/src/components/UploadButton/__snapshots__/UploadButton.test.tsx.snap +1 -1
  98. package/src/components/WhyThisAnswer/WhyThisAnswer.css +43 -0
  99. package/src/components/WhyThisAnswer/WhyThisAnswer.stories.tsx +44 -3
  100. package/src/components/WhyThisAnswer/WhyThisAnswer.test.tsx +128 -8
  101. package/src/components/WhyThisAnswer/WhyThisAnswer.tsx +28 -3
  102. package/src/components/WhyThisAnswer/__snapshots__/WhyThisAnswer.test.tsx.snap +15 -1
  103. package/src/components/layouts/layouts.stories.tsx +0 -8
  104. package/src/context/visemeContext.tsx +40 -41
  105. package/src/index.stories.tsx +63 -65
  106. package/src/locales/de.json +1 -0
  107. package/src/locales/en.json +1 -0
  108. package/src/locales/es.json +1 -0
  109. package/src/locales/fr.json +1 -0
  110. package/src/locales/it.json +1 -0
  111. package/src/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.ts +0 -308
@@ -1,6 +1,14 @@
1
1
  import { SkinnedMesh } from 'three';
2
2
  import { MathUtils } from 'three';
3
- import { EMOTION_SMOOTHING, VISEME_SMOOTHING, BLINK_CONFIG } from '../../constants';
3
+ import {
4
+ EMOTION_SMOOTHING,
5
+ VISEME_SMOOTHING,
6
+ BLINK_CONFIG,
7
+ MAPPING_EMOTIONS_ITALIAN_TO_ENGLISH,
8
+ MAPPING_BLEND_SHAPE_TO_EMOTION_RPM,
9
+ EmotionMapping,
10
+ BlendShapeMap,
11
+ } from '../../constants';
4
12
 
5
13
  /**
6
14
  * Controller class for handling morph target animations including emotions, visemes and blinking
@@ -9,16 +17,155 @@ export class MorphTargetController {
9
17
  private headMesh: SkinnedMesh;
10
18
  private currentEmotionValues: Record<string, number> = {};
11
19
  private previousEmotionKeys: Set<string> = new Set();
20
+ private isRPM: boolean = false;
12
21
 
13
- constructor(headMesh: SkinnedMesh) {
22
+ // Default RPM blend shape mappings
23
+ private rpmBlendShapes: BlendShapeMap =
24
+ MAPPING_BLEND_SHAPE_TO_EMOTION_RPM as BlendShapeMap;
25
+
26
+ // Default custom GLB emotion mappings
27
+ private customGlbMapping: EmotionMapping =
28
+ MAPPING_EMOTIONS_ITALIAN_TO_ENGLISH as EmotionMapping;
29
+
30
+ /**
31
+ * Constructor for MorphTargetController
32
+ * @param headMesh SkinnedMesh representing the head
33
+ * @param rpmBlendShapes Optional custom RPM blend shapes
34
+ * @param customGlbMapping Optional custom GLB emotion mapping
35
+ */
36
+ constructor(
37
+ headMesh: SkinnedMesh,
38
+ rpmBlendShapes?: BlendShapeMap,
39
+ customGlbMapping?: EmotionMapping
40
+ ) {
14
41
  this.headMesh = headMesh;
42
+
43
+ // Detect if this is an RPM avatar based on mesh name
44
+ this.isRPM = headMesh.name !== 'GBNL__Head';
45
+
46
+ // Override default maps if provided
47
+ if (rpmBlendShapes) {
48
+ this.rpmBlendShapes = rpmBlendShapes;
49
+ }
50
+
51
+ if (customGlbMapping) {
52
+ this.customGlbMapping = customGlbMapping;
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Process chat emission to extract emotion data
58
+ * @param chatEmission Chat emission text
59
+ * @param isLoading Loading state
60
+ * @returns Object with emotion morph targets
61
+ */
62
+ processChatEmission(
63
+ chatEmission: any,
64
+ isLoading: boolean
65
+ ): Record<string, number> {
66
+ // Default empty emotion targets
67
+ const defaultEmotions = this.getDefaultEmotionMorphTargets();
68
+
69
+ // If loading or no chat emission, return default emotions
70
+ if (isLoading || !chatEmission) {
71
+ return defaultEmotions;
72
+ }
73
+
74
+ // Check if chat emission contains emotion tag
75
+ const hasOutputTagEmotion = chatEmission?.includes(
76
+ '<output class="memori-emotion">'
77
+ );
78
+
79
+ if (!hasOutputTagEmotion) {
80
+ return defaultEmotions;
81
+ }
82
+
83
+ // Extract emotion name
84
+ const outputContentEmotion = chatEmission
85
+ ?.split('<output class="memori-emotion">')[1]
86
+ ?.split('</output>')[0]
87
+ ?.trim();
88
+
89
+ if (!outputContentEmotion) {
90
+ return defaultEmotions;
91
+ }
92
+
93
+ // Process emotion based on avatar type
94
+ return this.processEmotion(outputContentEmotion);
95
+ }
96
+
97
+ /**
98
+ * Process an emotion name into morph target values
99
+ * @param emotionName Emotion name (in Italian or English)
100
+ * @returns Object with morph target values
101
+ */
102
+ private processEmotion(emotionName: string): Record<string, number> {
103
+ // Get default empty emotion targets
104
+ const defaultEmotions = this.getDefaultEmotionMorphTargets();
105
+
106
+ // First, try to find the emotion regardless of language
107
+ if (this.isRPM) {
108
+ // For RPM avatars, find the matching emotion in the rpmBlendShapes array
109
+ const foundEmotion = this.rpmBlendShapes.find(
110
+ item =>
111
+ item.emotion.italian.toLowerCase() === emotionName.toLowerCase() ||
112
+ item.emotion.english.toLowerCase() === emotionName.toLowerCase()
113
+ );
114
+
115
+ if (foundEmotion) {
116
+ return { ...defaultEmotions, ...foundEmotion.blendShapes };
117
+ }
118
+ } else {
119
+ // For custom GLB, find the matching emotion in the customGlbMapping array
120
+ const foundEmotion = this.customGlbMapping.find(
121
+ item =>
122
+ item.italian.toLowerCase() === emotionName.toLowerCase() ||
123
+ item.english.toLowerCase() === emotionName.toLowerCase()
124
+ );
125
+
126
+ if (foundEmotion) {
127
+ return { ...defaultEmotions, [foundEmotion.english]: 1 };
128
+ }
129
+ }
130
+
131
+ console.log('[MorphTargetController] No emotion found:', emotionName);
132
+ return defaultEmotions;
133
+ }
134
+
135
+ /**
136
+ * Get default emotion morph targets (all set to 0)
137
+ */
138
+ private getDefaultEmotionMorphTargets(): Record<string, number> {
139
+ // For RPM, collect all blend shape keys
140
+ if (this.isRPM) {
141
+ const allBlendShapeKeys = new Set<string>();
142
+
143
+ this.rpmBlendShapes.forEach(item => {
144
+ Object.keys(item.blendShapes).forEach(key =>
145
+ allBlendShapeKeys.add(key)
146
+ );
147
+ });
148
+
149
+ return Array.from(allBlendShapeKeys).reduce(
150
+ (acc, key) => ({ ...acc, [key]: 0 }),
151
+ {}
152
+ );
153
+ }
154
+ // For custom GLB, use English emotion names
155
+ else {
156
+ return this.customGlbMapping.reduce(
157
+ (acc, emotion) => ({ ...acc, [emotion.english]: 0 }),
158
+ {}
159
+ );
160
+ }
15
161
  }
16
162
  /**
17
163
  * Updates the morph target influences for emotions, visemes and blinking
18
164
  */
19
165
  updateMorphTargets(
20
166
  currentTime: number,
21
- emotionMorphTargets: Record<string, number>,
167
+ chatEmission: any,
168
+ isLoading: boolean,
22
169
  currentViseme: { name: string; weight: number } | null,
23
170
  eyeBlink: boolean,
24
171
  blinkState: {
@@ -33,17 +180,25 @@ export class MorphTargetController {
33
180
  !this.headMesh.morphTargetDictionary ||
34
181
  !this.headMesh.morphTargetInfluences
35
182
  ) {
36
- console.error('[MorphTargetController] Missing morphTargetDictionary or morphTargetInfluences');
183
+ console.error(
184
+ '[MorphTargetController] Missing morphTargetDictionary or morphTargetInfluences'
185
+ );
37
186
  return;
38
187
  }
39
188
 
189
+ // Process chat emission to get emotion morph targets
190
+ const emotionMorphTargets = this.processChatEmission(
191
+ chatEmission,
192
+ isLoading
193
+ );
194
+
40
195
  // Calculate blink value for this frame
41
196
  const blinkValue = this.calculateBlinkValue(
42
197
  currentTime,
43
198
  blinkState,
44
199
  eyeBlink
45
200
  );
46
-
201
+
47
202
  const currentEmotionKeys = new Set(Object.keys(emotionMorphTargets));
48
203
 
49
204
  // Process each morph target
@@ -55,6 +210,7 @@ export class MorphTargetController {
55
210
 
56
211
  // Handle emotion morphs with smoothing
57
212
  if (currentEmotionKeys.has(key)) {
213
+ // console.log('[MorphTargetController] Processing morph target:', key);
58
214
  const targetEmotionValue = emotionMorphTargets[key];
59
215
  const currentEmotionValue = this.currentEmotionValues[key] || 0;
60
216
  const newEmotionValue = MathUtils.lerp(
@@ -124,15 +280,15 @@ export class MorphTargetController {
124
280
  if (blinkState.isBlinking) {
125
281
  const blinkProgress =
126
282
  (currentTime - blinkState.blinkStartTime) / BLINK_CONFIG.blinkDuration;
127
-
283
+
128
284
  // First half of blink - closing eyes
129
285
  if (blinkProgress <= 0.5) {
130
286
  blinkValue = blinkProgress * 2;
131
- }
287
+ }
132
288
  // Second half of blink - opening eyes
133
289
  else if (blinkProgress <= 1) {
134
290
  blinkValue = 2 - blinkProgress * 2;
135
- }
291
+ }
136
292
  // Blink complete
137
293
  else {
138
294
  blinkState.isBlinking = false;
@@ -15,22 +15,19 @@ import useHeadMovement from '../../utils/useHeadMovement';
15
15
 
16
16
  interface HalfBodyAvatarProps {
17
17
  url: string;
18
- setMorphTargetInfluences: (morphTargetInfluences: any) => void;
19
- setMorphTargetDictionary: (morphTargetDictionary: any) => void;
20
18
  updateCurrentViseme: (currentTime: number) => any;
21
19
  eyeBlink?: boolean;
22
- heightValue?: number; // 0-100 slider value
23
20
  avatarHeight: number;
24
21
  avatarDepth: number;
25
22
  onLoaded?: () => void;
26
23
  onCameraZChange: (value: number) => void;
27
24
  headMovement?: boolean;
25
+ chatEmission?: any;
26
+ loading?: boolean;
28
27
  }
29
28
 
30
29
  export default function HalfBodyAvatar({
31
30
  url,
32
- setMorphTargetInfluences,
33
- setMorphTargetDictionary,
34
31
  updateCurrentViseme,
35
32
  eyeBlink = false,
36
33
  avatarHeight = 50,
@@ -38,18 +35,22 @@ export default function HalfBodyAvatar({
38
35
  headMovement = false,
39
36
  onLoaded,
40
37
  onCameraZChange,
38
+ chatEmission,
39
+ loading = false,
41
40
  }: HalfBodyAvatarProps) {
42
41
  const { scene } = useGLTF(url);
43
42
  const { nodes, materials } = useGraph(scene);
44
43
  const { camera } = useThree();
45
44
 
46
- const morphTargetControllerRef = useRef<MorphTargetController>();
47
- const positionControllerRef = useRef<AvatarPositionController>();
45
+ const morphTargetControllerRef = useRef<MorphTargetController | null>(null);
46
+ const positionControllerRef = useRef<AvatarPositionController | null>(null);
48
47
  const targetCameraZRef = useRef(camera.position.z);
49
48
 
50
-
49
+ // Apply head movement if enabled
51
50
  useHeadMovement(headMovement, nodes);
52
51
 
52
+
53
+ // Eye blinking state
53
54
  const blinkStateRef = useRef({
54
55
  isBlinking: false,
55
56
  lastBlinkTime: 0,
@@ -63,7 +64,7 @@ export default function HalfBodyAvatar({
63
64
  scene?.traverse((object: Object3D) => {
64
65
  if (
65
66
  object instanceof SkinnedMesh &&
66
- (object.name === 'GBNL__Head' || object.name === 'Wolf3D_Avatar')
67
+ (object.name === 'GBNL__Head' || object.name === 'Wolf3D_Avatar' || object.name === 'Wolf3D_Avatar006_1')
67
68
  ) {
68
69
  foundMesh = object;
69
70
  }
@@ -80,21 +81,17 @@ export default function HalfBodyAvatar({
80
81
  );
81
82
  }
82
83
 
84
+ // Initialize MorphTargetController if head mesh exists
83
85
  if (headMesh) {
84
86
  morphTargetControllerRef.current = new MorphTargetController(headMesh);
85
-
86
- if (headMesh.morphTargetDictionary && headMesh.morphTargetInfluences) {
87
- setMorphTargetDictionary(headMesh.morphTargetDictionary);
88
- const initialInfluences = Object.keys(headMesh.morphTargetDictionary)
89
- .reduce((acc, key) => ({ ...acc, [key]: 0 }), {});
90
- setMorphTargetInfluences(initialInfluences);
91
- }
92
87
  }
93
88
 
89
+ // Correct materials and perform other initialization tasks
94
90
  correctMaterials(materials);
95
91
  onLoaded?.();
96
92
  hideHands(nodes);
97
93
 
94
+ // Cleanup on unmount
98
95
  return () => {
99
96
  Object.values(materials).forEach(material => material.dispose());
100
97
  Object.values(nodes)
@@ -103,12 +100,14 @@ export default function HalfBodyAvatar({
103
100
  };
104
101
  }, [materials, nodes, url, onLoaded, scene, headMesh]);
105
102
 
103
+ // Handle avatar height changes
106
104
  useEffect(() => {
107
105
  if (positionControllerRef.current) {
108
106
  positionControllerRef.current.updateHeight(avatarHeight, true);
109
107
  }
110
108
  }, [avatarHeight]);
111
109
 
110
+ // Handle avatar depth changes
112
111
  useEffect(() => {
113
112
  if (positionControllerRef.current && onCameraZChange) {
114
113
  const newCameraZ = positionControllerRef.current.updateDepth(avatarDepth, true);
@@ -123,9 +122,12 @@ export default function HalfBodyAvatar({
123
122
  // Update morph targets
124
123
  if (morphTargetControllerRef.current) {
125
124
  const currentViseme = updateCurrentViseme(currentTime / 1000);
125
+
126
+ // Use the updated MorphTargetController that handles chat emission directly
126
127
  morphTargetControllerRef.current.updateMorphTargets(
127
128
  currentTime,
128
- {},
129
+ chatEmission,
130
+ loading,
129
131
  currentViseme,
130
132
  eyeBlink,
131
133
  blinkStateRef.current,
@@ -11,94 +11,95 @@ export const SCALE_LERP_FACTOR = 0.1;
11
11
 
12
12
  // Maximum number of idle loops before forcing change
13
13
  export const MAX_IDLE_LOOPS_DEFAULT = 5;
14
-
15
-
16
- interface BaseAction {
17
- weight: number;
18
- action?: string;
14
+ // Type definitions for emotion handling
15
+ interface EmotionMappingItem {
16
+ italian: string;
17
+ english: string;
19
18
  }
19
+ export type EmotionMapping = EmotionMappingItem[];
20
20
 
21
- // Base animations for the avatar
22
- export const BASE_ACTIONS: Record<string, BaseAction> = {
23
- Gioia1: { weight: 0 },
24
- Gioia2: { weight: 0 },
25
- Gioia3: { weight: 0 },
26
- Idle1: { weight: 1 },
27
- Idle2: { weight: 0 },
28
- Idle3: { weight: 0 },
29
- Idle4: { weight: 0 },
30
- Idle5: { weight: 0 },
31
- Rabbia1: { weight: 0 },
32
- Rabbia2: { weight: 0 },
33
- Rabbia3: { weight: 0 },
34
- Sorpresa1: { weight: 0 },
35
- Sorpresa2: { weight: 0 },
36
- Sorpresa3: { weight: 0 },
37
- Timore1: { weight: 0 },
38
- Timore2: { weight: 0 },
39
- Timore3: { weight: 0 },
40
- Tristezza1: { weight: 0 },
41
- Tristezza2: { weight: 0 },
42
- Tristezza3: { weight: 0 },
43
- Loading1: { weight: 0 },
44
- Loading2: { weight: 0 },
45
- Loading3: { weight: 0 },
46
- };
47
-
48
- // Mapping of emotions from Italian to English
49
- export const MAPPING_EMOTIONS_ITALIAN_TO_ENGLISH = {
50
- Gioia: 'Joy',
51
- Rabbia: 'Anger',
52
- Sorpresa: 'Surprise',
53
- Tristezza: 'Sadness',
54
- Timore: 'Fear',
55
- };
21
+ interface BlendShapeMapItem {
22
+ emotion: { italian: string; english: string };
23
+ blendShapes: Record<string, number>;
24
+ }
25
+ export type BlendShapeMap = BlendShapeMapItem[];
56
26
 
57
- // Mapping of blend shapes to emotions
58
- export const MAPPING_BLEND_SHAPE_TO_EMOTION_RPM = {
59
- Rabbia: {
60
- 'browDownLeft': 0.5,
61
- 'browDownRight': 0.5,
62
- 'browOuterUpLeft': 0.5,
63
- 'browOuterUpRight': 0.5,
64
- 'mouthSmile': -0.2,
27
+ // Italian to English emotion mapping
28
+ // Italian to English emotion mapping
29
+ export const MAPPING_EMOTIONS_ITALIAN_TO_ENGLISH: EmotionMapping = [
30
+ {
31
+ italian: 'Gioia',
32
+ english: 'Joy',
65
33
  },
66
- Timore: {
67
- 'browOuterUpLeft': -0.5,
68
- 'browOuterUpRight': -0.5,
69
- 'eyeWideLeft': -0.5,
70
- 'eyeWideRight': -0.5,
34
+ {
35
+ italian: 'Rabbia',
36
+ english: 'Anger',
71
37
  },
72
- Tristezza: {
73
- 'browDownLeft': -0.5,
74
- 'browDownRight': -0.5,
75
- 'eyeSquintLeft': 0.5,
76
- 'eyeSquintRight': 0.5,
77
- 'mouthSmile': -0.6,
38
+ {
39
+ italian: 'Sorpresa',
40
+ english: 'Surprise',
78
41
  },
79
- Sorpresa: {
80
- 'browInnerUp': 0.5,
81
- 'browOuterUpLeft': 0.5,
82
- 'browOuterUpRight': 0.5,
83
- 'eyeWideLeft': 0.5,
84
- 'eyeWideRight': 0.5,
42
+ {
43
+ italian: 'Tristezza',
44
+ english: 'Sadness',
85
45
  },
86
- Gioia: {
87
- 'browDownLeft': 0.5,
88
- 'browDownRight': 0.5,
89
- 'browInnerUp': 0.5,
90
- 'mouthSmile': 0.8,
46
+ {
47
+ italian: 'Timore',
48
+ english: 'Fear',
91
49
  },
92
- };
50
+ ];
93
51
 
94
- // Mapping of blend shapes to emotions for custom GLB
95
- export const MAPPING_BLEND_SHAPE_TO_EMOTION_CUSTOM_GLB = {
96
- Gioia: 'Joy',
97
- Rabbia: 'Anger',
98
- Sorpresa: 'Surprise',
99
- Tristezza: 'Sadness',
100
- Timore: 'Fear',
101
- };
52
+ // Mapping of blend shapes to emotions for RPM avatars
53
+ export const MAPPING_BLEND_SHAPE_TO_EMOTION_RPM: BlendShapeMap = [
54
+ {
55
+ emotion: { italian: 'Rabbia', english: 'Anger' },
56
+ blendShapes: {
57
+ 'browDownLeft': 0.5,
58
+ 'browDownRight': 0.5,
59
+ 'browOuterUpLeft': 0.5,
60
+ 'browOuterUpRight': 0.5,
61
+ 'mouthSmile': -0.2,
62
+ },
63
+ },
64
+ {
65
+ emotion: { italian: 'Timore', english: 'Fear' },
66
+ blendShapes: {
67
+ 'browOuterUpLeft': -0.5,
68
+ 'browOuterUpRight': -0.5,
69
+ 'eyeWideLeft': -0.5,
70
+ 'eyeWideRight': -0.5,
71
+ },
72
+ },
73
+ {
74
+ emotion: { italian: 'Tristezza', english: 'Sadness' },
75
+ blendShapes: {
76
+ 'browDownLeft': -0.5,
77
+ 'browDownRight': -0.5,
78
+ 'eyeSquintLeft': 0.5,
79
+ 'eyeSquintRight': 0.5,
80
+ 'mouthSmile': -0.6,
81
+ },
82
+ },
83
+ {
84
+ emotion: { italian: 'Sorpresa', english: 'Surprise' },
85
+ blendShapes: {
86
+ 'browInnerUp': 0.5,
87
+ 'browOuterUpLeft': 0.5,
88
+ 'browOuterUpRight': 0.5,
89
+ 'eyeWideLeft': 0.5,
90
+ 'eyeWideRight': 0.5,
91
+ },
92
+ },
93
+ {
94
+ emotion: { italian: 'Gioia', english: 'Joy' },
95
+ blendShapes: {
96
+ 'browDownLeft': 0.5,
97
+ 'browDownRight': 0.5,
98
+ 'browInnerUp': 0.5,
99
+ 'mouthSmile': 0.8,
100
+ },
101
+ },
102
+ ];
102
103
 
103
104
  // URL for the male avatar
104
105
  export const ANIMATION_URLS = {
@@ -79,12 +79,10 @@ export default function ContainerAvatarView({
79
79
  fallbackImg,
80
80
  halfBody = true,
81
81
  loading,
82
- animation,
82
+ // animation,
83
83
  showControls = false,
84
84
  isZoomed,
85
85
  chatEmission,
86
- stopProcessing,
87
- resetVisemeQueue,
88
86
  updateCurrentViseme,
89
87
  enablePositionControls,
90
88
  setEnablePositionControls,
@@ -179,16 +177,12 @@ export default function ContainerAvatarView({
179
177
  sex={sex}
180
178
  showControls={showControls}
181
179
  loading={loading || false}
182
- animation={animation}
183
- isZoomed={isZoomed || false}
184
180
  eyeBlink={eyeBlink || false}
185
181
  headMovement={headMovement || false}
186
182
  speaking={speaking || false}
187
183
  halfBody={halfBody}
188
184
  chatEmission={chatEmission}
189
185
  updateCurrentViseme={updateCurrentViseme}
190
- stopProcessing={stopProcessing}
191
- resetVisemeQueue={resetVisemeQueue}
192
186
  setCameraZ={setCameraZ}
193
187
  avatarHeight={avatarHeight}
194
188
  avatarDepth={avatarDepth}
@@ -98,6 +98,15 @@
98
98
  color: var(--memori-primary-text);
99
99
  }
100
100
 
101
+ .memori-chat--bubble h1,
102
+ .memori-chat--bubble h2,
103
+ .memori-chat--bubble h3,
104
+ .memori-chat--bubble h4,
105
+ .memori-chat--bubble h5,
106
+ .memori-chat--bubble h6 {
107
+ color: inherit;
108
+ }
109
+
101
110
  @media (max-width: 600px) {
102
111
  .memori-chat--bubble p {
103
112
  font-size: 12px;
@@ -396,11 +396,23 @@ const ChatBubble: React.FC<Props> = ({
396
396
  {message.generatedByAI && showAIicon && (
397
397
  <Tooltip
398
398
  align="left"
399
- content={t('generatedByAI')}
399
+ content={
400
+ t('generatedByAI') ||
401
+ (lang === 'it'
402
+ ? 'Risposta generata da IA, può talvolta generare informazioni non corrette'
403
+ : 'Answer generated by AI, may occasionally generate incorrect informations')
404
+ }
400
405
  className="memori-chat--bubble-action-icon memori-chat--bubble-action-icon--ai"
401
406
  >
402
407
  <span>
403
- <AI title={t('generatedByAI') || undefined} />
408
+ <AI
409
+ title={
410
+ t('generatedByAI') ||
411
+ (lang === 'it'
412
+ ? 'Risposta generata da IA, può talvolta generare informazioni non corrette'
413
+ : 'Answer generated by AI, may occasionally generate incorrect informations')
414
+ }
415
+ />
404
416
  </span>
405
417
  </Tooltip>
406
418
  )}