@andresaya/edge-tts

中文文档
1.9.1发布于 2026/10/13GPL-3.0-onlyTypeScriptCommonJS近 30 天下载 9万

Edge TTS is a package that allows access to the online text-to-speech service used by Microsoft Edge without the need for Microsoft Edge, Windows, or an API key.

原始使用文档
文档目录33 节
  1. Available in three languages
  2. Features
  3. Installation
  4. TypeScript Support
  5. Available Types
  6. Type-Safe Usage Example
  7. Usage
  8. Command-Line Interface
  9. Integration into Your Project
  10. Configuration
  11. API Reference
  12. Voice Management
  13. Text Synthesis
  14. Audio Information
  15. Export Options
  16. Word and Sentence Boundaries
  17. Subtitles
  18. Examples
  19. Complete Example with Voice Selection
  20. Streaming Example
  21. Voice Exploration Example
  22. Browser Support
  23. CDN Usage (UMD)
  24. ES Module Import
  25. Streaming Support in Browser
  26. Other Browsers (Relay)
  27. Complete Browser Example
  28. Voice Options
  29. Synthesis Parameters
  30. Parameter Examples
  31. Error Handling
  32. License
  33. Acknowledgments

Edge TTS

Ask DeepWiki

Edge TTS is a powerful Text-to-Speech (TTS) package that leverages Microsoft's Edge capabilities. This package allows you to synthesize speech from text and manage voice options easily through a command-line interface (CLI).

Available in three languages

The same library for the Edge text-to-speech service, in Node.js, PHP and Go:

LanguageInstallRepository
Node.js and browsers (this one)npm install @andresaya/edge-ttsandresayac/edge-tts
PHPcomposer require afaya/edge-ttsandresayac/edge-tts-php
Gogo get github.com/andresayac/edge-tts-goandresayac/edge-tts-go

Features

  • Text-to-Speech: Convert text into natural-sounding speech using Microsoft Edge's TTS capabilities.
  • TypeScript Support: Full TypeScript support with comprehensive type definitions included.
  • Audio Formats: MP3 at 48 or 96 kbit/s, and WebM/Opus.
  • Multiple Voices: Access a variety of voices to suit your project's needs.
  • Voice Filtering: Filter voices by language and gender for better selection.
  • Audio Information: Get detailed information about generated audio (size, duration, format).
  • Audio Export Options: Export synthesized audio in different formats (raw, base64, or directly to a file).
  • Streaming Support: Stream audio data in real-time for better performance.
  • Word and Sentence Boundaries: Get word and sentence timings with precise timestamps.
  • Subtitles: Generate SRT or WebVTT subtitles, one cue per sentence.
  • Concurrent Use: generate() returns its own result, so one instance can run several syntheses at once.
  • Configurable: Override the endpoint, headers, timeout and voice cache without waiting for a release.
  • Command-Line Interface: Use a simple CLI for easy access to functionality.
  • Easy Integration: Modular structure allows for easy inclusion in existing projects.

Installation

You can install Edge TTS via npm or bun:

bun add @andresaya/edge-tts
npm install @andresaya/edge-tts

Tested on Node.js 18, 20 and 24, and on Bun.

TypeScript Support

Edge TTS is written in TypeScript and includes full type definitions. No additional @types packages are needed.

Available Types

import { 
    EdgeTTS, 
    EdgeTTSError,
    Constants,
    Voice,
    SynthesisOptions,
    SynthesisResult,
    EdgeTTSOptions,
    WordBoundary,
    SentenceBoundary
} from '@andresaya/edge-tts';

// Voice interface
interface Voice {
    Name: string;
    ShortName: string;
    Gender: string;               // 'Male' | 'Female'
    Locale: string;
    FriendlyName: string;
    LocalName: string;
    DisplayName?: string;
    LocaleName?: string;
    VoiceType?: string;
    SecondaryLocaleList?: string[];
    VoiceTag?: { TailoredScenarios: string[]; VoicePersonalities: string[] };
}

