Skip to content

Commit 9fda141

Browse files
feat(azure): support for the Realtime API (#1963)
1 parent 3dee863 commit 9fda141

File tree

4 files changed

+65
-5
lines changed

4 files changed

+65
-5
lines changed

src/openai/_utils/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@
2525
coerce_integer as coerce_integer,
2626
file_from_path as file_from_path,
2727
parse_datetime as parse_datetime,
28+
is_azure_client as is_azure_client,
2829
strip_not_given as strip_not_given,
2930
deepcopy_minimal as deepcopy_minimal,
3031
get_async_library as get_async_library,
3132
maybe_coerce_float as maybe_coerce_float,
3233
get_required_header as get_required_header,
3334
maybe_coerce_boolean as maybe_coerce_boolean,
3435
maybe_coerce_integer as maybe_coerce_integer,
36+
is_async_azure_client as is_async_azure_client,
3537
)
3638
from ._typing import (
3739
is_list_type as is_list_type,

src/openai/_utils/_utils.py

+16
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import inspect
66
import functools
77
from typing import (
8+
TYPE_CHECKING,
89
Any,
910
Tuple,
1011
Mapping,
@@ -30,6 +31,9 @@
3031
_SequenceT = TypeVar("_SequenceT", bound=Sequence[object])
3132
CallableT = TypeVar("CallableT", bound=Callable[..., Any])
3233

34+
if TYPE_CHECKING:
35+
from ..lib.azure import AzureOpenAI, AsyncAzureOpenAI
36+
3337

3438
def flatten(t: Iterable[Iterable[_T]]) -> list[_T]:
3539
return [item for sublist in t for item in sublist]
@@ -412,3 +416,15 @@ def json_safe(data: object) -> object:
412416
return data.isoformat()
413417

414418
return data
419+
420+
421+
def is_azure_client(client: object) -> TypeGuard[AzureOpenAI]:
422+
from ..lib.azure import AzureOpenAI
423+
424+
return isinstance(client, AzureOpenAI)
425+
426+
427+
def is_async_azure_client(client: object) -> TypeGuard[AsyncAzureOpenAI]:
428+
from ..lib.azure import AsyncAzureOpenAI
429+
430+
return isinstance(client, AsyncAzureOpenAI)

src/openai/lib/azure.py

+31-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import httpx
99

10-
from .._types import NOT_GIVEN, Omit, Timeout, NotGiven
10+
from .._types import NOT_GIVEN, Omit, Query, Timeout, NotGiven
1111
from .._utils import is_given, is_mapping
1212
from .._client import OpenAI, AsyncOpenAI
1313
from .._compat import model_copy
@@ -307,6 +307,21 @@ def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions:
307307

308308
return options
309309

310+
def _configure_realtime(self, model: str, extra_query: Query) -> tuple[Query, dict[str, str]]:
311+
auth_headers = {}
312+
query = {
313+
**extra_query,
314+
"api-version": self._api_version,
315+
"deployment": model,
316+
}
317+
if self.api_key != "<missing API key>":
318+
auth_headers = {"api-key": self.api_key}
319+
else:
320+
token = self._get_azure_ad_token()
321+
if token:
322+
auth_headers = {"Authorization": f"Bearer {token}"}
323+
return query, auth_headers
324+
310325

311326
class AsyncAzureOpenAI(BaseAzureClient[httpx.AsyncClient, AsyncStream[Any]], AsyncOpenAI):
312327
@overload
@@ -555,3 +570,18 @@ async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOp
555570
raise ValueError("Unable to handle auth")
556571

557572
return options
573+
574+
async def _configure_realtime(self, model: str, extra_query: Query) -> tuple[Query, dict[str, str]]:
575+
auth_headers = {}
576+
query = {
577+
**extra_query,
578+
"api-version": self._api_version,
579+
"deployment": model,
580+
}
581+
if self.api_key != "<missing API key>":
582+
auth_headers = {"api-key": self.api_key}
583+
else:
584+
token = await self._get_azure_ad_token()
585+
if token:
586+
auth_headers = {"Authorization": f"Bearer {token}"}
587+
return query, auth_headers

src/openai/resources/beta/realtime/realtime.py

+16-4
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@
2121
)
2222
from ...._types import NOT_GIVEN, Query, Headers, NotGiven
2323
from ...._utils import (
24+
is_azure_client,
2425
maybe_transform,
2526
strip_not_given,
2627
async_maybe_transform,
28+
is_async_azure_client,
2729
)
2830
from ...._compat import cached_property
2931
from ...._models import construct_type_unchecked
@@ -319,11 +321,16 @@ async def __aenter__(self) -> AsyncRealtimeConnection:
319321
except ImportError as exc:
320322
raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc
321323

324+
extra_query = self.__extra_query
325+
auth_headers = self.__client.auth_headers
326+
if is_async_azure_client(self.__client):
327+
extra_query, auth_headers = await self.__client._configure_realtime(self.__model, extra_query)
328+
322329
url = self._prepare_url().copy_with(
323330
params={
324331
**self.__client.base_url.params,
325332
"model": self.__model,
326-
**self.__extra_query,
333+
**extra_query,
327334
},
328335
)
329336
log.debug("Connecting to %s", url)
@@ -336,7 +343,7 @@ async def __aenter__(self) -> AsyncRealtimeConnection:
336343
user_agent_header=self.__client.user_agent,
337344
additional_headers=_merge_mappings(
338345
{
339-
**self.__client.auth_headers,
346+
**auth_headers,
340347
"OpenAI-Beta": "realtime=v1",
341348
},
342349
self.__extra_headers,
@@ -496,11 +503,16 @@ def __enter__(self) -> RealtimeConnection:
496503
except ImportError as exc:
497504
raise OpenAIError("You need to install `openai[realtime]` to use this method") from exc
498505

506+
extra_query = self.__extra_query
507+
auth_headers = self.__client.auth_headers
508+
if is_azure_client(self.__client):
509+
extra_query, auth_headers = self.__client._configure_realtime(self.__model, extra_query)
510+
499511
url = self._prepare_url().copy_with(
500512
params={
501513
**self.__client.base_url.params,
502514
"model": self.__model,
503-
**self.__extra_query,
515+
**extra_query,
504516
},
505517
)
506518
log.debug("Connecting to %s", url)
@@ -513,7 +525,7 @@ def __enter__(self) -> RealtimeConnection:
513525
user_agent_header=self.__client.user_agent,
514526
additional_headers=_merge_mappings(
515527
{
516-
**self.__client.auth_headers,
528+
**auth_headers,
517529
"OpenAI-Beta": "realtime=v1",
518530
},
519531
self.__extra_headers,

0 commit comments

Comments
 (0)