基于 Docker 的 Edge-TTS 中转API,兼容 OpenAI TTS接口

1,574 阅读5分钟

image.png

微软 Edge 浏览器的大声朗读功能强大,支持多种语言和角色。基于此,开发者创建了 edge-tts Python 包,允许在程序中使用微软 TTS 服务为文字配音。

然而,可能由于国内羊毛薅的太狠了,微软限制了国内访问,导致经常出现 403 错误。 切换 IP 或挂vpn使用国外 IP 才能正常使用。

为解决此问题,可以使用国外服务器搭建中转服务,提高稳定性,并兼容 OpenAI TTS 接口,方便在 OpenAI SDK 中直接使用。

最近制作了一个 Docker 镜像,以方便在服务器上快速部署此服务。

服务启动后,接口完全兼容 OpenAI。只需将 API 地址更改为 http://部署服务器ip:7899/v1,即可无缝替代 OpenAI TTS。

原理与实现

实现原理简述如下:

  1. 使用 Flask 框架定义与 OpenAI 相同的 /v1/audio/speech 接口,接收以下参数:

    • model: tts-1 (实际无作用)
    • input: 要合成的文本字符串
    • voice: 角色名称,与 OpenAI 参数一致,但角色名不同(edge-tts 支持 200+ 角色)。
    • speed: 语速,默认为 1.0。
    • response_format: 固定为 mp3
    • volume (可选/edge-tts专属): 音量,默认 0,大于 0 为增加百分比,小于 0 为降低到百分比
    • pitch (可选/edge-tts专属): 音调,默认 1,大于 1 增加 Hz,小于 1 降低 Hz

    请求数据类型为 Content-Type:application/json

  2. 将接收的参数转换为 edge-tts 所需格式,使用 edge-tts 包发起请求,返回配音后的音频数据。

  3. 使用 Waitress 启动 HTTP 服务,默认端口为 7899。

  4. 构建 Docker 镜像,Dockerfile 内容如下:

# 使用官方 Python 镜像作为基础镜像
FROM python:3.10-slim-bookworm

# 设置工作目录
WORKDIR /app

# 将 requirements.txt 复制到工作目录
COPY requirements.txt .

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 将应用代码复制到工作目录
COPY . .

# 设置环境变量
ENV FLASK_APP app.py
# 设置 Flask 监听地址,因为容器内不使用0.0.0.0
ENV FLASK_RUN_HOST 0.0.0.0
ENV FLASK_RUN_PORT 7899

# 暴露端口
EXPOSE 7899

# 启动应用
CMD ["python","app.py"]

镜像已推送到 Docker Hub,拉取命令:docker pull jianchang512/edge-tts-api

拉取 edge-tts-api 镜像并启动

确保已安装 Docker

使用以下命令拉取镜像并启动服务。启动后,即可在 OpenAI SDK 中使用。

docker run -p 7899:7899 jianchang512/edge-tts-api:latest

image.png

Ctrl+C 停止服务。

注意,此命令在前台运行,关闭终端窗口服务会停止。

使用以下命令后台启动服务:

docker run -d -p 7899:7899 jianchang512/edge-tts-api:latest

image.png

无报错表示启动成功。 在浏览器中打开 http://你的ip:7899/v1/audio/speech 验证,出现类似下图结果则表示启动成功。

image.png

可用角色

以下为部分可用角色列表,注意文字语言和角色要匹配。

完整配音角色查看该页面的shortName speech.platform.bing.com/consumer/sp…

中文发音角色:
    zh-HK-HiuGaaiNeural
    zh-HK-HiuMaanNeural
    zh-HK-WanLungNeural
    zh-CN-XiaoxiaoNeural
    zh-CN-XiaoyiNeural
    zh-CN-YunjianNeural
    zh-CN-YunxiNeural
    zh-CN-YunxiaNeural
    zh-CN-YunyangNeural
    zh-CN-liaoning-XiaobeiNeural
    zh-TW-HsiaoChenNeural
    zh-TW-YunJheNeural
    zh-TW-HsiaoYuNeural
    zh-CN-shaanxi-XiaoniNeural

