Skip to main content
Stream your microphone to Dialog-RSN-1 through the official openai SDK, and print each thing you say as a line of text. Then change the instructions and the same program becomes a support agent that hears the caller and answers in text. The SDK needs a new base URL and key, nothing else.

Full code on GitHub

A terminal transcriber in Python, and a voice-in, text-out support agent in Python and Node.

What you’ll build

  1. A transcriber. Speak, and each finished sentence prints with a timestamp, optionally appended to a file.
  2. A support agent. Speak, and Sam from a fictional outdoor store answers in text about three orders held in the prompt.
  3. The same support agent in Node, on the npm openai package.

How transcription works on Dialog-RSN-1

Dialog-RSN-1 has no separate speech-to-text model. It transcribes the caller as part of writing its reply, so every transcript belongs to a turn. That shapes the whole program:
  • You need a reply to get a transcript. Set create_response: true so each turn starts a reply on its own. With create_response: false, no transcript arrives until you send response.create.
  • The transcriber asks for a one-word reply. Its instructions say to answer “ok”, which keeps each turn short.
  • The transcript arrives when the turn ends. You get no partial text while the caller is still talking. The whole line lands in a few events just after input_audio_buffer.speech_stopped.
  • Only a completed reply sends .completed. If the caller cuts in while the reply is still generating, or the reply fails, the turn gets at most some .delta events and no .completed. The transcript is the last thing the model writes, so a turn interrupted early may get no transcript at all.
  • The reply starts before the transcript. The first response.output_text.delta comes within about 100 ms of speech_stopped, and the transcript follows. The support agent holds the reply back so the terminal reads in order.
  • audio.input.transcription changes nothing. The service accepts the field and echoes it in session.updated, but transcripts arrive the same with or without it.

Prerequisites

  1. A Dialog-RSN-1 API key. Sign up or log in at studio.poly.ai and create one in the API Keys tab. The quickstart walks through it.
  2. For Python: Python 3.12 and uv.
  3. For Node: Node 22. npm install compiles the naudiodon2 audio package, so you need a C++ toolchain.
  4. A microphone, or a 24 kHz, 16-bit mono WAV file to stream instead.

Run it

Speak, and each line prints when you finish the sentence. Add --reply to see the model’s “ok” under each line, and --out notes.txt to append each line to a file:
To test without a microphone, record a clip with the macOS say command and stream it at real time:

Step 1: Connect with the SDK

Pass the Dialog-RSN-1 base URL and key to the client. url is the full realtime URL, so drop /realtime and switch the scheme to get the base. The SDK builds wss://api.studio.poly.ai/v1/realtime?model=dialog-rsn-1, sends the key as Authorization: Bearer, and parses every event into its typed models.
url defaults to wss://api.studio.poly.ai/v1/realtime. Set DIALOG_REALTIME_URL in .env, or pass --url, to point somewhere else.

Step 2: Configure the session

  • output_modalities: ["text"]. This program prints text, so it asks for text. A new session defaults to ["audio"], where the server speaks the reply and sends its words as response.output_audio_transcript.*. Text only keeps the reply on response.output_text.*, which the program reads.
  • rate: 24000. The program opens the microphone at 24 kHz, so nothing resamples on the client. The service resamples to the model’s own rate.
  • create_response: true. Dialog-RSN-1 decides when you’ve finished and starts the turn itself. That turn carries the transcript.
The instructions ask for the shortest possible reply:

Step 3: Stream the microphone

sounddevice calls back with 100 ms of PCM16 at a time. The program base64-encodes each chunk and appends it to the input buffer:
The program never commits the buffer or asks for a reply. Dialog-RSN-1 does both when it hears the end of the turn.

Step 4: Print the transcript

Two events carry the transcript. conversation.item.input_audio_transcription.delta streams it in pieces, and conversation.item.input_audio_transcription.completed carries the whole line:
line() stamps the text with the time, prints it and appends it to the --out file. The response.done branch keeps what arrived when a reply ends without a .completed, so a line isn’t left half printed. Stop on invalid_request_error. It usually means the session.update was refused, which leaves the session on the server’s defaults:

Turn it into a support agent

support_agent.py keeps the connection, the session shape and the audio path. It changes three things. The instructions. prompt.py holds everything Sam knows: three orders in different states, the return and cancellation policy, and a rule to confirm the order before giving details. There are no tools. The data sits in the prompt. A seeded greeting. The program prints the greeting itself and adds it to the conversation as an assistant message, so the model’s history starts with it:
The reply waits for the transcript. Sam’s reply starts before the transcript of your line arrives. Printed in arrival order, the answer would sit above the question. The program buffers the reply until your line has printed:
Run it, in either language:
Say “I’m calling about order N W one zero four eight two, it’s under Maria Alvarez”, then “Can I still cancel it?”. That order has shipped, so Sam refuses and points you to a return:
Both programs take --file call.wav to stream a recording instead of the microphone, and --list-devices and --device to pick a microphone.

What the timing looks like

We streamed recorded clips to us-1 production over 14 turns, 20 ms at a time as a microphone would, from London (about 90 ms round trip): speech_stopped reports audio_end_ms, the point in your audio where Dialog-RSN-1 places the end of speech. That mark sits about 400 to 570 ms after the last word, so time your own measurements from the audio, not from audio_end_ms.

Troubleshooting

What this isn’t

The transcriber shows that a stock OpenAI Realtime client works unchanged against Dialog-RSN-1. It isn’t a full speech-to-text service. It has no speaker labels, no punctuation settings, and no partial results while the caller speaks.

Where to go next

Last modified on October 14, 2026