You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 06:52:06