Dify AI 语音助手完整实战三步接通按住说话到开口回答【免费下载链接】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你在手机里按住麦克风说帮我查下明天杭州天气几秒后助手开口回答——这个体验只依赖两个接口语音转文字STT把语音变成文本和文字转语音TTS把文本变成可播放的音频。Dify 内置的 AI 语音助手能力把这两个接口直接挂在你的应用上配好模型就能用。照这篇文章做十分钟能跑通一条最小验证链路做完后你会拥有一个会听、懂、说的语音应用而不只是一段孤立的代码。能力一览30 秒判断你的需求能不能落地这一节解决能不能做的问题读完你会拿到一份输入侧和输出侧的硬性限制清单对得上再继续往下看。方向接口输入输出硬限制STT 语音转文字POST /v1/apps/{app_id}/audio-to-text音频文件字段名固定为fileJSON{text: 识别结果}单文件 ≤ 30MB格式限 mp3 / m4a / wav / amr / mpgaTTS 文字转语音POST /v1/apps/{app_id}/text-to-audioJSON{text: ..., voice: 可选}音频流默认 MP3 容器非 JSON音色列表由模型提供商决定不传voice时用该提供商的第一个音色两点提醒两个接口都要在应用里显式开启对应功能开关没开会直接返回功能未启用类错误而不是静默失败。TTS 的返回体是原始音频字节前端不能当 JSON 解析要按 blob 处理。最短上手路径三分钟接通第一个语音接口读完这一节你会完成配提供商 → 选模型 → 发首个真实请求三步并亲眼看到识别文本、亲耳听到合成音频。第一步配提供商。打开 Dify 控制台进入设置 → 模型供应商添加一个同时支持 STT 和 TTS 的供应商下文以 OpenAI 为例填入 API Key。 两个方向都用同一把 Key 最省事后面不用切配置。第二步选模型并开启功能。进入你的应用打开功能设置分别开启语音转文本和文本转语音STT 选whisper-1TTS 选tts-1音色先按默认。第三步发首个真实请求。准备一段不超过 30MB 的测试音频执行# 字段名必须叫 file这是最常见的报错原因NoAudioUploaded curl -X POST http://127.0.0.1:5001/v1/apps/{app_id}/audio-to-text \ -H Authorization: Bearer 你的应用api_key \ -F filetest.mp3 # 成功后应看到{text: 你刚才说的内容}再验证 TTScurl -X POST http://127.0.0.1:5001/v1/apps/{app_id}/text-to-audio \ -H Authorization: Bearer api_key \ -H Content-Type: application/json \ -d {text: 你好我是语音助手} -o reply.mp3 # 成功后应听到reply.mp3 可以被播放器正常播放两个请求都通了最短链路就成立了。后端实现主要在api/services/audio_service.py排查行为时可以对照。声音怎么进来STT 配置要点与上传示例这一节解决音频进来之后会经过什么校验。读完后你应能独立处理格式、大小、鉴权三类 4xx 报错。配置要点对应源码中的校验顺序功能开关必须打开否则 400 类未启用错误MIME 类型必须在audio/{mp3|m4a|wav|amr|mpga}白名单内不在则返回不支持的音频类型体积超过 30MB 直接拒绝超长录音请在客户端先分段或压缩。提供商怎么选看语言场景和计费方式提供商语言支持中文效果成本特点OpenAI Whisper多语言稳定长句偶有错字按音频分钟计费短对话划算Azure Speech多语言好可定制语言区域按字符计费长文本便宜Google STT多语言中上按分钟计费有免费额度阿里云中文优先中文场景最省心的选择按量计费国内网络延迟低判断标准很简单中文为主选国内提供商多语言混用选 Whisper其余按免费额度和延迟实测定。前端上传最小示例≤15 行// 字段名必须是 file且要带真实 MIME白名单按 MIME 校验 const form new FormData(); form.append(file, blob, recording.mp3); const res await fetch( https://你的域名/v1/apps/${appId}/audio-to-text, { method: POST, headers: { Authorization: Bearer ${apiKey} }, body: form, } ); const { text } await res.json(); // 识别结果就在 text 字段声音怎么出去TTS 配置要点与音色策略这一节解决用什么声音说。读完你会拿到一张场景到音色的映射表以及一段可直接播放的流式处理代码。配置要点voice参数可传可不传——不传时Dify 会取该 TTS 模型返回的音色列表里的第一个见transcript_tts中voices[0]的逻辑。上线前最好显式指定避免供应商调整默认值后声音偷偷变了。可用哪些音色由模型决定以控制台里文本转语音下拉框为准不要凭记忆写死。音色选择策略表场景推荐音色理由客服问答、高频使用alloy或nova中性偏友好长时间听不累故事、品牌讲解fable女声叙述感强正式播报、通知onyx或echo低频偏多显得稳重创意内容、轻松语气shimmer变化多适合短内容一句话高频对话用中性音色低频内容用个性音色。流式播放最小示例≤15 行async function speak(text, voice nova) { const res await fetch( https://你的域名/v1/apps/${appId}/text-to-audio, { method: POST, headers: { Authorization: Bearer ${apiKey}, Content-Type: application/json, }, body: JSON.stringify({ text, voice }), } ); // 响应体是音频字节不是 JSON直接当 blob 播放 const url URL.createObjectURL(await res.blob()); new Audio(url).play(); }端到端实战音频 → 文本 → LLM → 音频这一节把前四节串起来。读完后你会清楚每一步的数据形态变化并拥有一个后端可运行的完整闭环。数据形态变化就三次音频字节 → 纯文本 → 纯文本 → 音频字节。中间两步文本到文本走普通对话接口和纯文字聊天完全一样语音只是首尾两端的翻译层。后端最小可运行闭环Python≤15 行import httpx def voice_chat(base: str, app_id: str, key: str, audio: bytes) - bytes: # 坑点1字段名必须是 file坑点2TTS 响应是音频字节不是 JSON h {Authorization: fBearer {key}} t httpx.post(f{base}/v1/apps/{app_id}/audio-to-text, headersh, files{file: (r.mp3, audio, audio/mpeg)}) text t.json()[text] a httpx.post(f{base}/v1/apps/{app_id}/chat-messages, headersh, json{inputs: {}, query: text, response_mode: blocking, user: demo}) answer a.json()[answer] r httpx.post(f{base}/v1/apps/{app_id}/text-to-audio, headersh, json{text: answer}) return r.content # 直接返回可播放的音频前端同理录音拿 blob → 调audio-to-text取text→ 调对话接口取answer→ 调text-to-audio播放。三处 URL 都在api/controllers/service_api/app/audio.py和 Web 侧api/controllers/web/audio.py有对应实现接口行为变化时以源码为准。上线前必查的三个坑坑一识别不准。现象文本有错字或句首句尾被吞。原因客户端把静音段一起录了或格式是模型不擅长的高压缩音频。解法前端剪掉首尾静音统一转 mp3/m4a 再上传中文场景换国内优化的 STT 模型复测同一段音频再下结论。坑二音色机械。现象回复像导航播报数字和英文特别生硬。原因LLM 原样输出代码、符号、连续数字TTS 直接照读。解法TTS 前加一步文本清洗拆长句、数字转口语、去 markdown 符号def for_speech(answer: str) - str: return re.sub(r[*_#\n], , answer) # 先去掉符号再进 TTS坑三首字延迟高。现象说完到开口回答超过 5 秒。原因STT、LLM、TTS 三段全串行且 TTS 要等 LLM 完整回答才合成。解法分别测三段耗时定位最慢段短问答用blocking模式长回答按句分段调用 TTS、音频端排队播放让第一句话先出声。⏱ 目标是首句出声压在 2~3 秒内。结尾上线检查清单STT 侧格式白名单mp3/m4a/wav/amr/mpga与 30MB 上限在前端提前拦截别等后端 413/415 才报错TTS 侧显式指定voice不要依赖供应商默认值全链路压一次说完→首句出声的延迟确认低于用户能忍的 3 秒两个接口的 401Key 失效和功能未启用错误都有用户可读的提示网络失败有重试TTS 请求建议失败后重试 1 次音频丢了对话就断了AI 语音助手的语音能力说到底就是两个音频接口加一次 LLM 调用——链路接通之后剩下要打磨的全是延迟和音色的细节而它们都可以逐段量化。【免费下载链接】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),仅供参考