@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.
- package/.turbo/turbo-build.log +1 -0
- package/CHANGELOG.md +78 -0
- package/README.md +219 -0
- package/dist/ServerTTSProvider.d.ts +64 -0
- package/dist/ServerTTSProvider.d.ts.map +1 -0
- package/dist/ServerTTSProvider.js +363 -0
- package/dist/ServerTTSProvider.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
- package/src/ServerTTSProvider.ts +528 -0
- package/src/index.ts +7 -0
- package/tsconfig.json +24 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$ tsc
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @pie-players/tts-client-server
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8584a3f: Initial 0.1.0 release of PIE section player and dependencies
|
|
8
|
+
|
|
9
|
+
This release includes:
|
|
10
|
+
|
|
11
|
+
## New Packages
|
|
12
|
+
|
|
13
|
+
### Section Player
|
|
14
|
+
|
|
15
|
+
- **@pie-players/pie-section-player** - QTI 3.0 compliant section player with support for passages, rubric blocks, page/item modes, and comprehensive tooling integration
|
|
16
|
+
|
|
17
|
+
### Player Variants
|
|
18
|
+
|
|
19
|
+
- **@pie-players/pie-esm-player** - ESM-based player for modern module loading
|
|
20
|
+
- **@pie-players/pie-fixed-player** - Fixed player for static content
|
|
21
|
+
- **@pie-players/pie-iife-player** - IIFE player for bundle-based loading
|
|
22
|
+
- **@pie-players/pie-inline-player** - Inline player for embedded scenarios
|
|
23
|
+
|
|
24
|
+
### Tools
|
|
25
|
+
|
|
26
|
+
- **@pie-players/pie-section-tools-toolbar** - Section-level toolbar for assessment tools
|
|
27
|
+
- **@pie-players/pie-tool-answer-eliminator** - Answer elimination tool with element-level state tracking
|
|
28
|
+
- **@pie-players/pie-tool-tts-inline** - Inline text-to-speech controls
|
|
29
|
+
|
|
30
|
+
### Core Libraries
|
|
31
|
+
|
|
32
|
+
- **@pie-players/pie-assessment-toolkit** - Core toolkit with tool coordination, TTS services, and accessibility features
|
|
33
|
+
- **@pie-players/pie-players-shared** - Shared types and utilities
|
|
34
|
+
- **@pie-players/tts-client-server** - Client-side TTS provider for server API integration
|
|
35
|
+
- **@pie-players/pie-calculator-desmos** - Desmos calculator provider for graphing and scientific calculators
|
|
36
|
+
|
|
37
|
+
## Publishing Fixes
|
|
38
|
+
|
|
39
|
+
All packages now properly configured for npm publishing:
|
|
40
|
+
|
|
41
|
+
- ✅ ESM-only format (no UMD mixing)
|
|
42
|
+
- ✅ CDN fields (unpkg/jsdelivr) for browser loading
|
|
43
|
+
- ✅ Correct exports configuration
|
|
44
|
+
- ✅ Public access configured
|
|
45
|
+
- ✅ TypeScript declarations included
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
### Section Player
|
|
50
|
+
|
|
51
|
+
- QTI 3.0 section structure support
|
|
52
|
+
- Passage handling with deduplication
|
|
53
|
+
- Rubric blocks (stimulus, instructions, rubric classes)
|
|
54
|
+
- Page mode (all items visible) and item mode (one at a time)
|
|
55
|
+
- Multiple layout options (split-panel, vertical)
|
|
56
|
+
- Session management and restoration
|
|
57
|
+
- Comprehensive event system
|
|
58
|
+
|
|
59
|
+
### Assessment Toolkit
|
|
60
|
+
|
|
61
|
+
- Tool coordination system
|
|
62
|
+
- TTS integration (Browser and Polly providers)
|
|
63
|
+
- Answer eliminator with element-level state
|
|
64
|
+
- Accessibility catalog support
|
|
65
|
+
- Highlight coordination
|
|
66
|
+
|
|
67
|
+
### Element Loading
|
|
68
|
+
|
|
69
|
+
- Multiple player types (ESM, IIFE, Fixed, Inline)
|
|
70
|
+
- Element pre-loading optimization
|
|
71
|
+
- Import map support
|
|
72
|
+
- Local ESM CDN for testing
|
|
73
|
+
|
|
74
|
+
## Development Tools
|
|
75
|
+
|
|
76
|
+
- Local ESM CDN plugin for testing packages before publishing
|
|
77
|
+
- Section-demos app with UI toggles for different player modes
|
|
78
|
+
- Comprehensive testing infrastructure
|
package/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# @pie-players/tts-client-server
|
|
2
|
+
|
|
3
|
+
Client-side TTS provider that calls a server API for synthesis with speech marks support.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides a browser-side TTS provider that offloads synthesis to a server API. The server handles provider selection (AWS Polly, Google Cloud TTS, etc.) and credential management, while the client plays audio and coordinates word highlighting.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- ✅ **Server-Side Synthesis** - Keeps credentials secure on server
|
|
12
|
+
- ✅ **Speech Marks** - Precise word-level timing from server
|
|
13
|
+
- ✅ **Multiple Providers** - Server can use Polly, Google, ElevenLabs, etc.
|
|
14
|
+
- ✅ **Word Highlighting** - 50ms polling for smooth synchronization
|
|
15
|
+
- ✅ **Audio Playback** - HTMLAudioElement with pause/resume
|
|
16
|
+
- ✅ **Blob URLs** - Efficient memory management
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @pie-players/tts-client-server
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Basic Setup
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { ServerTTSProvider } from '@pie-players/tts-client-server';
|
|
30
|
+
import { TTSService } from '@pie-players/pie-assessment-toolkit';
|
|
31
|
+
|
|
32
|
+
const provider = new ServerTTSProvider();
|
|
33
|
+
|
|
34
|
+
const ttsService = new TTSService();
|
|
35
|
+
await ttsService.initialize(provider, {
|
|
36
|
+
apiEndpoint: '/api/tts', // Your SvelteKit API route
|
|
37
|
+
provider: 'polly', // Server-side provider to use
|
|
38
|
+
voiceId: 'Joanna',
|
|
39
|
+
language: 'en-US',
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### With Authentication
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
await ttsService.initialize(provider, {
|
|
47
|
+
apiEndpoint: '/api/tts',
|
|
48
|
+
provider: 'polly',
|
|
49
|
+
authToken: 'your-jwt-token',
|
|
50
|
+
organizationId: 'org-123',
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Speak with Word Highlighting
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// The provider automatically coordinates word highlighting
|
|
58
|
+
await ttsService.speak('Hello world, this is a test.', {
|
|
59
|
+
contentElement: document.getElementById('content'),
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API Requirements
|
|
64
|
+
|
|
65
|
+
The server API must implement two endpoints:
|
|
66
|
+
|
|
67
|
+
### POST `/api/tts/synthesize`
|
|
68
|
+
|
|
69
|
+
**Request:**
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"text": "Hello world",
|
|
73
|
+
"provider": "polly",
|
|
74
|
+
"voice": "Joanna",
|
|
75
|
+
"language": "en-US",
|
|
76
|
+
"rate": 1.0,
|
|
77
|
+
"includeSpeechMarks": true
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Response:**
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"audio": "base64-encoded-audio",
|
|
85
|
+
"contentType": "audio/mpeg",
|
|
86
|
+
"speechMarks": [
|
|
87
|
+
{ "time": 0, "type": "word", "start": 0, "end": 5, "value": "Hello" },
|
|
88
|
+
{ "time": 340, "type": "word", "start": 6, "end": 11, "value": "world" }
|
|
89
|
+
],
|
|
90
|
+
"metadata": {
|
|
91
|
+
"providerId": "aws-polly",
|
|
92
|
+
"voice": "Joanna",
|
|
93
|
+
"duration": 1.5,
|
|
94
|
+
"charCount": 11,
|
|
95
|
+
"cached": false
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### GET `/api/tts/voices`
|
|
101
|
+
|
|
102
|
+
**Response:**
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"voices": [
|
|
106
|
+
{
|
|
107
|
+
"id": "Joanna",
|
|
108
|
+
"name": "Joanna",
|
|
109
|
+
"language": "English",
|
|
110
|
+
"languageCode": "en-US",
|
|
111
|
+
"gender": "female",
|
|
112
|
+
"quality": "neural"
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## SvelteKit Implementation Example
|
|
119
|
+
|
|
120
|
+
See the implementation guide in [tts-server-api-architecture.md](../../docs/tts-server-api-architecture.md).
|
|
121
|
+
|
|
122
|
+
Example route structure:
|
|
123
|
+
```
|
|
124
|
+
apps/example/src/routes/api/tts/
|
|
125
|
+
├── synthesize/+server.ts
|
|
126
|
+
└── voices/+server.ts
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Configuration
|
|
130
|
+
|
|
131
|
+
### ServerTTSProviderConfig
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
interface ServerTTSProviderConfig {
|
|
135
|
+
apiEndpoint: string; // API base URL (required)
|
|
136
|
+
provider?: string; // Server provider ('polly', 'google', etc.)
|
|
137
|
+
authToken?: string; // JWT or API key
|
|
138
|
+
organizationId?: string; // For multi-tenant setups
|
|
139
|
+
headers?: Record<string, string>; // Custom headers
|
|
140
|
+
voiceId?: string; // Voice ID
|
|
141
|
+
language?: string; // Language code
|
|
142
|
+
rate?: number; // Speech rate (0.25-4.0)
|
|
143
|
+
volume?: number; // Volume (0-1)
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## How It Works
|
|
148
|
+
|
|
149
|
+
1. **Client calls** `speak(text)`
|
|
150
|
+
2. **Provider POSTs** to `/api/tts/synthesize` with text
|
|
151
|
+
3. **Server synthesizes** using provider (Polly, Google, etc.)
|
|
152
|
+
4. **Server returns** base64 audio + speech marks
|
|
153
|
+
5. **Client converts** base64 to Blob URL
|
|
154
|
+
6. **Client plays** audio via HTMLAudioElement
|
|
155
|
+
7. **Client polls** audio time every 50ms
|
|
156
|
+
8. **Client fires** word boundary callbacks at correct times
|
|
157
|
+
9. **TTSService** highlights words in DOM
|
|
158
|
+
|
|
159
|
+
## Word Highlighting Synchronization
|
|
160
|
+
|
|
161
|
+
The provider uses a polling-based approach for reliable synchronization:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// Every 50ms, check current audio time
|
|
165
|
+
const currentTime = audio.currentTime * 1000; // Convert to ms
|
|
166
|
+
|
|
167
|
+
// Find words that should be highlighted
|
|
168
|
+
for (const timing of wordTimings) {
|
|
169
|
+
if (currentTime >= timing.time) {
|
|
170
|
+
onWordBoundary('', timing.charIndex);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
This is **much more reliable** than browser's `onboundary` events (which are broken in Safari and unreliable in Chrome).
|
|
176
|
+
|
|
177
|
+
## Memory Management
|
|
178
|
+
|
|
179
|
+
The provider automatically manages Blob URLs:
|
|
180
|
+
|
|
181
|
+
- Creates Blob URL from base64 audio
|
|
182
|
+
- Plays audio from Blob URL
|
|
183
|
+
- Revokes Blob URL when done (frees memory)
|
|
184
|
+
- Cleans up on stop/error
|
|
185
|
+
|
|
186
|
+
## Error Handling
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
try {
|
|
190
|
+
await ttsService.speak('Hello world');
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error('TTS failed:', error.message);
|
|
193
|
+
// Fallback to browser TTS or show error
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Browser Compatibility
|
|
198
|
+
|
|
199
|
+
- ✅ Chrome/Edge (latest)
|
|
200
|
+
- ✅ Firefox (latest)
|
|
201
|
+
- ✅ Safari (latest)
|
|
202
|
+
- ✅ Mobile browsers
|
|
203
|
+
|
|
204
|
+
Requires:
|
|
205
|
+
- `HTMLAudioElement` API
|
|
206
|
+
- `fetch` API
|
|
207
|
+
- `URL.createObjectURL`
|
|
208
|
+
- `atob` for base64 decoding
|
|
209
|
+
|
|
210
|
+
## Performance
|
|
211
|
+
|
|
212
|
+
- **Audio caching:** Server-side (Redis)
|
|
213
|
+
- **Blob URLs:** Efficient memory usage
|
|
214
|
+
- **50ms polling:** Smooth highlighting without jank
|
|
215
|
+
- **Parallel requests:** Audio + marks fetched together
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
import type { ITTSProvider, ITTSProviderImplementation, TTSConfig, TTSFeature, TTSProviderCapabilities } from "@pie-players/pie-tts";
|
|
9
|
+
/**
|
|
10
|
+
* Configuration for ServerTTSProvider
|
|
11
|
+
*/
|
|
12
|
+
export interface ServerTTSProviderConfig extends TTSConfig {
|
|
13
|
+
/** API endpoint base URL (e.g., '/api/tts' or 'https://api.example.com/tts') */
|
|
14
|
+
apiEndpoint: string;
|
|
15
|
+
/** Provider to use on server ('polly', 'google', 'elevenlabs', etc.) */
|
|
16
|
+
provider?: string;
|
|
17
|
+
/** Authentication token or API key */
|
|
18
|
+
authToken?: string;
|
|
19
|
+
/** Custom headers for API requests */
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
/** Language code */
|
|
22
|
+
language?: string;
|
|
23
|
+
/** Volume level 0-1 */
|
|
24
|
+
volume?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Validate API endpoint availability during initialization (slower but safer)
|
|
27
|
+
*
|
|
28
|
+
* @extension Performance vs safety tradeoff
|
|
29
|
+
* @default false (fast initialization, fail on first synthesis if unavailable)
|
|
30
|
+
* @note When true, adds 100-500ms to initialization time
|
|
31
|
+
*/
|
|
32
|
+
validateEndpoint?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Server TTS Provider
|
|
36
|
+
*
|
|
37
|
+
* Client-side provider that calls a server API for TTS synthesis.
|
|
38
|
+
* The server handles provider selection (Polly, Google, etc.) and credential management.
|
|
39
|
+
*/
|
|
40
|
+
export declare class ServerTTSProvider implements ITTSProvider {
|
|
41
|
+
readonly providerId = "server-tts";
|
|
42
|
+
readonly providerName = "Server TTS";
|
|
43
|
+
readonly version = "1.0.0";
|
|
44
|
+
private config;
|
|
45
|
+
/**
|
|
46
|
+
* Initialize the server TTS provider.
|
|
47
|
+
*
|
|
48
|
+
* This is designed to be fast by default (no API calls).
|
|
49
|
+
* Set validateEndpoint: true in config to test API availability during initialization.
|
|
50
|
+
*
|
|
51
|
+
* @performance Default: <10ms, With validation: 100-500ms
|
|
52
|
+
*/
|
|
53
|
+
initialize(config: TTSConfig): Promise<ITTSProviderImplementation>;
|
|
54
|
+
/**
|
|
55
|
+
* Test if API endpoint is available (with timeout).
|
|
56
|
+
*
|
|
57
|
+
* @performance 100-500ms depending on network
|
|
58
|
+
*/
|
|
59
|
+
private testAPIAvailability;
|
|
60
|
+
supportsFeature(feature: TTSFeature): boolean;
|
|
61
|
+
getCapabilities(): TTSProviderCapabilities;
|
|
62
|
+
destroy(): void;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=ServerTTSProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServerTTSProvider.d.ts","sourceRoot":"","sources":["../src/ServerTTSProvider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACX,YAAY,EACZ,0BAA0B,EAC1B,SAAS,EACT,UAAU,EACV,uBAAuB,EACvB,MAAM,sBAAsB,CAAC;AAE9B;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,SAAS;IACzD,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAC;IAEpB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,uBAAuB;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC3B;AAiXD;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IACrD,QAAQ,CAAC,UAAU,gBAAgB;IACnC,QAAQ,CAAC,YAAY,gBAAgB;IACrC,QAAQ,CAAC,OAAO,WAAW;IAE3B,OAAO,CAAC,MAAM,CAAwC;IAEtD;;;;;;;OAOG;IACG,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAsBxE;;;;OAIG;YACW,mBAAmB;IAiCjC,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IAgB7C,eAAe,IAAI,uBAAuB;IAY1C,OAAO,IAAI,IAAI;CAGf"}
|