英语角色:
    en-AU-NatashaNeural
    en-AU-WilliamNeural
    en-CA-ClaraNeural
    en-CA-LiamNeural
    en-HK-SamNeural
    en-HK-YanNeural
    en-IN-NeerjaExpressiveNeural
    en-IN-NeerjaNeural
    en-IN-PrabhatNeural
    en-IE-ConnorNeural
    en-IE-EmilyNeural
    en-KE-AsiliaNeural
    en-KE-ChilembaNeural
    en-NZ-MitchellNeural
    en-NZ-MollyNeural
    en-NG-AbeoNeural
    en-NG-EzinneNeural
    en-PH-JamesNeural
    en-PH-RosaNeural
    en-SG-LunaNeural
    en-SG-WayneNeural
    en-ZA-LeahNeural
    en-ZA-LukeNeural
    en-TZ-ElimuNeural
    en-TZ-ImaniNeural
    en-GB-LibbyNeural
    en-GB-MaisieNeural
    en-GB-RyanNeural
    en-GB-SoniaNeural
    en-GB-ThomasNeural
    en-US-AvaMultilingualNeural
    en-US-AndrewMultilingualNeural
    en-US-EmmaMultilingualNeural
    en-US-BrianMultilingualNeural
    en-US-AvaNeural
    en-US-AndrewNeural
    en-US-EmmaNeural
    en-US-BrianNeural
    en-US-AnaNeural
    en-US-AriaNeural
    en-US-ChristopherNeural
    en-US-EricNeural
    en-US-GuyNeural
    en-US-JennyNeural
    en-US-MichelleNeural
    en-US-RogerNeural
    en-US-SteffanNeural

日语角色:
    ja-JP-KeitaNeural
    ja-JP-NanamiNeural

韩语角色:
    ko-KR-HyunsuNeural
    ko-KR-InJoonNeural
    ko-KR-SunHiNeural

法语角色:
    fr-BE-CharlineNeural
    fr-BE-GerardNeural
    fr-CA-ThierryNeural
    fr-CA-AntoineNeural
    fr-CA-JeanNeural
    fr-CA-SylvieNeural
    fr-FR-VivienneMultilingualNeural
    fr-FR-RemyMultilingualNeural
    fr-FR-DeniseNeural
    fr-FR-EloiseNeural
    fr-FR-HenriNeural
    fr-CH-ArianeNeural
    fr-CH-FabriceNeural

德语角色:
    de-AT-IngridNeural
    de-AT-JonasNeural
    de-DE-SeraphinaMultilingualNeural
    de-DE-FlorianMultilingualNeural
    de-DE-AmalaNeural
    de-DE-ConradNeural
    de-DE-KatjaNeural
    de-DE-KillianNeural
    de-CH-JanNeural
    de-CH-LeniNeural

西班牙语角色:
    es-AR-ElenaNeural
    es-AR-TomasNeural
    es-BO-MarceloNeural
    es-BO-SofiaNeural
    es-CL-CatalinaNeural
    es-CL-LorenzoNeural
    es-ES-XimenaNeural
    es-CO-GonzaloNeural
    es-CO-SalomeNeural
    es-CR-JuanNeural
    es-CR-MariaNeural
    es-CU-BelkysNeural
    es-CU-ManuelNeural
    es-DO-EmilioNeural
    es-DO-RamonaNeural
    es-EC-AndreaNeural
    es-EC-LuisNeural
    es-SV-LorenaNeural
    es-SV-RodrigoNeural
    es-GQ-JavierNeural
    es-GQ-TeresaNeural
    es-GT-AndresNeural
    es-GT-MartaNeural
    es-HN-CarlosNeural
    es-HN-KarlaNeural
    es-MX-DaliaNeural
    es-MX-JorgeNeural
    es-NI-FedericoNeural
    es-NI-YolandaNeural
    es-PA-MargaritaNeural
    es-PA-RobertoNeural
    es-PY-MarioNeural
    es-PY-TaniaNeural
    es-PE-AlexNeural
    es-PE-CamilaNeural
    es-PR-KarinaNeural
    es-PR-VictorNeural
    es-ES-AlvaroNeural
    es-ES-ElviraNeural
    es-US-AlonsoNeural
    es-US-PalomaNeural
    es-UY-MateoNeural
    es-UY-ValentinaNeural
    es-VE-PaolaNeural
    es-VE-SebastianNeural


在 OpenAI SDK 中使用

需要安装 openai 库:pip install --upgrade openai

如果已安装,需升级到最新版

from openai import OpenAI

client = OpenAI(api_key='12314', base_url='http://你的ip:7899/v1')
with  client.audio.speech.with_streaming_response.create(
                    model='tts-1',
                    voice='zh-CN-YunxiNeural',
                    input='你好啊,亲爱的朋友们',
                    speed=1.0                    
                ) as response:
    with open('./test.mp3', 'wb') as f:
       for chunk in response.iter_bytes():
            f.write(chunk)

直接使用 requests 调用

import requests
res=requests.post('http://你的ip:7899/v1/audio/speech', json={"voice":"zh-CN-YunxiNeural",
                    "input":"你好啊,亲爱的朋友们",
                    "speed":1.0 })
with open('./test.mp3', 'wb') as f:
    f.write(res.content)

相关资源

  1. edge-tts: github.com/rany2/edge-…
  2. openai tts api格式: platform.openai.com/docs/api-re…
  3. 完整配音角色: speech.platform.bing.com/consumer/sp…
  4. edge-tts-api docker: hub.docker.com/r/jianchang…