refactor: OpenAIRealtime

This commit is contained in:
Ishaan Jaffer 2026-02-03 16:31:26 -08:00
parent ffb6265c01
commit 962e330596

View file

@ -16,6 +16,51 @@ from ..openai import OpenAIChatCompletion
class OpenAIRealtime(OpenAIChatCompletion):
"""
Base handler for OpenAI-compatible realtime WebSocket connections.
Subclasses can override template methods to customize:
- _get_default_api_base(): Default API base URL
- _get_additional_headers(): Extra headers beyond Authorization
- _get_ssl_config(): SSL configuration for WebSocket connection
"""
def _get_default_api_base(self) -> str:
"""
Get the default API base URL for this provider.
Override this in subclasses to set provider-specific defaults.
"""
return "https://api.openai.com/"
def _get_additional_headers(self, api_key: str) -> dict:
"""
Get additional headers beyond Authorization.
Override this in subclasses to customize headers (e.g., remove OpenAI-Beta).
Args:
api_key: API key for authentication
Returns:
Dictionary of additional headers
"""
return {
"Authorization": f"Bearer {api_key}",
"OpenAI-Beta": "realtime=v1",
}
def _get_ssl_config(self, url: str) -> Any:
"""
Get SSL configuration for WebSocket connection.
Override this in subclasses to customize SSL behavior.
Args:
url: WebSocket URL (ws:// or wss://)
Returns:
SSL configuration (None, True, or SSLContext)
"""
return None if url.startswith("ws://") else get_shared_realtime_ssl_context()
def _construct_url(self, api_base: str, query_params: RealtimeQueryParams) -> str:
"""
Construct the backend websocket URL with all query parameters (including 'model').
@ -45,8 +90,9 @@ class OpenAIRealtime(OpenAIChatCompletion):
):
import websockets
from websockets.asyncio.client import ClientConnection
if api_base is None:
api_base = "https://api.openai.com/"
api_base = self._get_default_api_base()
if api_key is None:
raise ValueError("api_key is required for OpenAI realtime calls")
@ -56,30 +102,27 @@ class OpenAIRealtime(OpenAIChatCompletion):
url = self._construct_url(api_base, query_params)
try:
# Only use SSL context for secure websocket connections (wss://)
# websockets library doesn't accept ssl argument for ws:// URIs
ssl_context = None if url.startswith("ws://") else get_shared_realtime_ssl_context()
# Get provider-specific SSL configuration
ssl_config = self._get_ssl_config(url)
# Get provider-specific headers
headers = self._get_additional_headers(api_key)
# Log a masked request preview consistent with other endpoints.
logging_obj.pre_call(
input=None,
api_key=api_key,
additional_args={
"api_base": url,
"headers": {
"Authorization": f"Bearer {api_key}",
"OpenAI-Beta": "realtime=v1",
},
"headers": headers,
"complete_input_dict": {"query_params": query_params},
},
)
async with websockets.connect( # type: ignore
url,
additional_headers={
"Authorization": f"Bearer {api_key}", # type: ignore
"OpenAI-Beta": "realtime=v1",
},
additional_headers=headers, # type: ignore
max_size=REALTIME_WEBSOCKET_MAX_MESSAGE_SIZE_BYTES,
ssl=ssl_context,
ssl=ssl_config,
) as backend_ws:
realtime_streaming = RealTimeStreaming(
websocket, cast(ClientConnection, backend_ws), logging_obj