我正在尝试实现如下流程:
即使尝试捕获编解码器(通过指定 MediaRecorder 的 mimeType)和配置 ConversationTranscriber(通过指定pepeatsdk.audio.AudioStreamFormat 实例的wave_stream_format 或compressed_audio_format)的多种组合,我也无法使此配置工作。
我尝试了 OGG/OPUS 编解码器并将其传递到语音 API,但它似乎无法识别(我得到的结果是检测到空文本)。
现在我正在考虑在前端捕获纯 PCM 音频,然后将其即时转码为 ConversationTranscriber 接受的 MP3 的选项。
ConversationTranscriber Python SDK 文档对可以使用的确切格式的描述有限。
我正在寻找前端编解码器、ConversationTranscriber 的 AudioStreamFormat 配置以及可能一些可以使整个设置正常工作的后端音频处理的正确组合的建议。
[编辑]
看起来 Speech API 可以使用的音频格式与 MediaRecorder 生成的格式之间不兼容。
语音 API 可以消化:WAV/PCM、MP3、OGG 容器中的 OPUS、WAV 容器中的 FLAC、ALAW、WAV 容器中的 MULAW、MP4
MediaRecorder 能够生成: WebM 容器中的 OPUS、WebM 容器中的 PMC(使用 RecordRTC 库)
这里的主要问题是如何将 WebM 容器转换为 WAV、OGG、MP4 中的任何一种。 FFmpeg 不是这里的解决方案,因为它太慢并且不支持分块/连续转码。
我正在寻找前端编解码器、ConversationTranscriber 的 AudioStreamFormat 配置以及可能一些可以使整个设置正常工作的后端音频处理的正确组合的建议。
使用 WebAudio API 捕获 PCM 格式的音频。设置 MediaRecorder 来捕获 PCM 音频流。检查采样率和位深度是否适合语音识别任务(通常为 16 kHz 采样率和 16 位深度)。
前端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audio Transcription</title>
</head>
<body>
<button onclick="startRecording()">Start Recording</button>
<button onclick="stopRecording()">Stop Recording</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lamejs/1.2.0/lame.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/libopus.js/dist/opus-stream-decoder.min.js"></script>
<script>
let mediaRecorder;
let audioChunks = [];
async function startRecording() {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = event => {
audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
const webmBlob = new Blob(audioChunks, { type: 'audio/webm' });
transcodeToMP3(webmBlob);
};
mediaRecorder.start();
}
function stopRecording() {
mediaRecorder.stop();
}
function transcodeToMP3(webmBlob) {
const reader = new FileReader();
reader.onloadend = function() {
const opusData = new OggOpusDecoder().decode(new Uint8Array(reader.result));
const mp3encoder = new lamejs.Mp3Encoder(1, 16000, 128); // Mono, 16 kHz sample rate, 128 kbps
const mp3Data = mp3encoder.encodeBuffer(opusData);
sendAudioToBackend(mp3Data);
};
reader.readAsArrayBuffer(webmBlob);
}
function sendAudioToBackend(mp3Data) {
const ws = new WebSocket('ws://localhost:8765');
ws.binaryType = 'arraybuffer';
ws.onopen = function() {
ws.send(mp3Data);
};
}
</script>
</body>
</html>
libopus.js
和 lamejs
将收集的音频块(WebM 格式)转码为 MP3。lamejs
或 libmp3lame.js
等 JavaScript 库进行浏览器内 MP3 编码。后端:
import asyncio
import websockets
from azure.cognitiveservices.speech import SpeechConfig, ConversationTranscriber
async def process_audio(websocket, path):
async for audio_data in websocket:
# Configure ConversationTranscriber
speech_config = SpeechConfig(subscription="your_subscription_key", region="your_region")
speech_config.speech_recognition_language = "en-US"
transcriber = ConversationTranscriber(speech_config)
# Process audio stream
result = await transcriber.recognize_once_async(audio_data)
# Handle transcription result
if result.reason == ResultReason.RecognizedSpeech:
print("Recognized: {}".format(result.text))
elif result.reason == ResultReason.NoMatch:
print("No speech could be recognized")
elif result.reason == ResultReason.Canceled:
cancellation_details = result.cancellation_details
print("Speech Recognition canceled: {}".format(cancellation_details.reason))
if cancellation_details.reason == CancellationReason.Error:
print("Error details: {}".format(cancellation_details.error_details))
start_server = websockets.serve(process_audio, "localhost", 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()