@andresaya/edge-tts

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

Edge TTS是一个包,可以访问由Microsoft Edge使用的在线文本到语音服务,而不需要Microsoft Edge,Windows,或API密钥.

中文使用文档
文档目录33 节
  1. 以三种语文提供
  2. 特征
  3. 安装
  4. 类型脚本支持
  5. 可用类型
  6. 类型安全使用示例
  7. 使用量
  8. 命令线接口
  9. 融入您的项目
  10. 配置
  11. API 参考
  12. 语音管理
  13. 文本合成
  14. 音频信息
  15. 导出选项
  16. 词句边界
  17. 字幕
  18. 实例
  19. 随语音选择完成示例
  20. 流出示例
  21. 语音探索示例
  22. 浏览器支持
  23. CDN 使用量 (UMD)
  24. ES 模块导入
  25. 浏览器中的流支持
  26. 其他浏览器 (Relay)
  27. 完整浏览器示例
  28. 语音选项
  29. 综合参数
  30. 参数示例
  31. 处理错误
  32. 许可证
  33. 承认

边缘 TTS

Ask DeepWiki

边缘 TTS 是一个强大的Text-to-Speech(TTS)软件包,它能利用微软的边缘能力. 此软件包允许您从文本中合成语音,并通过命令行界面(CLI)轻松管理语音选项.

以三种语文提供

用于 Edge 文本对语音服务的同一库, 在 Node.js, PHP 和 Go 中:

语言安装仓库
节点和浏览器 (这个)npm install @andresaya/edge-tts断层/断层
前一頁composer require afaya/edge-tts复诊/对接-ts-php
走开go get github.com/andresayac/edge-tts-go断层/断层

特征

  • 文字对语言: 使用微软Edge的TTS能力将文本转换为自然语音.
  • 类型脚本支持:包含有全面类型定义的完整类型脚本支持.
  • 音频格式: MP3在48或96 kbit/s,和WebM/Opus.
  • 多个声音: 访问各种声音以适应您的项目需求.
  • 语音过滤:按语言和性别筛选声音,以更好地选择.
  • 音频信息: 获取生成音频的详细信息(大小,持续时间,格式).
  • 音频导出选项:以不同格式(raw,base64,或直接到文件)导出合成的音频.
  • 流程支持: 实时流出音频数据,以提高性能.
  • 词句边界:获得有精确时间戳的文字和句子时间.
  • 字幕:生成 SRT 或 WebVTT 字幕,每句一个提示.
  • 同时使用数字 : generate() 返回自己的结果,因此一个实例可以同时运行多个合成.
  • 可配置:在不等待发布的情况下,覆盖结束点,标题,超时和语音缓存.
  • 命令线接口:使用简单的CLI来方便地访问功能.
  • 简单整合: 模块结构可以方便地纳入现有项目.

安装

您可以通过 npm 或 bun 安装 Edge TTS :

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

在Node.js 18,20和24以及Bun上测试.

类型脚本支持

边缘 TTS 以 类型脚本 并包括完整类型定义。 无额外 @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
}

类型安全使用示例

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[]

使用量

命令线接口

在全球安装以使用 CLI :

npm install -g @andresaya/edge-tts

从文本中合成语音 :

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

其他选项:

# 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

要列出可用的声音, 可选择过滤 :

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

融入您的项目

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

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

配置

每个选项都是可选的。 默认来自 Constants,所以当微软改变服务时,您可以将库指向新的值自己,而不是等待发布.

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
});

如果计算机的时钟关闭,服务会拒绝连接. 在Node.js中,库然后从服务器读取时间并重复一次.

API 参考

语音管理

获取全部声音

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

按语言过滤声音

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

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

按性别过滤声音

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

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

文本合成

基本综述

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

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

将语音匹配到文本

声音是特定的地方。 一个声音只能读取 : 中文、西里尔文、阿拉伯文或德瓦纳加里文 英语语音返回完全没有音频 :

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

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

英文句子中的几个外语是好的 仅当其他脚本是文本的大部分时才会出现. toBuffer() 丢入 而不是交出一个空缓冲器.

