OpenAI TTS API + Web 前端 AudioContext 实战方案
本文给你一套「能跑起来」的 OpenAI TTS API + Web 前端 AudioContext 实战方案:既有最稳妥的 后端代理 + 前端一次性播放,也给出 低延迟流式播放 的思路与样例。
⚠️ 切记:不要在浏览器里直接暴露 OpenAI API Key。生产里一律走你自己的后端(或 Edge Function)做签名与转发。API 形态与可用模型以官方文档为准。(OpenAI平台, OpenAI)
方案 A:后端生成音频(MP3/WAV)→ 前端用 AudioContext 播放
1)后端(Node / Express 示例)
把文字交给 OpenAI TTS 接口,后端返回音频二进制(建议 audio/mpeg
或 audio/wav
)。下面代码的 /api/tts
会把文本转成 MP3 流返回给前端。
// server.js
import express from "express";
import fetch from "node-fetch";const app = express();
app.use(express.json());app.post("/api/tts", async (req, res) => {const { text, voice = "alloy", format = "mp3" } = req.body || {};if (!text) return res.status(400).json({ error: "text required" });try {// 参考官方 Text-to-Speech 指南与 Audio API 参数。模型/字段名以文档为准。:contentReference[oaicite:1]{index=1}const r = await fetch("https://api.openai.com/v1/audio/speech", {method: "POST",headers: {"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,"Content-Type": "application/json"},body: JSON.stringify({// 常见:gpt-4o-mini-tts(示例;请以文档为准):contentReference[oaicite:2]{index=2}model: "gpt-4o-mini-tts",voice, // 例如:alloy / verse 等(以文档列出的可用 voice 为准)input: text,format // mp3 / wav / pcm 等})});if (!r.ok) {const msg = await r.text();return res.status(r.status).send(msg);}// 直接把音频二进制转发给浏览器res.setHeader("Content-Type", format === "wav" ? "audio/wav" : "audio/mpeg");// 可选:Cache-Control 视场景决定r.body.pipe(res);} catch (e) {console.error(e);res.status(500).json({ error: "tts failed" });}
});app.listen(8787, () => console.log("TTS proxy on http://localhost:8787"));
2)前端(AudioContext 播放)
用 fetch
拿到二进制音频 → arrayBuffer()
→ audioContext.decodeAudioData()
→ AudioBufferSourceNode
播放。这样可以后续接入滤波、混音、音量包络等任意 Web Audio 效果节点。
<button id="speak">Speak</button>
<script type="module">
const btn = document.getElementById('speak');
const ctx = new (window.AudioContext || window.webkitAudioContext)();async function ttsAndPlay(text) {const r = await fetch("/api/tts", {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({text,voice: "alloy", // 示例format: "mp3" // mp3/wav:mp3体积小;wav解码快})});if (!r.ok) throw new Error(await r.text());const buf = await r.arrayBuffer();const audioBuffer = await ctx.decodeAudioData(buf);const src = ctx.createBufferSource();src.buffer = audioBuffer;// 可选:加一个增益节点做音量控制const gain = ctx.createGain();gain.gain.value = 1.0;src.connect(gain).connect(ctx.destination);src.start(0);
}btn.onclick = async () => {if (ctx.state === "suspended") await ctx.resume();await ttsAndPlay("你好,欢迎体验大模型 TTS 与 Web Audio 的组合!");
};
</script>
优点:实现最简单、兼容性好、可叠加 Web Audio 效果。
缺点:必须等后端把整段音频生成完再播放,首帧延迟取决于网络与合成时长。
方案 B:低延迟「边下边播」(流式)到 AudioContext
当你想做近实时语音(更像对讲)时,需要流式输出。两条常见路:
-
Text-to-Speech 流式响应(chunked transfer)
-
Realtime API(WebSocket/WebRTC)语音输出 —— 用于真正的对话级低延迟(官方推荐)。(OpenAI平台)
浏览器端要把片段边到边解码。MP3/WAV 片段直接
decodeAudioData
是「整段解码」模型;要做到平滑拼接通常用 MediaSource Extensions(SourceBuffer
追加字节),或者采用 WebCodecs/ AudioWorklet 做自定义拼接与去噪。实现难度较 A 方案高。关于流式/实时能力的定位,官方指南有说明。(OpenAI Community)
下面给出 “流式 → MSE 播放” 的最小示例骨架(思路参考,具体要跟返回的容器/编码适配):
// 前端:用 MediaSource 把服务端的 mp3 流按 chunk 推给 <audio>;
// 然后如果需要进阶音频处理,再把 <audio> 的 MediaElementAudioSourceNode 接到 AudioContext。
const audioEl = document.querySelector("audio");
const mediaSource = new MediaSource();
audioEl.src = URL.createObjectURL(mediaSource);mediaSource.addEventListener("sourceopen", async () => {const sb = mediaSource.addSourceBuffer('audio/mpeg'); // 取决于后端编码const resp = await fetch("/api/tts/stream", { method: "POST", body: /*...*/ });const reader = resp.body.getReader();let queue = [];let appending = false;const pump = async () => {const { value, done } = await reader.read();if (done) {// 通知结束mediaSource.endOfStream();return;}queue.push(value);if (!appending && !sb.updating) {appending = true;const chunk = queue.shift();sb.appendBuffer(chunk);}};sb.addEventListener('updateend', () => {appending = false;if (queue.length) {appending = true;sb.appendBuffer(queue.shift());} else {pump();}});pump();
});
如果追求真正的“语音对话延迟”(数十到低百毫秒级),建议直接采用 Realtime API(WebRTC / WebSocket),把模型的音频输出流接到浏览器端播放,比在通用 TTS 端点上做「伪流式」更顺滑、更稳。(OpenAI平台)
可控性:情感/语速/人物
OpenAI 新一代音频模型支持更细腻的说话方式(“像同理心客服那样”),并能通过参数对情绪、风格等进行引导;模型名、可用 voice 与控制字段请以官方公告与 API 参考为准。(OpenAI, OpenAI平台)
请求体(示例):
{"model": "gpt-4o-mini-tts","voice": "alloy","input": "周报已生成,是否需要我同步发送邮件?","format": "mp3","style": "empathetic", // 依文档支持情况"rate": 1.0, // 语速(如果支持)"pitch": 0 // 音高(如果支持)
}
与 Web Audio API 组合的玩法
有了 AudioContext
,你可以很容易地叠加音频处理:
-
动态音量/淡入淡出:
GainNode
-
EQ/滤波/电话音效:
BiquadFilterNode
-
混响:
ConvolverNode
-
可视化:
AnalyserNode
+ Canvas 频谱 -
拼接与排程:把多段 TTS 结果排时间线顺序
source.start(when)
Web Audio 的节点图与规范可参考文档。(维基百科)
常见坑位清单
-
跨域与 Range:若用 MSE 追加,需要保证响应头与容器支持分段追加。
-
首帧延迟:一次性方案可换
wav
(解码快),或服务端先行并发生成。 -
移动端自动播放限制:首次必须由用户手势触发(点击)后
AudioContext.resume()
。 -
API 兼容/模型名:以官方文档的最新说明为准(TTS 指南、Audio API、Realtime API)。(OpenAI平台)
什么时候选哪种?
-
播客/整段旁白/合成后可缓存 → 选 方案 A(一次性),最省事。
-
需要“对话式”低延迟 → 直接上 Realtime API(WebRTC/WebSocket),从模型端就以流的方式送音频。(OpenAI平台)