// Synthesis options
interface SynthesisOptions {
    pitch?: string | number;       // e.g., '+20Hz' or 20
    rate?: string | number;        // e.g., '50%' or 50
    volume?: string | number;      // e.g., '90%' or 90
    outputFormat?: string;         // e.g., Constants.OUTPUT_FORMAT.AUDIO_24KHZ_96KBITRATE_MONO_MP3
    signal?: AbortSignal;          // cancels the synthesis
    timeout?: number;              // inactivity timeout in ms for this call
}

// Word and sentence boundary metadata (offset and duration in 100 ns ticks)
interface WordBoundary {
    type: "WordBoundary";
    offset: number;
    duration: number;
    text: string;
}

interface SentenceBoundary {
    type: "SentenceBoundary";
    offset: number;
    duration: number;
    text: string;
}

// Returned by generate()
interface SynthesisResult {
    audio: Uint8Array;            // a Buffer in Node.js
    format: string;               // file extension: 'mp3' or 'webm'
    outputFormat: string;
    wordBoundaries: WordBoundary[];
    sentenceBoundaries: SentenceBoundary[];
    duration: number;             // estimated, in seconds
}

Type-Safe Usage Example

import { EdgeTTS, SynthesisOptions, Constants } from '@andresaya/edge-tts';

const tts = new EdgeTTS();

const options: SynthesisOptions = {
    pitch: '+10Hz',
    rate: '100%',
    volume: '90%',
    outputFormat: Constants.OUTPUT_FORMAT.WEBM_24KHZ_16BIT_MONO_OPUS
};

await tts.synthesize("TypeScript example", 'en-US-AriaNeural', options);

const info = tts.getAudioInfo(); // Returns: { size: number; format: string; estimatedDuration: number }
const boundaries = tts.getWordBoundaries(); // Returns: WordBoundary[]

Usage

Command-Line Interface

Install globally to use the CLI:

npm install -g @andresaya/edge-tts

To synthesize speech from text:

edge-tts synthesize -t "Hello, world!" -o hello_world_audio

Other options:

# Choose the voice, read the text from a file, write subtitles too
edge-tts synthesize -f story.txt -v es-CO-SalomeNeural -o story.mp3 --subtitles story.srt

# Read from stdin, WebM/Opus output, WebVTT subtitles
cat story.txt | edge-tts synthesize -f - --format webm-24khz-16bit-mono-opus -o story --subtitles story.vtt

To list available voices, optionally filtered:

edge-tts voice-list
edge-tts voice-list --locale es-CO --gender female

Integration into Your Project

import { EdgeTTS } from '@andresaya/edge-tts';

// Initialize the EdgeTTS service
const tts = new EdgeTTS();

Configuration

Every option is optional. The defaults come from Constants, so when Microsoft changes the service you can point the library at the new values yourself instead of waiting for a release.

const tts = new EdgeTTS({
    wssUrl: 'wss://api.msedgeservices.com/tts/cognitiveservices/websocket/v1',
    voicesUrl: 'https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list',
    secMsGecVersion: '1-155.0.4283.45',
    headers: { 'User-Agent': '...' },   // Node.js only, added to the default headers
    timeout: 30000,                     // ms without data before giving up
    voicesCacheTtl: 600000,             // ms to reuse the voice list, 0 to always fetch it
});

If the computer's clock is off, the service refuses the connection. In Node.js the library then reads the time from the server and retries once.

API Reference

Voice Management

Get All Voices

const voices = await tts.getVoices();
console.log(`Found ${voices.length} voices`);

Filter Voices by Language

// Get all English voices
const englishVoices = await tts.getVoicesByLanguage('en');

// Get specific locale voices
const usEnglishVoices = await tts.getVoicesByLanguage('en-US');

Filter Voices by Gender

// Get all female voices
const femaleVoices = await tts.getVoicesByGender('Female');

// Get all male voices
const maleVoices = await tts.getVoicesByGender('Male');

