@creativeorange/azure-text-to-speech 3.0.0 → 3.0.2
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 +99 -140
- package/dist/SpeechToText.d.ts +27 -0
- package/dist/TextToSpeech.d.ts +87 -0
- package/dist/authentication.d.ts +44 -0
- package/dist/co-azure-tts.es.js +671 -401
- package/dist/co-azure-tts.umd.js +7 -11
- package/dist/main.d.ts +4 -0
- package/package.json +11 -7
- package/src/SpeechToText.ts +0 -172
- package/src/TextToSpeech.ts +0 -846
- package/src/authentication.ts +0 -228
- package/src/main.ts +0 -9
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
|
}
|
|
@@ -8350,170 +8537,24 @@ class RestMessageAdapter {
|
|
|
8350
8537
|
return Object.keys(params).map((k) => encodeURIComponent(k) + "=" + encodeURIComponent(params[k])).join("&");
|
|
8351
8538
|
}
|
|
8352
8539
|
}
|
|
8353
|
-
const DEFAULT_TOKEN_LIFETIME_MS = 8 * 60 * 1e3;
|
|
8354
|
-
function createSpeechAuthorizationProvider(options) {
|
|
8355
|
-
var _a;
|
|
8356
|
-
const hasTokenEndpoint = typeof options.tokenEndpoint === "string" && options.tokenEndpoint.trim() !== "";
|
|
8357
|
-
const hasProvider = typeof options.getAuthorizationToken === "function";
|
|
8358
|
-
if (hasTokenEndpoint && hasProvider) {
|
|
8359
|
-
throw new Error(
|
|
8360
|
-
"Provide either tokenEndpoint or getAuthorizationToken, not both."
|
|
8361
|
-
);
|
|
8362
|
-
}
|
|
8363
|
-
if (!hasTokenEndpoint && !hasProvider) {
|
|
8364
|
-
throw new Error(
|
|
8365
|
-
"A tokenEndpoint or getAuthorizationToken provider is required."
|
|
8366
|
-
);
|
|
8367
|
-
}
|
|
8368
|
-
if (hasProvider) {
|
|
8369
|
-
return options.getAuthorizationToken;
|
|
8370
|
-
}
|
|
8371
|
-
const tokenEndpoint = options.tokenEndpoint.trim();
|
|
8372
|
-
const requestOptions = (_a = options.tokenRequestOptions) != null ? _a : {};
|
|
8373
|
-
return async () => {
|
|
8374
|
-
var _a2, _b;
|
|
8375
|
-
let response;
|
|
8376
|
-
try {
|
|
8377
|
-
response = await fetch(tokenEndpoint, {
|
|
8378
|
-
method: "GET",
|
|
8379
|
-
credentials: (_a2 = requestOptions.credentials) != null ? _a2 : "same-origin",
|
|
8380
|
-
headers: {
|
|
8381
|
-
Accept: "application/json",
|
|
8382
|
-
...(_b = requestOptions.headers) != null ? _b : {}
|
|
8383
|
-
}
|
|
8384
|
-
});
|
|
8385
|
-
} catch {
|
|
8386
|
-
throw createSafeError(
|
|
8387
|
-
"Could not reach the speech token endpoint.",
|
|
8388
|
-
"TOKEN_ENDPOINT_UNREACHABLE"
|
|
8389
|
-
);
|
|
8390
|
-
}
|
|
8391
|
-
if (!response.ok) {
|
|
8392
|
-
throw createSafeError(
|
|
8393
|
-
`Speech token endpoint returned HTTP ${response.status}.`,
|
|
8394
|
-
"TOKEN_ENDPOINT_HTTP_ERROR"
|
|
8395
|
-
);
|
|
8396
|
-
}
|
|
8397
|
-
let payload;
|
|
8398
|
-
try {
|
|
8399
|
-
payload = await response.json();
|
|
8400
|
-
} catch {
|
|
8401
|
-
throw createSafeError(
|
|
8402
|
-
"Speech token endpoint returned invalid JSON.",
|
|
8403
|
-
"TOKEN_ENDPOINT_INVALID_JSON"
|
|
8404
|
-
);
|
|
8405
|
-
}
|
|
8406
|
-
return validateSpeechAuthorization(payload);
|
|
8407
|
-
};
|
|
8408
|
-
}
|
|
8409
|
-
function validateSpeechAuthorization(value) {
|
|
8410
|
-
if (!value || typeof value !== "object") {
|
|
8411
|
-
throw createSafeError(
|
|
8412
|
-
"Speech authorization response must be an object.",
|
|
8413
|
-
"TOKEN_INVALID_RESPONSE"
|
|
8414
|
-
);
|
|
8415
|
-
}
|
|
8416
|
-
const candidate = value;
|
|
8417
|
-
const token = typeof candidate.token === "string" ? candidate.token.trim() : "";
|
|
8418
|
-
const region = typeof candidate.region === "string" ? candidate.region.trim() : "";
|
|
8419
|
-
if (token === "") {
|
|
8420
|
-
throw createSafeError(
|
|
8421
|
-
"Speech authorization token is missing or empty.",
|
|
8422
|
-
"TOKEN_EMPTY"
|
|
8423
|
-
);
|
|
8424
|
-
}
|
|
8425
|
-
if (region === "") {
|
|
8426
|
-
throw createSafeError(
|
|
8427
|
-
"Speech authorization region is missing or empty.",
|
|
8428
|
-
"TOKEN_REGION_MISSING"
|
|
8429
|
-
);
|
|
8430
|
-
}
|
|
8431
|
-
return { token, region };
|
|
8432
|
-
}
|
|
8433
|
-
function createSafeError(message, code) {
|
|
8434
|
-
const error = new Error(message);
|
|
8435
|
-
error.message = message;
|
|
8436
|
-
if (code) {
|
|
8437
|
-
error.code = code;
|
|
8438
|
-
}
|
|
8439
|
-
return error;
|
|
8440
|
-
}
|
|
8441
|
-
function toSafeErrorDetail(error) {
|
|
8442
|
-
if (error && typeof error === "object") {
|
|
8443
|
-
const candidate = error;
|
|
8444
|
-
const message = typeof candidate.message === "string" && candidate.message.trim() !== "" ? sanitizeErrorText(candidate.message) : "An unexpected speech error occurred.";
|
|
8445
|
-
const detail = { message };
|
|
8446
|
-
if (typeof candidate.code === "string" && candidate.code.trim() !== "") {
|
|
8447
|
-
detail.code = candidate.code;
|
|
8448
|
-
}
|
|
8449
|
-
return detail;
|
|
8450
|
-
}
|
|
8451
|
-
return {
|
|
8452
|
-
message: "An unexpected speech error occurred."
|
|
8453
|
-
};
|
|
8454
|
-
}
|
|
8455
|
-
function sanitizeErrorText(message) {
|
|
8456
|
-
return message.replace(/Bearer\s+\S+/gi, "Bearer [redacted]").replace(/token["']?\s*[:=]\s*["']?[^"',\s}]+/gi, "token=[redacted]");
|
|
8457
|
-
}
|
|
8458
|
-
class SpeechAuthorizationManager {
|
|
8459
|
-
constructor(options) {
|
|
8460
|
-
__publicField(this, "authorization");
|
|
8461
|
-
__publicField(this, "authorizationExpiresAt", 0);
|
|
8462
|
-
__publicField(this, "authorizationRequest");
|
|
8463
|
-
__publicField(this, "provider");
|
|
8464
|
-
__publicField(this, "tokenLifetimeMs");
|
|
8465
|
-
this.provider = createSpeechAuthorizationProvider(options);
|
|
8466
|
-
this.tokenLifetimeMs = options.tokenLifetimeMs && options.tokenLifetimeMs > 0 ? options.tokenLifetimeMs : DEFAULT_TOKEN_LIFETIME_MS;
|
|
8467
|
-
}
|
|
8468
|
-
async getAuthorization() {
|
|
8469
|
-
if (this.authorization && Date.now() < this.authorizationExpiresAt) {
|
|
8470
|
-
return this.authorization;
|
|
8471
|
-
}
|
|
8472
|
-
if (this.authorizationRequest) {
|
|
8473
|
-
return this.authorizationRequest;
|
|
8474
|
-
}
|
|
8475
|
-
this.authorizationRequest = this.fetchAuthorization().then((authorization) => {
|
|
8476
|
-
this.authorization = authorization;
|
|
8477
|
-
this.authorizationExpiresAt = Date.now() + this.tokenLifetimeMs;
|
|
8478
|
-
return authorization;
|
|
8479
|
-
}).finally(() => {
|
|
8480
|
-
this.authorizationRequest = void 0;
|
|
8481
|
-
});
|
|
8482
|
-
return this.authorizationRequest;
|
|
8483
|
-
}
|
|
8484
|
-
clearAuthorization() {
|
|
8485
|
-
this.authorization = void 0;
|
|
8486
|
-
this.authorizationExpiresAt = 0;
|
|
8487
|
-
this.authorizationRequest = void 0;
|
|
8488
|
-
}
|
|
8489
|
-
async fetchAuthorization() {
|
|
8490
|
-
try {
|
|
8491
|
-
const authorization = await this.provider();
|
|
8492
|
-
return validateSpeechAuthorization(authorization);
|
|
8493
|
-
} catch (error) {
|
|
8494
|
-
this.clearAuthorization();
|
|
8495
|
-
throw createSafeError(
|
|
8496
|
-
toSafeErrorDetail(error).message,
|
|
8497
|
-
error == null ? void 0 : error.code
|
|
8498
|
-
);
|
|
8499
|
-
}
|
|
8500
|
-
}
|
|
8501
|
-
}
|
|
8502
8540
|
class SpeechToText {
|
|
8503
8541
|
constructor(options) {
|
|
8504
|
-
__publicField(this, "region");
|
|
8542
|
+
__publicField(this, "region", "");
|
|
8505
8543
|
__publicField(this, "sourceLanguage");
|
|
8506
8544
|
__publicField(this, "targetLanguage");
|
|
8507
8545
|
__publicField(this, "recognizer");
|
|
8508
8546
|
__publicField(this, "authorizationManager");
|
|
8509
|
-
|
|
8547
|
+
__publicField(this, "authorizationRefreshIntervalMs");
|
|
8548
|
+
__publicField(this, "authorizationRefreshTimer");
|
|
8549
|
+
__publicField(this, "stopPromise");
|
|
8550
|
+
var _a;
|
|
8510
8551
|
if (!options || typeof options.sourceLanguage !== "string" || options.sourceLanguage.trim() === "") {
|
|
8511
8552
|
throw new Error("A sourceLanguage is required.");
|
|
8512
8553
|
}
|
|
8513
8554
|
this.authorizationManager = new SpeechAuthorizationManager(options);
|
|
8514
|
-
this.
|
|
8555
|
+
this.authorizationRefreshIntervalMs = options.tokenLifetimeMs && options.tokenLifetimeMs > 0 ? options.tokenLifetimeMs : DEFAULT_TOKEN_LIFETIME_MS;
|
|
8515
8556
|
this.sourceLanguage = options.sourceLanguage;
|
|
8516
|
-
this.targetLanguage = (
|
|
8557
|
+
this.targetLanguage = (_a = options.targetLanguage) != null ? _a : options.sourceLanguage;
|
|
8517
8558
|
}
|
|
8518
8559
|
async start() {
|
|
8519
8560
|
await this.registerBindings(document);
|
|
@@ -8527,9 +8568,15 @@ class SpeechToText {
|
|
|
8527
8568
|
const currentNode = nodes[i];
|
|
8528
8569
|
if (currentNode.attributes) {
|
|
8529
8570
|
if (currentNode.attributes.getNamedItem("co-stt.start")) {
|
|
8530
|
-
await this.handleStartModifier(
|
|
8571
|
+
await this.handleStartModifier(
|
|
8572
|
+
currentNode,
|
|
8573
|
+
currentNode.attributes.getNamedItem("co-stt.start")
|
|
8574
|
+
);
|
|
8531
8575
|
} else if (currentNode.attributes.getNamedItem("co-stt.stop")) {
|
|
8532
|
-
await this.handleStopModifier(
|
|
8576
|
+
await this.handleStopModifier(
|
|
8577
|
+
currentNode,
|
|
8578
|
+
currentNode.attributes.getNamedItem("co-stt.stop")
|
|
8579
|
+
);
|
|
8533
8580
|
}
|
|
8534
8581
|
}
|
|
8535
8582
|
if (currentNode.childNodes.length > 0) {
|
|
@@ -8553,12 +8600,13 @@ class SpeechToText {
|
|
|
8553
8600
|
async handleStartModifier(node, attr) {
|
|
8554
8601
|
node.addEventListener("click", async (_) => {
|
|
8555
8602
|
try {
|
|
8603
|
+
await this.stop();
|
|
8556
8604
|
const speechConfig = await this.createSpeechTranslationConfig();
|
|
8557
8605
|
const audioConfig = AudioConfig.fromDefaultMicrophoneInput();
|
|
8558
8606
|
this.recognizer = new TranslationRecognizer(speechConfig, audioConfig);
|
|
8559
8607
|
document.dispatchEvent(new CustomEvent("COAzureSTTStartedRecording", {}));
|
|
8560
|
-
const prevResults =
|
|
8561
|
-
this.recognizer.recognizing = (
|
|
8608
|
+
const prevResults = {};
|
|
8609
|
+
this.recognizer.recognizing = (_sender, event) => {
|
|
8562
8610
|
const result = event.result;
|
|
8563
8611
|
if (result && result.reason === ResultReason.TranslatingSpeech) {
|
|
8564
8612
|
const translation = result.translations.get(this.targetLanguage);
|
|
@@ -8576,36 +8624,105 @@ class SpeechToText {
|
|
|
8576
8624
|
};
|
|
8577
8625
|
this.recognizer.startContinuousRecognitionAsync(
|
|
8578
8626
|
() => {
|
|
8627
|
+
this.scheduleAuthorizationRefresh();
|
|
8579
8628
|
},
|
|
8580
8629
|
(err) => {
|
|
8630
|
+
if (isLikelyAuthorizationError(err)) {
|
|
8631
|
+
this.authorizationManager.clearAuthorization();
|
|
8632
|
+
}
|
|
8581
8633
|
this.dispatchError(err, "RECOGNITION_ERROR");
|
|
8582
|
-
this.stop();
|
|
8634
|
+
void this.stop();
|
|
8583
8635
|
}
|
|
8584
8636
|
);
|
|
8585
8637
|
} catch (error) {
|
|
8638
|
+
this.clearAuthorizationRefreshTimer();
|
|
8639
|
+
if (isLikelyAuthorizationError(error)) {
|
|
8640
|
+
this.authorizationManager.clearAuthorization();
|
|
8641
|
+
}
|
|
8586
8642
|
this.dispatchError(error);
|
|
8587
8643
|
await this.stop();
|
|
8588
8644
|
}
|
|
8589
8645
|
});
|
|
8590
8646
|
}
|
|
8591
|
-
async handleStopModifier(node,
|
|
8647
|
+
async handleStopModifier(node, _attr) {
|
|
8592
8648
|
node.addEventListener("click", async (_) => {
|
|
8593
8649
|
await this.stop();
|
|
8594
8650
|
});
|
|
8595
8651
|
}
|
|
8596
8652
|
async stop() {
|
|
8597
|
-
if (this.
|
|
8653
|
+
if (this.stopPromise) {
|
|
8654
|
+
return this.stopPromise;
|
|
8655
|
+
}
|
|
8656
|
+
this.clearAuthorizationRefreshTimer();
|
|
8657
|
+
const recognizer = this.recognizer;
|
|
8658
|
+
if (!recognizer) {
|
|
8659
|
+
return;
|
|
8660
|
+
}
|
|
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
|
+
}
|
|
8598
8676
|
try {
|
|
8599
|
-
this.
|
|
8600
|
-
|
|
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();
|
|
8601
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
|
+
};
|
|
8602
8713
|
try {
|
|
8603
|
-
|
|
8714
|
+
recognizer.stopContinuousRecognitionAsync(
|
|
8715
|
+
() => {
|
|
8716
|
+
closeOnce();
|
|
8717
|
+
},
|
|
8718
|
+
() => {
|
|
8719
|
+
closeOnce();
|
|
8720
|
+
}
|
|
8721
|
+
);
|
|
8604
8722
|
} catch {
|
|
8723
|
+
closeOnce();
|
|
8605
8724
|
}
|
|
8606
|
-
|
|
8607
|
-
}
|
|
8608
|
-
document.dispatchEvent(new CustomEvent("COAzureSTTStoppedRecording", {}));
|
|
8725
|
+
});
|
|
8609
8726
|
}
|
|
8610
8727
|
dispatchError(error, code) {
|
|
8611
8728
|
const detail = toSafeErrorDetail(error);
|
|
@@ -8621,9 +8738,27 @@ class SpeechToText {
|
|
|
8621
8738
|
);
|
|
8622
8739
|
}
|
|
8623
8740
|
}
|
|
8741
|
+
const PUNCTUATION_MARKS = [
|
|
8742
|
+
".",
|
|
8743
|
+
",",
|
|
8744
|
+
"!",
|
|
8745
|
+
"?",
|
|
8746
|
+
"*",
|
|
8747
|
+
"(",
|
|
8748
|
+
")",
|
|
8749
|
+
"&",
|
|
8750
|
+
"\\",
|
|
8751
|
+
"/",
|
|
8752
|
+
"^",
|
|
8753
|
+
"[",
|
|
8754
|
+
"]",
|
|
8755
|
+
"<",
|
|
8756
|
+
">",
|
|
8757
|
+
":"
|
|
8758
|
+
];
|
|
8624
8759
|
class TextToSpeech {
|
|
8625
8760
|
constructor(options) {
|
|
8626
|
-
__publicField(this, "region");
|
|
8761
|
+
__publicField(this, "region", "");
|
|
8627
8762
|
__publicField(this, "voice");
|
|
8628
8763
|
__publicField(this, "rate");
|
|
8629
8764
|
__publicField(this, "pitch");
|
|
@@ -8636,8 +8771,6 @@ class TextToSpeech {
|
|
|
8636
8771
|
__publicField(this, "player");
|
|
8637
8772
|
__publicField(this, "synthesizer");
|
|
8638
8773
|
__publicField(this, "previousWordBoundary");
|
|
8639
|
-
__publicField(this, "interval");
|
|
8640
|
-
__publicField(this, "wordEncounters", []);
|
|
8641
8774
|
__publicField(this, "originalHighlightDivInnerHTML", "");
|
|
8642
8775
|
__publicField(this, "currentWord", "");
|
|
8643
8776
|
__publicField(this, "currentOffset", 0);
|
|
@@ -8650,16 +8783,18 @@ class TextToSpeech {
|
|
|
8650
8783
|
__publicField(this, "activePrefetchedAudioUrl", "");
|
|
8651
8784
|
__publicField(this, "playbackSegments", []);
|
|
8652
8785
|
__publicField(this, "authorizationManager");
|
|
8653
|
-
|
|
8786
|
+
__publicField(this, "stopPromise");
|
|
8787
|
+
__publicField(this, "playbackSessionId", 0);
|
|
8788
|
+
__publicField(this, "highlightInterval");
|
|
8789
|
+
var _a, _b, _c;
|
|
8654
8790
|
if (!options || typeof options.voice !== "string" || options.voice.trim() === "") {
|
|
8655
8791
|
throw new Error("A voice is required.");
|
|
8656
8792
|
}
|
|
8657
8793
|
this.authorizationManager = new SpeechAuthorizationManager(options);
|
|
8658
|
-
this.region = (_b = (_a = options.region) == null ? void 0 : _a.trim()) != null ? _b : "";
|
|
8659
8794
|
this.voice = options.voice;
|
|
8660
|
-
this.rate = (
|
|
8661
|
-
this.pitch = (
|
|
8662
|
-
this.url = (
|
|
8795
|
+
this.rate = (_a = options.rate) != null ? _a : 0;
|
|
8796
|
+
this.pitch = (_b = options.pitch) != null ? _b : 0;
|
|
8797
|
+
this.url = (_c = options.url) != null ? _c : "";
|
|
8663
8798
|
}
|
|
8664
8799
|
async start() {
|
|
8665
8800
|
await this.registerBindings(document);
|
|
@@ -8688,17 +8823,35 @@ class TextToSpeech {
|
|
|
8688
8823
|
const currentNode = nodes[i];
|
|
8689
8824
|
if (currentNode.attributes) {
|
|
8690
8825
|
if (currentNode.attributes.getNamedItem("co-tts.id")) {
|
|
8691
|
-
await this.handleIdModifier(
|
|
8826
|
+
await this.handleIdModifier(
|
|
8827
|
+
currentNode,
|
|
8828
|
+
currentNode.attributes.getNamedItem("co-tts.id")
|
|
8829
|
+
);
|
|
8692
8830
|
} else if (currentNode.attributes.getNamedItem("co-tts.ajax")) {
|
|
8693
|
-
await this.handleAjaxModifier(
|
|
8831
|
+
await this.handleAjaxModifier(
|
|
8832
|
+
currentNode,
|
|
8833
|
+
currentNode.attributes.getNamedItem("co-tts.ajax")
|
|
8834
|
+
);
|
|
8694
8835
|
} else if (currentNode.attributes.getNamedItem("co-tts")) {
|
|
8695
|
-
await this.handleDefault(
|
|
8836
|
+
await this.handleDefault(
|
|
8837
|
+
currentNode,
|
|
8838
|
+
currentNode.attributes.getNamedItem("co-tts")
|
|
8839
|
+
);
|
|
8696
8840
|
} else if (currentNode.attributes.getNamedItem("co-tts.stop")) {
|
|
8697
|
-
await this.handleStopModifier(
|
|
8841
|
+
await this.handleStopModifier(
|
|
8842
|
+
currentNode,
|
|
8843
|
+
currentNode.attributes.getNamedItem("co-tts.stop")
|
|
8844
|
+
);
|
|
8698
8845
|
} else if (currentNode.attributes.getNamedItem("co-tts.resume")) {
|
|
8699
|
-
await this.handleResumeModifier(
|
|
8846
|
+
await this.handleResumeModifier(
|
|
8847
|
+
currentNode,
|
|
8848
|
+
currentNode.attributes.getNamedItem("co-tts.resume")
|
|
8849
|
+
);
|
|
8700
8850
|
} else if (currentNode.attributes.getNamedItem("co-tts.pause")) {
|
|
8701
|
-
await this.handlePauseModifier(
|
|
8851
|
+
await this.handlePauseModifier(
|
|
8852
|
+
currentNode,
|
|
8853
|
+
currentNode.attributes.getNamedItem("co-tts.pause")
|
|
8854
|
+
);
|
|
8702
8855
|
}
|
|
8703
8856
|
}
|
|
8704
8857
|
if (currentNode.childNodes.length > 0) {
|
|
@@ -8708,9 +8861,8 @@ class TextToSpeech {
|
|
|
8708
8861
|
}
|
|
8709
8862
|
async handleIdModifier(node, attr) {
|
|
8710
8863
|
node.addEventListener("click", async (_) => {
|
|
8711
|
-
var _a, _b, _c
|
|
8712
|
-
this.stopPlayer();
|
|
8713
|
-
await this.createInterval();
|
|
8864
|
+
var _a, _b, _c;
|
|
8865
|
+
await this.stopPlayer();
|
|
8714
8866
|
const referenceDiv = document.getElementById(attr.value);
|
|
8715
8867
|
this.clickedNode = referenceDiv;
|
|
8716
8868
|
if (!referenceDiv) {
|
|
@@ -8721,49 +8873,30 @@ class TextToSpeech {
|
|
|
8721
8873
|
} else {
|
|
8722
8874
|
this.textToRead = (_c = (_b = referenceDiv.innerText) != null ? _b : referenceDiv.textContent) != null ? _c : "";
|
|
8723
8875
|
}
|
|
8724
|
-
|
|
8725
|
-
if (((_d = referenceDiv.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _d.value) !== "") {
|
|
8726
|
-
const newReferenceDiv = document.getElementById(referenceDiv.attributes.getNamedItem("co-tts.highlight").value);
|
|
8727
|
-
this.highlightDiv = newReferenceDiv;
|
|
8728
|
-
this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
|
|
8729
|
-
} else {
|
|
8730
|
-
this.highlightDiv = referenceDiv;
|
|
8731
|
-
this.originalHighlightDivInnerHTML = referenceDiv.innerHTML;
|
|
8732
|
-
}
|
|
8733
|
-
}
|
|
8876
|
+
this.setHighlightTargetFromNode(referenceDiv);
|
|
8734
8877
|
await this.startSynthesizer(node, attr);
|
|
8735
8878
|
});
|
|
8736
8879
|
}
|
|
8737
8880
|
async handleAjaxModifier(node, attr) {
|
|
8738
8881
|
node.addEventListener("click", async (_) => {
|
|
8739
|
-
this.stopPlayer();
|
|
8740
|
-
await this.createInterval();
|
|
8882
|
+
await this.stopPlayer();
|
|
8741
8883
|
this.clickedNode = node;
|
|
8742
8884
|
const response = await fetch(attr.value, {
|
|
8743
8885
|
method: `GET`
|
|
8744
8886
|
});
|
|
8745
8887
|
this.textToRead = await response.text();
|
|
8888
|
+
this.setHighlightTargetFromNode(node);
|
|
8746
8889
|
await this.startSynthesizer(node, attr);
|
|
8747
8890
|
});
|
|
8748
8891
|
}
|
|
8749
8892
|
async handleDefault(node, attr) {
|
|
8750
8893
|
node.addEventListener("click", async (_) => {
|
|
8751
|
-
var _a, _b
|
|
8752
|
-
this.stopPlayer();
|
|
8753
|
-
await this.createInterval();
|
|
8894
|
+
var _a, _b;
|
|
8895
|
+
await this.stopPlayer();
|
|
8754
8896
|
this.clickedNode = node;
|
|
8755
|
-
|
|
8756
|
-
if (((_a = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _a.value) !== "") {
|
|
8757
|
-
const newReferenceDiv = document.getElementById(node.attributes.getNamedItem("co-tts.highlight").value);
|
|
8758
|
-
this.highlightDiv = newReferenceDiv;
|
|
8759
|
-
this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
|
|
8760
|
-
} else {
|
|
8761
|
-
this.highlightDiv = node;
|
|
8762
|
-
this.originalHighlightDivInnerHTML = node.innerHTML;
|
|
8763
|
-
}
|
|
8764
|
-
}
|
|
8897
|
+
this.setHighlightTargetFromNode(node);
|
|
8765
8898
|
if (attr.value === "") {
|
|
8766
|
-
this.textToRead = (
|
|
8899
|
+
this.textToRead = (_b = (_a = node.innerText) != null ? _a : node.textContent) != null ? _b : "";
|
|
8767
8900
|
} else {
|
|
8768
8901
|
this.textToRead = attr.value;
|
|
8769
8902
|
}
|
|
@@ -8771,75 +8904,102 @@ class TextToSpeech {
|
|
|
8771
8904
|
});
|
|
8772
8905
|
}
|
|
8773
8906
|
async handleWithoutClick(node, attr) {
|
|
8774
|
-
var _a, _b
|
|
8775
|
-
this.stopPlayer();
|
|
8776
|
-
await this.createInterval();
|
|
8907
|
+
var _a, _b;
|
|
8908
|
+
await this.stopPlayer();
|
|
8777
8909
|
this.clickedNode = node;
|
|
8778
|
-
|
|
8779
|
-
if (((_a = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _a.value) !== "") {
|
|
8780
|
-
const newReferenceDiv = document.getElementById(node.attributes.getNamedItem("co-tts.highlight").value);
|
|
8781
|
-
this.highlightDiv = newReferenceDiv;
|
|
8782
|
-
if (newReferenceDiv !== null) {
|
|
8783
|
-
this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
|
|
8784
|
-
}
|
|
8785
|
-
} else {
|
|
8786
|
-
this.highlightDiv = node;
|
|
8787
|
-
this.originalHighlightDivInnerHTML = node.innerHTML;
|
|
8788
|
-
}
|
|
8789
|
-
}
|
|
8910
|
+
this.setHighlightTargetFromNode(node);
|
|
8790
8911
|
if (attr.value === "") {
|
|
8791
|
-
this.textToRead = (
|
|
8912
|
+
this.textToRead = (_b = (_a = node.innerText) != null ? _a : node.textContent) != null ? _b : "";
|
|
8792
8913
|
} else {
|
|
8793
8914
|
this.textToRead = attr.value;
|
|
8794
8915
|
}
|
|
8795
8916
|
await this.startSynthesizer(node, attr);
|
|
8796
8917
|
}
|
|
8797
|
-
async handleStopModifier(node,
|
|
8918
|
+
async handleStopModifier(node, _attr) {
|
|
8798
8919
|
node.addEventListener("click", async (_) => {
|
|
8799
8920
|
await this.stopPlayer();
|
|
8800
8921
|
document.dispatchEvent(new CustomEvent("COAzureTTSStoppedPlaying", {}));
|
|
8801
8922
|
});
|
|
8802
8923
|
}
|
|
8803
|
-
async handlePauseModifier(node,
|
|
8924
|
+
async handlePauseModifier(node, _attr) {
|
|
8804
8925
|
node.addEventListener("click", async (_) => {
|
|
8805
|
-
|
|
8926
|
+
if (!this.player || typeof this.player.pause !== "function") {
|
|
8927
|
+
return;
|
|
8928
|
+
}
|
|
8929
|
+
this.stopHighlightingInterval();
|
|
8806
8930
|
await this.player.pause();
|
|
8807
8931
|
document.dispatchEvent(new CustomEvent("COAzureTTSPausedPlaying", {}));
|
|
8808
8932
|
});
|
|
8809
8933
|
}
|
|
8810
|
-
async handleResumeModifier(node,
|
|
8934
|
+
async handleResumeModifier(node, _attr) {
|
|
8811
8935
|
node.addEventListener("click", async (_) => {
|
|
8812
|
-
|
|
8813
|
-
|
|
8936
|
+
if (!this.player) {
|
|
8937
|
+
return;
|
|
8938
|
+
}
|
|
8939
|
+
if (this.shouldHighlight()) {
|
|
8940
|
+
this.startHighlightingInterval(this.playbackSessionId);
|
|
8941
|
+
}
|
|
8942
|
+
if (typeof this.player.resume === "function") {
|
|
8943
|
+
await this.player.resume();
|
|
8944
|
+
} else if (typeof this.player.play === "function") {
|
|
8945
|
+
await this.player.play();
|
|
8946
|
+
} else {
|
|
8947
|
+
return;
|
|
8948
|
+
}
|
|
8814
8949
|
document.dispatchEvent(new CustomEvent("COAzureTTSResumedPlaying", {}));
|
|
8815
8950
|
});
|
|
8816
8951
|
}
|
|
8817
8952
|
async stopPlayer() {
|
|
8818
|
-
|
|
8819
|
-
|
|
8953
|
+
if (this.stopPromise) {
|
|
8954
|
+
return this.stopPromise;
|
|
8955
|
+
}
|
|
8956
|
+
this.stopPromise = this.performStopPlayer().finally(() => {
|
|
8957
|
+
this.stopPromise = void 0;
|
|
8958
|
+
});
|
|
8959
|
+
return this.stopPromise;
|
|
8960
|
+
}
|
|
8961
|
+
async performStopPlayer() {
|
|
8962
|
+
this.invalidatePlaybackSession();
|
|
8963
|
+
this.stopHighlightingInterval();
|
|
8964
|
+
if (this.highlightDiv) {
|
|
8820
8965
|
this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
|
|
8821
8966
|
}
|
|
8967
|
+
this.resetPlaybackSegments();
|
|
8968
|
+
const player = this.player;
|
|
8969
|
+
const activePrefetchedAudioUrl = this.activePrefetchedAudioUrl;
|
|
8970
|
+
const synthesizer = this.synthesizer;
|
|
8822
8971
|
this.textToRead = "";
|
|
8823
8972
|
this.currentWord = "";
|
|
8973
|
+
this.currentOffset = 0;
|
|
8974
|
+
this.wordBoundaryOffset = 0;
|
|
8824
8975
|
this.originalHighlightDivInnerHTML = "";
|
|
8825
8976
|
this.wordBoundryList = [];
|
|
8826
|
-
this.wordEncounters = [];
|
|
8827
|
-
this.resetPlaybackSegments();
|
|
8828
8977
|
this.playbackSegments = [];
|
|
8829
|
-
|
|
8830
|
-
this.player.pause();
|
|
8831
|
-
}
|
|
8832
|
-
if (this.activePrefetchedAudioUrl !== "") {
|
|
8833
|
-
URL.revokeObjectURL(this.activePrefetchedAudioUrl);
|
|
8834
|
-
this.activePrefetchedAudioUrl = "";
|
|
8835
|
-
}
|
|
8836
|
-
this.closeSynthesizer();
|
|
8837
|
-
this.player = void 0;
|
|
8838
|
-
this.audioConfig = void 0;
|
|
8839
|
-
this.speechConfig = void 0;
|
|
8978
|
+
this.previousWordBoundary = void 0;
|
|
8840
8979
|
this.highlightDiv = void 0;
|
|
8841
8980
|
this.prevTextOffset = 0;
|
|
8842
8981
|
this.playbackTextOffsetBase = void 0;
|
|
8982
|
+
this.audioConfig = void 0;
|
|
8983
|
+
this.speechConfig = void 0;
|
|
8984
|
+
if (this.player === player) {
|
|
8985
|
+
this.player = void 0;
|
|
8986
|
+
}
|
|
8987
|
+
if (this.activePrefetchedAudioUrl === activePrefetchedAudioUrl) {
|
|
8988
|
+
this.activePrefetchedAudioUrl = "";
|
|
8989
|
+
}
|
|
8990
|
+
if (this.synthesizer === synthesizer) {
|
|
8991
|
+
this.synthesizer = void 0;
|
|
8992
|
+
}
|
|
8993
|
+
if (player !== void 0 && typeof player.pause === "function") {
|
|
8994
|
+
try {
|
|
8995
|
+
player.pause();
|
|
8996
|
+
} catch {
|
|
8997
|
+
}
|
|
8998
|
+
}
|
|
8999
|
+
if (activePrefetchedAudioUrl !== "") {
|
|
9000
|
+
URL.revokeObjectURL(activePrefetchedAudioUrl);
|
|
9001
|
+
}
|
|
9002
|
+
this.closeResource(synthesizer);
|
|
8843
9003
|
}
|
|
8844
9004
|
async createSpeechConfig() {
|
|
8845
9005
|
const authorization = await this.authorizationManager.getAuthorization();
|
|
@@ -8852,13 +9012,21 @@ class TextToSpeech {
|
|
|
8852
9012
|
this.region = authorization.region;
|
|
8853
9013
|
return speechConfig;
|
|
8854
9014
|
}
|
|
8855
|
-
async startSynthesizer(
|
|
9015
|
+
async startSynthesizer(_node, _attr) {
|
|
8856
9016
|
try {
|
|
8857
9017
|
this.speechConfig = await this.createSpeechConfig();
|
|
8858
|
-
|
|
8859
|
-
this.
|
|
8860
|
-
|
|
8861
|
-
|
|
9018
|
+
const sessionId = this.createPlaybackSession();
|
|
9019
|
+
this.resetHighlightState();
|
|
9020
|
+
const player = new SpeakerAudioDestination();
|
|
9021
|
+
const audioConfig = AudioConfig.fromSpeakerOutput(player);
|
|
9022
|
+
const synthesizer = new SpeechSynthesizer(this.speechConfig, audioConfig);
|
|
9023
|
+
this.player = player;
|
|
9024
|
+
this.audioConfig = audioConfig;
|
|
9025
|
+
this.synthesizer = synthesizer;
|
|
9026
|
+
synthesizer.wordBoundary = (_s, e) => {
|
|
9027
|
+
if (!this.isActivePlaybackSession(sessionId)) {
|
|
9028
|
+
return;
|
|
9029
|
+
}
|
|
8862
9030
|
this.wordBoundryList.push(e);
|
|
8863
9031
|
};
|
|
8864
9032
|
const playbackChain = this.collectPlaybackChain(this.clickedNode);
|
|
@@ -8868,20 +9036,27 @@ class TextToSpeech {
|
|
|
8868
9036
|
} else {
|
|
8869
9037
|
this.playbackSegments = [];
|
|
8870
9038
|
}
|
|
8871
|
-
|
|
9039
|
+
player.onAudioEnd = async () => {
|
|
9040
|
+
var _a;
|
|
9041
|
+
if (!this.isActivePlaybackSession(sessionId)) {
|
|
9042
|
+
return;
|
|
9043
|
+
}
|
|
9044
|
+
const clickedNode = this.clickedNode;
|
|
8872
9045
|
const wasChainedPlayback = this.playbackSegments.length > 0;
|
|
8873
|
-
|
|
9046
|
+
const nextNodeId = ((_a = clickedNode == null ? void 0 : clickedNode.hasAttribute) == null ? void 0 : _a.call(clickedNode, "co-tts.next")) ? clickedNode.getAttribute("co-tts.next") : null;
|
|
9047
|
+
await this.stopPlayer();
|
|
8874
9048
|
if (wasChainedPlayback) {
|
|
8875
9049
|
document.dispatchEvent(new CustomEvent("COAzureTTSFinishedPlaying", {}));
|
|
8876
9050
|
return;
|
|
8877
9051
|
}
|
|
8878
|
-
if (
|
|
8879
|
-
const nextNode = document.getElementById(
|
|
9052
|
+
if (nextNodeId) {
|
|
9053
|
+
const nextNode = document.getElementById(nextNodeId);
|
|
8880
9054
|
if (nextNode && await this.playPrefetchedNode(nextNode)) {
|
|
8881
9055
|
return;
|
|
8882
9056
|
}
|
|
8883
|
-
|
|
8884
|
-
|
|
9057
|
+
const nextTextAttr = nextNode == null ? void 0 : nextNode.attributes.getNamedItem("co-tts.text");
|
|
9058
|
+
if (nextNode && nextTextAttr) {
|
|
9059
|
+
await this.handleWithoutClick(nextNode, nextTextAttr);
|
|
8885
9060
|
} else if (nextNode) {
|
|
8886
9061
|
nextNode.dispatchEvent(new Event("click"));
|
|
8887
9062
|
}
|
|
@@ -8889,24 +9064,46 @@ class TextToSpeech {
|
|
|
8889
9064
|
document.dispatchEvent(new CustomEvent("COAzureTTSFinishedPlaying", {}));
|
|
8890
9065
|
}
|
|
8891
9066
|
};
|
|
8892
|
-
|
|
9067
|
+
player.onAudioStart = async () => {
|
|
9068
|
+
if (!this.isActivePlaybackSession(sessionId)) {
|
|
9069
|
+
return;
|
|
9070
|
+
}
|
|
8893
9071
|
document.dispatchEvent(new CustomEvent("COAzureTTSStartedPlaying", {}));
|
|
8894
9072
|
};
|
|
9073
|
+
if (this.shouldHighlight()) {
|
|
9074
|
+
this.startHighlightingInterval(sessionId);
|
|
9075
|
+
}
|
|
8895
9076
|
if (!isChainedPlayback) {
|
|
8896
|
-
this.prefetchNextNode(this.clickedNode);
|
|
9077
|
+
void this.prefetchNextNode(this.clickedNode);
|
|
8897
9078
|
}
|
|
8898
|
-
this.
|
|
8899
|
-
|
|
9079
|
+
const ssml = this.buildSSML(this.textToRead);
|
|
9080
|
+
synthesizer.speakSsmlAsync(
|
|
9081
|
+
ssml,
|
|
8900
9082
|
() => {
|
|
8901
|
-
this.
|
|
9083
|
+
this.closeResource(synthesizer);
|
|
9084
|
+
if (this.isActivePlaybackSession(sessionId) && this.synthesizer === synthesizer) {
|
|
9085
|
+
this.synthesizer = void 0;
|
|
9086
|
+
}
|
|
8902
9087
|
},
|
|
8903
9088
|
(error) => {
|
|
9089
|
+
this.closeResource(synthesizer);
|
|
9090
|
+
if (!this.isActivePlaybackSession(sessionId)) {
|
|
9091
|
+
return;
|
|
9092
|
+
}
|
|
9093
|
+
if (this.synthesizer === synthesizer) {
|
|
9094
|
+
this.synthesizer = void 0;
|
|
9095
|
+
}
|
|
9096
|
+
if (isLikelyAuthorizationError(error)) {
|
|
9097
|
+
this.authorizationManager.clearAuthorization();
|
|
9098
|
+
}
|
|
8904
9099
|
this.dispatchError(error, "SYNTHESIS_ERROR");
|
|
8905
|
-
this.
|
|
8906
|
-
this.stopPlayer();
|
|
9100
|
+
void this.stopPlayer();
|
|
8907
9101
|
}
|
|
8908
9102
|
);
|
|
8909
9103
|
} catch (error) {
|
|
9104
|
+
if (isLikelyAuthorizationError(error)) {
|
|
9105
|
+
this.authorizationManager.clearAuthorization();
|
|
9106
|
+
}
|
|
8910
9107
|
this.dispatchError(error);
|
|
8911
9108
|
await this.stopPlayer();
|
|
8912
9109
|
}
|
|
@@ -8946,21 +9143,16 @@ class TextToSpeech {
|
|
|
8946
9143
|
this.textToRead = chain.map((segment) => segment.text).join(" ");
|
|
8947
9144
|
this.highlightDiv = void 0;
|
|
8948
9145
|
this.originalHighlightDivInnerHTML = "";
|
|
8949
|
-
this.
|
|
8950
|
-
this.previousWordBoundary = void 0;
|
|
8951
|
-
this.prevTextOffset = 0;
|
|
8952
|
-
this.playbackTextOffsetBase = void 0;
|
|
8953
|
-
this.currentWord = "";
|
|
8954
|
-
this.currentOffset = 0;
|
|
8955
|
-
this.wordBoundaryOffset = 0;
|
|
9146
|
+
this.resetHighlightState();
|
|
8956
9147
|
}
|
|
8957
9148
|
getHighlightDivForNode(node) {
|
|
8958
|
-
var _a;
|
|
8959
|
-
if (!node.hasAttribute("co-tts.highlight")) {
|
|
9149
|
+
var _a, _b, _c, _d;
|
|
9150
|
+
if (!((_a = node == null ? void 0 : node.hasAttribute) == null ? void 0 : _a.call(node, "co-tts.highlight"))) {
|
|
8960
9151
|
return void 0;
|
|
8961
9152
|
}
|
|
8962
|
-
|
|
8963
|
-
|
|
9153
|
+
const highlightTarget = (_c = (_b = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _b.value) != null ? _c : "";
|
|
9154
|
+
if (highlightTarget !== "") {
|
|
9155
|
+
return (_d = document.getElementById(highlightTarget)) != null ? _d : void 0;
|
|
8964
9156
|
}
|
|
8965
9157
|
return node;
|
|
8966
9158
|
}
|
|
@@ -8972,18 +9164,19 @@ class TextToSpeech {
|
|
|
8972
9164
|
});
|
|
8973
9165
|
}
|
|
8974
9166
|
updateChainedHighlight(wordBoundary) {
|
|
8975
|
-
var _a;
|
|
8976
|
-
if (~
|
|
9167
|
+
var _a, _b;
|
|
9168
|
+
if (~PUNCTUATION_MARKS.indexOf(wordBoundary.text)) {
|
|
8977
9169
|
wordBoundary = (_a = this.previousWordBoundary) != null ? _a : void 0;
|
|
8978
9170
|
}
|
|
8979
9171
|
if (!wordBoundary) {
|
|
8980
9172
|
this.resetPlaybackSegments();
|
|
8981
9173
|
return;
|
|
8982
9174
|
}
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
9175
|
+
this.ensurePlaybackTextOffsetBase();
|
|
9176
|
+
const normalizedTextOffset = Math.max(
|
|
9177
|
+
0,
|
|
9178
|
+
wordBoundary.textOffset - ((_b = this.playbackTextOffsetBase) != null ? _b : 0)
|
|
9179
|
+
);
|
|
8987
9180
|
const segment = this.playbackSegments.find((candidate) => normalizedTextOffset >= candidate.start && normalizedTextOffset < candidate.end);
|
|
8988
9181
|
this.resetPlaybackSegments();
|
|
8989
9182
|
if (!(segment == null ? void 0 : segment.highlightDiv)) {
|
|
@@ -8991,17 +9184,12 @@ class TextToSpeech {
|
|
|
8991
9184
|
return;
|
|
8992
9185
|
}
|
|
8993
9186
|
const relativeTextOffset = normalizedTextOffset - segment.start;
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
const endOffset = currentOffset + wordBoundary.wordLength;
|
|
9001
|
-
const endOfString = segment.originalHighlightDivInnerHTML.substring(endOffset);
|
|
9002
|
-
segment.highlightDiv.innerHTML = `
|
|
9003
|
-
${startOfString}<mark class='co-tts-highlight'>${wordBoundary.text}</mark>${endOfString}
|
|
9004
|
-
`;
|
|
9187
|
+
this.highlightTextRange(
|
|
9188
|
+
segment.highlightDiv,
|
|
9189
|
+
segment.originalHighlightDivInnerHTML,
|
|
9190
|
+
relativeTextOffset,
|
|
9191
|
+
wordBoundary.wordLength
|
|
9192
|
+
);
|
|
9005
9193
|
this.previousWordBoundary = wordBoundary;
|
|
9006
9194
|
}
|
|
9007
9195
|
getNodeText(node, attr) {
|
|
@@ -9055,9 +9243,9 @@ class TextToSpeech {
|
|
|
9055
9243
|
const prefetchPromise = (async () => {
|
|
9056
9244
|
try {
|
|
9057
9245
|
const speechConfig = await this.createSpeechConfig();
|
|
9058
|
-
synthesizer = new SpeechSynthesizer(speechConfig,
|
|
9246
|
+
synthesizer = new SpeechSynthesizer(speechConfig, void 0);
|
|
9059
9247
|
const wordBoundryList = [];
|
|
9060
|
-
synthesizer.wordBoundary = (
|
|
9248
|
+
synthesizer.wordBoundary = (_s, e) => {
|
|
9061
9249
|
wordBoundryList.push(e);
|
|
9062
9250
|
};
|
|
9063
9251
|
return await new Promise((resolve) => {
|
|
@@ -9085,6 +9273,9 @@ class TextToSpeech {
|
|
|
9085
9273
|
(error) => {
|
|
9086
9274
|
this.closeResource(synthesizer);
|
|
9087
9275
|
synthesizer = void 0;
|
|
9276
|
+
if (isLikelyAuthorizationError(error)) {
|
|
9277
|
+
this.authorizationManager.clearAuthorization();
|
|
9278
|
+
}
|
|
9088
9279
|
this.dispatchError(error, "PREFETCH_ERROR");
|
|
9089
9280
|
resolve(null);
|
|
9090
9281
|
}
|
|
@@ -9093,6 +9284,9 @@ class TextToSpeech {
|
|
|
9093
9284
|
} catch (error) {
|
|
9094
9285
|
this.closeResource(synthesizer);
|
|
9095
9286
|
synthesizer = void 0;
|
|
9287
|
+
if (isLikelyAuthorizationError(error)) {
|
|
9288
|
+
this.authorizationManager.clearAuthorization();
|
|
9289
|
+
}
|
|
9096
9290
|
this.dispatchError(error);
|
|
9097
9291
|
return null;
|
|
9098
9292
|
}
|
|
@@ -9102,7 +9296,7 @@ class TextToSpeech {
|
|
|
9102
9296
|
this.prefetchPromises.set(key, prefetchPromise);
|
|
9103
9297
|
}
|
|
9104
9298
|
async playPrefetchedNode(node) {
|
|
9105
|
-
var _a, _b
|
|
9299
|
+
var _a, _b;
|
|
9106
9300
|
const attr = (_a = node.attributes.getNamedItem("co-tts.text")) != null ? _a : node.attributes.getNamedItem("co-tts");
|
|
9107
9301
|
const text = this.getNodeText(node, attr);
|
|
9108
9302
|
const key = this.getPrefetchKey(node, text);
|
|
@@ -9111,44 +9305,39 @@ class TextToSpeech {
|
|
|
9111
9305
|
return false;
|
|
9112
9306
|
}
|
|
9113
9307
|
this.prefetchedAudio.delete(key);
|
|
9308
|
+
const sessionId = this.createPlaybackSession();
|
|
9309
|
+
this.resetHighlightState();
|
|
9114
9310
|
this.clickedNode = node;
|
|
9115
9311
|
this.textToRead = prefetch.text;
|
|
9116
9312
|
this.wordBoundryList = prefetch.wordBoundryList;
|
|
9117
|
-
this.
|
|
9118
|
-
this.
|
|
9119
|
-
this.prevTextOffset = 0;
|
|
9120
|
-
this.currentWord = "";
|
|
9121
|
-
this.currentOffset = 0;
|
|
9122
|
-
this.wordBoundaryOffset = 0;
|
|
9123
|
-
if (node.hasAttribute("co-tts.highlight")) {
|
|
9124
|
-
if (((_c = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _c.value) !== "") {
|
|
9125
|
-
const newReferenceDiv = document.getElementById(node.attributes.getNamedItem("co-tts.highlight").value);
|
|
9126
|
-
this.highlightDiv = newReferenceDiv;
|
|
9127
|
-
if (newReferenceDiv !== null) {
|
|
9128
|
-
this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
|
|
9129
|
-
}
|
|
9130
|
-
} else {
|
|
9131
|
-
this.highlightDiv = node;
|
|
9132
|
-
this.originalHighlightDivInnerHTML = node.innerHTML;
|
|
9133
|
-
}
|
|
9134
|
-
}
|
|
9135
|
-
await this.createInterval();
|
|
9313
|
+
this.playbackSegments = [];
|
|
9314
|
+
this.setHighlightTargetFromNode(node);
|
|
9136
9315
|
try {
|
|
9137
9316
|
const audio = new Audio(prefetch.url);
|
|
9138
9317
|
this.activePrefetchedAudioUrl = prefetch.url;
|
|
9139
9318
|
this.player = audio;
|
|
9140
9319
|
audio.addEventListener("play", () => {
|
|
9320
|
+
if (!this.isActivePlaybackSession(sessionId)) {
|
|
9321
|
+
return;
|
|
9322
|
+
}
|
|
9141
9323
|
document.dispatchEvent(new CustomEvent("COAzureTTSStartedPlaying", {}));
|
|
9142
9324
|
}, { once: true });
|
|
9143
9325
|
audio.addEventListener("ended", async () => {
|
|
9144
|
-
|
|
9145
|
-
if (this.
|
|
9146
|
-
|
|
9326
|
+
var _a2;
|
|
9327
|
+
if (!this.isActivePlaybackSession(sessionId)) {
|
|
9328
|
+
return;
|
|
9329
|
+
}
|
|
9330
|
+
const clickedNode = this.clickedNode;
|
|
9331
|
+
const nextNodeId = ((_a2 = clickedNode == null ? void 0 : clickedNode.hasAttribute) == null ? void 0 : _a2.call(clickedNode, "co-tts.next")) ? clickedNode.getAttribute("co-tts.next") : null;
|
|
9332
|
+
await this.stopPlayer();
|
|
9333
|
+
if (nextNodeId) {
|
|
9334
|
+
const nextNode = document.getElementById(nextNodeId);
|
|
9147
9335
|
if (nextNode && await this.playPrefetchedNode(nextNode)) {
|
|
9148
9336
|
return;
|
|
9149
9337
|
}
|
|
9150
|
-
|
|
9151
|
-
|
|
9338
|
+
const nextTextAttr = nextNode == null ? void 0 : nextNode.attributes.getNamedItem("co-tts.text");
|
|
9339
|
+
if (nextNode && nextTextAttr) {
|
|
9340
|
+
await this.handleWithoutClick(nextNode, nextTextAttr);
|
|
9152
9341
|
} else if (nextNode) {
|
|
9153
9342
|
nextNode.dispatchEvent(new Event("click"));
|
|
9154
9343
|
}
|
|
@@ -9157,101 +9346,186 @@ class TextToSpeech {
|
|
|
9157
9346
|
}
|
|
9158
9347
|
}, { once: true });
|
|
9159
9348
|
audio.addEventListener("error", () => {
|
|
9349
|
+
if (!this.isActivePlaybackSession(sessionId)) {
|
|
9350
|
+
return;
|
|
9351
|
+
}
|
|
9160
9352
|
this.dispatchError(
|
|
9161
9353
|
new Error("Prefetched audio resource closed unexpectedly."),
|
|
9162
9354
|
"AUDIO_RESOURCE_ERROR"
|
|
9163
9355
|
);
|
|
9164
|
-
this.stopPlayer();
|
|
9356
|
+
void this.stopPlayer();
|
|
9165
9357
|
}, { once: true });
|
|
9166
|
-
this.
|
|
9358
|
+
if (this.shouldHighlight()) {
|
|
9359
|
+
this.startHighlightingInterval(sessionId);
|
|
9360
|
+
}
|
|
9361
|
+
void this.prefetchNextNode(node);
|
|
9167
9362
|
await audio.play();
|
|
9168
9363
|
return true;
|
|
9169
9364
|
} catch (error) {
|
|
9365
|
+
this.stopHighlightingInterval();
|
|
9170
9366
|
this.dispatchError(error, "AUDIO_RESOURCE_ERROR");
|
|
9171
9367
|
await this.stopPlayer();
|
|
9172
9368
|
return false;
|
|
9173
9369
|
}
|
|
9174
9370
|
}
|
|
9175
|
-
|
|
9176
|
-
|
|
9371
|
+
createPlaybackSession() {
|
|
9372
|
+
this.playbackSessionId += 1;
|
|
9373
|
+
return this.playbackSessionId;
|
|
9177
9374
|
}
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
wordBoundary = (_a = this.previousWordBoundary) != null ? _a : void 0;
|
|
9198
|
-
}
|
|
9199
|
-
if (wordBoundary === void 0 || this.prevTextOffset > wordBoundary.prevTextOffset) {
|
|
9200
|
-
this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
|
|
9201
|
-
} else {
|
|
9202
|
-
if (!this.wordEncounters[wordBoundary.text]) {
|
|
9203
|
-
this.wordEncounters[wordBoundary.text] = 0;
|
|
9204
|
-
}
|
|
9205
|
-
this.prevTextOffset = wordBoundary.prevTextOffset;
|
|
9206
|
-
if (this.currentWord !== wordBoundary.text || this.wordBoundaryOffset !== wordBoundary.textOffset) {
|
|
9207
|
-
this.currentOffset = this.getPosition(
|
|
9208
|
-
this.originalHighlightDivInnerHTML,
|
|
9209
|
-
wordBoundary.text,
|
|
9210
|
-
wordBoundary.textOffset
|
|
9211
|
-
);
|
|
9212
|
-
this.wordEncounters[wordBoundary.text] = this.currentOffset + wordBoundary.wordLength;
|
|
9213
|
-
this.currentWord = wordBoundary.text;
|
|
9214
|
-
this.wordBoundaryOffset = wordBoundary.textOffset;
|
|
9215
|
-
}
|
|
9216
|
-
if (this.currentOffset === Number.MAX_SAFE_INTEGER) {
|
|
9217
|
-
this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
|
|
9218
|
-
} else {
|
|
9219
|
-
this.previousWordBoundary = wordBoundary;
|
|
9220
|
-
const startOfString = this.originalHighlightDivInnerHTML.substring(0, this.currentOffset);
|
|
9221
|
-
const endOffset = this.currentOffset + wordBoundary.wordLength;
|
|
9222
|
-
const endOfString = this.originalHighlightDivInnerHTML.substring(endOffset);
|
|
9223
|
-
this.highlightDiv.innerHTML = `
|
|
9224
|
-
${startOfString}<mark class='co-tts-highlight'>${wordBoundary.text}</mark>${endOfString}
|
|
9225
|
-
`;
|
|
9226
|
-
}
|
|
9227
|
-
}
|
|
9228
|
-
} else if (this.playbackSegments.length > 0) {
|
|
9229
|
-
this.resetPlaybackSegments();
|
|
9230
|
-
} else {
|
|
9231
|
-
this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
|
|
9232
|
-
}
|
|
9375
|
+
isActivePlaybackSession(sessionId) {
|
|
9376
|
+
return sessionId === this.playbackSessionId;
|
|
9377
|
+
}
|
|
9378
|
+
invalidatePlaybackSession() {
|
|
9379
|
+
this.playbackSessionId += 1;
|
|
9380
|
+
}
|
|
9381
|
+
stopHighlightingInterval() {
|
|
9382
|
+
if (!this.highlightInterval) {
|
|
9383
|
+
return;
|
|
9384
|
+
}
|
|
9385
|
+
clearInterval(this.highlightInterval);
|
|
9386
|
+
this.highlightInterval = void 0;
|
|
9387
|
+
}
|
|
9388
|
+
startHighlightingInterval(sessionId) {
|
|
9389
|
+
this.stopHighlightingInterval();
|
|
9390
|
+
this.highlightInterval = setInterval(() => {
|
|
9391
|
+
if (!this.isActivePlaybackSession(sessionId)) {
|
|
9392
|
+
this.stopHighlightingInterval();
|
|
9393
|
+
return;
|
|
9233
9394
|
}
|
|
9395
|
+
this.updateHighlightForCurrentTime(sessionId);
|
|
9234
9396
|
}, 50);
|
|
9235
9397
|
}
|
|
9236
|
-
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9398
|
+
updateHighlightForCurrentTime(sessionId) {
|
|
9399
|
+
var _a, _b;
|
|
9400
|
+
if (!this.isActivePlaybackSession(sessionId) || this.player === void 0) {
|
|
9401
|
+
return;
|
|
9402
|
+
}
|
|
9403
|
+
if (!this.shouldHighlight()) {
|
|
9404
|
+
return;
|
|
9405
|
+
}
|
|
9406
|
+
const currentTime = this.player.currentTime;
|
|
9407
|
+
let wordBoundary;
|
|
9408
|
+
for (const e of this.wordBoundryList) {
|
|
9409
|
+
if (currentTime * 1e3 > e.audioOffset / 1e4) {
|
|
9410
|
+
wordBoundary = e;
|
|
9411
|
+
} else {
|
|
9412
|
+
break;
|
|
9249
9413
|
}
|
|
9250
|
-
|
|
9251
|
-
|
|
9414
|
+
}
|
|
9415
|
+
if (wordBoundary === void 0) {
|
|
9416
|
+
this.resetCurrentHighlight();
|
|
9417
|
+
return;
|
|
9418
|
+
}
|
|
9419
|
+
if (this.playbackSegments.length > 0) {
|
|
9420
|
+
this.updateChainedHighlight(wordBoundary);
|
|
9421
|
+
return;
|
|
9422
|
+
}
|
|
9423
|
+
if (~PUNCTUATION_MARKS.indexOf(wordBoundary.text)) {
|
|
9424
|
+
wordBoundary = (_a = this.previousWordBoundary) != null ? _a : void 0;
|
|
9425
|
+
}
|
|
9426
|
+
if (wordBoundary === void 0 || this.prevTextOffset > wordBoundary.textOffset) {
|
|
9427
|
+
this.resetCurrentHighlight();
|
|
9428
|
+
return;
|
|
9429
|
+
}
|
|
9430
|
+
this.prevTextOffset = wordBoundary.textOffset;
|
|
9431
|
+
this.ensurePlaybackTextOffsetBase();
|
|
9432
|
+
const normalizedTextOffset = Math.max(
|
|
9433
|
+
0,
|
|
9434
|
+
wordBoundary.textOffset - ((_b = this.playbackTextOffsetBase) != null ? _b : 0)
|
|
9435
|
+
);
|
|
9436
|
+
this.highlightTextRange(
|
|
9437
|
+
this.highlightDiv,
|
|
9438
|
+
this.originalHighlightDivInnerHTML,
|
|
9439
|
+
normalizedTextOffset,
|
|
9440
|
+
wordBoundary.wordLength
|
|
9441
|
+
);
|
|
9442
|
+
this.previousWordBoundary = wordBoundary;
|
|
9443
|
+
this.currentWord = wordBoundary.text;
|
|
9444
|
+
this.wordBoundaryOffset = wordBoundary.textOffset;
|
|
9445
|
+
}
|
|
9446
|
+
highlightTextRange(target, originalHtml, textOffset, wordLength) {
|
|
9447
|
+
if (!target || wordLength <= 0) {
|
|
9448
|
+
return;
|
|
9449
|
+
}
|
|
9450
|
+
target.innerHTML = originalHtml;
|
|
9451
|
+
const walker = document.createTreeWalker(
|
|
9452
|
+
target,
|
|
9453
|
+
NodeFilter.SHOW_TEXT
|
|
9454
|
+
);
|
|
9455
|
+
let currentOffset = 0;
|
|
9456
|
+
let startNode;
|
|
9457
|
+
let endNode;
|
|
9458
|
+
let startOffset = 0;
|
|
9459
|
+
let endOffset = 0;
|
|
9460
|
+
const requestedEnd = textOffset + wordLength;
|
|
9461
|
+
while (walker.nextNode()) {
|
|
9462
|
+
const node = walker.currentNode;
|
|
9463
|
+
const nodeLength = node.data.length;
|
|
9464
|
+
const nodeStart = currentOffset;
|
|
9465
|
+
const nodeEnd = currentOffset + nodeLength;
|
|
9466
|
+
if (!startNode && textOffset >= nodeStart && textOffset < nodeEnd) {
|
|
9467
|
+
startNode = node;
|
|
9468
|
+
startOffset = textOffset - nodeStart;
|
|
9469
|
+
}
|
|
9470
|
+
if (requestedEnd > nodeStart && requestedEnd <= nodeEnd) {
|
|
9471
|
+
endNode = node;
|
|
9472
|
+
endOffset = requestedEnd - nodeStart;
|
|
9473
|
+
break;
|
|
9252
9474
|
}
|
|
9475
|
+
currentOffset = nodeEnd;
|
|
9476
|
+
}
|
|
9477
|
+
if (!startNode || !endNode) {
|
|
9478
|
+
return;
|
|
9479
|
+
}
|
|
9480
|
+
const range = document.createRange();
|
|
9481
|
+
try {
|
|
9482
|
+
range.setStart(startNode, startOffset);
|
|
9483
|
+
range.setEnd(endNode, endOffset);
|
|
9484
|
+
const mark = document.createElement("mark");
|
|
9485
|
+
mark.className = "co-tts-highlight";
|
|
9486
|
+
mark.appendChild(range.extractContents());
|
|
9487
|
+
range.insertNode(mark);
|
|
9488
|
+
} catch {
|
|
9489
|
+
target.innerHTML = originalHtml;
|
|
9490
|
+
}
|
|
9491
|
+
}
|
|
9492
|
+
setHighlightTargetFromNode(node) {
|
|
9493
|
+
var _a;
|
|
9494
|
+
const highlightDiv = this.getHighlightDivForNode(node);
|
|
9495
|
+
this.highlightDiv = highlightDiv;
|
|
9496
|
+
this.originalHighlightDivInnerHTML = (_a = highlightDiv == null ? void 0 : highlightDiv.innerHTML) != null ? _a : "";
|
|
9497
|
+
}
|
|
9498
|
+
shouldHighlight() {
|
|
9499
|
+
if (this.highlightDiv) {
|
|
9500
|
+
return true;
|
|
9501
|
+
}
|
|
9502
|
+
return this.playbackSegments.some((segment) => Boolean(segment.highlightDiv));
|
|
9503
|
+
}
|
|
9504
|
+
resetHighlightState() {
|
|
9505
|
+
this.prevTextOffset = 0;
|
|
9506
|
+
this.previousWordBoundary = void 0;
|
|
9507
|
+
this.currentWord = "";
|
|
9508
|
+
this.currentOffset = 0;
|
|
9509
|
+
this.wordBoundaryOffset = 0;
|
|
9510
|
+
this.playbackTextOffsetBase = void 0;
|
|
9511
|
+
}
|
|
9512
|
+
ensurePlaybackTextOffsetBase() {
|
|
9513
|
+
if (this.playbackTextOffsetBase !== void 0 || this.wordBoundryList.length === 0) {
|
|
9514
|
+
return;
|
|
9515
|
+
}
|
|
9516
|
+
this.playbackTextOffsetBase = this.wordBoundryList.reduce(
|
|
9517
|
+
(minimum, boundary) => Math.min(minimum, boundary.textOffset),
|
|
9518
|
+
this.wordBoundryList[0].textOffset
|
|
9519
|
+
);
|
|
9520
|
+
}
|
|
9521
|
+
resetCurrentHighlight() {
|
|
9522
|
+
if (this.playbackSegments.length > 0) {
|
|
9523
|
+
this.resetPlaybackSegments();
|
|
9524
|
+
return;
|
|
9525
|
+
}
|
|
9526
|
+
if (this.highlightDiv) {
|
|
9527
|
+
this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
|
|
9253
9528
|
}
|
|
9254
|
-
return string.indexOf(subString);
|
|
9255
9529
|
}
|
|
9256
9530
|
buildSSML(text) {
|
|
9257
9531
|
let ssml = `<speak xmlns="http://www.w3.org/2001/10/synthesis"
|
|
@@ -9273,10 +9547,6 @@ class TextToSpeech {
|
|
|
9273
9547
|
p.textContent = input;
|
|
9274
9548
|
return p.innerHTML;
|
|
9275
9549
|
}
|
|
9276
|
-
closeSynthesizer() {
|
|
9277
|
-
this.closeResource(this.synthesizer);
|
|
9278
|
-
this.synthesizer = void 0;
|
|
9279
|
-
}
|
|
9280
9550
|
closeResource(resource) {
|
|
9281
9551
|
if (!resource || typeof resource.close !== "function") {
|
|
9282
9552
|
return;
|
|
@@ -9300,4 +9570,4 @@ class TextToSpeech {
|
|
|
9300
9570
|
);
|
|
9301
9571
|
}
|
|
9302
9572
|
}
|
|
9303
|
-
export { SpeechToText, TextToSpeech };
|
|
9573
|
+
export { DEFAULT_TOKEN_LIFETIME_MS, SpeechAuthorizationManager, SpeechToText, TextToSpeech, createSpeechAuthorizationProvider, isLikelyAuthorizationError, sanitizeErrorText, toSafeErrorDetail, validateSpeechAuthorization };
|