Search code examples
swiftdecodingopenai-api

Swift API Call Decoding Issue: decoding error


Last week I made a chatGpt application using this tutorial: https://www.youtube.com/watch?v=bUDCW2NeO8Y . It worked just fine, but when I started working on it again today it didn't work. This uses the OpenAISwift package.

After 'debugging' it a bit I got this error:

failure(OpenAISwift.OpenAIError.decodingError(error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "object", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "object", intValue: nil) ("object").", underlyingError: nil))))

The code I use is almost the same as in the video, the only difference is that I trim white spaces and new lines (this isn't the issue I checked)

My code (that has the error) looks like this:

import OpenAISwift
import SwiftUI    
final class ViewModel: ObservableObject{
    init(){}
    
    private var client: OpenAISwift?
    
    func setup(){
        client = OpenAISwift(authToken: "MY_API_KEY")
    }
    
    func makeCall(text: String,
                  completion: @escaping (String) -> Void){
        client?.sendCompletion(with: text,
                               maxTokens: 500,
                               completionHandler: { result in
            switch result {
            case .success(let model):
                let output = model.choices.first?.text.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
                completion(output)
            case .failure:
                print("Failed: \(result)")
                break
            }
        })
    }
}

I hope someone could help me with this, because everything I have tried failed. I tried using other methods of calling the API but that also wouldn't work... So if you know what the issue is and how to fix it please let me know

Edit sendCompletion code:

public func sendCompletion(with prompt: String, model: OpenAIModelType = .gpt3(.davinci), maxTokens: Int = 16, temperature: Double = 1, completionHandler: @escaping (Result<OpenAI<TextResult>, OpenAIError>) -> Void) {
    let endpoint = Endpoint.completions
    let body = Command(prompt: prompt, model: model.modelName, maxTokens: maxTokens, temperature: temperature)
    let request = prepareRequest(endpoint, body: body)

makeRequest(request: request) { result in
    switch result {
    case .success(let success):
        do {
            let res = try JSONDecoder().decode(OpenAI<TextResult>.self, from: success)
            completionHandler(.success(res))
        } catch {
            completionHandler(.failure(.decodingError(error: error)))
        }
    case .failure(let failure):
        completionHandler(.failure(.genericError(error: failure)))
    }
}

}

Edit after feedback:

I updated the version, and after this it stopped giving me that error, but it now gives me a different one.... this one:

success(OpenAISwift.OpenAI<OpenAISwift.TextResult>(object: nil, model: nil, choices: nil, usage: nil, data: nil))


Solution

  • Try this example code, works well for me, if your YOUR-APIKEY is valid. Let me know if this does not work for you.

    Note, use the latest main branch of OpenAISwift, not other versions or tags.

    import Foundation
    import SwiftUI
    import OpenAISwift
    
    
    @MainActor
    class OpenAIModel: ObservableObject {
        
        @Published var answers = [String]()
        
        let client: OpenAISwift
        
        init() {
            client = OpenAISwift(authToken: "YOUR-APIKEY")
        }
        
        func ask(text: String) async {
            do {
                let result = try await client.sendCompletion(
                    with: text,
                    model: .gpt3(.davinci),
                    maxTokens: 500,
                    temperature: 1
                )
                let output = result.choices?.first?.text ?? "no answer"
                answers.append(output)
            } catch {
                print(error)
            }
        }
        
        func makeCall(text: String, completion: @escaping (String) -> Void) {
            client.sendCompletion(with: text, maxTokens: 500) { result in
                switch result {
                case .success(let model):
                    let output = model.choices?.first?.text.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
                    completion(output)
                case .failure:
                    print("---> Failed: \(result)")
                    completion("Failed")
                    break
                }
            }
        }
        
    }
    
    struct ContentView: View {
        @StateObject var openAI = OpenAIModel()
        let text = "explain Schrödinger's wave equation"
        
        var body: some View {
            VStack {
                Text("fetching...")
                ForEach(openAI.answers, id: \.self) { answer in
                    Text(answer)
                }
            }
            .onAppear {
                openAI.makeCall(text: text){ answer in
                    DispatchQueue.main.async {
                        openAI.answers.append(answer)
                    }
                }
            }
    //        .task{
    //            await openAI.ask(text: text)
    //        }
        }
    }
    

    Note also, there is an issue reported at: https://github.com/adamrushy/OpenAISwift/issues/28 regarding a bug in decoding, it may be relevant to your case.