@pie-players/tts-server-core 0.1.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 @@
1
+ $ tsc
package/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # @pie-players/tts-server-core
2
+
3
+ Core types, interfaces, and utilities for server-side Text-to-Speech (TTS) providers.
4
+
5
+ ## Overview
6
+
7
+ This package provides the foundation for building server-side TTS providers that return audio with precise word-level timing metadata (speech marks) for synchronized highlighting.
8
+
9
+ ## Features
10
+
11
+ - **Provider Interface** - Standard interface for all TTS providers
12
+ - **Speech Marks** - Unified format for word-level timing across providers
13
+ - **Caching** - Interface and utilities for caching synthesis results
14
+ - **Type Safety** - Full TypeScript support with comprehensive types
15
+ - **Utilities** - Helper functions for speech marks manipulation
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @pie-players/tts-server-core
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### Implementing a Provider
26
+
27
+ ```typescript
28
+ import { BaseTTSProvider, type SynthesizeRequest, type SynthesizeResponse } from '@pie-players/tts-server-core';
29
+
30
+ export class MyTTSProvider extends BaseTTSProvider {
31
+ readonly providerId = 'my-tts';
32
+ readonly providerName = 'My TTS Service';
33
+ readonly version = '1.0.0';
34
+
35
+ async initialize(config: TTSServerConfig): Promise<void> {
36
+ this.config = config;
37
+ this.initialized = true;
38
+ }
39
+
40
+ async synthesize(request: SynthesizeRequest): Promise<SynthesizeResponse> {
41
+ this.ensureInitialized();
42
+
43
+ // Your synthesis logic here
44
+ const audio = await this.callTTSAPI(request.text);
45
+ const speechMarks = await this.getSpeechMarks(request.text);
46
+
47
+ return {
48
+ audio,
49
+ contentType: 'audio/mpeg',
50
+ speechMarks,
51
+ metadata: {
52
+ providerId: this.providerId,
53
+ voice: request.voice || 'default',
54
+ duration: 0,
55
+ charCount: request.text.length,
56
+ cached: false,
57
+ },
58
+ };
59
+ }
60
+
61
+ // ... implement other required methods
62
+ }
63
+ ```
64
+
65
+ ### Using Speech Marks Utilities
66
+
67
+ ```typescript
68
+ import { estimateSpeechMarks, adjustSpeechMarksForRate } from '@pie-players/tts-server-core';
69
+
70
+ // Generate estimated marks when provider doesn't support them
71
+ const marks = estimateSpeechMarks('Hello world');
72
+
73
+ // Adjust timing for different speech rates
74
+ const fasterMarks = adjustSpeechMarksForRate(marks, 1.5);
75
+ ```
76
+
77
+ ### Using Cache
78
+
79
+ ```typescript
80
+ import { MemoryCache, generateHashedCacheKey } from '@pie-players/tts-server-core';
81
+
82
+ const cache = new MemoryCache();
83
+
84
+ // Generate cache key
85
+ const cacheKey = await generateHashedCacheKey({
86
+ providerId: 'my-tts',
87
+ text: 'Hello world',
88
+ voice: 'default',
89
+ });
90
+
91
+ // Check cache
92
+ const cached = await cache.get(cacheKey);
93
+ if (cached) {
94
+ return cached;
95
+ }
96
+
97
+ // Store in cache (24 hour TTL)
98
+ await cache.set(cacheKey, result, 86400);
99
+ ```
100
+
101
+ ## API Reference
102
+
103
+ ### Types
104
+
105
+ - `SpeechMark` - Word timing information
106
+ - `SynthesizeRequest` - Synthesis request parameters
107
+ - `SynthesizeResponse` - Synthesis result with audio and marks
108
+ - `Voice` - Voice definition
109
+ - `ServerProviderCapabilities` - Provider feature flags
110
+
111
+ ### Interfaces
112
+
113
+ - `ITTSServerProvider` - Provider interface
114
+ - `ITTSCache` - Cache interface
115
+
116
+ ### Classes
117
+
118
+ - `BaseTTSProvider` - Abstract base class for providers
119
+ - `MemoryCache` - In-memory cache implementation
120
+ - `TTSError` - Structured error class
121
+
122
+ ### Functions
123
+
124
+ - `estimateSpeechMarks()` - Generate estimated timing
125
+ - `adjustSpeechMarksForRate()` - Adjust for speech rate
126
+ - `validateSpeechMarks()` - Validate marks
127
+ - `generateCacheKey()` - Create cache key
128
+ - `hashText()` - SHA-256 hash for cache keys
129
+
130
+ ## Speech Marks Format
131
+
132
+ All providers return speech marks in this unified format:
133
+
134
+ ```typescript
135
+ interface SpeechMark {
136
+ time: number; // Milliseconds from audio start
137
+ type: 'word' | 'sentence' | 'ssml';
138
+ start: number; // Character index (inclusive)
139
+ end: number; // Character index (exclusive)
140
+ value: string; // The word text
141
+ }
142
+ ```
143
+
144
+ Example:
145
+ ```json
146
+ [
147
+ { "time": 0, "type": "word", "start": 0, "end": 5, "value": "Hello" },
148
+ { "time": 340, "type": "word", "start": 6, "end": 11, "value": "world" }
149
+ ]
150
+ ```
151
+
152
+ ## License
153
+
154
+ MIT
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Caching interface for TTS results
3
+ * @module @pie-players/tts-server-core
4
+ */
5
+ import type { SynthesizeResponse } from "./types.js";
6
+ /**
7
+ * Cache key components for TTS synthesis
8
+ */
9
+ export interface CacheKeyComponents {
10
+ /** Provider identifier */
11
+ providerId: string;
12
+ /** Text to synthesize */
13
+ text: string;
14
+ /** Voice ID */
15
+ voice: string;
16
+ /** Language code */
17
+ language?: string;
18
+ /** Speech rate */
19
+ rate?: number;
20
+ /** Audio format */
21
+ format?: string;
22
+ }
23
+ /**
24
+ * Cache interface for TTS providers
25
+ */
26
+ export interface ITTSCache {
27
+ /**
28
+ * Get cached synthesis result
29
+ *
30
+ * @param key - Cache key
31
+ * @returns Cached result or null if not found
32
+ */
33
+ get(key: string): Promise<SynthesizeResponse | null>;
34
+ /**
35
+ * Store synthesis result in cache
36
+ *
37
+ * @param key - Cache key
38
+ * @param value - Synthesis response to cache
39
+ * @param ttl - Time to live in seconds (optional)
40
+ */
41
+ set(key: string, value: SynthesizeResponse, ttl?: number): Promise<void>;
42
+ /**
43
+ * Check if key exists in cache
44
+ *
45
+ * @param key - Cache key
46
+ * @returns True if key exists
47
+ */
48
+ has(key: string): Promise<boolean>;
49
+ /**
50
+ * Delete cached result
51
+ *
52
+ * @param key - Cache key
53
+ */
54
+ delete(key: string): Promise<void>;
55
+ /**
56
+ * Clear all cached results
57
+ */
58
+ clear(): Promise<void>;
59
+ /**
60
+ * Get cache statistics
61
+ */
62
+ getStats?(): Promise<CacheStats>;
63
+ }
64
+ /**
65
+ * Cache statistics
66
+ */
67
+ export interface CacheStats {
68
+ /** Total cache hits */
69
+ hits: number;
70
+ /** Total cache misses */
71
+ misses: number;
72
+ /** Hit rate (0.0 to 1.0) */
73
+ hitRate: number;
74
+ /** Number of keys in cache */
75
+ keyCount: number;
76
+ /** Total size in bytes (if available) */
77
+ sizeBytes?: number;
78
+ }
79
+ /**
80
+ * Generate cache key from components
81
+ *
82
+ * @param components - Cache key components
83
+ * @returns Cache key string
84
+ */
85
+ export declare function generateCacheKey(components: CacheKeyComponents): string;
86
+ /**
87
+ * Generate SHA-256 hash for cache key
88
+ * Useful for creating shorter keys from long text
89
+ *
90
+ * @param text - Text to hash
91
+ * @returns Hex string hash
92
+ */
93
+ export declare function hashText(text: string): Promise<string>;
94
+ /**
95
+ * Generate short cache key using hash
96
+ *
97
+ * @param components - Cache key components
98
+ * @returns Promise resolving to cache key
99
+ */
100
+ export declare function generateHashedCacheKey(components: CacheKeyComponents): Promise<string>;
101
+ /**
102
+ * In-memory cache implementation
103
+ * Simple LRU cache for development/testing
104
+ */
105
+ export declare class MemoryCache implements ITTSCache {
106
+ private cache;
107
+ private hits;
108
+ private misses;
109
+ private maxSize;
110
+ constructor(maxSize?: number);
111
+ get(key: string): Promise<SynthesizeResponse | null>;
112
+ set(key: string, value: SynthesizeResponse, ttl?: number): Promise<void>;
113
+ has(key: string): Promise<boolean>;
114
+ delete(key: string): Promise<void>;
115
+ clear(): Promise<void>;
116
+ getStats(): Promise<CacheStats>;
117
+ }
118
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IAEnB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IAEb,eAAe;IACf,KAAK,EAAE,MAAM,CAAC;IAEd,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,kBAAkB;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,mBAAmB;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;IAErD;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzE;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEnC;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IAEb,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAC;IAEf,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAEhB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IAEjB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAwBvE;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO5D;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC3C,UAAU,EAAE,kBAAkB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAwBjB;AAED;;;GAGG;AACH,qBAAa,WAAY,YAAW,SAAS;IAC5C,OAAO,CAAC,KAAK,CAGT;IACJ,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,SAAM;IAInB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAwBpD,GAAG,CACR,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,kBAAkB,EACzB,GAAG,SAAQ,GACT,OAAO,CAAC,IAAI,CAAC;IAgBV,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAalC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC;CASrC"}
package/dist/cache.js ADDED
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Caching interface for TTS results
3
+ * @module @pie-players/tts-server-core
4
+ */
5
+ /**
6
+ * Generate cache key from components
7
+ *
8
+ * @param components - Cache key components
9
+ * @returns Cache key string
10
+ */
11
+ export function generateCacheKey(components) {
12
+ const { providerId, text, voice, language = "", rate = 1.0, format = "mp3", } = components;
13
+ // Create deterministic key from components
14
+ const keyParts = [
15
+ "tts",
16
+ providerId,
17
+ voice,
18
+ language,
19
+ rate.toFixed(2),
20
+ format,
21
+ text,
22
+ ];
23
+ // Use simple concatenation with delimiter
24
+ // In production, consider using a hash function for shorter keys
25
+ return keyParts.join(":");
26
+ }
27
+ /**
28
+ * Generate SHA-256 hash for cache key
29
+ * Useful for creating shorter keys from long text
30
+ *
31
+ * @param text - Text to hash
32
+ * @returns Hex string hash
33
+ */
34
+ export async function hashText(text) {
35
+ // Use Web Crypto API (available in modern Node.js and browsers)
36
+ const encoder = new TextEncoder();
37
+ const data = encoder.encode(text);
38
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
39
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
40
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
41
+ }
42
+ /**
43
+ * Generate short cache key using hash
44
+ *
45
+ * @param components - Cache key components
46
+ * @returns Promise resolving to cache key
47
+ */
48
+ export async function generateHashedCacheKey(components) {
49
+ const { providerId, text, voice, language = "", rate = 1.0, format = "mp3", } = components;
50
+ // Hash the text to keep key length reasonable
51
+ const textHash = await hashText(text);
52
+ const keyParts = [
53
+ "tts",
54
+ providerId,
55
+ voice,
56
+ language,
57
+ rate.toFixed(2),
58
+ format,
59
+ textHash,
60
+ ];
61
+ return keyParts.join(":");
62
+ }
63
+ /**
64
+ * In-memory cache implementation
65
+ * Simple LRU cache for development/testing
66
+ */
67
+ export class MemoryCache {
68
+ cache = new Map();
69
+ hits = 0;
70
+ misses = 0;
71
+ maxSize;
72
+ constructor(maxSize = 100) {
73
+ this.maxSize = maxSize;
74
+ }
75
+ async get(key) {
76
+ const entry = this.cache.get(key);
77
+ if (!entry) {
78
+ this.misses++;
79
+ return null;
80
+ }
81
+ // Check expiration
82
+ if (Date.now() > entry.expires) {
83
+ this.cache.delete(key);
84
+ this.misses++;
85
+ return null;
86
+ }
87
+ this.hits++;
88
+ // Update metadata to mark as served from cache
89
+ const result = { ...entry.value };
90
+ result.metadata = { ...result.metadata, cached: true };
91
+ return result;
92
+ }
93
+ async set(key, value, ttl = 86400) {
94
+ // Enforce max size (simple LRU)
95
+ if (this.cache.size >= this.maxSize) {
96
+ // Delete oldest entry (first key)
97
+ const firstKey = this.cache.keys().next().value;
98
+ if (firstKey) {
99
+ this.cache.delete(firstKey);
100
+ }
101
+ }
102
+ this.cache.set(key, {
103
+ value,
104
+ expires: Date.now() + ttl * 1000,
105
+ });
106
+ }
107
+ async has(key) {
108
+ const entry = this.cache.get(key);
109
+ if (!entry)
110
+ return false;
111
+ // Check expiration
112
+ if (Date.now() > entry.expires) {
113
+ this.cache.delete(key);
114
+ return false;
115
+ }
116
+ return true;
117
+ }
118
+ async delete(key) {
119
+ this.cache.delete(key);
120
+ }
121
+ async clear() {
122
+ this.cache.clear();
123
+ this.hits = 0;
124
+ this.misses = 0;
125
+ }
126
+ async getStats() {
127
+ const total = this.hits + this.misses;
128
+ return {
129
+ hits: this.hits,
130
+ misses: this.misses,
131
+ hitRate: total > 0 ? this.hits / total : 0,
132
+ keyCount: this.cache.size,
133
+ };
134
+ }
135
+ }
136
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Core types and interfaces for server-side TTS providers
3
+ * @module @pie-players/tts-server-core
4
+ */
5
+ export type { CacheKeyComponents, CacheStats, ITTSCache, } from "./cache.js";
6
+ export { generateCacheKey, generateHashedCacheKey, hashText, MemoryCache, } from "./cache.js";
7
+ export type { ITTSServerProvider, TTSServerConfig, } from "./provider.js";
8
+ export { BaseTTSProvider } from "./provider.js";
9
+ export { adjustSpeechMarksForRate, estimateSpeechMarks, filterSpeechMarksByType, getSpeechMarkAtTime, getSpeechMarksStats, mergeSpeechMarks, validateSpeechMarks, } from "./speech-marks.js";
10
+ export type { GetVoicesOptions, ServerProviderCapabilities, SpeechMark, StandardTTSParameters, SynthesizeMetadata, SynthesizeRequest, SynthesizeResponse, TTSProviderExtensions, Voice, VoiceFeatures, } from "./types.js";
11
+ export { TTSError, TTSErrorCode } from "./types.js";
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,YAAY,EACX,kBAAkB,EAClB,UAAU,EACV,SAAS,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,gBAAgB,EAChB,sBAAsB,EACtB,QAAQ,EACR,WAAW,GACX,MAAM,YAAY,CAAC;AAGpB,YAAY,EACX,kBAAkB,EAClB,eAAe,GACf,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EACN,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,UAAU,EACV,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,EACL,aAAa,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Core types and interfaces for server-side TTS providers
3
+ * @module @pie-players/tts-server-core
4
+ */
5
+ export { generateCacheKey, generateHashedCacheKey, hashText, MemoryCache, } from "./cache.js";
6
+ export { BaseTTSProvider } from "./provider.js";
7
+ // Export speech marks utilities
8
+ export { adjustSpeechMarksForRate, estimateSpeechMarks, filterSpeechMarksByType, getSpeechMarkAtTime, getSpeechMarksStats, mergeSpeechMarks, validateSpeechMarks, } from "./speech-marks.js";
9
+ export { TTSError, TTSErrorCode } from "./types.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EACN,gBAAgB,EAChB,sBAAsB,EACtB,QAAQ,EACR,WAAW,GACX,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,gCAAgC;AAChC,OAAO,EACN,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,GACnB,MAAM,mBAAmB,CAAC;AAc3B,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Server-side TTS Provider interface
3
+ * @module @pie-players/tts-server-core
4
+ */
5
+ import type { GetVoicesOptions, ServerProviderCapabilities, SynthesizeRequest, SynthesizeResponse, Voice } from "./types.js";
6
+ /**
7
+ * Base configuration for TTS providers
8
+ */
9
+ export interface TTSServerConfig {
10
+ /** Provider-specific configuration */
11
+ [key: string]: unknown;
12
+ }
13
+ /**
14
+ * Server-side TTS Provider interface
15
+ *
16
+ * All server-side TTS providers must implement this interface.
17
+ * Providers handle synthesis requests and return audio with speech marks.
18
+ *
19
+ * ## Initialization Performance
20
+ *
21
+ * The `initialize()` method MUST be fast and lightweight:
22
+ * - Should only validate config and create API clients
23
+ * - MUST NOT fetch voices or make expensive API calls
24
+ * - MUST NOT perform test synthesis requests
25
+ *
26
+ * Use `getVoices()` explicitly when voice discovery is needed (e.g., in demo/admin UIs).
27
+ * Runtime synthesis should work with hardcoded voice IDs without querying available voices.
28
+ *
29
+ * @example Fast initialization (runtime)
30
+ * ```typescript
31
+ * const provider = new PollyServerProvider();
32
+ * await provider.initialize({ region: 'us-east-1', defaultVoice: 'Joanna' });
33
+ * // Ready to synthesize immediately - no voices query
34
+ * await provider.synthesize({ text: 'Hello', voice: 'Joanna' });
35
+ * ```
36
+ *
37
+ * @example Explicit voice discovery (admin/demo UIs)
38
+ * ```typescript
39
+ * const provider = new PollyServerProvider();
40
+ * await provider.initialize({ region: 'us-east-1' });
41
+ * const voices = await provider.getVoices(); // Explicit, separate call
42
+ * ```
43
+ */
44
+ export interface ITTSServerProvider {
45
+ /**
46
+ * Unique provider identifier (e.g., 'aws-polly', 'google-cloud-tts')
47
+ */
48
+ readonly providerId: string;
49
+ /**
50
+ * Human-readable provider name
51
+ */
52
+ readonly providerName: string;
53
+ /**
54
+ * Provider version
55
+ */
56
+ readonly version: string;
57
+ /**
58
+ * Initialize the provider with configuration.
59
+ *
60
+ * MUST be fast and lightweight - only validates config and creates clients.
61
+ * MUST NOT fetch voices or make expensive API calls during initialization.
62
+ *
63
+ * @param config - Provider-specific configuration
64
+ * @throws {TTSError} If initialization fails
65
+ * @performance Should complete in <100ms
66
+ */
67
+ initialize(config: TTSServerConfig): Promise<void>;
68
+ /**
69
+ * Synthesize speech from text
70
+ *
71
+ * @param request - Synthesis request parameters
72
+ * @returns Audio data and speech marks
73
+ * @throws {TTSError} If synthesis fails
74
+ */
75
+ synthesize(request: SynthesizeRequest): Promise<SynthesizeResponse>;
76
+ /**
77
+ * Get available voices (explicit, secondary query).
78
+ *
79
+ * This is an EXPLICIT operation for voice discovery in demo/admin UIs.
80
+ * NOT called during initialization - call separately when needed.
81
+ *
82
+ * @param options - Optional filters for voices
83
+ * @returns List of available voices
84
+ * @throws {TTSError} If voice listing fails
85
+ * @note May take 200-500ms depending on provider
86
+ */
87
+ getVoices(options?: GetVoicesOptions): Promise<Voice[]>;
88
+ /**
89
+ * Get provider capabilities (synchronous, fast).
90
+ *
91
+ * Returns static capability information without API calls.
92
+ *
93
+ * @returns Provider feature support
94
+ * @performance Should complete in <1ms (synchronous)
95
+ */
96
+ getCapabilities(): ServerProviderCapabilities;
97
+ /**
98
+ * Clean up provider resources
99
+ * Called when provider is no longer needed
100
+ */
101
+ destroy(): Promise<void>;
102
+ }
103
+ /**
104
+ * Abstract base class for TTS providers
105
+ * Provides common functionality and helpers
106
+ */
107
+ export declare abstract class BaseTTSProvider implements ITTSServerProvider {
108
+ abstract readonly providerId: string;
109
+ abstract readonly providerName: string;
110
+ abstract readonly version: string;
111
+ protected config: TTSServerConfig;
112
+ protected initialized: boolean;
113
+ abstract initialize(config: TTSServerConfig): Promise<void>;
114
+ abstract synthesize(request: SynthesizeRequest): Promise<SynthesizeResponse>;
115
+ abstract getVoices(options?: GetVoicesOptions): Promise<Voice[]>;
116
+ abstract getCapabilities(): ServerProviderCapabilities;
117
+ destroy(): Promise<void>;
118
+ /**
119
+ * Ensure provider is initialized before operations
120
+ * @throws {TTSError} If provider not initialized
121
+ */
122
+ protected ensureInitialized(): void;
123
+ /**
124
+ * Validate synthesis request
125
+ * @throws {TTSError} If request is invalid
126
+ */
127
+ protected validateRequest(request: SynthesizeRequest, capabilities: ServerProviderCapabilities): void;
128
+ }
129
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,EACL,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,sCAAsC;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;;;;;;;;OASG;IACH,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;;;OAMG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAEpE;;;;;;;;;;OAUG;IACH,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAExD;;;;;;;OAOG;IACH,eAAe,IAAI,0BAA0B,CAAC;IAE9C;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED;;;GAGG;AACH,8BAAsB,eAAgB,YAAW,kBAAkB;IAClE,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAElC,SAAS,CAAC,MAAM,EAAE,eAAe,CAAM;IACvC,SAAS,CAAC,WAAW,UAAS;IAE9B,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3D,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAC5E,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAChE,QAAQ,CAAC,eAAe,IAAI,0BAA0B;IAEhD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B;;;OAGG;IACH,SAAS,CAAC,iBAAiB,IAAI,IAAI;IAMnC;;;OAGG;IACH,SAAS,CAAC,eAAe,CACxB,OAAO,EAAE,iBAAiB,EAC1B,YAAY,EAAE,0BAA0B,GACtC,IAAI;CAyCP"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Server-side TTS Provider interface
3
+ * @module @pie-players/tts-server-core
4
+ */
5
+ /**
6
+ * Abstract base class for TTS providers
7
+ * Provides common functionality and helpers
8
+ */
9
+ export class BaseTTSProvider {
10
+ config = {};
11
+ initialized = false;
12
+ async destroy() {
13
+ this.initialized = false;
14
+ this.config = {};
15
+ }
16
+ /**
17
+ * Ensure provider is initialized before operations
18
+ * @throws {TTSError} If provider not initialized
19
+ */
20
+ ensureInitialized() {
21
+ if (!this.initialized) {
22
+ throw new Error(`Provider ${this.providerId} not initialized`);
23
+ }
24
+ }
25
+ /**
26
+ * Validate synthesis request
27
+ * @throws {TTSError} If request is invalid
28
+ */
29
+ validateRequest(request, capabilities) {
30
+ if (!request.text || request.text.trim().length === 0) {
31
+ throw new Error("Text is required and cannot be empty");
32
+ }
33
+ if (request.text.length > capabilities.standard.maxTextLength) {
34
+ throw new Error(`Text length (${request.text.length}) exceeds maximum (${capabilities.standard.maxTextLength})`);
35
+ }
36
+ if (request.format &&
37
+ !capabilities.extensions.supportedFormats.includes(request.format)) {
38
+ throw new Error(`Format '${request.format}' not supported. Supported formats: ${capabilities.extensions.supportedFormats.join(", ")}`);
39
+ }
40
+ if (request.rate !== undefined &&
41
+ (request.rate < 0.25 || request.rate > 4.0)) {
42
+ throw new Error("Rate must be between 0.25 and 4.0");
43
+ }
44
+ if (request.pitch !== undefined &&
45
+ (request.pitch < -20 || request.pitch > 20)) {
46
+ throw new Error("Pitch must be between -20 and 20");
47
+ }
48
+ if (request.volume !== undefined &&
49
+ (request.volume < 0 || request.volume > 1)) {
50
+ throw new Error("Volume must be between 0 and 1");
51
+ }
52
+ }
53
+ }
54
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoHH;;;GAGG;AACH,MAAM,OAAgB,eAAe;IAK1B,MAAM,GAAoB,EAAE,CAAC;IAC7B,WAAW,GAAG,KAAK,CAAC;IAO9B,KAAK,CAAC,OAAO;QACZ,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IAClB,CAAC;IAED;;;OAGG;IACO,iBAAiB;QAC1B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC,UAAU,kBAAkB,CAAC,CAAC;QAChE,CAAC;IACF,CAAC;IAED;;;OAGG;IACO,eAAe,CACxB,OAA0B,EAC1B,YAAwC;QAExC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACzD,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CACd,gBAAgB,OAAO,CAAC,IAAI,CAAC,MAAM,sBAAsB,YAAY,CAAC,QAAQ,CAAC,aAAa,GAAG,CAC/F,CAAC;QACH,CAAC;QAED,IACC,OAAO,CAAC,MAAM;YACd,CAAC,YAAY,CAAC,UAAU,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EACjE,CAAC;YACF,MAAM,IAAI,KAAK,CACd,WAAW,OAAO,CAAC,MAAM,uCAAuC,YAAY,CAAC,UAAU,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrH,CAAC;QACH,CAAC;QAED,IACC,OAAO,CAAC,IAAI,KAAK,SAAS;YAC1B,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,EAC1C,CAAC;YACF,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACtD,CAAC;QAED,IACC,OAAO,CAAC,KAAK,KAAK,SAAS;YAC3B,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,EAC1C,CAAC;YACF,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACrD,CAAC;QAED,IACC,OAAO,CAAC,MAAM,KAAK,SAAS;YAC5B,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,EACzC,CAAC;YACF,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACnD,CAAC;IACF,CAAC;CACD"}