speech-provider
v0.2.1
Published
A unified interface for browser speech synthesis and Eleven Labs voices
Maintainers
Readme
speech-provider
A unified interface for browser speech synthesis and Eleven Labs voices.
Installation
# Using npm
npm install speech-provider
# Using yarn
yarn add speech-provider
# Using bun
bun add speech-providerDocumentation
Full API documentation is available at https://osteele.github.io/speech-provider/.
Usage
import { getVoiceProvider } from 'speech-provider';
// Use browser voices only
const provider = getVoiceProvider({});
// Use Eleven Labs voices if API key is available
const provider = getVoiceProvider({ elevenLabsApiKey: 'your-api-key' });
// Use Eleven Labs with custom cache duration
const provider = getVoiceProvider({
elevenLabsApiKey: 'your-api-key',
cacheMaxAge: 86400 // Cache for 1 day
});
// Use Eleven Labs with volume normalization
const provider = getVoiceProvider({
elevenLabsApiKey: 'your-api-key',
normalizeVolume: true // Enable volume normalization
});
// Get voices for a specific language
const voices = await provider.getVoices({ lang: 'en-US', minVoices: 1 });
// Explicitly fall back to unrelated voices when no language match exists
const fallbackVoices = await provider.getVoices({
lang: 'en-US',
minVoices: 1,
fallbackToAnyLanguage: true
});
// Get default voice for a language
const defaultVoice = await provider.getDefaultVoice({ lang: 'en-US' });
// Create and play an utterance
if (defaultVoice) {
const utterance = defaultVoice.createUtterance('Hello, world!');
utterance.onstart = () => console.log('Started speaking');
utterance.onend = () => console.log('Finished speaking');
utterance.onerror = error => console.error(error);
await utterance.start();
}Features
- Unified interface for both browser speech synthesis and Eleven Labs voices
- Automatic fallback to browser voices when Eleven Labs API key is not provided
- Typesafe API with TypeScript support
- Simple voice selection by language
- Event listeners for speech start, end, and error events
- Cancellable Eleven Labs requests and playback
- Efficient caching of Eleven Labs API responses using the browser's Cache API
- Configurable cache duration for Eleven Labs responses
- Audio volume normalization for Eleven Labs voices to ensure consistent volume levels
Used In
This package is used in Mandarin Sentence Practice, a web application for practicing Mandarin Chinese with listening and translation exercises. The app uses this package to provide high-quality text-to-speech for Mandarin sentences, with automatic fallback to browser voices when Eleven Labs is not available.
Examples
The package includes an interactive example in the examples directory that demonstrates both browser and Eleven Labs voice providers. To run it:
- View the live demo, or
- Open
examples/demo.htmldirectly in a browser, or - Run
bunx serve examplesand open http://localhost:3000/demo.html
The example includes:
- Session-only API key management for Eleven Labs
- Provider selection (Browser/Eleven Labs)
- Language selection with system language detection
- Voice selection with descriptions
- Example sentences in multiple languages
- Text-to-speech controls
- Volume normalization for Eleven Labs voices
API
getVoiceProvider(options)
Creates a voice provider based on the available API keys. Falls back to browser speech synthesis if no API keys are provided.
function getVoiceProvider(options: {
elevenLabsApiKey?: string | null;
cacheMaxAge?: number | null; // Cache duration in seconds (default: 1 hour). Set to null to disable caching.
normalizeVolume?: boolean; // Enable volume normalization for Eleven Labs voices (default: false)
}): VoiceProvider;createElevenLabsVoiceProvider(apiKey, options?)
Creates an Eleven Labs voice provider with optional configuration.
function createElevenLabsVoiceProvider(
apiKey: string,
baseUrl?: string,
options?: {
printVoiceProperties?: boolean;
cacheMaxAge?: number | null; // Cache duration in seconds (default: 1 hour). Set to null to disable caching.
normalizeVolume?: boolean; // Enable volume normalization for more consistent audio levels (default: false)
}
): VoiceProvider;Caching
The library implements efficient caching for Eleven Labs API responses using the browser's Cache API:
- Browser voices are cached automatically by the browser's speech synthesis engine
- Eleven Labs responses are cached using the browser's Cache API with a default duration of 1 hour
- Cache duration can be configured when creating the provider
- Cached responses are automatically invalidated after the specified duration
- Cache keys use SHA-256 fingerprints and do not store raw API keys or utterance text
- Cache can be disabled by setting
cacheMaxAge: nullin the provider options - The Cache API provides better performance than IndexedDB for network requests
Examples of cache configuration:
// Use default 1-hour cache
const provider = getVoiceProvider({ elevenLabsApiKey: 'your-api-key' });
// Cache for 1 day
const provider = getVoiceProvider({
elevenLabsApiKey: 'your-api-key',
cacheMaxAge: 86400 // 24 hours in seconds
});
// Cache for 1 week
const provider = getVoiceProvider({
elevenLabsApiKey: 'your-api-key',
cacheMaxAge: 604800 // 7 days in seconds
});
// Disable caching (preferred approach)
const provider = getVoiceProvider({
elevenLabsApiKey: 'your-api-key',
cacheMaxAge: null
});
// Alternative way to disable caching
const provider = getVoiceProvider({
elevenLabsApiKey: 'your-api-key',
cacheMaxAge: 0
});Language matching
Language tags are matched using BCP-47 primary languages, so regional variants
such as en-US and en-GB can match when an exact regional voice is not
available. Unrelated voices are excluded by default. Set
fallbackToAnyLanguage: true to request the previous cross-language fallback
behavior when fewer than minVoices matches are available.
Volume Normalization
The library includes a volume normalization feature for Eleven Labs voices to ensure consistent audio levels:
- Automatically normalizes audio volume during playback using the Web Audio API
- Helps maintain consistent volume levels across different voices and utterances
- Uses a dynamics compressor to balance loud and quiet sections of audio
- Can be enabled by setting
normalizeVolume: truein the provider options
Examples of volume normalization configuration:
// Enable volume normalization
const provider = getVoiceProvider({
elevenLabsApiKey: 'your-api-key',
normalizeVolume: true
});
// Enable volume normalization with custom cache settings
const provider = getVoiceProvider({
elevenLabsApiKey: 'your-api-key',
normalizeVolume: true,
cacheMaxAge: 86400 // 24 hours in seconds
});
// Direct use with ElevenLabsVoiceProvider
const provider = createElevenLabsVoiceProvider('your-api-key', undefined, {
normalizeVolume: true
});VoiceProvider Interface
interface VoiceProvider {
name: string;
getVoices(options: {
lang: string;
minVoices: number;
fallbackToAnyLanguage?: boolean;
}): Promise<Voice[]>;
getDefaultVoice({ lang }: { lang: string }): Promise<Voice | null>;
}Voice Interface
interface Voice {
name: string;
id: string;
lang: string;
provider: VoiceProvider;
description: string | null;
createUtterance(text: string): Utterance;
}Utterance Interface
interface Utterance {
start(): Promise<void>;
stop(): Promise<void>;
set onstart(callback: () => void);
set onend(callback: () => void);
set onerror(callback: (error: Error) => void);
}Browser Compatibility
Browser Speech Synthesis
The browser speech synthesis provider (BrowserVoiceProvider) is supported in all modern browsers:
- Chrome/Edge: Full support (voices load asynchronously)
- Firefox: Full support
- Safari: Full support (iOS and macOS)
- Opera: Full support
Note: Voice availability and quality vary by browser and operating system. Chrome and Edge typically offer the best selection of voices.
ElevenLabs Provider
The ElevenLabs provider (ElevenLabsVoiceProvider) requires:
- Cache API: For caching API responses (supported in modern browsers)
- Fetch API: For making API requests (supported in all modern browsers)
- Audio API: For playing synthesized speech (supported in all modern browsers)
Minimum Requirements
- Modern browser with ES2022 support
- Cache API support (for ElevenLabs caching)
- No Internet Explorer support
Server-Side Rendering (SSR)
The library is designed for client-side use. When used in SSR environments:
- Browser voice provider gracefully handles the absence of
window.speechSynthesis - Returns empty arrays when browser APIs are unavailable
- Safe to import in SSR frameworks (Next.js, Nuxt, etc.) but should only be used client-side
Contributing
Contributions are welcome! Please read the CONTRIBUTING.md guide for details on our code of conduct and the process for submitting pull requests.
Changelog
See CHANGELOG.md for a list of changes and version history.
License
Copyright 2025 by Oliver Steele
MIT
