@pie-players/tts-client-server 0.2.0

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.
@@ -0,0 +1,363 @@
1
+ /**
2
+ * ServerTTSProvider - Client-side TTS provider that calls server API
3
+ *
4
+ * Provides high-quality TTS by calling a server-side API that uses
5
+ * providers like AWS Polly, Google Cloud TTS, etc.
6
+ * Returns audio with precise word-level timing (speech marks).
7
+ */
8
+ /**
9
+ * Provider implementation that handles audio playback
10
+ */
11
+ class ServerTTSProviderImpl {
12
+ config;
13
+ currentAudio = null;
14
+ pausedState = false;
15
+ wordTimings = [];
16
+ highlightInterval = null;
17
+ intentionallyStopped = false;
18
+ onWordBoundary;
19
+ constructor(config) {
20
+ this.config = config;
21
+ }
22
+ async speak(text) {
23
+ // Stop any current playback
24
+ this.stop();
25
+ // Reset intentionally stopped flag for new playback
26
+ this.intentionallyStopped = false;
27
+ // Call server API to synthesize speech
28
+ const { audioUrl, wordTimings } = await this.synthesizeSpeech(text);
29
+ // Adjust word timing for playback rate
30
+ // Speech marks are at 1.0x speed, so we need to scale them
31
+ const playbackRate = this.config.rate || 1.0;
32
+ this.wordTimings = wordTimings.map((timing) => ({
33
+ ...timing,
34
+ time: timing.time / playbackRate,
35
+ }));
36
+ return new Promise((resolve, reject) => {
37
+ // Create audio element
38
+ const audio = new Audio(audioUrl);
39
+ this.currentAudio = audio;
40
+ // Apply rate from config
41
+ if (this.config.rate) {
42
+ audio.playbackRate = Math.max(0.25, Math.min(4.0, this.config.rate));
43
+ }
44
+ // Apply volume from config
45
+ if (this.config.volume !== undefined) {
46
+ audio.volume = Math.max(0, Math.min(1, this.config.volume));
47
+ }
48
+ // Setup event handlers
49
+ audio.onplay = () => {
50
+ this.pausedState = false;
51
+ // Start word highlighting
52
+ if (this.onWordBoundary && this.wordTimings.length > 0) {
53
+ this.startWordHighlighting();
54
+ }
55
+ };
56
+ audio.onended = () => {
57
+ this.stopWordHighlighting();
58
+ URL.revokeObjectURL(audioUrl);
59
+ this.currentAudio = null;
60
+ this.wordTimings = [];
61
+ resolve();
62
+ };
63
+ audio.onerror = (event) => {
64
+ this.stopWordHighlighting();
65
+ URL.revokeObjectURL(audioUrl);
66
+ this.currentAudio = null;
67
+ this.wordTimings = [];
68
+ // Only reject if this wasn't an intentional stop
69
+ if (!this.intentionallyStopped) {
70
+ reject(new Error("Failed to play audio from server"));
71
+ }
72
+ else {
73
+ // Intentional stop, resolve normally
74
+ resolve();
75
+ }
76
+ };
77
+ audio.onpause = () => {
78
+ this.stopWordHighlighting();
79
+ this.pausedState = true;
80
+ };
81
+ // Start playback
82
+ audio.play().catch(reject);
83
+ });
84
+ }
85
+ /**
86
+ * Call server API to synthesize speech
87
+ */
88
+ async synthesizeSpeech(text) {
89
+ const headers = {
90
+ "Content-Type": "application/json",
91
+ ...this.config.headers,
92
+ };
93
+ // Add authentication if provided
94
+ if (this.config.authToken) {
95
+ headers["Authorization"] = `Bearer ${this.config.authToken}`;
96
+ }
97
+ const requestBody = {
98
+ text,
99
+ provider: this.config.provider || "polly",
100
+ voice: this.config.voice,
101
+ language: this.config.language,
102
+ rate: this.config.rate,
103
+ includeSpeechMarks: true,
104
+ };
105
+ const response = await fetch(`${this.config.apiEndpoint}/synthesize`, {
106
+ method: "POST",
107
+ headers,
108
+ body: JSON.stringify(requestBody),
109
+ });
110
+ if (!response.ok) {
111
+ const errorData = await response.json().catch(() => ({}));
112
+ const errorMessage = errorData.message ||
113
+ errorData.error?.message ||
114
+ `Server returned ${response.status}`;
115
+ throw new Error(errorMessage);
116
+ }
117
+ const data = await response.json();
118
+ // Convert base64 audio to blob URL
119
+ const audioBlob = this.base64ToBlob(data.audio, data.contentType);
120
+ const audioUrl = URL.createObjectURL(audioBlob);
121
+ // Convert speech marks to word timings
122
+ const wordTimings = this.parseSpeechMarks(data.speechMarks);
123
+ return { audioUrl, wordTimings };
124
+ }
125
+ /**
126
+ * Convert base64 to Blob
127
+ */
128
+ base64ToBlob(base64, contentType) {
129
+ const byteCharacters = atob(base64);
130
+ const byteNumbers = new Array(byteCharacters.length);
131
+ for (let i = 0; i < byteCharacters.length; i++) {
132
+ byteNumbers[i] = byteCharacters.charCodeAt(i);
133
+ }
134
+ const byteArray = new Uint8Array(byteNumbers);
135
+ return new Blob([byteArray], { type: contentType });
136
+ }
137
+ /**
138
+ * Parse speech marks into word timings
139
+ */
140
+ parseSpeechMarks(marks) {
141
+ return marks
142
+ .filter((mark) => mark.type === "word")
143
+ .map((mark, index) => ({
144
+ time: mark.time,
145
+ wordIndex: index,
146
+ charIndex: mark.start,
147
+ length: mark.end - mark.start,
148
+ }));
149
+ }
150
+ /**
151
+ * Start word highlighting synchronized with audio playback
152
+ */
153
+ startWordHighlighting() {
154
+ this.stopWordHighlighting();
155
+ if (!this.currentAudio ||
156
+ !this.onWordBoundary ||
157
+ this.wordTimings.length === 0) {
158
+ console.log("[ServerTTSProvider] Cannot start highlighting:", {
159
+ hasAudio: !!this.currentAudio,
160
+ hasCallback: !!this.onWordBoundary,
161
+ wordTimingsCount: this.wordTimings.length,
162
+ });
163
+ return;
164
+ }
165
+ console.log("[ServerTTSProvider] Starting word highlighting with", this.wordTimings.length, "word timings");
166
+ console.log("[ServerTTSProvider] Playback rate:", this.currentAudio.playbackRate);
167
+ console.log("[ServerTTSProvider] First 3 timings:", this.wordTimings.slice(0, 3));
168
+ let lastWordIndex = -1;
169
+ // Poll every 50ms to check current playback time
170
+ this.highlightInterval = window.setInterval(() => {
171
+ if (!this.currentAudio) {
172
+ this.stopWordHighlighting();
173
+ return;
174
+ }
175
+ // Get current playback time in milliseconds
176
+ const currentTime = this.currentAudio.currentTime * 1000;
177
+ // Find words that should be highlighted at current time
178
+ for (let i = 0; i < this.wordTimings.length; i++) {
179
+ const timing = this.wordTimings[i];
180
+ if (currentTime >= timing.time && i > lastWordIndex) {
181
+ // Fire word boundary callback
182
+ if (this.onWordBoundary) {
183
+ console.log("[ServerTTSProvider] Highlighting word at charIndex:", timing.charIndex, "length:", timing.length, "time:", timing.time, "currentTime:", currentTime);
184
+ // Pass the length as the "word" parameter so TTSService can use it
185
+ this.onWordBoundary("", timing.charIndex, timing.length);
186
+ }
187
+ lastWordIndex = i;
188
+ break;
189
+ }
190
+ }
191
+ }, 50); // 50ms polling = 20 times per second
192
+ }
193
+ /**
194
+ * Stop word highlighting
195
+ */
196
+ stopWordHighlighting() {
197
+ if (this.highlightInterval !== null) {
198
+ clearInterval(this.highlightInterval);
199
+ this.highlightInterval = null;
200
+ }
201
+ }
202
+ pause() {
203
+ if (this.currentAudio && !this.pausedState) {
204
+ this.currentAudio.pause();
205
+ this.stopWordHighlighting();
206
+ this.pausedState = true;
207
+ }
208
+ }
209
+ resume() {
210
+ if (this.currentAudio && this.pausedState) {
211
+ this.currentAudio.play();
212
+ this.pausedState = false;
213
+ // Resume word highlighting
214
+ if (this.onWordBoundary && this.wordTimings.length > 0) {
215
+ this.startWordHighlighting();
216
+ }
217
+ }
218
+ }
219
+ stop() {
220
+ this.stopWordHighlighting();
221
+ if (this.currentAudio) {
222
+ // Mark as intentionally stopped to prevent error handler from rejecting
223
+ this.intentionallyStopped = true;
224
+ this.currentAudio.pause();
225
+ if (this.currentAudio.src) {
226
+ URL.revokeObjectURL(this.currentAudio.src);
227
+ }
228
+ this.currentAudio.src = "";
229
+ this.currentAudio = null;
230
+ }
231
+ this.pausedState = false;
232
+ this.wordTimings = [];
233
+ }
234
+ isPlaying() {
235
+ return this.currentAudio !== null && !this.pausedState;
236
+ }
237
+ isPaused() {
238
+ return this.pausedState;
239
+ }
240
+ /**
241
+ * Update settings dynamically (rate, pitch, voice)
242
+ * Note: Voice changes require resynthesis, so voice updates are stored but
243
+ * take effect on the next speak() call. Rate can be applied to current playback.
244
+ */
245
+ updateSettings(settings) {
246
+ // Update config
247
+ if (settings.rate !== undefined) {
248
+ this.config.rate = settings.rate;
249
+ // Apply rate immediately to current playback if active
250
+ if (this.currentAudio) {
251
+ this.currentAudio.playbackRate = Math.max(0.25, Math.min(4.0, settings.rate));
252
+ }
253
+ }
254
+ if (settings.pitch !== undefined) {
255
+ // Server-side pitch is baked into audio, so this only affects next speak()
256
+ this.config.pitch = settings.pitch;
257
+ }
258
+ if (settings.voice !== undefined) {
259
+ // Voice change requires resynthesis, affects next speak()
260
+ this.config.voice = settings.voice;
261
+ }
262
+ }
263
+ }
264
+ /**
265
+ * Server TTS Provider
266
+ *
267
+ * Client-side provider that calls a server API for TTS synthesis.
268
+ * The server handles provider selection (Polly, Google, etc.) and credential management.
269
+ */
270
+ export class ServerTTSProvider {
271
+ providerId = "server-tts";
272
+ providerName = "Server TTS";
273
+ version = "1.0.0";
274
+ config = null;
275
+ /**
276
+ * Initialize the server TTS provider.
277
+ *
278
+ * This is designed to be fast by default (no API calls).
279
+ * Set validateEndpoint: true in config to test API availability during initialization.
280
+ *
281
+ * @performance Default: <10ms, With validation: 100-500ms
282
+ */
283
+ async initialize(config) {
284
+ const serverConfig = config;
285
+ if (!serverConfig.apiEndpoint) {
286
+ throw new Error("apiEndpoint is required for ServerTTSProvider");
287
+ }
288
+ this.config = serverConfig;
289
+ // Only test API availability if explicitly requested (slower but safer)
290
+ if (serverConfig.validateEndpoint) {
291
+ const available = await this.testAPIAvailability();
292
+ if (!available) {
293
+ throw new Error(`Server TTS API not available at ${serverConfig.apiEndpoint}`);
294
+ }
295
+ }
296
+ return new ServerTTSProviderImpl(serverConfig);
297
+ }
298
+ /**
299
+ * Test if API endpoint is available (with timeout).
300
+ *
301
+ * @performance 100-500ms depending on network
302
+ */
303
+ async testAPIAvailability() {
304
+ if (!this.config)
305
+ return false;
306
+ try {
307
+ const headers = { ...this.config.headers };
308
+ if (this.config.authToken) {
309
+ headers["Authorization"] = `Bearer ${this.config.authToken}`;
310
+ }
311
+ // Create abort controller for timeout
312
+ const controller = new AbortController();
313
+ const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
314
+ try {
315
+ // Try to fetch voices to test API
316
+ const response = await fetch(`${this.config.apiEndpoint}/voices`, {
317
+ headers,
318
+ signal: controller.signal,
319
+ });
320
+ clearTimeout(timeoutId);
321
+ return response.ok;
322
+ }
323
+ catch (fetchError) {
324
+ clearTimeout(timeoutId);
325
+ // If aborted due to timeout or network error, consider API unavailable
326
+ return false;
327
+ }
328
+ }
329
+ catch {
330
+ return false;
331
+ }
332
+ }
333
+ supportsFeature(feature) {
334
+ switch (feature) {
335
+ case "pause":
336
+ case "resume":
337
+ case "wordBoundary":
338
+ case "voiceSelection":
339
+ case "rateControl":
340
+ return true;
341
+ case "pitchControl":
342
+ // Depends on server provider, assume no for safety
343
+ return false;
344
+ default:
345
+ return false;
346
+ }
347
+ }
348
+ getCapabilities() {
349
+ return {
350
+ supportsPause: true,
351
+ supportsResume: true,
352
+ supportsWordBoundary: true, // ✅ Via speech marks from server
353
+ supportsVoiceSelection: true,
354
+ supportsRateControl: true,
355
+ supportsPitchControl: false, // Depends on server provider
356
+ maxTextLength: 3000, // Conservative estimate
357
+ };
358
+ }
359
+ destroy() {
360
+ this.config = null;
361
+ }
362
+ }
363
+ //# sourceMappingURL=ServerTTSProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerTTSProvider.js","sourceRoot":"","sources":["../src/ServerTTSProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Client-side TTS provider for calling server APIs
3
+ * @module @pie-players/tts-client-server
4
+ */
5
+ export type { ServerTTSProviderConfig } from "./ServerTTSProvider.js";
6
+ export { ServerTTSProvider } from "./ServerTTSProvider.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Client-side TTS provider for calling server APIs
3
+ * @module @pie-players/tts-client-server
4
+ */
5
+ export { ServerTTSProvider } from "./ServerTTSProvider.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@pie-players/tts-client-server",
3
+ "version": "0.2.0",
4
+ "description": "Client-side TTS provider that calls server API for synthesis",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "test": "vitest",
18
+ "test:coverage": "vitest --coverage"
19
+ },
20
+ "keywords": [
21
+ "tts",
22
+ "text-to-speech",
23
+ "client",
24
+ "server-api",
25
+ "speech-marks"
26
+ ],
27
+ "author": "PIE Framework",
28
+ "license": "MIT",
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "@pie-players/pie-tts": "workspace:*"
34
+ },
35
+ "devDependencies": {
36
+ "typescript": "^5.3.3",
37
+ "vitest": "^1.0.4"
38
+ }
39
+ }