如何将浏览器录制的音频流发送至Node.js服务器适配IBM Watson
解决音频流直接传输到Node.js并适配IBM Watson的方案
嘿,这事儿我熟!我来帮你把音频流直接传到Node.js后端,完美适配IBM Watson的需求,完全不用碰文件存储那一套~
一、前端改造:实现录制启停与流发送
首先咱们得给前端添上录制控制逻辑,用MediaRecorder来处理音频录制,停止后直接把流发给后端:
<!DOCTYPE html> <html lang='fr'> <head> <script> let mediaRecorder = null; let mediaStream = null; let isRecording = false; function startRecording() { if (isRecording) { // 停止录制 mediaRecorder.stop(); return; } navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { mediaStream = stream; // 选择IBM Watson支持的音频格式,这里用audio/wav(也可选更高效的audio/ogg; codecs=opus) const mimeType = 'audio/wav'; if (!MediaRecorder.isTypeSupported(mimeType)) { console.warn(`${mimeType} 不被浏览器支持,将使用默认格式`); } mediaRecorder = new MediaRecorder(stream, { mimeType }); const audioChunks = []; mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) audioChunks.push(e.data); }; mediaRecorder.onstop = () => { // 将录制的音频块转为Blob,再转成ReadableStream发送给后端 const audioBlob = new Blob(audioChunks, { type: mimeType }); sendAudioStream(audioBlob.stream()); // 关闭媒体流,释放资源 mediaStream.getTracks().forEach(track => track.stop()); isRecording = false; document.getElementById('recordBtn').textContent = 'Lancer l\'audio'; }; mediaRecorder.start(); isRecording = true; document.getElementById('recordBtn').textContent = 'Arrêter l\'enregistrement'; }) .catch(err => { console.error('获取音频权限失败:', err); }); } function sendAudioStream(audioStream) { fetch('/api/audio-stream', { method: 'POST', body: audioStream, headers: { 'Content-Type': 'audio/wav' // 和录制格式保持一致 } }) .then(response => { if (!response.ok) throw new Error(`请求失败: ${response.status}`); return response.json(); }) .then(watsonResponse => { console.log('IBM Watson 返回结果:', watsonResponse); // 这里可以把Watson的响应展示给用户,比如语音播报或者文字显示 }) .catch(err => { console.error('发送音频流失败:', err); }); } </script> <title>Enregistreur audio pour Watson</title> </head> <body> <button id='recordBtn' onclick='startRecording()'>Lancer l'audio</button> </body> </html>
二、后端Express实现:接收流并传给IBM Watson
接下来配置Node.js后端,直接把前端传来的流转发给IBM Watson,全程不落地文件:
1. 先安装依赖
npm install express ibm-watson @ibm-cloud/platform-sdk
2. 后端代码
const express = require('express'); const { SpeechToTextV1 } = require('ibm-watson'); const { IamAuthenticator } = require('ibm-cloud-sdk-core'); const app = express(); const PORT = process.env.PORT || 3000; // 初始化IBM Watson语音转文本客户端 const speechToText = new SpeechToTextV1({ authenticator: new IamAuthenticator({ apikey: '你的Watson API密钥', // 替换成你的密钥 }), serviceUrl: '你的Watson服务URL', // 替换成你的服务地址 }); // 托管前端静态文件(把上面的HTML放到项目根目录的public文件夹里) app.use(express.static('public')); // 处理音频流的POST请求 app.post('/api/audio-stream', async (req, res) => { try { const recognizeParams = { audio: req, // 直接将请求流传给Watson contentType: 'audio/wav', // 和前端发送的格式一致 model: 'fr-FR_BroadbandModel', // 法语模型,根据你的需求调整 }; // 调用Watson语音识别API const watsonResult = await speechToText.recognize(recognizeParams); res.json(watsonResult.result); } catch (error) { console.error('Watson处理出错:', error); res.status(500).json({ error: error.message }); } }); app.listen(PORT, () => { console.log(`服务器运行在 http://localhost:${PORT}`); });
三、关键细节说明
- 流式传输核心:前端把Blob转为
ReadableStream发送,后端直接将req(本身就是流对象)传给Watson,全程没有文件的读写删除操作,完全符合你的需求。 - 音频格式适配:要确保前端录制的格式和Watson支持的一致,Watson支持
audio/wav、audio/ogg; codecs=opus等格式,选哪个都可以,只要前后端和Watson配置统一。 - 资源释放:停止录制后记得关闭媒体流的track,避免浏览器持续占用麦克风资源。
对了,顺便说个小趣事:我的Imgur ID以"NUL"开头,在法语里这可是“菜鸟”的意思,哈哈!
内容的提问来源于stack exchange,提问作者user11609642




