@memori.ai/memori-react 7.6.0 → 7.7.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 +25 -0
- package/dist/components/Avatar/Avatar.js +2 -2
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +4 -3
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +10 -6
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +11 -17
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +128 -104
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +1 -4
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +2 -4
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/index.d.ts +5 -3
- package/dist/components/Avatar/AvatarView/index.js +2 -2
- package/dist/components/Avatar/AvatarView/index.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +117 -118
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/layouts/HiddenChat.js +3 -4
- package/dist/components/layouts/HiddenChat.js.map +1 -1
- package/dist/components/layouts/ZoomedFullBody.d.ts +2 -2
- package/dist/components/layouts/ZoomedFullBody.js +11 -2
- package/dist/components/layouts/ZoomedFullBody.js.map +1 -1
- package/dist/components/layouts/hidden-chat.css +23 -23
- package/dist/components/layouts/zoomed-full-body.css +16 -0
- package/dist/context/visemeContext.d.ts +8 -15
- package/dist/context/visemeContext.js +64 -166
- package/dist/context/visemeContext.js.map +1 -1
- package/dist/helpers/translations.js +10 -2
- package/dist/helpers/translations.js.map +1 -1
- package/dist/helpers/utils.js +5 -6
- package/dist/helpers/utils.js.map +1 -1
- package/dist/styles.css +1 -0
- package/esm/components/Avatar/Avatar.js +2 -2
- package/esm/components/Avatar/Avatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +4 -3
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +10 -6
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +11 -17
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +131 -107
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +1 -4
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +2 -4
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/index.d.ts +5 -3
- package/esm/components/Avatar/AvatarView/index.js +2 -2
- package/esm/components/Avatar/AvatarView/index.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +117 -118
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/layouts/HiddenChat.js +3 -4
- package/esm/components/layouts/HiddenChat.js.map +1 -1
- package/esm/components/layouts/ZoomedFullBody.d.ts +2 -2
- package/esm/components/layouts/ZoomedFullBody.js +11 -2
- package/esm/components/layouts/ZoomedFullBody.js.map +1 -1
- package/esm/components/layouts/hidden-chat.css +23 -23
- package/esm/components/layouts/zoomed-full-body.css +16 -0
- package/esm/context/visemeContext.d.ts +8 -15
- package/esm/context/visemeContext.js +65 -167
- package/esm/context/visemeContext.js.map +1 -1
- package/esm/helpers/translations.js +10 -2
- package/esm/helpers/translations.js.map +1 -1
- package/esm/helpers/utils.js +5 -6
- package/esm/helpers/utils.js.map +1 -1
- package/esm/styles.css +1 -0
- package/package.json +1 -1
- package/src/components/Avatar/Avatar.stories.tsx +7 -5
- package/src/components/Avatar/Avatar.tsx +3 -5
- package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +20 -19
- package/src/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.tsx +206 -140
- package/src/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.tsx +1 -7
- package/src/components/Avatar/AvatarView/AvatarView.stories.tsx +36 -24
- package/src/components/Avatar/AvatarView/index.tsx +3 -8
- package/src/components/MemoriWidget/MemoriWidget.tsx +140 -160
- package/src/components/layouts/HiddenChat.tsx +13 -14
- package/src/components/layouts/ZoomedFullBody.tsx +38 -29
- package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +12 -12
- package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +25 -21
- package/src/components/layouts/hidden-chat.css +23 -23
- package/src/components/layouts/zoomed-full-body.css +16 -0
- package/src/context/visemeContext.tsx +90 -260
- package/src/helpers/translations.ts +11 -8
- package/src/helpers/utils.ts +9 -8
- package/src/styles.css +1 -0
|
@@ -17,7 +17,9 @@ export interface Props {
|
|
|
17
17
|
isZoomed?: boolean;
|
|
18
18
|
chatEmission?: any;
|
|
19
19
|
setMeshRef?: any;
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
updateCurrentViseme: (currentTime: number) => {
|
|
21
|
+
name: string;
|
|
22
|
+
weight: number;
|
|
23
|
+
} | null;
|
|
22
24
|
}
|
|
23
|
-
export default function ContainerAvatarView({ url, sex, style, rotateAvatar, eyeBlink, headMovement, speaking, fallback, fallbackImg, halfBody, loading, animation, showControls, isZoomed, chatEmission,
|
|
25
|
+
export default function ContainerAvatarView({ url, sex, style, rotateAvatar, eyeBlink, headMovement, speaking, fallback, fallbackImg, halfBody, loading, animation, showControls, isZoomed, chatEmission, updateCurrentViseme, }: Props): JSX.Element;
|
|
@@ -34,8 +34,8 @@ const getCameraSettings = (halfBody, isZoomed) => halfBody
|
|
|
34
34
|
}
|
|
35
35
|
: { fov: 40, position: [0, 0.0000175, 3] };
|
|
36
36
|
const getLightingComponent = () => (0, utils_1.isAndroid)() || (0, utils_1.isiOS)() ? ((0, jsx_runtime_1.jsx)(drei_1.SpotLight, { distance: 100, position: [-0.3, 0.2, 1.25], angle: Math.PI / 2, attenuation: 5, anglePower: 5 })) : ((0, jsx_runtime_1.jsx)(drei_1.Environment, { files: "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/venice_sunset_1k.hdr" }));
|
|
37
|
-
function ContainerAvatarView({ url, sex, style, rotateAvatar, eyeBlink, headMovement, speaking, fallback, fallbackImg, halfBody = true, loading, animation, showControls = false, isZoomed, chatEmission,
|
|
38
|
-
return ((0, jsx_runtime_1.jsx)(fiber_1.Canvas, { style: style || (halfBody ? defaultStyles.halfBody : defaultStyles.fullBody), camera: getCameraSettings(halfBody, isZoomed), children: (0, jsx_runtime_1.jsxs)(react_1.Suspense, { fallback: fallback || (0, jsx_runtime_1.jsx)(loader_1.default, { fallbackImg: fallbackImg }), children: [getLightingComponent(), rotateAvatar && (0, jsx_runtime_1.jsx)(drei_1.OrbitControls, { enablePan: false, enableZoom: false }), (0, jsx_runtime_1.jsx)(avatarComponent_1.AvatarView, { url: url, sex: sex, showControls: showControls, loading: loading || false, animation: animation, isZoomed: isZoomed || false, eyeBlink: eyeBlink || false, headMovement: headMovement || false, speaking: speaking || false, halfBody: halfBody || false, chatEmission: chatEmission,
|
|
37
|
+
function ContainerAvatarView({ url, sex, style, rotateAvatar, eyeBlink, headMovement, speaking, fallback, fallbackImg, halfBody = true, loading, animation, showControls = false, isZoomed, chatEmission, updateCurrentViseme, }) {
|
|
38
|
+
return ((0, jsx_runtime_1.jsx)(fiber_1.Canvas, { style: style || (halfBody ? defaultStyles.halfBody : defaultStyles.fullBody), camera: getCameraSettings(halfBody, isZoomed), children: (0, jsx_runtime_1.jsxs)(react_1.Suspense, { fallback: fallback || (0, jsx_runtime_1.jsx)(loader_1.default, { fallbackImg: fallbackImg }), children: [getLightingComponent(), rotateAvatar && (0, jsx_runtime_1.jsx)(drei_1.OrbitControls, { enablePan: false, enableZoom: false }), (0, jsx_runtime_1.jsx)(avatarComponent_1.AvatarView, { url: url, sex: sex, showControls: showControls, loading: loading || false, animation: animation, isZoomed: isZoomed || false, eyeBlink: eyeBlink || false, headMovement: headMovement || false, speaking: speaking || false, halfBody: halfBody || false, chatEmission: chatEmission, updateCurrentViseme: updateCurrentViseme })] }) }));
|
|
39
39
|
}
|
|
40
40
|
exports.default = ContainerAvatarView;
|
|
41
41
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/Avatar/AvatarView/index.tsx"],"names":[],"mappings":";;;;AACA,iCAAwC;AACxC,8CAA4C;AAC5C,4CAA0E;AAC1E,kDAA0D;AAC1D,uEAA6D;AAC7D,yFAAyD;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/Avatar/AvatarView/index.tsx"],"names":[],"mappings":";;;;AACA,iCAAwC;AACxC,8CAA4C;AAC5C,4CAA0E;AAC1E,kDAA0D;AAC1D,uEAA6D;AAC7D,yFAAyD;AAsBzD,MAAM,aAAa,GAAG;IACpB,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,MAAM;QACd,SAAS,EAAE,OAAO;QAClB,eAAe,EAAE,OAAO;QACxB,YAAY,EAAE,MAAM;KACrB;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,OAAO;QACf,eAAe,EAAE,OAAO;KACzB;CACF,CAAC;AAGF,MAAM,iBAAiB,GAAG,CAAC,QAAiB,EAAE,QAAkB,EAAE,EAAE,CAClE,QAAQ;IACN,CAAC,CAAC;QACE,GAAG,EAAE,EAAE;QACP,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;KACtB;IACH,CAAC,CAAC,CAAC,QAAQ,IAAI,QAAQ;QACvB,CAAC,CAAC;YAEE,GAAG,EAAE,EAAE;YACP,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;SACvB;QACH,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC;AAE/C,MAAM,oBAAoB,GAAG,GAAG,EAAE,CAChC,IAAA,iBAAS,GAAE,IAAI,IAAA,aAAK,GAAE,CAAC,CAAC,CAAC,CACvB,uBAAC,gBAAS,IACR,QAAQ,EAAE,GAAG,EACb,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAC3B,KAAK,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,EAClB,WAAW,EAAE,CAAC,EACd,UAAU,EAAE,CAAC,GACb,CACH,CAAC,CAAC,CAAC,CACF,uBAAC,kBAAW,IAAC,KAAK,EAAC,+GAA+G,GAAG,CACtI,CAAC;AAIJ,SAAwB,mBAAmB,CAAC,EAC1C,GAAG,EACH,GAAG,EACH,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,QAAQ,GAAG,IAAI,EACf,OAAO,EACP,SAAS,EACT,YAAY,GAAG,KAAK,EACpB,QAAQ,EACR,YAAY,EACZ,mBAAmB,GACb;IACN,OAAO,CACL,uBAAC,cAAM,IACL,KAAK,EACH,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,EAEvE,MAAM,EAAE,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAQ,YAEpD,wBAAC,gBAAQ,IAAC,QAAQ,EAAE,QAAQ,IAAI,uBAAC,gBAAM,IAAC,WAAW,EAAE,WAAW,GAAI,aACjE,oBAAoB,EAAE,EACtB,YAAY,IAAI,uBAAC,oBAAa,IAAC,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,GAAI,EACvE,uBAAC,4BAAU,IACT,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,OAAO,IAAI,KAAK,EACzB,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,IAAI,KAAK,EAC3B,QAAQ,EAAE,QAAQ,IAAI,KAAK,EAC3B,YAAY,EAAE,YAAY,IAAI,KAAK,EACnC,QAAQ,EAAE,QAAQ,IAAI,KAAK,EAC3B,QAAQ,EAAE,QAAQ,IAAI,KAAK,EAC3B,YAAY,EAAE,YAAY,EAC1B,mBAAmB,EAAE,mBAAmB,GACxC,IACO,GACJ,CACV,CAAC;AACJ,CAAC;AA7CD,sCA6CC"}
|
|
@@ -219,7 +219,11 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, ownerUserName, tenan
|
|
|
219
219
|
const [isPlayingAudio, setIsPlayingAudio] = (0, react_1.useState)(false);
|
|
220
220
|
const [controlsPosition, setControlsPosition] = (0, react_1.useState)('center');
|
|
221
221
|
const [hideEmissions, setHideEmissions] = (0, react_1.useState)(false);
|
|
222
|
-
const {
|
|
222
|
+
const { startProcessing, stopProcessing, addViseme, resetVisemeQueue, isProcessing, } = (0, visemeContext_1.useViseme)();
|
|
223
|
+
const audioContextRef = (0, react_1.useRef)(null);
|
|
224
|
+
const speechSynthesizerRef = (0, react_1.useRef)(null);
|
|
225
|
+
const audioDestinationRef = (0, react_1.useRef)(null);
|
|
226
|
+
const currentSpeechRef = (0, react_1.useRef)(null);
|
|
223
227
|
(0, react_1.useEffect)(() => {
|
|
224
228
|
setIsPlayingAudio(!!speechSynthesizer);
|
|
225
229
|
memoriSpeaking = !!speechSynthesizer;
|
|
@@ -1246,16 +1250,43 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, ownerUserName, tenan
|
|
|
1246
1250
|
const e = new CustomEvent('MemoriEndSpeak');
|
|
1247
1251
|
document.dispatchEvent(e);
|
|
1248
1252
|
};
|
|
1249
|
-
const
|
|
1253
|
+
const initializeAudioContext = (0, react_1.useCallback)(() => {
|
|
1254
|
+
if (!audioContextRef.current || audioContextRef.current.state === 'closed') {
|
|
1255
|
+
audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
|
|
1256
|
+
}
|
|
1257
|
+
return audioContextRef.current;
|
|
1258
|
+
}, []);
|
|
1259
|
+
const initializeSpeechSynthesizer = (0, react_1.useCallback)((audioConfig) => {
|
|
1260
|
+
if (!speechSynthesizerRef.current && AZURE_COGNITIVE_SERVICES_TTS_KEY) {
|
|
1261
|
+
const speechConfig = speechSdk.SpeechConfig.fromSubscription(AZURE_COGNITIVE_SERVICES_TTS_KEY, 'eastus');
|
|
1262
|
+
speechSynthesizerRef.current = new speechSdk.SpeechSynthesizer(speechConfig, audioConfig);
|
|
1263
|
+
}
|
|
1264
|
+
return speechSynthesizerRef.current;
|
|
1265
|
+
}, []);
|
|
1266
|
+
const stopCurrentSpeech = (0, react_1.useCallback)(() => {
|
|
1267
|
+
if (currentSpeechRef.current) {
|
|
1268
|
+
currentSpeechRef.current.cancel();
|
|
1269
|
+
currentSpeechRef.current = null;
|
|
1270
|
+
}
|
|
1271
|
+
if (audioContextRef.current) {
|
|
1272
|
+
audioContextRef.current.suspend();
|
|
1273
|
+
}
|
|
1274
|
+
if (audioDestinationRef.current) {
|
|
1275
|
+
audioDestinationRef.current.pause();
|
|
1276
|
+
}
|
|
1277
|
+
setIsPlayingAudio(false);
|
|
1278
|
+
stopProcessing();
|
|
1279
|
+
resetVisemeQueue();
|
|
1280
|
+
}, []);
|
|
1281
|
+
const speak = (0, react_1.useCallback)(async (text) => {
|
|
1250
1282
|
if (!AZURE_COGNITIVE_SERVICES_TTS_KEY || preview) {
|
|
1251
1283
|
emitEndSpeakEvent();
|
|
1252
1284
|
return;
|
|
1253
1285
|
}
|
|
1254
1286
|
stopListening();
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
memoriSpeaking = false;
|
|
1287
|
+
stopCurrentSpeech();
|
|
1288
|
+
if (preview || muteSpeaker || speakerMuted) {
|
|
1289
|
+
setIsPlayingAudio(false);
|
|
1259
1290
|
setMemoriTyping(false);
|
|
1260
1291
|
emitEndSpeakEvent();
|
|
1261
1292
|
if (continuousSpeech) {
|
|
@@ -1263,136 +1294,98 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, ownerUserName, tenan
|
|
|
1263
1294
|
}
|
|
1264
1295
|
return;
|
|
1265
1296
|
}
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
!
|
|
1270
|
-
|
|
1271
|
-
if (audioContext.state === 'interrupted') {
|
|
1272
|
-
audioContext.resume().then(() => speak(text));
|
|
1273
|
-
return;
|
|
1274
|
-
}
|
|
1275
|
-
if (audioContext.state === 'closed') {
|
|
1276
|
-
audioContext = new standardized_audio_context_1.AudioContext();
|
|
1277
|
-
let buffer = audioContext.createBuffer(1, 10000, 22050);
|
|
1278
|
-
let source = audioContext.createBufferSource();
|
|
1279
|
-
source.buffer = buffer;
|
|
1280
|
-
source.connect(audioContext.destination);
|
|
1281
|
-
}
|
|
1282
|
-
else if (audioContext.state === 'suspended') {
|
|
1283
|
-
stopAudio();
|
|
1284
|
-
audioContext = new standardized_audio_context_1.AudioContext();
|
|
1285
|
-
let buffer = audioContext.createBuffer(1, 10000, 22050);
|
|
1286
|
-
let source = audioContext.createBufferSource();
|
|
1287
|
-
source.buffer = buffer;
|
|
1288
|
-
source.connect(audioContext.destination);
|
|
1289
|
-
}
|
|
1290
|
-
if (!speechSynthesizer) {
|
|
1291
|
-
if (!isIOS) {
|
|
1292
|
-
audioDestination = new speechSdk.SpeakerAudioDestination();
|
|
1297
|
+
try {
|
|
1298
|
+
const audioContext = initializeAudioContext();
|
|
1299
|
+
await audioContext.resume();
|
|
1300
|
+
if (!audioDestinationRef.current) {
|
|
1301
|
+
audioDestinationRef.current = new speechSdk.SpeakerAudioDestination();
|
|
1293
1302
|
}
|
|
1294
|
-
|
|
1295
|
-
speechSynthesizer =
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1303
|
+
const audioConfig = speechSdk.AudioConfig.fromSpeakerOutput(audioDestinationRef.current);
|
|
1304
|
+
const speechSynthesizer = initializeSpeechSynthesizer(audioConfig);
|
|
1305
|
+
if (speechSynthesizer) {
|
|
1306
|
+
speechSynthesizer.visemeReceived = (_, e) => {
|
|
1307
|
+
addViseme(e.visemeId, e.audioOffset);
|
|
1308
|
+
console.log('viseme added');
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
startProcessing();
|
|
1312
|
+
const textToSpeak = (0, utils_1.escapeHTML)((0, utils_1.stripMarkdown)((0, utils_1.stripEmojis)((0, utils_1.stripHTML)((0, utils_1.stripOutputTags)(text)))));
|
|
1313
|
+
const ssml = `
|
|
1314
|
+
<speak version="1.0"
|
|
1315
|
+
xmlns="http://www.w3.org/2001/10/synthesis"
|
|
1316
|
+
xmlns:mstts="https://www.w3.org/2001/mstts"
|
|
1317
|
+
xml:lang="${getCultureCodeByLanguage(userLang)}">
|
|
1318
|
+
<voice name="${getTTSVoice(userLang)}">
|
|
1319
|
+
<s>${replaceTextWithPhonemes(textToSpeak, userLang.toLowerCase())}</s>
|
|
1320
|
+
</voice>
|
|
1321
|
+
</speak>
|
|
1322
|
+
`;
|
|
1323
|
+
const speakPromise = new Promise((resolve, reject) => {
|
|
1324
|
+
speechSynthesizer === null || speechSynthesizer === void 0 ? void 0 : speechSynthesizer.speakSsmlAsync(ssml, result => resolve(result), error => reject(error));
|
|
1314
1325
|
});
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
memoriSpeaking = true;
|
|
1321
|
-
processVisemeQueue();
|
|
1322
|
-
try {
|
|
1323
|
-
audioContext.decodeAudioData(result.audioData, function (buffer) {
|
|
1324
|
-
source.buffer = buffer;
|
|
1325
|
-
source.connect(audioContext.destination);
|
|
1326
|
-
if (history.length < 1 || (isSafari && isIOS)) {
|
|
1327
|
-
source.start(0);
|
|
1328
|
-
}
|
|
1329
|
-
});
|
|
1330
|
-
audioContext.onstatechange = () => {
|
|
1331
|
-
if (audioContext.state === 'suspended' ||
|
|
1332
|
-
audioContext.state === 'closed') {
|
|
1333
|
-
source.disconnect();
|
|
1334
|
-
setIsPlayingAudio(false);
|
|
1335
|
-
memoriSpeaking = false;
|
|
1336
|
-
}
|
|
1337
|
-
else if (audioContext.state === 'interrupted') {
|
|
1338
|
-
audioContext.resume();
|
|
1339
|
-
}
|
|
1340
|
-
};
|
|
1341
|
-
audioContext.resume();
|
|
1342
|
-
if (speechSynthesizer) {
|
|
1343
|
-
speechSynthesizer.close();
|
|
1344
|
-
speechSynthesizer = null;
|
|
1345
|
-
}
|
|
1326
|
+
currentSpeechRef.current = {
|
|
1327
|
+
cancel: () => {
|
|
1328
|
+
var _a;
|
|
1329
|
+
speechSynthesizer === null || speechSynthesizer === void 0 ? void 0 : speechSynthesizer.close();
|
|
1330
|
+
(_a = audioDestinationRef.current) === null || _a === void 0 ? void 0 : _a.pause();
|
|
1346
1331
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1332
|
+
};
|
|
1333
|
+
const result = await speakPromise;
|
|
1334
|
+
setIsPlayingAudio(true);
|
|
1335
|
+
if (audioContext && result) {
|
|
1336
|
+
const audioBuffer = await audioContext.decodeAudioData(result.audioData);
|
|
1337
|
+
const source = audioContext.createBufferSource();
|
|
1338
|
+
source.buffer = audioBuffer;
|
|
1339
|
+
source.connect(audioContext.destination);
|
|
1340
|
+
source.onended = () => {
|
|
1351
1341
|
setIsPlayingAudio(false);
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
speechSynthesizer = null;
|
|
1356
|
-
}
|
|
1342
|
+
stopProcessing();
|
|
1343
|
+
resetVisemeQueue();
|
|
1344
|
+
currentSpeechRef.current = null;
|
|
1357
1345
|
emitEndSpeakEvent();
|
|
1358
|
-
|
|
1346
|
+
onEndSpeakStartListen();
|
|
1347
|
+
};
|
|
1348
|
+
await audioContext.resume();
|
|
1349
|
+
source.start(0);
|
|
1359
1350
|
}
|
|
1360
1351
|
else {
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
memoriSpeaking = false;
|
|
1365
|
-
emitEndSpeakEvent();
|
|
1352
|
+
stopProcessing();
|
|
1353
|
+
resetVisemeQueue();
|
|
1354
|
+
throw new Error('No result from speech synthesis');
|
|
1366
1355
|
}
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1356
|
+
}
|
|
1357
|
+
catch (error) {
|
|
1358
|
+
console.error('Speech synthesis error:', error);
|
|
1359
|
+
stopProcessing();
|
|
1360
|
+
resetVisemeQueue();
|
|
1361
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
1362
|
+
window.speechSynthesis.speak(utterance);
|
|
1363
|
+
}
|
|
1364
|
+
finally {
|
|
1365
|
+
setMemoriTyping(false);
|
|
1366
|
+
}
|
|
1367
|
+
}, [initializeAudioContext, initializeSpeechSynthesizer, stopCurrentSpeech]);
|
|
1368
|
+
const stopAudio = (0, react_1.useCallback)(() => {
|
|
1377
1369
|
setIsPlayingAudio(false);
|
|
1378
1370
|
memoriSpeaking = false;
|
|
1379
1371
|
try {
|
|
1380
|
-
if (
|
|
1381
|
-
|
|
1382
|
-
|
|
1372
|
+
if (speechSynthesizerRef.current) {
|
|
1373
|
+
speechSynthesizerRef.current.close();
|
|
1374
|
+
speechSynthesizerRef.current = null;
|
|
1383
1375
|
}
|
|
1384
|
-
if (
|
|
1385
|
-
|
|
1376
|
+
if (audioContextRef.current && audioContextRef.current.state !== 'closed') {
|
|
1377
|
+
audioContextRef.current.close();
|
|
1386
1378
|
}
|
|
1387
|
-
if (
|
|
1388
|
-
|
|
1389
|
-
|
|
1379
|
+
if (audioDestinationRef.current) {
|
|
1380
|
+
audioDestinationRef.current.pause();
|
|
1381
|
+
audioDestinationRef.current.close();
|
|
1390
1382
|
}
|
|
1383
|
+
stopCurrentSpeech();
|
|
1391
1384
|
}
|
|
1392
1385
|
catch (e) {
|
|
1393
1386
|
console.debug('stopAudio error: ', e);
|
|
1394
1387
|
}
|
|
1395
|
-
};
|
|
1388
|
+
}, [stopCurrentSpeech]);
|
|
1396
1389
|
(0, react_1.useEffect)(() => {
|
|
1397
1390
|
let textarea = document.querySelector('#chat-fieldset textarea');
|
|
1398
1391
|
if (textarea)
|
|
@@ -1525,6 +1518,12 @@ const MemoriWidget = ({ memori, memoriConfigs, ownerUserID, ownerUserName, tenan
|
|
|
1525
1518
|
(0, react_1.useEffect)(() => {
|
|
1526
1519
|
return () => {
|
|
1527
1520
|
resetUIEffects();
|
|
1521
|
+
if (speechSynthesizerRef.current) {
|
|
1522
|
+
speechSynthesizerRef.current.close();
|
|
1523
|
+
}
|
|
1524
|
+
if (audioContextRef.current) {
|
|
1525
|
+
audioContextRef.current.close();
|
|
1526
|
+
}
|
|
1528
1527
|
};
|
|
1529
1528
|
}, []);
|
|
1530
1529
|
(0, react_1.useEffect)(() => {
|