Text Synthesis

Basic Synthesis

// Simple synthesis with default voice
await tts.synthesize("Hello, world!");

// Synthesis with specific voice
await tts.synthesize("Hello, world!", 'en-US-AriaNeural');

Matching the voice to the text

Voices are locale specific. A voice can only read text written in the script of its own language, so passing Chinese, Cyrillic, Arabic or Devanagari text to an English voice returns no audio at all:

// Nothing to play: an English voice cannot read this.
await tts.synthesize("这是一个测试", 'en-US-AriaNeural');

// Works.
await tts.synthesize("这是一个测试", 'zh-CN-XiaoxiaoNeural');

A few foreign words inside an otherwise English sentence are fine; the problem only appears when the other script is most of the text. toBuffer() throws in this case rather than handing back an empty buffer.

Advanced Synthesis with Options

await tts.synthesize("Hello, world!", 'en-US-AriaNeural', {
    rate: '50%',           // Speech rate: -100% to +200% (or number)
    volume: '90%',         // Speech volume: -100% to +100% (or number)
    pitch: '+20Hz',        // Voice pitch: -100Hz to +100Hz (or number)
    outputFormat: 'audio-24khz-96kbitrate-mono-mp3'  // Audio output format
});

Independent Results with generate()

synthesize() keeps the audio on the instance, so two calls at the same time on one instance overwrite each other. generate() returns everything in its own result instead and leaves the instance alone:

const [hello, bye] = await Promise.all([
    tts.generate("Hello!", 'en-US-AriaNeural'),
    tts.generate("Goodbye!", 'en-US-AriaNeural'),
]);

hello.audio;              // Buffer in Node.js, Uint8Array in the browser
hello.format;             // 'mp3'
hello.duration;           // estimated seconds
hello.wordBoundaries;     // WordBoundary[]
hello.sentenceBoundaries; // SentenceBoundary[]

Audio Output Formats

You can specify the format using the outputFormat option:

import { EdgeTTS, Constants } from '@andresaya/edge-tts';

const tts = new EdgeTTS();

// High quality MP3
await tts.synthesize("Hello!", 'en-US-AriaNeural', {
    outputFormat: Constants.OUTPUT_FORMAT.AUDIO_24KHZ_96KBITRATE_MONO_MP3
});
await tts.toFile('./output/audio'); // Automatically saved as .mp3

// WebM/Opus for web
await tts.synthesize("Hello!", 'en-US-AriaNeural', {
    outputFormat: Constants.OUTPUT_FORMAT.WEBM_24KHZ_16BIT_MONO_OPUS
});
await tts.toFile('./output/audio'); // Automatically saved as .webm

Available formats:

ConstantValue
AUDIO_24KHZ_48KBITRATE_MONO_MP3 (default)audio-24khz-48kbitrate-mono-mp3
AUDIO_24KHZ_96KBITRATE_MONO_MP3audio-24khz-96kbitrate-mono-mp3
WEBM_24KHZ_16BIT_MONO_OPUSwebm-24khz-16bit-mono-opus

The service returns no audio for other formats, such as WAV, PCM or other MP3 bitrates.

Streaming Synthesis

// Stream audio data in real-time
for await (const chunk of tts.synthesizeStream("Long text to stream...", 'en-US-AriaNeural')) {
    // Process each audio chunk as it arrives
    console.log(`Received chunk: ${chunk.length} bytes`);
}

Leaving the loop early with break closes the connection.

Cancelling and Timeouts

const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);

try {
    await tts.synthesize("Hello!", 'en-US-AriaNeural', { signal: controller.signal, timeout: 10000 });
} catch (error) {
    if (error.name === 'AbortError') console.log('Cancelled');
}

signal works with synthesize(), synthesizeStream() and generate(). timeout is how long to wait without receiving data, 30 seconds by default.

Audio Information

Get Audio Details

await tts.synthesize("Hello, world!");

