Mr. Man
Mr. Man

Reputation: 38

Cannot pass function of type '(OpenAIChatResponse) async -> Void' to parameter expecting synchronous function type with two functions

I have two functions:

    @MainActor func sendMessage(messages: [Message], completion: @escaping (_ response: OpenAIChatResponse) -> Void) async {
        let openAIMessages = messages.map({OpenAIChatMessage(role: $0.role, content: $0.content)})
        let body = OpenAIChatBody(model: "gpt-3.5-turbo", messages: openAIMessages)
        var request = URLRequest(url: endpointUrl!)
        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
        request.httpMethod = "POST"
        do {
            let encoded = try JSONEncoder().encode(body)
            request.httpBody = encoded
        } catch {
            print(error)
        }
        request.setValue("Bearer \(Constants.openAIApiKey)", forHTTPHeaderField: "Authorization")
        
        do {
            Task {
                let (data, _) = try await URLSession.shared.data(for: request)
                let responseData = try JSONDecoder().decode(OpenAIChatResponse.self, from: data)
                completion(responseData)
            }
        } catch NetworkError.badUrl {
            print("There was an error creating the URL")
        } catch NetworkError.badResponse {
            print("Did not get a valid response")
        } catch NetworkError.badStatus {
            print("Did not get a 2xx status code from the response")
        } catch NetworkError.failedToDecodeResponse {
            print("Failed to decode response into the given type")
        } catch {
            print("An error occured downloading the data")
        }
    }
        func sendMessage2(myMessage: String) {
            let newMessage = Message(id: UUID(), role: .user, content: myMessage, createAt: Date())
            messages.append(newMessage)
            Task {
                try await openAIService.sendMessage(messages: messages, completion: { response in
                    guard let receivedOpenAIMessage = response.choices?.first?.message else {
                        return
                    }
                    let receivedMessage = Message(id: UUID(), role: receivedOpenAIMessage.role, content: receivedOpenAIMessage.content, createAt: Date())
                    await MainActor.run {
                        messages.append(receivedMessage)
                    }
                })
            }
        }

But I am getting the error: Cannot pass function of type '(OpenAIChatResponse) async -> Void' to parameter expecting synchronous function type with two functions when trying to use the sendMessage2 function. I just switched to using completionHandlers to try and get around the async and await pieces of code. But I don't know how to resolve this error. Here is an image of where it shows up. What is this error and how do I get rid of it?

Error location

Upvotes: 0

Views: 289

Answers (1)

Do not mix completion handlers and the async/await concurrency framework.

Try this approach using only the async/await concurrency framework.

func sendMessage(messages: [Message]) async -> OpenAIChatResponse {
    let openAIMessages = messages.map{OpenAIChatMessage(role: $0.role, content: $0.content)}
    let body = OpenAIChatBody(model: "gpt-3.5-turbo", messages: openAIMessages)
    
    var request = URLRequest(url: endpointUrl!)
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
    request.httpMethod = "POST"
    do {
        let encoded = try JSONEncoder().encode(body)
        request.httpBody = encoded
    } catch {
        print(error)
    }
    request.setValue("Bearer \(Constants.openAIApiKey)", forHTTPHeaderField: "Authorization")
    
    do {
        let (data, _) = try await URLSession.shared.data(for: request)
        
        return try JSONDecoder().decode(OpenAIChatResponse.self, from: data)
        
    } catch NetworkError.badUrl {
        print("There was an error creating the URL")
    } catch NetworkError.badResponse {
        print("Did not get a valid response")
    } catch NetworkError.badStatus {
        print("Did not get a 2xx status code from the response")
    } catch NetworkError.failedToDecodeResponse {
        print("Failed to decode response into the given type")
    } catch {
        // todo deal with the error
        print(error)
    }
}

func sendMessage2(myMessage: String) async {
    let newMessage = Message(id: UUID(), role: .user, content: myMessage, createAt: Date())
    messages.append(newMessage)
    do {
        let response = try await sendMessage(messages: messages)
        guard let receivedOpenAIMessage = response.text else {
            return
        }
        let receivedMessage = Message(id: UUID(), role: receivedOpenAIMessage.role, content: receivedOpenAIMessage.content, createAt: Date())
        messages.append(receivedMessage)
    } catch {
        // todo deal with the error
        print(error)
    }
}
    

And call it like this await sendMessage2(myMessage: "Hello")

Upvotes: 0

Related Questions