豆包语音合成 · Harness 插件
把本机调试页 豆包语音合成_Tina老师.html 变成 DeepSeek Harness 里的正式面板:
侧边栏出现「语音合成」入口,点开即用,不再需要另开终端启动 proxy.js。
它做了什么
原网页依赖浏览器 WebSocket,而浏览器不允许给 WebSocket 加 X-Api-Key 请求头,
所以它必须通过本地代理(proxy.js)转发。插件把这层代理搬进了 Host:
浏览器面板 --POST /doubao-tts/synthesize--> Host(Node)
└─wss─> openspeech.bytedance.com
/api/v3/tts/bidirection
- Host 侧完整实现火山引擎 v3 双向流协议(二进制帧、会话、流式送字、音频回收)。
- 浏览器只发一次 JSON,拿回完整音频(PCM 会封装成 WAV),随后用
<audio>播放、下载。 - 面板复刻原网页:示例文本、文本输入、语音指令(
context_texts)、上下文记忆 (section_id)、单人/双人对话、音调/语速/音量、格式与采样率、模型、字幕、 事件日志、历史记录、底部播放器。
安装
dsh plugin --profile desktop add /Users/aoao/Documents/deepseek-harness/default-workspace/doubao-tts
装好后重启 Harness(或在设置里确认插件已启用),侧边栏即出现「语音合成」。
配置 API Key
两种方式,任选其一:
面板内粘贴(推荐):面板右侧「配置」→ API Key → 保存。Key 只存在本机
localStorage,随请求发到本机 Host,不会写进插件配置或上传第三方。插件配置:在
cordis.patch.yml的doubao-tts行上加:- insert: - id: doubao-tts name: 'youyou-doubao-tts' config: apiKey: 'your-key'适合固定 Key 的机器;注意这会把明文写进 profile 配置。
可选配置项:resourceId(默认 seed-tts-2.0)、endpoint、timeoutMs。
使用要点
- 单次最多 5000 字;长文本合成耗时会长一些,面板会显示进度与事件流。
- 语音指令与上下文只对
seed-tts-2.0-expressive+ 2.0 音色生效。 - 双人模式:每行用
A:/B:(或甲:/乙:)开头,没写前缀则按行交替。 - 默认输出
pcm24kHz,Host 会封装成 WAV;也可以直接选 mp3 / wav / ogg_opus。 - 历史记录只存在内存里,刷新页面即清空(和原网页一致)。
系统 Say(离线语音)
面板顶部有「豆包 2.0 / 系统 Say / 微软神经」三档切换。切到「系统 Say」后用的是 macOS 自带的
say 命令,完全在本机合成:不联网、不需要 API Key、不消耗额度。
- 声音列表来自
say -v '?',按中文 / 其他语言分组,可一键刷新。 - 可调语速(80–400 词/分钟),导出 WAV(系统直出 24kHz 单声道)或 MP3
(本机有
ffmpeg时转码)。 - 播放、下载、历史记录与豆包模式共用同一套底部播放器和结果条。
- 系统语音不支持语音指令、上下文记忆和双人对话——这些是豆包侧的能力。
给应用 / Agent 调用
Host 注册了工具 system_say_speak,参数 { text, voice?, rate?, format? },
生成的文件写到 ~/.dsh/tts-output/say-<时间戳>.<wav|mp3>,返回文件路径、时长、
大小和声音名,可直接播放或作为其他流程的素材。
也可以像面板一样直接调路由(同样要求 x-doubao-tts: 1 请求头)。
微软神经音色(在线、免费)
面板顶部的第三档「微软神经」走微软 Edge 朗读服务(Edge TTS),用它公开的 WebSocket 接口在线合成,不消耗豆包额度,中文男声女声齐全:
- 音色列表实时从微软拉取(约 320 个),按中文普通话 / 粤语·台湾 / 英语 / 其他分组, 内置常用音色标签:晓晓、晓伊(女声),云希、云健、云扬、云夏(男声), 以及粤语曉佳/曉曼/雲龍、台湾曉臻/曉雨/雲哲等;拉取失败时回落到内置列表。
- 可选语速(-50% ~ +50%)和音调(-20 ~ +20 Hz),导出 MP3(24kHz,微软直接输出) 或 WAV(本机 ffmpeg 转码)。
- 长文本按句切分后最多 3 路并行合成,最后按原顺序拼接,几千字也能在十几秒内完成。
- 播放、下载、历史记录与另外两个引擎共用同一套播放器和结果条。
给应用 / Agent 调用
Host 注册了工具 edge_neural_speak,参数 { text, voice?, rate?, pitch?, format? },
生成的文件写到 ~/.dsh/tts-output/edge-<时间戳>.<mp3|wav>,返回文件路径、时长、
大小和音色名。
对应的本机路由(同样要求 x-doubao-tts: 1 请求头):
POST /doubao-tts/edge→ 微软音色合成,返回{ ok, audio, mime, ext, duration, words, voice, events }POST /doubao-tts/edge/voices→{ ok, online, voices: [{ name, locale, gender, friendly }] }
音标发音(本机免费,推荐)
「音素」页默认走本机模式:用 macOS 自带的语音引擎(AVSpeechSynthesizer)配合
AVSpeechSynthesisIPANotationAttribute 按 IPA 注音渲染,完全离线、免费、不需要任何 Key。
- 每行「文字 | 音标」,段与段之间自动留 400ms 停顿;音标省略时就是普通朗读。
- 音色来自系统语音包,面板按 英语 / 中文 / 其他语言 分组,常用的有 Samantha(美式女)、Daniel(英式男)、Karen(澳式女)、Moira(爱尔兰女)、 Tingting(中文女)、Li-Mu / Yu-shu(Siri 中文男 / 女)、Meijia(台湾女)、Sinji(粤语)。
- 输出 WAV(系统原生)或 MP3(需要本机 ffmpeg)。
- 首次使用会把
ipa-helper.swift编译成小工具(首次编译约 1–2 分钟,插件启动后会在后台预热;之后直接复用); 编译需要 Xcode 命令行工具(xcode-select --install)。
给应用 / Agent 调用
工具 local_ipa_speak,参数 { items: [{ word, ipa? }], voice?, rate?, format? },
文件写到 ~/.dsh/tts-output/ipa-local-<时间戳>.<wav|mp3>。
路由(同样要求 x-doubao-tts: 1 请求头):
POST /doubao-tts/ipa→{ ok, audio(base64), mime, ext, duration, words, voice, sampleRate, segments }POST /doubao-tts/ipa/voices→{ ok, voices: [{ identifier, name, language, quality }], defaultVoice, platform }
音标发音(Azure 语音,可选)
「音素」页切到「Azure(需 Key)」时才用这条路,适合中文多音字和云端批量场景。
面板右下角新增「音素」页,用来做逐音节 / 逐单词的精确发音,适合自然拼读、单词 跟读这类素材。每行写一段文字和它的国际音标:
restaurant | ˈrestərɑːnt
re | re
stə | stə
rɑːnt | rɑːnt
- 用 SSML 的
<phoneme alphabet="ipa">交给 Azure 语音合成,段与段之间自动留 400ms 停顿,可整段试听、下载,也进历史记录(标注「音素 · 音色名」)。 - 音标可省略:只写文字时按默认读音合成,等于一个普通的 Azure 朗读器。
- 音色可选 Jenny / Aria / Guy / Davis(美式)、Sonia / Ryan(英式)、晓晓 / 云希 / 云健(中文)、曉臻(台湾)、Nanami(日语);支持语速 -50%+50%、音调 -20+20 Hz。
- 输出 MP3(24kHz 48kbps,微软直出)或 WAV(24kHz 16bit PCM,不需要 ffmpeg)。
怎么拿 Key
- 登录 Azure 门户,搜索「语音服务 / Speech」创建资源, 定价层选 Free F0(每月 50 万字符免费,个人够用)。
- 资源创建好后,在「密钥和终结点」里复制 密钥 1 和 区域(例如
eastasia、eastus,就是你创建资源时选的区域)。 - 回到面板「音素」页,把 Key 和区域填进去,点「保存」。Key 只存在本机浏览器 localStorage 里,不会发到别处;合成时由 Host 直接发往 Azure。
给应用 / Agent 调用
Host 注册了工具 azure_phoneme_speak,参数
{ items: [{ word, ipa? }], voice?, rate?, pitch?, format? },文件写到
~/.dsh/tts-output/ipa-<时间戳>.<mp3|wav>,返回路径、时长、大小、音色。
工具用的是插件配置里的 azureApiKey / azureRegion(cordis.patch.yml 或插件配置里填),
不是面板里那对值。
对应的本机路由(同样要求 x-doubao-tts: 1 请求头):
POST /doubao-tts/azure→{ ok, audio(base64), mime, ext, duration, words, voice, events }POST /doubao-tts/azure/voices→{ ok, voices: [{ name, locale, gender, label }], region, hasKey }POST /doubao-tts/ipa→ 本机 IPA 合成(免费离线)POST /doubao-tts/ipa/voices→ 本机系统音色列表POST /doubao-tts/elevenlabs/POST /doubao-tts/elevenlabs/voices→ ElevenLabs 云端 IPAPOST /doubao-tts/cartesia/POST /doubao-tts/cartesia/voices→ Cartesia 云端 IPAPOST /doubao-tts/ipa/convert→ 单词转换:查音标并生成 v4 / Flash / Cartesia 写法POST /doubao-tts/elevenlabs/POST /doubao-tts/cartesia的请求体支持rate(-50~50)和volume(0~200)
音标发音(ElevenLabs,可选)
「音素」页切到「ElevenLabs」并填 API Key 后使用。免费档 1 万字符/月,注册不用绑卡。
- 拿到 Key:登录 ElevenLabs → 左下角头像 → API Keys → 创建。
- 两种写法,面板里按模型自动选:
- Eleven v4(默认):音标用斜杠包起来直接写在文本里,如
"/ˈrestərɑːnt/"; 文档说明 v4 原生支持 IPA,一个词一个斜杠片段。 - Flash v2:
<phoneme alphabet="ipa" ph="ˈrestərɑːnt">restaurant</phoneme>, 一个标签只能包一个词。
- Eleven v4(默认):音标用斜杠包起来直接写在文本里,如
- 每段单独请求一次,段与段之间的 400ms 停顿由本机 ffmpeg 拼出来(所以多段时要装 ffmpeg)。
- 语速走
voice_settings.speed:官方只接受 0.7–1.2 倍,面板滑块是百分数, 超出会被自动收敛到边界;万一某个模型不认这个字段(返回 422),插件会去掉 speed 重试一次, 日志里会写明「用了默认语速」。 - 音量:ElevenLabs 没有音量参数,插件用本机 ffmpeg 做增益(0–200%,100% 不处理、不耗额度)。
单词转换(选音标来源 → 生成厂商格式)
面板里 ElevenLabs / Cartesia 两档都有「单词转换」区块:输入英文单词(可一次输入多个, 用空格或逗号分隔),点「转换」后每个词会同时给出三组音标来源:
| 来源 | 内容 |
|---|---|
| 有道词典 · 美 / 英 | 在线查词,美式和英式各一份(有的词还有多种读法) |
| v6 词典音标 | 本地 v6 音节词库里的整词音标,带音节拆分(如 e-mo-tion / ɪˈməʊʃn) |
| v6 自然拼读 | 同一词库的自然拼读音标(如 ɪˈməʊʃ(ə)n) |
- 每个来源下面直接给出当前引擎要求的写法:
- ElevenLabs v4:
"/ɪˈməʊʃn/" - ElevenLabs Flash:
<phoneme alphabet="ipa" ph="ɪˈməʊʃn">emotion</phoneme> - Cartesia:
<<ɪ|ˈ|m|oʊ|ʃ|n>>
- ElevenLabs v4:
- 点来源按钮即时切换,代码区跟着重算,不用重新请求。
- 「填入片段」把
word | 音标追加到上面的发音片段(合成时再按引擎转格式); 「按音节填入」按当前引擎的官方写法一次填完整个词:- ElevenLabs v4:
/prəʊ/,/græm/(逗号分隔的斜杠音标,直接粘进 ElevenLabs 也能用) - ElevenLabs Flash:
<phoneme alphabet="ipa" ph="prəʊ">pro</phoneme>,<phoneme …>gram</phoneme> - 本机 / Cartesia / Azure:每个音节一行
pro | prəʊ、gram | græm发音片段输入框也直接认/prəʊ/,/græm/这种纯音标行(只支持 ElevenLabs),合成时会原样发给厂商; 「复制」复制当前词、当前来源的厂商格式文本;右上角「复制整段」复制所有词拼好的整段文本。
- ElevenLabs v4:
- 默认优先用 v6 词典音标(有音节拆分),其次有道,再退 v6 拼读;词库都没有时可手填音标。
v6 词库目录默认是
/Users/aoao/Documents/deepseek-harness/default-workspace/word-syllable-v6,
换位置时设环境变量 DSH_DOUBAO_V6_DIR 指向新目录即可(请求体也可以带 v6Dir)。
词库只读取 data/records.jsonl 和 data/phonics_words.jsonl(共约 9.4MB),首次转换加载一次后缓存 30 分钟。
- 查词结果(有道 / v6)都会缓存,重复转换同一个词不会反复读盘或请求。
- 转换本身不消耗任何额度,也不要求先填 Key。
- 同一词在 v6 词库有多条记录时按「切分更细 + 音标更完整 + 有拼读数据」取优,不按 wid 大小猜。
路由
POST /doubao-tts/elevenlabs→ 合成,返回{ ok, audio, mime, ext, duration, words, voice, model }POST /doubao-tts/elevenlabs/voices→{ ok, voices: [{ id, name, gender, accent, language }], models }POST /doubao-tts/ipa/convert→{ words: [...], v6Dir? }(或{ word, ipa }用指定音标重算) →{ ok, items: [{ word, ipa, source, sourceLabel, selectedKey, ws, syllableList, options: [{ key, label, ipa, elevenV4, elevenFlash, cartesia }], variants, error? }] }
音标发音(Cartesia,可选)
「音素」页切到「Cartesia」,填 Key 即可。免费档 2 万 credits/月(约 27 分钟音频)。
- 拿到 Key:play.cartesia.ai → API Keys。
- Cartesia 只认它自己的 41 个英文音素,写法是
<<ˈ|ɹ|ɛ|s|t|ə|ɹ|ɑ|n|t>>(符号之间用|隔开)。 面板会自动把你输入的普通 IPA 转成这种写法:r→ɹ、g→ɡ、ɑː→ɑ、ʌ→ə、ɜ/ɚ→ɝ、e→ɛ、 去掉长度符号ː;表里没有的符号会直接报错,换写法或用本机 / ElevenLabs。 - 已经写成 Cartesia 原生格式(带
|或<<...>>)时会原样使用。 - 语速滑块对应 Cartesia 的
speed参数(-50~50 → 0.5~1.5 倍)。 - 音量同样没有官方参数,用本机 ffmpeg 做增益(0–200%)。
路由
POST /doubao-tts/cartesia→ 合成,返回同样的{ ok, audio, mime, ext, duration, words, voice, model }POST /doubao-tts/cartesia/voices→{ ok, voices: [{ id, name, language }], models }POST /doubao-tts/ipa/convert→ 单词转换(查音标 + 三套写法),两个引擎共用
历史记录
每次合成都会进「历史」,并按来源打标签:
| 标签 | 来源 |
|---|---|
| 豆包 | 豆包 2.0(含双人对话) |
| 系统 Say | macOS 本机语音 |
| 微软神经 | Edge 朗读音色 |
| 本机音素 | macOS IPA(AVSpeechSynthesizer) |
| ElevenLabs / Cartesia | 云端音素引擎 |
| Azure 音素 | Azure Speech |
- 顶部有来源筛选(全部 / 豆包 / 系统 Say / …),带条数。
- 音素类记录会把
word | 音标逐行展示出来,并多一个「填入音素」按钮: 一键切回「音素」页、把这些行填回去,方便改一个音标重合成。 - 云端记录还会标出这次用的语速和音量(非默认时才显示)。
- 下载文件名带来源前缀,例如
doubao_tts_elevenlabs_1730000000000.mp3。
结构
| 文件 | 作用 |
|---|---|
index.js |
Host 半:协议实现 + 本机路由 + system_say_speak / edge_neural_speak / azure_phoneme_speak 工具 |
client.js |
浏览器半:侧边栏入口 + 整页面板(豆包 / 系统 Say / 微软神经三模式 + 音素页,音素页含本机 / ElevenLabs / Cartesia / Azure 四档) |
cordis.patch.yml |
插件行声明 |
locale/*.json |
插件管理器里显示的名称与描述 |
icon.svg |
插件图标(原创) |
ipa-helper.swift |
本机音标发音助手源码(首次使用由 Host 编译,走 AVSpeechSynthesizer + IPA) |
node_modules/ws |
随包附带的 WebSocket 客户端(MIT,见其 LICENSE) |
路由(都要求请求头 x-doubao-tts: 1):
POST /doubao-tts/synthesize→{ ok, audio(base64), mime, ext, duration, words, segments, events }POST /doubao-tts/test→ 只握手,不计费POST /doubao-tts/say→ 系统语音合成,返回同样的{ ok, audio, mime, ext, duration, words, voice, events }POST /doubao-tts/say/voices→{ ok, available, ffmpeg, voices: [{ name, locale, sample }] }POST /doubao-tts/edge→ 微软神经音色合成,返回{ ok, audio, mime, ext, duration, words, voice, events }POST /doubao-tts/edge/voices→{ ok, online, voices: [{ name, locale, gender, friendly }] }
可选配置项还有:outputDir(三个工具共用的落盘目录,默认 ~/.dsh/tts-output)、
sayVoice(系统语音默认声音,默认 Tingting)、azureApiKey 与 azureRegion
(azure_phoneme_speak 工具用,按需填,留空则工具会提示先配置)、
elevenApiKey / elevenVoiceId / elevenModel、cartesiaApiKey / cartesiaVoiceId / cartesiaModel
(云端音素引擎用;面板里填的 Key 存在浏览器 localStorage,配置项里的 Key 供路由与服务端调用)。
已知限制
- 双人模式下
mp3是两段音频字节直接拼接;主流播放器可用,但不是严格意义上的单文件重编码。 wav/ogg_opus的时长由播放器解析,Host 只对pcm计时。- 本机音标发音只支持 macOS,且 IPA 只能表达系统语音支持的音素;中文多音字用 IPA 效果有限, 更适合把词拆开或改用 Azure。
- 本机模式首次编译需要 Xcode 命令行工具;编译产物放在临时目录,重启系统后会自动重编一次。
- Azure 音标发音需要自己申请 Key,没 Key 时切到 Azure 会提示先填写;音标写错 Azure 返回 400。
- ElevenLabs / Cartesia 都按字符计费:一次合成多少字就扣多少,音节素材很省,但整段课文请先算额度。 两家都需要本机 ffmpeg 才能把多段拼成一条音频(单段 MP3 不需要)。
- Cartesia 的音素表只有 41 个英文音素,中文拼音和部分冷门 IPA 符号用不了,会直接报错。
- ElevenLabs 免费档不能商用;做商用素材需要 Starter 及以上套餐。
- 微软神经音色依赖微软的公开朗读接口:需要联网,接口鉴权版本变化时可能需要更新插件
(Host 里的
EDGE_GEC_VERSION/EDGE_TOKEN两个常量)。接口不可用时面板会给出错误, 不影响豆包与系统 Say 两档。 - Siri 音色无法接入:
say -v '?'不提供 Siri 声音,第三方请求会被系统静默替换成默认音色。
No comments yet. Be the first to write one.