@pie-players/pie-tool-line-reader 0.3.28 → 0.3.30
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/dist/{dist-Bud4G4lv.js → dist-DIBQdekL.js} +193 -138
- package/dist/{dist-DwP27yIs.js → dist-rF11IR1B.js} +13 -1
- package/dist/tool-line-reader.js +1526 -1440
- package/package.json +6 -7
- package/index.ts +0 -8
|
@@ -1,66 +1,101 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { t as l } from "./defineProperty-CyepwRr5.js";
|
|
2
|
+
function w(e, t) {
|
|
3
|
+
if (typeof e != "string" || e.length === 0) return null;
|
|
4
|
+
try {
|
|
5
|
+
const r = typeof t.apiEndpoint == "string" && /^https?:\/\//i.test(t.apiEndpoint) ? t.apiEndpoint : void 0, i = r ? new URL(e, r) : new URL(e);
|
|
6
|
+
return i.protocol !== "http:" && i.protocol !== "https:" ? null : i;
|
|
7
|
+
} catch {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function k(e, t) {
|
|
12
|
+
const r = Array.isArray(t.assetOrigins) ? t.assetOrigins.filter((i) => typeof i == "string" && i.length > 0).map((i) => {
|
|
13
|
+
try {
|
|
14
|
+
return new URL(i).origin;
|
|
15
|
+
} catch {
|
|
16
|
+
return i;
|
|
17
|
+
}
|
|
18
|
+
}) : [];
|
|
19
|
+
if (r.length === 0) {
|
|
20
|
+
if (typeof t.apiEndpoint == "string" && /^https?:\/\//i.test(t.apiEndpoint)) try {
|
|
21
|
+
return new URL(t.apiEndpoint).origin === e.origin;
|
|
22
|
+
} catch {
|
|
23
|
+
return !1;
|
|
24
|
+
}
|
|
25
|
+
return typeof window < "u" && typeof window.location?.origin == "string" && window.location.origin === e.origin;
|
|
26
|
+
}
|
|
27
|
+
return r.includes(e.origin);
|
|
28
|
+
}
|
|
29
|
+
function A(e) {
|
|
30
|
+
const t = {};
|
|
31
|
+
for (const [r, i] of Object.entries(e)) {
|
|
32
|
+
const o = r.toLowerCase();
|
|
33
|
+
o === "authorization" || o === "proxy-authorization" || o === "cookie" || o.startsWith("x-auth-") || (t[r] = i);
|
|
34
|
+
}
|
|
35
|
+
return t;
|
|
36
|
+
}
|
|
37
|
+
var R = (e) => {
|
|
38
|
+
const t = (e.providerOptions && typeof e.providerOptions == "object" ? e.providerOptions : {}).__pieTelemetry;
|
|
39
|
+
return typeof t == "function" ? t : void 0;
|
|
40
|
+
}, M = {
|
|
6
41
|
pie: 3e3,
|
|
7
42
|
custom: 3e3
|
|
8
|
-
},
|
|
9
|
-
const
|
|
10
|
-
return r === "polly" || r === "google" ? `${
|
|
11
|
-
},
|
|
12
|
-
const
|
|
13
|
-
if (typeof
|
|
14
|
-
const r = Number(
|
|
43
|
+
}, T = (e) => e.replace(/\/+$/, ""), E = (e) => {
|
|
44
|
+
const t = T(e.apiEndpoint), r = (e.provider || "").toLowerCase();
|
|
45
|
+
return r === "polly" || r === "google" ? `${t}/${r}/voices` : `${t}/voices`;
|
|
46
|
+
}, b = (e) => e.transportMode === "custom" ? "custom" : e.transportMode === "pie" ? "pie" : e.provider === "custom" ? "custom" : "pie", S = (e, t) => e.endpointMode ? e.endpointMode : t === "custom" ? "rootPost" : "synthesizePath", U = (e, t) => e.endpointValidationMode ? e.endpointValidationMode : t === "custom" ? "none" : "voices", O = (e) => {
|
|
47
|
+
const t = e.providerOptions || {};
|
|
48
|
+
if (typeof t.speedRate == "string") return t.speedRate;
|
|
49
|
+
const r = Number(e.rate ?? 1);
|
|
15
50
|
return !Number.isFinite(r) || r <= 0.95 ? "slow" : r >= 1.5 ? "fast" : "medium";
|
|
16
|
-
},
|
|
17
|
-
const
|
|
51
|
+
}, P = (e) => {
|
|
52
|
+
const t = [];
|
|
18
53
|
let r = 0;
|
|
19
|
-
const i =
|
|
54
|
+
const i = e.split(`
|
|
20
55
|
`).map((o) => o.trim()).filter(Boolean);
|
|
21
56
|
for (const o of i) try {
|
|
22
|
-
const s = JSON.parse(o), a = typeof s.type == "string" ? s.type : "word", d = typeof s.time == "number" && Number.isFinite(s.time) ? s.time : 0, n = typeof s.value == "string" ? s.value : "",
|
|
23
|
-
r = Math.max(
|
|
57
|
+
const s = JSON.parse(o), a = typeof s.type == "string" ? s.type : "word", d = typeof s.time == "number" && Number.isFinite(s.time) ? s.time : 0, n = typeof s.value == "string" ? s.value : "", h = typeof s.start == "number" && Number.isFinite(s.start) ? s.start : null, u = typeof s.end == "number" && Number.isFinite(s.end) ? s.end : null, p = h ?? r, c = u ?? p + Math.max(1, n.length || String(s.value || "").length);
|
|
58
|
+
r = Math.max(c + 1, r), t.push({
|
|
24
59
|
time: d,
|
|
25
60
|
type: a,
|
|
26
|
-
start:
|
|
27
|
-
end:
|
|
61
|
+
start: p,
|
|
62
|
+
end: c,
|
|
28
63
|
value: n
|
|
29
64
|
});
|
|
30
65
|
} catch {
|
|
31
66
|
}
|
|
32
|
-
return
|
|
33
|
-
},
|
|
34
|
-
if (!Array.isArray(
|
|
35
|
-
const
|
|
67
|
+
return t;
|
|
68
|
+
}, C = (e) => {
|
|
69
|
+
if (!Array.isArray(e)) return [];
|
|
70
|
+
const t = [];
|
|
36
71
|
let r = 0;
|
|
37
|
-
for (const i of
|
|
72
|
+
for (const i of e) {
|
|
38
73
|
if (!i || typeof i != "object") continue;
|
|
39
|
-
const o = typeof i.type == "string" ? i.type : "word", s = typeof i.time == "number" && Number.isFinite(i.time) ? i.time : 0, a = typeof i.value == "string" ? i.value : "", d = typeof i.start == "number" && Number.isFinite(i.start) ? i.start : null, n = typeof i.end == "number" && Number.isFinite(i.end) ? i.end : null,
|
|
40
|
-
r = Math.max(r, u + 1),
|
|
74
|
+
const o = typeof i.type == "string" ? i.type : "word", s = typeof i.time == "number" && Number.isFinite(i.time) ? i.time : 0, a = typeof i.value == "string" ? i.value : "", d = typeof i.start == "number" && Number.isFinite(i.start) ? i.start : null, n = typeof i.end == "number" && Number.isFinite(i.end) ? i.end : null, h = d ?? r, u = n ?? h + Math.max(1, a.length || 1);
|
|
75
|
+
r = Math.max(r, u + 1), t.push({
|
|
41
76
|
time: s,
|
|
42
77
|
type: o,
|
|
43
|
-
start:
|
|
78
|
+
start: h,
|
|
44
79
|
end: u,
|
|
45
80
|
value: a
|
|
46
81
|
});
|
|
47
82
|
}
|
|
48
|
-
return
|
|
49
|
-
},
|
|
83
|
+
return t.sort((i, o) => i.time !== o.time ? i.time - o.time : i.start !== o.start ? i.start - o.start : i.end - o.end);
|
|
84
|
+
}, x = {
|
|
50
85
|
pie: {
|
|
51
86
|
id: "pie",
|
|
52
|
-
resolveSynthesisUrl: (
|
|
53
|
-
const
|
|
54
|
-
return
|
|
87
|
+
resolveSynthesisUrl: (e) => {
|
|
88
|
+
const t = S(e, "pie"), r = T(e.apiEndpoint);
|
|
89
|
+
return t === "rootPost" ? r : `${r}/synthesize`;
|
|
55
90
|
},
|
|
56
|
-
buildRequestBody: (
|
|
57
|
-
const r =
|
|
91
|
+
buildRequestBody: (e, t) => {
|
|
92
|
+
const r = t.providerOptions || {}, i = typeof t.engine == "string" ? t.engine : typeof r.engine == "string" ? r.engine : void 0, o = typeof r.sampleRate == "number" && Number.isFinite(r.sampleRate) ? r.sampleRate : void 0, s = r.format === "mp3" || r.format === "ogg" || r.format === "pcm" ? r.format : void 0, a = Array.isArray(r.speechMarkTypes) ? r.speechMarkTypes.filter((d) => d === "word" || d === "sentence" || d === "ssml") : void 0;
|
|
58
93
|
return {
|
|
59
|
-
text:
|
|
60
|
-
provider:
|
|
61
|
-
voice:
|
|
62
|
-
language:
|
|
63
|
-
rate:
|
|
94
|
+
text: e,
|
|
95
|
+
provider: t.provider || "polly",
|
|
96
|
+
voice: t.voice,
|
|
97
|
+
language: t.language,
|
|
98
|
+
rate: t.rate,
|
|
64
99
|
engine: i,
|
|
65
100
|
sampleRate: o,
|
|
66
101
|
format: s,
|
|
@@ -68,73 +103,79 @@ var b = (t) => {
|
|
|
68
103
|
includeSpeechMarks: !0
|
|
69
104
|
};
|
|
70
105
|
},
|
|
71
|
-
parseResponse: async (
|
|
72
|
-
const
|
|
106
|
+
parseResponse: async (e) => {
|
|
107
|
+
const t = await e.json();
|
|
73
108
|
return {
|
|
74
109
|
audio: {
|
|
75
110
|
kind: "base64",
|
|
76
|
-
data:
|
|
77
|
-
contentType:
|
|
111
|
+
data: t.audio,
|
|
112
|
+
contentType: t.contentType
|
|
78
113
|
},
|
|
79
|
-
speechMarks: Array.isArray(
|
|
114
|
+
speechMarks: Array.isArray(t.speechMarks) ? t.speechMarks : []
|
|
80
115
|
};
|
|
81
116
|
}
|
|
82
117
|
},
|
|
83
118
|
custom: {
|
|
84
119
|
id: "custom",
|
|
85
|
-
resolveSynthesisUrl: (
|
|
86
|
-
const
|
|
87
|
-
return
|
|
120
|
+
resolveSynthesisUrl: (e) => {
|
|
121
|
+
const t = S(e, "custom"), r = T(e.apiEndpoint);
|
|
122
|
+
return t === "synthesizePath" ? `${r}/synthesize` : r;
|
|
88
123
|
},
|
|
89
|
-
buildRequestBody: (
|
|
90
|
-
const r =
|
|
124
|
+
buildRequestBody: (e, t) => {
|
|
125
|
+
const r = t.providerOptions || {}, i = typeof r.lang_id == "string" ? r.lang_id : t.language || "en-US", o = typeof r.cache == "boolean" ? r.cache : !0;
|
|
91
126
|
return {
|
|
92
|
-
text:
|
|
93
|
-
speedRate:
|
|
127
|
+
text: e,
|
|
128
|
+
speedRate: O(t),
|
|
94
129
|
lang_id: i,
|
|
95
130
|
cache: o
|
|
96
131
|
};
|
|
97
132
|
},
|
|
98
|
-
parseResponse: async (
|
|
99
|
-
const o = await
|
|
100
|
-
if (
|
|
101
|
-
for (const [
|
|
133
|
+
parseResponse: async (e, t, r, i) => {
|
|
134
|
+
const o = await e.json(), s = {};
|
|
135
|
+
if (t.includeAuthOnAssetFetch)
|
|
136
|
+
for (const [h, u] of Object.entries(r)) h.toLowerCase() === "authorization" && (s[h] = u);
|
|
102
137
|
let a = [];
|
|
103
|
-
const d =
|
|
138
|
+
const d = C(o.speechMarks);
|
|
104
139
|
if (d.length > 0) a = d;
|
|
105
140
|
else if (typeof o.word == "string" && o.word.length > 0) {
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
141
|
+
const h = w(o.word, t);
|
|
142
|
+
if (h !== null) {
|
|
143
|
+
const u = k(h, t) ? s : A(s), p = await fetch(h.toString(), {
|
|
144
|
+
headers: u,
|
|
145
|
+
signal: i,
|
|
146
|
+
redirect: "error"
|
|
147
|
+
});
|
|
148
|
+
p.ok && (a = P(await p.text()));
|
|
149
|
+
}
|
|
111
150
|
}
|
|
151
|
+
const n = w(o.audioContent, t);
|
|
152
|
+
if (n === null) throw new Error("TTS server returned an invalid audio URL");
|
|
112
153
|
return {
|
|
113
154
|
audio: {
|
|
114
155
|
kind: "url",
|
|
115
|
-
url:
|
|
156
|
+
url: n.toString()
|
|
116
157
|
},
|
|
117
158
|
speechMarks: a
|
|
118
159
|
};
|
|
119
160
|
}
|
|
120
161
|
}
|
|
121
|
-
},
|
|
122
|
-
constructor(
|
|
123
|
-
|
|
162
|
+
}, z = class {
|
|
163
|
+
constructor(e, t) {
|
|
164
|
+
l(this, "config", void 0), l(this, "adapter", void 0), l(this, "currentAudio", null), l(this, "pausedState", !1), l(this, "wordTimings", []), l(this, "highlightInterval", null), l(this, "intentionallyStopped", !1), l(this, "activeSynthesisController", null), l(this, "synthesisRunId", 0), l(this, "telemetryReporter", void 0), l(this, "onWordBoundary", void 0), this.config = e, this.adapter = t, this.telemetryReporter = R(e);
|
|
124
165
|
}
|
|
125
|
-
async emitTelemetry(
|
|
166
|
+
async emitTelemetry(e, t) {
|
|
126
167
|
try {
|
|
127
|
-
await this.telemetryReporter?.(
|
|
168
|
+
await this.telemetryReporter?.(e, t);
|
|
128
169
|
} catch (r) {
|
|
129
170
|
console.warn("[ServerTTSProvider] telemetry callback failed:", r);
|
|
130
171
|
}
|
|
131
172
|
}
|
|
132
|
-
async speak(
|
|
173
|
+
async speak(e) {
|
|
133
174
|
this.stop(), this.intentionallyStopped = !1;
|
|
134
|
-
const
|
|
175
|
+
const t = ++this.synthesisRunId, r = new AbortController();
|
|
135
176
|
this.activeSynthesisController = r;
|
|
136
|
-
const { audioUrl: i, wordTimings: o } = await this.synthesizeSpeech(
|
|
137
|
-
if (
|
|
177
|
+
const { audioUrl: i, wordTimings: o } = await this.synthesizeSpeech(e, r.signal, t);
|
|
178
|
+
if (t !== this.synthesisRunId) {
|
|
138
179
|
URL.revokeObjectURL(i);
|
|
139
180
|
return;
|
|
140
181
|
}
|
|
@@ -148,14 +189,14 @@ var b = (t) => {
|
|
|
148
189
|
this.pausedState = !1, this.onWordBoundary && this.wordTimings.length > 0 && this.startWordHighlighting();
|
|
149
190
|
}, n.onended = () => {
|
|
150
191
|
this.stopWordHighlighting(), URL.revokeObjectURL(i), this.currentAudio = null, this.wordTimings = [], a();
|
|
151
|
-
}, n.onerror = (
|
|
192
|
+
}, n.onerror = (h) => {
|
|
152
193
|
this.stopWordHighlighting(), URL.revokeObjectURL(i), this.currentAudio = null, this.wordTimings = [], this.intentionallyStopped ? a() : d(/* @__PURE__ */ new Error("Failed to play audio from server"));
|
|
153
194
|
}, n.onpause = () => {
|
|
154
195
|
this.stopWordHighlighting(), this.pausedState = !0;
|
|
155
196
|
}, n.play().catch(d);
|
|
156
197
|
});
|
|
157
198
|
}
|
|
158
|
-
async synthesizeSpeech(
|
|
199
|
+
async synthesizeSpeech(e, t, r) {
|
|
159
200
|
const i = Date.now();
|
|
160
201
|
await this.emitTelemetry("pie-tool-backend-call-start", {
|
|
161
202
|
toolId: "tts",
|
|
@@ -167,27 +208,27 @@ var b = (t) => {
|
|
|
167
208
|
...this.config.headers
|
|
168
209
|
};
|
|
169
210
|
this.config.authToken && (o.Authorization = `Bearer ${this.config.authToken}`);
|
|
170
|
-
const s = this.adapter.resolveSynthesisUrl(this.config), a = this.adapter.buildRequestBody(
|
|
211
|
+
const s = this.adapter.resolveSynthesisUrl(this.config), a = this.adapter.buildRequestBody(e, this.config), d = await (async () => {
|
|
171
212
|
try {
|
|
172
213
|
return await fetch(s, {
|
|
173
214
|
method: "POST",
|
|
174
215
|
headers: o,
|
|
175
216
|
body: JSON.stringify(a),
|
|
176
|
-
signal:
|
|
217
|
+
signal: t
|
|
177
218
|
});
|
|
178
|
-
} catch (
|
|
219
|
+
} catch (c) {
|
|
179
220
|
throw await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
180
221
|
toolId: "tts",
|
|
181
222
|
backend: this.config.provider || "server",
|
|
182
223
|
operation: "synthesize-speech",
|
|
183
224
|
duration: Date.now() - i,
|
|
184
225
|
errorType: "TTSBackendNetworkError",
|
|
185
|
-
message:
|
|
186
|
-
}),
|
|
226
|
+
message: c instanceof Error ? c.message : String(c)
|
|
227
|
+
}), c;
|
|
187
228
|
}
|
|
188
229
|
})();
|
|
189
230
|
if (!d.ok) {
|
|
190
|
-
const
|
|
231
|
+
const c = await d.json().catch(() => ({})), y = c.message || c.error?.message || `Server returned ${d.status}`;
|
|
191
232
|
throw await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
192
233
|
toolId: "tts",
|
|
193
234
|
backend: this.config.provider || "server",
|
|
@@ -195,15 +236,15 @@ var b = (t) => {
|
|
|
195
236
|
duration: Date.now() - i,
|
|
196
237
|
statusCode: d.status,
|
|
197
238
|
errorType: "TTSBackendRequestError",
|
|
198
|
-
message:
|
|
199
|
-
}), new Error(
|
|
239
|
+
message: y
|
|
240
|
+
}), new Error(y);
|
|
200
241
|
}
|
|
201
|
-
const n = await this.adapter.parseResponse(d, this.config, o,
|
|
202
|
-
if (r !== this.synthesisRunId ||
|
|
203
|
-
let
|
|
204
|
-
if (n.audio.kind === "base64")
|
|
242
|
+
const n = await this.adapter.parseResponse(d, this.config, o, t);
|
|
243
|
+
if (r !== this.synthesisRunId || t.aborted) throw new Error("Synthesis superseded by a newer request");
|
|
244
|
+
let h;
|
|
245
|
+
if (n.audio.kind === "base64") h = this.base64ToBlob(n.audio.data, n.audio.contentType);
|
|
205
246
|
else {
|
|
206
|
-
const
|
|
247
|
+
const c = n.audio.url, y = Date.now();
|
|
207
248
|
await this.emitTelemetry("pie-tool-backend-call-start", {
|
|
208
249
|
toolId: "tts",
|
|
209
250
|
backend: this.config.provider || "server",
|
|
@@ -211,18 +252,29 @@ var b = (t) => {
|
|
|
211
252
|
});
|
|
212
253
|
const f = {};
|
|
213
254
|
this.config.includeAuthOnAssetFetch && this.config.authToken && (f.Authorization = `Bearer ${this.config.authToken}`);
|
|
214
|
-
const
|
|
255
|
+
const v = w(c, this.config);
|
|
256
|
+
if (v === null)
|
|
257
|
+
throw await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
258
|
+
toolId: "tts",
|
|
259
|
+
backend: this.config.provider || "server",
|
|
260
|
+
operation: "fetch-synthesized-audio-asset",
|
|
261
|
+
duration: Date.now() - y,
|
|
262
|
+
errorType: "TTSAssetInvalidUrl",
|
|
263
|
+
message: "TTS asset URL rejected (non-http(s) or malformed)"
|
|
264
|
+
}), new Error("TTS asset URL rejected (non-http(s) or malformed)");
|
|
265
|
+
const I = k(v, this.config) ? f : A(f), m = await (async () => {
|
|
215
266
|
try {
|
|
216
|
-
return await fetch(
|
|
217
|
-
headers:
|
|
218
|
-
signal:
|
|
267
|
+
return await fetch(v.toString(), {
|
|
268
|
+
headers: I,
|
|
269
|
+
signal: t,
|
|
270
|
+
redirect: "error"
|
|
219
271
|
});
|
|
220
272
|
} catch (g) {
|
|
221
273
|
throw await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
222
274
|
toolId: "tts",
|
|
223
275
|
backend: this.config.provider || "server",
|
|
224
276
|
operation: "fetch-synthesized-audio-asset",
|
|
225
|
-
duration: Date.now() -
|
|
277
|
+
duration: Date.now() - y,
|
|
226
278
|
errorType: "TTSAssetNetworkError",
|
|
227
279
|
message: g instanceof Error ? g.message : String(g)
|
|
228
280
|
}), g;
|
|
@@ -233,19 +285,19 @@ var b = (t) => {
|
|
|
233
285
|
toolId: "tts",
|
|
234
286
|
backend: this.config.provider || "server",
|
|
235
287
|
operation: "fetch-synthesized-audio-asset",
|
|
236
|
-
duration: Date.now() -
|
|
288
|
+
duration: Date.now() - y,
|
|
237
289
|
statusCode: m.status,
|
|
238
290
|
errorType: "TTSAssetFetchError",
|
|
239
291
|
message: `Failed to download synthesized audio (${m.status})`
|
|
240
292
|
}), new Error(`Failed to download synthesized audio (${m.status})`);
|
|
241
|
-
|
|
293
|
+
h = await m.blob(), await this.emitTelemetry("pie-tool-backend-call-success", {
|
|
242
294
|
toolId: "tts",
|
|
243
295
|
backend: this.config.provider || "server",
|
|
244
296
|
operation: "fetch-synthesized-audio-asset",
|
|
245
|
-
duration: Date.now() -
|
|
297
|
+
duration: Date.now() - y
|
|
246
298
|
});
|
|
247
299
|
}
|
|
248
|
-
const u = URL.createObjectURL(
|
|
300
|
+
const u = URL.createObjectURL(h), p = this.parseSpeechMarks(n.speechMarks);
|
|
249
301
|
return await this.emitTelemetry("pie-tool-backend-call-success", {
|
|
250
302
|
toolId: "tts",
|
|
251
303
|
backend: this.config.provider || "server",
|
|
@@ -253,20 +305,21 @@ var b = (t) => {
|
|
|
253
305
|
duration: Date.now() - i
|
|
254
306
|
}), {
|
|
255
307
|
audioUrl: u,
|
|
256
|
-
wordTimings:
|
|
308
|
+
wordTimings: p
|
|
257
309
|
};
|
|
258
310
|
}
|
|
259
|
-
base64ToBlob(
|
|
260
|
-
const r = atob(
|
|
261
|
-
for (let
|
|
262
|
-
|
|
311
|
+
base64ToBlob(e, t) {
|
|
312
|
+
const r = atob(e), i = new Array(r.length);
|
|
313
|
+
for (let s = 0; s < r.length; s++) i[s] = r.charCodeAt(s);
|
|
314
|
+
const o = new Uint8Array(i);
|
|
315
|
+
return new Blob([o], { type: t });
|
|
263
316
|
}
|
|
264
|
-
parseSpeechMarks(
|
|
265
|
-
return
|
|
266
|
-
time:
|
|
317
|
+
parseSpeechMarks(e) {
|
|
318
|
+
return e.filter((t) => t.type === "word").map((t, r) => ({
|
|
319
|
+
time: t.time,
|
|
267
320
|
wordIndex: r,
|
|
268
|
-
charIndex:
|
|
269
|
-
length:
|
|
321
|
+
charIndex: t.start,
|
|
322
|
+
length: t.end - t.start
|
|
270
323
|
}));
|
|
271
324
|
}
|
|
272
325
|
startWordHighlighting() {
|
|
@@ -279,17 +332,17 @@ var b = (t) => {
|
|
|
279
332
|
return;
|
|
280
333
|
}
|
|
281
334
|
console.log("[ServerTTSProvider] Starting word highlighting with", this.wordTimings.length, "word timings"), console.log("[ServerTTSProvider] Playback rate:", this.currentAudio.playbackRate), console.log("[ServerTTSProvider] First 3 timings:", this.wordTimings.slice(0, 3));
|
|
282
|
-
let
|
|
335
|
+
let e = -1;
|
|
283
336
|
this.highlightInterval = window.setInterval(() => {
|
|
284
337
|
if (!this.currentAudio) {
|
|
285
338
|
this.stopWordHighlighting();
|
|
286
339
|
return;
|
|
287
340
|
}
|
|
288
|
-
const
|
|
341
|
+
const t = this.currentAudio.currentTime * 1e3;
|
|
289
342
|
for (let r = 0; r < this.wordTimings.length; r++) {
|
|
290
343
|
const i = this.wordTimings[r];
|
|
291
|
-
if (
|
|
292
|
-
this.onWordBoundary && (console.log("[ServerTTSProvider] Highlighting word at charIndex:", i.charIndex, "length:", i.length, "time:", i.time, "currentTime:",
|
|
344
|
+
if (t >= i.time && r > e) {
|
|
345
|
+
this.onWordBoundary && (console.log("[ServerTTSProvider] Highlighting word at charIndex:", i.charIndex, "length:", i.length, "time:", i.time, "currentTime:", t), this.onWordBoundary("", i.charIndex, i.length)), e = r;
|
|
293
346
|
break;
|
|
294
347
|
}
|
|
295
348
|
}
|
|
@@ -313,61 +366,63 @@ var b = (t) => {
|
|
|
313
366
|
isPaused() {
|
|
314
367
|
return this.pausedState;
|
|
315
368
|
}
|
|
316
|
-
updateSettings(
|
|
317
|
-
|
|
369
|
+
updateSettings(e) {
|
|
370
|
+
e.rate !== void 0 && (this.config.rate = e.rate, this.currentAudio && (this.currentAudio.playbackRate = Math.max(0.25, Math.min(4, e.rate)))), e.pitch !== void 0 && (this.config.pitch = e.pitch), e.voice !== void 0 && (this.config.voice = e.voice);
|
|
318
371
|
}
|
|
319
|
-
},
|
|
372
|
+
}, L = class {
|
|
320
373
|
constructor() {
|
|
321
|
-
|
|
374
|
+
l(this, "providerId", "server-tts"), l(this, "providerName", "Server TTS"), l(this, "version", "1.0.0"), l(this, "config", null), l(this, "adapter", null), l(this, "telemetryReporter", void 0);
|
|
322
375
|
}
|
|
323
|
-
async emitTelemetry(
|
|
376
|
+
async emitTelemetry(e, t) {
|
|
324
377
|
try {
|
|
325
|
-
await this.telemetryReporter?.(
|
|
378
|
+
await this.telemetryReporter?.(e, t);
|
|
326
379
|
} catch (r) {
|
|
327
380
|
console.warn("[ServerTTSProvider] telemetry callback failed:", r);
|
|
328
381
|
}
|
|
329
382
|
}
|
|
330
|
-
async initialize(
|
|
331
|
-
const
|
|
332
|
-
if (!
|
|
333
|
-
|
|
334
|
-
|
|
383
|
+
async initialize(e) {
|
|
384
|
+
const t = e;
|
|
385
|
+
if (!t.apiEndpoint) throw new Error("apiEndpoint is required for ServerTTSProvider");
|
|
386
|
+
this.config = t, this.telemetryReporter = R(t);
|
|
387
|
+
const r = b(t);
|
|
388
|
+
if (this.adapter = x[r], t.validateEndpoint) {
|
|
389
|
+
const i = Date.now();
|
|
335
390
|
if (await this.emitTelemetry("pie-tool-backend-call-start", {
|
|
336
391
|
toolId: "tts",
|
|
337
|
-
backend:
|
|
392
|
+
backend: t.provider || "server",
|
|
338
393
|
operation: "validate-endpoint"
|
|
339
394
|
}), !await this.testAPIAvailability())
|
|
340
395
|
throw await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
341
396
|
toolId: "tts",
|
|
342
|
-
backend:
|
|
397
|
+
backend: t.provider || "server",
|
|
343
398
|
operation: "validate-endpoint",
|
|
344
|
-
duration: Date.now() -
|
|
399
|
+
duration: Date.now() - i,
|
|
345
400
|
errorType: "TTSEndpointValidationError",
|
|
346
|
-
message: `Server TTS API not available at ${
|
|
347
|
-
}), new Error(`Server TTS API not available at ${
|
|
401
|
+
message: `Server TTS API not available at ${t.apiEndpoint}`
|
|
402
|
+
}), new Error(`Server TTS API not available at ${t.apiEndpoint}`);
|
|
348
403
|
await this.emitTelemetry("pie-tool-backend-call-success", {
|
|
349
404
|
toolId: "tts",
|
|
350
|
-
backend:
|
|
405
|
+
backend: t.provider || "server",
|
|
351
406
|
operation: "validate-endpoint",
|
|
352
|
-
duration: Date.now() -
|
|
407
|
+
duration: Date.now() - i
|
|
353
408
|
});
|
|
354
409
|
}
|
|
355
|
-
return new
|
|
410
|
+
return new z(t, this.adapter);
|
|
356
411
|
}
|
|
357
412
|
async testAPIAvailability() {
|
|
358
413
|
if (!this.config || !this.adapter) return !1;
|
|
359
414
|
try {
|
|
360
|
-
const
|
|
361
|
-
this.config.authToken && (
|
|
362
|
-
const
|
|
415
|
+
const e = { ...this.config.headers };
|
|
416
|
+
this.config.authToken && (e.Authorization = `Bearer ${this.config.authToken}`);
|
|
417
|
+
const t = new AbortController(), r = setTimeout(() => t.abort(), 5e3), i = U(this.config, this.adapter.id);
|
|
363
418
|
if (i === "none")
|
|
364
419
|
return clearTimeout(r), !0;
|
|
365
|
-
const o = i === "voices" ?
|
|
420
|
+
const o = i === "voices" ? E(this.config) : this.adapter.resolveSynthesisUrl(this.config), s = i === "voices" ? "GET" : "OPTIONS";
|
|
366
421
|
try {
|
|
367
422
|
const a = await fetch(o, {
|
|
368
423
|
method: s,
|
|
369
|
-
headers:
|
|
370
|
-
signal:
|
|
424
|
+
headers: e,
|
|
425
|
+
signal: t.signal
|
|
371
426
|
});
|
|
372
427
|
return clearTimeout(r), a.ok || a.status === 405;
|
|
373
428
|
} catch {
|
|
@@ -377,8 +432,8 @@ var b = (t) => {
|
|
|
377
432
|
return !1;
|
|
378
433
|
}
|
|
379
434
|
}
|
|
380
|
-
supportsFeature(
|
|
381
|
-
switch (
|
|
435
|
+
supportsFeature(e) {
|
|
436
|
+
switch (e) {
|
|
382
437
|
case "pause":
|
|
383
438
|
case "resume":
|
|
384
439
|
case "wordBoundary":
|
|
@@ -399,7 +454,7 @@ var b = (t) => {
|
|
|
399
454
|
supportsVoiceSelection: !0,
|
|
400
455
|
supportsRateControl: !0,
|
|
401
456
|
supportsPitchControl: !1,
|
|
402
|
-
maxTextLength:
|
|
457
|
+
maxTextLength: M[this.config ? b(this.config) : "pie"]
|
|
403
458
|
};
|
|
404
459
|
}
|
|
405
460
|
destroy() {
|
|
@@ -407,5 +462,5 @@ var b = (t) => {
|
|
|
407
462
|
}
|
|
408
463
|
};
|
|
409
464
|
export {
|
|
410
|
-
|
|
465
|
+
L as ServerTTSProvider
|
|
411
466
|
};
|
|
@@ -41,7 +41,8 @@ var n = class {
|
|
|
41
41
|
try {
|
|
42
42
|
const t = await fetch(e.proxyEndpoint);
|
|
43
43
|
if (!t.ok) throw new Error(`Proxy endpoint returned ${t.status}`);
|
|
44
|
-
|
|
44
|
+
const r = await t.json();
|
|
45
|
+
this.apiKey = r.apiKey, await this.emitTelemetry("pie-tool-backend-call-success", {
|
|
45
46
|
toolId: "calculator",
|
|
46
47
|
backend: "desmos",
|
|
47
48
|
operation: "proxy-auth-fetch",
|
|
@@ -179,6 +180,17 @@ Recommended: Use proxyEndpoint for production, apiKey for development only.`);
|
|
|
179
180
|
resize() {
|
|
180
181
|
this.calculator.resize && this.calculator.resize();
|
|
181
182
|
}
|
|
183
|
+
focus() {
|
|
184
|
+
try {
|
|
185
|
+
if (this.type === "graphing" && typeof this.calculator?.focusFirstExpression == "function") {
|
|
186
|
+
this.calculator.focusFirstExpression();
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
this.container.querySelector('.dcg-mq-editable-field[tabindex="0"], textarea, [contenteditable="true"], [tabindex]:not([tabindex="-1"])')?.focus();
|
|
190
|
+
} catch (e) {
|
|
191
|
+
console.warn("[DesmosCalculator] focus() failed:", e);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
182
194
|
exportState() {
|
|
183
195
|
let e = {};
|
|
184
196
|
return this.type === "graphing" && this.calculator.getState && (e = this.calculator.getState()), {
|