文字转语音Edge-TTS知识学习使用

Edge-TTS 安装使用完整教程

1. Edge-TTS 简介

Edge-TTS 是一个 Python 库,它允许你直接调用微软 Edge 浏览器的在线文本转语音服务,无需安装 Edge 浏览器,无需 Windows 系统,也无需 API 密钥,即可免费使用微软的神经网络语音合成技术。它本质上是调用微软 Azure 认知服务的神经语音合成接口,但通过开源封装规避了付费限制,支持 60 余种语言,可生成接近真人发音的高质量语音。

主要优势:

  • 完全免费,无需注册或申请 API Key
  • 支持多种语言和语音角色(包括普通话、粤语、英语等)
  • 生成的语音自然度高,基于深度学习模型
  • 支持语速、音量、音调等参数调节
  • 支持流式输出,适合实时交互场景

使用限制:

  • 不建议将输出语音用于商业售卖(如制作有声书出售)
  • 单日调用次数建议控制在 5 万次以内,避免触发风控
  • 需要网络连接(调用微软在线服务)

2. 环境准备与安装

2.1 前置条件

确保系统已安装 Python 3.8 或更高版本,可通过以下命令检查:

bash 复制代码
python --version

2.2 安装 Edge-TTS

使用 pip 安装:

bash 复制代码
pip install edge-tts

如果只打算在命令行中使用(不嵌入 Python 项目),推荐使用 pipx 安装,避免污染全局环境:

bash 复制代码
pipx install edge-tts

2.3 验证安装

安装完成后,验证是否成功:

bash 复制代码
edge-tts --list-voices | grep "zh-CN"

如果能看到中文语音列表,说明安装成功。

3. 命令行基础使用

3.1 最简单的语音合成

bash 复制代码
edge-tts --text "你好,这是Edge TTS语音合成测试。" --write-media output.mp3

3.2 指定语音角色

bash 复制代码
edge-tts --voice zh-CN-YunxiNeural --text "大家好,欢迎使用Edge TTS" --write-media hello_cn.mp3

3.3 查看所有可用语音

bash 复制代码
edge-tts --list-voices > voices.json

常用中文语音角色:

语音名 说明
zh-CN-XiaoxiaoNeural 女声(自然流畅)
zh-CN-YunxiNeural 男声(中气十足)
zh-CN-YunjianNeural 男声(成熟稳重)
zh-CN-XiaoyiNeural 女声(温柔型)
zh-HK-HiuGaaiNeural 粤语(香港)女声
zh-TW-HsiaoChenNeural 台湾普通话女声

3.4 调整语速、音量和音调

bash 复制代码
# 语速减慢50%
edge-tts --rate=-50% --text "Hello, world!" --write-media slow.mp3

# 音量降低50%
edge-tts --volume=-50% --text "Hello, world!" --write-media quiet.mp3

# 音调降低50Hz
edge-tts --pitch=-50Hz --text "Hello, world!" --write-media low_pitch.mp3

参数格式说明:

  • rate :语速调整,如 +20% 表示加快 20%,-10% 表示减慢 10%
  • volume :音量调整,如 +50% 表示增大 50%
  • pitch :音调调整,如 +5Hz 表示升高 5Hz,-10Hz 表示降低 10Hz

3.5 从文件读取文本

bash 复制代码
edge-tts --text-file input.txt --write-media output.mp3

3.6 生成字幕文件

bash 复制代码
edge-tts --text "Hello world" --write-media output.mp3 --write-subtitles output.srt

4. Python 项目中的详细使用

4.1 同步调用(快速上手)

对于简单的脚本,可以使用 save_sync 方法进行同步调用:

python 复制代码
import edge_tts

text = "大家好,欢迎关注语音之家。"
voice = "zh-CN-YunxiNeural"
communicate = edge_tts.Communicate(text=text, voice=voice)
communicate.save_sync("output.mp3")

这是最简洁的调用方式,适合快速验证和简单场景。

4.2 异步调用(推荐)

Edge-TTS 原生是异步库,在异步项目中使用 await communicate.save() 是更高效的方式:

python 复制代码
import asyncio
import edge_tts

async def main():
    text = "大家好,这是异步方式生成的语音。"
    voice = "zh-CN-XiaoxiaoNeural"
    communicate = edge_tts.Communicate(text, voice)
    await communicate.save("output.mp3")

asyncio.run(main())

如果你已经在异步框架(如 FastAPI、aiohttp)中,直接在协程内 await 即可:

python 复制代码
async def generate_speech(text: str, output_path: str):
    communicate = edge_tts.Communicate(text, "zh-CN-YunxiNeural")
    await communicate.save(output_path)