const audioInfo = tts.getAudioInfo();
console.log(`Size: ${audioInfo.size} bytes`);
console.log(`Format: ${audioInfo.format}`);
console.log(`Duration: ${audioInfo.estimatedDuration} seconds`);

Get Duration Only

const duration = tts.getDuration();
console.log(`Audio duration: ${duration} seconds`);

Export Options

Export as Base64

await tts.synthesize("Hello, world!");
const base64Audio = tts.toBase64();
console.log(`Base64 length: ${base64Audio.length}`);

Export as Raw Buffer

const rawAudio = tts.toRaw(); // Alias for toBase64()
const buffer = tts.toBuffer(); // Get as Buffer object

Export to File

const filePath = await tts.toFile("output_audio");
console.log(`Audio saved to: ${filePath}`);
// Creates: output_audio.mp3

await tts.toFile("speech.mp3"); // Creates: speech.mp3 (the extension is not repeated)

Word and Sentence Boundaries

Offsets and durations are in 100-nanosecond ticks (10,000,000 per second).

await tts.synthesize("Hello, world. How are you?", 'en-US-AriaNeural');

const words = tts.getWordBoundaries();         // [{ type: 'WordBoundary', offset, duration, text: 'Hello' }, ...]
const sentences = tts.getSentenceBoundaries(); // [{ type: 'SentenceBoundary', offset, duration, text: 'Hello, world.' }, ...]

// Save word boundaries to a JSON file
await tts.saveMetadata('metadata.json');

Subtitles

One cue per sentence, with the punctuation of the original text.

import { writeFile } from 'fs/promises';
import { toSRT, toVTT } from '@andresaya/edge-tts';

await tts.synthesize("¿Hola? Esto es una prueba.", 'es-CO-SalomeNeural');
await writeFile('speech.srt', tts.toSRT());
await writeFile('speech.vtt', tts.toVTT());

// From a generate() result
const result = await tts.generate("Hello, world.", 'en-US-AriaNeural');
await writeFile('hello.srt', toSRT(result.sentenceBoundaries));

Examples

Complete Example with Voice Selection

import { EdgeTTS } from '@andresaya/edge-tts';

async function textToSpeechExample() {
    const tts = new EdgeTTS();
    
    // Get available English voices
    const englishVoices = await tts.getVoicesByLanguage('en-US');
    console.log(`Available English voices: ${englishVoices.length}`);
    
    // Use the first available voice
    const voice = englishVoices[0];
    console.log(`Using voice: ${voice.FriendlyName}`);
    
    // Synthesize with custom options
    await tts.synthesize(
        "This is a test of the Edge TTS system with custom voice parameters.",
        voice.ShortName,
        {
            pitch: '+10Hz',
            rate: '-10%',
            volume: '90%'
        }
    );
    
    // Get audio information
    const info = tts.getAudioInfo();
    console.log(`Generated audio: ${info.size} bytes, ${info.estimatedDuration.toFixed(2)}s`);
    
    // Save to file
    const outputPath = await tts.toFile('./output/speech');
    console.log(`Audio saved to: ${outputPath}`);
}

textToSpeechExample().catch(console.error);

Streaming Example

import { EdgeTTS } from '@andresaya/edge-tts';
import { createWriteStream } from 'fs';

async function streamingExample() {
    const tts = new EdgeTTS();
    const writeStream = createWriteStream('streaming_output.mp3');
    
    const longText = "This is a very long text that will be streamed...";
    
    for await (const chunk of tts.synthesizeStream(longText, 'en-US-AriaNeural')) {
        writeStream.write(chunk);
        console.log(`Streamed ${chunk.length} bytes`);
    }
    
    writeStream.end();
    console.log('Streaming completed!');
}

streamingExample().catch(console.error);

Voice Exploration Example

import { EdgeTTS } from '@andresaya/edge-tts';

