Azure OpenAI Realtime
Speech-to-speech with OpenAI's realtime models deployed on Azure, with AzureRealtimeLLMService.
Overview
AzureRealtimeLLMService:OpenAIRealtimeLLMServicepointed at an Azure OpenAI deployment of a realtime model (gpt-realtimeand friends). The session, events, function calling, transcripts and turn handling are those of the OpenAI service; this class changes the URL and the authentication.
It speaks Azure's v1 realtime API (/openai/v1/realtime), whose protocol is OpenAI's. URLs with
a dated api-version serve the older preview protocol, which this service doesn't implement: it
logs a warning when given one.
For Azure's own speech-to-speech API, with Azure voices, avatars and noise suppression, see Azure Voice Live.
Upstream page
Pipecat's documentation for the same service.
Source
packages/azure/src/realtime/llm.ts.
Azure docs
The realtime API over WebSocket on Azure.
Installation
bun add @pipedog/azureimport { AzureRealtimeLLMService } from "@pipedog/azure/realtime/llm";
import { SessionProperties } from "@pipedog/openai/realtime/events";The session classes come from @pipedog/openai/realtime/events, which @pipedog/azure
installs.
Prerequisites
- An Azure OpenAI (or Azure AI Foundry) resource with a realtime model deployed.
- The resource's API key, or a Microsoft Entra ID identity with access to it. The examples read
the key from
AZURE_OPENAI_API_KEY.
AzureRealtimeLLMService
Configuration
Prop
Type
Settings
AzureRealtimeLLMService.Settings (AzureRealtimeLLMSettings) has the same fields and defaults
as OpenAIRealtimeLLMSettings. model must be your
deployment's name: it is appended to baseUrl as ?model=<deployment>.
Usage
import { AzureRealtimeLLMService } from "@pipedog/azure/realtime/llm";
import {
AudioConfiguration,
AudioInput,
AudioOutput,
InputAudioTranscription,
SemanticTurnDetection,
SessionProperties,
} from "@pipedog/openai/realtime/events";
const llm = new AzureRealtimeLLMService({
apiKey: process.env.AZURE_OPENAI_API_KEY ?? "",
baseUrl: "wss://my-resource.openai.azure.com/openai/v1/realtime",
settings: new AzureRealtimeLLMService.Settings({
// The deployment name, sent as ?model=<deployment>.
model: "my-gpt-realtime-deployment",
systemInstruction: "You are a helpful assistant in a voice conversation.",
sessionProperties: new SessionProperties({
audio: new AudioConfiguration({
input: new AudioInput({
transcription: new InputAudioTranscription(),
turnDetection: new SemanticTurnDetection({ eagerness: "medium" }),
}),
output: new AudioOutput({ voice: "marin" }),
}),
}),
}),
});With Microsoft Entra ID instead of a key:
// For example getBearerTokenProvider(credential, "https://ai.azure.com/.default")
// from @azure/identity. It is called once per connection.
declare const tokenProvider: () => Promise<string>;
const withEntra = new AzureRealtimeLLMService({
tokenProvider,
baseUrl: "wss://my-resource.openai.azure.com/openai/v1/realtime",
settings: new AzureRealtimeLLMService.Settings({ model: "my-gpt-realtime-deployment" }),
});Event handlers
The same as OpenAIRealtimeLLMService:
on_conversation_item_created and on_conversation_item_updated.
Notes
- With an API key the socket sends it as the
api-keyheader. WithtokenProvider, the token is fetched before each connection and sent asAuthorization: Bearer <token>. One of the two is required. The service picks the header in_authHeaders(), the hookOpenAIRealtimeLLMServicecalls when it connects, and otherwise connects as that service does. - A
baseUrlthat already has a query string is used as given, so you can name the deployment (or other parameters) yourself. - Frames, turn detection, pre-roll and video input behave as in the OpenAI Realtime notes.
Runtime notes
| Runtime | Works | What it needs |
|---|---|---|
| Bun | ✅ yes | Nothing. |
| Node.js | ✅ yes | Nothing. |
| Deno | ✅ yes | Nothing. |
| Cloudflare Workers | ✅ yes | Nothing. |
Generated from pipecat.runtimes and pipecat.compat in packages/azure/package.json: ✅ means the compat smoke test passes on that runtime.
- The socket is opened with
websocketConnect()from core, which sends the auth header from the globalWebSocketon Bun, Node and Deno, and throughfetchon Cloudflare Workers. - Browsers can't set WebSocket headers, so this service is for servers.
pipedog is an unofficial community TypeScript port of Pipecat. It is not affiliated with or endorsed by Daily or the Pipecat project.
Portions adapted from the Pipecat documentation, Copyright (c) 2024–2025 Daily, BSD-2-Clause (see apps/docs/LICENSE-pipecat-docs).