注意 :Edge-TTS 是异步库,无法直接在非异步上下文中使用 await。如果必须在同步代码中调用,可以通过事件循环包装:

python 复制代码
import asyncio

def sync_generate(text, voice, output):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    communicate = edge_tts.Communicate(text, voice)
    loop.run_until_complete(communicate.save(output))
    loop.close()

4.3 流式获取音频数据

communicate.stream() 方法以流式方式返回音频数据块,适合需要实时处理音频的场景(如边生成边播放、实时对话系统):

python 复制代码
import asyncio
import edge_tts

async def stream_audio(text, voice="zh-CN-XiaoxiaoNeural"):
    communicate = edge_tts.Communicate(text, voice)
    audio_bytes = b""
    async for chunk in communicate.stream():
        if chunk["type"] == "audio":
            audio_bytes += chunk["data"]
    return audio_bytes

每个 chunk 的结构包含 type 和 data 两个字段。当 type == "audio" 时,data 是音频二进制数据;还可能出现 type == "WordBoundary" 的 chunk,包含单词边界信息,可用于生成字幕。

4.4 获取单词边界时间戳

流式处理时,WordBoundary 类型的 chunk 提供了每个词的精确时间信息:

python 复制代码
async def get_word_timings(text, voice="zh-CN-XiaoxiaoNeural"):
    communicate = edge_tts.Communicate(text, voice)
    timings = []
    async for chunk in communicate.stream():
        if chunk["type"] == "WordBoundary":
            timings.append({
                "text": chunk["text"],
                "offset": chunk["offset"],      # 100纳秒单位
                "duration": chunk["duration"]    # 100纳秒单位
            })
    return timings

这些时间戳可以用于生成 SRT 字幕或实现卡拉 OK 效果。

5. 参数详解与高级调优

5.1 Communicate 构造参数

python 复制代码
communicate = edge_tts.Communicate(
    text="要合成的文本",
    voice="zh-CN-XiaoxiaoNeural",
    rate="+0%",        # 语速,默认 +0%
    volume="+0%",      # 音量,默认 +0%
    pitch="+0Hz",      # 音调,默认 +0Hz
)

5.2 不同场景的参数推荐

场景 rate pitch 效果
正常播报 +0% +0Hz 标准语速和音调
快速播报(新闻) +15%~+25% +0Hz 节奏紧凑
温柔叙述(有声书) -5%~-10% -3Hz~+3Hz 舒缓自然
活泼角色 +10%~+20% +5Hz~+15Hz 年轻有活力
低沉角色 -5%~-10% -10Hz~-20Hz 成熟稳重
紧张/惊恐 +20%~+30% +8Hz~+15Hz 急促高亢

5.3 使用 SSML 精细控制

Edge-TTS 支持 SSML(语音合成标记语言),可以通过文本内容传入 SSML 来实现更精细的控制:

python 复制代码
import asyncio
import edge_tts

async def speak_with_ssml():
    ssml = """<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="zh-CN">
        <voice name="zh-CN-YunxiNeural">
            <prosody rate="+15%" pitch="+5Hz">
                这是通过SSML控制的语音合成示例。
            </prosody>
        </voice>
    </speak>"""

    communicate = edge_tts.Communicate(ssml, "zh-CN-YunxiNeural")
    await communicate.save("ssml_output.mp3")

asyncio.run(speak_with_ssml())

当文本以 <speak> 开头时,Edge-TTS 会自动识别为 SSML 格式。

6. 多角色批量合成实战

在实际项目中,经常需要为对话文本生成多角色语音。以下是一个完整的批量合成示例:

python 复制代码
import asyncio
import edge_tts

# 角色-语音映射表
VOICE_MAP = {
    "旁白": "zh-CN-YunjianNeural",
    "女主": "zh-CN-XiaoxiaoNeural",
    "男主": "zh-CN-YunxiNeural",
    "老人": "zh-CN-YunjianNeural",
}

# 角色-参数映射(语速、音调)
PARAM_MAP = {
    "旁白": {"rate": "-5%", "pitch": "+0Hz"},
    "女主": {"rate": "+5%", "pitch": "+5Hz"},
    "男主": {"rate": "+0%", "pitch": "-3Hz"},
    "老人": {"rate": "-15%", "pitch": "-10Hz"},
}