带有选项的高级合成

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
});

有生成的独立结果( )

synthesize() 将音频保存在实例上,因此在一次实例上同时两次通话互相覆盖. generate() 返回所有结果, 并留下一个实例 :

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[]

音频输出格式

您可以使用 outputFormat 选项 :

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

可用格式 :

常数数值
AUDIO_24KHZ_48KBITRATE_MONO_MP3 (默认)audio-24khz-48kbitrate-mono-mp3
AUDIO_24KHZ_96KBITRATE_MONO_MP3audio-24khz-96kbitrate-mono-mp3
WEBM_24KHZ_16BIT_MONO_OPUSwebm-24khz-16bit-mono-opus

该服务不返回其他格式的音频,例如WAV,PCM或其他MP3比特率.

流化综合

// 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`);
}

提前离开循环 break 关闭连接.

取消和超时

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 与 synthesize(), (中文(简体) ), synthesizeStream() 财务报告和审定财务报表 generate()。 。 。 . timeout 是等待多长时间而不收到数据,30秒默认.

音频信息

获取音频细节

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`);

仅获取持续时间

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

导出选项

导出为 Base64

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

导出为 Raw 缓冲

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

导出为文件

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)

词句边界

抵消和持续时间为100秒(每秒10 000 000克).

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');

字幕

每句1个提示,加上正文的出处.

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));

实例

随语音选择完成示例

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);

流出示例

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);

语音探索示例

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);

浏览器支持

这个库可以通过CDN或ES模块在网页浏览器中直接被使用.

重要内容: 直接连接, 合成只在 微软边缘。语音服务拒绝用户代理不是Edge的连接,一个网页不能更改其浏览器发送的用户代理。 Chrome,Firefox和Safari在合成时得到一款403. 对于这些浏览器,请使用中继器(见 其他浏览器) (中文(简体) ). 节点.js版本没有受到影响.

CDN 使用量 (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 模块导入

<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>

浏览器中的流支持

<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>

其他浏览器 (Relay)

在Node.js运行的小型中继器会用Edge头连接到服务并传递消息. 开始实例中继 :

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

用浏览器指向它:

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

这个例子只能听 127.0.0.1。如果您部署它,请在您自己的认证或原产地检查之后放置它,这样它就不会向所有人开放.

完整浏览器示例

关于语音选择和合成的完整实例,见 examples/browser-standalone.html。 。 。 .

语音选项

综合参数

参数类型范围说明
pitchstring | number-100Hz 改为 +100Hz语音音标调整
ratestring | number-100% 改为 +200%语音率调整
volumestring | number-100% 改为 +100%数量调整

参数示例


// 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 }

处理错误

库提出的错误是: EdgeTTSError 实例 code从Node.js(例如: ECONNREFUSED)通过时不变.

code何时
HANDSHAKE服务拒绝连接. status 在Node.js(通常是403)中持有 HTTP 状态.
NETWORK打开后连接失败( 浏览器) .
TIMEOUT未收到数据 timeout m.
NO_AUDIO尚未合成, 或服务未返回音频( 不同脚本中的语音和文本, 或仅标出平分的文本) .
REFUSED该服务拒绝了请求,并说为什么,例如: Unsupported voice xx-XX-NobodyNeural. 或不支持的输出格式. status 持有WebSocket的近接码(1007).
INVALID_OPTION文本为空,或 pitch, (中文(简体) ), rate 或者说 volume 无效.
VOICES语音列表请求失败 . status 持有 HTTP 状态 .

取消一个 AbortSignal 以信号的理由拒绝,一个 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 ...
    }
}

许可证

该项目根据GNU通用公共许可证v3(GPLv3)获得许可.

承认

我们谨感谢下列项目的开发者和捐助者的启发和基础工作:

版本与发布记录

@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是一个包,可以访问由Microsoft Edge使用的在线文本到语音服务,而不需要Microsoft Edge,Windows,或API密钥.

如何安装 @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 和提交记录判断。