@memori.ai/memori-react 7.8.0-rc.0 → 7.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +1 -1
  3. package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +113 -103
  4. package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -1
  5. package/dist/components/MemoriWidget/MemoriWidget.js +15 -24
  6. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  7. package/dist/components/layouts/ZoomedFullBody.js +7 -0
  8. package/dist/components/layouts/ZoomedFullBody.js.map +1 -1
  9. package/dist/components/layouts/zoomed-full-body.css +1 -1
  10. package/dist/context/visemeContext.js +2 -2
  11. package/dist/context/visemeContext.js.map +1 -1
  12. package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +1 -1
  13. package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +115 -105
  14. package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -1
  15. package/esm/components/MemoriWidget/MemoriWidget.js +15 -24
  16. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  17. package/esm/components/layouts/ZoomedFullBody.js +7 -0
  18. package/esm/components/layouts/ZoomedFullBody.js.map +1 -1
  19. package/esm/components/layouts/zoomed-full-body.css +1 -1
  20. package/esm/context/visemeContext.js +2 -2
  21. package/esm/context/visemeContext.js.map +1 -1
  22. package/package.json +1 -1
  23. package/src/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.tsx +86 -92
  24. package/src/components/MemoriWidget/MemoriWidget.tsx +26 -33
  25. package/src/components/layouts/ZoomedFullBody.tsx +10 -1
  26. package/src/components/layouts/zoomed-full-body.css +1 -1
  27. package/src/context/visemeContext.tsx +2 -2
  28. package/src/index.stories.tsx +41 -14
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { useEffect, useRef, useMemo, useCallback } from 'react';
2
2
  import {
3
3
  Vector3,
4
4
  Euler,
@@ -11,7 +11,6 @@ import {
11
11
  } from 'three';
12
12
  import { useAnimations, useGLTF } from '@react-three/drei';
13
13
  import { useGraph, useFrame } from '@react-three/fiber';
14
- import { correctMaterials, isSkinnedMesh } from '../../../../../helpers/utils';
15
14
 
16
15
  interface FullbodyAvatarProps {
17
16
  url: string;
@@ -41,6 +40,7 @@ interface FullbodyAvatarProps {
41
40
  emotionMorphTargets: Record<string, number>;
42
41
  }
43
42
 
43
+
44
44
  const AVATAR_POSITION = new Vector3(0, -1, 0);
45
45
  const AVATAR_ROTATION = new Euler(0.175, 0, 0);
46
46
  const AVATAR_POSITION_ZOOMED = new Vector3(0, -1.45, 0);
@@ -51,24 +51,23 @@ const ANIMATION_URLS = {
51
51
  'https://assets.memori.ai/api/v2/asset/0e49aa5d-f757-4292-a170-d843c2839a41.glb',
52
52
  };
53
53
 
54
- // Blink configuration
55
54
  const BLINK_CONFIG = {
56
55
  minInterval: 1000,
57
56
  maxInterval: 5000,
58
57
  blinkDuration: 150,
59
58
  };
60
59
 
61
- const EMOTION_TRANSITION_SPEED = 0.1; // Adjust this value to control emotion transition speed
60
+ const EMOTION_SMOOTHING = 0.3;
61
+ const VISME_SMOOTHING = 0.5;
62
+
62
63
 
63
64
  export default function FullbodyAvatar({
64
65
  url,
65
66
  sex,
66
- onLoaded,
67
67
  currentBaseAction,
68
68
  timeScale,
69
69
  isZoomed,
70
70
  eyeBlink,
71
- morphTargetSmoothing = 0.5,
72
71
  updateCurrentViseme,
73
72
  setMorphTargetDictionary,
74
73
  setMorphTargetInfluences,
@@ -76,55 +75,51 @@ export default function FullbodyAvatar({
76
75
  }: FullbodyAvatarProps) {
77
76
  const { scene } = useGLTF(url);
78
77
  const { animations } = useGLTF(ANIMATION_URLS[sex]);
79
- const { nodes, materials } = useGraph(scene);
80
78
  const { actions } = useAnimations(animations, scene);
81
79
 
82
- const mixer = useRef(new AnimationMixer(scene));
80
+ const mixerRef = useRef<AnimationMixer>();
83
81
  const headMeshRef = useRef<SkinnedMesh>();
84
82
  const currentActionRef = useRef<AnimationAction | null>(null);
85
- const [isTransitioningToIdle, setIsTransitioningToIdle] = useState(false);
83
+ const isTransitioningToIdleRef = useRef(false);
86
84
 
87
- // Blink state
88
- const lastBlinkTime = useRef(0);
89
- const nextBlinkTime = useRef(0);
90
- const isBlinking = useRef(false);
91
- const blinkStartTime = useRef(0);
85
+ const lastBlinkTimeRef = useRef(0);
86
+ const nextBlinkTimeRef = useRef(0);
87
+ const isBlinkingRef = useRef(false);
88
+ const blinkStartTimeRef = useRef(0);
92
89
 
93
- // Morph targets
94
90
  const currentEmotionRef = useRef<Record<string, number>>({});
95
91
  const previousEmotionKeysRef = useRef<Set<string>>(new Set());
96
92
 
97
- useEffect(() => {
98
- correctMaterials(materials);
99
-
93
+ // Memoize the scene traversal
94
+ const headMesh = useMemo(() => {
95
+ let foundMesh: SkinnedMesh | undefined;
100
96
  scene.traverse((object: Object3D) => {
101
- if (object instanceof SkinnedMesh) {
102
- if (object.name === 'GBNL__Head' || object.name === 'Wolf3D_Avatar') {
103
- headMeshRef.current = object;
104
- if (object.morphTargetDictionary && object.morphTargetInfluences) {
105
- setMorphTargetDictionary(object.morphTargetDictionary);
106
-
107
- const initialInfluences = Object.keys(
108
- object.morphTargetDictionary
109
- ).reduce((acc, key) => ({ ...acc, [key]: 0 }), {});
110
- setMorphTargetInfluences(initialInfluences);
111
- }
112
- }
97
+ if (
98
+ object instanceof SkinnedMesh &&
99
+ (object.name === 'GBNL__Head' || object.name === 'Wolf3D_Avatar')
100
+ ) {
101
+ foundMesh = object;
113
102
  }
114
103
  });
104
+ return foundMesh;
105
+ }, [scene]);
115
106
 
116
- onLoaded?.();
117
-
118
- return () => {
119
- Object.values(materials).forEach(material => material.dispose());
120
- Object.values(nodes)
121
- .filter(isSkinnedMesh)
122
- .forEach(mesh => mesh.geometry.dispose());
123
- };
124
- }, [materials, nodes, url, onLoaded, scene]);
125
-
126
- // Handle base animation changes
127
107
  useEffect(() => {
108
+ if (headMesh) {
109
+ headMeshRef.current = headMesh;
110
+ if (headMesh.morphTargetDictionary && headMesh.morphTargetInfluences) {
111
+ setMorphTargetDictionary(headMesh.morphTargetDictionary);
112
+ const initialInfluences = Object.keys(
113
+ headMesh.morphTargetDictionary
114
+ ).reduce((acc, key) => ({ ...acc, [key]: 0 }), {});
115
+ setMorphTargetInfluences(initialInfluences);
116
+ }
117
+ }
118
+ mixerRef.current = new AnimationMixer(scene);
119
+ }, [headMesh, scene, setMorphTargetDictionary, setMorphTargetInfluences]);
120
+
121
+ // Memoize the animation change handler
122
+ const handleAnimationChange = useCallback(() => {
128
123
  if (!actions || !currentBaseAction.action) return;
129
124
 
130
125
  const newAction = actions[currentBaseAction.action];
@@ -141,15 +136,11 @@ export default function FullbodyAvatar({
141
136
  if (currentActionRef.current) {
142
137
  currentActionRef.current.fadeOut(fadeOutDuration);
143
138
  }
144
-
145
- console.log(newAction);
139
+
146
140
  newAction.reset().fadeIn(fadeInDuration).play();
147
141
  currentActionRef.current = newAction;
148
-
149
- // Set the time scale for the new action
150
142
  newAction.timeScale = timeScale;
151
143
 
152
- // If it's an emotion animation, set it to play once and then transition to idle
153
144
  if (
154
145
  currentBaseAction.action.startsWith('Gioia') ||
155
146
  currentBaseAction.action.startsWith('Rabbia') ||
@@ -159,55 +150,55 @@ export default function FullbodyAvatar({
159
150
  ) {
160
151
  newAction.setLoop(LoopOnce, 1);
161
152
  newAction.clampWhenFinished = true;
162
- setIsTransitioningToIdle(true);
153
+ isTransitioningToIdleRef.current = true;
163
154
  }
164
155
  }, [actions, currentBaseAction, timeScale]);
165
156
 
166
- useFrame(state => {
167
- if (
168
- headMeshRef.current &&
169
- headMeshRef.current.morphTargetDictionary &&
170
- headMeshRef.current.morphTargetInfluences
171
- ) {
172
- const currentTime = state.clock.getElapsedTime() * 1000; // Convert to milliseconds
157
+ useEffect(() => {
158
+ handleAnimationChange();
159
+ }, [handleAnimationChange]);
160
+
161
+ // Optimize the frame update function
162
+ const updateFrame = useCallback(
163
+ (currentTime: number) => {
164
+ if (
165
+ !headMeshRef.current ||
166
+ !headMeshRef.current.morphTargetDictionary ||
167
+ !headMeshRef.current.morphTargetInfluences
168
+ )
169
+ return;
173
170
 
174
- // Handle blinking
175
171
  let blinkValue = 0;
176
172
  if (eyeBlink) {
177
- if (currentTime >= nextBlinkTime.current && !isBlinking.current) {
178
- isBlinking.current = true;
179
- blinkStartTime.current = currentTime;
180
- lastBlinkTime.current = currentTime;
181
- nextBlinkTime.current =
173
+ if (currentTime >= nextBlinkTimeRef.current && !isBlinkingRef.current) {
174
+ isBlinkingRef.current = true;
175
+ blinkStartTimeRef.current = currentTime;
176
+ lastBlinkTimeRef.current = currentTime;
177
+ nextBlinkTimeRef.current =
182
178
  currentTime +
183
179
  Math.random() *
184
180
  (BLINK_CONFIG.maxInterval - BLINK_CONFIG.minInterval) +
185
181
  BLINK_CONFIG.minInterval;
186
182
  }
187
183
 
188
- if (isBlinking.current) {
184
+ if (isBlinkingRef.current) {
189
185
  const blinkProgress =
190
- (currentTime - blinkStartTime.current) / BLINK_CONFIG.blinkDuration;
186
+ (currentTime - blinkStartTimeRef.current) /
187
+ BLINK_CONFIG.blinkDuration;
191
188
  if (blinkProgress <= 0.5) {
192
- // Eyes closing
193
189
  blinkValue = blinkProgress * 2;
194
190
  } else if (blinkProgress <= 1) {
195
- // Eyes opening
196
191
  blinkValue = 2 - blinkProgress * 2;
197
192
  } else {
198
- // Blink finished
199
- isBlinking.current = false;
193
+ isBlinkingRef.current = false;
200
194
  blinkValue = 0;
201
195
  }
202
196
  }
203
197
  }
204
198
 
205
199
  const currentViseme = updateCurrentViseme(currentTime / 1000);
206
-
207
- // Create a set of current emotion keys
208
200
  const currentEmotionKeys = new Set(Object.keys(emotionMorphTargets));
209
201
 
210
- // Reset old emotion morph targets
211
202
  previousEmotionKeysRef.current.forEach(key => {
212
203
  if (!currentEmotionKeys.has(key)) {
213
204
  const index = headMeshRef.current!.morphTargetDictionary![key];
@@ -220,75 +211,78 @@ export default function FullbodyAvatar({
220
211
  }
221
212
  });
222
213
 
223
- // Update morph targets
224
214
  Object.entries(headMeshRef.current.morphTargetDictionary).forEach(
225
215
  ([key, index]) => {
226
216
  if (typeof index === 'number') {
227
217
  let targetValue = 0;
228
218
 
229
- // Handle emotions (base layer)
230
- if (Object.prototype.hasOwnProperty.call(emotionMorphTargets, key)) {
219
+ if (currentEmotionKeys.has(key)) {
231
220
  const targetEmotionValue = emotionMorphTargets[key];
232
221
  const currentEmotionValue = currentEmotionRef.current[key] || 0;
233
222
  const newEmotionValue = MathUtils.lerp(
234
223
  currentEmotionValue,
235
- targetEmotionValue * 2,
236
- EMOTION_TRANSITION_SPEED
224
+ targetEmotionValue * 2.5,
225
+ EMOTION_SMOOTHING
237
226
  );
238
227
  currentEmotionRef.current[key] = newEmotionValue;
239
228
  targetValue += newEmotionValue;
240
229
  }
241
230
 
242
- // Handle visemes (additive layer)
243
231
  if (currentViseme && key === currentViseme.name) {
244
- targetValue += currentViseme.weight * 1.3; // Amplify the effect
232
+ targetValue += currentViseme.weight * 1;
245
233
  }
246
234
 
247
- // Handle blinking (additive layer, only for 'eyesClosed')
248
235
  if (key === 'eyesClosed' && eyeBlink) {
249
236
  targetValue += blinkValue;
250
237
  }
251
238
 
252
- // Clamp the final value between 0 and 1
253
239
  targetValue = MathUtils.clamp(targetValue, 0, 1);
254
-
255
- // Apply smoothing
256
- if (headMeshRef.current && headMeshRef.current.morphTargetInfluences) {
240
+ if (
241
+ headMeshRef.current &&
242
+ headMeshRef.current.morphTargetInfluences
243
+ ) {
257
244
  headMeshRef.current.morphTargetInfluences[index] = MathUtils.lerp(
258
245
  headMeshRef.current.morphTargetInfluences[index],
259
246
  targetValue,
260
- morphTargetSmoothing
247
+ VISME_SMOOTHING
261
248
  );
262
249
  }
263
250
  }
264
251
  }
265
252
  );
266
253
 
267
- // Update the set of previous emotion keys for the next frame
268
254
  previousEmotionKeysRef.current = currentEmotionKeys;
269
255
 
270
- // Handle transition from emotion animation to idle
271
- if (isTransitioningToIdle && currentActionRef.current) {
256
+ if (isTransitioningToIdleRef.current && currentActionRef.current) {
272
257
  if (
273
258
  currentActionRef.current.time >=
274
259
  currentActionRef.current.getClip().duration
275
260
  ) {
276
- // Transition to the idle animation
277
- const idleNumber = Math.floor(Math.random() * 5) + 1; // Randomly choose 1, 2, 3, 4 or 5
278
- const idleAction = actions[`Idle${idleNumber == 3 ? 4 : idleNumber}`];
261
+ const idleNumber = Math.floor(Math.random() * 5) + 1;
262
+ const idleAction =
263
+ actions[`Idle${idleNumber === 3 ? 4 : idleNumber}`];
279
264
 
280
265
  if (idleAction) {
281
266
  currentActionRef.current.fadeOut(0.5);
282
267
  idleAction.reset().fadeIn(0.5).play();
283
268
  currentActionRef.current = idleAction;
284
- setIsTransitioningToIdle(false);
269
+ isTransitioningToIdleRef.current = false;
285
270
  }
286
271
  }
287
272
  }
288
273
 
289
- // Update the animation mixer
290
- mixer.current.update(0.01); // Fixed delta time for consistent animation speed
291
- }
274
+ mixerRef.current?.update(0.01);
275
+ },
276
+ [
277
+ actions,
278
+ emotionMorphTargets,
279
+ eyeBlink,
280
+ updateCurrentViseme,
281
+ ]
282
+ );
283
+
284
+ useFrame(state => {
285
+ updateFrame(state.clock.getElapsedTime() * 1000);
292
286
  });
293
287
 
294
288
  return (
@@ -543,13 +543,10 @@ const MemoriWidget = ({
543
543
  const [hideEmissions, setHideEmissions] = useState(false);
544
544
 
545
545
  const {
546
- updateCurrentViseme,
547
546
  startProcessing,
548
- resetAndStartProcessing,
549
- isProcessing,
550
547
  addViseme,
551
548
  stopProcessing,
552
- resetVisemeQueue,
549
+ resetVisemeQueue
553
550
  } = useViseme();
554
551
 
555
552
  useEffect(() => {
@@ -1963,7 +1960,7 @@ const MemoriWidget = ({
1963
1960
  onEndSpeakStartListen();
1964
1961
  };
1965
1962
 
1966
- // Add this before starting new speech synthesis
1963
+ // Clear any existing visemes before starting new speech
1967
1964
  resetVisemeQueue();
1968
1965
 
1969
1966
  // Set up the viseme event handler
@@ -1978,7 +1975,9 @@ const MemoriWidget = ({
1978
1975
  speechSynthesizer.speakSsmlAsync(
1979
1976
  `<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" xml:lang="${getCultureCodeByLanguage(
1980
1977
  userLang
1981
- )}"><voice name="${getTTSVoice(userLang)}"><s>${replaceTextWithPhonemes(
1978
+ )}"><voice name="${getTTSVoice(
1979
+ userLang
1980
+ )}"><s>${replaceTextWithPhonemes(
1982
1981
  textToSpeak,
1983
1982
  userLang.toLowerCase()
1984
1983
  )}</s></voice></speak>`,
@@ -1987,24 +1986,18 @@ const MemoriWidget = ({
1987
1986
  setIsPlayingAudio(true);
1988
1987
  memoriSpeaking = true;
1989
1988
 
1989
+ // Process the viseme data
1990
+ startProcessing();
1991
+
1990
1992
  try {
1991
1993
  // Decode the audio data
1992
- audioContext!.decodeAudioData(result.audioData, function (buffer) {
1993
- console.log('decoded');
1994
- const currentSource = audioContext!.createBufferSource();
1995
- currentSource.buffer = buffer;
1996
- currentSource.connect(audioContext!.destination);
1997
- startProcessing();
1998
- currentSource.start();
1999
-
2000
- currentSource.onended = () => {
2001
- console.log('ended');
2002
- setIsPlayingAudio(false);
2003
- memoriSpeaking = false;
2004
- stopProcessing();
2005
- resetVisemeQueue();
2006
- emitEndSpeakEvent();
2007
- };
1994
+ audioContext.decodeAudioData(result.audioData, function (buffer) {
1995
+ source.buffer = buffer;
1996
+ source.connect(audioContext.destination);
1997
+
1998
+ if (history.length < 1 || (isSafari && isIOS)) {
1999
+ source.start(0);
2000
+ }
2008
2001
  });
2009
2002
 
2010
2003
  // Handle the audio context state changes
@@ -2013,28 +2006,29 @@ const MemoriWidget = ({
2013
2006
  audioContext.state === 'suspended' ||
2014
2007
  audioContext.state === 'closed'
2015
2008
  ) {
2016
- console.log('suspended');
2017
2009
  source.disconnect();
2018
2010
  setIsPlayingAudio(false);
2019
2011
  stopProcessing();
2020
2012
  resetVisemeQueue();
2021
2013
  memoriSpeaking = false;
2022
- emitEndSpeakEvent();
2023
2014
  } else if ((audioContext.state as string) === 'interrupted') {
2024
- console.log('interrupted');
2025
- stopProcessing();
2026
- resetVisemeQueue();
2027
-
2028
2015
  audioContext.resume();
2029
2016
  }
2030
2017
  };
2018
+
2019
+ audioContext.resume();
2020
+
2021
+ if (speechSynthesizer) {
2022
+ speechSynthesizer.close();
2023
+ speechSynthesizer = null;
2024
+ }
2031
2025
  } catch (e) {
2032
2026
  console.warn('speak error: ', e);
2033
2027
  window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
2034
- setIsPlayingAudio(false);
2035
- memoriSpeaking = false;
2036
2028
  stopProcessing();
2037
2029
  resetVisemeQueue();
2030
+ setIsPlayingAudio(false);
2031
+ memoriSpeaking = false;
2038
2032
 
2039
2033
  if (speechSynthesizer) {
2040
2034
  speechSynthesizer.close();
@@ -2045,7 +2039,6 @@ const MemoriWidget = ({
2045
2039
  } else {
2046
2040
  audioContext.resume();
2047
2041
  stopProcessing();
2048
- resetVisemeQueue();
2049
2042
  setIsPlayingAudio(false);
2050
2043
  memoriSpeaking = false;
2051
2044
  emitEndSpeakEvent();
@@ -2055,9 +2048,9 @@ const MemoriWidget = ({
2055
2048
  console.error('speak:', error);
2056
2049
  window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
2057
2050
  setIsPlayingAudio(false);
2058
- memoriSpeaking = false;
2059
2051
  stopProcessing();
2060
2052
  resetVisemeQueue();
2053
+ memoriSpeaking = false;
2061
2054
  emitEndSpeakEvent();
2062
2055
  }
2063
2056
  );
@@ -3425,4 +3418,4 @@ const MemoriWidget = ({
3425
3418
  );
3426
3419
  };
3427
3420
 
3428
- export default MemoriWidget;
3421
+ export default MemoriWidget;
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect } from 'react';
2
2
  import Spin from '../ui/Spin';
3
3
  import { LayoutProps } from '../MemoriWidget/MemoriWidget';
4
4
 
@@ -21,6 +21,15 @@ const ZoomedFullBodyLayout: React.FC<LayoutProps> = ({
21
21
  loading = false,
22
22
  poweredBy,
23
23
  }) => {
24
+
25
+ useEffect(() => {
26
+ document.body.style.overflow = 'hidden';
27
+ return () => {
28
+ document.body.style.overflow = '';
29
+ };
30
+ }, []);
31
+
32
+
24
33
  return (
25
34
  <>
26
35
  {integrationStyle}
@@ -12,7 +12,7 @@
12
12
  }
13
13
 
14
14
  .memori--grid-column--zoomed-full-body {
15
- max-height: calc(100% - 80px) !important;
15
+ max-height: calc(100% - 130px) !important;
16
16
  }
17
17
 
18
18
  .memori.memori-widget.memori-layout-zoomed_full_body .memori--grid {
@@ -53,9 +53,9 @@ const VISEME_MAP: { [key: number]: string } = {
53
53
  };
54
54
 
55
55
  const DEFAULT_VISEME_DURATION = 0.04; //0; // Reduced from 0.4 for smoother transitions
56
- const VISEME_OVERLAP = 0.15; // Slightly increased from 0.04 for more overlap
56
+ const VISEME_OVERLAP = 0.02; // Slightly increased from 0.04 for more overlap
57
57
  const SMOOTHING_FACTOR = 0.35; // New constant for weight smoothing
58
- const TIME_OFFSET = -0.04; // Adjust this value as needed (in seconds)
58
+ const TIME_OFFSET = 0; // Adjust this value as needed (in seconds)
59
59
  const PRELOAD_TIME = 1; // Preload visemes 0.5 seconds in advance
60
60
 
61
61
  export const VisemeProvider: React.FC<{ children: React.ReactNode }> = ({
@@ -28,6 +28,31 @@ export const Anonymous = Template.bind({});
28
28
  Anonymous.args = {
29
29
  ownerUserName: 'nzambello',
30
30
  memoriName: 'Nicola',
31
+ tenantID: 'www.aisuru.com',
32
+ engineURL: 'https://engine.memori.ai',
33
+ apiURL: 'https://backend.memori.ai',
34
+ baseURL: 'https://www.aisuru.com',
35
+ uiLang: 'IT',
36
+ spokenLang: 'IT',
37
+ layout: 'ZOOMED_FULL_BODY',
38
+ showInstruct: 'false',
39
+ showSettings: 'true',
40
+ showClear: 'false',
41
+ showAIicon: 'true',
42
+ showWhyThisAnswer: 'true',
43
+ showTypingText: 'false',
44
+ showOnlyLastMessages: 'false',
45
+ showTranslationOriginal: 'false',
46
+ showCopyButton: 'false',
47
+ showShare: 'true',
48
+ showLogin: 'false',
49
+ enableAudio: 'true',
50
+ };
51
+
52
+ export const Nunzio = Template.bind({});
53
+ Nunzio.args = {
54
+ ownerUserName: 'nunzio.fiore',
55
+ memoriName: 'Nunzio',
31
56
  tenantID: 'aisuru.com',
32
57
  apiURL: 'https://backend.memori.ai',
33
58
  baseURL: 'https://www.aisuru.com',
@@ -95,18 +120,6 @@ Giovanna.args = {
95
120
  uiLang: 'IT',
96
121
  spokenLang: 'IT',
97
122
  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
123
  };
111
124
 
112
125
  export const GiovannaProva = Template.bind({});
@@ -122,6 +135,21 @@ GiovannaProva.args = {
122
135
  uiLang: 'EN',
123
136
  spokenLang: 'IT',
124
137
  layout: 'ZOOMED_FULL_BODY',
138
+ integrationID: 'e92ac275-39b5-474d-8f9e-826cc5284f1e',
139
+ initialQuestion: 'inizio simulazione',
140
+ };
141
+
142
+ export const NunzioFiore = Template.bind({});
143
+ NunzioFiore.args = {
144
+ ownerUserName: 'nunzio.fiore',
145
+ memoriName: 'Nunzio',
146
+ tenantID: 'www.aisuru.com',
147
+ engineURL: 'https://engine.memori.ai',
148
+ apiURL: 'https://backend.memori.ai',
149
+ baseURL: 'https://www.aisuru.com',
150
+ uiLang: 'IT',
151
+ spokenLang: 'IT',
152
+ layout: 'ZOOMED_FULL_BODY',
125
153
  showInstruct: 'false',
126
154
  showSettings: 'true',
127
155
  showClear: 'false',
@@ -134,10 +162,9 @@ GiovannaProva.args = {
134
162
  showShare: 'true',
135
163
  showLogin: 'false',
136
164
  enableAudio: 'true',
137
- integrationID: 'e92ac275-39b5-474d-8f9e-826cc5284f1e',
138
- initialQuestion: 'inizio simulazione',
139
165
  };
140
166
 
167
+
141
168
  const TemplateWithBatchButton: Story<Props> = args => (
142
169
  <div>
143
170
  <button