@davi-ai/retorik-framework 4.0.4 → 5.0.1
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/README.md +13 -0
- package/dist/{AttachmentDetail.637ad44f.js → AttachmentDetail.3f9c113d.js} +15 -6
- package/dist/AttachmentDetail.3f9c113d.js.map +1 -0
- package/dist/{AttachmentDetail.83788045.js → AttachmentDetail.57c5579a.js} +15 -6
- package/dist/AttachmentDetail.57c5579a.js.map +1 -0
- package/dist/{CustomView.bf84bdf3.js → CustomView.6b96f53f.js} +8 -4
- package/dist/CustomView.6b96f53f.js.map +1 -0
- package/dist/{CustomView.9930c671.js → CustomView.b32a608f.js} +8 -4
- package/dist/CustomView.b32a608f.js.map +1 -0
- package/dist/{Emergency.1112c09f.js → Emergency.43605d14.js} +11 -2
- package/dist/Emergency.43605d14.js.map +1 -0
- package/dist/{Emergency.d5810ff2.js → Emergency.f1287bd5.js} +11 -2
- package/dist/Emergency.f1287bd5.js.map +1 -0
- package/dist/FullScreenImage.17df27bf.js.map +1 -1
- package/dist/FullScreenImage.99e19e10.js.map +1 -1
- package/dist/{HistoryList.3b4b1ffb.js → HistoryList.c19556a7.js} +8 -2
- package/dist/HistoryList.c19556a7.js.map +1 -0
- package/dist/{HistoryList.e5c01f21.js → HistoryList.e7262d62.js} +8 -2
- package/dist/HistoryList.e7262d62.js.map +1 -0
- package/dist/{LanguageChoice.1d866cfa.js → LanguageChoice.54fae1dc.js} +19 -8
- package/dist/LanguageChoice.54fae1dc.js.map +1 -0
- package/dist/{LanguageChoice.cce361a3.js → LanguageChoice.6e8b74f6.js} +19 -8
- package/dist/LanguageChoice.6e8b74f6.js.map +1 -0
- package/dist/LittleWeatherContainer.7e41105e.js.map +1 -1
- package/dist/LittleWeatherContainer.ee087e22.js.map +1 -1
- package/dist/{MapContainer.14c28128.js → MapContainer.25c8f4b4.js} +20 -5
- package/dist/MapContainer.25c8f4b4.js.map +1 -0
- package/dist/{MapContainer.f22ad81f.js → MapContainer.d00ab5b2.js} +20 -5
- package/dist/MapContainer.d00ab5b2.js.map +1 -0
- package/dist/{NewsContainer.d9de093c.js → NewsContainer.a39630c3.js} +33 -26
- package/dist/NewsContainer.a39630c3.js.map +1 -0
- package/dist/{NewsContainer.463e74de.js → NewsContainer.ec15c3bb.js} +33 -26
- package/dist/NewsContainer.ec15c3bb.js.map +1 -0
- package/dist/PrintingPreview.375e62b0.js.map +1 -1
- package/dist/PrintingPreview.c0ca7706.js.map +1 -1
- package/dist/RecognitionManager.c58b8a3d.js +298 -0
- package/dist/RecognitionManager.c58b8a3d.js.map +1 -0
- package/dist/RecognitionManager.cdfb39fc.js +314 -0
- package/dist/RecognitionManager.cdfb39fc.js.map +1 -0
- package/dist/SpiritEngineWrapper.21ea10d4.js.map +1 -1
- package/dist/SpiritEngineWrapper.39627300.js.map +1 -1
- package/dist/SynthesisPonyfillManager.10888d6d.js +888 -0
- package/dist/SynthesisPonyfillManager.10888d6d.js.map +1 -0
- package/dist/SynthesisPonyfillManager.f9f9a915.js +920 -0
- package/dist/SynthesisPonyfillManager.f9f9a915.js.map +1 -0
- package/dist/{ThreeJsWrapper.dd4906ff.js → ThreeJsWrapper.0285d280.js} +24 -12
- package/dist/ThreeJsWrapper.0285d280.js.map +1 -0
- package/dist/{ThreeJsWrapper.c02a077f.js → ThreeJsWrapper.ad746197.js} +24 -11
- package/dist/ThreeJsWrapper.ad746197.js.map +1 -0
- package/dist/{VeilleManager.f3bafdec.js → VeilleManager.0b3f2454.js} +11 -13
- package/dist/VeilleManager.0b3f2454.js.map +1 -0
- package/dist/{VeilleManager.85967e7c.js → VeilleManager.340a7825.js} +11 -13
- package/dist/VeilleManager.340a7825.js.map +1 -0
- package/dist/{Weather.7e945307.js → Weather.abc13d88.js} +9 -3
- package/dist/Weather.abc13d88.js.map +1 -0
- package/dist/{Weather.e81b7205.js → Weather.b9d9f82e.js} +9 -3
- package/dist/Weather.b9d9f82e.js.map +1 -0
- package/dist/index.d.ts +21 -951
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52952 -33750
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +53468 -34269
- package/dist/index.modern.js.map +1 -1
- package/package.json +21 -21
- package/dist/AttachmentDetail.637ad44f.js.map +0 -1
- package/dist/AttachmentDetail.83788045.js.map +0 -1
- package/dist/CustomView.9930c671.js.map +0 -1
- package/dist/CustomView.bf84bdf3.js.map +0 -1
- package/dist/Emergency.1112c09f.js.map +0 -1
- package/dist/Emergency.d5810ff2.js.map +0 -1
- package/dist/HistoryList.3b4b1ffb.js.map +0 -1
- package/dist/HistoryList.e5c01f21.js.map +0 -1
- package/dist/LanguageChoice.1d866cfa.js.map +0 -1
- package/dist/LanguageChoice.cce361a3.js.map +0 -1
- package/dist/MapContainer.14c28128.js.map +0 -1
- package/dist/MapContainer.f22ad81f.js.map +0 -1
- package/dist/NewsContainer.463e74de.js.map +0 -1
- package/dist/NewsContainer.d9de093c.js.map +0 -1
- package/dist/ThreeJsWrapper.c02a077f.js.map +0 -1
- package/dist/ThreeJsWrapper.dd4906ff.js.map +0 -1
- package/dist/VeilleManager.85967e7c.js.map +0 -1
- package/dist/VeilleManager.f3bafdec.js.map +0 -1
- package/dist/Weather.7e945307.js.map +0 -1
- package/dist/Weather.e81b7205.js.map +0 -1
|
@@ -0,0 +1,888 @@
|
|
|
1
|
+
import {jsx as $cMDfV$jsx, jsxs as $cMDfV$jsxs} from "react/jsx-runtime";
|
|
2
|
+
import $cMDfV$react, {useState as $cMDfV$useState, useRef as $cMDfV$useRef, useEffect as $cMDfV$useEffect} from "react";
|
|
3
|
+
import {createSpeechSynthesisPonyfill as $cMDfV$createSpeechSynthesisPonyfill, SpeechSynthesisUtterance as $cMDfV$SpeechSynthesisUtterance} from "@davi-ai/web-speech-cognitive-services-davi";
|
|
4
|
+
import {useDispatch as $cMDfV$useDispatch, useSelector as $cMDfV$useSelector} from "react-redux";
|
|
5
|
+
import {SpeechMarkdown as $cMDfV$SpeechMarkdown} from "@davi-ai/speechmarkdown-davi-js";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
function $parcel$defineInteropFlag(a) {
|
|
9
|
+
Object.defineProperty(a, '__esModule', {value: true, configurable: true});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function $parcel$export(e, n, v, s) {
|
|
13
|
+
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
var $parcel$global = globalThis;
|
|
17
|
+
var parcelRequire = $parcel$global["parcelRequirea39d"];
|
|
18
|
+
var parcelRegister = parcelRequire.register;
|
|
19
|
+
parcelRegister("jv4ce", function(module, exports) {
|
|
20
|
+
|
|
21
|
+
$parcel$defineInteropFlag(module.exports);
|
|
22
|
+
|
|
23
|
+
$parcel$export(module.exports, "default", () => $982637234a32cc59$export$2e2bcd8739ae039);
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
var $8ItUL = parcelRequire("8ItUL");
|
|
30
|
+
|
|
31
|
+
var $d1wbP = parcelRequire("d1wbP");
|
|
32
|
+
|
|
33
|
+
var $1mU9f = parcelRequire("1mU9f");
|
|
34
|
+
|
|
35
|
+
var $3S6OO = parcelRequire("3S6OO");
|
|
36
|
+
const $982637234a32cc59$var$SynthesisPonyfillManager = ({ isRetorikNews: isRetorikNews })=>{
|
|
37
|
+
const dispatch = (0, $cMDfV$useDispatch)();
|
|
38
|
+
const customVoice = (0, $cMDfV$useSelector)((state)=>state.speechReducer.customVoice);
|
|
39
|
+
const ponyfillCredentials = (0, $cMDfV$useSelector)((state)=>state.speechReducer.ponyfillCredentials);
|
|
40
|
+
const locale = (0, $cMDfV$useSelector)((state)=>state.localeReducer.locale);
|
|
41
|
+
const agentData = (0, $cMDfV$useSelector)((state)=>state.retorikReducer.agentData);
|
|
42
|
+
const [ponyfillCreated, setPonyfillCreated] = (0, $cMDfV$useState)(false);
|
|
43
|
+
const ponyfillRef = (0, $cMDfV$useRef)(undefined);
|
|
44
|
+
const refreshTimerRef = (0, $cMDfV$useRef)(null);
|
|
45
|
+
/**
|
|
46
|
+
* Async function to retrieve a new token and assign it to the speechConfig inside ponyfill.speechSynthesis
|
|
47
|
+
* @param {string} region
|
|
48
|
+
* @param {string} key
|
|
49
|
+
*/ const refreshTokenInNineMinutes = async (region, key)=>{
|
|
50
|
+
// A token is valid during 10 minutes, let's refresh it after 9 minutes
|
|
51
|
+
refreshTimerRef.current = setTimeout(async ()=>{
|
|
52
|
+
const token = await (0, $d1wbP.fetchSpeechServicesToken)(region, key);
|
|
53
|
+
if (token && ponyfillRef.current?.speechSynthesis?.speechConfig) {
|
|
54
|
+
ponyfillRef.current.speechSynthesis.speechConfig.authorizationToken = token;
|
|
55
|
+
refreshTokenInNineMinutes(region, key);
|
|
56
|
+
}
|
|
57
|
+
}, 540000) // 9 minutes
|
|
58
|
+
;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Fetch speech synthesis token and create the ponyfill containing all data
|
|
62
|
+
* @param {string} region
|
|
63
|
+
* @param {string} key
|
|
64
|
+
*/ const fetchTokenAndCreatePonyfill = async (region, key)=>{
|
|
65
|
+
const token = await (0, $d1wbP.fetchSpeechServicesToken)(region, key);
|
|
66
|
+
if (token) {
|
|
67
|
+
ponyfillRef.current = (0, $cMDfV$createSpeechSynthesisPonyfill)({
|
|
68
|
+
credentials: {
|
|
69
|
+
region: ponyfillCredentials?.region,
|
|
70
|
+
authorizationToken: token
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
// Launch token refresh after ponyfill creation
|
|
74
|
+
refreshTokenInNineMinutes(region, key);
|
|
75
|
+
setPonyfillCreated(true);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
(0, $cMDfV$useEffect)(()=>{
|
|
79
|
+
if (ponyfillCredentials?.authorizationToken && ponyfillCredentials.region) {
|
|
80
|
+
const data = {
|
|
81
|
+
credentials: ponyfillCredentials
|
|
82
|
+
};
|
|
83
|
+
ponyfillRef.current = (0, $cMDfV$createSpeechSynthesisPonyfill)(data);
|
|
84
|
+
setPonyfillCreated(true);
|
|
85
|
+
} else if (ponyfillCredentials?.subscriptionKey && ponyfillCredentials.region) fetchTokenAndCreatePonyfill(ponyfillCredentials.region, ponyfillCredentials.subscriptionKey);
|
|
86
|
+
else if (ponyfillCredentials?.speechSynthesisHostname) {
|
|
87
|
+
// To use self-hosted voice containers, we need no 'region', and 'speechSynthesisHostname' and 'speechRecognitionHostname' must both be defined
|
|
88
|
+
// As this ponyfill is for speech synthesis only, we put a mock 'speechRecognitionHostname'
|
|
89
|
+
const data = {
|
|
90
|
+
credentials: {
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
speechSynthesisHostname: new URL(ponyfillCredentials.speechSynthesisHostname),
|
|
93
|
+
speechRecognitionHostname: ponyfillCredentials.speechRecognitionHostname || 'mandatory_recognition_host_name',
|
|
94
|
+
subscriptionKey: ponyfillCredentials.subscriptionKey || 'mandatory_subscription_key'
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
ponyfillRef.current = (0, $cMDfV$createSpeechSynthesisPonyfill)(data);
|
|
98
|
+
setPonyfillCreated(true);
|
|
99
|
+
}
|
|
100
|
+
}, [
|
|
101
|
+
ponyfillCredentials
|
|
102
|
+
]);
|
|
103
|
+
const onVoicesChanged = ()=>{
|
|
104
|
+
const voices = ponyfillRef.current?.speechSynthesis.getVoices();
|
|
105
|
+
if (voices && Array.isArray(voices) && voices.length) dispatch((0, $8ItUL.storeActions).speech.setVoice((0, $1mU9f.selectVoice)(voices, locale, customVoice, agentData) || undefined));
|
|
106
|
+
};
|
|
107
|
+
(0, $cMDfV$useEffect)(()=>{
|
|
108
|
+
if (ponyfillRef.current) {
|
|
109
|
+
const voices = ponyfillRef.current.speechSynthesis.getVoices();
|
|
110
|
+
if (voices && Array.isArray(voices) && voices.length) dispatch((0, $8ItUL.storeActions).speech.setVoice((0, $1mU9f.selectVoice)(voices, locale, customVoice, agentData) || undefined));
|
|
111
|
+
else ponyfillRef.current.speechSynthesis.onvoiceschanged = onVoicesChanged;
|
|
112
|
+
}
|
|
113
|
+
}, [
|
|
114
|
+
ponyfillCreated,
|
|
115
|
+
customVoice,
|
|
116
|
+
agentData,
|
|
117
|
+
locale
|
|
118
|
+
]);
|
|
119
|
+
(0, $cMDfV$useEffect)(()=>{
|
|
120
|
+
return ()=>{
|
|
121
|
+
refreshTimerRef.current && clearTimeout(refreshTimerRef.current);
|
|
122
|
+
};
|
|
123
|
+
}, []);
|
|
124
|
+
return ponyfillCreated && ponyfillRef.current ? /*#__PURE__*/ (0, $cMDfV$jsx)((0, $3S6OO.default), {
|
|
125
|
+
ponyfill: ponyfillRef.current,
|
|
126
|
+
isRetorikNews: isRetorikNews
|
|
127
|
+
}) : /*#__PURE__*/ (0, $cMDfV$jsx)((0, $cMDfV$react).Fragment, {});
|
|
128
|
+
};
|
|
129
|
+
var $982637234a32cc59$export$2e2bcd8739ae039 = $982637234a32cc59$var$SynthesisPonyfillManager;
|
|
130
|
+
|
|
131
|
+
});
|
|
132
|
+
parcelRegister("d1wbP", function(module, exports) {
|
|
133
|
+
|
|
134
|
+
$parcel$export(module.exports, "fetchSpeechServicesToken", () => $f9d43385082cde31$export$a2ce4fdd6972d6a7);
|
|
135
|
+
const $f9d43385082cde31$export$a2ce4fdd6972d6a7 = async (region, key)=>{
|
|
136
|
+
const tokenRes = await fetch(`https://${region}.api.cognitive.microsoft.com/sts/v1.0/issueToken`, {
|
|
137
|
+
method: 'POST',
|
|
138
|
+
headers: {
|
|
139
|
+
'Ocp-Apim-Subscription-Key': key
|
|
140
|
+
}
|
|
141
|
+
}).then((value)=>{
|
|
142
|
+
return value.text();
|
|
143
|
+
}).catch((error)=>{
|
|
144
|
+
console.log('Error : ', error);
|
|
145
|
+
return undefined;
|
|
146
|
+
});
|
|
147
|
+
return tokenRes;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
parcelRegister("1mU9f", function(module, exports) {
|
|
153
|
+
|
|
154
|
+
$parcel$export(module.exports, "selectVoice", () => $e3b82aafad2d0e5e$export$4bf371fc4fa74a28);
|
|
155
|
+
const $e3b82aafad2d0e5e$export$4bf371fc4fa74a28 = (voices, locale, customVoice, agentData)=>{
|
|
156
|
+
let voice = null;
|
|
157
|
+
// Check if a custom voice is defined in the props
|
|
158
|
+
if (customVoice) {
|
|
159
|
+
if (customVoice.voice) {
|
|
160
|
+
// Search voice with its full name (ex: AriaNeural, GuyNeural)
|
|
161
|
+
const neuralVoice = new RegExp(customVoice.voice, 'iu');
|
|
162
|
+
voice = voices.find(({ name: name })=>neuralVoice.test(name) || name === customVoice.voice);
|
|
163
|
+
} else if (customVoice.gender) // Search voice depending on given gender and locale
|
|
164
|
+
voice = voices.find(({ gender: gender, lang: lang })=>{
|
|
165
|
+
return gender.toLowerCase() === customVoice?.gender?.toLowerCase() && lang === locale;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
// Get voice depending on locale and gender
|
|
169
|
+
if (!voice) voice = voices.find(({ gender: gender, lang: lang })=>{
|
|
170
|
+
return gender.toLowerCase() === (agentData?.gender?.toLowerCase() || 'female') && lang === locale;
|
|
171
|
+
});
|
|
172
|
+
// No voice found, fall back to US default voices : female => Aria / male => Guy
|
|
173
|
+
if (!voice) {
|
|
174
|
+
const genderedVoice = agentData?.gender?.toLowerCase() === 'female' ? 'AriaNeural' : 'GuyNeural';
|
|
175
|
+
const neuralVoice = new RegExp(genderedVoice, 'iu');
|
|
176
|
+
voice = voices.find(({ name: name })=>neuralVoice.test(name));
|
|
177
|
+
}
|
|
178
|
+
return voice;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
parcelRegister("3S6OO", function(module, exports) {
|
|
184
|
+
|
|
185
|
+
$parcel$export(module.exports, "default", () => $0b8e5d756ffed1ac$export$2e2bcd8739ae039);
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
var $8ItUL = parcelRequire("8ItUL");
|
|
191
|
+
|
|
192
|
+
var $712C3 = parcelRequire("712C3");
|
|
193
|
+
|
|
194
|
+
var $4ucVo = parcelRequire("4ucVo");
|
|
195
|
+
|
|
196
|
+
var $1mU9f = parcelRequire("1mU9f");
|
|
197
|
+
|
|
198
|
+
var $7UkSC = parcelRequire("7UkSC");
|
|
199
|
+
|
|
200
|
+
var $b56Ud = parcelRequire("b56Ud");
|
|
201
|
+
const $0b8e5d756ffed1ac$var$SynthesisManager = ({ ponyfill: ponyfill, isRetorikNews: isRetorikNews })=>{
|
|
202
|
+
const dispatch = (0, $cMDfV$useDispatch)();
|
|
203
|
+
const cancel = (0, $cMDfV$useSelector)((state)=>state.speechReducer.cancel);
|
|
204
|
+
const streamingQueue = (0, $cMDfV$useSelector)((state)=>state.speechReducer.streamingQueue);
|
|
205
|
+
const voice = (0, $cMDfV$useSelector)((state)=>state.speechReducer.voice);
|
|
206
|
+
const customVoice = (0, $cMDfV$useSelector)((state)=>state.speechReducer.customVoice);
|
|
207
|
+
const activeRecognitionState = (0, $cMDfV$useSelector)((state)=>state.speechReducer.activeRecognitionState);
|
|
208
|
+
const externalTextToSpeech = (0, $cMDfV$useSelector)((state)=>state.speechReducer.externalTextToSpeech);
|
|
209
|
+
const isMicrophoneAllowed = (0, $cMDfV$useSelector)((state)=>state.speechReducer.isMicrophoneAllowed);
|
|
210
|
+
const mode = (0, $cMDfV$useSelector)((state)=>state.speechReducer.mode);
|
|
211
|
+
const route = (0, $cMDfV$useSelector)((state)=>state.viewReducer.route);
|
|
212
|
+
const locale = (0, $cMDfV$useSelector)((state)=>state.localeReducer.locale);
|
|
213
|
+
const replacementLocales = (0, $cMDfV$useSelector)((state)=>state.localeReducer.replacementLocales);
|
|
214
|
+
const agentData = (0, $cMDfV$useSelector)((state)=>state.retorikReducer.agentData);
|
|
215
|
+
const appAvailable = (0, $cMDfV$useSelector)((state)=>state.retorikReducer.appAvailable);
|
|
216
|
+
const preventExpectedInputHint = (0, $cMDfV$useSelector)((state)=>state.retorikReducer.configuration.preventExpectedInputHint);
|
|
217
|
+
const speechSynthesisOptions = (0, $cMDfV$useSelector)((state)=>state.retorikReducer.configuration.speechSynthesisOptions);
|
|
218
|
+
const sendTrace = (0, $712C3.useTelemetry)().sendTrace;
|
|
219
|
+
const [utterance, setUtterance] = (0, $cMDfV$useState)(null);
|
|
220
|
+
const [nextUtterance, setNextUtterance] = (0, $cMDfV$useState)(null);
|
|
221
|
+
const [forceSpeechCaching, setForceSpeechCaching] = (0, $cMDfV$useState)(false);
|
|
222
|
+
const isNewsViewRef = (0, $cMDfV$useRef)(!!isRetorikNews);
|
|
223
|
+
const lastListTextPlayedRef = (0, $cMDfV$useRef)('');
|
|
224
|
+
const streamingQueueRef = (0, $cMDfV$useRef)([]);
|
|
225
|
+
const currentActivityRef = (0, $cMDfV$useRef)(null);
|
|
226
|
+
/**
|
|
227
|
+
* Check activity locale in case of voice change during the speech, to keep the language defined in activity
|
|
228
|
+
* instead of switching languages between answers that are written in the same language
|
|
229
|
+
* @param {string} activityLocale
|
|
230
|
+
* @returns {SpeechSynthesisVoice | null}
|
|
231
|
+
*/ const getVoiceAfterCheckingActivityLocale = (activityLocale)=>{
|
|
232
|
+
return activityLocale === locale ? voice : (0, $1mU9f.selectVoice)(ponyfill.speechSynthesis.getVoices(), activityLocale, customVoice, agentData);
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Check if the activity is a list one, to prevent text re-reading on state update
|
|
236
|
+
* @param {CreateUtteranceParams} params
|
|
237
|
+
* @returns {SpeechSynthesisUtterance}
|
|
238
|
+
*/ const checkActivityAndCreateUtterance = (params)=>{
|
|
239
|
+
if (params.activity.attachmentLayout && params.activity.attachmentLayout.toLowerCase() === 'davilist') {
|
|
240
|
+
const textToSpeak = params.activity.speak || params.activity.text;
|
|
241
|
+
if (textToSpeak) {
|
|
242
|
+
if (textToSpeak === lastListTextPlayedRef.current) return (0, $7UkSC.checkSayAsWordsAndCreateUtterance)({
|
|
243
|
+
...params,
|
|
244
|
+
voice: null
|
|
245
|
+
}, speechSynthesisOptions?.sayAs);
|
|
246
|
+
else lastListTextPlayedRef.current = textToSpeak;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return (0, $7UkSC.checkSayAsWordsAndCreateUtterance)(params, speechSynthesisOptions?.sayAs);
|
|
250
|
+
};
|
|
251
|
+
const resetData = ()=>{
|
|
252
|
+
// Set all activities currently in the queue as ended
|
|
253
|
+
streamingQueueRef.current?.forEach((activity)=>{
|
|
254
|
+
dispatch((0, $8ItUL.storeActions).activity.addEndedActivity(activity.id));
|
|
255
|
+
});
|
|
256
|
+
streamingQueueRef.current = [];
|
|
257
|
+
dispatch((0, $8ItUL.storeActions).speech.killCurrentStreaming());
|
|
258
|
+
currentActivityRef.current = null;
|
|
259
|
+
setUtterance(null);
|
|
260
|
+
setNextUtterance(null);
|
|
261
|
+
dispatch((0, $8ItUL.storeActions).speech.resetCancelCurrentUtterance());
|
|
262
|
+
dispatch((0, $8ItUL.storeActions).speech.setSpeaking(false));
|
|
263
|
+
dispatch((0, $8ItUL.storeActions).speech.setBoundaryData([]));
|
|
264
|
+
};
|
|
265
|
+
const checkReplacementLocaleAndGetUtterance = (activity, checkReplacement = true)=>{
|
|
266
|
+
const replacementLocale = checkReplacement ? replacementLocales?.[locale] || locale : locale;
|
|
267
|
+
const params = {
|
|
268
|
+
activity: activity,
|
|
269
|
+
voice: getVoiceAfterCheckingActivityLocale(replacementLocale),
|
|
270
|
+
locale: replacementLocale
|
|
271
|
+
};
|
|
272
|
+
return checkActivityAndCreateUtterance(params);
|
|
273
|
+
};
|
|
274
|
+
/**
|
|
275
|
+
* Check if the microphone can be opened automatically
|
|
276
|
+
*/ const checkDictateState = ()=>{
|
|
277
|
+
if (!preventExpectedInputHint && mode === (0, $8ItUL.Mode).vocal && activeRecognitionState === (0, $8ItUL.RecognitionState).Closed) {
|
|
278
|
+
if (!isMicrophoneAllowed) dispatch((0, $8ItUL.storeActions).speech.askPermission());
|
|
279
|
+
else dispatch((0, $8ItUL.storeActions).speech.toggleMicrophone(true));
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* On route change, reset all data and check if we are on the news view
|
|
284
|
+
*/ (0, $cMDfV$useEffect)(()=>{
|
|
285
|
+
resetData();
|
|
286
|
+
if (!isRetorikNews) isNewsViewRef.current = route === (0, $8ItUL.Routes).News || route === (0, $8ItUL.Routes).NewsInVeille;
|
|
287
|
+
// Force speech caching when using Retorik News or when using news in veille
|
|
288
|
+
setForceSpeechCaching(isRetorikNews || route === (0, $8ItUL.Routes).NewsInVeille);
|
|
289
|
+
}, [
|
|
290
|
+
route
|
|
291
|
+
]);
|
|
292
|
+
/**
|
|
293
|
+
* On cancel call, reset all data and kill current streaming
|
|
294
|
+
*/ (0, $cMDfV$useEffect)(()=>{
|
|
295
|
+
cancel && resetData();
|
|
296
|
+
}, [
|
|
297
|
+
cancel
|
|
298
|
+
]);
|
|
299
|
+
/**
|
|
300
|
+
* Play external speech immediately but don't add it to the history
|
|
301
|
+
*/ (0, $cMDfV$useEffect)(()=>{
|
|
302
|
+
if (externalTextToSpeech) {
|
|
303
|
+
const activity = {
|
|
304
|
+
speak: externalTextToSpeech,
|
|
305
|
+
locale: locale
|
|
306
|
+
};
|
|
307
|
+
currentActivityRef.current = activity;
|
|
308
|
+
setUtterance(checkReplacementLocaleAndGetUtterance(activity, false));
|
|
309
|
+
}
|
|
310
|
+
}, [
|
|
311
|
+
externalTextToSpeech
|
|
312
|
+
]);
|
|
313
|
+
const dispatchSpeechEvent = (start)=>{
|
|
314
|
+
const speechEvent = start ? new Event('retorikSpeakStart') : new Event('retorikSpeakStop');
|
|
315
|
+
document.dispatchEvent(speechEvent);
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* Called when utterance's "start" event is fired
|
|
319
|
+
*/ const handleUtteranceStart = ()=>{
|
|
320
|
+
sendTrace((0, $4ucVo.TraceType).utteranceStart, {
|
|
321
|
+
activityId: currentActivityRef.current?.id,
|
|
322
|
+
text: currentActivityRef.current?.speak || currentActivityRef.current?.text
|
|
323
|
+
});
|
|
324
|
+
dispatch((0, $8ItUL.storeActions).speech.setSpeaking(true));
|
|
325
|
+
if (!isNewsViewRef.current && currentActivityRef?.current) {
|
|
326
|
+
dispatch((0, $8ItUL.storeActions).speech.setCurrentOrLastPlayedActivity(currentActivityRef.current));
|
|
327
|
+
currentActivityRef.current.id && dispatch((0, $8ItUL.storeActions).directline.dispatchMarkActivity({
|
|
328
|
+
id: currentActivityRef.current.id,
|
|
329
|
+
speaking: true
|
|
330
|
+
}));
|
|
331
|
+
}
|
|
332
|
+
dispatchSpeechEvent(true);
|
|
333
|
+
// Set next utterance to prepare synthesis data in order to improve fluidity
|
|
334
|
+
if (streamingQueueRef.current.length && !streamingQueueRef.current[0].value?.streamingCount) {
|
|
335
|
+
const utt = checkReplacementLocaleAndGetUtterance(streamingQueueRef.current[0], false);
|
|
336
|
+
setNextUtterance((current)=>utt.text === current?.text ? null : utt);
|
|
337
|
+
} else setNextUtterance(null);
|
|
338
|
+
};
|
|
339
|
+
/**
|
|
340
|
+
* Called when utterance's "end" event is fired
|
|
341
|
+
*/ const handleUtteranceEnd = ()=>{
|
|
342
|
+
sendTrace((0, $4ucVo.TraceType).utteranceEnd, {
|
|
343
|
+
activityId: currentActivityRef.current?.id
|
|
344
|
+
});
|
|
345
|
+
dispatch((0, $8ItUL.storeActions).speech.setSpeaking(false));
|
|
346
|
+
dispatchSpeechEvent(false);
|
|
347
|
+
if (isNewsViewRef.current) {
|
|
348
|
+
dispatch((0, $8ItUL.storeActions).utils.setRetorikNewsEnded(true));
|
|
349
|
+
currentActivityRef.current = null;
|
|
350
|
+
} else handleEnded();
|
|
351
|
+
};
|
|
352
|
+
const handleEnded = ()=>{
|
|
353
|
+
// Add played activity id to context's endedActivities
|
|
354
|
+
if (currentActivityRef.current?.id) {
|
|
355
|
+
dispatch((0, $8ItUL.storeActions).activity.addEndedActivity(currentActivityRef.current.id));
|
|
356
|
+
dispatch((0, $8ItUL.storeActions).directline.dispatchMarkActivity({
|
|
357
|
+
id: currentActivityRef.current.id,
|
|
358
|
+
speaking: false
|
|
359
|
+
}));
|
|
360
|
+
}
|
|
361
|
+
if (streamingQueueRef.current?.length) {
|
|
362
|
+
// Check if this is the message sent after streaming activities
|
|
363
|
+
if (streamingQueueRef.current[0].value?.streamingCount) {
|
|
364
|
+
dispatch((0, $8ItUL.storeActions).activity.addEndedActivity(streamingQueueRef.current[0].id));
|
|
365
|
+
// If there is another activity after this message, play it. If not, let's check if the microphone should be opened
|
|
366
|
+
if (streamingQueueRef.current?.length > 1) {
|
|
367
|
+
const utt = checkReplacementLocaleAndGetUtterance(streamingQueueRef.current[1]);
|
|
368
|
+
currentActivityRef.current = streamingQueueRef.current[1];
|
|
369
|
+
setUtterance(utt);
|
|
370
|
+
dispatch((0, $8ItUL.storeActions).speech.removeFirstFromStreamingQueue(true));
|
|
371
|
+
} else {
|
|
372
|
+
streamingQueueRef.current[0].inputHint === 'expectingInput' && checkDictateState();
|
|
373
|
+
currentActivityRef.current = null;
|
|
374
|
+
setUtterance(null);
|
|
375
|
+
setNextUtterance(null);
|
|
376
|
+
dispatch((0, $8ItUL.storeActions).speech.removeFirstFromStreamingQueue(false));
|
|
377
|
+
}
|
|
378
|
+
} else {
|
|
379
|
+
const utt = checkReplacementLocaleAndGetUtterance(streamingQueueRef.current[0]);
|
|
380
|
+
currentActivityRef.current = streamingQueueRef.current[0];
|
|
381
|
+
setUtterance(utt);
|
|
382
|
+
dispatch((0, $8ItUL.storeActions).speech.removeFirstFromStreamingQueue(false));
|
|
383
|
+
}
|
|
384
|
+
} else {
|
|
385
|
+
currentActivityRef.current?.inputHint === 'expectingInput' && checkDictateState();
|
|
386
|
+
currentActivityRef.current = null;
|
|
387
|
+
setUtterance(null);
|
|
388
|
+
setNextUtterance(null);
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
/**
|
|
392
|
+
* Wait for app loading and voice selection to begin playing speech
|
|
393
|
+
*/ (0, $cMDfV$useEffect)(()=>{
|
|
394
|
+
// Set ref from the state to use in events
|
|
395
|
+
streamingQueueRef.current = streamingQueue;
|
|
396
|
+
if (appAvailable && voice && streamingQueue.length && !currentActivityRef.current) handleEnded();
|
|
397
|
+
}, [
|
|
398
|
+
appAvailable,
|
|
399
|
+
voice,
|
|
400
|
+
streamingQueue
|
|
401
|
+
]);
|
|
402
|
+
return /*#__PURE__*/ (0, $cMDfV$jsx)((0, $b56Ud.default), {
|
|
403
|
+
ponyfill: ponyfill,
|
|
404
|
+
appAvailable: appAvailable,
|
|
405
|
+
utterance: utterance,
|
|
406
|
+
nextUtterance: nextUtterance,
|
|
407
|
+
forceSpeechCaching: forceSpeechCaching,
|
|
408
|
+
onStart: handleUtteranceStart,
|
|
409
|
+
onError: handleUtteranceEnd,
|
|
410
|
+
onEnd: handleUtteranceEnd
|
|
411
|
+
});
|
|
412
|
+
};
|
|
413
|
+
var $0b8e5d756ffed1ac$export$2e2bcd8739ae039 = $0b8e5d756ffed1ac$var$SynthesisManager;
|
|
414
|
+
|
|
415
|
+
});
|
|
416
|
+
parcelRegister("7UkSC", function(module, exports) {
|
|
417
|
+
|
|
418
|
+
$parcel$export(module.exports, "checkSayAsWordsAndCreateUtterance", () => $66dccbb634d6ce27$export$f969af62bba9a48b);
|
|
419
|
+
|
|
420
|
+
var $jvc7U = parcelRequire("jvc7U");
|
|
421
|
+
/**
|
|
422
|
+
* Check if there are some replacement codes for this language, to improve speech synthesis, and then create the utterance
|
|
423
|
+
* @param {CreateUtteranceParams} params - data needed to create an utterance
|
|
424
|
+
* @param {SayAs} sayAs - string that should be replaced by their ipa codes
|
|
425
|
+
* @returns {SpeechSynthesisUtterance}
|
|
426
|
+
*/ const $66dccbb634d6ce27$export$f969af62bba9a48b = (params, sayAs)=>{
|
|
427
|
+
let sayAsWords = [];
|
|
428
|
+
if (sayAs) {
|
|
429
|
+
sayAs.common?.length && (sayAsWords = [
|
|
430
|
+
...sayAs.common
|
|
431
|
+
]);
|
|
432
|
+
sayAs.localized && sayAs.localized[params.locale]?.length && (sayAsWords = [
|
|
433
|
+
...sayAsWords,
|
|
434
|
+
...sayAs.localized[params.locale]
|
|
435
|
+
]);
|
|
436
|
+
}
|
|
437
|
+
return (0, $jvc7U.default)({
|
|
438
|
+
...params,
|
|
439
|
+
sayAsWords: sayAsWords
|
|
440
|
+
});
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
});
|
|
444
|
+
parcelRegister("jvc7U", function(module, exports) {
|
|
445
|
+
|
|
446
|
+
$parcel$export(module.exports, "default", () => $972cc4ac7a9f8914$export$2e2bcd8739ae039);
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
const $972cc4ac7a9f8914$var$buildSSML = (activity, locale, speechMarkdownParser, sayAsWords)=>{
|
|
450
|
+
let speech = activity.speak || activity.text;
|
|
451
|
+
// Replace character not recognized in Microsoft TTS
|
|
452
|
+
speech = speech.replaceAll("\u2019", "'");
|
|
453
|
+
let textParsedAsSSML = '';
|
|
454
|
+
try {
|
|
455
|
+
if (sayAsWords?.length) {
|
|
456
|
+
const wordsUsed = [];
|
|
457
|
+
sayAsWords.forEach((tuple)=>{
|
|
458
|
+
if (!wordsUsed.includes(tuple.text.toLocaleLowerCase(locale))) {
|
|
459
|
+
const regex = new RegExp(`\\b${tuple.text}\\b`, 'gi');
|
|
460
|
+
speech = speech.replaceAll(regex, `(${tuple.text})[ipa:"${tuple.ipa}"]`);
|
|
461
|
+
wordsUsed.push(tuple.text.toLocaleLowerCase(locale));
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
textParsedAsSSML = speechMarkdownParser.toSSML(speech);
|
|
466
|
+
} catch (e) {
|
|
467
|
+
console.warn('Retorik Framework > error in speechmarkdown parser : ', e);
|
|
468
|
+
}
|
|
469
|
+
return `<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="${locale}">` + textParsedAsSSML + '</speak>';
|
|
470
|
+
};
|
|
471
|
+
const $972cc4ac7a9f8914$var$createUtterance = ({ activity: activity, voice: voice, locale: locale, sayAsWords: sayAsWords })=>{
|
|
472
|
+
// If there is no text to be read, create an empty utterance that will be put in the array of ended activities
|
|
473
|
+
if (!voice || !activity.speak && !activity.text) return new (0, $cMDfV$SpeechSynthesisUtterance)('');
|
|
474
|
+
return new (0, $cMDfV$SpeechSynthesisUtterance)($972cc4ac7a9f8914$var$buildSSML(activity, locale, new (0, $cMDfV$SpeechMarkdown)({
|
|
475
|
+
platform: 'microsoft-azure',
|
|
476
|
+
includeSpeakTag: false,
|
|
477
|
+
globalVoiceAndLang: {
|
|
478
|
+
voice: voice.name,
|
|
479
|
+
lang: voice.name.toLowerCase().includes('multilingual') ? locale : undefined
|
|
480
|
+
}
|
|
481
|
+
}), sayAsWords));
|
|
482
|
+
};
|
|
483
|
+
var $972cc4ac7a9f8914$export$2e2bcd8739ae039 = $972cc4ac7a9f8914$var$createUtterance;
|
|
484
|
+
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
parcelRegister("b56Ud", function(module, exports) {
|
|
489
|
+
|
|
490
|
+
$parcel$export(module.exports, "default", () => $637384b103093c58$export$2e2bcd8739ae039);
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
var $8ItUL = parcelRequire("8ItUL");
|
|
496
|
+
|
|
497
|
+
var $9RfWh = parcelRequire("9RfWh");
|
|
498
|
+
|
|
499
|
+
var $eAy5f = parcelRequire("eAy5f");
|
|
500
|
+
|
|
501
|
+
var $6zM6Q = parcelRequire("6zM6Q");
|
|
502
|
+
const $637384b103093c58$var$DBManager = new (0, $eAy5f.default)();
|
|
503
|
+
const $637384b103093c58$var$tagsRemoverRegex = /<[^<>]+>/g;
|
|
504
|
+
const $637384b103093c58$var$RetorikSpeech = ({ ponyfill: ponyfill, onEnd: onEnd, onError: onError, onStart: onStart, utterance: utterance, nextUtterance: nextUtterance, appAvailable: appAvailable, forceSpeechCaching: forceSpeechCaching })=>{
|
|
505
|
+
const dispatch = (0, $cMDfV$useDispatch)();
|
|
506
|
+
const locale = (0, $cMDfV$useSelector)((state)=>state.localeReducer.locale);
|
|
507
|
+
const loaderClosed = (0, $cMDfV$useSelector)((state)=>state.retorikReducer.loaderClosed);
|
|
508
|
+
const enableSpeechCaching = (0, $cMDfV$useSelector)((state)=>state.retorikReducer.configuration.enableSpeechCaching);
|
|
509
|
+
const speechRecognitionOptions = (0, $cMDfV$useSelector)((state)=>state.retorikReducer.configuration.speechRecognitionOptions);
|
|
510
|
+
const useOldRemote = (0, $cMDfV$useSelector)((state)=>state.retorikReducer.configuration.useOldRemote);
|
|
511
|
+
const voice = (0, $cMDfV$useSelector)((state)=>state.speechReducer.voice);
|
|
512
|
+
const muted = (0, $cMDfV$useSelector)((state)=>state.speechReducer.muted);
|
|
513
|
+
const activeRecognitionState = (0, $cMDfV$useSelector)((state)=>state.speechReducer.activeRecognitionState);
|
|
514
|
+
const boundaryRef = (0, $cMDfV$useRef)(null);
|
|
515
|
+
const visemeRef = (0, $cMDfV$useRef)(null);
|
|
516
|
+
const bookmarkRef = (0, $cMDfV$useRef)(null);
|
|
517
|
+
const audioRef = (0, $cMDfV$useRef)(null);
|
|
518
|
+
const speechRecognitionAudioRef = (0, $cMDfV$useRef)(null);
|
|
519
|
+
const microphoneOpenAudioRef = (0, $cMDfV$useRef)(null);
|
|
520
|
+
const microphoneCloseAudioRef = (0, $cMDfV$useRef)(null);
|
|
521
|
+
const [DBReady, setDBReady] = (0, $cMDfV$useState)(false);
|
|
522
|
+
const [playingBlob, setPlayingBlob] = (0, $cMDfV$useState)(false);
|
|
523
|
+
const nextUtteranceDataRef = (0, $cMDfV$useRef)(null);
|
|
524
|
+
const nextUtteranceTextRef = (0, $cMDfV$useRef)(null);
|
|
525
|
+
const nextUtteranceBoundariesRef = (0, $cMDfV$useRef)([]);
|
|
526
|
+
const nextUtteranceVisemesRef = (0, $cMDfV$useRef)([]);
|
|
527
|
+
const nextUtteranceBookmarksRef = (0, $cMDfV$useRef)([]);
|
|
528
|
+
const emptyTextUtteranceRef = (0, $cMDfV$useRef)(null);
|
|
529
|
+
(0, $cMDfV$useEffect)(()=>{
|
|
530
|
+
$637384b103093c58$var$DBManager.checkDB().then((result)=>setDBReady(result));
|
|
531
|
+
return ()=>{
|
|
532
|
+
stopCurrentPlaying();
|
|
533
|
+
emptyTextUtteranceRef?.current && clearTimeout(emptyTextUtteranceRef.current);
|
|
534
|
+
};
|
|
535
|
+
}, []);
|
|
536
|
+
const stopCurrentPlaying = ()=>{
|
|
537
|
+
if (appAvailable || loaderClosed) {
|
|
538
|
+
// Cancel synthesis if using synthesizer
|
|
539
|
+
if (!playingBlob) ponyfill.speechSynthesis.cancel();
|
|
540
|
+
resetNextUtteranceData();
|
|
541
|
+
if (audioRef.current && !audioRef.current?.paused) {
|
|
542
|
+
audioRef.current.pause();
|
|
543
|
+
handleEnd();
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
const attachEvents = (tempUtterance, isMainUtterance)=>{
|
|
548
|
+
tempUtterance.onerror = (event)=>{
|
|
549
|
+
isMainUtterance ? handleError(event) : nextUtteranceDataRef.current = null;
|
|
550
|
+
};
|
|
551
|
+
tempUtterance.onsynthesiscompleted = ()=>{
|
|
552
|
+
const endBoundary = {
|
|
553
|
+
word: '',
|
|
554
|
+
startTime: 0,
|
|
555
|
+
endTime: 0,
|
|
556
|
+
boundaryType: 'EndBoundary'
|
|
557
|
+
};
|
|
558
|
+
if (isMainUtterance) {
|
|
559
|
+
const tempBoundaries = boundaryRef?.current || [];
|
|
560
|
+
boundaryRef.current = [
|
|
561
|
+
...tempBoundaries,
|
|
562
|
+
endBoundary
|
|
563
|
+
];
|
|
564
|
+
dispatch((0, $8ItUL.storeActions).speech.setBoundaryData([
|
|
565
|
+
...tempBoundaries,
|
|
566
|
+
endBoundary
|
|
567
|
+
]));
|
|
568
|
+
} else nextUtteranceBoundariesRef.current = [
|
|
569
|
+
...nextUtteranceBoundariesRef.current,
|
|
570
|
+
endBoundary
|
|
571
|
+
];
|
|
572
|
+
};
|
|
573
|
+
tempUtterance.onboundary = (event)=>{
|
|
574
|
+
if (event.boundaryType !== 'Viseme') {
|
|
575
|
+
const newBoundary = {
|
|
576
|
+
word: event.name,
|
|
577
|
+
startTime: event.elapsedTime,
|
|
578
|
+
endTime: event.elapsedTime + event.duration,
|
|
579
|
+
boundaryType: event.boundaryType
|
|
580
|
+
};
|
|
581
|
+
if (isMainUtterance) {
|
|
582
|
+
// Update the boundaryData state with the new data.
|
|
583
|
+
const tempBoundaries = boundaryRef?.current || [];
|
|
584
|
+
boundaryRef.current = [
|
|
585
|
+
...tempBoundaries,
|
|
586
|
+
newBoundary
|
|
587
|
+
];
|
|
588
|
+
dispatch((0, $8ItUL.storeActions).speech.setBoundaryData([
|
|
589
|
+
...tempBoundaries,
|
|
590
|
+
newBoundary
|
|
591
|
+
]));
|
|
592
|
+
} else nextUtteranceBoundariesRef.current = [
|
|
593
|
+
...nextUtteranceBoundariesRef.current,
|
|
594
|
+
newBoundary
|
|
595
|
+
];
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
tempUtterance.onviseme = (event)=>{
|
|
599
|
+
if (isMainUtterance) {
|
|
600
|
+
// Collect visemes locally - they will be dispatched when audio starts playing
|
|
601
|
+
const tempVisemes = visemeRef?.current || [];
|
|
602
|
+
visemeRef.current = [
|
|
603
|
+
...tempVisemes,
|
|
604
|
+
event
|
|
605
|
+
];
|
|
606
|
+
} else nextUtteranceVisemesRef.current = [
|
|
607
|
+
...nextUtteranceVisemesRef.current,
|
|
608
|
+
event
|
|
609
|
+
];
|
|
610
|
+
};
|
|
611
|
+
tempUtterance.onmark = (event)=>{
|
|
612
|
+
console.log('Retorik Framework > onmark event', event);
|
|
613
|
+
const bookmark = {
|
|
614
|
+
name: event.name,
|
|
615
|
+
time: event.elapsedTime
|
|
616
|
+
};
|
|
617
|
+
if (isMainUtterance) {
|
|
618
|
+
// Collect bookmarks locally - they will be dispatched when audio starts playing
|
|
619
|
+
const tempBookmarks = bookmarkRef?.current || [];
|
|
620
|
+
bookmarkRef.current = [
|
|
621
|
+
...tempBookmarks,
|
|
622
|
+
bookmark
|
|
623
|
+
];
|
|
624
|
+
} else nextUtteranceBookmarksRef.current = [
|
|
625
|
+
...nextUtteranceBookmarksRef.current,
|
|
626
|
+
bookmark
|
|
627
|
+
];
|
|
628
|
+
};
|
|
629
|
+
return tempUtterance;
|
|
630
|
+
};
|
|
631
|
+
const processNextData = (data)=>{
|
|
632
|
+
nextUtteranceDataRef.current = data?.byteLength && nextUtteranceTextRef.current ? {
|
|
633
|
+
text: nextUtteranceTextRef.current,
|
|
634
|
+
data: {
|
|
635
|
+
speechData: data,
|
|
636
|
+
boundaries: nextUtteranceBoundariesRef.current,
|
|
637
|
+
visemes: nextUtteranceVisemesRef.current,
|
|
638
|
+
bookmarks: nextUtteranceBookmarksRef.current
|
|
639
|
+
}
|
|
640
|
+
} : null;
|
|
641
|
+
// Reset boundary / viseme data
|
|
642
|
+
resetNextUtteranceData(true);
|
|
643
|
+
};
|
|
644
|
+
const resetNextUtteranceData = (keepArrayBufferData)=>{
|
|
645
|
+
!keepArrayBufferData && (nextUtteranceDataRef.current = null);
|
|
646
|
+
nextUtteranceTextRef.current = null;
|
|
647
|
+
nextUtteranceBoundariesRef.current = [];
|
|
648
|
+
nextUtteranceVisemesRef.current = [];
|
|
649
|
+
nextUtteranceBookmarksRef.current = [];
|
|
650
|
+
};
|
|
651
|
+
(0, $cMDfV$useEffect)(()=>{
|
|
652
|
+
if (utterance) {
|
|
653
|
+
if (utterance.text) {
|
|
654
|
+
if (audioRef?.current) {
|
|
655
|
+
if (nextUtteranceDataRef.current?.text === utterance.text && nextUtteranceDataRef.current.data) {
|
|
656
|
+
boundaryRef.current = nextUtteranceDataRef.current.data.boundaries;
|
|
657
|
+
dispatch((0, $8ItUL.storeActions).speech.setBoundaryData(nextUtteranceDataRef.current.data.boundaries));
|
|
658
|
+
// Store visemes locally - they will be dispatched when audio starts playing
|
|
659
|
+
visemeRef.current = nextUtteranceDataRef.current.data.visemes;
|
|
660
|
+
processData(nextUtteranceDataRef.current.data.speechData, true);
|
|
661
|
+
} else // Play utterance whether by asking for a speech synthesis, or by retrieving data from indexedDB
|
|
662
|
+
playUtterance(attachEvents(utterance, true));
|
|
663
|
+
} else stopCurrentPlaying();
|
|
664
|
+
} else handleEmptyTextUtterance();
|
|
665
|
+
} else stopCurrentPlaying();
|
|
666
|
+
}, [
|
|
667
|
+
utterance
|
|
668
|
+
]);
|
|
669
|
+
(0, $cMDfV$useEffect)(()=>{
|
|
670
|
+
// If there are data in nextUtteranceTextRef, this means the previous synthesis data retrieval is not finished, so we don't begin a new one
|
|
671
|
+
if (nextUtterance?.text && !nextUtteranceTextRef.current) {
|
|
672
|
+
const tempUtterance = attachEvents(nextUtterance);
|
|
673
|
+
nextUtteranceTextRef.current = nextUtterance.text;
|
|
674
|
+
ponyfill.speechSynthesis.synthesizeAndGetArrayData(tempUtterance, processNextData);
|
|
675
|
+
} else resetNextUtteranceData();
|
|
676
|
+
}, [
|
|
677
|
+
nextUtterance
|
|
678
|
+
]);
|
|
679
|
+
const playUtterance = async (utt)=>{
|
|
680
|
+
if (DBReady && (enableSpeechCaching !== false || forceSpeechCaching) && utt) {
|
|
681
|
+
const dataFromIndexedDB = await $637384b103093c58$var$DBManager.getSpeechData(`${locale}.${voice?.name}.${utt.text.replace($637384b103093c58$var$tagsRemoverRegex, '')}`);
|
|
682
|
+
if (dataFromIndexedDB) {
|
|
683
|
+
boundaryRef.current = dataFromIndexedDB.boundaries;
|
|
684
|
+
dispatch((0, $8ItUL.storeActions).speech.setBoundaryData(dataFromIndexedDB.boundaries));
|
|
685
|
+
// Store visemes locally - they will be dispatched when audio starts playing
|
|
686
|
+
visemeRef.current = dataFromIndexedDB.visemes || [];
|
|
687
|
+
processData(dataFromIndexedDB.value, true);
|
|
688
|
+
} else ponyfill.speechSynthesis.synthesizeAndGetArrayData(utt, processData);
|
|
689
|
+
} else ponyfill.speechSynthesis.synthesizeAndGetArrayData(utt, processData);
|
|
690
|
+
};
|
|
691
|
+
const processData = (data, alreadyExistsInDB)=>{
|
|
692
|
+
if (data?.byteLength) {
|
|
693
|
+
const blob = new Blob([
|
|
694
|
+
data
|
|
695
|
+
], {
|
|
696
|
+
type: 'audio/mp3'
|
|
697
|
+
});
|
|
698
|
+
!alreadyExistsInDB && (enableSpeechCaching !== false || forceSpeechCaching) && DBReady && boundaryRef?.current && utterance && $637384b103093c58$var$DBManager.addSpeechData({
|
|
699
|
+
id: `${locale}.${voice?.name}.${utterance.text.replace($637384b103093c58$var$tagsRemoverRegex, '')}`,
|
|
700
|
+
value: data,
|
|
701
|
+
boundaries: boundaryRef.current,
|
|
702
|
+
visemes: visemeRef.current || []
|
|
703
|
+
});
|
|
704
|
+
const url = URL.createObjectURL(blob);
|
|
705
|
+
if (audioRef?.current) {
|
|
706
|
+
setPlayingBlob(true);
|
|
707
|
+
audioRef.current.src = url;
|
|
708
|
+
audioRef.current.play().catch((e)=>console.warn(e));
|
|
709
|
+
}
|
|
710
|
+
} else handleEmptyTextUtterance();
|
|
711
|
+
};
|
|
712
|
+
const resetData = ()=>{
|
|
713
|
+
boundaryRef.current = [];
|
|
714
|
+
visemeRef.current = [];
|
|
715
|
+
dispatch((0, $8ItUL.storeActions).speech.setBoundaryData([]));
|
|
716
|
+
dispatch((0, $8ItUL.storeActions).speech.setVisemeData([]));
|
|
717
|
+
dispatch((0, $8ItUL.storeActions).speech.setBookmarkData([]));
|
|
718
|
+
setPlayingBlob(false);
|
|
719
|
+
};
|
|
720
|
+
const handleStart = ()=>{
|
|
721
|
+
if (appAvailable || loaderClosed) {
|
|
722
|
+
// Dispatch visemes now that audio is playing, ensuring lip sync timing is correct
|
|
723
|
+
if (visemeRef.current?.length) {
|
|
724
|
+
dispatch((0, $8ItUL.storeActions).speech.setVisemeData(visemeRef.current));
|
|
725
|
+
dispatch((0, $8ItUL.storeActions).speech.setBookmarkData(bookmarkRef.current || []));
|
|
726
|
+
}
|
|
727
|
+
onStart?.();
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
const handleEnd = ()=>{
|
|
731
|
+
if (appAvailable || loaderClosed) {
|
|
732
|
+
onEnd?.();
|
|
733
|
+
resetData();
|
|
734
|
+
} else dispatch((0, $8ItUL.storeActions).retorik.setLoaderClosed(true));
|
|
735
|
+
};
|
|
736
|
+
const handleError = (error)=>{
|
|
737
|
+
console.log('Retorik Framework > speech synthesis error ', error);
|
|
738
|
+
onError?.();
|
|
739
|
+
resetData();
|
|
740
|
+
};
|
|
741
|
+
const handleEmptyTextUtterance = ()=>{
|
|
742
|
+
handleStart();
|
|
743
|
+
emptyTextUtteranceRef?.current && clearTimeout(emptyTextUtteranceRef.current);
|
|
744
|
+
emptyTextUtteranceRef.current = setTimeout(()=>{
|
|
745
|
+
handleEnd();
|
|
746
|
+
}, 50);
|
|
747
|
+
};
|
|
748
|
+
/**
|
|
749
|
+
* On call :
|
|
750
|
+
* - play 1 second muted sound to prime audio output
|
|
751
|
+
* - MANDATORY FOR SAFARI IN VOCAL MODE
|
|
752
|
+
*/ const primeRetorikSpeech = ()=>{
|
|
753
|
+
if (audioRef.current) {
|
|
754
|
+
audioRef.current.play().catch((e)=>console.warn(e));
|
|
755
|
+
speechRecognitionAudioRef?.current && speechRecognitionAudioRef.current.play().catch((e)=>console.warn(e));
|
|
756
|
+
// Send animation start event to secure animation not playing on safari if permissions are not sufficient
|
|
757
|
+
window.dispatchEvent(new Event('retorikSpiritEnginePlay'));
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
/**
|
|
761
|
+
* Play sound on speech recognition activation if it isn't disabled in configuration
|
|
762
|
+
*/ (0, $cMDfV$useEffect)(()=>{
|
|
763
|
+
if (useOldRemote) {
|
|
764
|
+
if (!!speechRecognitionOptions?.enableActivationSound && activeRecognitionState === (0, $8ItUL.RecognitionState).Listening) speechRecognitionAudioRef?.current?.play().catch((e)=>console.warn(e));
|
|
765
|
+
} else if (!!speechRecognitionOptions?.enableActivationSound) switch(activeRecognitionState){
|
|
766
|
+
case (0, $8ItUL.RecognitionState).Listening:
|
|
767
|
+
microphoneOpenAudioRef?.current?.play().catch((e)=>console.warn(e));
|
|
768
|
+
break;
|
|
769
|
+
case (0, $8ItUL.RecognitionState).Closing:
|
|
770
|
+
case (0, $8ItUL.RecognitionState).ForceClosing:
|
|
771
|
+
microphoneCloseAudioRef?.current?.play().catch((e)=>console.warn(e));
|
|
772
|
+
break;
|
|
773
|
+
default:
|
|
774
|
+
break;
|
|
775
|
+
}
|
|
776
|
+
}, [
|
|
777
|
+
useOldRemote,
|
|
778
|
+
activeRecognitionState,
|
|
779
|
+
speechRecognitionOptions
|
|
780
|
+
]);
|
|
781
|
+
return /*#__PURE__*/ (0, $cMDfV$jsxs)((0, $cMDfV$react).Fragment, {
|
|
782
|
+
children: [
|
|
783
|
+
/*#__PURE__*/ (0, $cMDfV$jsx)("audio", {
|
|
784
|
+
ref: audioRef,
|
|
785
|
+
src: (0, $9RfWh.audioFiles).onesecond,
|
|
786
|
+
muted: appAvailable || loaderClosed ? muted : true,
|
|
787
|
+
onPlay: handleStart,
|
|
788
|
+
onEnded: handleEnd
|
|
789
|
+
}),
|
|
790
|
+
/*#__PURE__*/ (0, $cMDfV$jsx)("audio", {
|
|
791
|
+
ref: speechRecognitionAudioRef,
|
|
792
|
+
src: (0, $9RfWh.audioFiles).speechrecognition,
|
|
793
|
+
preload: "auto",
|
|
794
|
+
muted: appAvailable || loaderClosed ? muted : true
|
|
795
|
+
}),
|
|
796
|
+
/*#__PURE__*/ (0, $cMDfV$jsx)("audio", {
|
|
797
|
+
ref: microphoneOpenAudioRef,
|
|
798
|
+
src: (0, $9RfWh.audioFiles).microphoneopen,
|
|
799
|
+
preload: "auto",
|
|
800
|
+
muted: appAvailable || loaderClosed ? muted : true
|
|
801
|
+
}),
|
|
802
|
+
/*#__PURE__*/ (0, $cMDfV$jsx)("audio", {
|
|
803
|
+
ref: microphoneCloseAudioRef,
|
|
804
|
+
src: (0, $9RfWh.audioFiles).microphoneclose,
|
|
805
|
+
preload: "auto",
|
|
806
|
+
muted: appAvailable || loaderClosed ? muted : true
|
|
807
|
+
}),
|
|
808
|
+
/*#__PURE__*/ (0, $cMDfV$jsx)((0, $6zM6Q.default), {
|
|
809
|
+
appAvailable: appAvailable,
|
|
810
|
+
handleValidation: primeRetorikSpeech
|
|
811
|
+
})
|
|
812
|
+
]
|
|
813
|
+
});
|
|
814
|
+
};
|
|
815
|
+
var $637384b103093c58$export$2e2bcd8739ae039 = $637384b103093c58$var$RetorikSpeech;
|
|
816
|
+
|
|
817
|
+
});
|
|
818
|
+
parcelRegister("eAy5f", function(module, exports) {
|
|
819
|
+
|
|
820
|
+
$parcel$export(module.exports, "default", () => $f8b1c4b1ab628567$export$2e2bcd8739ae039);
|
|
821
|
+
class $f8b1c4b1ab628567$var$IndexedDbManager {
|
|
822
|
+
constructor(){
|
|
823
|
+
this.version = 1;
|
|
824
|
+
this.storeName = 'speechSynthesisData';
|
|
825
|
+
this.checkDB = async ()=>{
|
|
826
|
+
return new Promise((resolve)=>{
|
|
827
|
+
const request = indexedDB.open('retorik-framework-db', this.version);
|
|
828
|
+
request.onsuccess = ()=>{
|
|
829
|
+
resolve(true);
|
|
830
|
+
};
|
|
831
|
+
request.onerror = ()=>{
|
|
832
|
+
resolve(false);
|
|
833
|
+
};
|
|
834
|
+
request.onupgradeneeded = ()=>{
|
|
835
|
+
const db = request.result;
|
|
836
|
+
// If the data object store doesn't exist, create it
|
|
837
|
+
if (!db.objectStoreNames.contains(this.storeName)) db.createObjectStore(this.storeName, {
|
|
838
|
+
keyPath: 'id'
|
|
839
|
+
});
|
|
840
|
+
};
|
|
841
|
+
});
|
|
842
|
+
};
|
|
843
|
+
this.addSpeechData = async (data)=>{
|
|
844
|
+
return new Promise((resolve)=>{
|
|
845
|
+
const request = indexedDB.open('retorik-framework-db', this.version);
|
|
846
|
+
request.onsuccess = ()=>{
|
|
847
|
+
const db = request.result;
|
|
848
|
+
const tx = db.transaction(this.storeName, 'readwrite');
|
|
849
|
+
const store = tx.objectStore(this.storeName);
|
|
850
|
+
// Base 64 encode
|
|
851
|
+
data.id = window.btoa(encodeURI(data.id));
|
|
852
|
+
store.add(data);
|
|
853
|
+
resolve(true);
|
|
854
|
+
};
|
|
855
|
+
request.onerror = ()=>{
|
|
856
|
+
resolve(false);
|
|
857
|
+
};
|
|
858
|
+
});
|
|
859
|
+
};
|
|
860
|
+
this.getSpeechData = async (id)=>{
|
|
861
|
+
return new Promise((resolve)=>{
|
|
862
|
+
const request = indexedDB.open('retorik-framework-db', this.version);
|
|
863
|
+
request.onsuccess = ()=>{
|
|
864
|
+
const db = request.result;
|
|
865
|
+
const tx = db.transaction(this.storeName, 'readonly');
|
|
866
|
+
const store = tx.objectStore(this.storeName);
|
|
867
|
+
// Base 64 encode
|
|
868
|
+
const data = store.get(window.btoa(encodeURI(id)));
|
|
869
|
+
data.onsuccess = ()=>{
|
|
870
|
+
resolve(data.result);
|
|
871
|
+
};
|
|
872
|
+
};
|
|
873
|
+
request.onerror = ()=>{
|
|
874
|
+
resolve(null);
|
|
875
|
+
};
|
|
876
|
+
});
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
var $f8b1c4b1ab628567$export$2e2bcd8739ae039 = $f8b1c4b1ab628567$var$IndexedDbManager;
|
|
881
|
+
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
//# sourceMappingURL=SynthesisPonyfillManager.10888d6d.js.map
|