Skip to main content
This tutorial shows how to combine two live streams:
  • pyannoteAI streaming diarization tells you who is speaking and when speaker turns end.
  • OpenAI realtime transcription tells you what was said.
The key step is deciding which speaker label belongs to each transcript segment as both APIs stream events independently.

Prerequisites

  • A pyannoteAI API key from the dashboard
  • An OpenAI API key
  • Python 3.10+
  • Microphone access
Install dependencies:
Create a .env file:

How the merge works

pyannote emits diarization_speaker_start and diarization_speaker_end events. OpenAI emits transcription deltas and completed transcript segments. The script keeps two pieces of shared state:
  • active: speakers pyannote currently hears. Live transcript deltas are displayed with latest active speaker.
  • pending: speaker labels waiting for completed OpenAI transcript segments. When pyannote emits a speaker end event, script commits OpenAI’s audio buffer and queues that speaker label.
This line is the handoff point between diarization and transcription:
It tells OpenAI to finalize audio collected during the pyannote speaker turn. When OpenAI later emits transcription.completed, the script pops from pending and prints completed text with that speaker.

Complete script

Save this as live_diarized_transcription.py:
Run it:
Speak into your microphone. Partial text updates in place while OpenAI streams deltas. Completed turns print as separate lines with speaker labels like [SPEAKER_00]. Example output:

Important details

Create a pyannote stream

The script creates a streaming session with one simple request:
The response contains a WebSocket URL. Connect to it and send 16 kHz mono float32 PCM chunks every 100 ms. See Streaming Diarization for stream format details.

Use pyannote as turn detector

OpenAI realtime transcription can do its own turn detection, but this script disables it:
pyannote owns speaker turns, so speaker boundaries and transcript segment boundaries stay aligned.

Send one audio stream to both APIs

The microphone captures 16 kHz float32 audio. That exact frame goes to pyannote:
The same audio is upsampled to 24 kHz PCM16 and appended to OpenAI’s input buffer:

Attribute completed text to speaker turns

When pyannote ends a turn, queue that speaker label and commit OpenAI’s buffer:
When OpenAI returns completed text, assign queued speaker:
This queue is what combines realtime diarization segments with realtime transcription segments.

Next steps

  • Replace terminal output with WebSocket broadcasts to your frontend.
  • Store completed {speaker, text} turns in your database.
  • Add timestamps from pyannote events if your UI needs time-aligned captions.