如何在AWS Transcribe中实现说话人区分,仅保留目标说话人语音?
实现AWS Transcribe流式转写的目标说话人语音过滤
问题背景
aws-sdk版本: 3.797.0
已基于AWS Transcribe实现基础语音转文本功能,需求是添加说话人区分,仅保留目标说话人的语音内容,排除无关语音。
解决方案
要实现该需求,需借助AWS Transcribe的说话人标签功能,结合转录结果的过滤逻辑完成,具体步骤如下:
1. 开启说话人识别功能
在StartStreamTranscriptionCommand的配置中添加说话人相关参数,让Transcribe返回每个转录片段对应的说话人ID:
const command = new StartStreamTranscriptionCommand({ LanguageCode: LanguageCode.EN_US, MediaEncoding: 'pcm', MediaSampleRateHertz: audioContext.sampleRate, ShowSpeakerLabels: true, // 开启说话人标签识别 MaxSpeakerLabels: 2, // 根据场景设置最多识别的说话人数量,比如2人对话就设2 AudioStream: { [Symbol.asyncIterator]: async function* () { while (true) { const { value, done } = await audioDataIterator.read(); if (done) break; yield value; } }, }, });
2. 确定目标说话人ID
如果是实时场景,先让目标说话人说一段参考内容(比如"测试语音"),在转录结果中记录下对应的说话人ID(格式为spk_0、spk_1等);如果是预先已知目标说话人特征,可结合AWS Transcribe批量API建立说话人档案,再匹配流式转写的结果。
3. 过滤目标说话人的转录内容
修改processTranscriptResultStream函数,只保留目标说话人ID对应的文本片段:
async processTranscriptResultStream(stream: any, box_index: number, transcribeTillNow: string) { const targetSpeakerId = 'spk_0'; // 替换成实际识别到的目标说话人ID let fullTranscript = transcribeTillNow; for await (const event of stream) { if (event.TranscriptEvent?.Transcript?.Results) { for (const result of event.TranscriptEvent.Transcript.Results) { if (!result.IsPartial) { // 过滤出目标说话人的转录片段 const targetSegments = result.Alternatives[0].Items.filter( item => item.SpeakerLabel === targetSpeakerId ); // 拼接目标说话人的文本内容 const targetText = targetSegments.map(item => item.Content).join(' '); if (targetText) { fullTranscript += ' ' + targetText; this.transcribeResultSubject.next({ transcript: fullTranscript.trim(), box_index }); } } } } } }
4. 修复停止流的代码问题
你的stopStreaming函数中this.mediaRecorder未在startStreaming中定义,需改为引用AudioWorkletNode实例,同时关闭媒体流:
// 在类中添加实例变量 private processor: AudioWorkletNode | undefined; private stream: MediaStream | undefined; // 修改startStreaming中的createAudioDataReadableStream createAudioDataReadableStream(audioContext: AudioContext, source: MediaStreamAudioSourceNode, recordingProps: any): ReadableStream { return new ReadableStream({ start(controller) { const processor = new AudioWorkletNode(audioContext, 'recording-processor', { processorOptions: recordingProps }); this.processor = processor; // 保存为实例变量 processor.port.onmessage = (event) => { const eventData = event.data; if (eventData.message === "SHARE_RECORDING_BUFFER") { const abuffer = pcmEncode(eventData.buffer[0]); const audiodata = new Uint8Array(abuffer); controller.enqueue({ AudioEvent: { AudioChunk: audiodata } }); } }; processor.port.postMessage({ message: "UPDATE_RECORDING_STATE", setRecording: true }); source.connect(processor); }.bind(this), // 绑定this以访问实例变量 }); } // 修改stopStreaming函数 stopStreaming() { this.stopStreamingAsync = true; // 停止音频处理器 if (this.processor) { this.processor.port.postMessage({ message: "UPDATE_RECORDING_STATE", setRecording: false, }); this.processor.port.postMessage({ message: "STOP_STREAM" }); this.processor.port.close(); this.processor.disconnect(); } // 关闭媒体流 if (this.stream) { this.stream.getTracks().forEach(track => track.stop()); } }
内容的提问来源于stack exchange,提问作者SGR
相关产品推荐
相关产品推荐

