@creativeorange/azure-text-to-speech 2.2.3 → 3.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 +455 -0
- package/dist/SpeechToText.d.ts +27 -0
- package/dist/TextToSpeech.d.ts +79 -0
- package/dist/authentication.d.ts +44 -0
- package/dist/co-azure-tts.es.js +672 -209
- package/dist/co-azure-tts.umd.js +8 -8
- package/dist/main.d.ts +4 -0
- package/package.json +27 -5
- package/.eslintrc.js +0 -30
- package/index.html +0 -578
- package/nuxt/plugins/azure-speech-to-text.client.js +0 -27
- package/nuxt/plugins/azure-text-to-speech.client.js +0 -28
- package/src/SpeechToText.ts +0 -106
- package/src/TextToSpeech.ts +0 -745
- package/src/main.ts +0 -2
- package/tsconfig.json +0 -21
- package/vite.config.ts +0 -26
package/dist/co-azure-tts.es.js
CHANGED
|
@@ -4,6 +4,193 @@ var __publicField = (obj, key, value) => {
|
|
|
4
4
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
return value;
|
|
6
6
|
};
|
|
7
|
+
const DEFAULT_TOKEN_LIFETIME_MS = 8 * 60 * 1e3;
|
|
8
|
+
function createSpeechAuthorizationProvider(options) {
|
|
9
|
+
var _a;
|
|
10
|
+
const hasTokenEndpoint = typeof options.tokenEndpoint === "string" && options.tokenEndpoint.trim() !== "";
|
|
11
|
+
const hasProvider = typeof options.getAuthorizationToken === "function";
|
|
12
|
+
if (hasTokenEndpoint && hasProvider) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
"Provide either tokenEndpoint or getAuthorizationToken, not both."
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
if (!hasTokenEndpoint && !hasProvider) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
"A tokenEndpoint or getAuthorizationToken provider is required."
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
if (hasProvider) {
|
|
23
|
+
return options.getAuthorizationToken;
|
|
24
|
+
}
|
|
25
|
+
const tokenEndpoint = options.tokenEndpoint.trim();
|
|
26
|
+
const requestOptions = (_a = options.tokenRequestOptions) != null ? _a : {};
|
|
27
|
+
return async () => {
|
|
28
|
+
var _a2, _b, _c;
|
|
29
|
+
let response;
|
|
30
|
+
try {
|
|
31
|
+
response = await fetch(tokenEndpoint, {
|
|
32
|
+
method: "GET",
|
|
33
|
+
cache: (_a2 = requestOptions.cache) != null ? _a2 : "no-store",
|
|
34
|
+
credentials: (_b = requestOptions.credentials) != null ? _b : "same-origin",
|
|
35
|
+
headers: {
|
|
36
|
+
Accept: "application/json",
|
|
37
|
+
...(_c = requestOptions.headers) != null ? _c : {}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
} catch {
|
|
41
|
+
throw createSafeError(
|
|
42
|
+
"Could not reach the speech token endpoint.",
|
|
43
|
+
"TOKEN_ENDPOINT_UNREACHABLE"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
throw createSafeError(
|
|
48
|
+
`Speech token endpoint returned HTTP ${response.status}.`,
|
|
49
|
+
"TOKEN_ENDPOINT_HTTP_ERROR"
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
let payload;
|
|
53
|
+
try {
|
|
54
|
+
payload = await response.json();
|
|
55
|
+
} catch {
|
|
56
|
+
throw createSafeError(
|
|
57
|
+
"Speech token endpoint returned invalid JSON.",
|
|
58
|
+
"TOKEN_ENDPOINT_INVALID_JSON"
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return validateSpeechAuthorization(payload);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function validateSpeechAuthorization(value) {
|
|
65
|
+
if (!value || typeof value !== "object") {
|
|
66
|
+
throw createSafeError(
|
|
67
|
+
"Speech authorization response must be an object.",
|
|
68
|
+
"TOKEN_INVALID_RESPONSE"
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const candidate = value;
|
|
72
|
+
const token = typeof candidate.token === "string" ? candidate.token.trim() : "";
|
|
73
|
+
const region = typeof candidate.region === "string" ? candidate.region.trim() : "";
|
|
74
|
+
if (token === "") {
|
|
75
|
+
throw createSafeError(
|
|
76
|
+
"Speech authorization token is missing or empty.",
|
|
77
|
+
"TOKEN_EMPTY"
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
if (region === "") {
|
|
81
|
+
throw createSafeError(
|
|
82
|
+
"Speech authorization region is missing or empty.",
|
|
83
|
+
"TOKEN_REGION_MISSING"
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
return { token, region };
|
|
87
|
+
}
|
|
88
|
+
function createSafeError(message, code) {
|
|
89
|
+
const error = new Error(sanitizeErrorText(message));
|
|
90
|
+
error.message = sanitizeErrorText(message);
|
|
91
|
+
if (code) {
|
|
92
|
+
error.code = code;
|
|
93
|
+
}
|
|
94
|
+
return error;
|
|
95
|
+
}
|
|
96
|
+
function toSafeErrorDetail(error) {
|
|
97
|
+
if (typeof error === "string") {
|
|
98
|
+
const message = error.trim() !== "" ? sanitizeErrorText(error) : "An unexpected speech error occurred.";
|
|
99
|
+
return { message };
|
|
100
|
+
}
|
|
101
|
+
if (error && typeof error === "object") {
|
|
102
|
+
const candidate = error;
|
|
103
|
+
const rawMessage = [
|
|
104
|
+
typeof candidate.message === "string" ? candidate.message : "",
|
|
105
|
+
typeof candidate.errorDetails === "string" ? candidate.errorDetails : "",
|
|
106
|
+
typeof candidate.reason === "string" ? candidate.reason : ""
|
|
107
|
+
].filter((part) => part.trim() !== "").join(" ");
|
|
108
|
+
const message = rawMessage !== "" ? sanitizeErrorText(rawMessage) : "An unexpected speech error occurred.";
|
|
109
|
+
const detail = { message };
|
|
110
|
+
if (typeof candidate.code === "string" && candidate.code.trim() !== "") {
|
|
111
|
+
detail.code = candidate.code;
|
|
112
|
+
} else if (typeof candidate.code === "number") {
|
|
113
|
+
detail.code = String(candidate.code);
|
|
114
|
+
}
|
|
115
|
+
return detail;
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
message: "An unexpected speech error occurred."
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function sanitizeErrorText(message) {
|
|
122
|
+
return message.replace(/Authorization\s*:\s*Bearer\s+\S+/gi, "Authorization: Bearer [redacted]").replace(/Bearer\s+\S+/gi, "Bearer [redacted]").replace(
|
|
123
|
+
/authorization[_-]?token["']?\s*[:=]\s*["']?[^"',\s}]+/gi,
|
|
124
|
+
"authorizationToken=[redacted]"
|
|
125
|
+
).replace(
|
|
126
|
+
/access[_-]?token["']?\s*[:=]\s*["']?[^"',\s}]+/gi,
|
|
127
|
+
"accessToken=[redacted]"
|
|
128
|
+
).replace(
|
|
129
|
+
/["']token["']\s*:\s*["'][^"']+["']/gi,
|
|
130
|
+
'"token":"[redacted]"'
|
|
131
|
+
).replace(
|
|
132
|
+
/token["']?\s*[:=]\s*["']?[^"',\s}]+/gi,
|
|
133
|
+
"token=[redacted]"
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
function isLikelyAuthorizationError(error) {
|
|
137
|
+
var _a;
|
|
138
|
+
const detail = toSafeErrorDetail(error);
|
|
139
|
+
const haystack = `${detail.message} ${(_a = detail.code) != null ? _a : ""}`.toLowerCase();
|
|
140
|
+
return haystack.includes("unauthorized") || haystack.includes("authentication") || haystack.includes("authorization") || haystack.includes("invalid token") || haystack.includes("token expired") || haystack.includes("expired token") || haystack.includes("403") || haystack.includes("401") || detail.code === "TOKEN_REFRESH_ERROR";
|
|
141
|
+
}
|
|
142
|
+
class SpeechAuthorizationManager {
|
|
143
|
+
constructor(options) {
|
|
144
|
+
__publicField(this, "authorization");
|
|
145
|
+
__publicField(this, "authorizationExpiresAt", 0);
|
|
146
|
+
__publicField(this, "authorizationRequest");
|
|
147
|
+
__publicField(this, "provider");
|
|
148
|
+
__publicField(this, "tokenLifetimeMs");
|
|
149
|
+
this.provider = createSpeechAuthorizationProvider(options);
|
|
150
|
+
this.tokenLifetimeMs = options.tokenLifetimeMs && options.tokenLifetimeMs > 0 ? options.tokenLifetimeMs : DEFAULT_TOKEN_LIFETIME_MS;
|
|
151
|
+
}
|
|
152
|
+
getTokenLifetimeMs() {
|
|
153
|
+
return this.tokenLifetimeMs;
|
|
154
|
+
}
|
|
155
|
+
async getAuthorization() {
|
|
156
|
+
if (this.authorization && Date.now() < this.authorizationExpiresAt) {
|
|
157
|
+
return this.authorization;
|
|
158
|
+
}
|
|
159
|
+
if (this.authorizationRequest) {
|
|
160
|
+
return this.authorizationRequest;
|
|
161
|
+
}
|
|
162
|
+
this.authorizationRequest = this.fetchAuthorization().then((authorization) => {
|
|
163
|
+
this.authorization = authorization;
|
|
164
|
+
this.authorizationExpiresAt = Date.now() + this.tokenLifetimeMs;
|
|
165
|
+
return authorization;
|
|
166
|
+
}).finally(() => {
|
|
167
|
+
this.authorizationRequest = void 0;
|
|
168
|
+
});
|
|
169
|
+
return this.authorizationRequest;
|
|
170
|
+
}
|
|
171
|
+
async refreshAuthorization() {
|
|
172
|
+
this.authorization = void 0;
|
|
173
|
+
this.authorizationExpiresAt = 0;
|
|
174
|
+
if (this.authorizationRequest) {
|
|
175
|
+
return this.authorizationRequest;
|
|
176
|
+
}
|
|
177
|
+
return this.getAuthorization();
|
|
178
|
+
}
|
|
179
|
+
clearAuthorization() {
|
|
180
|
+
this.authorization = void 0;
|
|
181
|
+
this.authorizationExpiresAt = 0;
|
|
182
|
+
}
|
|
183
|
+
async fetchAuthorization() {
|
|
184
|
+
try {
|
|
185
|
+
const authorization = await this.provider();
|
|
186
|
+
return validateSpeechAuthorization(authorization);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
this.clearAuthorization();
|
|
189
|
+
const detail = toSafeErrorDetail(error);
|
|
190
|
+
throw createSafeError(detail.message, detail.code);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
7
194
|
var ws = {};
|
|
8
195
|
var getRandomValues;
|
|
9
196
|
var rnds8 = new Uint8Array(16);
|
|
@@ -1079,7 +1266,7 @@ class Timeout {
|
|
|
1079
1266
|
throw new Error(message);
|
|
1080
1267
|
}
|
|
1081
1268
|
});
|
|
1082
|
-
const
|
|
1269
|
+
const clearTimeout2 = (timerId) => {
|
|
1083
1270
|
const id = Math.random();
|
|
1084
1271
|
unhandledRequests.set(id, timerId);
|
|
1085
1272
|
scheduledTimeoutFunctions.set(timerId, id);
|
|
@@ -1104,7 +1291,7 @@ class Timeout {
|
|
|
1104
1291
|
return timerId;
|
|
1105
1292
|
};
|
|
1106
1293
|
return {
|
|
1107
|
-
clearTimeout,
|
|
1294
|
+
clearTimeout: clearTimeout2,
|
|
1108
1295
|
setTimeout: setTimeout2
|
|
1109
1296
|
};
|
|
1110
1297
|
}
|
|
@@ -8351,16 +8538,23 @@ class RestMessageAdapter {
|
|
|
8351
8538
|
}
|
|
8352
8539
|
}
|
|
8353
8540
|
class SpeechToText {
|
|
8354
|
-
constructor(
|
|
8355
|
-
__publicField(this, "
|
|
8356
|
-
__publicField(this, "region");
|
|
8541
|
+
constructor(options) {
|
|
8542
|
+
__publicField(this, "region", "");
|
|
8357
8543
|
__publicField(this, "sourceLanguage");
|
|
8358
8544
|
__publicField(this, "targetLanguage");
|
|
8359
8545
|
__publicField(this, "recognizer");
|
|
8360
|
-
this
|
|
8361
|
-
this
|
|
8362
|
-
this
|
|
8363
|
-
this
|
|
8546
|
+
__publicField(this, "authorizationManager");
|
|
8547
|
+
__publicField(this, "authorizationRefreshIntervalMs");
|
|
8548
|
+
__publicField(this, "authorizationRefreshTimer");
|
|
8549
|
+
__publicField(this, "stopPromise");
|
|
8550
|
+
var _a;
|
|
8551
|
+
if (!options || typeof options.sourceLanguage !== "string" || options.sourceLanguage.trim() === "") {
|
|
8552
|
+
throw new Error("A sourceLanguage is required.");
|
|
8553
|
+
}
|
|
8554
|
+
this.authorizationManager = new SpeechAuthorizationManager(options);
|
|
8555
|
+
this.authorizationRefreshIntervalMs = options.tokenLifetimeMs && options.tokenLifetimeMs > 0 ? options.tokenLifetimeMs : DEFAULT_TOKEN_LIFETIME_MS;
|
|
8556
|
+
this.sourceLanguage = options.sourceLanguage;
|
|
8557
|
+
this.targetLanguage = (_a = options.targetLanguage) != null ? _a : options.sourceLanguage;
|
|
8364
8558
|
}
|
|
8365
8559
|
async start() {
|
|
8366
8560
|
await this.registerBindings(document);
|
|
@@ -8374,9 +8568,15 @@ class SpeechToText {
|
|
|
8374
8568
|
const currentNode = nodes[i];
|
|
8375
8569
|
if (currentNode.attributes) {
|
|
8376
8570
|
if (currentNode.attributes.getNamedItem("co-stt.start")) {
|
|
8377
|
-
await this.handleStartModifier(
|
|
8571
|
+
await this.handleStartModifier(
|
|
8572
|
+
currentNode,
|
|
8573
|
+
currentNode.attributes.getNamedItem("co-stt.start")
|
|
8574
|
+
);
|
|
8378
8575
|
} else if (currentNode.attributes.getNamedItem("co-stt.stop")) {
|
|
8379
|
-
await this.handleStopModifier(
|
|
8576
|
+
await this.handleStopModifier(
|
|
8577
|
+
currentNode,
|
|
8578
|
+
currentNode.attributes.getNamedItem("co-stt.stop")
|
|
8579
|
+
);
|
|
8380
8580
|
}
|
|
8381
8581
|
}
|
|
8382
8582
|
if (currentNode.childNodes.length > 0) {
|
|
@@ -8384,59 +8584,163 @@ class SpeechToText {
|
|
|
8384
8584
|
}
|
|
8385
8585
|
}
|
|
8386
8586
|
}
|
|
8587
|
+
async createSpeechTranslationConfig() {
|
|
8588
|
+
const authorization = await this.authorizationManager.getAuthorization();
|
|
8589
|
+
const speechConfig = SpeechTranslationConfig.fromAuthorizationToken(
|
|
8590
|
+
authorization.token,
|
|
8591
|
+
authorization.region
|
|
8592
|
+
);
|
|
8593
|
+
speechConfig.speechRecognitionLanguage = this.sourceLanguage;
|
|
8594
|
+
speechConfig.addTargetLanguage(
|
|
8595
|
+
this.targetLanguage
|
|
8596
|
+
);
|
|
8597
|
+
this.region = authorization.region;
|
|
8598
|
+
return speechConfig;
|
|
8599
|
+
}
|
|
8387
8600
|
async handleStartModifier(node, attr) {
|
|
8388
8601
|
node.addEventListener("click", async (_) => {
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8602
|
+
try {
|
|
8603
|
+
await this.stop();
|
|
8604
|
+
const speechConfig = await this.createSpeechTranslationConfig();
|
|
8605
|
+
const audioConfig = AudioConfig.fromDefaultMicrophoneInput();
|
|
8606
|
+
this.recognizer = new TranslationRecognizer(speechConfig, audioConfig);
|
|
8607
|
+
document.dispatchEvent(new CustomEvent("COAzureSTTStartedRecording", {}));
|
|
8608
|
+
const prevResults = {};
|
|
8609
|
+
this.recognizer.recognizing = (_sender, event) => {
|
|
8610
|
+
const result = event.result;
|
|
8611
|
+
if (result && result.reason === ResultReason.TranslatingSpeech) {
|
|
8612
|
+
const translation = result.translations.get(this.targetLanguage);
|
|
8613
|
+
prevResults["result_" + result.privOffset.toString()] = translation;
|
|
8614
|
+
const totalResult = Object.values(prevResults).join(". ");
|
|
8615
|
+
const inputElement = document.getElementById(attr.value);
|
|
8616
|
+
if (inputElement !== null) {
|
|
8617
|
+
if (inputElement instanceof HTMLInputElement) {
|
|
8618
|
+
inputElement.value = `${totalResult} `;
|
|
8619
|
+
} else {
|
|
8620
|
+
inputElement.innerHTML = `${totalResult} `;
|
|
8621
|
+
}
|
|
8408
8622
|
}
|
|
8409
8623
|
}
|
|
8624
|
+
};
|
|
8625
|
+
this.recognizer.startContinuousRecognitionAsync(
|
|
8626
|
+
() => {
|
|
8627
|
+
this.scheduleAuthorizationRefresh();
|
|
8628
|
+
},
|
|
8629
|
+
(err) => {
|
|
8630
|
+
if (isLikelyAuthorizationError(err)) {
|
|
8631
|
+
this.authorizationManager.clearAuthorization();
|
|
8632
|
+
}
|
|
8633
|
+
this.dispatchError(err, "RECOGNITION_ERROR");
|
|
8634
|
+
void this.stop();
|
|
8635
|
+
}
|
|
8636
|
+
);
|
|
8637
|
+
} catch (error) {
|
|
8638
|
+
this.clearAuthorizationRefreshTimer();
|
|
8639
|
+
if (isLikelyAuthorizationError(error)) {
|
|
8640
|
+
this.authorizationManager.clearAuthorization();
|
|
8410
8641
|
}
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
},
|
|
8415
|
-
(err) => {
|
|
8416
|
-
console.log(err);
|
|
8417
|
-
this.stop();
|
|
8418
|
-
}
|
|
8419
|
-
);
|
|
8642
|
+
this.dispatchError(error);
|
|
8643
|
+
await this.stop();
|
|
8644
|
+
}
|
|
8420
8645
|
});
|
|
8421
8646
|
}
|
|
8422
|
-
async handleStopModifier(node,
|
|
8647
|
+
async handleStopModifier(node, _attr) {
|
|
8423
8648
|
node.addEventListener("click", async (_) => {
|
|
8424
8649
|
await this.stop();
|
|
8425
8650
|
});
|
|
8426
8651
|
}
|
|
8427
8652
|
async stop() {
|
|
8428
|
-
if (this.
|
|
8429
|
-
this.
|
|
8430
|
-
|
|
8431
|
-
|
|
8653
|
+
if (this.stopPromise) {
|
|
8654
|
+
return this.stopPromise;
|
|
8655
|
+
}
|
|
8656
|
+
this.clearAuthorizationRefreshTimer();
|
|
8657
|
+
const recognizer = this.recognizer;
|
|
8658
|
+
if (!recognizer) {
|
|
8659
|
+
return;
|
|
8432
8660
|
}
|
|
8433
|
-
|
|
8661
|
+
this.recognizer = void 0;
|
|
8662
|
+
this.stopPromise = this.stopRecognizer(recognizer).finally(() => {
|
|
8663
|
+
this.stopPromise = void 0;
|
|
8664
|
+
document.dispatchEvent(
|
|
8665
|
+
new CustomEvent("COAzureSTTStoppedRecording", {})
|
|
8666
|
+
);
|
|
8667
|
+
});
|
|
8668
|
+
return this.stopPromise;
|
|
8669
|
+
}
|
|
8670
|
+
scheduleAuthorizationRefresh() {
|
|
8671
|
+
this.clearAuthorizationRefreshTimer();
|
|
8672
|
+
this.authorizationRefreshTimer = setTimeout(async () => {
|
|
8673
|
+
if (!this.recognizer) {
|
|
8674
|
+
return;
|
|
8675
|
+
}
|
|
8676
|
+
try {
|
|
8677
|
+
const authorization = await this.authorizationManager.refreshAuthorization();
|
|
8678
|
+
if (!this.recognizer) {
|
|
8679
|
+
return;
|
|
8680
|
+
}
|
|
8681
|
+
this.recognizer.authorizationToken = authorization.token;
|
|
8682
|
+
this.region = authorization.region;
|
|
8683
|
+
this.scheduleAuthorizationRefresh();
|
|
8684
|
+
} catch (error) {
|
|
8685
|
+
this.dispatchError(error, "TOKEN_REFRESH_ERROR");
|
|
8686
|
+
await this.stop();
|
|
8687
|
+
}
|
|
8688
|
+
}, this.authorizationRefreshIntervalMs);
|
|
8689
|
+
}
|
|
8690
|
+
clearAuthorizationRefreshTimer() {
|
|
8691
|
+
if (!this.authorizationRefreshTimer) {
|
|
8692
|
+
return;
|
|
8693
|
+
}
|
|
8694
|
+
clearTimeout(this.authorizationRefreshTimer);
|
|
8695
|
+
this.authorizationRefreshTimer = void 0;
|
|
8696
|
+
}
|
|
8697
|
+
stopRecognizer(recognizer) {
|
|
8698
|
+
return new Promise((resolve) => {
|
|
8699
|
+
let closed = false;
|
|
8700
|
+
const closeOnce = () => {
|
|
8701
|
+
if (closed) {
|
|
8702
|
+
resolve();
|
|
8703
|
+
return;
|
|
8704
|
+
}
|
|
8705
|
+
closed = true;
|
|
8706
|
+
try {
|
|
8707
|
+
recognizer.close();
|
|
8708
|
+
} catch {
|
|
8709
|
+
} finally {
|
|
8710
|
+
resolve();
|
|
8711
|
+
}
|
|
8712
|
+
};
|
|
8713
|
+
try {
|
|
8714
|
+
recognizer.stopContinuousRecognitionAsync(
|
|
8715
|
+
() => {
|
|
8716
|
+
closeOnce();
|
|
8717
|
+
},
|
|
8718
|
+
() => {
|
|
8719
|
+
closeOnce();
|
|
8720
|
+
}
|
|
8721
|
+
);
|
|
8722
|
+
} catch {
|
|
8723
|
+
closeOnce();
|
|
8724
|
+
}
|
|
8725
|
+
});
|
|
8726
|
+
}
|
|
8727
|
+
dispatchError(error, code) {
|
|
8728
|
+
const detail = toSafeErrorDetail(error);
|
|
8729
|
+
if (code && !detail.code) {
|
|
8730
|
+
detail.code = code;
|
|
8731
|
+
}
|
|
8732
|
+
document.dispatchEvent(
|
|
8733
|
+
new CustomEvent("COAzureSTTError", {
|
|
8734
|
+
detail: {
|
|
8735
|
+
error: detail
|
|
8736
|
+
}
|
|
8737
|
+
})
|
|
8738
|
+
);
|
|
8434
8739
|
}
|
|
8435
8740
|
}
|
|
8436
8741
|
class TextToSpeech {
|
|
8437
|
-
constructor(
|
|
8438
|
-
__publicField(this, "
|
|
8439
|
-
__publicField(this, "region");
|
|
8742
|
+
constructor(options) {
|
|
8743
|
+
__publicField(this, "region", "");
|
|
8440
8744
|
__publicField(this, "voice");
|
|
8441
8745
|
__publicField(this, "rate");
|
|
8442
8746
|
__publicField(this, "pitch");
|
|
@@ -8462,12 +8766,17 @@ class TextToSpeech {
|
|
|
8462
8766
|
__publicField(this, "prefetchPromises", /* @__PURE__ */ new Map());
|
|
8463
8767
|
__publicField(this, "activePrefetchedAudioUrl", "");
|
|
8464
8768
|
__publicField(this, "playbackSegments", []);
|
|
8465
|
-
this
|
|
8466
|
-
this
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8769
|
+
__publicField(this, "authorizationManager");
|
|
8770
|
+
__publicField(this, "stopPromise");
|
|
8771
|
+
var _a, _b, _c;
|
|
8772
|
+
if (!options || typeof options.voice !== "string" || options.voice.trim() === "") {
|
|
8773
|
+
throw new Error("A voice is required.");
|
|
8774
|
+
}
|
|
8775
|
+
this.authorizationManager = new SpeechAuthorizationManager(options);
|
|
8776
|
+
this.voice = options.voice;
|
|
8777
|
+
this.rate = (_a = options.rate) != null ? _a : 0;
|
|
8778
|
+
this.pitch = (_b = options.pitch) != null ? _b : 0;
|
|
8779
|
+
this.url = (_c = options.url) != null ? _c : "";
|
|
8471
8780
|
}
|
|
8472
8781
|
async start() {
|
|
8473
8782
|
await this.registerBindings(document);
|
|
@@ -8496,17 +8805,35 @@ class TextToSpeech {
|
|
|
8496
8805
|
const currentNode = nodes[i];
|
|
8497
8806
|
if (currentNode.attributes) {
|
|
8498
8807
|
if (currentNode.attributes.getNamedItem("co-tts.id")) {
|
|
8499
|
-
await this.handleIdModifier(
|
|
8808
|
+
await this.handleIdModifier(
|
|
8809
|
+
currentNode,
|
|
8810
|
+
currentNode.attributes.getNamedItem("co-tts.id")
|
|
8811
|
+
);
|
|
8500
8812
|
} else if (currentNode.attributes.getNamedItem("co-tts.ajax")) {
|
|
8501
|
-
await this.handleAjaxModifier(
|
|
8813
|
+
await this.handleAjaxModifier(
|
|
8814
|
+
currentNode,
|
|
8815
|
+
currentNode.attributes.getNamedItem("co-tts.ajax")
|
|
8816
|
+
);
|
|
8502
8817
|
} else if (currentNode.attributes.getNamedItem("co-tts")) {
|
|
8503
|
-
await this.handleDefault(
|
|
8818
|
+
await this.handleDefault(
|
|
8819
|
+
currentNode,
|
|
8820
|
+
currentNode.attributes.getNamedItem("co-tts")
|
|
8821
|
+
);
|
|
8504
8822
|
} else if (currentNode.attributes.getNamedItem("co-tts.stop")) {
|
|
8505
|
-
await this.handleStopModifier(
|
|
8823
|
+
await this.handleStopModifier(
|
|
8824
|
+
currentNode,
|
|
8825
|
+
currentNode.attributes.getNamedItem("co-tts.stop")
|
|
8826
|
+
);
|
|
8506
8827
|
} else if (currentNode.attributes.getNamedItem("co-tts.resume")) {
|
|
8507
|
-
await this.handleResumeModifier(
|
|
8828
|
+
await this.handleResumeModifier(
|
|
8829
|
+
currentNode,
|
|
8830
|
+
currentNode.attributes.getNamedItem("co-tts.resume")
|
|
8831
|
+
);
|
|
8508
8832
|
} else if (currentNode.attributes.getNamedItem("co-tts.pause")) {
|
|
8509
|
-
await this.handlePauseModifier(
|
|
8833
|
+
await this.handlePauseModifier(
|
|
8834
|
+
currentNode,
|
|
8835
|
+
currentNode.attributes.getNamedItem("co-tts.pause")
|
|
8836
|
+
);
|
|
8510
8837
|
}
|
|
8511
8838
|
}
|
|
8512
8839
|
if (currentNode.childNodes.length > 0) {
|
|
@@ -8516,8 +8843,8 @@ class TextToSpeech {
|
|
|
8516
8843
|
}
|
|
8517
8844
|
async handleIdModifier(node, attr) {
|
|
8518
8845
|
node.addEventListener("click", async (_) => {
|
|
8519
|
-
var _a, _b;
|
|
8520
|
-
this.stopPlayer();
|
|
8846
|
+
var _a, _b, _c, _d, _e, _f;
|
|
8847
|
+
await this.stopPlayer();
|
|
8521
8848
|
await this.createInterval();
|
|
8522
8849
|
const referenceDiv = document.getElementById(attr.value);
|
|
8523
8850
|
this.clickedNode = referenceDiv;
|
|
@@ -8527,65 +8854,69 @@ class TextToSpeech {
|
|
|
8527
8854
|
if (referenceDiv.hasAttribute("co-tts.text") && referenceDiv.getAttribute("co-tts.text") !== "") {
|
|
8528
8855
|
this.textToRead = (_a = referenceDiv.getAttribute("co-tts.text")) != null ? _a : "";
|
|
8529
8856
|
} else {
|
|
8530
|
-
this.textToRead = referenceDiv.innerText;
|
|
8857
|
+
this.textToRead = (_c = (_b = referenceDiv.innerText) != null ? _b : referenceDiv.textContent) != null ? _c : "";
|
|
8531
8858
|
}
|
|
8532
8859
|
if (referenceDiv.hasAttribute("co-tts.highlight")) {
|
|
8533
|
-
|
|
8534
|
-
|
|
8860
|
+
const highlightTarget = (_e = (_d = referenceDiv.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _d.value) != null ? _e : "";
|
|
8861
|
+
if (highlightTarget !== "") {
|
|
8862
|
+
const newReferenceDiv = document.getElementById(highlightTarget);
|
|
8535
8863
|
this.highlightDiv = newReferenceDiv;
|
|
8536
|
-
this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
|
|
8864
|
+
this.originalHighlightDivInnerHTML = (_f = newReferenceDiv == null ? void 0 : newReferenceDiv.innerHTML) != null ? _f : "";
|
|
8537
8865
|
} else {
|
|
8538
8866
|
this.highlightDiv = referenceDiv;
|
|
8539
8867
|
this.originalHighlightDivInnerHTML = referenceDiv.innerHTML;
|
|
8540
8868
|
}
|
|
8541
8869
|
}
|
|
8542
|
-
this.startSynthesizer(node, attr);
|
|
8870
|
+
await this.startSynthesizer(node, attr);
|
|
8543
8871
|
});
|
|
8544
8872
|
}
|
|
8545
8873
|
async handleAjaxModifier(node, attr) {
|
|
8546
8874
|
node.addEventListener("click", async (_) => {
|
|
8547
|
-
this.stopPlayer();
|
|
8875
|
+
await this.stopPlayer();
|
|
8548
8876
|
await this.createInterval();
|
|
8549
8877
|
this.clickedNode = node;
|
|
8550
8878
|
const response = await fetch(attr.value, {
|
|
8551
8879
|
method: `GET`
|
|
8552
8880
|
});
|
|
8553
8881
|
this.textToRead = await response.text();
|
|
8554
|
-
this.startSynthesizer(node, attr);
|
|
8882
|
+
await this.startSynthesizer(node, attr);
|
|
8555
8883
|
});
|
|
8556
8884
|
}
|
|
8557
8885
|
async handleDefault(node, attr) {
|
|
8558
8886
|
node.addEventListener("click", async (_) => {
|
|
8559
|
-
var _a;
|
|
8560
|
-
this.stopPlayer();
|
|
8887
|
+
var _a, _b, _c, _d, _e;
|
|
8888
|
+
await this.stopPlayer();
|
|
8561
8889
|
await this.createInterval();
|
|
8562
8890
|
this.clickedNode = node;
|
|
8563
8891
|
if (node.hasAttribute("co-tts.highlight")) {
|
|
8564
|
-
|
|
8565
|
-
|
|
8892
|
+
const highlightTarget = (_b = (_a = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _a.value) != null ? _b : "";
|
|
8893
|
+
if (highlightTarget !== "") {
|
|
8894
|
+
const newReferenceDiv = document.getElementById(highlightTarget);
|
|
8566
8895
|
this.highlightDiv = newReferenceDiv;
|
|
8567
|
-
this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
|
|
8896
|
+
this.originalHighlightDivInnerHTML = (_c = newReferenceDiv == null ? void 0 : newReferenceDiv.innerHTML) != null ? _c : "";
|
|
8568
8897
|
} else {
|
|
8569
8898
|
this.highlightDiv = node;
|
|
8570
8899
|
this.originalHighlightDivInnerHTML = node.innerHTML;
|
|
8571
8900
|
}
|
|
8572
8901
|
}
|
|
8573
8902
|
if (attr.value === "") {
|
|
8574
|
-
this.textToRead = node.innerText;
|
|
8903
|
+
this.textToRead = (_e = (_d = node.innerText) != null ? _d : node.textContent) != null ? _e : "";
|
|
8575
8904
|
} else {
|
|
8576
8905
|
this.textToRead = attr.value;
|
|
8577
8906
|
}
|
|
8578
|
-
this.startSynthesizer(node, attr);
|
|
8907
|
+
await this.startSynthesizer(node, attr);
|
|
8579
8908
|
});
|
|
8580
8909
|
}
|
|
8581
8910
|
async handleWithoutClick(node, attr) {
|
|
8582
|
-
var _a;
|
|
8583
|
-
this.stopPlayer();
|
|
8911
|
+
var _a, _b, _c;
|
|
8912
|
+
await this.stopPlayer();
|
|
8584
8913
|
await this.createInterval();
|
|
8585
8914
|
this.clickedNode = node;
|
|
8586
8915
|
if (node.hasAttribute("co-tts.highlight")) {
|
|
8587
8916
|
if (((_a = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _a.value) !== "") {
|
|
8588
|
-
const newReferenceDiv = document.getElementById(
|
|
8917
|
+
const newReferenceDiv = document.getElementById(
|
|
8918
|
+
node.attributes.getNamedItem("co-tts.highlight").value
|
|
8919
|
+
);
|
|
8589
8920
|
this.highlightDiv = newReferenceDiv;
|
|
8590
8921
|
if (newReferenceDiv !== null) {
|
|
8591
8922
|
this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
|
|
@@ -8596,111 +8927,172 @@ class TextToSpeech {
|
|
|
8596
8927
|
}
|
|
8597
8928
|
}
|
|
8598
8929
|
if (attr.value === "") {
|
|
8599
|
-
this.textToRead = node.innerText;
|
|
8930
|
+
this.textToRead = (_c = (_b = node.innerText) != null ? _b : node.textContent) != null ? _c : "";
|
|
8600
8931
|
} else {
|
|
8601
8932
|
this.textToRead = attr.value;
|
|
8602
8933
|
}
|
|
8603
|
-
this.startSynthesizer(node, attr);
|
|
8934
|
+
await this.startSynthesizer(node, attr);
|
|
8604
8935
|
}
|
|
8605
|
-
async handleStopModifier(node,
|
|
8936
|
+
async handleStopModifier(node, _attr) {
|
|
8606
8937
|
node.addEventListener("click", async (_) => {
|
|
8607
8938
|
await this.stopPlayer();
|
|
8608
8939
|
document.dispatchEvent(new CustomEvent("COAzureTTSStoppedPlaying", {}));
|
|
8609
8940
|
});
|
|
8610
8941
|
}
|
|
8611
|
-
async handlePauseModifier(node,
|
|
8942
|
+
async handlePauseModifier(node, _attr) {
|
|
8612
8943
|
node.addEventListener("click", async (_) => {
|
|
8944
|
+
if (!this.player || typeof this.player.pause !== "function") {
|
|
8945
|
+
return;
|
|
8946
|
+
}
|
|
8613
8947
|
await this.clearInterval();
|
|
8614
8948
|
await this.player.pause();
|
|
8615
8949
|
document.dispatchEvent(new CustomEvent("COAzureTTSPausedPlaying", {}));
|
|
8616
8950
|
});
|
|
8617
8951
|
}
|
|
8618
|
-
async handleResumeModifier(node,
|
|
8952
|
+
async handleResumeModifier(node, _attr) {
|
|
8619
8953
|
node.addEventListener("click", async (_) => {
|
|
8954
|
+
if (!this.player) {
|
|
8955
|
+
return;
|
|
8956
|
+
}
|
|
8620
8957
|
await this.createInterval();
|
|
8621
|
-
|
|
8958
|
+
if (typeof this.player.resume === "function") {
|
|
8959
|
+
await this.player.resume();
|
|
8960
|
+
} else if (typeof this.player.play === "function") {
|
|
8961
|
+
await this.player.play();
|
|
8962
|
+
} else {
|
|
8963
|
+
return;
|
|
8964
|
+
}
|
|
8622
8965
|
document.dispatchEvent(new CustomEvent("COAzureTTSResumedPlaying", {}));
|
|
8623
8966
|
});
|
|
8624
8967
|
}
|
|
8625
8968
|
async stopPlayer() {
|
|
8969
|
+
if (this.stopPromise) {
|
|
8970
|
+
return this.stopPromise;
|
|
8971
|
+
}
|
|
8972
|
+
this.stopPromise = this.performStopPlayer().finally(() => {
|
|
8973
|
+
this.stopPromise = void 0;
|
|
8974
|
+
});
|
|
8975
|
+
return this.stopPromise;
|
|
8976
|
+
}
|
|
8977
|
+
async performStopPlayer() {
|
|
8626
8978
|
await this.clearInterval();
|
|
8627
8979
|
if (this.highlightDiv !== void 0) {
|
|
8628
8980
|
this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
|
|
8629
8981
|
}
|
|
8982
|
+
this.resetPlaybackSegments();
|
|
8983
|
+
const player = this.player;
|
|
8984
|
+
const activePrefetchedAudioUrl = this.activePrefetchedAudioUrl;
|
|
8985
|
+
const synthesizer = this.synthesizer;
|
|
8630
8986
|
this.textToRead = "";
|
|
8631
8987
|
this.currentWord = "";
|
|
8632
8988
|
this.originalHighlightDivInnerHTML = "";
|
|
8633
8989
|
this.wordBoundryList = [];
|
|
8634
8990
|
this.wordEncounters = [];
|
|
8635
|
-
this.resetPlaybackSegments();
|
|
8636
8991
|
this.playbackSegments = [];
|
|
8637
|
-
if (this.player !== void 0) {
|
|
8638
|
-
this.player.pause();
|
|
8639
|
-
}
|
|
8640
|
-
if (this.activePrefetchedAudioUrl !== "") {
|
|
8641
|
-
URL.revokeObjectURL(this.activePrefetchedAudioUrl);
|
|
8642
|
-
this.activePrefetchedAudioUrl = "";
|
|
8643
|
-
}
|
|
8644
|
-
this.player = void 0;
|
|
8645
8992
|
this.highlightDiv = void 0;
|
|
8646
8993
|
this.prevTextOffset = 0;
|
|
8647
8994
|
this.playbackTextOffsetBase = void 0;
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
this.speechConfig.speechSynthesisOutputFormat = SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3;
|
|
8653
|
-
this.player = new SpeakerAudioDestination();
|
|
8654
|
-
this.audioConfig = AudioConfig.fromSpeakerOutput(this.player);
|
|
8655
|
-
this.synthesizer = new SpeechSynthesizer(this.speechConfig, this.audioConfig);
|
|
8656
|
-
this.synthesizer.wordBoundary = (s, e) => {
|
|
8657
|
-
this.wordBoundryList.push(e);
|
|
8658
|
-
};
|
|
8659
|
-
const playbackChain = this.collectPlaybackChain(this.clickedNode);
|
|
8660
|
-
const isChainedPlayback = playbackChain.length > 1;
|
|
8661
|
-
if (isChainedPlayback) {
|
|
8662
|
-
this.preparePlaybackChain(playbackChain);
|
|
8663
|
-
} else {
|
|
8664
|
-
this.playbackSegments = [];
|
|
8995
|
+
this.audioConfig = void 0;
|
|
8996
|
+
this.speechConfig = void 0;
|
|
8997
|
+
if (this.player === player) {
|
|
8998
|
+
this.player = void 0;
|
|
8665
8999
|
}
|
|
8666
|
-
this.
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
9000
|
+
if (this.activePrefetchedAudioUrl === activePrefetchedAudioUrl) {
|
|
9001
|
+
this.activePrefetchedAudioUrl = "";
|
|
9002
|
+
}
|
|
9003
|
+
if (this.synthesizer === synthesizer) {
|
|
9004
|
+
this.synthesizer = void 0;
|
|
9005
|
+
}
|
|
9006
|
+
if (player !== void 0 && typeof player.pause === "function") {
|
|
9007
|
+
try {
|
|
9008
|
+
player.pause();
|
|
9009
|
+
} catch {
|
|
8672
9010
|
}
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
9011
|
+
}
|
|
9012
|
+
if (activePrefetchedAudioUrl !== "") {
|
|
9013
|
+
URL.revokeObjectURL(activePrefetchedAudioUrl);
|
|
9014
|
+
}
|
|
9015
|
+
this.closeResource(synthesizer);
|
|
9016
|
+
}
|
|
9017
|
+
async createSpeechConfig() {
|
|
9018
|
+
const authorization = await this.authorizationManager.getAuthorization();
|
|
9019
|
+
const speechConfig = SpeechConfig.fromAuthorizationToken(
|
|
9020
|
+
authorization.token,
|
|
9021
|
+
authorization.region
|
|
9022
|
+
);
|
|
9023
|
+
speechConfig.speechSynthesisVoiceName = `Microsoft Server Speech Text to Speech Voice (${this.voice})`;
|
|
9024
|
+
speechConfig.speechSynthesisOutputFormat = SpeechSynthesisOutputFormat.Audio24Khz160KBitRateMonoMp3;
|
|
9025
|
+
this.region = authorization.region;
|
|
9026
|
+
return speechConfig;
|
|
9027
|
+
}
|
|
9028
|
+
async startSynthesizer(_node, _attr) {
|
|
9029
|
+
try {
|
|
9030
|
+
this.speechConfig = await this.createSpeechConfig();
|
|
9031
|
+
this.player = new SpeakerAudioDestination();
|
|
9032
|
+
this.audioConfig = AudioConfig.fromSpeakerOutput(this.player);
|
|
9033
|
+
this.synthesizer = new SpeechSynthesizer(this.speechConfig, this.audioConfig);
|
|
9034
|
+
this.synthesizer.wordBoundary = (_s, e) => {
|
|
9035
|
+
this.wordBoundryList.push(e);
|
|
9036
|
+
};
|
|
9037
|
+
const playbackChain = this.collectPlaybackChain(this.clickedNode);
|
|
9038
|
+
const isChainedPlayback = playbackChain.length > 1;
|
|
9039
|
+
if (isChainedPlayback) {
|
|
9040
|
+
this.preparePlaybackChain(playbackChain);
|
|
9041
|
+
} else {
|
|
9042
|
+
this.playbackSegments = [];
|
|
9043
|
+
}
|
|
9044
|
+
this.player.onAudioEnd = async () => {
|
|
9045
|
+
var _a;
|
|
9046
|
+
const clickedNode = this.clickedNode;
|
|
9047
|
+
const wasChainedPlayback = this.playbackSegments.length > 0;
|
|
9048
|
+
const nextNodeId = ((_a = clickedNode == null ? void 0 : clickedNode.hasAttribute) == null ? void 0 : _a.call(clickedNode, "co-tts.next")) ? clickedNode.getAttribute("co-tts.next") : null;
|
|
9049
|
+
await this.stopPlayer();
|
|
9050
|
+
if (wasChainedPlayback) {
|
|
9051
|
+
document.dispatchEvent(new CustomEvent("COAzureTTSFinishedPlaying", {}));
|
|
8676
9052
|
return;
|
|
8677
9053
|
}
|
|
8678
|
-
if (
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
9054
|
+
if (nextNodeId) {
|
|
9055
|
+
const nextNode = document.getElementById(nextNodeId);
|
|
9056
|
+
if (nextNode && await this.playPrefetchedNode(nextNode)) {
|
|
9057
|
+
return;
|
|
9058
|
+
}
|
|
9059
|
+
const nextTextAttr = nextNode == null ? void 0 : nextNode.attributes.getNamedItem("co-tts.text");
|
|
9060
|
+
if (nextNode && nextTextAttr) {
|
|
9061
|
+
await this.handleWithoutClick(nextNode, nextTextAttr);
|
|
9062
|
+
} else if (nextNode) {
|
|
9063
|
+
nextNode.dispatchEvent(new Event("click"));
|
|
9064
|
+
}
|
|
9065
|
+
} else {
|
|
9066
|
+
document.dispatchEvent(new CustomEvent("COAzureTTSFinishedPlaying", {}));
|
|
8682
9067
|
}
|
|
8683
|
-
}
|
|
8684
|
-
|
|
9068
|
+
};
|
|
9069
|
+
this.player.onAudioStart = async () => {
|
|
9070
|
+
document.dispatchEvent(new CustomEvent("COAzureTTSStartedPlaying", {}));
|
|
9071
|
+
};
|
|
9072
|
+
if (!isChainedPlayback) {
|
|
9073
|
+
void this.prefetchNextNode(this.clickedNode);
|
|
8685
9074
|
}
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
9075
|
+
this.synthesizer.speakSsmlAsync(
|
|
9076
|
+
this.buildSSML(this.textToRead),
|
|
9077
|
+
() => {
|
|
9078
|
+
this.closeSynthesizer();
|
|
9079
|
+
},
|
|
9080
|
+
(error) => {
|
|
9081
|
+
if (isLikelyAuthorizationError(error)) {
|
|
9082
|
+
this.authorizationManager.clearAuthorization();
|
|
9083
|
+
}
|
|
9084
|
+
this.dispatchError(error, "SYNTHESIS_ERROR");
|
|
9085
|
+
this.closeSynthesizer();
|
|
9086
|
+
void this.stopPlayer();
|
|
9087
|
+
}
|
|
9088
|
+
);
|
|
9089
|
+
} catch (error) {
|
|
9090
|
+
if (isLikelyAuthorizationError(error)) {
|
|
9091
|
+
this.authorizationManager.clearAuthorization();
|
|
8702
9092
|
}
|
|
8703
|
-
|
|
9093
|
+
this.dispatchError(error);
|
|
9094
|
+
await this.stopPlayer();
|
|
9095
|
+
}
|
|
8704
9096
|
}
|
|
8705
9097
|
collectPlaybackChain(node) {
|
|
8706
9098
|
var _a, _b;
|
|
@@ -8751,7 +9143,9 @@ class TextToSpeech {
|
|
|
8751
9143
|
return void 0;
|
|
8752
9144
|
}
|
|
8753
9145
|
if (((_a = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _a.value) !== "") {
|
|
8754
|
-
return document.getElementById(
|
|
9146
|
+
return document.getElementById(
|
|
9147
|
+
node.attributes.getNamedItem("co-tts.highlight").value
|
|
9148
|
+
);
|
|
8755
9149
|
}
|
|
8756
9150
|
return node;
|
|
8757
9151
|
}
|
|
@@ -8763,7 +9157,7 @@ class TextToSpeech {
|
|
|
8763
9157
|
});
|
|
8764
9158
|
}
|
|
8765
9159
|
updateChainedHighlight(wordBoundary) {
|
|
8766
|
-
var _a;
|
|
9160
|
+
var _a, _b;
|
|
8767
9161
|
if (~[".", ",", "!", "?", "*", "(", ")", "&", "\\", "/", "^", "[", "]", "<", ">", ":"].indexOf(wordBoundary.text)) {
|
|
8768
9162
|
wordBoundary = (_a = this.previousWordBoundary) != null ? _a : void 0;
|
|
8769
9163
|
}
|
|
@@ -8774,7 +9168,10 @@ class TextToSpeech {
|
|
|
8774
9168
|
if (this.playbackTextOffsetBase === void 0) {
|
|
8775
9169
|
this.playbackTextOffsetBase = wordBoundary.textOffset;
|
|
8776
9170
|
}
|
|
8777
|
-
const normalizedTextOffset = Math.max(
|
|
9171
|
+
const normalizedTextOffset = Math.max(
|
|
9172
|
+
0,
|
|
9173
|
+
wordBoundary.textOffset - ((_b = this.playbackTextOffsetBase) != null ? _b : 0)
|
|
9174
|
+
);
|
|
8778
9175
|
const segment = this.playbackSegments.find((candidate) => normalizedTextOffset >= candidate.start && normalizedTextOffset < candidate.end);
|
|
8779
9176
|
this.resetPlaybackSegments();
|
|
8780
9177
|
if (!(segment == null ? void 0 : segment.highlightDiv)) {
|
|
@@ -8782,7 +9179,11 @@ class TextToSpeech {
|
|
|
8782
9179
|
return;
|
|
8783
9180
|
}
|
|
8784
9181
|
const relativeTextOffset = normalizedTextOffset - segment.start;
|
|
8785
|
-
const currentOffset = this.getPosition(
|
|
9182
|
+
const currentOffset = this.getPosition(
|
|
9183
|
+
segment.originalHighlightDivInnerHTML,
|
|
9184
|
+
wordBoundary.text,
|
|
9185
|
+
relativeTextOffset
|
|
9186
|
+
);
|
|
8786
9187
|
if (currentOffset === Number.MAX_SAFE_INTEGER) {
|
|
8787
9188
|
this.previousWordBoundary = wordBoundary;
|
|
8788
9189
|
return;
|
|
@@ -8796,14 +9197,14 @@ class TextToSpeech {
|
|
|
8796
9197
|
this.previousWordBoundary = wordBoundary;
|
|
8797
9198
|
}
|
|
8798
9199
|
getNodeText(node, attr) {
|
|
8799
|
-
var _a;
|
|
9200
|
+
var _a, _b, _c;
|
|
8800
9201
|
if (attr && attr.value !== "") {
|
|
8801
9202
|
return attr.value;
|
|
8802
9203
|
}
|
|
8803
9204
|
if (node.hasAttribute("co-tts.text") && node.getAttribute("co-tts.text") !== "") {
|
|
8804
9205
|
return (_a = node.getAttribute("co-tts.text")) != null ? _a : "";
|
|
8805
9206
|
}
|
|
8806
|
-
return node.innerText;
|
|
9207
|
+
return (_c = (_b = node.innerText) != null ? _b : node.textContent) != null ? _c : "";
|
|
8807
9208
|
}
|
|
8808
9209
|
getPrefetchKey(node, text) {
|
|
8809
9210
|
return [
|
|
@@ -8842,41 +9243,58 @@ class TextToSpeech {
|
|
|
8842
9243
|
if (this.prefetchedAudio.has(key) || this.prefetchPromises.has(key)) {
|
|
8843
9244
|
return;
|
|
8844
9245
|
}
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
9246
|
+
let synthesizer;
|
|
9247
|
+
const prefetchPromise = (async () => {
|
|
9248
|
+
try {
|
|
9249
|
+
const speechConfig = await this.createSpeechConfig();
|
|
9250
|
+
synthesizer = new SpeechSynthesizer(speechConfig, void 0);
|
|
9251
|
+
const wordBoundryList = [];
|
|
9252
|
+
synthesizer.wordBoundary = (_s, e) => {
|
|
9253
|
+
wordBoundryList.push(e);
|
|
9254
|
+
};
|
|
9255
|
+
return await new Promise((resolve) => {
|
|
9256
|
+
synthesizer == null ? void 0 : synthesizer.speakSsmlAsync(
|
|
9257
|
+
this.buildSSML(text),
|
|
9258
|
+
(result) => {
|
|
9259
|
+
this.closeResource(synthesizer);
|
|
9260
|
+
synthesizer = void 0;
|
|
9261
|
+
if (!(result == null ? void 0 : result.audioData)) {
|
|
9262
|
+
resolve(null);
|
|
9263
|
+
return;
|
|
9264
|
+
}
|
|
9265
|
+
const blob = new Blob([result.audioData], { type: "audio/mpeg" });
|
|
9266
|
+
const url = URL.createObjectURL(blob);
|
|
9267
|
+
const prefetch = {
|
|
9268
|
+
key,
|
|
9269
|
+
nodeId: nextNode.id,
|
|
9270
|
+
text,
|
|
9271
|
+
url,
|
|
9272
|
+
wordBoundryList
|
|
9273
|
+
};
|
|
9274
|
+
this.prefetchedAudio.set(key, prefetch);
|
|
9275
|
+
resolve(prefetch);
|
|
9276
|
+
},
|
|
9277
|
+
(error) => {
|
|
9278
|
+
this.closeResource(synthesizer);
|
|
9279
|
+
synthesizer = void 0;
|
|
9280
|
+
if (isLikelyAuthorizationError(error)) {
|
|
9281
|
+
this.authorizationManager.clearAuthorization();
|
|
9282
|
+
}
|
|
9283
|
+
this.dispatchError(error, "PREFETCH_ERROR");
|
|
9284
|
+
resolve(null);
|
|
9285
|
+
}
|
|
9286
|
+
);
|
|
9287
|
+
});
|
|
9288
|
+
} catch (error) {
|
|
9289
|
+
this.closeResource(synthesizer);
|
|
9290
|
+
synthesizer = void 0;
|
|
9291
|
+
if (isLikelyAuthorizationError(error)) {
|
|
9292
|
+
this.authorizationManager.clearAuthorization();
|
|
8877
9293
|
}
|
|
8878
|
-
|
|
8879
|
-
|
|
9294
|
+
this.dispatchError(error);
|
|
9295
|
+
return null;
|
|
9296
|
+
}
|
|
9297
|
+
})().finally(() => {
|
|
8880
9298
|
this.prefetchPromises.delete(key);
|
|
8881
9299
|
});
|
|
8882
9300
|
this.prefetchPromises.set(key, prefetchPromise);
|
|
@@ -8902,7 +9320,9 @@ class TextToSpeech {
|
|
|
8902
9320
|
this.wordBoundaryOffset = 0;
|
|
8903
9321
|
if (node.hasAttribute("co-tts.highlight")) {
|
|
8904
9322
|
if (((_c = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _c.value) !== "") {
|
|
8905
|
-
const newReferenceDiv = document.getElementById(
|
|
9323
|
+
const newReferenceDiv = document.getElementById(
|
|
9324
|
+
node.attributes.getNamedItem("co-tts.highlight").value
|
|
9325
|
+
);
|
|
8906
9326
|
this.highlightDiv = newReferenceDiv;
|
|
8907
9327
|
if (newReferenceDiv !== null) {
|
|
8908
9328
|
this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
|
|
@@ -8913,31 +9333,48 @@ class TextToSpeech {
|
|
|
8913
9333
|
}
|
|
8914
9334
|
}
|
|
8915
9335
|
await this.createInterval();
|
|
8916
|
-
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
const
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
9336
|
+
try {
|
|
9337
|
+
const audio = new Audio(prefetch.url);
|
|
9338
|
+
this.activePrefetchedAudioUrl = prefetch.url;
|
|
9339
|
+
this.player = audio;
|
|
9340
|
+
audio.addEventListener("play", () => {
|
|
9341
|
+
document.dispatchEvent(new CustomEvent("COAzureTTSStartedPlaying", {}));
|
|
9342
|
+
}, { once: true });
|
|
9343
|
+
audio.addEventListener("ended", async () => {
|
|
9344
|
+
var _a2;
|
|
9345
|
+
const clickedNode = this.clickedNode;
|
|
9346
|
+
const nextNodeId = ((_a2 = clickedNode == null ? void 0 : clickedNode.hasAttribute) == null ? void 0 : _a2.call(clickedNode, "co-tts.next")) ? clickedNode.getAttribute("co-tts.next") : null;
|
|
9347
|
+
await this.stopPlayer();
|
|
9348
|
+
if (nextNodeId) {
|
|
9349
|
+
const nextNode = document.getElementById(nextNodeId);
|
|
9350
|
+
if (nextNode && await this.playPrefetchedNode(nextNode)) {
|
|
9351
|
+
return;
|
|
9352
|
+
}
|
|
9353
|
+
const nextTextAttr = nextNode == null ? void 0 : nextNode.attributes.getNamedItem("co-tts.text");
|
|
9354
|
+
if (nextNode && nextTextAttr) {
|
|
9355
|
+
await this.handleWithoutClick(nextNode, nextTextAttr);
|
|
9356
|
+
} else if (nextNode) {
|
|
9357
|
+
nextNode.dispatchEvent(new Event("click"));
|
|
9358
|
+
}
|
|
9359
|
+
} else {
|
|
9360
|
+
document.dispatchEvent(new CustomEvent("COAzureTTSFinishedPlaying", {}));
|
|
8933
9361
|
}
|
|
8934
|
-
}
|
|
8935
|
-
|
|
8936
|
-
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
9362
|
+
}, { once: true });
|
|
9363
|
+
audio.addEventListener("error", () => {
|
|
9364
|
+
this.dispatchError(
|
|
9365
|
+
new Error("Prefetched audio resource closed unexpectedly."),
|
|
9366
|
+
"AUDIO_RESOURCE_ERROR"
|
|
9367
|
+
);
|
|
9368
|
+
void this.stopPlayer();
|
|
9369
|
+
}, { once: true });
|
|
9370
|
+
void this.prefetchNextNode(node);
|
|
9371
|
+
await audio.play();
|
|
9372
|
+
return true;
|
|
9373
|
+
} catch (error) {
|
|
9374
|
+
this.dispatchError(error, "AUDIO_RESOURCE_ERROR");
|
|
9375
|
+
await this.stopPlayer();
|
|
9376
|
+
return false;
|
|
9377
|
+
}
|
|
8941
9378
|
}
|
|
8942
9379
|
async clearInterval() {
|
|
8943
9380
|
clearInterval(this.interval);
|
|
@@ -9040,5 +9477,31 @@ class TextToSpeech {
|
|
|
9040
9477
|
p.textContent = input;
|
|
9041
9478
|
return p.innerHTML;
|
|
9042
9479
|
}
|
|
9480
|
+
closeSynthesizer() {
|
|
9481
|
+
this.closeResource(this.synthesizer);
|
|
9482
|
+
this.synthesizer = void 0;
|
|
9483
|
+
}
|
|
9484
|
+
closeResource(resource) {
|
|
9485
|
+
if (!resource || typeof resource.close !== "function") {
|
|
9486
|
+
return;
|
|
9487
|
+
}
|
|
9488
|
+
try {
|
|
9489
|
+
resource.close();
|
|
9490
|
+
} catch {
|
|
9491
|
+
}
|
|
9492
|
+
}
|
|
9493
|
+
dispatchError(error, code) {
|
|
9494
|
+
const detail = toSafeErrorDetail(error);
|
|
9495
|
+
if (code && !detail.code) {
|
|
9496
|
+
detail.code = code;
|
|
9497
|
+
}
|
|
9498
|
+
document.dispatchEvent(
|
|
9499
|
+
new CustomEvent("COAzureTTSError", {
|
|
9500
|
+
detail: {
|
|
9501
|
+
error: detail
|
|
9502
|
+
}
|
|
9503
|
+
})
|
|
9504
|
+
);
|
|
9505
|
+
}
|
|
9043
9506
|
}
|
|
9044
|
-
export { SpeechToText, TextToSpeech };
|
|
9507
|
+
export { DEFAULT_TOKEN_LIFETIME_MS, SpeechAuthorizationManager, SpeechToText, TextToSpeech, createSpeechAuthorizationProvider, isLikelyAuthorizationError, sanitizeErrorText, toSafeErrorDetail, validateSpeechAuthorization };
|