Field Note

我用 openai-edge-tts + n8n 搭了一个完全免费的本地文本转语音流程

在 Mac 上跑 openai-edge-tts,再用 n8n 的 HTTP Request 节点接入一个本地 TTS 服务,做出可自动化、可选音色、输出 mp3 的免费文本转语音方案。

#tts#n8n#automation#ai#open-source

今天折腾了一个我觉得挺实用的小系统:

在 Mac 上运行一个开源的本地 TTS 服务,再通过 n8n 调用它,把文本自动转成语音。

而且关键点是:

  • 完全免费
  • 本地可跑
  • 可以接进自动化工作流
  • 支持选择不同音色
  • 最终可以直接输出 mp3

我用到的开源项目是:

openai-edge-tts
GitHub:https://github.com/travisvn/openai-edge-tts

这篇就记录一下我今天怎么把它跑起来,以及为什么我觉得这个方案很适合个人自动化使用。

为什么我想搞这个

文本转语音这件事,需求其实一直都在。

比如你会想把:

  • 一段文字变成语音播报
  • 一条通知自动读出来
  • 工作流里的文本内容转成音频
  • 某些文章或摘要快速生成可听版本

这些场景如果都走商业 TTS API,虽然省事,但长期用下来通常有几个问题:

  • 要付费
  • 有额度限制
  • 依赖第三方服务
  • 接自动化时不一定够灵活

所以我今天更想做的是一个:

够用、免费、可控,而且能直接接进自己工作流里的本地 TTS 方案。

我最后采用的方案

我最后用的是这套组合:

  • 运行环境:Mac
  • TTS 服务openai-edge-tts
  • 自动化编排n8n
  • 调用方式HTTP Request
  • 输出格式mp3

也就是说,整个流程可以理解成:

文本 → n8n → HTTP 请求本地 TTS 服务 → 返回语音文件

这类方案我很喜欢的一点在于,它不是单独一个 demo,而是能真正接进已有自动化流程里。

服务启动前,我先写了一个 .env

把项目从 GitHub 下载下来之后,我先在根目录写了一个 .env 文件,内容如下:

API_KEY=your_api_key_here
PORT=5050

DEFAULT_VOICE=en-US-AvaNeural
DEFAULT_RESPONSE_FORMAT=mp3
DEFAULT_SPEED=1.0

DEFAULT_LANGUAGE=en-US

REQUIRE_API_KEY=True
REMOVE_FILTER=False
EXPAND_API=True
DETAILED_ERROR_LOGGING=True

这些配置大致是做什么的

  • API_KEY:本地服务的访问密钥
  • PORT:服务监听端口,我这里设成了 5050
  • DEFAULT_VOICE:默认音色
  • DEFAULT_RESPONSE_FORMAT:默认输出格式,这里是 mp3
  • DEFAULT_SPEED:默认语速
  • DEFAULT_LANGUAGE:默认语言
  • REQUIRE_API_KEY=True:要求调用时必须带 API Key
  • DETAILED_ERROR_LOGGING=True:调试时更方便排查问题

这一层配置很重要,因为它把整个本地服务的认证方式、默认音色、输出格式和端口都定下来了。

n8n 里我是怎么接的

我这边在 n8n 里用的是 HTTP Request 节点,直接去请求本地跑起来的 TTS 服务。

基本请求配置

  • MethodPOST
  • URLhttp://host.docker.internal:5050/v1/audio/speech
  • Authentication:None
  • Send Headers:开启
  • Specify Headers:Using JSON
  • Send Body:开启
  • Body Content Type:JSON
  • Specify Body:Using JSON

这里用 host.docker.internal,是因为我这边的 n8n 跑在容器里,需要通过这个地址访问宿主机上的本地服务。

Header 配置

我这里加了一个认证头:

Authorization: Bearer your_api_key_here
n8n 中 HTTP Request 节点的 Header 配置示意

如果你的本地服务设置了 API Key,这一步就需要带上。

这里要特别注意:

.env 里的 API_KEY,和 n8n 请求头里的 Authorization: Bearer ...,必须是同一个值。

比如你在 .env 里设置的是:

API_KEY=my_secret_tts_key_123

那在 n8n 里就必须写成:

Authorization: Bearer my_secret_tts_key_123

因为我这里开了:

REQUIRE_API_KEY=True

如果这两边不一致,请求就不会通过。

Body 配置

请求体里主要传这几个字段:

