Dify 语音助手实战:STT 与 TTS 一步到位
【免费下载链接】difyBuild Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.项目地址: https://gitcode.com/GitHub_Trending/di/dify
你搭好一个客服聊天应用后,用户发来的往往不是一段文字,而是 30 秒语音。Dify 语音助手能力就为这种场景服务:把音频文件 POST 给/v1/apps/{app_id}/audio-to-text拿到识别文本,交给 LLM 生成回复,再把回复 POST 给/v1/apps/{app_id}/text-to-audio直接取回音频流。整条链路只需要配置两件事——模型服务商的 Speech-to-Text(STT)与 Text-to-Speech(TTS)默认模型,以及应用侧的功能开关。
一图看懂 Dify 语音功能全貌
Dify 的语音实现不在应用代码里,而是统一委托给ModelManager:它按租户取出ModelType.SPEECH2TEXT和ModelType.TTS的默认模型实例,所以换服务商时只需要改工作区模型配置,应用调用代码不用动。
能力边界先看这张表:
| 项目 | 约束 |
|---|---|
| STT 输入格式 | audio/mp3、audio/mpga、audio/m4a、audio/wav、audio/amr |
| STT 文件大小 | ≤ 30 MB |
| STT 输出 | JSON:{"text": "识别结果"} |
| TTS 输入 | text或message_id(二选一,message_id优先) |
| TTS 输出 | 二进制音频流,容器格式取决于服务商(AAC / FLAC / MP3 / MP4 / OGG / WAV / WebM),以响应头Content-Type为准 |
| 应用适用范围 | 基础 Chat 读应用设置;Chatflow / Workflow 读功能配置speech_to_text/text_to_speech |
最小可运行路径
最短链路三步:
- 工作区 → 模型供应商:配置好服务商(如 OpenAI)凭证,并在模型配置里指定 Speech-to-Text 与 Text-to-Speech 的默认模型(如
whisper-1、tts-1)。 - 应用设置中打开「语音转文字」和「文本转语音」开关(Chatflow / Workflow 应用在「功能设置」里勾选对应项)。
- 带
Bearer应用 API Token 调用 STT 接口:
这段代码演示上传一段 m4a 音频并拿到识别文本。
const form = new FormData(); form.append('file', new Blob([bytes], { type: 'audio/m4a' }), 'voice.m4a'); const res = await fetch('https://<host>/v1/apps/{app_id}/audio-to-text', { method: 'POST', headers: { Authorization: `Bearer ${apiKey}` }, body: form, }); const { text } = await res.json();⚠️ 坑:上传.m4a文件时 MIME 必须是audio/m4a或audio/x-m4a,其他类型会直接返回415 unsupported_audio_type,与文件内容是否真的是音频无关。
5 分钟配好 STT:audio-to-text 参数
STT 没有模型选择参数——它固定使用租户的默认 Speech2Text 模型,想换识别引擎就去模型配置页改默认模型。接口本身只有一个字段:
| 参数 | 位置 | 必填 | 说明 |
|---|---|---|---|
file | multipart/form-data | 是 | 音频文件,字段名固定为file |
user | multipart 或 query | 视接入端 | 终端用户标识,用于计量与会话归属 |
常见错误码:audio_too_large(413,超过 30 MB)、unsupported_audio_type(415,MIME 不在白名单)、speech_to_text_disabled(400,应用未开启)、provider_not_support_speech_to_text(400,未配置默认 STT 模型)。
识别结果的置信度依赖原始音频质量:采样率低、带强背景音的 m4a 转码文件,识别效果通常差于原生录音。拿不准时先用ffmpeg -i in.m4a -ar 16000 out.wav转成 16 kHz WAV 再上传,这是成本最低的调优点。
TTS 语音参数怎么选:text-to-audio
TTS 接口的 JSON 请求体共 4 个字段:
| 字段 | 类型 | 说明 |
|---|---|---|
text | string | 要合成的文本 |
voice | string | 音色,取决于 TTS 服务商,如 OpenAI 的alloy/nova/echo;省略时使用应用设置里配置的音色,再没有则取服务商返回的第一个音色 |
message_id | string | 传历史消息 ID,直接对该条回复做合成,优先于text。Web 应用里消息气泡的"播放"按钮走的就是这条路径 |
streaming | bool | 兼容保留字段,实际响应形态由服务商决定 |
这段代码演示把一段文本合成为语音并直接播放。
const res = await fetch(`https://<host>/v1/apps/${appId}/text-to-audio`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` }, body: JSON.stringify({ text: '你好,这里是 Dify 语音助手' }), }); new Audio(URL.createObjectURL(await res.blob())).play();⚠️ 坑:成功响应是二进制音频,对它调res.json()会得到乱码。按Content-Type当 blob 处理即可;不同服务商返回的容器格式不同(OpenAI 常见audio/mpeg,Azure 常见audio/ogg),不要在前端硬编码.mp3后缀。
音色选择建议:客服与助手类场景用中性音色(如alloy),讲解与播报类用更有人声起伏的音色(如nova);同一应用内保持音色固定,比追新音色更重要。
端到端串联:语音对话完整链路
服务端也可以直接调用AudioService把两段串起来(audio_service.py),便于写自定义中转服务:
这段 Python 演示在服务端完成"识别 → 回复 → 合成"的完整回合。
from services.audio_service import AudioService def voice_roundtrip(app_model, session, file, reply): asr = AudioService.transcript_asr( app_model=app_model, file=file, session=session ) return asr["text"], AudioService.transcript_tts( app_model=app_model, session=session, text=reply, voice="nova", )前端只需把上一节两个调用按顺序接上:
这段 JavaScript 实现一次"语音问、语音答"的完整交互。
async function askByVoice(appId, apiKey, audioBlob, chatCompletion) { const form = new FormData(); form.append('file', audioBlob, 'voice.m4a'); const asr = await fetch(`/v1/apps/${appId}/audio-to-text`, { method: 'POST', headers: { Authorization: `Bearer ${apiKey}` }, body: form, }).then(r => r.json()); const answer = await chatCompletion(appId, apiKey, asr.text); const tts = await fetch(`/v1/apps/${appId}/text-to-audio`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` }, body: JSON.stringify({ text: answer }), }); new Audio(URL.createObjectURL(await tts.blob())).play(); }踩坑清单
| 现象 | 原因 | 解法 |
|---|---|---|
400speech_to_text_disabled | Chatflow / Workflow 应用在功能设置里未勾选 STT,或 Agent 应用的 Agent Soul 未开启语音能力 | 到对应功能设置页开启speech_to_text |
415unsupported_audio_type | 上传的 MIME 不在mp3 / mpga / m4a / wav / amr白名单内 | 前端转码或重设type后再上传 |
413audio_too_large | 文件超过 30 MB 上限 | 压缩或分段上传,长录音改走文件解析链路 |
TTS 400provider_not_initialize | 工作区未配置 TTS 服务商凭证或没设默认 TTS 模型 | 模型配置页补全凭证并指定默认模型 |
| 返回音频播放无声或花屏 | 把二进制响应当 JSON / 文本读取 | 用blob()读取,并信任响应头Content-Type而非猜测后缀 |
⚠️ 特别注意:Agent 型应用的 STT 生效配置来自 Agent Soul 与旧版应用设置的合并结果,改应用设置页可能不生效,需同时检查 Agent 功能配置。
下一步:把这条语音链路接到 Chatflow 应用,做"语音提问 → RAG 检索 → 语音播报"的完整闭环;模型侧的 Speech2Text / TTS 凭证与默认模型配置,见模型供应商章节。
【免费下载链接】difyBuild Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.项目地址: https://gitcode.com/GitHub_Trending/di/dify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考