Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,36 @@ Import the framework in your project:

[Create an OpenAI API key](https://platform.openai.com/account/api-keys) and add it to your configuration:

`let openAI = OpenAISwift(authToken: "TOKEN")`
`let openAI: OpenAISwift = OpenAISwift(config: OpenAISwift.Config.makeDefaultOpenAI(apiKey: "TOKEN"))`


To follow [OpenAI requirements](https://platform.openai.com/docs/api-reference/authentication)

> Remember that your API key is a secret! Do not share it with others or expose it in any client-side code (browsers, apps). Production requests must be routed through your own backend server where your API key can be securely loaded from an environment variable or key management service.

and basic industrial safety you should not call OpenAI API directly.

```swift
private lazy var proxyOpenAIBackend: OpenAISwift = .init(
config: OpenAISwift.Config(
baseURL: "http://localhost",
endpointPrivider: OpenAIEndpointProvider(source: .proxy(path: { _ -> String in
"/chat/completions"
}, method: { _ -> String in
"POST"
})),
session: session,
authorizeRequest: { [weak self] request in
self?.authorizeRequest(&request)
}
))

private func authorizeRequest(_ request: inout URLRequest) {
if let apiKey = try? Encryptor.getApiToken() {
request.setValue(apiKey, forHTTPHeaderField: "X-API-KEY")
}
}
```

This framework supports Swift concurrency; each example below has both an async/await and completion handler variant.

Expand Down
12 changes: 12 additions & 0 deletions Sources/OpenAISwift/Models/ChatMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ public struct ChatMessage: Codable, Identifiable {
self.role = role
self.content = content
}


// MARK: - Custom Encoding
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(role, forKey: .role)
try container.encodeIfPresent(content, forKey: .content)
}

private enum CodingKeys: String, CodingKey {
case role, content
}
}

/// A structure that represents a chat conversation.
Expand Down
7 changes: 6 additions & 1 deletion Sources/OpenAISwift/OpenAISwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import FoundationXML
#endif

public enum OpenAIError: Error {
case networkError(code: Int)
case genericError(error: Error)
case decodingError(error: Error)
case chatError(error: ChatError.Payload)
Expand Down Expand Up @@ -294,11 +295,15 @@ extension OpenAISwift {
let task = session.dataTask(with: request) { (data, response, error) in
if let error = error {
completionHandler(.failure(error))
} else if let response = response as? HTTPURLResponse, !(200...299).contains(response.statusCode) {
completionHandler(.failure(OpenAIError.networkError(code: response.statusCode)))
} else if let data = data {
completionHandler(.success(data))
} else {
let error = NSError(domain: "OpenAI", code: 6666, userInfo: [NSLocalizedDescriptionKey: "Unknown error"])
completionHandler(.failure(OpenAIError.genericError(error: error)))
}
}

task.resume()
}

Expand Down