@memori.ai/memori-react 7.11.4 → 7.12.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 +41 -0
- package/README.md +2 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +52 -75
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.js +2 -2
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.d.ts +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +8 -2
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.d.ts +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/MorphTargetController.js +6 -3
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/MorphTargetController.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/PositionController.js +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/PositionController.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controls.d.ts +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controls.js +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controls.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +74 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js +101 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/constants.js.map +1 -0
- package/dist/components/Chat/Chat.d.ts +10 -1
- package/dist/components/Chat/Chat.js +2 -10
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/ChatBubble/ChatBubble.js +14 -4
- package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
- package/dist/components/ChatInputs/ChatInputs.d.ts +11 -2
- package/dist/components/ChatInputs/ChatInputs.js +44 -6
- package/dist/components/ChatInputs/ChatInputs.js.map +1 -1
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.css +8 -0
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js +75 -51
- package/dist/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
- package/dist/components/ExpertsDrawer/ExpertsDrawer.js +1 -1
- package/dist/components/ExpertsDrawer/ExpertsDrawer.js.map +1 -1
- package/dist/components/FilePreview/FilePreview.css +155 -0
- package/dist/components/FilePreview/FilePreview.d.ts +12 -0
- package/dist/components/FilePreview/FilePreview.js +21 -0
- package/dist/components/FilePreview/FilePreview.js.map +1 -0
- package/dist/components/MemoriWidget/MemoriWidget.d.ts +3 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +26 -11
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/UploadButton/UploadButton.css +38 -0
- package/dist/components/UploadButton/UploadButton.d.ts +8 -0
- package/dist/components/UploadButton/UploadButton.js +79 -0
- package/dist/components/UploadButton/UploadButton.js.map +1 -0
- package/dist/components/icons/Preview.d.ts +5 -0
- package/dist/components/icons/Preview.js +6 -0
- package/dist/components/icons/Preview.js.map +1 -0
- package/dist/components/icons/Upload.d.ts +5 -0
- package/dist/components/icons/Upload.js +6 -0
- package/dist/components/icons/Upload.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +52 -75
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.js +2 -2
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.d.ts +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +8 -2
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.d.ts +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/MorphTargetController.js +6 -3
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/MorphTargetController.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/PositionController.js +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/PositionController.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.d.ts +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.js +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controls.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/constants.d.ts +74 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js +98 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/constants.js.map +1 -0
- package/esm/components/Chat/Chat.d.ts +10 -1
- package/esm/components/Chat/Chat.js +2 -10
- package/esm/components/Chat/Chat.js.map +1 -1
- package/esm/components/ChatBubble/ChatBubble.js +14 -4
- package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
- package/esm/components/ChatInputs/ChatInputs.d.ts +11 -2
- package/esm/components/ChatInputs/ChatInputs.js +45 -7
- package/esm/components/ChatInputs/ChatInputs.js.map +1 -1
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.css +8 -0
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js +76 -52
- package/esm/components/CompletionProviderStatus/CompletionProviderStatus.js.map +1 -1
- package/esm/components/ExpertsDrawer/ExpertsDrawer.js +1 -1
- package/esm/components/ExpertsDrawer/ExpertsDrawer.js.map +1 -1
- package/esm/components/FilePreview/FilePreview.css +155 -0
- package/esm/components/FilePreview/FilePreview.d.ts +12 -0
- package/esm/components/FilePreview/FilePreview.js +18 -0
- package/esm/components/FilePreview/FilePreview.js.map +1 -0
- package/esm/components/MemoriWidget/MemoriWidget.d.ts +3 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +26 -11
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/UploadButton/UploadButton.css +38 -0
- package/esm/components/UploadButton/UploadButton.d.ts +8 -0
- package/esm/components/UploadButton/UploadButton.js +76 -0
- package/esm/components/UploadButton/UploadButton.js.map +1 -0
- package/esm/components/icons/Preview.d.ts +5 -0
- package/esm/components/icons/Preview.js +4 -0
- package/esm/components/icons/Preview.js.map +1 -0
- package/esm/components/icons/Upload.d.ts +5 -0
- package/esm/components/icons/Upload.js +4 -0
- package/esm/components/icons/Upload.js.map +1 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +3 -2
- package/esm/index.js.map +1 -1
- package/esm/styles.css +2 -0
- package/package.json +2 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +120 -153
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.ts +3 -6
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.tsx +11 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.ts +1 -0
- package/src/components/Avatar/AvatarView/AvatarComponent/components/MorphTargetController.ts +33 -10
- package/src/components/Avatar/AvatarView/AvatarComponent/components/PositionController.ts +1 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/components/controls.tsx +2 -2
- package/src/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.tsx +1 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/constants.ts +127 -0
- package/src/components/Chat/Chat.tsx +16 -10
- package/src/components/ChatBubble/ChatBubble.tsx +23 -2
- package/src/components/ChatInputs/ChatInputs.stories.tsx +5 -0
- package/src/components/ChatInputs/ChatInputs.test.tsx +6 -6
- package/src/components/ChatInputs/ChatInputs.tsx +91 -23
- package/src/components/CompletionProviderStatus/CompletionProviderStatus.css +8 -0
- package/src/components/CompletionProviderStatus/CompletionProviderStatus.stories.tsx +1 -1
- package/src/components/CompletionProviderStatus/CompletionProviderStatus.tsx +95 -66
- package/src/components/ExpertsDrawer/ExpertsDrawer.tsx +3 -1
- package/src/components/FilePreview/FilePreview.css +155 -0
- package/src/components/FilePreview/FilePreview.stories.tsx +66 -0
- package/src/components/FilePreview/FilePreview.test.tsx +26 -0
- package/src/components/FilePreview/FilePreview.tsx +85 -0
- package/src/components/FilePreview/__snapshots__/FilePreview.test.tsx.snap +149 -0
- package/src/components/MemoriWidget/MemoriWidget.tsx +68 -3
- package/src/components/StartPanel/__snapshots__/StartPanel.test.tsx.snap +240 -0
- package/src/components/UploadButton/UploadButton.css +38 -0
- package/src/components/UploadButton/UploadButton.stories.tsx +62 -0
- package/src/components/UploadButton/UploadButton.test.tsx +11 -0
- package/src/components/UploadButton/UploadButton.tsx +126 -0
- package/src/components/UploadButton/__snapshots__/UploadButton.test.tsx.snap +31 -0
- package/src/components/icons/Preview.tsx +23 -0
- package/src/components/icons/Upload.tsx +23 -0
- package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +24 -0
- package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +24 -0
- package/src/components/layouts/__snapshots__/Totem.test.tsx.snap +24 -0
- package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +24 -0
- package/src/components/layouts/layouts.stories.tsx +30 -46
- package/src/index.stories.tsx +68 -2
- package/src/index.tsx +4 -0
- package/src/styles.css +2 -0
- package/src/components/Avatar/AvatarView/AvatarComponent/components/constants.ts +0 -29
package/src/components/Avatar/AvatarView/AvatarComponent/components/MorphTargetController.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { SkinnedMesh } from 'three';
|
|
2
2
|
import { MathUtils } from 'three';
|
|
3
|
-
import { EMOTION_SMOOTHING, VISEME_SMOOTHING, BLINK_CONFIG } from '
|
|
3
|
+
import { EMOTION_SMOOTHING, VISEME_SMOOTHING, BLINK_CONFIG } from '../constants';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Controller class for handling morph target animations including emotions, visemes and blinking
|
|
7
|
+
*/
|
|
5
8
|
export class MorphTargetController {
|
|
6
9
|
private headMesh: SkinnedMesh;
|
|
7
10
|
private currentEmotionValues: Record<string, number> = {};
|
|
@@ -10,7 +13,9 @@ export class MorphTargetController {
|
|
|
10
13
|
constructor(headMesh: SkinnedMesh) {
|
|
11
14
|
this.headMesh = headMesh;
|
|
12
15
|
}
|
|
13
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Updates the morph target influences for emotions, visemes and blinking
|
|
18
|
+
*/
|
|
14
19
|
updateMorphTargets(
|
|
15
20
|
currentTime: number,
|
|
16
21
|
emotionMorphTargets: Record<string, number>,
|
|
@@ -23,57 +28,64 @@ export class MorphTargetController {
|
|
|
23
28
|
blinkStartTime: number;
|
|
24
29
|
}
|
|
25
30
|
) {
|
|
31
|
+
// Validate required mesh properties exist
|
|
26
32
|
if (
|
|
27
33
|
!this.headMesh.morphTargetDictionary ||
|
|
28
34
|
!this.headMesh.morphTargetInfluences
|
|
29
35
|
) {
|
|
36
|
+
console.error('[MorphTargetController] Missing morphTargetDictionary or morphTargetInfluences');
|
|
30
37
|
return;
|
|
31
38
|
}
|
|
32
39
|
|
|
40
|
+
// Calculate blink value for this frame
|
|
33
41
|
const blinkValue = this.calculateBlinkValue(
|
|
34
42
|
currentTime,
|
|
35
43
|
blinkState,
|
|
36
44
|
eyeBlink
|
|
37
45
|
);
|
|
46
|
+
|
|
38
47
|
const currentEmotionKeys = new Set(Object.keys(emotionMorphTargets));
|
|
39
48
|
|
|
49
|
+
// Process each morph target
|
|
40
50
|
Object.entries(this.headMesh.morphTargetDictionary).forEach(
|
|
41
51
|
([key, index]) => {
|
|
42
52
|
if (typeof index !== 'number') return;
|
|
43
53
|
|
|
44
54
|
let targetValue = 0;
|
|
45
55
|
|
|
46
|
-
// Handle emotion morphs
|
|
56
|
+
// Handle emotion morphs with smoothing
|
|
47
57
|
if (currentEmotionKeys.has(key)) {
|
|
48
58
|
const targetEmotionValue = emotionMorphTargets[key];
|
|
49
59
|
const currentEmotionValue = this.currentEmotionValues[key] || 0;
|
|
50
60
|
const newEmotionValue = MathUtils.lerp(
|
|
51
61
|
currentEmotionValue,
|
|
52
|
-
targetEmotionValue *
|
|
62
|
+
targetEmotionValue * 3, // Amplify emotion by 3x
|
|
53
63
|
EMOTION_SMOOTHING
|
|
54
64
|
);
|
|
65
|
+
console.log(`[MorphTargetController] Emotion ${key}: current=${currentEmotionValue}, target=${targetEmotionValue}, new=${newEmotionValue}`);
|
|
55
66
|
this.currentEmotionValues[key] = newEmotionValue;
|
|
56
67
|
targetValue += newEmotionValue;
|
|
57
68
|
}
|
|
58
69
|
|
|
59
|
-
//
|
|
70
|
+
// Add viseme influence if active
|
|
60
71
|
if (currentViseme && key === currentViseme.name) {
|
|
61
72
|
targetValue += currentViseme.weight;
|
|
62
73
|
}
|
|
63
74
|
|
|
64
|
-
//
|
|
75
|
+
// Add blink influence if active
|
|
65
76
|
if (key === 'eyesClosed' && eyeBlink) {
|
|
66
77
|
targetValue += blinkValue;
|
|
67
78
|
}
|
|
68
79
|
|
|
69
|
-
//
|
|
80
|
+
// Clamp and smooth final value
|
|
70
81
|
targetValue = MathUtils.clamp(targetValue, 0, 1);
|
|
71
82
|
if (this.headMesh.morphTargetInfluences) {
|
|
72
|
-
|
|
83
|
+
const finalValue = MathUtils.lerp(
|
|
73
84
|
this.headMesh.morphTargetInfluences[index] || 0,
|
|
74
85
|
targetValue,
|
|
75
86
|
VISEME_SMOOTHING
|
|
76
87
|
);
|
|
88
|
+
this.headMesh.morphTargetInfluences[index] = finalValue;
|
|
77
89
|
}
|
|
78
90
|
}
|
|
79
91
|
);
|
|
@@ -81,6 +93,9 @@ export class MorphTargetController {
|
|
|
81
93
|
this.previousEmotionKeys = currentEmotionKeys;
|
|
82
94
|
}
|
|
83
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Calculates the blink value based on timing and state
|
|
98
|
+
*/
|
|
84
99
|
private calculateBlinkValue(
|
|
85
100
|
currentTime: number,
|
|
86
101
|
blinkState: {
|
|
@@ -95,6 +110,7 @@ export class MorphTargetController {
|
|
|
95
110
|
|
|
96
111
|
let blinkValue = 0;
|
|
97
112
|
|
|
113
|
+
// Start new blink if it's time
|
|
98
114
|
if (currentTime >= blinkState.nextBlinkTime && !blinkState.isBlinking) {
|
|
99
115
|
blinkState.isBlinking = true;
|
|
100
116
|
blinkState.blinkStartTime = currentTime;
|
|
@@ -105,14 +121,21 @@ export class MorphTargetController {
|
|
|
105
121
|
BLINK_CONFIG.minInterval;
|
|
106
122
|
}
|
|
107
123
|
|
|
124
|
+
// Calculate blink animation progress
|
|
108
125
|
if (blinkState.isBlinking) {
|
|
109
126
|
const blinkProgress =
|
|
110
127
|
(currentTime - blinkState.blinkStartTime) / BLINK_CONFIG.blinkDuration;
|
|
128
|
+
|
|
129
|
+
// First half of blink - closing eyes
|
|
111
130
|
if (blinkProgress <= 0.5) {
|
|
112
131
|
blinkValue = blinkProgress * 2;
|
|
113
|
-
}
|
|
132
|
+
}
|
|
133
|
+
// Second half of blink - opening eyes
|
|
134
|
+
else if (blinkProgress <= 1) {
|
|
114
135
|
blinkValue = 2 - blinkProgress * 2;
|
|
115
|
-
}
|
|
136
|
+
}
|
|
137
|
+
// Blink complete
|
|
138
|
+
else {
|
|
116
139
|
blinkState.isBlinking = false;
|
|
117
140
|
blinkValue = 0;
|
|
118
141
|
}
|
|
@@ -13,7 +13,7 @@ interface AdditiveAction {
|
|
|
13
13
|
|
|
14
14
|
export interface AnimationControlPanelProps {
|
|
15
15
|
baseActions: Record<string, BaseAction>;
|
|
16
|
-
onBaseActionChange: (action: string) => void;
|
|
16
|
+
onBaseActionChange: (action: string, outputContent: string) => void;
|
|
17
17
|
currentBaseAction: {
|
|
18
18
|
action: string;
|
|
19
19
|
weight: number;
|
|
@@ -54,7 +54,7 @@ const AnimationControlPanel: React.FC<AnimationControlPanelProps> = ({
|
|
|
54
54
|
baseNames.forEach(name => {
|
|
55
55
|
const settings = baseActions[name];
|
|
56
56
|
panelSettingsRef.current[name] = () => {
|
|
57
|
-
onBaseActionChange(name);
|
|
57
|
+
onBaseActionChange(name, '');
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
const control = folder1.add(panelSettingsRef.current, name);
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Vector3, Euler } from 'three';
|
|
2
|
+
import { AnimationConfig } from './components/FullbodyAvatar/types';
|
|
3
|
+
|
|
4
|
+
// Position and rotation of the avatar
|
|
5
|
+
export const AVATAR_POSITION = new Vector3(0, -1, 0);
|
|
6
|
+
export const AVATAR_ROTATION = new Euler(0.175, 0, 0);
|
|
7
|
+
export const AVATAR_POSITION_ZOOMED = new Vector3(0, -1.45, 0);
|
|
8
|
+
|
|
9
|
+
// Factor for lerping the scale of the avatar
|
|
10
|
+
export const SCALE_LERP_FACTOR = 0.1;
|
|
11
|
+
|
|
12
|
+
// Maximum number of idle loops before forcing change
|
|
13
|
+
export const MAX_IDLE_LOOPS_DEFAULT = 5;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
interface BaseAction {
|
|
17
|
+
weight: number;
|
|
18
|
+
action?: string;
|
|
19
|
+
}
|
|
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
|
+
};
|
|
56
|
+
|
|
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,
|
|
65
|
+
},
|
|
66
|
+
Timore: {
|
|
67
|
+
'browOuterUpLeft': -0.5,
|
|
68
|
+
'browOuterUpRight': -0.5,
|
|
69
|
+
'eyeWideLeft': -0.5,
|
|
70
|
+
'eyeWideRight': -0.5,
|
|
71
|
+
},
|
|
72
|
+
Tristezza: {
|
|
73
|
+
'browDownLeft': -0.5,
|
|
74
|
+
'browDownRight': -0.5,
|
|
75
|
+
'eyeSquintLeft': 0.5,
|
|
76
|
+
'eyeSquintRight': 0.5,
|
|
77
|
+
'mouthSmile': -0.6,
|
|
78
|
+
},
|
|
79
|
+
Sorpresa: {
|
|
80
|
+
'browInnerUp': 0.5,
|
|
81
|
+
'browOuterUpLeft': 0.5,
|
|
82
|
+
'browOuterUpRight': 0.5,
|
|
83
|
+
'eyeWideLeft': 0.5,
|
|
84
|
+
'eyeWideRight': 0.5,
|
|
85
|
+
},
|
|
86
|
+
Gioia: {
|
|
87
|
+
'browDownLeft': 0.5,
|
|
88
|
+
'browDownRight': 0.5,
|
|
89
|
+
'browInnerUp': 0.5,
|
|
90
|
+
'mouthSmile': 0.8,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
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
|
+
};
|
|
102
|
+
|
|
103
|
+
// URL for the male avatar
|
|
104
|
+
export const ANIMATION_URLS = {
|
|
105
|
+
MALE: 'https://assets.memori.ai/api/v2/asset/2c5e88a4-cf62-408b-9ef0-518b099dfcb2.glb',
|
|
106
|
+
FEMALE:
|
|
107
|
+
'https://assets.memori.ai/api/v2/asset/2adc934b-24b2-45bd-94ad-ffec58d3cb32.glb',
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Blink configuration
|
|
111
|
+
export const BLINK_CONFIG = {
|
|
112
|
+
minInterval: 1000,
|
|
113
|
+
maxInterval: 5000,
|
|
114
|
+
blinkDuration: 150,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Default animation configuration
|
|
118
|
+
export const DEFAULT_CONFIG: AnimationConfig = {
|
|
119
|
+
fadeInDuration: 0.8,
|
|
120
|
+
fadeOutDuration: 0.8,
|
|
121
|
+
idleCount: 5,
|
|
122
|
+
timeScale: 1.0,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Smoothing factors for emotion and viseme morphs
|
|
126
|
+
export const EMOTION_SMOOTHING = 0.3;
|
|
127
|
+
export const VISEME_SMOOTHING = 0.5;
|
|
@@ -38,6 +38,7 @@ export interface Props {
|
|
|
38
38
|
pushMessage: (message: Message) => void;
|
|
39
39
|
simulateUserPrompt: (text: string, translatedText?: string) => void;
|
|
40
40
|
showDates?: boolean;
|
|
41
|
+
showUpload?: boolean;
|
|
41
42
|
showContextPerLine?: boolean;
|
|
42
43
|
showAIicon?: boolean;
|
|
43
44
|
showTranslationOriginal?: boolean;
|
|
@@ -56,7 +57,16 @@ export interface Props {
|
|
|
56
57
|
showMicrophone?: boolean;
|
|
57
58
|
userMessage?: string;
|
|
58
59
|
onChangeUserMessage: (userMessage: string) => void;
|
|
59
|
-
sendMessage: (
|
|
60
|
+
sendMessage: (
|
|
61
|
+
msg: string,
|
|
62
|
+
media?: {
|
|
63
|
+
mediumID: string;
|
|
64
|
+
mimeType: string;
|
|
65
|
+
content: string;
|
|
66
|
+
title?: string;
|
|
67
|
+
properties?: { [key: string]: any };
|
|
68
|
+
}
|
|
69
|
+
) => void;
|
|
60
70
|
listening?: boolean;
|
|
61
71
|
setEnableFocusChatInput: (enableFocusChatInput: boolean) => void;
|
|
62
72
|
isPlayingAudio?: boolean;
|
|
@@ -115,6 +125,7 @@ const Chat: React.FC<Props> = ({
|
|
|
115
125
|
customMediaRenderer,
|
|
116
126
|
user,
|
|
117
127
|
userAvatar,
|
|
128
|
+
showUpload = false,
|
|
118
129
|
experts,
|
|
119
130
|
useMathFormatting = false,
|
|
120
131
|
}) => {
|
|
@@ -162,14 +173,6 @@ const Chat: React.FC<Props> = ({
|
|
|
162
173
|
scrollToBottom();
|
|
163
174
|
}
|
|
164
175
|
};
|
|
165
|
-
const onTextareaPressEnter = () => {
|
|
166
|
-
if (sendOnEnter === 'keypress' && userMessage?.length > 0) {
|
|
167
|
-
stopListening();
|
|
168
|
-
sendMessage(userMessage);
|
|
169
|
-
onChangeUserMessage('');
|
|
170
|
-
resetTranscript();
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
176
|
|
|
174
177
|
return (
|
|
175
178
|
<div
|
|
@@ -233,6 +236,7 @@ const Chat: React.FC<Props> = ({
|
|
|
233
236
|
showCopyButton={showCopyButton}
|
|
234
237
|
useMathFormatting={useMathFormatting}
|
|
235
238
|
/>
|
|
239
|
+
|
|
236
240
|
{showDates && !!message.timestamp && (
|
|
237
241
|
<small
|
|
238
242
|
className={`memori-chat--timestamp ${
|
|
@@ -252,6 +256,7 @@ const Chat: React.FC<Props> = ({
|
|
|
252
256
|
)}
|
|
253
257
|
</small>
|
|
254
258
|
)}
|
|
259
|
+
|
|
255
260
|
{showContextPerLine &&
|
|
256
261
|
!!Object.keys(message.contextVars ?? {}).length && (
|
|
257
262
|
<div className="memori-chat--context-vars">
|
|
@@ -363,6 +368,7 @@ const Chat: React.FC<Props> = ({
|
|
|
363
368
|
|
|
364
369
|
{showInputs && (
|
|
365
370
|
<ChatInputs
|
|
371
|
+
resetTranscript={resetTranscript}
|
|
366
372
|
userMessage={userMessage}
|
|
367
373
|
onChangeUserMessage={onChangeUserMessage}
|
|
368
374
|
dialogState={dialogState}
|
|
@@ -372,9 +378,9 @@ const Chat: React.FC<Props> = ({
|
|
|
372
378
|
microphoneMode={microphoneMode}
|
|
373
379
|
sendOnEnter={sendOnEnter}
|
|
374
380
|
setSendOnEnter={setSendOnEnter}
|
|
381
|
+
showUpload={showUpload}
|
|
375
382
|
attachmentsMenuOpen={attachmentsMenuOpen}
|
|
376
383
|
setAttachmentsMenuOpen={setAttachmentsMenuOpen}
|
|
377
|
-
onTextareaPressEnter={onTextareaPressEnter}
|
|
378
384
|
onTextareaFocus={onTextareaFocus}
|
|
379
385
|
onTextareaBlur={onTextareaBlur}
|
|
380
386
|
startListening={startListening}
|
|
@@ -24,12 +24,12 @@ import Copy from '../icons/Copy';
|
|
|
24
24
|
import Code from '../icons/Code';
|
|
25
25
|
import WhyThisAnswer from '../WhyThisAnswer/WhyThisAnswer';
|
|
26
26
|
import { cleanUrl, stripHTML, stripOutputTags } from '../../helpers/utils';
|
|
27
|
+
import FilePreview from '../FilePreview/FilePreview';
|
|
27
28
|
|
|
28
29
|
import markedLinkifyIt from 'marked-linkify-it';
|
|
29
30
|
import markedKatex from 'marked-katex-extension';
|
|
30
31
|
import markedExtendedTables from '../../helpers/markedExtendedTables';
|
|
31
32
|
|
|
32
|
-
|
|
33
33
|
marked.use({
|
|
34
34
|
async: false,
|
|
35
35
|
gfm: true,
|
|
@@ -245,7 +245,9 @@ const ChatBubble: React.FC<Props> = ({
|
|
|
245
245
|
!!message.emitter?.length &&
|
|
246
246
|
!!memori.enableBoardOfExperts &&
|
|
247
247
|
experts?.find(e => e.name === message.emitter)
|
|
248
|
-
? `${
|
|
248
|
+
? `${
|
|
249
|
+
new URL(apiUrl ?? '/').origin
|
|
250
|
+
}/api/v1/memoriai/memori/avatar/${
|
|
249
251
|
experts.find(e => e.name === message.emitter)
|
|
250
252
|
?.expertMemoriID
|
|
251
253
|
}`
|
|
@@ -265,6 +267,7 @@ const ChatBubble: React.FC<Props> = ({
|
|
|
265
267
|
})
|
|
266
268
|
}
|
|
267
269
|
onError={e => {
|
|
270
|
+
// Fallback image handling if primary source fails
|
|
268
271
|
e.currentTarget.src =
|
|
269
272
|
memori.avatarURL && memori.avatarURL.length > 0
|
|
270
273
|
? getResourceUrl({
|
|
@@ -284,6 +287,7 @@ const ChatBubble: React.FC<Props> = ({
|
|
|
284
287
|
/>
|
|
285
288
|
</Transition.Child>
|
|
286
289
|
)}
|
|
290
|
+
|
|
287
291
|
<Transition.Child
|
|
288
292
|
as="div"
|
|
289
293
|
className={cx('memori-chat--bubble', {
|
|
@@ -311,6 +315,7 @@ const ChatBubble: React.FC<Props> = ({
|
|
|
311
315
|
className="memori-chat--bubble-content"
|
|
312
316
|
dangerouslySetInnerHTML={{ __html: renderedText }}
|
|
313
317
|
/>
|
|
318
|
+
|
|
314
319
|
{((!message.fromUser && showCopyButton) ||
|
|
315
320
|
(message.generatedByAI && showAIicon) ||
|
|
316
321
|
(showFeedback && simulateUserPrompt)) && (
|
|
@@ -325,6 +330,7 @@ const ChatBubble: React.FC<Props> = ({
|
|
|
325
330
|
onClick={() => navigator.clipboard.writeText(plainText)}
|
|
326
331
|
/>
|
|
327
332
|
)}
|
|
333
|
+
|
|
328
334
|
{!message.fromUser &&
|
|
329
335
|
showCopyButton &&
|
|
330
336
|
plainText !== message.text && (
|
|
@@ -401,6 +407,21 @@ const ChatBubble: React.FC<Props> = ({
|
|
|
401
407
|
)}
|
|
402
408
|
</div>
|
|
403
409
|
)}
|
|
410
|
+
|
|
411
|
+
{message.fromUser &&
|
|
412
|
+
message.media?.length &&
|
|
413
|
+
message.media[0].properties?.isAttachedFile && (
|
|
414
|
+
<FilePreview
|
|
415
|
+
previewFiles={message.media.map(m => ({
|
|
416
|
+
name: m.title ?? '',
|
|
417
|
+
id: m.mediumID,
|
|
418
|
+
content: m.content ?? '',
|
|
419
|
+
}))}
|
|
420
|
+
removeFile={() => {}}
|
|
421
|
+
allowRemove={false}
|
|
422
|
+
isMessagePreview={true}
|
|
423
|
+
/>
|
|
424
|
+
)}
|
|
404
425
|
</Transition.Child>
|
|
405
426
|
|
|
406
427
|
{message.fromUser && (
|
|
@@ -227,6 +227,11 @@ ContinuousSpeechListening.args = {
|
|
|
227
227
|
microphoneMode: 'CONTINUOUS',
|
|
228
228
|
};
|
|
229
229
|
|
|
230
|
+
export const WithUploadButton = Template.bind({});
|
|
231
|
+
WithUploadButton.args = {
|
|
232
|
+
showUpload: true,
|
|
233
|
+
};
|
|
234
|
+
|
|
230
235
|
export const WithoutMicrophone = Template.bind({});
|
|
231
236
|
WithoutMicrophone.args = {
|
|
232
237
|
dialogState,
|
|
@@ -10,7 +10,6 @@ it('renders ChatInputs unchanged', () => {
|
|
|
10
10
|
userMessage=""
|
|
11
11
|
onChangeUserMessage={jest.fn()}
|
|
12
12
|
sendMessage={jest.fn()}
|
|
13
|
-
onTextareaPressEnter={jest.fn()}
|
|
14
13
|
onTextareaFocus={jest.fn()}
|
|
15
14
|
onTextareaBlur={jest.fn()}
|
|
16
15
|
setAttachmentsMenuOpen={jest.fn()}
|
|
@@ -20,6 +19,7 @@ it('renders ChatInputs unchanged', () => {
|
|
|
20
19
|
stopAudio={jest.fn()}
|
|
21
20
|
startListening={jest.fn()}
|
|
22
21
|
stopListening={jest.fn()}
|
|
22
|
+
resetTranscript={jest.fn()}
|
|
23
23
|
showMicrophone={true}
|
|
24
24
|
/>
|
|
25
25
|
);
|
|
@@ -33,7 +33,6 @@ it('renders ChatInputs with user message unchanged', () => {
|
|
|
33
33
|
onChangeUserMessage={jest.fn()}
|
|
34
34
|
dialogState={dialogState}
|
|
35
35
|
sendMessage={jest.fn()}
|
|
36
|
-
onTextareaPressEnter={jest.fn()}
|
|
37
36
|
onTextareaFocus={jest.fn()}
|
|
38
37
|
onTextareaBlur={jest.fn()}
|
|
39
38
|
setAttachmentsMenuOpen={jest.fn()}
|
|
@@ -43,6 +42,7 @@ it('renders ChatInputs with user message unchanged', () => {
|
|
|
43
42
|
stopAudio={jest.fn()}
|
|
44
43
|
startListening={jest.fn()}
|
|
45
44
|
stopListening={jest.fn()}
|
|
45
|
+
resetTranscript={jest.fn()}
|
|
46
46
|
showMicrophone={true}
|
|
47
47
|
/>
|
|
48
48
|
);
|
|
@@ -59,7 +59,6 @@ it('renders ChatInputs on instruct unchanged', () => {
|
|
|
59
59
|
acceptsMedia: true,
|
|
60
60
|
}}
|
|
61
61
|
sendMessage={jest.fn()}
|
|
62
|
-
onTextareaPressEnter={jest.fn()}
|
|
63
62
|
onTextareaFocus={jest.fn()}
|
|
64
63
|
onTextareaBlur={jest.fn()}
|
|
65
64
|
setAttachmentsMenuOpen={jest.fn()}
|
|
@@ -70,6 +69,7 @@ it('renders ChatInputs on instruct unchanged', () => {
|
|
|
70
69
|
stopAudio={jest.fn()}
|
|
71
70
|
startListening={jest.fn()}
|
|
72
71
|
stopListening={jest.fn()}
|
|
72
|
+
resetTranscript={jest.fn()}
|
|
73
73
|
showMicrophone={true}
|
|
74
74
|
/>
|
|
75
75
|
);
|
|
@@ -83,7 +83,6 @@ it('renders ChatInputs listening unchanged', () => {
|
|
|
83
83
|
onChangeUserMessage={jest.fn()}
|
|
84
84
|
dialogState={dialogState}
|
|
85
85
|
sendMessage={jest.fn()}
|
|
86
|
-
onTextareaPressEnter={jest.fn()}
|
|
87
86
|
onTextareaFocus={jest.fn()}
|
|
88
87
|
onTextareaBlur={jest.fn()}
|
|
89
88
|
setAttachmentsMenuOpen={jest.fn()}
|
|
@@ -93,6 +92,7 @@ it('renders ChatInputs listening unchanged', () => {
|
|
|
93
92
|
stopAudio={jest.fn()}
|
|
94
93
|
startListening={jest.fn()}
|
|
95
94
|
stopListening={jest.fn()}
|
|
95
|
+
resetTranscript={jest.fn()}
|
|
96
96
|
showMicrophone={true}
|
|
97
97
|
/>
|
|
98
98
|
);
|
|
@@ -106,7 +106,6 @@ it('renders ChatInputs without microphone button unchanged', () => {
|
|
|
106
106
|
onChangeUserMessage={jest.fn()}
|
|
107
107
|
dialogState={dialogState}
|
|
108
108
|
sendMessage={jest.fn()}
|
|
109
|
-
onTextareaPressEnter={jest.fn()}
|
|
110
109
|
onTextareaFocus={jest.fn()}
|
|
111
110
|
onTextareaBlur={jest.fn()}
|
|
112
111
|
setAttachmentsMenuOpen={jest.fn()}
|
|
@@ -116,6 +115,7 @@ it('renders ChatInputs without microphone button unchanged', () => {
|
|
|
116
115
|
stopAudio={jest.fn()}
|
|
117
116
|
startListening={jest.fn()}
|
|
118
117
|
stopListening={jest.fn()}
|
|
118
|
+
resetTranscript={jest.fn()}
|
|
119
119
|
showMicrophone={false}
|
|
120
120
|
/>
|
|
121
121
|
);
|
|
@@ -132,7 +132,6 @@ it('renders ChatInputs disabled unchanged', () => {
|
|
|
132
132
|
state: 'X3',
|
|
133
133
|
}}
|
|
134
134
|
sendMessage={jest.fn()}
|
|
135
|
-
onTextareaPressEnter={jest.fn()}
|
|
136
135
|
onTextareaFocus={jest.fn()}
|
|
137
136
|
onTextareaBlur={jest.fn()}
|
|
138
137
|
setAttachmentsMenuOpen={jest.fn()}
|
|
@@ -142,6 +141,7 @@ it('renders ChatInputs disabled unchanged', () => {
|
|
|
142
141
|
stopAudio={jest.fn()}
|
|
143
142
|
startListening={jest.fn()}
|
|
144
143
|
stopListening={jest.fn()}
|
|
144
|
+
resetTranscript={jest.fn()}
|
|
145
145
|
showMicrophone={true}
|
|
146
146
|
/>
|
|
147
147
|
);
|