A unified interface for browser speech synthesis and Eleven Labs voices.
# Using npm
npm install speech-provider
# Using yarn
yarn add speech-provider
# Using bun
bun add speech-provider
Full API documentation is available at https://osteele.github.io/speech-provider/.
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 });
// 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.start();
}
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.
The package includes an interactive example in the examples
directory that demonstrates both browser and Eleven Labs voice providers. To run it:
examples/demo.html
directly in a browser, orbunx serve examples
and open http://localhost:3000/demo.htmlThe example includes:
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?: {
validateResponses?: boolean;
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;
The library implements efficient caching for Eleven Labs API responses using the browser's Cache API:
cacheMaxAge: null
in the provider optionsExamples 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
});
The library includes a volume normalization feature for Eleven Labs voices to ensure consistent audio levels:
normalizeVolume: true
in the provider optionsExamples 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
Interfaceinterface VoiceProvider {
name: string;
getVoices({ lang, minVoices }: { lang: string; minVoices: number }): Promise<Voice[]>;
getDefaultVoice({ lang }: { lang: string }): Promise<Voice | null>;
}
Voice
Interfaceinterface Voice {
name: string;
id: string;
lang: string;
provider: VoiceProvider;
description: string | null;
createUtterance(text: string): Utterance;
}
Utterance
Interfaceinterface Utterance {
start(): void;
stop(): void;
set onstart(callback: () => void);
set onend(callback: () => void);
}
Copyright 2025 by Oliver Steele
MIT