本文给你一套「能跑起来」的 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平台)