@pie-players/pie-section-player 0.3.44 → 0.3.46
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 +11 -23
- package/dist/chunks/dist-24a90544.js +198 -173
- package/dist/chunks/{dist-DIBQdekL-ec6db34a.js → dist-DfQrc9XY-6d8e61c6.js} +175 -150
- package/dist/chunks/{dist-rF11IR1B-adc4857f.js → dist-Dns3leWh-4f7af4d3.js} +1 -1
- package/dist/chunks/dist-c4148994.js +1 -1
- package/dist/chunks/sre-0162a7a9.js +17534 -0
- package/dist/chunks/sre-CXN7ed6H-7db47d5d.js +17532 -0
- package/dist/chunks/tool-annotation-toolbar-db5bfbec.js +5309 -2122
- package/dist/components/shared/section-player-host-runtime.d.ts +2 -11
- package/dist/contracts/layout-contract.d.ts +2 -2
- package/dist/contracts/public-events.d.ts +8 -15
- package/dist/pie-section-player.js +39445 -16746
- package/package.json +10 -10
- /package/dist/chunks/{defineProperty-aab5a8e0.js → defineProperty-8fd4b6d7.js} +0 -0
- /package/dist/chunks/{defineProperty-CyepwRr5-3800a70a.js → defineProperty-Dt7ri80W-76aeaed7.js} +0 -0
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
function
|
|
1
|
+
import { t as h } from "./defineProperty-Dt7ri80W-76aeaed7.js";
|
|
2
|
+
function T(e, t) {
|
|
3
3
|
if (typeof e != "string" || e.length === 0) return null;
|
|
4
4
|
try {
|
|
5
|
-
const
|
|
6
|
-
return
|
|
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
7
|
} catch {
|
|
8
8
|
return null;
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
-
function
|
|
12
|
-
const
|
|
11
|
+
function A(e, t) {
|
|
12
|
+
const r = Array.isArray(t.assetOrigins) ? t.assetOrigins.filter((i) => typeof i == "string" && i.length > 0).map((i) => {
|
|
13
13
|
try {
|
|
14
|
-
return new URL(
|
|
14
|
+
return new URL(i).origin;
|
|
15
15
|
} catch {
|
|
16
|
-
return
|
|
16
|
+
return i;
|
|
17
17
|
}
|
|
18
18
|
}) : [];
|
|
19
|
-
if (
|
|
19
|
+
if (r.length === 0) {
|
|
20
20
|
if (typeof t.apiEndpoint == "string" && /^https?:\/\//i.test(t.apiEndpoint)) try {
|
|
21
21
|
return new URL(t.apiEndpoint).origin === e.origin;
|
|
22
22
|
} catch {
|
|
@@ -24,79 +24,83 @@ function k(e, t) {
|
|
|
24
24
|
}
|
|
25
25
|
return typeof window < "u" && typeof window.location?.origin == "string" && window.location.origin === e.origin;
|
|
26
26
|
}
|
|
27
|
-
return
|
|
27
|
+
return r.includes(e.origin);
|
|
28
28
|
}
|
|
29
|
-
function
|
|
29
|
+
function R(e) {
|
|
30
30
|
const t = {};
|
|
31
|
-
for (const [
|
|
32
|
-
const o =
|
|
33
|
-
o === "authorization" || o === "proxy-authorization" || o === "cookie" || o.startsWith("x-auth-") || (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
34
|
}
|
|
35
35
|
return t;
|
|
36
36
|
}
|
|
37
|
-
var
|
|
37
|
+
var I = (e) => {
|
|
38
38
|
const t = (e.providerOptions && typeof e.providerOptions == "object" ? e.providerOptions : {}).__pieTelemetry;
|
|
39
39
|
return typeof t == "function" ? t : void 0;
|
|
40
40
|
}, E = {
|
|
41
41
|
pie: 3e3,
|
|
42
42
|
custom: 3e3
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
}, P = /* @__PURE__ */ new Set(["polly", "google"]), U = (e) => {
|
|
44
|
+
if (!e || b(e) !== "pie") return !1;
|
|
45
|
+
const t = (e.provider || "polly").toLowerCase();
|
|
46
|
+
return P.has(t);
|
|
47
|
+
}, S = (e) => e.replace(/\/+$/, ""), z = (e) => {
|
|
48
|
+
const t = S(e.apiEndpoint), r = (e.provider || "").toLowerCase();
|
|
49
|
+
return r === "polly" || r === "google" ? `${t}/${r}/voices` : `${t}/voices`;
|
|
50
|
+
}, b = (e) => e.transportMode === "custom" ? "custom" : e.transportMode === "pie" ? "pie" : e.provider === "custom" ? "custom" : "pie", k = (e, t) => e.endpointMode ? e.endpointMode : t === "custom" ? "rootPost" : "synthesizePath", M = (e, t) => e.endpointValidationMode ? e.endpointValidationMode : t === "custom" ? "none" : "voices", O = (e) => {
|
|
47
51
|
const t = e.providerOptions || {};
|
|
48
52
|
if (typeof t.speedRate == "string") return t.speedRate;
|
|
49
|
-
const
|
|
50
|
-
return !Number.isFinite(
|
|
51
|
-
},
|
|
53
|
+
const r = Number(e.rate ?? 1);
|
|
54
|
+
return !Number.isFinite(r) || r <= 0.95 ? "slow" : r >= 1.5 ? "fast" : "medium";
|
|
55
|
+
}, C = (e) => {
|
|
52
56
|
const t = [];
|
|
53
|
-
let
|
|
54
|
-
const
|
|
57
|
+
let r = 0;
|
|
58
|
+
const i = e.split(`
|
|
55
59
|
`).map((o) => o.trim()).filter(Boolean);
|
|
56
|
-
for (const o of
|
|
57
|
-
const s = JSON.parse(o), a = typeof s.type == "string" ? s.type : "word",
|
|
58
|
-
|
|
59
|
-
time:
|
|
60
|
+
for (const o of i) try {
|
|
61
|
+
const s = JSON.parse(o), a = typeof s.type == "string" ? s.type : "word", n = typeof s.time == "number" && Number.isFinite(s.time) ? s.time : 0, l = typeof s.value == "string" ? s.value : "", d = typeof s.start == "number" && Number.isFinite(s.start) ? s.start : null, u = typeof s.end == "number" && Number.isFinite(s.end) ? s.end : null, g = d ?? r, c = u ?? g + Math.max(1, l.length || String(s.value || "").length);
|
|
62
|
+
r = Math.max(c + 1, r), t.push({
|
|
63
|
+
time: n,
|
|
60
64
|
type: a,
|
|
61
|
-
start:
|
|
62
|
-
end:
|
|
63
|
-
value:
|
|
65
|
+
start: g,
|
|
66
|
+
end: c,
|
|
67
|
+
value: l
|
|
64
68
|
});
|
|
65
69
|
} catch {
|
|
66
70
|
}
|
|
67
71
|
return t;
|
|
68
|
-
},
|
|
72
|
+
}, L = (e) => {
|
|
69
73
|
if (!Array.isArray(e)) return [];
|
|
70
74
|
const t = [];
|
|
71
|
-
let
|
|
72
|
-
for (const
|
|
73
|
-
if (!
|
|
74
|
-
const o = typeof
|
|
75
|
-
|
|
75
|
+
let r = 0;
|
|
76
|
+
for (const i of e) {
|
|
77
|
+
if (!i || typeof i != "object") continue;
|
|
78
|
+
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 : "", n = typeof i.start == "number" && Number.isFinite(i.start) ? i.start : null, l = typeof i.end == "number" && Number.isFinite(i.end) ? i.end : null, d = n ?? r, u = l ?? d + Math.max(1, a.length || 1);
|
|
79
|
+
r = Math.max(r, u + 1), t.push({
|
|
76
80
|
time: s,
|
|
77
81
|
type: o,
|
|
78
|
-
start:
|
|
82
|
+
start: d,
|
|
79
83
|
end: u,
|
|
80
84
|
value: a
|
|
81
85
|
});
|
|
82
86
|
}
|
|
83
|
-
return t.sort((
|
|
84
|
-
},
|
|
87
|
+
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);
|
|
88
|
+
}, B = {
|
|
85
89
|
pie: {
|
|
86
90
|
id: "pie",
|
|
87
91
|
resolveSynthesisUrl: (e) => {
|
|
88
|
-
const t =
|
|
89
|
-
return t === "rootPost" ?
|
|
92
|
+
const t = k(e, "pie"), r = S(e.apiEndpoint);
|
|
93
|
+
return t === "rootPost" ? r : `${r}/synthesize`;
|
|
90
94
|
},
|
|
91
95
|
buildRequestBody: (e, t) => {
|
|
92
|
-
const
|
|
96
|
+
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((n) => n === "word" || n === "sentence" || n === "ssml") : void 0;
|
|
93
97
|
return {
|
|
94
98
|
text: e,
|
|
95
99
|
provider: t.provider || "polly",
|
|
96
100
|
voice: t.voice,
|
|
97
101
|
language: t.language,
|
|
98
102
|
rate: t.rate,
|
|
99
|
-
engine:
|
|
103
|
+
engine: i,
|
|
100
104
|
sampleRate: o,
|
|
101
105
|
format: s,
|
|
102
106
|
speechMarkTypes: a,
|
|
@@ -118,85 +122,81 @@ var R = (e) => {
|
|
|
118
122
|
custom: {
|
|
119
123
|
id: "custom",
|
|
120
124
|
resolveSynthesisUrl: (e) => {
|
|
121
|
-
const t =
|
|
122
|
-
return t === "synthesizePath" ? `${
|
|
125
|
+
const t = k(e, "custom"), r = S(e.apiEndpoint);
|
|
126
|
+
return t === "synthesizePath" ? `${r}/synthesize` : r;
|
|
123
127
|
},
|
|
124
128
|
buildRequestBody: (e, t) => {
|
|
125
|
-
const
|
|
129
|
+
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;
|
|
126
130
|
return {
|
|
127
131
|
text: e,
|
|
128
|
-
speedRate:
|
|
129
|
-
lang_id:
|
|
132
|
+
speedRate: O(t),
|
|
133
|
+
lang_id: i,
|
|
130
134
|
cache: o
|
|
131
135
|
};
|
|
132
136
|
},
|
|
133
|
-
parseResponse: async (e, t,
|
|
137
|
+
parseResponse: async (e, t, r, i) => {
|
|
134
138
|
const o = await e.json(), s = {};
|
|
135
|
-
if (t.includeAuthOnAssetFetch) for (const [
|
|
139
|
+
if (t.includeAuthOnAssetFetch) for (const [d, u] of Object.entries(r)) d.toLowerCase() === "authorization" && (s[d] = u);
|
|
136
140
|
let a = [];
|
|
137
|
-
const
|
|
138
|
-
if (
|
|
141
|
+
const n = L(o.speechMarks);
|
|
142
|
+
if (n.length > 0) a = n;
|
|
139
143
|
else if (typeof o.word == "string" && o.word.length > 0) {
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
142
|
-
const u =
|
|
144
|
+
const d = T(o.word, t);
|
|
145
|
+
if (d !== null) {
|
|
146
|
+
const u = A(d, t) ? s : R(s), g = await fetch(d.toString(), {
|
|
143
147
|
headers: u,
|
|
144
|
-
signal:
|
|
148
|
+
signal: i,
|
|
145
149
|
redirect: "error"
|
|
146
150
|
});
|
|
147
|
-
|
|
151
|
+
g.ok && (a = C(await g.text()));
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
|
-
const
|
|
151
|
-
if (
|
|
154
|
+
const l = T(o.audioContent, t);
|
|
155
|
+
if (l === null) throw new Error("TTS server returned an invalid audio URL");
|
|
152
156
|
return {
|
|
153
157
|
audio: {
|
|
154
158
|
kind: "url",
|
|
155
|
-
url:
|
|
159
|
+
url: l.toString()
|
|
156
160
|
},
|
|
157
161
|
speechMarks: a
|
|
158
162
|
};
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
|
-
},
|
|
165
|
+
}, x = class {
|
|
162
166
|
constructor(e, t) {
|
|
163
|
-
|
|
167
|
+
h(this, "config", void 0), h(this, "adapter", void 0), h(this, "currentAudio", null), h(this, "pausedState", !1), h(this, "wordTimings", []), h(this, "highlightInterval", null), h(this, "intentionallyStopped", !1), h(this, "activeSynthesisController", null), h(this, "synthesisRunId", 0), h(this, "telemetryReporter", void 0), h(this, "onWordBoundary", void 0), this.config = e, this.adapter = t, this.telemetryReporter = I(e);
|
|
164
168
|
}
|
|
165
169
|
async emitTelemetry(e, t) {
|
|
166
170
|
try {
|
|
167
171
|
await this.telemetryReporter?.(e, t);
|
|
168
|
-
} catch (
|
|
169
|
-
console.warn("[ServerTTSProvider] telemetry callback failed:",
|
|
172
|
+
} catch (r) {
|
|
173
|
+
console.warn("[ServerTTSProvider] telemetry callback failed:", r);
|
|
170
174
|
}
|
|
171
175
|
}
|
|
172
176
|
async speak(e) {
|
|
173
177
|
this.stop(), this.intentionallyStopped = !1;
|
|
174
|
-
const t = ++this.synthesisRunId,
|
|
175
|
-
this.activeSynthesisController =
|
|
176
|
-
const { audioUrl:
|
|
178
|
+
const t = ++this.synthesisRunId, r = new AbortController();
|
|
179
|
+
this.activeSynthesisController = r;
|
|
180
|
+
const { audioUrl: i, wordTimings: o } = await this.synthesizeSpeech(e, r.signal, t);
|
|
177
181
|
if (t !== this.synthesisRunId) {
|
|
178
|
-
URL.revokeObjectURL(
|
|
182
|
+
URL.revokeObjectURL(i);
|
|
179
183
|
return;
|
|
180
184
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
time: a.time / s
|
|
185
|
-
})), new Promise((a, h) => {
|
|
186
|
-
const n = new Audio(r);
|
|
187
|
-
this.currentAudio = n, this.config.rate && (n.playbackRate = Math.max(0.25, Math.min(4, this.config.rate))), this.config.volume !== void 0 && (n.volume = Math.max(0, Math.min(1, this.config.volume))), n.onplay = () => {
|
|
185
|
+
return this.wordTimings = o, new Promise((s, a) => {
|
|
186
|
+
const n = new Audio(i);
|
|
187
|
+
this.currentAudio = n, this.config.volume !== void 0 && (n.volume = Math.max(0, Math.min(1, this.config.volume))), n.onplay = () => {
|
|
188
188
|
this.pausedState = !1, this.onWordBoundary && this.wordTimings.length > 0 && this.startWordHighlighting();
|
|
189
189
|
}, n.onended = () => {
|
|
190
|
-
this.stopWordHighlighting(), URL.revokeObjectURL(
|
|
191
|
-
}, n.onerror = (
|
|
192
|
-
this.stopWordHighlighting(), URL.revokeObjectURL(
|
|
190
|
+
this.stopWordHighlighting(), URL.revokeObjectURL(i), this.currentAudio = null, this.wordTimings = [], s();
|
|
191
|
+
}, n.onerror = (l) => {
|
|
192
|
+
this.stopWordHighlighting(), URL.revokeObjectURL(i), this.currentAudio = null, this.wordTimings = [], this.intentionallyStopped ? s() : a(/* @__PURE__ */ new Error("Failed to play audio from server"));
|
|
193
193
|
}, n.onpause = () => {
|
|
194
194
|
this.stopWordHighlighting(), this.pausedState = !0;
|
|
195
|
-
}, n.play().catch(
|
|
195
|
+
}, n.play().catch(a);
|
|
196
196
|
});
|
|
197
197
|
}
|
|
198
|
-
async synthesizeSpeech(e, t,
|
|
199
|
-
const
|
|
198
|
+
async synthesizeSpeech(e, t, r) {
|
|
199
|
+
const i = Date.now();
|
|
200
200
|
await this.emitTelemetry("pie-tool-backend-call-start", {
|
|
201
201
|
toolId: "tts",
|
|
202
202
|
backend: this.config.provider || "server",
|
|
@@ -207,7 +207,7 @@ var R = (e) => {
|
|
|
207
207
|
...this.config.headers
|
|
208
208
|
};
|
|
209
209
|
this.config.authToken && (o.Authorization = `Bearer ${this.config.authToken}`);
|
|
210
|
-
const s = this.adapter.resolveSynthesisUrl(this.config), a = this.adapter.buildRequestBody(e, this.config),
|
|
210
|
+
const s = this.adapter.resolveSynthesisUrl(this.config), a = this.adapter.buildRequestBody(e, this.config), n = await (async () => {
|
|
211
211
|
try {
|
|
212
212
|
return await fetch(s, {
|
|
213
213
|
method: "POST",
|
|
@@ -215,108 +215,131 @@ var R = (e) => {
|
|
|
215
215
|
body: JSON.stringify(a),
|
|
216
216
|
signal: t
|
|
217
217
|
});
|
|
218
|
-
} catch (
|
|
218
|
+
} catch (c) {
|
|
219
219
|
throw await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
220
220
|
toolId: "tts",
|
|
221
221
|
backend: this.config.provider || "server",
|
|
222
222
|
operation: "synthesize-speech",
|
|
223
|
-
duration: Date.now() -
|
|
223
|
+
duration: Date.now() - i,
|
|
224
224
|
errorType: "TTSBackendNetworkError",
|
|
225
|
-
message:
|
|
226
|
-
}),
|
|
225
|
+
message: c instanceof Error ? c.message : String(c)
|
|
226
|
+
}), c;
|
|
227
227
|
}
|
|
228
228
|
})();
|
|
229
|
-
if (!
|
|
230
|
-
const
|
|
231
|
-
|
|
229
|
+
if (!n.ok) {
|
|
230
|
+
const c = await n.text().catch(() => "");
|
|
231
|
+
let p = {};
|
|
232
|
+
if (c) try {
|
|
233
|
+
p = JSON.parse(c);
|
|
234
|
+
} catch (f) {
|
|
235
|
+
console.warn("[ServerTTSProvider] non-OK response body was not JSON", {
|
|
236
|
+
status: n.status,
|
|
237
|
+
url: s,
|
|
238
|
+
rawBodyPreview: c.slice(0, 500),
|
|
239
|
+
parseError: f instanceof Error ? f.message : String(f)
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
const y = typeof p.message == "string" && p.message || (typeof p.error?.message == "string" ? p.error.message : void 0) || `Server returned ${n.status}`;
|
|
243
|
+
await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
232
244
|
toolId: "tts",
|
|
233
245
|
backend: this.config.provider || "server",
|
|
234
246
|
operation: "synthesize-speech",
|
|
235
|
-
duration: Date.now() -
|
|
236
|
-
statusCode:
|
|
247
|
+
duration: Date.now() - i,
|
|
248
|
+
statusCode: n.status,
|
|
237
249
|
errorType: "TTSBackendRequestError",
|
|
238
|
-
message:
|
|
239
|
-
})
|
|
250
|
+
message: y
|
|
251
|
+
});
|
|
252
|
+
const m = e.replace(/\s+/g, " ").trim().slice(0, 120);
|
|
253
|
+
throw console.error("[ServerTTSProvider] synthesize request failed", {
|
|
254
|
+
status: n.status,
|
|
255
|
+
url: s,
|
|
256
|
+
backend: this.config.provider || "server",
|
|
257
|
+
message: y,
|
|
258
|
+
responseBody: p,
|
|
259
|
+
textLength: e.length,
|
|
260
|
+
textPreview: m.length < e.length ? `${m}…` : m
|
|
261
|
+
}), new Error(y);
|
|
240
262
|
}
|
|
241
|
-
const
|
|
242
|
-
if (
|
|
243
|
-
let
|
|
244
|
-
if (
|
|
263
|
+
const l = await this.adapter.parseResponse(n, this.config, o, t);
|
|
264
|
+
if (r !== this.synthesisRunId || t.aborted) throw new Error("Synthesis superseded by a newer request");
|
|
265
|
+
let d;
|
|
266
|
+
if (l.audio.kind === "base64") d = this.base64ToBlob(l.audio.data, l.audio.contentType);
|
|
245
267
|
else {
|
|
246
|
-
const
|
|
268
|
+
const c = l.audio.url, p = Date.now();
|
|
247
269
|
await this.emitTelemetry("pie-tool-backend-call-start", {
|
|
248
270
|
toolId: "tts",
|
|
249
271
|
backend: this.config.provider || "server",
|
|
250
272
|
operation: "fetch-synthesized-audio-asset"
|
|
251
273
|
});
|
|
252
|
-
const
|
|
253
|
-
this.config.includeAuthOnAssetFetch && this.config.authToken && (
|
|
254
|
-
const
|
|
255
|
-
if (
|
|
274
|
+
const y = {};
|
|
275
|
+
this.config.includeAuthOnAssetFetch && this.config.authToken && (y.Authorization = `Bearer ${this.config.authToken}`);
|
|
276
|
+
const m = T(c, this.config);
|
|
277
|
+
if (m === null) throw await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
256
278
|
toolId: "tts",
|
|
257
279
|
backend: this.config.provider || "server",
|
|
258
280
|
operation: "fetch-synthesized-audio-asset",
|
|
259
|
-
duration: Date.now() -
|
|
281
|
+
duration: Date.now() - p,
|
|
260
282
|
errorType: "TTSAssetInvalidUrl",
|
|
261
283
|
message: "TTS asset URL rejected (non-http(s) or malformed)"
|
|
262
284
|
}), /* @__PURE__ */ new Error("TTS asset URL rejected (non-http(s) or malformed)");
|
|
263
|
-
const
|
|
285
|
+
const f = A(m, this.config) ? y : R(y), v = await (async () => {
|
|
264
286
|
try {
|
|
265
|
-
return await fetch(
|
|
266
|
-
headers:
|
|
287
|
+
return await fetch(m.toString(), {
|
|
288
|
+
headers: f,
|
|
267
289
|
signal: t,
|
|
268
290
|
redirect: "error"
|
|
269
291
|
});
|
|
270
|
-
} catch (
|
|
292
|
+
} catch (w) {
|
|
271
293
|
throw await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
272
294
|
toolId: "tts",
|
|
273
295
|
backend: this.config.provider || "server",
|
|
274
296
|
operation: "fetch-synthesized-audio-asset",
|
|
275
|
-
duration: Date.now() -
|
|
297
|
+
duration: Date.now() - p,
|
|
276
298
|
errorType: "TTSAssetNetworkError",
|
|
277
|
-
message:
|
|
278
|
-
}),
|
|
299
|
+
message: w instanceof Error ? w.message : String(w)
|
|
300
|
+
}), w;
|
|
279
301
|
}
|
|
280
302
|
})();
|
|
281
|
-
if (!
|
|
303
|
+
if (!v.ok) throw await this.emitTelemetry("pie-tool-backend-call-error", {
|
|
282
304
|
toolId: "tts",
|
|
283
305
|
backend: this.config.provider || "server",
|
|
284
306
|
operation: "fetch-synthesized-audio-asset",
|
|
285
|
-
duration: Date.now() -
|
|
286
|
-
statusCode:
|
|
307
|
+
duration: Date.now() - p,
|
|
308
|
+
statusCode: v.status,
|
|
287
309
|
errorType: "TTSAssetFetchError",
|
|
288
|
-
message: `Failed to download synthesized audio (${
|
|
289
|
-
}), /* @__PURE__ */ new Error(`Failed to download synthesized audio (${
|
|
290
|
-
|
|
310
|
+
message: `Failed to download synthesized audio (${v.status})`
|
|
311
|
+
}), /* @__PURE__ */ new Error(`Failed to download synthesized audio (${v.status})`);
|
|
312
|
+
d = await v.blob(), await this.emitTelemetry("pie-tool-backend-call-success", {
|
|
291
313
|
toolId: "tts",
|
|
292
314
|
backend: this.config.provider || "server",
|
|
293
315
|
operation: "fetch-synthesized-audio-asset",
|
|
294
|
-
duration: Date.now() -
|
|
316
|
+
duration: Date.now() - p
|
|
295
317
|
});
|
|
296
318
|
}
|
|
297
|
-
const u = URL.createObjectURL(
|
|
319
|
+
const u = URL.createObjectURL(d), g = this.parseSpeechMarks(l.speechMarks);
|
|
298
320
|
return await this.emitTelemetry("pie-tool-backend-call-success", {
|
|
299
321
|
toolId: "tts",
|
|
300
322
|
backend: this.config.provider || "server",
|
|
301
323
|
operation: "synthesize-speech",
|
|
302
|
-
duration: Date.now() -
|
|
324
|
+
duration: Date.now() - i
|
|
303
325
|
}), {
|
|
304
326
|
audioUrl: u,
|
|
305
|
-
wordTimings:
|
|
327
|
+
wordTimings: g
|
|
306
328
|
};
|
|
307
329
|
}
|
|
308
330
|
base64ToBlob(e, t) {
|
|
309
|
-
const
|
|
310
|
-
for (let s = 0; s <
|
|
311
|
-
const o = new Uint8Array(
|
|
331
|
+
const r = atob(e), i = new Array(r.length);
|
|
332
|
+
for (let s = 0; s < r.length; s++) i[s] = r.charCodeAt(s);
|
|
333
|
+
const o = new Uint8Array(i);
|
|
312
334
|
return new Blob([o], { type: t });
|
|
313
335
|
}
|
|
314
336
|
parseSpeechMarks(e) {
|
|
315
|
-
return e.filter((t) => t.type === "word").map((t,
|
|
337
|
+
return e.filter((t) => t.type === "word").map((t, r) => ({
|
|
316
338
|
time: t.time,
|
|
317
|
-
wordIndex:
|
|
339
|
+
wordIndex: r,
|
|
318
340
|
charIndex: t.start,
|
|
319
|
-
length: t.end - t.start
|
|
341
|
+
length: t.end - t.start,
|
|
342
|
+
word: t.value
|
|
320
343
|
}));
|
|
321
344
|
}
|
|
322
345
|
startWordHighlighting() {
|
|
@@ -336,10 +359,10 @@ var R = (e) => {
|
|
|
336
359
|
return;
|
|
337
360
|
}
|
|
338
361
|
const t = this.currentAudio.currentTime * 1e3;
|
|
339
|
-
for (let
|
|
340
|
-
const
|
|
341
|
-
if (t >=
|
|
342
|
-
this.onWordBoundary && (console.log("[ServerTTSProvider] Highlighting word at charIndex:",
|
|
362
|
+
for (let r = 0; r < this.wordTimings.length; r++) {
|
|
363
|
+
const i = this.wordTimings[r];
|
|
364
|
+
if (t >= i.time && r > e) {
|
|
365
|
+
this.onWordBoundary && (console.log("[ServerTTSProvider] Highlighting word at charIndex:", i.charIndex, "length:", i.length, "time:", i.time, "currentTime:", t), this.onWordBoundary(i.word, i.charIndex, i.length)), e = r;
|
|
343
366
|
break;
|
|
344
367
|
}
|
|
345
368
|
}
|
|
@@ -364,26 +387,26 @@ var R = (e) => {
|
|
|
364
387
|
return this.pausedState;
|
|
365
388
|
}
|
|
366
389
|
updateSettings(e) {
|
|
367
|
-
e.rate !== void 0 && (this.config.rate = e.rate
|
|
390
|
+
e.rate !== void 0 && (this.config.rate = e.rate), e.pitch !== void 0 && (this.config.pitch = e.pitch), e.voice !== void 0 && (this.config.voice = e.voice);
|
|
368
391
|
}
|
|
369
|
-
},
|
|
392
|
+
}, N = class {
|
|
370
393
|
constructor() {
|
|
371
|
-
|
|
394
|
+
h(this, "providerId", "server-tts"), h(this, "providerName", "Server TTS"), h(this, "version", "1.0.0"), h(this, "config", null), h(this, "adapter", null), h(this, "telemetryReporter", void 0);
|
|
372
395
|
}
|
|
373
396
|
async emitTelemetry(e, t) {
|
|
374
397
|
try {
|
|
375
398
|
await this.telemetryReporter?.(e, t);
|
|
376
|
-
} catch (
|
|
377
|
-
console.warn("[ServerTTSProvider] telemetry callback failed:",
|
|
399
|
+
} catch (r) {
|
|
400
|
+
console.warn("[ServerTTSProvider] telemetry callback failed:", r);
|
|
378
401
|
}
|
|
379
402
|
}
|
|
380
403
|
async initialize(e) {
|
|
381
404
|
const t = e;
|
|
382
405
|
if (!t.apiEndpoint) throw new Error("apiEndpoint is required for ServerTTSProvider");
|
|
383
|
-
this.config = t, this.telemetryReporter =
|
|
384
|
-
const
|
|
385
|
-
if (this.adapter =
|
|
386
|
-
const
|
|
406
|
+
this.config = t, this.telemetryReporter = I(t);
|
|
407
|
+
const r = b(t);
|
|
408
|
+
if (this.adapter = B[r], t.validateEndpoint) {
|
|
409
|
+
const i = Date.now();
|
|
387
410
|
if (await this.emitTelemetry("pie-tool-backend-call-start", {
|
|
388
411
|
toolId: "tts",
|
|
389
412
|
backend: t.provider || "server",
|
|
@@ -392,7 +415,7 @@ var R = (e) => {
|
|
|
392
415
|
toolId: "tts",
|
|
393
416
|
backend: t.provider || "server",
|
|
394
417
|
operation: "validate-endpoint",
|
|
395
|
-
duration: Date.now() -
|
|
418
|
+
duration: Date.now() - i,
|
|
396
419
|
errorType: "TTSEndpointValidationError",
|
|
397
420
|
message: `Server TTS API not available at ${t.apiEndpoint}`
|
|
398
421
|
}), /* @__PURE__ */ new Error(`Server TTS API not available at ${t.apiEndpoint}`);
|
|
@@ -400,28 +423,28 @@ var R = (e) => {
|
|
|
400
423
|
toolId: "tts",
|
|
401
424
|
backend: t.provider || "server",
|
|
402
425
|
operation: "validate-endpoint",
|
|
403
|
-
duration: Date.now() -
|
|
426
|
+
duration: Date.now() - i
|
|
404
427
|
});
|
|
405
428
|
}
|
|
406
|
-
return new
|
|
429
|
+
return new x(t, this.adapter);
|
|
407
430
|
}
|
|
408
431
|
async testAPIAvailability() {
|
|
409
432
|
if (!this.config || !this.adapter) return !1;
|
|
410
433
|
try {
|
|
411
434
|
const e = { ...this.config.headers };
|
|
412
435
|
this.config.authToken && (e.Authorization = `Bearer ${this.config.authToken}`);
|
|
413
|
-
const t = new AbortController(),
|
|
414
|
-
if (
|
|
415
|
-
const o =
|
|
436
|
+
const t = new AbortController(), r = setTimeout(() => t.abort(), 5e3), i = M(this.config, this.adapter.id);
|
|
437
|
+
if (i === "none") return clearTimeout(r), !0;
|
|
438
|
+
const o = i === "voices" ? z(this.config) : this.adapter.resolveSynthesisUrl(this.config), s = i === "voices" ? "GET" : "OPTIONS";
|
|
416
439
|
try {
|
|
417
440
|
const a = await fetch(o, {
|
|
418
441
|
method: s,
|
|
419
442
|
headers: e,
|
|
420
443
|
signal: t.signal
|
|
421
444
|
});
|
|
422
|
-
return clearTimeout(
|
|
445
|
+
return clearTimeout(r), a.ok || a.status === 405;
|
|
423
446
|
} catch {
|
|
424
|
-
return clearTimeout(
|
|
447
|
+
return clearTimeout(r), !1;
|
|
425
448
|
}
|
|
426
449
|
} catch {
|
|
427
450
|
return !1;
|
|
@@ -442,6 +465,7 @@ var R = (e) => {
|
|
|
442
465
|
}
|
|
443
466
|
}
|
|
444
467
|
getCapabilities() {
|
|
468
|
+
const e = this.config ? b(this.config) : "pie";
|
|
445
469
|
return {
|
|
446
470
|
supportsPause: !0,
|
|
447
471
|
supportsResume: !0,
|
|
@@ -449,7 +473,8 @@ var R = (e) => {
|
|
|
449
473
|
supportsVoiceSelection: !0,
|
|
450
474
|
supportsRateControl: !0,
|
|
451
475
|
supportsPitchControl: !1,
|
|
452
|
-
|
|
476
|
+
supportsSSML: U(this.config),
|
|
477
|
+
maxTextLength: E[e]
|
|
453
478
|
};
|
|
454
479
|
}
|
|
455
480
|
destroy() {
|
|
@@ -457,5 +482,5 @@ var R = (e) => {
|
|
|
457
482
|
}
|
|
458
483
|
};
|
|
459
484
|
export {
|
|
460
|
-
|
|
485
|
+
N as ServerTTSProvider
|
|
461
486
|
};
|