@memori.ai/memori-react 1.0.0-alpha.21 → 1.0.0-alpha.22

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.
@@ -31,7 +31,7 @@ import React, {
31
31
  } from 'react';
32
32
  import { useTranslation } from 'react-i18next';
33
33
  import memoriApiClient from '@memori.ai/memori-api-client';
34
- import { AudioContext } from 'standardized-audio-context';
34
+ import { AudioContext, IAudioContext } from 'standardized-audio-context';
35
35
  import * as speechSdk from 'microsoft-cognitiveservices-speech-sdk';
36
36
  import cx from 'classnames';
37
37
 
@@ -143,6 +143,7 @@ let recognizer: SpeechRecognizer | null;
143
143
  let speechConfig: SpeechConfig;
144
144
  let speechSynthesizer: SpeechSynthesizer | null;
145
145
  let audioDestination: SpeakerAudioDestination;
146
+ let audioContext: IAudioContext;
146
147
 
147
148
  export interface Props {
148
149
  memori: Memori;
@@ -254,7 +255,7 @@ const MemoriWidget = ({
254
255
  const [showPositionDrawer, setShowPositionDrawer] = useState(false);
255
256
  const [showSettingsDrawer, setShowSettingsDrawer] = useState(false);
256
257
  const [muteSpeaker, setMuteSpeaker] = useState(false);
257
- const [continuousSpeech, setContinuousSpeech] = useState(false);
258
+ const [continuousSpeech, setContinuousSpeech] = useState(true);
258
259
  const [continuousSpeechTimeout, setContinuousSpeechTimeout] = useState(3);
259
260
  const [isPlayingAudio, setIsPlayingAudio] = useState(false);
260
261
  useEffect(() => {
@@ -264,7 +265,7 @@ const MemoriWidget = ({
264
265
 
265
266
  useEffect(() => {
266
267
  setMuteSpeaker(getLocalConfig('muteSpeaker', false));
267
- setContinuousSpeech(getLocalConfig('continuousSpeech', false));
268
+ setContinuousSpeech(getLocalConfig('continuousSpeech', true));
268
269
  setContinuousSpeechTimeout(getLocalConfig('continuousSpeechTimeout', 3));
269
270
  }, []);
270
271
 
@@ -379,6 +380,7 @@ const MemoriWidget = ({
379
380
  media: currentState.media,
380
381
  fromUser: false,
381
382
  });
383
+ speak(currentState.emission);
382
384
  }
383
385
  } else {
384
386
  console.error(response, resp);
@@ -405,6 +407,7 @@ const MemoriWidget = ({
405
407
  media: currentState.media,
406
408
  fromUser: false,
407
409
  });
410
+ speak(currentState.emission);
408
411
  }
409
412
  } else {
410
413
  console.error(response, resp);
@@ -420,19 +423,25 @@ const MemoriWidget = ({
420
423
  !instruct &&
421
424
  isMultilanguageEnabled
422
425
  ) {
423
- translateDialogState(currentState, userLang);
426
+ translateDialogState(currentState, userLang).then(ts => {
427
+ if (ts.emission) {
428
+ speak(ts.emission);
429
+ }
430
+ });
424
431
  } else {
425
432
  setCurrentDialogState({
426
433
  ...currentState,
427
434
  emission,
428
435
  });
429
436
 
430
- if (emission)
437
+ if (emission) {
431
438
  pushMessage({
432
439
  text: emission,
433
440
  media: currentState.media,
434
441
  fromUser: false,
435
442
  });
443
+ speak(emission);
444
+ }
436
445
  }
437
446
  } else if (response.resultCode === 404) {
438
447
  // remove last sent message, will set it as initial
@@ -447,15 +456,16 @@ const MemoriWidget = ({
447
456
  instruct && memori.giverPIN ? memori.giverPIN : undefined,
448
457
  initialContextVars,
449
458
  initialQuestion
450
- ).then(sessionID => {
459
+ ).then(state => {
451
460
  console.info('session timeout');
452
- if (sessionID) {
461
+ if (state?.sessionID) {
453
462
  setTimeout(() => {
454
- sendMessage(text, media, sessionID);
463
+ sendMessage(text, media, state?.sessionID);
455
464
  }, 500);
456
465
  }
457
466
  });
458
467
  }
468
+
459
469
  setMemoriTyping(false);
460
470
  };
461
471
 
@@ -577,53 +587,6 @@ const MemoriWidget = ({
577
587
  session.resultCode === 0
578
588
  ) {
579
589
  setSessionId(session.sessionID);
580
- const language =
581
- memori.culture?.split('-')?.[0] ?? i18n.language ?? 'IT';
582
-
583
- if (
584
- !instruct &&
585
- isMultilanguageEnabled &&
586
- userLang.toLowerCase() !== language.toLowerCase()
587
- ) {
588
- translateDialogState(session.currentState, userLang).then(state => {
589
- if (state?.emission) {
590
- history.length <= 1
591
- ? setHistory([
592
- {
593
- text: state.emission,
594
- media: state.media,
595
- fromUser: false,
596
- initial: true,
597
- },
598
- ])
599
- : pushMessage({
600
- text: state.emission,
601
- media: state.media,
602
- fromUser: false,
603
- initial: true,
604
- });
605
- }
606
- });
607
- } else {
608
- setCurrentDialogState(session.currentState);
609
- if (session.currentState.emission) {
610
- history.length <= 1
611
- ? setHistory([
612
- {
613
- text: session.currentState.emission,
614
- media: session.currentState.media,
615
- fromUser: false,
616
- initial: true,
617
- },
618
- ])
619
- : pushMessage({
620
- text: session.currentState.emission,
621
- media: session.currentState.media,
622
- fromUser: false,
623
- initial: true,
624
- });
625
- }
626
- }
627
590
 
628
591
  if (position) applyPosition(position, session.sessionID);
629
592
 
@@ -688,7 +651,10 @@ const MemoriWidget = ({
688
651
  if (position) applyPosition(position, sessionID);
689
652
 
690
653
  setLoading(false);
691
- return sessionID;
654
+ return {
655
+ dialogState: currentState,
656
+ sessionID,
657
+ };
692
658
  } else {
693
659
  console.error(response);
694
660
  message.error(t(getErrori18nKey(response.resultCode)));
@@ -721,7 +687,6 @@ const MemoriWidget = ({
721
687
 
722
688
  if (resultCode === 0) {
723
689
  let textResult = 0;
724
- // console.debug('[APPCONTEXT/CHANGETAG]', currentState);
725
690
  if (
726
691
  tag !== anonTag &&
727
692
  pin &&
@@ -846,13 +811,18 @@ const MemoriWidget = ({
846
811
  translateDialogState(
847
812
  { ...currentState, emission: emission },
848
813
  userLang
849
- );
814
+ ).then(ts => {
815
+ if (ts.emission) {
816
+ speak(ts.emission);
817
+ }
818
+ });
850
819
  } else if (emission && emission.length > 0) {
851
820
  pushMessage({
852
821
  text: emission,
853
822
  media: currentState.media,
854
823
  fromUser: false,
855
824
  });
825
+ speak(emission);
856
826
  setCurrentDialogState(currentState);
857
827
  }
858
828
  }
@@ -916,40 +886,19 @@ const MemoriWidget = ({
916
886
  speechConfig.speechSynthesisOutputFormat =
917
887
  speechSdk.SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3;
918
888
 
919
- let memoriAudioElement = document.getElementById(
920
- 'memori-audio'
921
- ) as HTMLAudioElement;
922
- if (memoriAudioElement && window.navigator.userAgent.includes('Safari')) {
923
- memoriAudioElement.muted = false;
924
- memoriAudioElement
925
- .play()
926
- .then(() => {
927
- console.log('played intro audio');
928
- try {
929
- const context = new AudioContext();
930
- let buffer = context.createBuffer(1, 1, 22050);
931
- let source = context.createBufferSource();
932
- source.buffer = buffer;
933
- source.connect(context.destination);
934
- } catch (e) {
935
- console.error(e);
936
- }
937
- })
938
- .catch((e: any) => {
939
- console.error('error playing intro audio', e);
940
- });
941
- }
889
+ audioContext = new AudioContext();
890
+ let buffer = audioContext.createBuffer(1, 10000, 22050);
891
+ let source = audioContext.createBufferSource();
892
+ source.buffer = buffer;
893
+ source.connect(audioContext.destination);
894
+
895
+ audioDestination = new speechSdk.SpeakerAudioDestination();
896
+ let audioConfig = speechSdk.AudioConfig.fromSpeakerOutput(audioDestination);
897
+ speechSynthesizer = new speechSdk.SpeechSynthesizer(
898
+ speechConfig,
899
+ audioConfig
900
+ );
942
901
  };
943
- useEffect(() => {
944
- return () => {
945
- if (audioDestination) audioDestination.pause();
946
- if (speechSynthesizer) {
947
- speechSynthesizer.close();
948
- speechSynthesizer = null;
949
- }
950
- };
951
- // eslint-disable-next-line react-hooks/exhaustive-deps
952
- }, []);
953
902
 
954
903
  const getTTSVoice = useCallback(
955
904
  (lang?: string): string => {
@@ -1032,8 +981,12 @@ const MemoriWidget = ({
1032
981
 
1033
982
  const getCultureCodeByLanguage = (lang?: string): string => {
1034
983
  let voice = '';
1035
- let voiceLang = (lang ?? memori.culture?.split('-')?.[0] ?? i18n.language,
1036
- 'IT').toUpperCase();
984
+ let voiceLang = (
985
+ lang ||
986
+ memori.culture?.split('-')?.[0] ||
987
+ i18n.language ||
988
+ 'IT'
989
+ ).toUpperCase();
1037
990
  switch (voiceLang) {
1038
991
  case 'IT':
1039
992
  voice = 'it-IT';
@@ -1121,7 +1074,7 @@ const MemoriWidget = ({
1121
1074
  // .replace(/qfe/gi, `<sub alias="Quota Filo Erba">QFE</sub>`)
1122
1075
  };
1123
1076
 
1124
- const speak = (text: string, fireListeningEvent = true): void => {
1077
+ const speak = (text: string): void => {
1125
1078
  console.log(
1126
1079
  AZURE_COGNITIVE_SERVICES_TTS_KEY,
1127
1080
  hasUserActivatedSpeak,
@@ -1129,59 +1082,54 @@ const MemoriWidget = ({
1129
1082
  );
1130
1083
  if (!AZURE_COGNITIVE_SERVICES_TTS_KEY) return;
1131
1084
 
1132
- if (preview || !hasUserActivatedSpeak) return;
1085
+ if (preview) return;
1086
+
1133
1087
  if (audioDestination) audioDestination.pause();
1134
- if (speechSynthesizer) {
1135
- speechSynthesizer.close();
1136
- speechSynthesizer = null;
1088
+
1089
+ let isSafari =
1090
+ window.navigator.userAgent.includes('Safari') &&
1091
+ !window.navigator.userAgent.includes('Chrome');
1092
+ let isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
1093
+ if (isIOS && isSafari) {
1094
+ audioContext.suspend();
1095
+ } else if (audioContext.state === 'suspended') {
1096
+ stopAudio();
1097
+ audioContext = new AudioContext();
1098
+ let buffer = audioContext.createBuffer(1, 10000, 22050);
1099
+ let source = audioContext.createBufferSource();
1100
+ source.buffer = buffer;
1101
+ source.connect(audioContext.destination);
1137
1102
  }
1138
1103
 
1139
- if (muteSpeaker && fireListeningEvent) {
1140
- setTimeout(() => {
1141
- // trigger start continuous listening if set, see MemoriChat
1142
- document.dispatchEvent(new Event('endSpeakStartListen'));
1143
- }, 3000);
1144
- return;
1145
- } else if (muteSpeaker) {
1146
- return;
1104
+ if (!speechSynthesizer) {
1105
+ audioDestination = new speechSdk.SpeakerAudioDestination();
1106
+ let audioConfig =
1107
+ speechSdk.AudioConfig.fromSpeakerOutput(audioDestination);
1108
+ speechSynthesizer = new speechSdk.SpeechSynthesizer(
1109
+ speechConfig,
1110
+ audioConfig
1111
+ );
1147
1112
  }
1148
1113
 
1149
- audioDestination = new speechSdk.SpeakerAudioDestination();
1150
- let audioConfig = speechSdk.AudioConfig.fromSpeakerOutput(audioDestination);
1151
- speechSynthesizer = new speechSdk.SpeechSynthesizer(
1152
- speechConfig,
1153
- audioConfig
1154
- );
1114
+ if (muteSpeaker) {
1115
+ // trigger start continuous listening if set, see MemoriChat
1116
+ if (continuousSpeech) {
1117
+ setListeningTimeout();
1118
+ }
1119
+ return;
1120
+ }
1155
1121
 
1156
1122
  audioDestination.onAudioEnd = () => {
1157
1123
  setIsPlayingAudio(false);
1158
1124
 
1159
- if (fireListeningEvent) {
1160
- // trigger start continuous listening if set, see MemoriChat
1125
+ if (continuousSpeech) {
1126
+ // trigger start continuous listening if set
1161
1127
  document.dispatchEvent(new Event('endSpeakStartListen'));
1162
1128
  }
1163
1129
  };
1164
1130
 
1165
- // speechSynthesizer.visemeReceived = function (s, e) {
1166
- // window.console.log(
1167
- // '(Viseme), Audio offset: ' +
1168
- // e.audioOffset / 10000 +
1169
- // 'ms. Viseme ID: ' +
1170
- // e.visemeId,
1171
- // e,
1172
- // );
1173
-
1174
- // // `Animation` is an xml string for SVG or a json string for blend shapes
1175
- // // var animation = e.Animation;
1176
- // };
1177
-
1178
1131
  setIsPlayingAudio(true);
1179
- console.log('speaking', text);
1180
- console.log('speechSynthesizer', speechSynthesizer);
1181
- console.log('audioDestination', audioDestination);
1182
- console.log('speechConfig', speechConfig);
1183
- console.log('audioConfig', audioConfig);
1184
- // window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
1132
+
1185
1133
  speechSynthesizer.speakSsmlAsync(
1186
1134
  `<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(
1187
1135
  userLang
@@ -1191,7 +1139,19 @@ const MemoriWidget = ({
1191
1139
  )}</s></voice></speak>`,
1192
1140
  result => {
1193
1141
  if (result) {
1142
+ console.log('result', result);
1194
1143
  try {
1144
+ audioContext.decodeAudioData(result.audioData, function (buffer) {
1145
+ const source = audioContext.createBufferSource();
1146
+ source.buffer = buffer;
1147
+ source.connect(audioContext.destination);
1148
+
1149
+ if (history.length < 1 || (isSafari && isIOS)) {
1150
+ source.start(0);
1151
+ }
1152
+ });
1153
+ audioContext.resume();
1154
+
1195
1155
  if (speechSynthesizer) {
1196
1156
  speechSynthesizer.close();
1197
1157
  speechSynthesizer = null;
@@ -1200,9 +1160,14 @@ const MemoriWidget = ({
1200
1160
  console.error('speak error: ', e);
1201
1161
  window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
1202
1162
  setIsPlayingAudio(false);
1163
+
1164
+ if (speechSynthesizer) {
1165
+ speechSynthesizer.close();
1166
+ speechSynthesizer = null;
1167
+ }
1203
1168
  }
1204
1169
  } else {
1205
- window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
1170
+ audioContext.resume();
1206
1171
  setIsPlayingAudio(false);
1207
1172
  }
1208
1173
  },
@@ -1214,12 +1179,20 @@ const MemoriWidget = ({
1214
1179
  );
1215
1180
 
1216
1181
  setIsPlayingAudio(false);
1182
+ setMemoriTyping(false);
1217
1183
  };
1218
1184
  const stopAudio = () => {
1219
1185
  if (speechSynthesizer) {
1220
1186
  speechSynthesizer.close();
1221
1187
  speechSynthesizer = null;
1222
1188
  }
1189
+ if (audioContext) {
1190
+ audioContext.close();
1191
+ }
1192
+ if (audioDestination) {
1193
+ audioDestination.pause();
1194
+ audioDestination.close();
1195
+ }
1223
1196
  };
1224
1197
 
1225
1198
  /**
@@ -1271,10 +1244,7 @@ const MemoriWidget = ({
1271
1244
  useEffect(() => {
1272
1245
  resetListeningTimeout();
1273
1246
  resetInteractionTimeout();
1274
- if (transcript?.length > 0) {
1275
- const transcriptMessage = stripDuplicates(transcript);
1276
- if (transcriptMessage.length > 0) setUserMessage(transcriptMessage);
1277
- }
1247
+
1278
1248
  // eslint-disable-next-line react-hooks/exhaustive-deps
1279
1249
  }, [transcript]);
1280
1250
 
@@ -1317,7 +1287,13 @@ const MemoriWidget = ({
1317
1287
  setListening(true);
1318
1288
  recognizer.recognized = (_s, e) => {
1319
1289
  if (e.result.reason === speechSdk.ResultReason.RecognizedSpeech) {
1320
- setTranscript(e.result.text ?? '');
1290
+ let transcript = e.result.text;
1291
+ setTranscript(transcript || '');
1292
+ if (transcript?.length > 0) {
1293
+ const transcriptMessage = stripDuplicates(transcript);
1294
+ if (transcriptMessage.length > 0)
1295
+ setUserMessage(transcriptMessage);
1296
+ }
1321
1297
  } else if (e.result.reason === speechSdk.ResultReason.NoMatch) {
1322
1298
  console.debug('NOMATCH: Speech could not be recognized.');
1323
1299
  }
@@ -1374,19 +1350,6 @@ const MemoriWidget = ({
1374
1350
  // eslint-disable-next-line react-hooks/exhaustive-deps
1375
1351
  }, [currentDialogState?.state]);
1376
1352
 
1377
- useEffect(() => {
1378
- if (
1379
- hasUserActivatedSpeak &&
1380
- !preview &&
1381
- !muteSpeaker &&
1382
- history.length > 0 &&
1383
- currentDialogState?.emission
1384
- ) {
1385
- speak(currentDialogState.emission, currentDialogState.state !== 'Z0');
1386
- }
1387
- // eslint-disable-next-line react-hooks/exhaustive-deps
1388
- }, [currentDialogState, hasUserActivatedSpeak]);
1389
-
1390
1353
  /**
1391
1354
  * Speech recognition event handlers
1392
1355
  */
@@ -1658,7 +1621,19 @@ const MemoriWidget = ({
1658
1621
  const sessionID = session?.sessionID || sessionId;
1659
1622
  const dialogState = session?.dialogState || currentDialogState;
1660
1623
  setClickedStart(true);
1661
- console.log('onClickStart');
1624
+
1625
+ let memoriAudioElement = document.getElementById(
1626
+ 'memori-audio'
1627
+ ) as HTMLAudioElement;
1628
+ let isSafari =
1629
+ window.navigator.userAgent.includes('Safari') &&
1630
+ !window.navigator.userAgent.includes('Chrome');
1631
+ if (memoriAudioElement && isSafari) {
1632
+ memoriAudioElement.muted = false;
1633
+ memoriAudioElement.play().catch((e: any) => {
1634
+ console.error('error playing intro audio', e);
1635
+ });
1636
+ }
1662
1637
 
1663
1638
  if (
1664
1639
  (!sessionID &&
@@ -1682,7 +1657,7 @@ const MemoriWidget = ({
1682
1657
  initialContextVars,
1683
1658
  initialQuestion,
1684
1659
  });
1685
- onClickStart(session || undefined);
1660
+ await onClickStart(session || undefined);
1686
1661
  return;
1687
1662
  } else if (initialSessionID) {
1688
1663
  // check if session is valid and not expired
@@ -1692,7 +1667,7 @@ const MemoriWidget = ({
1692
1667
  setGotErrorInOpening(true);
1693
1668
  setSessionId(undefined);
1694
1669
  setClickedStart(false);
1695
- onClickStart();
1670
+ await onClickStart();
1696
1671
  return;
1697
1672
  }
1698
1673
 
@@ -1722,9 +1697,15 @@ const MemoriWidget = ({
1722
1697
  );
1723
1698
 
1724
1699
  if (session && session.resultCode === 0) {
1725
- translateDialogState(session.currentState, userLang).finally(() => {
1726
- setHasUserActivatedSpeak(true);
1727
- });
1700
+ translateDialogState(session.currentState, userLang)
1701
+ .then(ts => {
1702
+ if (ts.emission) {
1703
+ speak(ts.emission);
1704
+ }
1705
+ })
1706
+ .finally(() => {
1707
+ setHasUserActivatedSpeak(true);
1708
+ });
1728
1709
  } else {
1729
1710
  console.error('session #1', session);
1730
1711
  throw new Error('No session');
@@ -1762,9 +1743,15 @@ const MemoriWidget = ({
1762
1743
  );
1763
1744
 
1764
1745
  if (session && session.resultCode === 0) {
1765
- translateDialogState(session.currentState, userLang).finally(() => {
1766
- setHasUserActivatedSpeak(true);
1767
- });
1746
+ translateDialogState(session.currentState, userLang)
1747
+ .then(ts => {
1748
+ if (ts.emission) {
1749
+ speak(ts.emission);
1750
+ }
1751
+ })
1752
+ .finally(() => {
1753
+ setHasUserActivatedSpeak(true);
1754
+ });
1768
1755
  } else {
1769
1756
  console.error('session #4', session);
1770
1757
  throw new Error('No session');
@@ -1802,9 +1789,15 @@ const MemoriWidget = ({
1802
1789
  );
1803
1790
 
1804
1791
  if (session && session.resultCode === 0) {
1805
- translateDialogState(session.currentState, userLang).finally(() => {
1806
- setHasUserActivatedSpeak(true);
1807
- });
1792
+ translateDialogState(session.currentState, userLang)
1793
+ .then(ts => {
1794
+ if (ts.emission) {
1795
+ speak(ts.emission);
1796
+ }
1797
+ })
1798
+ .finally(() => {
1799
+ setHasUserActivatedSpeak(true);
1800
+ });
1808
1801
  } else {
1809
1802
  console.error('session #7', session);
1810
1803
  throw new Error('No session');
@@ -1825,18 +1818,30 @@ const MemoriWidget = ({
1825
1818
  }
1826
1819
  } else {
1827
1820
  // no need to change tag
1828
- translateDialogState(currentState, userLang).finally(() => {
1829
- setHasUserActivatedSpeak(true);
1830
- });
1821
+ translateDialogState(currentState, userLang)
1822
+ .then(ts => {
1823
+ if (ts.emission) {
1824
+ speak(ts.emission);
1825
+ }
1826
+ })
1827
+ .finally(() => {
1828
+ setHasUserActivatedSpeak(true);
1829
+ });
1831
1830
  }
1832
1831
  } else {
1833
1832
  // reset history
1834
1833
  setHistory([]);
1835
1834
 
1836
1835
  // everything is fine, just translate dialog state and activate chat
1837
- translateDialogState(dialogState!, userLang).finally(() => {
1838
- setHasUserActivatedSpeak(true);
1839
- });
1836
+ translateDialogState(dialogState!, userLang)
1837
+ .then(ts => {
1838
+ if (ts.emission) {
1839
+ speak(ts.emission);
1840
+ }
1841
+ })
1842
+ .finally(() => {
1843
+ setHasUserActivatedSpeak(true);
1844
+ });
1840
1845
  }
1841
1846
  };
1842
1847
 
@@ -1890,7 +1895,18 @@ const MemoriWidget = ({
1890
1895
  setShowPositionDrawer={setShowPositionDrawer}
1891
1896
  setShowSettingsDrawer={setShowSettingsDrawer}
1892
1897
  speakerMuted={muteSpeaker}
1893
- setSpeakerMuted={setMuteSpeaker}
1898
+ setSpeakerMuted={mute => {
1899
+ setMuteSpeaker(mute);
1900
+ if (mute) {
1901
+ stopAudio();
1902
+ } else {
1903
+ audioContext = new AudioContext();
1904
+ let buffer = audioContext.createBuffer(1, 10000, 22050);
1905
+ let source = audioContext.createBufferSource();
1906
+ source.buffer = buffer;
1907
+ source.connect(audioContext.destination);
1908
+ }
1909
+ }}
1894
1910
  showSettings={showSettings}
1895
1911
  hasUserActivatedSpeak={hasUserActivatedSpeak}
1896
1912
  />
@@ -2070,9 +2086,9 @@ const MemoriWidget = ({
2070
2086
  initialContextVars,
2071
2087
  initialQuestion
2072
2088
  )
2073
- .then(() => {
2089
+ .then(state => {
2074
2090
  setAuthModalState(null);
2075
- setHasUserActivatedSpeak(true);
2091
+ onClickStart(state || undefined);
2076
2092
  })
2077
2093
  .catch(() => {
2078
2094
  setAuthModalState(null);
@@ -2119,6 +2135,7 @@ const MemoriWidget = ({
2119
2135
  media: currentState.media,
2120
2136
  fromUser: false,
2121
2137
  });
2138
+ speak(currentState.emission);
2122
2139
  }
2123
2140
  } else {
2124
2141
  console.error(resp, currentState, medium);
@@ -2174,6 +2191,7 @@ const MemoriWidget = ({
2174
2191
  media: currentState.media,
2175
2192
  fromUser: false,
2176
2193
  });
2194
+ speak(currentState.emission);
2177
2195
  }
2178
2196
  } else {
2179
2197
  console.error(resp, currentState, medium);
@@ -213,6 +213,9 @@ const StartPanel: React.FC<Props> = ({
213
213
  disabled={!!memori.blockedUntil && !memori.isGiver}
214
214
  loading={clickedStart}
215
215
  onClick={_e => {
216
+ speechSynthesis.speak(
217
+ new SpeechSynthesisUtterance('') // This is needed to enable the speech synthesis on iOS
218
+ );
216
219
  if (initializeTTS) initializeTTS();
217
220
  if (onClickStart) onClickStart();
218
221
  }}