From 3af401d8a52b0f778ee3e45f29ed62e20a481bbd Mon Sep 17 00:00:00 2001 From: jamesrochabrun Date: Thu, 13 Nov 2025 21:48:53 -0800 Subject: [PATCH 1/2] Support for azure --- .../Public/Service/DefaultOpenAIService.swift | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/Sources/OpenAI/Public/Service/DefaultOpenAIService.swift b/Sources/OpenAI/Public/Service/DefaultOpenAIService.swift index 16206a14..6b30b369 100644 --- a/Sources/OpenAI/Public/Service/DefaultOpenAIService.swift +++ b/Sources/OpenAI/Public/Service/DefaultOpenAIService.swift @@ -82,35 +82,55 @@ struct DefaultOpenAIService: OpenAIService { func realtimeSession( model: String, configuration: OpenAIRealtimeSessionConfiguration) - async throws -> OpenAIRealtimeSession + async throws -> OpenAIRealtimeSession { // Build the WebSocket URL let baseURL = openAIEnvironment.baseURL.replacingOccurrences(of: "https://", with: "wss://") let version = openAIEnvironment.version ?? "v1" - let path = openAIEnvironment.proxyPath.map { "\($0)/\(version)" } ?? version - let urlString = "\(baseURL)/\(path)/realtime?model=\(model)" - + + // Check if this is an Azure endpoint (contains "azure_openai" in base URL or proxy path) + let isAzureEndpoint = openAIEnvironment.baseURL.contains("azure_openai") || + (openAIEnvironment.proxyPath?.contains("azure_openai") ?? false) + + let path: String + let urlString: String + + if isAzureEndpoint { + // Azure format: path/realtime?api-version=X&deployment=Y + // For Airbnb's Azure proxy, deployment is passed as a query parameter + path = openAIEnvironment.proxyPath ?? "" + urlString = "\(baseURL)/\(path)/realtime?api-version=\(version)&deployment=\(model)" + } else { + // OpenAI format: path/version/realtime?model=Y + path = openAIEnvironment.proxyPath.map { "\($0)/\(version)" } ?? version + urlString = "\(baseURL)/\(path)/realtime?model=\(model)" + } + guard let url = URL(string: urlString) else { throw APIError.requestFailed(description: "Invalid realtime session URL") } - + // Create the WebSocket request with auth headers var request = URLRequest(url: url) request.setValue(apiKey.value, forHTTPHeaderField: apiKey.headerField) - request.setValue("realtime=v1", forHTTPHeaderField: "openai-beta") - + + // Only add openai-beta header for non-Azure endpoints + if !isAzureEndpoint { + request.setValue("realtime=v1", forHTTPHeaderField: "openai-beta") + } + if let organizationID { request.setValue(organizationID, forHTTPHeaderField: "OpenAI-Organization") } - + // Add any extra headers extraHeaders?.forEach { key, value in request.setValue(value, forHTTPHeaderField: key) } - + // Create the WebSocket task let webSocketTask = URLSession.shared.webSocketTask(with: request) - + // Return the realtime session return OpenAIRealtimeSession( webSocketTask: webSocketTask, From 26cb0ef712f890830fd7e0fbe641f0ac37893ba8 Mon Sep 17 00:00:00 2001 From: jamesrochabrun Date: Thu, 13 Nov 2025 21:57:32 -0800 Subject: [PATCH 2/2] lint --- .../Public/Service/DefaultOpenAIService.swift | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Sources/OpenAI/Public/Service/DefaultOpenAIService.swift b/Sources/OpenAI/Public/Service/DefaultOpenAIService.swift index 6b30b369..f2c3f053 100644 --- a/Sources/OpenAI/Public/Service/DefaultOpenAIService.swift +++ b/Sources/OpenAI/Public/Service/DefaultOpenAIService.swift @@ -82,19 +82,19 @@ struct DefaultOpenAIService: OpenAIService { func realtimeSession( model: String, configuration: OpenAIRealtimeSessionConfiguration) - async throws -> OpenAIRealtimeSession + async throws -> OpenAIRealtimeSession { // Build the WebSocket URL let baseURL = openAIEnvironment.baseURL.replacingOccurrences(of: "https://", with: "wss://") let version = openAIEnvironment.version ?? "v1" - + // Check if this is an Azure endpoint (contains "azure_openai" in base URL or proxy path) let isAzureEndpoint = openAIEnvironment.baseURL.contains("azure_openai") || - (openAIEnvironment.proxyPath?.contains("azure_openai") ?? false) - + (openAIEnvironment.proxyPath?.contains("azure_openai") ?? false) + let path: String let urlString: String - + if isAzureEndpoint { // Azure format: path/realtime?api-version=X&deployment=Y // For Airbnb's Azure proxy, deployment is passed as a query parameter @@ -105,32 +105,32 @@ struct DefaultOpenAIService: OpenAIService { path = openAIEnvironment.proxyPath.map { "\($0)/\(version)" } ?? version urlString = "\(baseURL)/\(path)/realtime?model=\(model)" } - + guard let url = URL(string: urlString) else { throw APIError.requestFailed(description: "Invalid realtime session URL") } - + // Create the WebSocket request with auth headers var request = URLRequest(url: url) request.setValue(apiKey.value, forHTTPHeaderField: apiKey.headerField) - + // Only add openai-beta header for non-Azure endpoints if !isAzureEndpoint { request.setValue("realtime=v1", forHTTPHeaderField: "openai-beta") } - + if let organizationID { request.setValue(organizationID, forHTTPHeaderField: "OpenAI-Organization") } - + // Add any extra headers extraHeaders?.forEach { key, value in request.setValue(value, forHTTPHeaderField: key) } - + // Create the WebSocket task let webSocketTask = URLSession.shared.webSocketTask(with: request) - + // Return the realtime session return OpenAIRealtimeSession( webSocketTask: webSocketTask,