From 6dbd9d9444cb47ca0acb42600c283fe4a9cdcc12 Mon Sep 17 00:00:00 2001 From: Kyrylo Mukha Date: Sat, 11 Mar 2023 17:34:39 +0200 Subject: [PATCH] Updated error parsing for more readable information. --- Example/OpenAIKit/ViewController.swift | 12 ++++++-- OpenAIKit.podspec | 2 +- Package.swift | 3 +- README.md | 30 ++++++++++++++++--- .../OpenAIKit/Helpers/OpenAIKitNetwork.swift | 14 +++++---- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/Example/OpenAIKit/ViewController.swift b/Example/OpenAIKit/ViewController.swift index 9f29252..3854529 100644 --- a/Example/OpenAIKit/ViewController.swift +++ b/Example/OpenAIKit/ViewController.swift @@ -44,14 +44,19 @@ extension ViewController { textView.text = " " let prompt = textField.text ?? "" + /// You can put messages you send and recieved before for maka chat uderstand your context. + /// Be careful! There is limit of total tokens count. The total limit of tokens is 4096. + /// So if you requests maxTokens = 2048, total sum of tokens in newMessage + previousMessages must be 2048. + /// Number of tokens you can recieve from response model from field usage. + let previousMessages: [AIMessage] = [] - openAI.sendCompletion(prompt: prompt, model: .gptV3_5(.davinciText003), maxTokens: 2048) { [weak self] result in + openAI?.sendChatCompletion(newMessage: AIMessage(role: .user, content: prompt), previousMessages: previousMessages, model: .gptV3_5(.gptTurbo), maxTokens: 2048, n: 1, completion: { [weak self] result in in DispatchQueue.main.async { self?.stopLoading() } switch result { case .success(let aiResult): DispatchQueue.main.async { [weak self] in - if let text = aiResult.choices.first?.text { + if let text = aiResult.choices.first?.message?.content { self?.textView.text = text } } @@ -62,6 +67,9 @@ extension ViewController { self?.present(alert, animated: true) } } + }) + + openAI.sendCompletion(prompt: prompt, model: .gptV3_5(.davinciText003), maxTokens: 2048) { [weak self] _ in } } } diff --git a/OpenAIKit.podspec b/OpenAIKit.podspec index 28c74cb..409bf7f 100644 --- a/OpenAIKit.podspec +++ b/OpenAIKit.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'OpenAIKit' - s.version = '1.1.1' + s.version = '1.1.2' s.summary = 'OpenAI is a community-maintained repository containing Swift implementation over OpenAI public API.' s.description = <<-DESC diff --git a/Package.swift b/Package.swift index e3909f3..746a4da 100644 --- a/Package.swift +++ b/Package.swift @@ -13,7 +13,8 @@ let package = Package( targets: [ .target( name: "OpenAIKit", - dependencies: []), + dependencies: [], + path: "Sources"), .testTarget( name: "OpenAIKitTests", dependencies: ["OpenAIKit"]), diff --git a/README.md b/README.md index 7576a83..d75e7d2 100644 --- a/README.md +++ b/README.md @@ -49,11 +49,11 @@ import OpenAIKit public let openAI = OpenAIKit(apiToken: apiToken, organization: organizationName) ``` +### Completions Create a call to the completions API, passing in a text prompt. ```swift -openAI.sendCompletion(prompt: "Hello!", model: .gptV3_5(.gptTurbo), maxTokens: 2048) { [weak self] result in - +openAI.sendCompletion(prompt: "Hello!", model: .gptV3_5(.davinciText003), maxTokens: 2048) { [weak self] result in switch result { case .success(let aiResult): DispatchQueue.main.async { @@ -70,9 +70,9 @@ openAI.sendCompletion(prompt: "Hello!", model: .gptV3_5(.gptTurbo), maxTokens: 2 } } ``` -Also supports async/await usage for all methods. +Also supports async/await usage for all methods. Here is example. ```swift -let result = await openAI.sendCompletion(prompt: "Hello!", model: .gptV3_5(.gptTurbo), maxTokens: 2048) +let result = await openAI.sendCompletion(prompt: "Hello!", model: .gptV3_5(.davinciText003), maxTokens: 2048) switch result { case .success(let aiResult): @@ -85,6 +85,28 @@ case .failure(let error): print(error.localizedDescription) } ``` +### Chat Completions +Chat completions almost the same as completions, there only few differences: + + - It can understand context with pathing previous chat messages ([read more](https://platform.openai.com/docs/guides/chat)). + - Response text located in message field of retrieved completion + - Supports **ONLY** *gpt-3.5-turbo* and *gpt-3.5-turbo-0301* models ([read more about models compatibility](https://platform.openai.com/docs/models/model-endpoint-compatability)). +```swift +openAI?.sendChatCompletion(newMessage: AIMessage(role: .user, content: prompt), previousMessages: [], model: .gptV3_5(.gptTurbo), maxTokens: 2048, n: 1, completion: { [weak self] result in in + DispatchQueue.main.async { self?.stopLoading() } + + switch result { + case .success(let aiResult): + // Handle result actions + if let text = aiResult.choices.first?.message?.content { + print(text) + } + case .failure(let error): + // Handle error actions + print(error.localizedDescription) + } +}) +``` ### Generate Image [DALLĀ·E](https://platform.openai.com/docs/models/dall-e) is a AI system that can create realistic images and art from a description in natural language. We currently support the ability, given a prommpt, to create a new image with a certain size, edit an existing image, or create variations of a user provided image. diff --git a/Sources/OpenAIKit/Helpers/OpenAIKitNetwork.swift b/Sources/OpenAIKit/Helpers/OpenAIKitNetwork.swift index 15997bd..9a8d859 100644 --- a/Sources/OpenAIKit/Helpers/OpenAIKitNetwork.swift +++ b/Sources/OpenAIKit/Helpers/OpenAIKitNetwork.swift @@ -14,8 +14,6 @@ import FoundationXML public enum OpenAINetworkError: Error { case invalidURL case invalidResponse - case requestFailed(Error) - case decodeFailed(Error) } public final class OpenAIKitNetwork { @@ -41,7 +39,7 @@ public final class OpenAIKitNetwork { let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { - completion(.failure(OpenAINetworkError.requestFailed(error))) + completion(.failure(error)) return } @@ -51,7 +49,13 @@ public final class OpenAIKitNetwork { } guard 200 ... 299 ~= response.statusCode else { - let error = OpenAINetworkError.requestFailed(NSError(domain: NSURLErrorDomain, code: response.statusCode, userInfo: nil)) + var userInfo: [String: Any] = [:] + + if let decodedError = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { + userInfo = decodedError + } + + let error = NSError(domain: NSURLErrorDomain, code: response.statusCode, userInfo: userInfo) completion(.failure(error)) return } @@ -61,7 +65,7 @@ public final class OpenAIKitNetwork { let responseObj = try decoder.decode(ResponseType.self, from: data) completion(.success(responseObj)) } catch { - completion(.failure(OpenAINetworkError.decodeFailed(error))) + completion(.failure(error)) } }