edge-tts-universal
Version:
Universal text-to-speech library using Microsoft Edge's online TTS service. Works in Node.js and browsers WITHOUT needing Microsoft Edge, Windows, or an API key
310 lines (303 loc) • 11 kB
TypeScript
/**
* Represents a chunk of data received during TTS streaming.
* Can contain either audio data or word boundary metadata.
*/
type TTSChunk = {
/** The type of chunk - either audio data or word boundary metadata */
type: "audio" | "WordBoundary";
/** Raw audio data buffer (present for audio chunks) */
data?: Buffer;
/** Duration of the word in 100-nanosecond units (present for WordBoundary chunks) */
duration?: number;
/** Offset from the beginning in 100-nanosecond units (present for WordBoundary chunks) */
offset?: number;
/** The spoken text (present for WordBoundary chunks) */
text?: string;
};
/**
* Voice characteristics and personality tags from the Microsoft Edge TTS service.
*/
type VoiceTag = {
/** Content categories that the voice is optimized for */
ContentCategories: ("Cartoon" | "Conversation" | "Copilot" | "Dialect" | "General" | "News" | "Novel" | "Sports")[];
/** Personality traits that describe the voice's characteristics */
VoicePersonalities: ("Approachable" | "Authentic" | "Authority" | "Bright" | "Caring" | "Casual" | "Cheerful" | "Clear" | "Comfort" | "Confident" | "Considerate" | "Conversational" | "Cute" | "Expressive" | "Friendly" | "Honest" | "Humorous" | "Lively" | "Passion" | "Pleasant" | "Positive" | "Professional" | "Rational" | "Reliable" | "Sincere" | "Sunshine" | "Warm")[];
};
/**
* Complete voice definition as returned by the Microsoft Edge TTS service.
*/
type Voice = {
/** Full voice name identifier */
Name: string;
/** Short name for the voice */
ShortName: string;
/** Gender of the voice */
Gender: "Female" | "Male";
/** Locale code (e.g., "en-US", "zh-CN") */
Locale: string;
/** Recommended audio codec for this voice */
SuggestedCodec: "audio-24khz-48kbitrate-mono-mp3";
/** Human-readable friendly name */
FriendlyName: string;
/** Voice availability status */
Status: "GA";
/** Voice characteristics and personality traits */
VoiceTag: VoiceTag;
};
/**
* Extended voice type with language information for the VoicesManager.
*/
type VoicesManagerVoice = Voice & {
/** Language code extracted from the locale (e.g., "en" from "en-US") */
Language: string;
};
/**
* Filter criteria for finding voices using the VoicesManager.
*/
type VoicesManagerFind = {
/** Filter by voice gender */
Gender?: "Female" | "Male";
/** Filter by locale code */
Locale?: string;
/** Filter by language code */
Language?: string;
};
/**
* Internal state tracking for the Communicate class during streaming.
*/
type CommunicateState = {
/** Buffer for partial text data */
partialText: Buffer;
/** Timing offset compensation for multi-request scenarios */
offsetCompensation: number;
/** Last recorded duration offset for timing calculations */
lastDurationOffset: number;
/** Flag indicating if the stream method has been called */
streamWasCalled: boolean;
};
/**
* Utility class for generating SRT subtitles from WordBoundary events.
*
* @example
* ```typescript
* const subMaker = new SubMaker();
*
* for await (const chunk of communicate.stream()) {
* if (chunk.type === 'WordBoundary') {
* subMaker.feed(chunk);
* }
* }
*
* const srt = subMaker.getSrt();
* ```
*/
declare class SubMaker {
private cues;
/**
* Adds a WordBoundary chunk to the subtitle maker.
*
* @param msg - Must be a WordBoundary type chunk with offset, duration, and text
* @throws {ValueError} If chunk is not a WordBoundary with required fields
*/
feed(msg: TTSChunk): void;
/**
* Merges consecutive cues to create subtitle entries with multiple words.
* This is useful for creating more readable subtitles instead of word-by-word display.
*
* @param words - Maximum number of words per merged cue
* @throws {ValueError} If words parameter is invalid
*/
mergeCues(words: number): void;
/**
* Returns the subtitles in SRT format.
*
* @returns SRT formatted subtitles
*/
getSrt(): string;
toString(): string;
}
interface IsomorphicTTSChunk {
type: "audio" | "WordBoundary";
data?: Uint8Array;
duration?: number;
offset?: number;
text?: string;
}
/**
* Configuration options for the isomorphic Communicate class.
*/
interface IsomorphicCommunicateOptions {
/** Voice to use for synthesis (e.g., "en-US-EmmaMultilingualNeural") */
voice?: string;
/** Speech rate adjustment (e.g., "+20%", "-10%") */
rate?: string;
/** Volume level adjustment (e.g., "+50%", "-25%") */
volume?: string;
/** Pitch adjustment in Hz (e.g., "+5Hz", "-10Hz") */
pitch?: string;
/** Proxy URL for requests (Node.js only) */
proxy?: string;
/** WebSocket connection timeout in milliseconds */
connectionTimeout?: number;
}
/**
* Isomorphic Communicate class that works in both Node.js and browsers.
* Uses isomorphic packages to provide consistent functionality across environments.
*
* @example
* ```typescript
* // Works in both Node.js and browsers (with CORS considerations)
* const communicate = new IsomorphicCommunicate('Hello, world!', {
* voice: 'en-US-EmmaMultilingualNeural',
* });
*
* for await (const chunk of communicate.stream()) {
* if (chunk.type === 'audio' && chunk.data) {
* // Handle audio data
* }
* }
* ```
*/
declare class IsomorphicCommunicate {
private readonly ttsConfig;
private readonly texts;
private readonly proxy?;
private readonly connectionTimeout?;
private readonly isNode;
private state;
/**
* Creates a new isomorphic Communicate instance for text-to-speech synthesis.
*
* @param text - The text to synthesize
* @param options - Configuration options for synthesis
*/
constructor(text: string, options?: IsomorphicCommunicateOptions);
private parseMetadata;
private createWebSocket;
private _stream;
/**
* Streams text-to-speech synthesis results using isomorphic WebSocket.
* Works in both Node.js and browsers (subject to CORS policy).
*
* @yields TTSChunk - Audio data or word boundary information
* @throws {Error} If called more than once
* @throws {NoAudioReceived} If no audio data is received
* @throws {WebSocketError} If WebSocket connection fails
*/
stream(): AsyncGenerator<IsomorphicTTSChunk, void, unknown>;
}
/**
* Error class for fetch-related errors (isomorphic equivalent of AxiosError)
*/
declare class FetchError extends Error {
response?: {
status: number;
headers: Record<string, string>;
};
constructor(message: string, response?: {
status: number;
headers: Record<string, string>;
});
}
/**
* Fetches all available voices from the Microsoft Edge TTS service (isomorphic version).
* Works in both Node.js and browsers (subject to CORS policy).
*
* @param proxy - Optional proxy URL for the request (limited browser support)
* @returns Promise resolving to array of available voices
*/
declare function listVoices(proxy?: string): Promise<Voice[]>;
/**
* Isomorphic utility class for finding and filtering available voices.
* Works in both Node.js and browsers (subject to CORS policy).
*
* @example
* ```typescript
* const voicesManager = await IsomorphicVoicesManager.create();
* const englishVoices = voicesManager.find({ Language: 'en' });
* ```
*/
declare class IsomorphicVoicesManager {
private voices;
private calledCreate;
/**
* Creates a new IsomorphicVoicesManager instance.
*
* @param customVoices - Optional custom voice list instead of fetching from API
* @param proxy - Optional proxy URL for API requests (limited browser support)
* @returns Promise resolving to IsomorphicVoicesManager instance
*/
static create(customVoices?: Voice[], proxy?: string): Promise<IsomorphicVoicesManager>;
/**
* Finds voices matching the specified criteria.
*
* @param filter - Filter criteria for voice selection
* @returns Array of voices matching the filter
* @throws {Error} If called before create()
*/
find(filter: VoicesManagerFind): VoicesManagerVoice[];
}
/**
* Isomorphic DRM class that works in both Node.js and browsers.
* Uses appropriate crypto APIs based on the environment.
*/
declare class IsomorphicDRM {
private static clockSkewSeconds;
static adjClockSkewSeconds(skewSeconds: number): void;
static getUnixTimestamp(): number;
static parseRfc2616Date(date: string): number | null;
static handleClientResponseError(response: Response | {
status: number;
headers: Record<string, string>;
}): void;
static generateSecMsGec(): Promise<string>;
}
/**
* Base exception class for all Edge TTS related errors.
*/
declare class EdgeTTSException extends Error {
constructor(message: string);
}
/**
* Exception raised when there's an error adjusting clock skew for API requests.
* This typically occurs when the client and server clocks are significantly out of sync.
*/
declare class SkewAdjustmentError extends EdgeTTSException {
constructor(message: string);
}
/**
* Exception raised when an unknown response is received from the TTS service.
* This indicates an unexpected message type or format that the client cannot handle.
*/
declare class UnknownResponse extends EdgeTTSException {
constructor(message: string);
}
/**
* Exception raised when an unexpected response is received from the TTS service.
* This indicates a response that doesn't match the expected protocol flow.
*/
declare class UnexpectedResponse extends EdgeTTSException {
constructor(message: string);
}
/**
* Exception raised when no audio data is received during synthesis.
* This typically indicates a problem with the synthesis request or service.
*/
declare class NoAudioReceived extends EdgeTTSException {
constructor(message: string);
}
/**
* Exception raised when there's an error with the WebSocket connection.
* This can occur during connection establishment, data transmission, or connection closure.
*/
declare class WebSocketError extends EdgeTTSException {
constructor(message: string);
}
/**
* Exception raised when an invalid value is provided to a function or method.
* This is typically used for input validation errors.
*/
declare class ValueError extends EdgeTTSException {
constructor(message: string);
}
export { type CommunicateState as C, EdgeTTSException as E, FetchError as F, IsomorphicCommunicate as I, NoAudioReceived as N, SubMaker as S, type TTSChunk as T, UnknownResponse as U, type Voice as V, WebSocketError as W, type VoicesManagerFind as a, type VoicesManagerVoice as b, type IsomorphicCommunicateOptions as c, IsomorphicVoicesManager as d, IsomorphicDRM as e, SkewAdjustmentError as f, UnexpectedResponse as g, ValueError as h, type VoiceTag as i, listVoices as l };