async def synthesize_dialogue(dialogue_list: list, output_dir: str = "./output"):
    """
    dialogue_list: [(角色, 文本), ...]
    """
    import os
    os.makedirs(output_dir, exist_ok=True)

    for i, (speaker, text) in enumerate(dialogue_list):
        voice = VOICE_MAP.get(speaker, "zh-CN-XiaoxiaoNeural")
        params = PARAM_MAP.get(speaker, {})
        rate = params.get("rate", "+0%")
        pitch = params.get("pitch", "+0Hz")

        communicate = edge_tts.Communicate(
            text, voice, rate=rate, pitch=pitch
        )
        filename = f"{output_dir}/{i+1:03d}_{speaker}.mp3"
        await communicate.save(filename)
        print(f"已生成: {filename}")

async def main():
    dialogue = [
        ("旁白", "在一个风和日丽的下午,故事开始了。"),
        ("女主", "你今天怎么来得这么晚?"),
        ("男主", "路上堵车了,抱歉让你久等。"),
        ("老人", "年轻人啊,时间不等人,要珍惜每一天。"),
    ]
    await synthesize_dialogue(dialogue)

asyncio.run(main())

如果需要将多段音频合并为一段完整的语音,可以使用 pydub 进行拼接:

python 复制代码
from pydub import AudioSegment
import os

def merge_audio_files(file_list, output_path):
    combined = AudioSegment.empty()
    for f in file_list:
        audio = AudioSegment.from_mp3(f)
        combined += audio
        combined += AudioSegment.silent(duration=300)  # 每段后加300ms停顿
    combined.export(output_path, format="mp3")

7. 在 Web 框架中集成

7.1 FastAPI 示例

python 复制代码
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse
import edge_tts
import tempfile
import os

app = FastAPI()

@app.post("/tts")
async def text_to_speech(text: str, voice: str = "zh-CN-XiaoxiaoNeural"):
    try:
        communicate = edge_tts.Communicate(text, voice)
        with tempfile.NamedTemporaryFile(
            delete=False, suffix=".mp3"
        ) as tmp:
            tmp_path = tmp.name

        await communicate.save(tmp_path)
        return FileResponse(
            tmp_path,
            media_type="audio/mpeg",
            filename="speech.mp3"
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

7.2 带重试机制的健壮版本

网络请求可能偶发失败,建议加入重试逻辑:

python 复制代码
async def synthesize_with_retry(
    text, voice, output_path, max_retries=5, delay=1
):
    for attempt in range(max_retries):
        try:
            communicate = edge_tts.Communicate(text, voice)
            await communicate.save(output_path)
            return True
        except Exception as e:
            print(f"第 {attempt+1} 次尝试失败: {e}")
            if attempt < max_retries - 1:
                await asyncio.sleep(delay * (attempt + 1))
    return False

8. 常见问题与注意事项

Q:报错 RuntimeError: asyncio.run() cannot be called from a running event loop?

说明你已经在异步环境中调用了 asyncio.run()。在异步框架中直接 await communicate.save() 即可,不要嵌套 asyncio.run()。

Q:生成的语音不完整或中断?

通常是网络波动导致。建议加入重试机制,或使用流式方式逐块获取后自行拼接。

Q:命令行参数报错 --rate -50%?

命令行中使用带负号的参数值时,需要写成 --rate=-50% 的形式,等号不能省略。

Q:如何选择合适的语音角色?

先运行 edge-tts --list-voices 查看全部可用语音,中文语音可以按 zh-CN 过滤。建议通过试听小段文本来确定最合适的音色。

Q:能否完全离线使用?

不能。Edge-TTS 调用的是微软在线服务,需要网络连接。如需完全离线,可以考虑 Coqui TTS 或 pyttsx3 等方案。

相关推荐
B2_Proxy2 小时前
Scrapy 代理 IP 调度进阶:基于 Redis 与中间件的高可用架构实战
python·scrapy·1024程序员节
文慧的科技江湖2 小时前
2026年10月24日智慧农业行业早报:模型数到175个,棚里的账还按年算
开源·智慧农业·农业物联网·数字乡村·1024程序员节·农业机器人·农业数字化
在世修行2 小时前
智学文枢:AI 客户端封装
python·http·ai·1024程序员节·pyside
buddyMe智能助手2 小时前
记忆还没失效,但动作已经危险:该不该先核实,是动作说了算
1024程序员节
l1t2 小时前
在windows中测试musql数据库
数据库·sqlite·go·1024程序员节
大江东去浪淘尽千古风流人物2 小时前
【HIMO】跨模态图像匹配算法:IMO方向场提取与PolarP描述符源码精讲
matlab·跨模态·遥感·图像匹配·1024程序员节·特征描述符
小南家的青蛙2 小时前
华为云DCS全产品对比
redis·1024程序员节
芝麻开门2922 小时前
c++11
c++11·1024程序员节
乃嘿仔2 小时前
AI 热点日报 · 2026-10-24
1024程序员节