Skip to content

Implementing cross-platform support by supporting Linux-friendly HTTP clients #143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
131 changes: 131 additions & 0 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ let package = Package(
name: "SwiftOpenAI",
targets: ["SwiftOpenAI"]),
],
dependencies: [
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.25.2"),
],
Comment on lines +19 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is possible, but can we scope this to only linux for now? ie wrap in #if os(Linux) ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made this change by using condition: .when(platforms: [.linux]), since #if os(Linux) doesn't work in Package.swift.

targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "SwiftOpenAI"),
name: "SwiftOpenAI",
dependencies: [
.product(name: "AsyncHTTPClient", package: "async-http-client")
]),
.testTarget(
name: "SwiftOpenAITests",
dependencies: ["SwiftOpenAI"]),
Expand Down
3 changes: 2 additions & 1 deletion Sources/OpenAI/AIProxy/AIProxyCertificatePinning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Created by Lou Zell on 6/23/24.
//

#if !os(Linux)
import Foundation
import OSLog

Expand Down Expand Up @@ -181,3 +181,4 @@ private func getServerCert(secTrust: SecTrust) -> SecCertificate? {
return SecTrustGetCertificateAtIndex(secTrust, 0)
}
}
#endif
27 changes: 26 additions & 1 deletion Sources/OpenAI/AIProxy/AIProxyService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Created by Lou Zell on 3/27/24.
//

#if !os(Linux)
import Foundation

private let aiproxySecureDelegate = AIProxyCertificatePinningDelegate()
Expand Down Expand Up @@ -44,8 +44,10 @@ struct AIProxyService: OpenAIService {
self.organizationID = organizationID
self.debugEnabled = debugEnabled
openAIEnvironment = .init(baseURL: serviceURL ?? "https://api.aiproxy.pro", proxyPath: nil, version: "v1")
self.httpClient = NoOpClient()
}

let httpClient: HTTPClient
let session: URLSession
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with the code, but it seems weird to see both HTTPClient and URLSession properties here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not remove the session property, the NoOpClient type, and do

self.httpClient = URLSessionHTTPClientAdapter(urlSession: URLSession(
      configuration: .default,
      delegate: aiproxySecureDelegate,
      delegateQueue: nil))

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a good idea, removed the NoOpClient in favor of your solution!

let decoder: JSONDecoder
let openAIEnvironment: OpenAIEnvironment
Expand Down Expand Up @@ -1314,3 +1316,26 @@ struct AIProxyService: OpenAIService {
private let organizationID: String?

}

// MARK: - NoOpClient

// An HTTPClient created specifically for AIProxyService, since it will only be used on iOS/macOS
// and we will not be supporting it on Linux.
private struct NoOpClient: HTTPClient {
func data(for request: HTTPRequest) async throws -> (Data, HTTPResponse) {
(
Data(),
HTTPResponse(statusCode: 500, headers: [:])
)
}

func bytes(for request: HTTPRequest) async throws -> (HTTPByteStream, HTTPResponse) {
(
HTTPByteStream.bytes(
.init(unfolding: { nil })
),
HTTPResponse(statusCode: 500, headers: [:])
)
}
}
#endif
3 changes: 2 additions & 1 deletion Sources/OpenAI/AIProxy/Endpoint+AIProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Created by Lou Zell on 3/26/24.
//

#if !os(Linux)
import DeviceCheck
import Foundation
import OSLog
Expand Down Expand Up @@ -242,3 +242,4 @@ private func copy_mac_address() -> CFData? {
return nil
}
#endif
#endif
9 changes: 6 additions & 3 deletions Sources/OpenAI/Azure/DefaultOpenAIAzureService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@
//

import Foundation
#if os(Linux)
import FoundationNetworking
#endif

final public class DefaultOpenAIAzureService: OpenAIService {

public init(
azureConfiguration: AzureOpenAIConfiguration,
urlSessionConfiguration: URLSessionConfiguration = .default,
httpClient: HTTPClient,
decoder: JSONDecoder = .init(),
debugEnabled: Bool)
{
session = URLSession(configuration: urlSessionConfiguration)
self.httpClient = httpClient
self.decoder = decoder
openAIEnvironment = OpenAIEnvironment(
baseURL: "https://\(azureConfiguration.resourceName)/openai.azure.com",
Expand All @@ -27,7 +30,7 @@ final public class DefaultOpenAIAzureService: OpenAIService {
self.debugEnabled = debugEnabled
}

public let session: URLSession
public let httpClient: HTTPClient
public let decoder: JSONDecoder
public let openAIEnvironment: OpenAIEnvironment

Expand Down
6 changes: 3 additions & 3 deletions Sources/OpenAI/LocalModelService/LocalModelService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ struct LocalModelService: OpenAIService {
baseURL: String,
proxyPath: String? = nil,
overrideVersion: String? = nil,
configuration: URLSessionConfiguration = .default,
httpClient: HTTPClient,
decoder: JSONDecoder = .init(),
debugEnabled: Bool)
{
session = URLSession(configuration: configuration)
self.httpClient = httpClient
self.decoder = decoder
self.apiKey = apiKey
openAIEnvironment = OpenAIEnvironment(baseURL: baseURL, proxyPath: proxyPath, version: overrideVersion ?? "v1")
Expand Down Expand Up @@ -49,7 +49,7 @@ struct LocalModelService: OpenAIService {
"Currently, this API is not supported. We welcome and encourage contributions to our open-source project. Please consider opening an issue or submitting a pull request to add support for this feature.")
}

let session: URLSession
let httpClient: HTTPClient
let decoder: JSONDecoder
let openAIEnvironment: OpenAIEnvironment

Expand Down
Loading