async function exploreVoices() {
    const tts = new EdgeTTS();
    
    // Get all voices
    const allVoices = await tts.getVoices();
    console.log(`Total voices available: ${allVoices.length}`);
    
    // Group by language
    const languages = [...new Set(allVoices.map(v => v.Locale.split('-')[0]))];
    console.log(`Languages available: ${languages.join(', ')}`);
    
    // Get Spanish voices
    const spanishVoices = await tts.getVoicesByLanguage('es');
    console.log(`Spanish voices: ${spanishVoices.length}`);
    
    // Get female voices
    const femaleVoices = await tts.getVoicesByGender('Female');
    console.log(`Female voices: ${femaleVoices.length}`);
    
    // Test different voices
    const testText = "Hola, este es un ejemplo de síntesis de voz.";
    
    for (const voice of spanishVoices.slice(0, 3)) {
        console.log(`Testing voice: ${voice.FriendlyName}`);
        
        await tts.synthesize(testText, voice.ShortName);
        const filePath = await tts.toFile(`./voices/${voice.ShortName}`);
        
        console.log(`Saved: ${filePath}`);
    }
}

exploreVoices().catch(console.error);

Browser Support

This library can be used directly in web browsers via CDN or ES modules.

⚠️ Important: Connecting directly, synthesis only works in Microsoft Edge. The speech service refuses connections whose user agent is not Edge, and a web page cannot change the user agent its browser sends. Chrome, Firefox and Safari get a 403 when synthesizing. For those browsers, use a relay (see Other Browsers). The Node.js version is not affected.

CDN Usage (UMD)

<!-- Load from CDN -->
<script src="https://unpkg.com/@andresaya/edge-tts@latest/dist/browser/edge-tts.umd.min.js"></script>

<script>
  const tts = new EdgeTTS();
  
  // Get available voices
  tts.getVoices().then(voices => {
    console.log('Available voices:', voices.length);
  });
  
  // Synthesize speech
  async function speak() {
    await tts.synthesize("Hello from the browser!", 'en-US-AriaNeural');
    const audioData = tts.getAudioData();
    
    // Play audio
    const audioBlob = new Blob([audioData], { type: 'audio/mp3' });
    const audioUrl = URL.createObjectURL(audioBlob);
    const audio = new Audio(audioUrl);
    audio.play();
  }
</script>

ES Module Import

<script type="module">
  import { EdgeTTS } from 'https://unpkg.com/@andresaya/edge-tts@latest/dist/browser/edge-tts.esm.min.js';
  
  const tts = new EdgeTTS();
  
  // Use the library
  const voices = await tts.getVoices();
  console.log(voices);
</script>

Streaming Support in Browser

<script type="module">
  import { EdgeTTS } from 'https://unpkg.com/@andresaya/edge-tts@latest/dist/browser/edge-tts.esm.min.js';
  
  const tts = new EdgeTTS();
  const chunks = [];
  
  // Stream audio chunks in real-time
  for await (const chunk of tts.synthesizeStream("Long text to stream...", 'en-US-AriaNeural')) {
    chunks.push(chunk);
    console.log(`Received chunk: ${chunk.length} bytes`);
  }
  
  // Combine and play all chunks
  const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
  const audioData = new Uint8Array(totalLength);
  let offset = 0;
  for (const chunk of chunks) {
    audioData.set(chunk, offset);
    offset += chunk.length;
  }
  
  const blob = new Blob([audioData], { type: 'audio/mp3' });
  const audio = new Audio(URL.createObjectURL(blob));
  audio.play();
</script>

Other Browsers (Relay)

A small relay running in Node.js connects to the service with Edge's headers and passes the messages through. Start the example relay:

node examples/relay-server.mjs   # ws://127.0.0.1:8080

And point the browser at it:

const tts = new EdgeTTS({ wssUrl: 'ws://127.0.0.1:8080' });
await tts.synthesize("Hello from Chrome!", 'en-US-AriaNeural');

The example only listens on 127.0.0.1. If you deploy it, put it behind your own authentication or origin check so it is not open to everyone.

Complete Browser Example

