@memori.ai/memori-react 2.18.8 → 2.19.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 +20 -0
- package/README.md +1 -0
- package/dist/components/Chat/Chat.d.ts +3 -1
- package/dist/components/Chat/Chat.js +2 -2
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/Chat/Chat.test.js +12 -0
- package/dist/components/Chat/Chat.test.js.map +1 -1
- package/dist/components/ChatBubble/ChatBubble.d.ts +4 -1
- package/dist/components/ChatBubble/ChatBubble.js +4 -2
- package/dist/components/ChatBubble/ChatBubble.js.map +1 -1
- package/dist/components/ChatBubble/ChatBubble.test.js +27 -0
- package/dist/components/ChatBubble/ChatBubble.test.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.d.ts +2 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +39 -26
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/esm/components/Chat/Chat.d.ts +3 -1
- package/esm/components/Chat/Chat.js +2 -2
- package/esm/components/Chat/Chat.js.map +1 -1
- package/esm/components/Chat/Chat.test.js +12 -0
- package/esm/components/Chat/Chat.test.js.map +1 -1
- package/esm/components/ChatBubble/ChatBubble.d.ts +4 -1
- package/esm/components/ChatBubble/ChatBubble.js +5 -3
- package/esm/components/ChatBubble/ChatBubble.js.map +1 -1
- package/esm/components/ChatBubble/ChatBubble.test.js +27 -0
- package/esm/components/ChatBubble/ChatBubble.test.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.d.ts +2 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +39 -26
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.js +3 -2
- package/esm/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Chat/Chat.stories.tsx +51 -0
- package/src/components/Chat/Chat.test.tsx +96 -0
- package/src/components/Chat/Chat.tsx +7 -0
- package/src/components/Chat/__snapshots__/Chat.test.tsx.snap +1329 -252
- package/src/components/ChatBubble/ChatBubble.stories.tsx +57 -0
- package/src/components/ChatBubble/ChatBubble.test.tsx +55 -0
- package/src/components/ChatBubble/ChatBubble.tsx +66 -17
- package/src/components/ChatBubble/__snapshots__/ChatBubble.test.tsx.snap +73 -0
- package/src/components/MemoriWidget/MemoriWidget.stories.tsx +14 -0
- package/src/components/MemoriWidget/MemoriWidget.tsx +55 -42
- package/src/index.stories.tsx +59 -39
- package/src/index.tsx +4 -0
|
@@ -120,3 +120,60 @@ WithAllAddonsContents.args = {
|
|
|
120
120
|
showFeedback: true,
|
|
121
121
|
simulateUserPrompt: () => {},
|
|
122
122
|
};
|
|
123
|
+
|
|
124
|
+
export const FromUserWithAvatar = Template.bind({});
|
|
125
|
+
FromUserWithAvatar.args = {
|
|
126
|
+
memori,
|
|
127
|
+
tenant,
|
|
128
|
+
user: { avatarURL: 'https://picsum.photos/200' },
|
|
129
|
+
message: {
|
|
130
|
+
fromUser: true,
|
|
131
|
+
text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
132
|
+
initial: false,
|
|
133
|
+
translatedText:
|
|
134
|
+
'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export const FromUserWithCustomAvatar = Template.bind({});
|
|
139
|
+
FromUserWithCustomAvatar.args = {
|
|
140
|
+
memori,
|
|
141
|
+
tenant,
|
|
142
|
+
userAvatar: 'https://picsum.photos/200',
|
|
143
|
+
message: {
|
|
144
|
+
fromUser: true,
|
|
145
|
+
text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
146
|
+
initial: false,
|
|
147
|
+
translatedText:
|
|
148
|
+
'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export const FromUserWithCustomAvatarElement = Template.bind({});
|
|
153
|
+
FromUserWithCustomAvatarElement.args = {
|
|
154
|
+
memori,
|
|
155
|
+
tenant,
|
|
156
|
+
userAvatar: <span>USER</span>,
|
|
157
|
+
message: {
|
|
158
|
+
fromUser: true,
|
|
159
|
+
text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
160
|
+
initial: false,
|
|
161
|
+
translatedText:
|
|
162
|
+
'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export const FromUserWithAvatarAndCustomAvatar = Template.bind({});
|
|
167
|
+
FromUserWithAvatarAndCustomAvatar.args = {
|
|
168
|
+
memori,
|
|
169
|
+
tenant,
|
|
170
|
+
userAvatar: () => <span>USER</span>,
|
|
171
|
+
user: { avatarURL: 'https://picsum.photos/200' },
|
|
172
|
+
message: {
|
|
173
|
+
fromUser: true,
|
|
174
|
+
text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
175
|
+
initial: false,
|
|
176
|
+
translatedText:
|
|
177
|
+
'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
178
|
+
},
|
|
179
|
+
};
|
|
@@ -71,3 +71,58 @@ it('renders ChatBubble with msg generated by AI unchanged', () => {
|
|
|
71
71
|
);
|
|
72
72
|
expect(container).toMatchSnapshot();
|
|
73
73
|
});
|
|
74
|
+
|
|
75
|
+
it('renders ChatBubble from user with avatar unchanged', () => {
|
|
76
|
+
const { container } = render(
|
|
77
|
+
<ChatBubble
|
|
78
|
+
memori={memori}
|
|
79
|
+
tenant={tenant}
|
|
80
|
+
user={{ avatarURL: 'https://picsum.photos/200' }}
|
|
81
|
+
message={{
|
|
82
|
+
fromUser: true,
|
|
83
|
+
text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
84
|
+
initial: false,
|
|
85
|
+
translatedText:
|
|
86
|
+
'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
87
|
+
}}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
expect(container).toMatchSnapshot();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('renders ChatBubble from user with custom avatar unchanged', () => {
|
|
94
|
+
const { container } = render(
|
|
95
|
+
<ChatBubble
|
|
96
|
+
memori={memori}
|
|
97
|
+
tenant={tenant}
|
|
98
|
+
userAvatar="https://picsum.photos/200"
|
|
99
|
+
message={{
|
|
100
|
+
fromUser: true,
|
|
101
|
+
text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
102
|
+
initial: false,
|
|
103
|
+
translatedText:
|
|
104
|
+
'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
105
|
+
}}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
expect(container).toMatchSnapshot();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('renders ChatBubble from user with avatar as react element unchanged', () => {
|
|
112
|
+
const { container } = render(
|
|
113
|
+
<ChatBubble
|
|
114
|
+
memori={memori}
|
|
115
|
+
tenant={tenant}
|
|
116
|
+
user={{ avatarURL: 'https://picsum.photos/200' }}
|
|
117
|
+
userAvatar={<span>USER</span>}
|
|
118
|
+
message={{
|
|
119
|
+
fromUser: true,
|
|
120
|
+
text: 'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
121
|
+
initial: false,
|
|
122
|
+
translatedText:
|
|
123
|
+
'Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.',
|
|
124
|
+
}}
|
|
125
|
+
/>
|
|
126
|
+
);
|
|
127
|
+
expect(container).toMatchSnapshot();
|
|
128
|
+
});
|
|
@@ -4,10 +4,12 @@ import {
|
|
|
4
4
|
Memori,
|
|
5
5
|
Message,
|
|
6
6
|
Tenant,
|
|
7
|
+
User,
|
|
7
8
|
} from '@memori.ai/memori-api-client/dist/types';
|
|
9
|
+
import { Props as MemoriProps } from '../MemoriWidget/MemoriWidget';
|
|
8
10
|
import { Transition } from '@headlessui/react';
|
|
9
11
|
import { getResourceUrl } from '../../helpers/media';
|
|
10
|
-
import
|
|
12
|
+
import UserIcon from '../icons/User';
|
|
11
13
|
import AI from '../icons/AI';
|
|
12
14
|
import Tooltip from '../ui/Tooltip';
|
|
13
15
|
import FeedbackButtons from '../FeedbackButtons/FeedbackButtons';
|
|
@@ -23,6 +25,8 @@ export interface Props {
|
|
|
23
25
|
simulateUserPrompt?: (msg: string) => void;
|
|
24
26
|
showAIicon?: boolean;
|
|
25
27
|
isFirst?: boolean;
|
|
28
|
+
userAvatar?: MemoriProps['userAvatar'];
|
|
29
|
+
user?: User;
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
const ChatBubble: React.FC<Props> = ({
|
|
@@ -35,6 +39,8 @@ const ChatBubble: React.FC<Props> = ({
|
|
|
35
39
|
simulateUserPrompt,
|
|
36
40
|
showAIicon = true,
|
|
37
41
|
isFirst = false,
|
|
42
|
+
user,
|
|
43
|
+
userAvatar,
|
|
38
44
|
}) => {
|
|
39
45
|
const { t } = useTranslation();
|
|
40
46
|
|
|
@@ -156,22 +162,65 @@ const ChatBubble: React.FC<Props> = ({
|
|
|
156
162
|
</Transition.Child>
|
|
157
163
|
|
|
158
164
|
{message.fromUser && (
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
165
|
+
<>
|
|
166
|
+
{(!!userAvatar && typeof userAvatar === 'string') ||
|
|
167
|
+
(!userAvatar && !!user?.avatarURL?.length) ? (
|
|
168
|
+
<Transition.Child
|
|
169
|
+
as="picture"
|
|
170
|
+
className="memori-chat--bubble-avatar"
|
|
171
|
+
enter="transition ease-in-out duration-300"
|
|
172
|
+
enterFrom={`opacity-0 scale-075 ${
|
|
173
|
+
message.fromUser ? 'translate-x-15' : 'translate-x--15'
|
|
174
|
+
}`}
|
|
175
|
+
enterTo="opacity-1 scale-1 translate-x-0"
|
|
176
|
+
leave="transition ease-in-out duration-300"
|
|
177
|
+
leaveFrom="opacity-1 scale-1 translate-x-0"
|
|
178
|
+
leaveTo={`opacity-0 scale-075 ${
|
|
179
|
+
message.fromUser ? 'translate-x-15' : 'translate-x--15'
|
|
180
|
+
}`}
|
|
181
|
+
>
|
|
182
|
+
<img
|
|
183
|
+
className="memori-chat--bubble-avatar-img"
|
|
184
|
+
alt={user?.userName ?? 'User'}
|
|
185
|
+
src={userAvatar ?? user?.avatarURL}
|
|
186
|
+
/>
|
|
187
|
+
</Transition.Child>
|
|
188
|
+
) : !!userAvatar ? (
|
|
189
|
+
<Transition.Child
|
|
190
|
+
as="div"
|
|
191
|
+
className="memori-chat--bubble-avatar"
|
|
192
|
+
enter="transition ease-in-out duration-300"
|
|
193
|
+
enterFrom={`opacity-0 scale-075 ${
|
|
194
|
+
message.fromUser ? 'translate-x-15' : 'translate-x--15'
|
|
195
|
+
}`}
|
|
196
|
+
enterTo="opacity-1 scale-1 translate-x-0"
|
|
197
|
+
leave="transition ease-in-out duration-300"
|
|
198
|
+
leaveFrom="opacity-1 scale-1 translate-x-0"
|
|
199
|
+
leaveTo={`opacity-0 scale-075 ${
|
|
200
|
+
message.fromUser ? 'translate-x-15' : 'translate-x--15'
|
|
201
|
+
}`}
|
|
202
|
+
>
|
|
203
|
+
{userAvatar}
|
|
204
|
+
</Transition.Child>
|
|
205
|
+
) : (
|
|
206
|
+
<Transition.Child
|
|
207
|
+
as="div"
|
|
208
|
+
className="memori-chat--bubble-avatar"
|
|
209
|
+
enter="transition ease-in-out duration-300"
|
|
210
|
+
enterFrom={`opacity-0 scale-075 ${
|
|
211
|
+
message.fromUser ? 'translate-x-15' : 'translate-x--15'
|
|
212
|
+
}`}
|
|
213
|
+
enterTo="opacity-1 scale-1 translate-x-0"
|
|
214
|
+
leave="transition ease-in-out duration-300"
|
|
215
|
+
leaveFrom="opacity-1 scale-1 translate-x-0"
|
|
216
|
+
leaveTo={`opacity-0 scale-075 ${
|
|
217
|
+
message.fromUser ? 'translate-x-15' : 'translate-x--15'
|
|
218
|
+
}`}
|
|
219
|
+
>
|
|
220
|
+
<UserIcon />
|
|
221
|
+
</Transition.Child>
|
|
222
|
+
)}
|
|
223
|
+
</>
|
|
175
224
|
)}
|
|
176
225
|
</Transition>
|
|
177
226
|
</>
|
|
@@ -1,5 +1,78 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
+
exports[`renders ChatBubble from user with avatar as react element unchanged 1`] = `
|
|
4
|
+
<div>
|
|
5
|
+
<div
|
|
6
|
+
class="memori-chat--bubble-container memori-chat--bubble-from-user"
|
|
7
|
+
>
|
|
8
|
+
<div
|
|
9
|
+
class="memori-chat--bubble memori-chat--user-bubble transition ease-in-out duration-300 opacity-0 scale-09 translate-x-30"
|
|
10
|
+
>
|
|
11
|
+
<p>
|
|
12
|
+
Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.
|
|
13
|
+
</p>
|
|
14
|
+
</div>
|
|
15
|
+
<div
|
|
16
|
+
class="memori-chat--bubble-avatar transition ease-in-out duration-300 opacity-0 scale-075 translate-x-15"
|
|
17
|
+
>
|
|
18
|
+
<span>
|
|
19
|
+
USER
|
|
20
|
+
</span>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
exports[`renders ChatBubble from user with avatar unchanged 1`] = `
|
|
27
|
+
<div>
|
|
28
|
+
<div
|
|
29
|
+
class="memori-chat--bubble-container memori-chat--bubble-from-user"
|
|
30
|
+
>
|
|
31
|
+
<div
|
|
32
|
+
class="memori-chat--bubble memori-chat--user-bubble transition ease-in-out duration-300 opacity-0 scale-09 translate-x-30"
|
|
33
|
+
>
|
|
34
|
+
<p>
|
|
35
|
+
Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.
|
|
36
|
+
</p>
|
|
37
|
+
</div>
|
|
38
|
+
<picture
|
|
39
|
+
class="memori-chat--bubble-avatar transition ease-in-out duration-300 opacity-0 scale-075 translate-x-15"
|
|
40
|
+
>
|
|
41
|
+
<img
|
|
42
|
+
alt="User"
|
|
43
|
+
class="memori-chat--bubble-avatar-img"
|
|
44
|
+
src="https://picsum.photos/200"
|
|
45
|
+
/>
|
|
46
|
+
</picture>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
exports[`renders ChatBubble from user with custom avatar unchanged 1`] = `
|
|
52
|
+
<div>
|
|
53
|
+
<div
|
|
54
|
+
class="memori-chat--bubble-container memori-chat--bubble-from-user"
|
|
55
|
+
>
|
|
56
|
+
<div
|
|
57
|
+
class="memori-chat--bubble memori-chat--user-bubble transition ease-in-out duration-300 opacity-0 scale-09 translate-x-30"
|
|
58
|
+
>
|
|
59
|
+
<p>
|
|
60
|
+
Proin libero ante, dignissim sit amet turpis a, pretium condimentum dolor.
|
|
61
|
+
</p>
|
|
62
|
+
</div>
|
|
63
|
+
<picture
|
|
64
|
+
class="memori-chat--bubble-avatar transition ease-in-out duration-300 opacity-0 scale-075 translate-x-15"
|
|
65
|
+
>
|
|
66
|
+
<img
|
|
67
|
+
alt="User"
|
|
68
|
+
class="memori-chat--bubble-avatar-img"
|
|
69
|
+
src="https://picsum.photos/200"
|
|
70
|
+
/>
|
|
71
|
+
</picture>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
`;
|
|
75
|
+
|
|
3
76
|
exports[`renders ChatBubble unchanged 1`] = `
|
|
4
77
|
<div>
|
|
5
78
|
<div
|
|
@@ -170,3 +170,17 @@ WithCustomMediaRenderer.args = {
|
|
|
170
170
|
</div>
|
|
171
171
|
),
|
|
172
172
|
};
|
|
173
|
+
|
|
174
|
+
export const WithUserAvatar = Template.bind({});
|
|
175
|
+
WithUserAvatar.args = {
|
|
176
|
+
memori,
|
|
177
|
+
tenant,
|
|
178
|
+
userAvatar: 'https://picsum.photos/200',
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export const WithUserAvatarAsElement = Template.bind({});
|
|
182
|
+
WithUserAvatarAsElement.args = {
|
|
183
|
+
memori,
|
|
184
|
+
tenant,
|
|
185
|
+
userAvatar: <span>USER</span>,
|
|
186
|
+
};
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
Tenant,
|
|
15
15
|
Asset,
|
|
16
16
|
MemoriSession,
|
|
17
|
+
User,
|
|
17
18
|
} from '@memori.ai/memori-api-client/src/types';
|
|
18
19
|
import {
|
|
19
20
|
SpeakerAudioDestination,
|
|
@@ -122,8 +123,18 @@ const typeMessage = (
|
|
|
122
123
|
hasBatchQueued,
|
|
123
124
|
},
|
|
124
125
|
});
|
|
125
|
-
|
|
126
126
|
document.dispatchEvent(e);
|
|
127
|
+
|
|
128
|
+
const isSafariIOS =
|
|
129
|
+
window.navigator.userAgent.includes('Safari') &&
|
|
130
|
+
!window.navigator.userAgent.includes('Chrome') &&
|
|
131
|
+
/iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
132
|
+
|
|
133
|
+
if (isSafariIOS) {
|
|
134
|
+
setTimeout(() => {
|
|
135
|
+
document.dispatchEvent(new CustomEvent('MemoriEndSpeak'));
|
|
136
|
+
}, 300);
|
|
137
|
+
}
|
|
127
138
|
};
|
|
128
139
|
const typeMessageHidden = (
|
|
129
140
|
message: string,
|
|
@@ -189,6 +200,11 @@ const typeBatchMessages = (
|
|
|
189
200
|
?.hasAttribute('disabled');
|
|
190
201
|
}
|
|
191
202
|
|
|
203
|
+
const isSafariIOS =
|
|
204
|
+
window.navigator.userAgent.includes('Safari') &&
|
|
205
|
+
!window.navigator.userAgent.includes('Chrome') &&
|
|
206
|
+
/iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
207
|
+
|
|
192
208
|
const stepsGenerator = (function* () {
|
|
193
209
|
yield* messages;
|
|
194
210
|
})();
|
|
@@ -200,20 +216,35 @@ const typeBatchMessages = (
|
|
|
200
216
|
const step = next.value;
|
|
201
217
|
|
|
202
218
|
if (step) {
|
|
219
|
+
if (!areInputsDisabled()) {
|
|
220
|
+
disableInputs();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let waitForPrevious = step.waitForPrevious;
|
|
224
|
+
if (isSafariIOS) waitForPrevious = false;
|
|
225
|
+
|
|
203
226
|
typeMessage(
|
|
204
227
|
step.message,
|
|
205
|
-
|
|
228
|
+
waitForPrevious,
|
|
206
229
|
step.hidden,
|
|
207
230
|
step.typingText,
|
|
208
231
|
step.useLoaderTextAsMsg,
|
|
209
232
|
!next.done
|
|
210
233
|
);
|
|
234
|
+
|
|
235
|
+
if (isSafariIOS) {
|
|
236
|
+
setTimeout(() => {
|
|
237
|
+
document.dispatchEvent(new CustomEvent('MemoriEndSpeak'));
|
|
238
|
+
reEnableInputs();
|
|
239
|
+
}, 3000);
|
|
240
|
+
}
|
|
211
241
|
} else if (areInputsDisabled()) {
|
|
212
242
|
reEnableInputs();
|
|
213
243
|
}
|
|
214
244
|
|
|
215
245
|
if (next.done) {
|
|
216
246
|
document.removeEventListener('MemoriEndSpeak', submitNewMessage);
|
|
247
|
+
if (areInputsDisabled()) reEnableInputs();
|
|
217
248
|
return;
|
|
218
249
|
}
|
|
219
250
|
};
|
|
@@ -323,6 +354,7 @@ export interface Props {
|
|
|
323
354
|
additionalInfo?: OpenSession['additionalInfo'] & { [key: string]: string };
|
|
324
355
|
customMediaRenderer?: ChatProps['customMediaRenderer'];
|
|
325
356
|
additionalSettings?: JSX.Element | null;
|
|
357
|
+
userAvatar?: string | JSX.Element;
|
|
326
358
|
}
|
|
327
359
|
|
|
328
360
|
const MemoriWidget = ({
|
|
@@ -360,6 +392,7 @@ const MemoriWidget = ({
|
|
|
360
392
|
additionalInfo,
|
|
361
393
|
additionalSettings,
|
|
362
394
|
customMediaRenderer,
|
|
395
|
+
userAvatar,
|
|
363
396
|
}: Props) => {
|
|
364
397
|
const { t, i18n } = useTranslation();
|
|
365
398
|
|
|
@@ -382,6 +415,10 @@ const MemoriWidget = ({
|
|
|
382
415
|
|
|
383
416
|
const [instruct, setInstruct] = useState(false);
|
|
384
417
|
|
|
418
|
+
const [user, setUser] = useState<User>({
|
|
419
|
+
avatarURL: typeof userAvatar === 'string' ? userAvatar : undefined,
|
|
420
|
+
} as User);
|
|
421
|
+
|
|
385
422
|
const [clickedStart, setClickedStart] = useState(false);
|
|
386
423
|
const [gotErrorInOpening, setGotErrorInOpening] = useState(false);
|
|
387
424
|
|
|
@@ -776,13 +813,14 @@ const MemoriWidget = ({
|
|
|
776
813
|
/**
|
|
777
814
|
* Age verification
|
|
778
815
|
*/
|
|
779
|
-
const minAge =
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
816
|
+
const minAge =
|
|
817
|
+
memori.ageRestriction !== undefined
|
|
818
|
+
? memori.ageRestriction
|
|
819
|
+
: memori.nsfw
|
|
820
|
+
? 18
|
|
821
|
+
: memori.enableCompletions
|
|
822
|
+
? 14
|
|
823
|
+
: 0;
|
|
786
824
|
const [birthDate, setBirthDate] = useState<string | undefined>();
|
|
787
825
|
const [showAgeVerification, setShowAgeVerification] = useState(false);
|
|
788
826
|
|
|
@@ -1544,35 +1582,6 @@ const MemoriWidget = ({
|
|
|
1544
1582
|
audioContext.resume().then(() => speak(text));
|
|
1545
1583
|
return;
|
|
1546
1584
|
}
|
|
1547
|
-
if (isIOS && isSafari) {
|
|
1548
|
-
audioContext.suspend();
|
|
1549
|
-
|
|
1550
|
-
if (isPlayingAudio) {
|
|
1551
|
-
try {
|
|
1552
|
-
memoriSpeaking = false;
|
|
1553
|
-
if (speechSynthesizer) {
|
|
1554
|
-
speechSynthesizer.close();
|
|
1555
|
-
speechSynthesizer = null;
|
|
1556
|
-
}
|
|
1557
|
-
if (audioDestination) {
|
|
1558
|
-
audioDestination.pause();
|
|
1559
|
-
audioDestination.close();
|
|
1560
|
-
}
|
|
1561
|
-
if (audioContext) {
|
|
1562
|
-
// audioContext.close().then(() => {
|
|
1563
|
-
// audioContext = new AudioContext();
|
|
1564
|
-
// let buffer = audioContext.createBuffer(1, 10000, 22050);
|
|
1565
|
-
// let source = audioContext.createBufferSource();
|
|
1566
|
-
// source.buffer = buffer;
|
|
1567
|
-
// source.connect(audioContext.destination);
|
|
1568
|
-
// });
|
|
1569
|
-
audioContext.destination.disconnect();
|
|
1570
|
-
}
|
|
1571
|
-
} catch (e) {
|
|
1572
|
-
console.error('stopAudio error: ', e);
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
1585
|
if (audioContext.state === 'closed') {
|
|
1577
1586
|
audioContext = new AudioContext();
|
|
1578
1587
|
let buffer = audioContext.createBuffer(1, 10000, 22050);
|
|
@@ -1590,7 +1599,9 @@ const MemoriWidget = ({
|
|
|
1590
1599
|
}
|
|
1591
1600
|
|
|
1592
1601
|
if (!speechSynthesizer) {
|
|
1593
|
-
|
|
1602
|
+
if (!isIOS) {
|
|
1603
|
+
audioDestination = new speechSdk.SpeakerAudioDestination();
|
|
1604
|
+
}
|
|
1594
1605
|
let audioConfig =
|
|
1595
1606
|
speechSdk.AudioConfig.fromSpeakerOutput(audioDestination);
|
|
1596
1607
|
speechSynthesizer = new speechSdk.SpeechSynthesizer(
|
|
@@ -1628,9 +1639,6 @@ const MemoriWidget = ({
|
|
|
1628
1639
|
memoriSpeaking = true;
|
|
1629
1640
|
|
|
1630
1641
|
try {
|
|
1631
|
-
// if (audioContext.destination.context.state === 'running') {
|
|
1632
|
-
// audioContext.destination.disconnect();
|
|
1633
|
-
// }
|
|
1634
1642
|
audioContext.decodeAudioData(result.audioData, function (buffer) {
|
|
1635
1643
|
source.buffer = buffer;
|
|
1636
1644
|
source.connect(audioContext.destination);
|
|
@@ -1669,11 +1677,13 @@ const MemoriWidget = ({
|
|
|
1669
1677
|
speechSynthesizer.close();
|
|
1670
1678
|
speechSynthesizer = null;
|
|
1671
1679
|
}
|
|
1680
|
+
emitEndSpeakEvent();
|
|
1672
1681
|
}
|
|
1673
1682
|
} else {
|
|
1674
1683
|
audioContext.resume();
|
|
1675
1684
|
setIsPlayingAudio(false);
|
|
1676
1685
|
memoriSpeaking = false;
|
|
1686
|
+
emitEndSpeakEvent();
|
|
1677
1687
|
}
|
|
1678
1688
|
},
|
|
1679
1689
|
error => {
|
|
@@ -1681,6 +1691,7 @@ const MemoriWidget = ({
|
|
|
1681
1691
|
window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
|
|
1682
1692
|
setIsPlayingAudio(false);
|
|
1683
1693
|
memoriSpeaking = false;
|
|
1694
|
+
emitEndSpeakEvent();
|
|
1684
1695
|
}
|
|
1685
1696
|
);
|
|
1686
1697
|
|
|
@@ -2658,6 +2669,8 @@ const MemoriWidget = ({
|
|
|
2658
2669
|
listening,
|
|
2659
2670
|
isPlayingAudio,
|
|
2660
2671
|
customMediaRenderer,
|
|
2672
|
+
user,
|
|
2673
|
+
userAvatar,
|
|
2661
2674
|
};
|
|
2662
2675
|
|
|
2663
2676
|
const integrationBackground =
|
package/src/index.stories.tsx
CHANGED
|
@@ -52,6 +52,65 @@ Localhost.args = {
|
|
|
52
52
|
integrationID: '82f017cc-450b-4c47-acf5-47910d336ce9',
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
const TemplateWithBatchButton: Story<Props> = args => (
|
|
56
|
+
<div>
|
|
57
|
+
<button
|
|
58
|
+
style={{
|
|
59
|
+
position: 'fixed',
|
|
60
|
+
top: '0.5rem',
|
|
61
|
+
left: '0.5rem',
|
|
62
|
+
zIndex: 99999,
|
|
63
|
+
}}
|
|
64
|
+
onClick={() => {
|
|
65
|
+
window.typeBatchMessages([
|
|
66
|
+
{
|
|
67
|
+
message: 'uno di tre',
|
|
68
|
+
hidden: false,
|
|
69
|
+
waitForPrevious: true,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
message: 'due di tre',
|
|
73
|
+
hidden: false,
|
|
74
|
+
waitForPrevious: true,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
message: 'tre di tre',
|
|
78
|
+
hidden: false,
|
|
79
|
+
waitForPrevious: true,
|
|
80
|
+
},
|
|
81
|
+
]);
|
|
82
|
+
}}
|
|
83
|
+
>
|
|
84
|
+
Start Batch
|
|
85
|
+
</button>
|
|
86
|
+
<Memori {...args} />
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
export const WithBatch = TemplateWithBatchButton.bind({});
|
|
90
|
+
WithBatch.args = {
|
|
91
|
+
ownerUserName: 'nzambello',
|
|
92
|
+
memoriName: 'Nicola',
|
|
93
|
+
tenantID: 'app.memorytwin.com',
|
|
94
|
+
apiURL: 'https://backend.memori.ai',
|
|
95
|
+
baseURL: 'https://app.memorytwin.com',
|
|
96
|
+
uiLang: 'it',
|
|
97
|
+
showShare: true,
|
|
98
|
+
showSettings: true,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const WithCustomUserAvatar = Template.bind({});
|
|
102
|
+
WithCustomUserAvatar.args = {
|
|
103
|
+
ownerUserName: 'nzambello',
|
|
104
|
+
memoriName: 'Nicola',
|
|
105
|
+
tenantID: 'app.memorytwin.com',
|
|
106
|
+
apiURL: 'https://backend.memori.ai',
|
|
107
|
+
baseURL: 'https://app.memorytwin.com',
|
|
108
|
+
uiLang: 'it',
|
|
109
|
+
showShare: true,
|
|
110
|
+
showSettings: true,
|
|
111
|
+
userAvatar: 'https://picsum.photos/200',
|
|
112
|
+
};
|
|
113
|
+
|
|
55
114
|
// export const Instruction = Template.bind({});
|
|
56
115
|
// Instruction.args = {
|
|
57
116
|
// ownerUserName: 'nzambello',
|
|
@@ -65,42 +124,3 @@ Localhost.args = {
|
|
|
65
124
|
// pin: 'giver pin',
|
|
66
125
|
// authToken: 'your login token',
|
|
67
126
|
// };
|
|
68
|
-
|
|
69
|
-
export const DemoSophia = Template.bind({});
|
|
70
|
-
DemoSophia.args = {
|
|
71
|
-
layout: 'TOTEM',
|
|
72
|
-
memoriName: 'Sophia',
|
|
73
|
-
ownerUserName: 'francescoimpellizzeri',
|
|
74
|
-
memoriID: '57405959-a2c5-4499-adb8-bb8dcc848ad5',
|
|
75
|
-
ownerUserID: '44ccefdb-d7a2-447e-9851-2a76be055a40',
|
|
76
|
-
tenantID: 'nextpresent.aclambda.online',
|
|
77
|
-
apiURL: 'https://backend.memori.ai',
|
|
78
|
-
baseURL: 'https://nextpresent.aclambda.online',
|
|
79
|
-
uiLang: 'it',
|
|
80
|
-
lang: 'it',
|
|
81
|
-
showShare: true,
|
|
82
|
-
showSettings: true,
|
|
83
|
-
integrationID: 'd10bbffd-26f3-4614-a092-15b215d04ffa',
|
|
84
|
-
initialQuestion: 'Welcome Totem',
|
|
85
|
-
contextVars: 'CONTEXT:TOTEM',
|
|
86
|
-
// https://assets.memori.ai/api/v2/asset/6af08bf1-f011-40ea-92a2-699b7b53a53c.glb
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export const DemoStefano = Template.bind({});
|
|
90
|
-
DemoStefano.args = {
|
|
91
|
-
layout: 'TOTEM',
|
|
92
|
-
memoriName: 'Stefano Zingoni',
|
|
93
|
-
ownerUserName: 'roberta.bianchi',
|
|
94
|
-
memoriID: 'd6df4c75-8dfb-4e6d-b19f-193fa8a9bcce',
|
|
95
|
-
ownerUserID: 'b242160e-c19c-468f-b7f8-b2dc1ce51045',
|
|
96
|
-
tenantID: 'gruppoe.aclambda.online',
|
|
97
|
-
apiURL: 'https://backend.memori.ai',
|
|
98
|
-
baseURL: 'https://gruppoe.aclambda.online',
|
|
99
|
-
uiLang: 'it',
|
|
100
|
-
lang: 'it',
|
|
101
|
-
showShare: true,
|
|
102
|
-
showSettings: true,
|
|
103
|
-
contextVars: 'CONTEXT:TOTEM',
|
|
104
|
-
integrationID: '5712601d-6174-45e7-bfb1-b4ac71c4ff80',
|
|
105
|
-
// https://assets.memori.ai/api/v2/asset/ed50c6a4-37cd-458b-9209-8cabfa256b30.glb
|
|
106
|
-
};
|
package/src/index.tsx
CHANGED
|
@@ -48,6 +48,7 @@ export interface Props {
|
|
|
48
48
|
additionalInfo?: WidgetProps['additionalInfo'];
|
|
49
49
|
customMediaRenderer?: WidgetProps['customMediaRenderer'];
|
|
50
50
|
additionalSettings?: WidgetProps['additionalSettings'];
|
|
51
|
+
userAvatar?: WidgetProps['userAvatar'];
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
const getPreferredLanguages = () => {
|
|
@@ -103,6 +104,7 @@ const Memori: React.FC<Props> = ({
|
|
|
103
104
|
additionalInfo,
|
|
104
105
|
customMediaRenderer,
|
|
105
106
|
additionalSettings,
|
|
107
|
+
userAvatar,
|
|
106
108
|
}) => {
|
|
107
109
|
const [memori, setMemori] = useState<IMemori>();
|
|
108
110
|
const [speechKey, setSpeechKey] = useState<string | undefined>(
|
|
@@ -237,6 +239,7 @@ const Memori: React.FC<Props> = ({
|
|
|
237
239
|
additionalInfo={additionalInfo}
|
|
238
240
|
customMediaRenderer={customMediaRenderer}
|
|
239
241
|
additionalSettings={additionalSettings}
|
|
242
|
+
userAvatar={userAvatar}
|
|
240
243
|
{...(tag && pin ? { personification: { tag, pin } } : {})}
|
|
241
244
|
/>
|
|
242
245
|
) : (
|
|
@@ -296,6 +299,7 @@ Memori.propTypes = {
|
|
|
296
299
|
additionalInfo: PropTypes.objectOf(PropTypes.any),
|
|
297
300
|
customMediaRenderer: PropTypes.func,
|
|
298
301
|
additionalSettings: PropTypes.any,
|
|
302
|
+
userAvatar: PropTypes.oneOfType([PropTypes.string, PropTypes.any]),
|
|
299
303
|
};
|
|
300
304
|
|
|
301
305
|
export default Memori;
|