{
  "input": "这里放要转语音的文本",
  "voice": "zh-CN-XiaoxiaoNeural",
  "response_format": "mp3",
  "speed": 1.0
}
n8n 中 HTTP Request 节点的 Body 配置示意

字段说明

input

要转换的文本内容。

voice

音色参数,对应你想使用的 voice 名称。

response_format

我这里直接设成 mp3,这样后面无论是保存、传输还是继续接流程都比较方便。

speed

控制语速,1.0 是默认值。

n8n 中 HTTP Request 节点的配置示意

这一套为什么好用

一旦它被接成 n8n 里的 HTTP Request 节点,这个本地 TTS 服务就不只是“能跑起来”,而是变成了一个可以复用的能力节点。

后面无论你是要:

  • 接 webhook 传来的文本
  • 接 AI 生成的摘要
  • 接通知内容
  • 接文章或脚本片段

都可以统一走这一步,把文本输出成语音文件。

音色怎么选

这套方案还有一个挺实用的点:音色不是固定死的。

可以直接去这个页面试听和查看可用音色:

https://tts.travisvn.com/

你在页面里选中喜欢的声音后,直接把对应的 voice 参数值填进 n8n 请求体就行。

例如一些常见中文音色包括:

  • zh-CN-XiaoxiaoNeural
  • zh-CN-XiaoyiNeural
  • zh-CN-YunjianNeural
  • zh-CN-YunxiNeural
  • zh-CN-YunxiaNeural

这就意味着你不仅能做“文本转语音”,还能根据场景切不同声音。

比如:

  • 用偏自然的声音做摘要朗读
  • 用更清晰的音色做通知播报
  • 用不同 voice 区分不同工作流来源

对于自动化系统来说,这种可配置性其实很重要。

这个方案为什么值得

我觉得它最有价值的地方,不是“它能发声”,而是它在个人工作流里很顺手。

1. 免费

这是最直接的优点。

对于个人使用、实验和轻量自动化来说,免费意味着你可以更放心地接进流程里,不用每次都计算成本。

2. 本地可控

服务跑在自己的机器上,整个过程更可控,也更适合喜欢自己搭系统的人。

3. 很适合接 n8n

一旦它能被 HTTP Request 打通,就不再只是一个本地工具,而是一个可以嵌进自动化流程的组件。

这时候你就能做很多事:

  • 新消息自动转语音
  • 某段文本自动生成播报音频
  • 博客摘要或日报自动语音化
  • 某些提醒内容直接输出成可播放文件

4. 输出格式直接实用

直接返回 mp3,比只拿到一段临时数据更方便后续处理。

我觉得它适合什么场景

如果是个人项目或者轻量工作流,这方案很合适。

比如:

  • 自动语音播报
  • 内容摘要转语音
  • 提醒系统
  • 文章/笔记朗读
  • 某些机器人或自动化助手的语音输出

尤其是当你已经在用 n8n 的时候,这种“能 HTTP 调用的本地能力”会非常自然地融进现有工作流。

它的局限也要说清楚

当然,这种方案也不是没有边界。

我目前的感受是:

1. 它更适合个人和实验型场景

如果你要做的是商业级、大规模、高稳定性的语音服务,那还是要评估更多因素。

2. 音色体验未必能完全替代成熟商用服务

虽然已经够用了,但如果你追求特别强的情绪表达、极高拟真度或者复杂语音产品能力,商用 TTS 依然有优势。

3. 本地部署意味着你要自己维护

这既是优点,也是代价。你获得了自由度,也要接受自己维护环境和流程。

我自己的一个判断

今天把这条链跑通之后,我更确信一件事:

对个人自动化来说,很多时候最重要的不是“最强”,而是“够用、免费、可控,还能接进自己的工作流”。

这类本地能力一旦通过 n8n 接起来,它的意义就不只是“一个开源项目能跑”,而是你多了一个真正可复用的工作流组件。

这也是我最近越来越喜欢的一类工具:

  • 不一定最花哨
  • 不一定最商业化
  • 但能接得进系统
  • 能长期自己掌控

最后

如果你也在找一个:

  • 免费
  • 本地运行
  • 可自动化调用
  • 支持选音色
  • 能输出 mp3

的文本转语音方案,我觉得 openai-edge-tts + n8n 这条路很值得试。

至少对我今天这个需求来说,它已经不是一个“能跑的 demo”,而是一条真正可以放进日常工作流里的链路了。