For a full working example with voice selection and synthesis, see examples/browser-standalone.html.

Voice Options

Synthesis Parameters

ParameterTypeRangeDescription
pitchstring | number-100Hz to +100HzVoice pitch adjustment
ratestring | number-100% to +200%Speech rate adjustment
volumestring | number-100% to +100%Volume adjustment

Parameter Examples


// Using numbers (recommended)
{ pitch: 20, rate: -10, volume: 90 }

// Using strings
{ pitch: '+20Hz', rate: '-10%', volume: '90%' }

// Mixed usage
{ pitch: 15, rate: '25%', volume: 85 }

Error Handling

Errors raised by the library are EdgeTTSError instances with a code. Network errors from Node.js (such as ECONNREFUSED) are passed through unchanged.

codeWhen
HANDSHAKEThe service refused the connection. status holds the HTTP status in Node.js (usually 403).
NETWORKThe connection failed after it was open (browser).
TIMEOUTNo data arrived for timeout ms.
NO_AUDIONo synthesis yet, or the service returned no audio (voice and text in different scripts, or a text of only punctuation).
REFUSEDThe service refused the request and said why, such as Unsupported voice xx-XX-NobodyNeural. or an unsupported output format. status holds the WebSocket close code (1007).
INVALID_OPTIONThe text is empty, or pitch, rate or volume is not valid.
VOICESThe voice list request failed. status holds the HTTP status.

Cancelling with an AbortSignal rejects with the signal's reason, an AbortError.

import { EdgeTTS, EdgeTTSError } from '@andresaya/edge-tts';

async function handleErrors() {
    const tts = new EdgeTTS();
    
    try {
        await tts.synthesize("Test", 'en-US-AriaNeural', { volume: -150 });
    } catch (error) {
        if (error instanceof EdgeTTSError && error.code === 'INVALID_OPTION') {
            console.error('Invalid parameter:', error.message);
        }
    }
    
    try {
        // This will throw an error - no audio data
        const duration = tts.getDuration();
    } catch (error) {
        console.error(error.code, error.message); // NO_AUDIO ...
    }
}

License

This project is licensed under the GNU General Public License v3 (GPLv3).

Acknowledgments

We would like to extend our gratitude to the developers and contributors of the following projects for their inspiration and groundwork:

版本与发布记录

@andresaya/edge-tts 共发布 35 个版本,首次发布于 2024/10/05;过去 12 个月发布了 8 个版本。

版本发布日期距今
1.9.1latest2026/10/1325 天前
1.9.02026/10/1325 天前
1.8.32026/10/1325 天前
1.8.12026/09/191 个月前
1.8.02025/12/1310 个月前
1.7.22025/12/0611 个月前

关于 @andresaya/edge-tts 的常见问题

@andresaya/edge-tts 是什么?

Edge TTS is a package that allows access to the online text-to-speech service used by Microsoft Edge without the need for Microsoft Edge, Windows, or an API key.

如何安装 @andresaya/edge-tts?

在项目目录运行 npm install @andresaya/edge-tts,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 edge-tts,可以用 npx edge-tts 直接运行。

@andresaya/edge-tts 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@andresaya/edge-tts 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@andresaya/edge-tts 可以商用吗?

@andresaya/edge-tts 使用 GPL-3.0-only 许可。强 Copyleft:分发包含该代码的软件时,整个作品需以 GPL-3.0 兼容许可开源,并附带专利与反锁定条款。仅内部使用不触发此义务。以上为概括,不构成法律意见,请以许可原文为准。

@andresaya/edge-tts 的下载量有多少?

根据 npm 官方下载统计,@andresaya/edge-tts 在 2026/10/06 – 2026/11/04 这 30 天内被下载 90,454 次,日均约 3,015 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@andresaya/edge-tts 还在维护吗?

最新版本 1.9.1 发布于 2026/10/13(25 天前);至今共发布 35 个版本,其中过去 12 个月发布了 8 个;首次发布于 2024/10/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。